diff --git a/doc/sphinx/source/drivers/power/max17616.rst b/doc/sphinx/source/drivers/power/max17616.rst new file mode 100644 index 00000000000..541eb1c51a3 --- /dev/null +++ b/doc/sphinx/source/drivers/power/max17616.rst @@ -0,0 +1 @@ +.. include:: ../../../../../drivers/power/max17616/README.rst \ No newline at end of file diff --git a/doc/sphinx/source/projects/power/max17616.rst b/doc/sphinx/source/projects/power/max17616.rst new file mode 100644 index 00000000000..024a7c06fae --- /dev/null +++ b/doc/sphinx/source/projects/power/max17616.rst @@ -0,0 +1 @@ +.. include:: ../../../../../projects/max17616/README.rst \ No newline at end of file diff --git a/drivers/power/max17616/README.rst b/drivers/power/max17616/README.rst new file mode 100644 index 00000000000..b9b1da12ee2 --- /dev/null +++ b/drivers/power/max17616/README.rst @@ -0,0 +1,206 @@ +MAX17616 no-OS driver +===================== + +.. no-os-doxygen:: + +Supported Devices +----------------- + +* `MAX17616/MAX17616A `_ + +Overview +-------- + +The MAX17616/MAX17616A offers highly versatile and programmable protection +boundaries for systems against input voltage faults and output overcurrent +faults. Input-voltage faults (with positive polarity) are protected up to +80V +(without Reverse Current Protection)/+75V (with Reverse Current Protection), by +an internal nFET featuring low ON-resistance (20mΩ typ). The devices feature a +programmable undervoltage-lockout (UVLO) thresholds by using external voltage- +dividers. The MAX17616 features a programmable overvoltage-lockout (OVLO) while +MAX17616A offers a programmable output voltage clamp function through the OVFB +pin that features an output voltage limiting regulation during input transient +surge events. Input undervoltage and overvoltage protection (MAX17616)/output +voltage clamp function (MAX17616A) can be programmed across the entire 3V to 80V +operating range. + +Applications +------------ + +MAX17616 +-------- + +* Input Voltage and Output Overcurrent Protections +* Loss of Ground Protection +* Surge Protection + +MAX17616 Device Configuration +----------------------------- + +Driver Initialization +--------------------- + +In order to be able to use the device, you will have to provide the support +for the communication protocol (I2C) alongside other GPIO pins if needed in the +specific application (depends on the way the device is used). + +The first API to be called is **max17616_init**. Make sure that it return 0, +which means that the driver was initialized correctly. + +The initialization API uses the device descriptor and an initialization +parameter. + +Status Bytes +------------ + +Assertion in the status bytes/words indicates fault/warning in device input/ +output, temperature, and communication, memory and logic. These statuses can be +accessed via the **max17616_read_status** API. + +Telemetry +--------- + +Measurements for each output channel can be read using the +**max17616_read_telemetry_all** API. Some telemetry values includes input/output +voltage, input current, temperature, and output power. + +MAX17616 Driver Initialization Example +-------------------------------------- + +.. code-block:: bash + + struct max17616_dev *max17616_dev; + + struct no_os_i2c_init_param i2c_ip = { + .device_id = I2C_DEVICE_ID, + .max_speed_hz = I2C_CLK_SPEED, + .platform_ops = I2C_OPS, + .slave_address = I2C_ADDR, + .extra = I2C_EXTRA, + }; + + struct max17616_init_param max17616_ip = { + .i2c_init = &i2c_ip, + .chip_id = ID_MAX17616, + }; + + ret = max17616_init(&max17616_dev, &max17616_ip); + if (ret) + goto error; + +MAX17616 no-OS IIO support +-------------------------- + +The MAX17616 IIO driver comes on top of the MAX17616 driver and offers support +for interfacing IIO clients through libiio. + +MAX17616 IIO Device Configuration +--------------------------------- + +Channels +-------- + +The device has a total of 15 input channels and 7 output channels: + +**Telemetry Input Channels:** + +* ``vin - input voltage`` +* ``vout - output voltage`` +* ``iout - output current`` +* ``temp1 - device temperature`` +* ``pout - output power (calculated from vout * iout)`` + +**Status Input Channels:** + +* ``status_word - 16-bit comprehensive status register (hex)`` +* ``status_vout - VOUT status byte (hex)`` +* ``status_iout - IOUT status byte (hex)`` +* ``status_input - INPUT status byte (hex)`` +* ``status_temperature - TEMPERATURE status byte (hex)`` +* ``status_cml - Communication/Memory/Logic status byte (hex)`` +* ``status_mfr_specific - Manufacturer-specific status byte (hex)`` +* ``capability - Device capability register (hex)`` + +**Control Output Channels:** + +* ``operation - device operation state (0=disabled, 1=enabled)`` +* ``clmode - current limit mode setting`` +* ``istart_ratio - current start ratio setting`` +* ``tstoc - short circuit timeout setting`` +* ``istlim - current limit setting`` +* ``vout_uv_fault_limit - output undervoltage fault limit setting`` + +Input Channel Attributes +------------------------ + +The telemetry input channels (vin, vout, iout, temp1, pout) each have 2 channel +attributes: + +* ``raw - the raw converted value from the device using DIRECT format conversion`` +* ``scale - the scale factor (always returns 1 for DIRECT format values)`` + +The status input channels (status_word, status_vout, status_iout, status_input, +status_temperature, status_cml, status_mfr_specific, capability) each have +1 channel attribute: + +* ``raw - the raw hexadecimal value of the status register`` + +Output Channel Attributes +------------------------- + +The control output channels (operation, clmode, istart_ratio, tstoc, istlim, +vout_uv_fault_limit) each have 1 channel attribute: + +* ``raw - read/write the integer value of the control setting`` + +Global Attributes +----------------- + +The device has a total of 4 global attributes: + +* ``operation - device operation state (read/write: "enabled"/"disabled" or "1"/"0")`` +* ``clear_faults - clears all asserted faults (write-only, write any value to trigger)`` +* ``device_info - device identification information (read-only string)`` +* ``fault_summary - summary of current active faults (read-only string)`` + +Debug Attributes +---------------- + +The device has no debug attributes implemented. + +MAX17616 IIO Driver Initialization Example +------------------------------------------ + +.. code-block:: bash + + int ret; + + struct max17616_iio_desc *max17616_iio_desc; + struct max17616_iio_desc_init_param max17616_iio_ip = { + .max17616_init_param = &max17616_ip, + }; + + struct iio_app_desc *app; + struct iio_app_init_param app_init_param = { 0 }; + + ret = max17616_iio_init(&max17616_iio_desc, &max17616_iio_ip); + if (ret) + return ret; + + struct iio_app_device iio_devices[] = { + { + .name = "max17616", + .dev = max17616_iio_desc, + .dev_descriptor = max17616_iio_desc->iio_dev, + } + }; + + app_init_param.devices = iio_devices; + app_init_param.nb_devices = NO_OS_ARRAY_SIZE(iio_devices); + app_init_param.uart_init_params = uart_ip; + + ret = iio_app_init(&app, app_init_param); + if (ret) + return ret; + + return iio_app_run(app); diff --git a/drivers/power/max17616/iio_max17616.c b/drivers/power/max17616/iio_max17616.c new file mode 100644 index 00000000000..89689fd1744 --- /dev/null +++ b/drivers/power/max17616/iio_max17616.c @@ -0,0 +1,818 @@ +/***************************************************************************//** +* @file iio_max17616.c +* @brief Source file of the MAX17616 IIO Driver +* @author Carlos Jones (carlosjr.jones@analog.com) +******************************************************************************** +* Copyright 2025(c) Analog Devices, Inc. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* 3. Neither the name of Analog Devices, Inc. nor the names of its +* contributors may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#include +#include +#include +#include "no_os_alloc.h" +#include "no_os_error.h" +#include "no_os_units.h" +#include "no_os_util.h" +#include "iio.h" +#include "iio_types.h" + +#include "max17616.h" +#include "iio_max17616.h" + +/* Forward declarations */ +STATIC int max17616_iio_read_attr(void *device, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv); + +STATIC int max17616_iio_write_attr(void *device, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv); + +STATIC int max17616_iio_read_global_attr(void *device, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv); + +STATIC int max17616_iio_write_global_attr(void *device, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv); + +/* Channels enumeration */ +enum max17616_iio_channels { + MAX17616_IIO_VIN_CHAN, + MAX17616_IIO_VOUT_CHAN, + MAX17616_IIO_IOUT_CHAN, + MAX17616_IIO_TEMP_CHAN, + MAX17616_IIO_POUT_CHAN, + MAX17616_IIO_STATUS_WORD_CHAN, + MAX17616_IIO_STATUS_VOUT_CHAN, + MAX17616_IIO_STATUS_IOUT_CHAN, + MAX17616_IIO_STATUS_INPUT_CHAN, + MAX17616_IIO_STATUS_TEMP_CHAN, + MAX17616_IIO_STATUS_CML_CHAN, + MAX17616_IIO_STATUS_MFR_SPECIFIC_CHAN, + /* Output channels for control settings */ + MAX17616_IIO_CLMODE_CHAN, + MAX17616_IIO_ISTART_RATIO_CHAN, + MAX17616_IIO_TSTOC_CHAN, + MAX17616_IIO_ISTLIM_CHAN, + /* Additional PMBus channels */ + MAX17616_IIO_CAPABILITY_CHAN, + /* VOUT UV fault limit configuration channels */ + MAX17616_IIO_NOMINAL_VOLTAGE_CHAN, + MAX17616_IIO_PGOOD_THRESHOLD_CHAN, +}; + +/* Global attributes enumeration */ +enum max17616_iio_global_attrs { + MAX17616_IIO_OPERATION_ATTR, + MAX17616_IIO_CLEAR_FAULTS_ATTR, + MAX17616_IIO_DEVICE_INFO_ATTR, + MAX17616_IIO_FAULT_SUMMARY_ATTR, + MAX17616_IIO_CAPABILITY_ATTR, +}; + + +/* Channel attributes for raw values and status registers */ +static struct iio_attribute max17616_vin_attrs[] = { + { + .name = "raw", + .priv = 0, + .show = max17616_iio_read_attr, + }, + { + .name = "scale", + .priv = 1, + .show = max17616_iio_read_attr, + }, + END_ATTRIBUTES_ARRAY +}; + +static struct iio_attribute max17616_vout_attrs[] = { + { + .name = "raw", + .priv = 0, + .show = max17616_iio_read_attr, + }, + { + .name = "scale", + .priv = 1, + .show = max17616_iio_read_attr, + }, + END_ATTRIBUTES_ARRAY +}; + +static struct iio_attribute max17616_iout_attrs[] = { + { + .name = "raw", + .priv = 0, + .show = max17616_iio_read_attr, + }, + { + .name = "scale", + .priv = 1, + .show = max17616_iio_read_attr, + }, + END_ATTRIBUTES_ARRAY +}; + +static struct iio_attribute max17616_temp_attrs[] = { + { + .name = "raw", + .priv = 0, + .show = max17616_iio_read_attr, + }, + { + .name = "scale", + .priv = 1, + .show = max17616_iio_read_attr, + }, + END_ATTRIBUTES_ARRAY +}; + +static struct iio_attribute max17616_pout_attrs[] = { + { + .name = "raw", + .priv = 0, + .show = max17616_iio_read_attr, + }, + { + .name = "scale", + .priv = 1, + .show = max17616_iio_read_attr, + }, + END_ATTRIBUTES_ARRAY +}; + +static struct iio_attribute max17616_status_attrs[] = { + { + .name = "raw", + .show = max17616_iio_read_attr, + }, + END_ATTRIBUTES_ARRAY +}; + +/* Output channel attributes (read/write) */ +static struct iio_attribute max17616_output_attrs[] = { + { + .name = "raw", + .show = max17616_iio_read_attr, + .store = max17616_iio_write_attr, + }, + END_ATTRIBUTES_ARRAY +}; + +/* IIO channels definition */ +static struct iio_channel max17616_channels[] = { + { + .name = "vin", + .ch_type = IIO_VOLTAGE, + .channel = MAX17616_IIO_VIN_CHAN, + .address = MAX17616_IIO_VIN_CHAN, + .indexed = 1, + .channel2 = IIO_MOD_X, + .modified = 1, + .attributes = max17616_vin_attrs, + .ch_out = false, + }, + { + .name = "vout", + .ch_type = IIO_VOLTAGE, + .channel = MAX17616_IIO_VOUT_CHAN, + .address = MAX17616_IIO_VOUT_CHAN, + .indexed = 1, + .channel2 = IIO_MOD_Y, + .modified = 1, + .attributes = max17616_vout_attrs, + .ch_out = false, + }, + { + .name = "iout", + .ch_type = IIO_CURRENT, + .channel = MAX17616_IIO_IOUT_CHAN, + .address = MAX17616_IIO_IOUT_CHAN, + .indexed = 1, + .attributes = max17616_iout_attrs, + .ch_out = false, + }, + { + .name = "temp1", + .ch_type = IIO_TEMP, + .channel = MAX17616_IIO_TEMP_CHAN, + .address = MAX17616_IIO_TEMP_CHAN, + .indexed = 1, + .attributes = max17616_temp_attrs, + .ch_out = false, + }, + { + .name = "pout", + .ch_type = IIO_ALTVOLTAGE, + .channel = MAX17616_IIO_POUT_CHAN, + .address = MAX17616_IIO_POUT_CHAN, + .indexed = 1, + .attributes = max17616_pout_attrs, + .ch_out = false, + }, + { + .name = "status_word", + .ch_type = IIO_ALTVOLTAGE, + .channel = MAX17616_IIO_STATUS_WORD_CHAN, + .address = MAX17616_IIO_STATUS_WORD_CHAN, + .indexed = 1, + .attributes = max17616_status_attrs, + .ch_out = false, + }, + { + .name = "status_vout", + .ch_type = IIO_ALTVOLTAGE, + .channel = MAX17616_IIO_STATUS_VOUT_CHAN, + .address = MAX17616_IIO_STATUS_VOUT_CHAN, + .indexed = 1, + .attributes = max17616_status_attrs, + .ch_out = false, + }, + { + .name = "status_iout", + .ch_type = IIO_ALTVOLTAGE, + .channel = MAX17616_IIO_STATUS_IOUT_CHAN, + .address = MAX17616_IIO_STATUS_IOUT_CHAN, + .indexed = 1, + .attributes = max17616_status_attrs, + .ch_out = false, + }, + { + .name = "status_input", + .ch_type = IIO_ALTVOLTAGE, + .channel = MAX17616_IIO_STATUS_INPUT_CHAN, + .address = MAX17616_IIO_STATUS_INPUT_CHAN, + .indexed = 1, + .attributes = max17616_status_attrs, + .ch_out = false, + }, + { + .name = "status_temperature", + .ch_type = IIO_ALTVOLTAGE, + .channel = MAX17616_IIO_STATUS_TEMP_CHAN, + .address = MAX17616_IIO_STATUS_TEMP_CHAN, + .indexed = 1, + .attributes = max17616_status_attrs, + .ch_out = false, + }, + { + .name = "status_cml", + .ch_type = IIO_ALTVOLTAGE, + .channel = MAX17616_IIO_STATUS_CML_CHAN, + .address = MAX17616_IIO_STATUS_CML_CHAN, + .indexed = 1, + .attributes = max17616_status_attrs, + .ch_out = false, + }, + { + .name = "status_mfr_specific", + .ch_type = IIO_ALTVOLTAGE, + .channel = MAX17616_IIO_STATUS_MFR_SPECIFIC_CHAN, + .address = MAX17616_IIO_STATUS_MFR_SPECIFIC_CHAN, + .indexed = 1, + .attributes = max17616_status_attrs, + .ch_out = false, + }, + /* Output channels for control settings */ + { + .name = "clmode", + .ch_type = IIO_ALTVOLTAGE, + .channel = MAX17616_IIO_CLMODE_CHAN, + .address = MAX17616_IIO_CLMODE_CHAN, + .indexed = 1, + .attributes = max17616_output_attrs, + .ch_out = true, + }, + { + .name = "istart_ratio", + .ch_type = IIO_ALTVOLTAGE, + .channel = MAX17616_IIO_ISTART_RATIO_CHAN, + .address = MAX17616_IIO_ISTART_RATIO_CHAN, + .indexed = 1, + .attributes = max17616_output_attrs, + .ch_out = true, + }, + { + .name = "tstoc", + .ch_type = IIO_ALTVOLTAGE, + .channel = MAX17616_IIO_TSTOC_CHAN, + .address = MAX17616_IIO_TSTOC_CHAN, + .indexed = 1, + .attributes = max17616_output_attrs, + .ch_out = true, + }, + { + .name = "istlim", + .ch_type = IIO_ALTVOLTAGE, + .channel = MAX17616_IIO_ISTLIM_CHAN, + .address = MAX17616_IIO_ISTLIM_CHAN, + .indexed = 1, + .attributes = max17616_output_attrs, + .ch_out = true, + }, + /* VOUT UV fault limit configuration channels */ + { + .name = "nominal_voltage", + .ch_type = IIO_ALTVOLTAGE, + .channel = MAX17616_IIO_NOMINAL_VOLTAGE_CHAN, + .address = MAX17616_IIO_NOMINAL_VOLTAGE_CHAN, + .indexed = 1, + .attributes = max17616_output_attrs, + .ch_out = true, + }, + { + .name = "pgood_threshold", + .ch_type = IIO_ALTVOLTAGE, + .channel = MAX17616_IIO_PGOOD_THRESHOLD_CHAN, + .address = MAX17616_IIO_PGOOD_THRESHOLD_CHAN, + .indexed = 1, + .attributes = max17616_output_attrs, + .ch_out = true, + } +}; + +/* Device global attributes */ +static struct iio_attribute max17616_global_attrs[] = { + { + .name = "operation", + .priv = MAX17616_IIO_OPERATION_ATTR, + .show = max17616_iio_read_global_attr, + .store = max17616_iio_write_global_attr, + }, + { + .name = "clear_faults", + .priv = MAX17616_IIO_CLEAR_FAULTS_ATTR, + .store = max17616_iio_write_global_attr, + }, + { + .name = "device_info", + .priv = MAX17616_IIO_DEVICE_INFO_ATTR, + .show = max17616_iio_read_global_attr, + }, + { + .name = "fault_summary", + .priv = MAX17616_IIO_FAULT_SUMMARY_ATTR, + .show = max17616_iio_read_global_attr, + }, + { + .name = "capability", + .priv = MAX17616_IIO_CAPABILITY_ATTR, + .show = max17616_iio_read_global_attr, + }, + END_ATTRIBUTES_ARRAY, +}; + +/* IIO device structure - declared early for use in init function */ +static struct iio_device max17616_iio_device = { + .num_ch = NO_OS_ARRAY_SIZE(max17616_channels), + .channels = max17616_channels, + .attributes = max17616_global_attrs, + .debug_attributes = NULL, + .buffer_attributes = NULL, + .pre_enable = NULL, + .post_disable = NULL, + .read_dev = NULL, + .debug_reg_read = NULL, + .debug_reg_write = NULL, +}; + +/** + * @brief Read attribute function for MAX17616 PMBus IIO driver + * @param device - IIO device structure + * @param buf - Buffer to write the attribute value + * @param len - Maximum length of the buffer + * @param channel - IIO channel information + * @param priv - Private data (0=raw, 1=scale) + * @return Length of the attribute value on success, negative error code otherwise + */ +STATIC int max17616_iio_read_attr(void *device, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv) +{ + struct max17616_iio_desc *iio_max17616 = (struct max17616_iio_desc *)device; + struct max17616_telemetry telemetry; + struct max17616_status status; + uint16_t raw_value; + int ret; + + /* Handle measurement channels */ + switch (channel->address) { + case MAX17616_IIO_VIN_CHAN: + if (priv == 0) { + ret = max17616_read_telemetry_all(iio_max17616->max17616_dev, + &telemetry); + if (ret) + return ret; + if (!(telemetry.valid_mask & NO_OS_BIT(0))) + return -ENODATA; + return snprintf(buf, len, "%d", telemetry.vin); + } else if (priv == 1) { + return snprintf(buf, len, "1"); + } + break; + + case MAX17616_IIO_VOUT_CHAN: + if (priv == 0) { + ret = max17616_read_telemetry_all(iio_max17616->max17616_dev, + &telemetry); + if (ret) + return ret; + if (!(telemetry.valid_mask & NO_OS_BIT(1))) + return -ENODATA; + return snprintf(buf, len, "%d", telemetry.vout); + } else if (priv == 1) { + return snprintf(buf, len, "1"); + } + break; + + case MAX17616_IIO_IOUT_CHAN: + if (priv == 0) { + ret = max17616_read_telemetry_all(iio_max17616->max17616_dev, + &telemetry); + if (ret) + return ret; + if (!(telemetry.valid_mask & NO_OS_BIT(3))) + return -ENODATA; + return snprintf(buf, len, "%d", telemetry.iout); + } else if (priv == 1) { + return snprintf(buf, len, "1"); + } + break; + + case MAX17616_IIO_TEMP_CHAN: + if (priv == 0) { + ret = max17616_read_telemetry_all(iio_max17616->max17616_dev, + &telemetry); + if (ret) + return ret; + if (!(telemetry.valid_mask & NO_OS_BIT(4))) + return -ENODATA; + return snprintf(buf, len, "%d", telemetry.temp1); + } else if (priv == 1) { + return snprintf(buf, len, "1"); + } + break; + + case MAX17616_IIO_POUT_CHAN: + if (priv == 0) { + ret = max17616_read_telemetry_all(iio_max17616->max17616_dev, + &telemetry); + if (ret) + return ret; + if (!(telemetry.valid_mask & NO_OS_BIT(5))) + return -ENODATA; + return snprintf(buf, len, "%d", telemetry.pout); + } else if (priv == 1) { + return snprintf(buf, len, "1"); + } + break; + + /* Status registers */ + case MAX17616_IIO_STATUS_WORD_CHAN: + ret = max17616_read_status(iio_max17616->max17616_dev, &status); + if (ret) + return ret; + return snprintf(buf, len, "0x%04X", status.word); + + case MAX17616_IIO_STATUS_VOUT_CHAN: { + uint8_t status_vout; + ret = max17616_read_status_vout(iio_max17616->max17616_dev, &status_vout); + if (ret) + return ret; + return snprintf(buf, len, "0x%02X", status_vout); + } + + case MAX17616_IIO_STATUS_IOUT_CHAN: { + uint8_t status_iout; + ret = max17616_read_status_iout(iio_max17616->max17616_dev, &status_iout); + if (ret) + return ret; + return snprintf(buf, len, "0x%02X", status_iout); + } + + case MAX17616_IIO_STATUS_INPUT_CHAN: { + uint8_t status_input; + ret = max17616_read_status_input(iio_max17616->max17616_dev, &status_input); + if (ret) + return ret; + return snprintf(buf, len, "0x%02X", status_input); + } + + case MAX17616_IIO_STATUS_TEMP_CHAN: { + uint8_t status_temp; + ret = max17616_read_status_temperature(iio_max17616->max17616_dev, + &status_temp); + if (ret) + return ret; + return snprintf(buf, len, "0x%02X", status_temp); + } + + case MAX17616_IIO_STATUS_CML_CHAN: { + uint8_t status_cml; + ret = max17616_read_status_cml(iio_max17616->max17616_dev, &status_cml); + if (ret) + return ret; + return snprintf(buf, len, "0x%02X", status_cml); + } + + case MAX17616_IIO_STATUS_MFR_SPECIFIC_CHAN: { + uint8_t status_mfr; + ret = max17616_read_status_mfr_specific(iio_max17616->max17616_dev, + &status_mfr); + if (ret) + return ret; + return snprintf(buf, len, "0x%02X", status_mfr); + } + + /* Output channels */ + case MAX17616_IIO_CLMODE_CHAN: { + enum max17616_current_limit_mode value; + ret = max17616_get_current_limit_mode(iio_max17616->max17616_dev, &value); + if (ret) + return ret; + return snprintf(buf, len, "%d", (uint8_t)value); + } + + case MAX17616_IIO_ISTART_RATIO_CHAN: { + enum max17616_istart_ratio value; + ret = max17616_get_istart_ratio(iio_max17616->max17616_dev, &value); + if (ret) + return ret; + return snprintf(buf, len, "%d", (uint8_t)value); + } + + case MAX17616_IIO_TSTOC_CHAN: { + enum max17616_overcurrent_timeout value; + ret = max17616_get_overcurrent_timeout(iio_max17616->max17616_dev, &value); + if (ret) + return ret; + return snprintf(buf, len, "%d", (uint8_t)value); + } + + case MAX17616_IIO_ISTLIM_CHAN: { + enum max17616_overcurrent_limit value; + ret = max17616_get_overcurrent_limit(iio_max17616->max17616_dev, &value); + if (ret) + return ret; + return snprintf(buf, len, "%d", (uint8_t)value); + } + + case MAX17616_IIO_NOMINAL_VOLTAGE_CHAN: { + enum max17616_nominal_voltage voltage; + enum max17616_pgood_threshold threshold; + ret = max17616_get_vout_uv_fault_limit_config(iio_max17616->max17616_dev, + &voltage, &threshold); + if (ret) + return ret; + return snprintf(buf, len, "%d", (uint8_t)voltage); + } + + case MAX17616_IIO_PGOOD_THRESHOLD_CHAN: { + enum max17616_nominal_voltage voltage; + enum max17616_pgood_threshold threshold; + ret = max17616_get_vout_uv_fault_limit_config(iio_max17616->max17616_dev, + &voltage, &threshold); + if (ret) + return ret; + return snprintf(buf, len, "%d", (uint8_t)threshold); + } + + default: + return -EINVAL; + } +} + +/** + * @brief Write attribute function for MAX17616 output channels + * @param device - IIO device structure + * @param buf - Buffer containing the attribute value to write + * @param len - Length of the buffer + * @param channel - IIO channel information + * @param priv - Private data (attribute ID) + * @return Number of bytes written on success, negative error code otherwise + */ +STATIC int max17616_iio_write_attr(void *device, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv) +{ + struct max17616_iio_desc *iio_max17616 = (struct max17616_iio_desc *)device; + int value; + int ret; + + ret = sscanf(buf, "%d", &value); + if (ret != 1) + return -EINVAL; + + switch (channel->address) { + + case MAX17616_IIO_CLMODE_CHAN: + ret = max17616_set_current_limit_mode(iio_max17616->max17616_dev, + (enum max17616_current_limit_mode)value); + break; + + case MAX17616_IIO_ISTART_RATIO_CHAN: + ret = max17616_set_istart_ratio(iio_max17616->max17616_dev, + (enum max17616_istart_ratio)value); + break; + + case MAX17616_IIO_TSTOC_CHAN: + ret = max17616_set_overcurrent_timeout(iio_max17616->max17616_dev, + (enum max17616_overcurrent_timeout)value); + break; + + case MAX17616_IIO_ISTLIM_CHAN: + ret = max17616_set_overcurrent_limit(iio_max17616->max17616_dev, + (enum max17616_overcurrent_limit)value); + break; + + default: + return -EINVAL; + } + + if (ret) + return ret; + + return len; +} + +/** + * @brief Read global attribute function for MAX17616 IIO device + * @param device - IIO device structure (max17616_iio_desc) + * @param buf - Buffer to write the attribute value + * @param len - Maximum length of the buffer + * @param channel - IIO channel information (unused for global attributes) + * @param priv - Private data identifying which global attribute to read + * @return Length of the attribute value on success, negative error code otherwise + */ +STATIC int max17616_iio_read_global_attr(void *device, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv) +{ + struct max17616_iio_desc *iio_max17616 = (struct max17616_iio_desc *)device; + int ret; + + /* Use priv to determine which attribute to read */ + switch (priv) { + case MAX17616_IIO_OPERATION_ATTR: { + bool enabled; + ret = max17616_get_operation_state(iio_max17616->max17616_dev, &enabled); + if (ret) + return ret; + return snprintf(buf, len, "%s", enabled ? "enabled" : "disabled"); + } + + case MAX17616_IIO_DEVICE_INFO_ATTR: + return snprintf(buf, len, "MAX17616/MAX17616A Protection IC"); + + case MAX17616_IIO_FAULT_SUMMARY_ATTR: { + struct max17616_status status; + ret = max17616_read_status(iio_max17616->max17616_dev, &status); + if (ret) + return ret; + + if (status.word == 0) { + return snprintf(buf, len, "No faults"); + } + + char fault_info[256] = {0}; + int pos = 0; + + if (status.vout) pos += snprintf(fault_info + pos, sizeof(fault_info) - pos, + "VOUT_FAULT "); + if (status.iout) pos += snprintf(fault_info + pos, sizeof(fault_info) - pos, + "IOUT_FAULT "); + if (status.input) pos += snprintf(fault_info + pos, sizeof(fault_info) - pos, + "VIN_FAULT "); + if (status.temperature) pos += snprintf(fault_info + pos, + sizeof(fault_info) - pos, "TEMP_FAULT "); + if (status.cml) pos += snprintf(fault_info + pos, sizeof(fault_info) - pos, + "CML_FAULT "); + if (status.mfr_specific) pos += snprintf(fault_info + pos, + sizeof(fault_info) - pos, "MFR_FAULT "); + + return snprintf(buf, len, "%s", fault_info); + } + case MAX17616_IIO_CAPABILITY_ATTR: { + uint8_t capability; + ret = max17616_read_capability(iio_max17616->max17616_dev, &capability); + if (ret) + return ret; + return snprintf(buf, len, "%d", capability); + } + + default: + return -EINVAL; + } +} + +/** + * @brief Write global attribute function for MAX17616 IIO device + * @param device - IIO device structure (max17616_iio_desc) + * @param buf - Buffer containing the attribute value to write + * @param len - Length of the buffer + * @param channel - IIO channel information (unused for global attributes) + * @param priv - Private data identifying which global attribute to write + * @return Number of bytes written on success, negative error code otherwise + */ +STATIC int max17616_iio_write_global_attr(void *device, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv) +{ + struct max17616_iio_desc *iio_max17616 = (struct max17616_iio_desc *)device; + + switch (priv) { + case MAX17616_IIO_OPERATION_ATTR: { + int enable = 0; + if (!strncmp(buf, "1", 1) || !strncasecmp(buf, "enable", 6)) { + enable = 1; + } + return max17616_set_operation_state(iio_max17616->max17616_dev, enable); + } + + case MAX17616_IIO_CLEAR_FAULTS_ATTR: + return max17616_clear_faults(iio_max17616->max17616_dev); + + default: + return -EINVAL; + } +} + +/** + * @brief Initializes the MAX17616 IIO descriptor. + * @param iio_desc - Pointer to IIO device descriptor. + * @param init_param - Device initialization parameters. + * @return 0 in case of success, an error code otherwise. + */ +int max17616_iio_init(struct max17616_iio_desc **iio_desc, + struct max17616_iio_desc_init_param *init_param) +{ + struct max17616_iio_desc *descriptor; + int ret; + + if (!iio_desc || !init_param || !init_param->max17616_init_param) + return -EINVAL; + + descriptor = no_os_calloc(1, sizeof(*descriptor)); + if (!descriptor) + return -ENOMEM; + + ret = max17616_init(&descriptor->max17616_dev, + init_param->max17616_init_param); + if (ret) + goto dev_err; + + descriptor->iio_dev = &max17616_iio_device; + + *iio_desc = descriptor; + + return 0; + +dev_err: + no_os_free(descriptor); + + return ret; +} + +/** + * @brief Free resources allocated by the init function. + * @param iio_desc - The iio device descriptor. + * @return 0 in case of success, an error code otherwise. + */ +int max17616_iio_remove(struct max17616_iio_desc *iio_desc) +{ + if (!iio_desc) + return -ENODEV; + + if (iio_desc->iio_dev) + max17616_remove(iio_desc->max17616_dev); + + no_os_free(iio_desc); + + return 0; +} diff --git a/drivers/power/max17616/iio_max17616.h b/drivers/power/max17616/iio_max17616.h new file mode 100644 index 00000000000..48cd602b1b6 --- /dev/null +++ b/drivers/power/max17616/iio_max17616.h @@ -0,0 +1,62 @@ +/***************************************************************************//** +* @file iio_max17616.h +* @brief Header file of the MAX17616 IIO Driver +* @author Carlos Jones (carlosjr.jones@analog.com) +******************************************************************************** +* Copyright 2025(c) Analog Devices, Inc. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* 3. Neither the name of Analog Devices, Inc. nor the names of its +* contributors may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef __IIO_MAX17616_H__ +#define __IIO_MAX17616_H__ + +#include +#include "iio.h" +#include "max17616.h" + +/** + * @brief Structure holding the MAX17616 IIO device descriptor +*/ +struct max17616_iio_desc { + struct max17616_dev *max17616_dev; + struct iio_device *iio_dev; +}; + +/** + * @brief Structure holding the MAX17616 IIO initialization parameter. +*/ +struct max17616_iio_desc_init_param { + struct max17616_init_param *max17616_init_param; +}; + +/** Initializes the MAX17616 IIO descriptor. */ +int max17616_iio_init(struct max17616_iio_desc **iio_desc, + struct max17616_iio_desc_init_param *init_param); + +/** Free resources allocated by the initialization function. */ +int max17616_iio_remove(struct max17616_iio_desc *desc); + +#endif /* __IIO_MAX17616_H__ */ diff --git a/drivers/power/max17616/max17616.c b/drivers/power/max17616/max17616.c new file mode 100644 index 00000000000..f0197a3c843 --- /dev/null +++ b/drivers/power/max17616/max17616.c @@ -0,0 +1,1182 @@ +/***************************************************************************//** +* @file max17616.c +* @brief Source file of the MAX17616 Driver +* @author Carlos Jones (carlosjr.jones@analog.com) +******************************************************************************** +* Copyright 2025(c) Analog Devices, Inc. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* 3. Neither the name of Analog Devices, Inc. nor the names of its +* contributors may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#include +#include +#include +#include +#include + +#include "no_os_units.h" +#include "no_os_util.h" +#include "no_os_delay.h" +#include "no_os_alloc.h" +#include "no_os_i2c.h" +#include "no_os_crc8.h" + +#include "max17616.h" + +/* Reference : max17616-max17616a.pdf */ +#define MAX17616_PMBUS_REVISION_VALUE 0x33 /* PMBus Part I and II Rev1.3 */ +#define MAX17616_MFR_ID_STR "MAXIM" +#define MAX17616_MFR_ID_SIZE 5 +#define MAX17616_MFR_REV_SIZE 2 + +/* DIRECT format coefficients for MAX17616 data conversion */ +struct max17616_direct_coeffs { + int16_t m; /* Slope coefficient */ + int16_t b; /* Offset coefficient */ + int8_t R; /* Exponent */ +}; + +/* Reference : max17616-max17616a.pdf */ +static const struct max17616_direct_coeffs max17616_vin_coeffs = { + .m = 512, .b = -18, .R = -1 +}; +static const struct max17616_direct_coeffs max17616_vout_coeffs = { + .m = 512, .b = -18, .R = -1 +}; +static const struct max17616_direct_coeffs max17616_iout_coeffs = { + .m = 5845, .b = 80, .R = -1 +}; +static const struct max17616_direct_coeffs max17616_temp_coeffs = { + .m = 71, .b = 19653, .R = -1 +}; + +static const struct max17616_chip_info max17616_info = { + .mfr_id = MAX17616_MFR_ID_STR, + .mfr_id_size = MAX17616_MFR_ID_SIZE, + .mfr_rev = "01", + .mfr_rev_size = MAX17616_MFR_REV_SIZE, + .pmbus_rev = MAX17616_PMBUS_REVISION_VALUE, + .specific_info = { + [ID_MAX17616] = { + .ic_dev_id = "MAX17616", + .ic_dev_id_size = sizeof("MAX17616") - 1, + }, + [ID_MAX17616A] = { + .ic_dev_id = "MAX17616A", + .ic_dev_id_size = sizeof("MAX17616A") - 1, + } + }, +}; + +/** + * @brief Send a PMBus command to the device + * @param dev - Device structure + * @param cmd - PMBus command + * @return 0 in case of success, negative error code otherwise + */ +int max17616_send_byte(struct max17616_dev *dev, uint8_t cmd) +{ + uint8_t tx_buf[2] = {0}; + + tx_buf[0] = cmd; + + return no_os_i2c_write(dev->i2c_desc, tx_buf, 1, 1); +} + +/** + * @brief Perform a raw PMBus read byte operation + * @param dev - Device structure + * @param cmd - PMBus command + * @param data - Address of the byte read + * @return 0 in case of success, negative error code otherwise + */ +int max17616_read_byte(struct max17616_dev *dev, uint8_t cmd, uint8_t *data) +{ + int ret; + uint8_t rx_buf[2]; + uint8_t tx_buf[2] = {0}; + tx_buf[0] = cmd; + + ret = no_os_i2c_write(dev->i2c_desc, tx_buf, 1, 0); + if (ret) + return ret; + + ret = no_os_i2c_read(dev->i2c_desc, rx_buf, 1, 1); + if (ret) + return ret; + + *data = rx_buf[0]; + + return 0; +} + +/** + * @brief Perform a raw PMBus read word operation + * @param dev - Device structure + * @param cmd - PMBus command + * @param word - Address of the read word + * @return 0 in case of success, negative error code otherwise + */ +int max17616_read_word(struct max17616_dev *dev, uint8_t cmd, uint16_t *word) +{ + int ret; + uint8_t rx_buf[3] = {0}; + uint8_t tx_buf[2] = {0}; + tx_buf[0] = cmd; + + ret = no_os_i2c_write(dev->i2c_desc, tx_buf, 1, 0); + if (ret) + return ret; + + ret = no_os_i2c_read(dev->i2c_desc, rx_buf, 2, 1); + if (ret) + return ret; + + *word = no_os_get_unaligned_le16(rx_buf); + + return 0; +} + +/** + * @brief Perform a PMBus read block operation + * @param dev - Device structure + * @param cmd - PMBus command + * @param data - Address of the read block + * @param nbytes - Size of the block in bytes + * @return 0 in case of success, negative error code otherwise + */ +int max17616_read_block_data(struct max17616_dev *dev, uint8_t cmd, + uint8_t *data, size_t nbytes) +{ + int ret; + uint8_t rxbuf[nbytes + 2]; + + ret = no_os_i2c_write(dev->i2c_desc, &cmd, 1, 0); + if (ret) + return ret; + + ret = no_os_i2c_read(dev->i2c_desc, rxbuf, nbytes + 1, 1); + if (ret) + return ret; + + if ((size_t)rxbuf[0] > nbytes) + return -EMSGSIZE; + + memcpy(data, &rxbuf[1], nbytes); + + return 0; +} + +/** + * @brief Perform a raw PMBus write byte operation + * @param dev - Device structure + * @param cmd - PMBus command + * @param value - Byte to be written + * @return 0 in case of success, negative error code otherwise + */ +int max17616_write_byte(struct max17616_dev *dev, uint8_t cmd, uint8_t value) +{ + uint8_t tx_buf[3] = {0}; + + tx_buf[0] = cmd; + tx_buf[1] = value; + + return no_os_i2c_write(dev->i2c_desc, tx_buf, 2, 1); +} + +/** + * @brief Convert DIRECT format raw value to integer + * @param raw_value - Raw 16-bit value from device + * @param coeffs - DIRECT format coefficients + * @return Converted integer value + */ +static int max17616_direct_to_int(uint16_t raw_value, + const struct max17616_direct_coeffs *coeffs) +{ + int32_t y = (int16_t)raw_value; /* Convert to signed */ + int32_t result; + + /* X = (1/m) × (Y × 10^(-R) - b) */ + /* First: Y × 10^(-R) */ + int32_t y_scaled; + /* Negative R: Y × 10^(-R) = Y × 10^|R| */ + int32_t power = 1; + for (int i = 0; i < -coeffs->R; i++) + power *= 10; + + y_scaled = y * power; + + /* Then: (Y × 10^(-R) - b) / m */ + result = (y_scaled - coeffs->b) / coeffs->m; + + return (int)result; +} + +/** + * @brief Read STATUS_BYTE register + * @param dev - Device structure + * @param status_byte - Pointer to store status byte + * @return 0 on success, negative error code otherwise + */ +int max17616_read_status_byte(struct max17616_dev *dev, uint8_t *status_byte) +{ + return max17616_read_byte(dev, MAX17616_CMD(MAX17616_STATUS_BYTE), + status_byte); +} + +/** + * @brief Read STATUS_VOUT register + * @param dev - Device structure + * @param status_vout - Pointer to store status VOUT byte + * @return 0 on success, negative error code otherwise + */ +int max17616_read_status_vout(struct max17616_dev *dev, uint8_t *status_vout) +{ + if (!dev || !status_vout) + return -EINVAL; + + return max17616_read_byte(dev, MAX17616_CMD(MAX17616_STATUS_VOUT), + status_vout); +} + +/** + * @brief Read STATUS_IOUT register + * @param dev - Device structure + * @param status_iout - Pointer to store status IOUT byte + * @return 0 on success, negative error code otherwise + */ +int max17616_read_status_iout(struct max17616_dev *dev, uint8_t *status_iout) +{ + if (!dev || !status_iout) + return -EINVAL; + + return max17616_read_byte(dev, MAX17616_CMD(MAX17616_STATUS_IOUT), + status_iout); +} + +/** + * @brief Read STATUS_INPUT register + * @param dev - Device structure + * @param status_input - Pointer to store status INPUT byte + * @return 0 on success, negative error code otherwise + */ +int max17616_read_status_input(struct max17616_dev *dev, uint8_t *status_input) +{ + if (!dev || !status_input) + return -EINVAL; + + return max17616_read_byte(dev, MAX17616_CMD(MAX17616_STATUS_INPUT), + status_input); +} + +/** + * @brief Read STATUS_TEMPERATURE register + * @param dev - Device structure + * @param status_temperature - Pointer to store status TEMPERATURE byte + * @return 0 on success, negative error code otherwise + */ +int max17616_read_status_temperature(struct max17616_dev *dev, + uint8_t *status_temperature) +{ + if (!dev || !status_temperature) + return -EINVAL; + + return max17616_read_byte(dev, MAX17616_CMD(MAX17616_STATUS_TEMPERATURE), + status_temperature); +} + +/** + * @brief Read STATUS_CML register + * @param dev - Device structure + * @param status_cml - Pointer to store status CML byte + * @return 0 on success, negative error code otherwise + */ +int max17616_read_status_cml(struct max17616_dev *dev, uint8_t *status_cml) +{ + if (!dev || !status_cml) + return -EINVAL; + + return max17616_read_byte(dev, MAX17616_CMD(MAX17616_STATUS_CML), + status_cml); +} + +/** + * @brief Read STATUS_MFR_SPECIFIC register + * @param dev - Device structure + * @param status_mfr - Pointer to store status MFR SPECIFIC byte + * @return 0 on success, negative error code otherwise + */ +int max17616_read_status_mfr_specific(struct max17616_dev *dev, + uint8_t *status_mfr) +{ + if (!dev || !status_mfr) + return -EINVAL; + + return max17616_read_byte(dev, MAX17616_CMD(MAX17616_STATUS_MFR_SPECIFIC), + status_mfr); +} + +/** + * @brief Read device capability register + * @param dev - Device structure + * @param capability - Pointer to store capability byte + * @return 0 on success, negative error code otherwise + */ +int max17616_read_capability(struct max17616_dev *dev, uint8_t *capability) +{ + if (!dev || !capability) + return -EINVAL; + + return max17616_read_byte(dev, MAX17616_CMD(MAX17616_CAPABILITY), + capability); +} + +/** + * @brief Read and verify manufacturer ID + * @param dev - Device structure + * @return 0 on success, negative error code otherwise + */ +int max17616_verify_manufacturer_id(struct max17616_dev *dev) +{ + uint8_t mfr_id[8]; + int ret; + + ret = max17616_read_block_data(dev, MAX17616_CMD(MAX17616_MFR_ID), + mfr_id, + MAX17616_DATA_SIZE(MAX17616_MFR_ID)); + if (ret) + return ret; + + if (strncmp((char*)mfr_id, + MAX17616_MFR_ID_STR, MAX17616_MFR_ID_SIZE) != 0) + return -ENODEV; + + return 0; +} + +/** + * @brief Read device ID and identify chip variant + * @param dev - Device structure + * @return 0 on success, negative error code otherwise + */ +int max17616_identify_chip_variant(struct max17616_dev *dev) +{ + uint8_t device_id[16]; + int ret; + + ret = max17616_read_block_data(dev, MAX17616_CMD(MAX17616_IC_DEVICE_ID), + device_id, + MAX17616_DATA_SIZE(MAX17616_IC_DEVICE_ID)); + if (ret) + return ret; + + for (int i = 0; i < ID_MAX17616_CHIP_COUNT; i++) { + if (strncmp((char*)device_id, dev->chip_info->specific_info[i].ic_dev_id, + dev->chip_info->specific_info[i].ic_dev_id_size) == 0) { + dev->chip_id = i; + return 0; + } + } + + return -ENODEV; +} + +/** + * @brief Verify PMBus revision + * @param dev - Device structure + * @return 0 on success, negative error code otherwise + */ +int max17616_verify_pmbus_revision(struct max17616_dev *dev) +{ + uint16_t pmbus_rev; + int ret; + + ret = max17616_read_word(dev, MAX17616_CMD(MAX17616_PMBUS_REVISION), + &pmbus_rev); + if (ret) + return ret; + + if (pmbus_rev != MAX17616_PMBUS_REVISION_VALUE) + return -ENODEV; + + return 0; +} + +/** + * @brief Identify MAX17616 device and verify compatibility + * @param dev - Device structure + * @return 0 on success, negative error code otherwise + */ +static int max17616_identify(struct max17616_dev *dev) +{ + int ret; + + ret = max17616_verify_manufacturer_id(dev); + if (ret) + return ret; + + ret = max17616_identify_chip_variant(dev); + if (ret) + return ret; + + ret = max17616_verify_pmbus_revision(dev); + if (ret) + return ret; + + return 0; +} + +/** + * @brief Clear all asserted faults + * @param dev - Device structure + * @return 0 in case of success, negative error code otherwise + */ +int max17616_clear_faults(struct max17616_dev *dev) +{ + return max17616_send_byte(dev, MAX17616_CMD(MAX17616_CLEAR_FAULTS)); +} + +/** + * @brief Read a specific value with automatic data conversion + * @param dev - Device structure + * @param value_type - Type of value to read + * @param value - Pointer to store the converted value + * @return 0 on success, negative error code otherwise + */ +int max17616_read_value(struct max17616_dev *dev, + enum max17616_value_type value_type, int *value) +{ + uint16_t raw_value; + int ret; + int vin, iout; + + if (!dev || !value) + return -EINVAL; + + switch (value_type) { + case MAX17616_VIN: + ret = max17616_read_word(dev, MAX17616_CMD(MAX17616_READ_VIN), + &raw_value); + if (ret) + return ret; + + *value = max17616_direct_to_int(raw_value, &max17616_vin_coeffs); + break; + + case MAX17616_VOUT: + ret = max17616_read_word(dev, MAX17616_CMD(MAX17616_READ_VOUT), + &raw_value); + if (ret) + return ret; + + *value = max17616_direct_to_int(raw_value, &max17616_vout_coeffs); + break; + + case MAX17616_IOUT: + ret = max17616_read_word(dev, MAX17616_CMD(MAX17616_READ_IOUT), + &raw_value); + if (ret) + return ret; + + *value = max17616_direct_to_int(raw_value, &max17616_iout_coeffs); + break; + + case MAX17616_TEMP: + ret = max17616_read_word(dev, + MAX17616_CMD(MAX17616_READ_TEMPERATURE_1), + &raw_value); + if (ret) + return ret; + + *value = max17616_direct_to_int(raw_value, &max17616_temp_coeffs); + break; + + case MAX17616_POWER: + /* Calculate power from voltage and current */ + ret = max17616_read_value(dev, MAX17616_VOUT, &vin); + if (ret) + return ret; + ret = max17616_read_value(dev, MAX17616_IOUT, &iout); + if (ret) + return ret; + + *value = vin * iout; + break; + + default: + return -EINVAL; + } + + return 0; +} + +/** + * @brief Set device operation state + * @param dev - Device structure + * @param enable - true to enable, false to disable + * @return 0 on success, negative error code otherwise + */ +int max17616_set_operation_state(struct max17616_dev *dev, bool enable) +{ + uint8_t byte_value = enable ? 0x80 : 0x00; + return max17616_write_byte(dev, MAX17616_CMD(MAX17616_OPERATION), + byte_value); +} + +/** + * @brief Get device operation state + * @param dev - Device structure + * @param enabled - Pointer to store operation state + * @return 0 on success, negative error code otherwise + */ +int max17616_get_operation_state(struct max17616_dev *dev, bool *enabled) +{ + uint8_t operation; + + if (!dev || !enabled) + return -EINVAL; + + int ret = max17616_read_byte(dev, MAX17616_CMD(MAX17616_OPERATION), + &operation); + + if (ret == 0) + *enabled = (operation & 0x80) ? true : false; + + return ret; +} + +/** + * @brief Get current limit mode + * @param dev - Device structure + * @param clmode - Pointer to the current limit mode setting + * @return 0 on success, negative error code otherwise + */ +int max17616_get_current_limit_mode(struct max17616_dev *dev, + enum max17616_current_limit_mode *clmode) +{ + uint8_t raw_value; + int ret; + + if (!dev || !clmode) + return -EINVAL; + + ret = max17616_read_byte(dev, MAX17616_CMD(MAX17616_SET_CLMODE), + &raw_value); + if (ret) + return ret; + + /* Extract bits 7:6 and convert to enum */ + switch (raw_value & MAX17616_CLMODE_BITS_MASK) { + case MAX17616_CLMODE_LATCH_OFF_BITS: + *clmode = MAX17616_CLMODE_LATCH_OFF; + break; + case MAX17616_CLMODE_CONTINUOUS_BITS: + *clmode = MAX17616_CLMODE_CONTINUOUS; + break; + case MAX17616_CLMODE_AUTO_RETRY_BITS: + *clmode = MAX17616_CLMODE_AUTO_RETRY; + break; + default: + return -EINVAL; + } + + return 0; +} + +/** + * @brief Set current limit mode + * @param dev - Device structure + * @param clmode - Current limit mode setting + * @return 0 on success, negative error code otherwise + */ +int max17616_set_current_limit_mode(struct max17616_dev *dev, + enum max17616_current_limit_mode clmode) +{ + if (!dev) + return -EINVAL; + + return max17616_write_byte(dev, MAX17616_CMD(MAX17616_SET_CLMODE), + (uint8_t)clmode); +} + +/** + * @brief Get current start ratio + * @param dev - Device structure + * @param istart_ratio - Pointer to the current start ratio setting + * @return 0 on success, negative error code otherwise + */ +int max17616_get_istart_ratio(struct max17616_dev *dev, + enum max17616_istart_ratio *istart_ratio) +{ + uint8_t raw_value; + int ret; + + if (!dev || !istart_ratio) + return -EINVAL; + + ret = max17616_read_byte(dev, MAX17616_CMD(MAX17616_SET_ISTART_RATIO), + &raw_value); + if (ret) + return ret; + + /* Extract bits 3:0 and convert to enum */ + switch (raw_value & MAX17616_ISTART_BITS_MASK) { + case MAX17616_ISTART_FULL_BITS: + *istart_ratio = MAX17616_ISTART_FULL; + break; + case MAX17616_ISTART_HALF_BITS: + *istart_ratio = MAX17616_ISTART_HALF; + break; + case MAX17616_ISTART_QUARTER_BITS: + *istart_ratio = MAX17616_ISTART_QUARTER; + break; + case MAX17616_ISTART_EIGHTH_BITS: + *istart_ratio = MAX17616_ISTART_EIGHTH; + break; + case MAX17616_ISTART_SIXTEENTH_BITS: + *istart_ratio = MAX17616_ISTART_SIXTEENTH; + break; + default: + return -EINVAL; + } + + return 0; +} + +/** + * @brief Set current start ratio + * @param dev - Device structure + * @param istart_ratio - Current start ratio setting + * @return 0 on success, negative error code otherwise + */ +int max17616_set_istart_ratio(struct max17616_dev *dev, + enum max17616_istart_ratio istart_ratio) +{ + if (!dev) + return -EINVAL; + + return max17616_write_byte(dev, MAX17616_CMD(MAX17616_SET_ISTART_RATIO), + (uint8_t)istart_ratio); +} + +/** + * @brief Get short-term overcurrent duration + * @param dev - Device structure + * @param timeout - Pointer to store short-term overcurrent duration setting + * @return 0 on success, negative error code otherwise + */ +int max17616_get_overcurrent_timeout(struct max17616_dev *dev, + enum max17616_overcurrent_timeout *timeout) +{ + uint8_t raw_value; + int ret; + + if (!dev || !timeout) + return -EINVAL; + + ret = max17616_read_byte(dev, MAX17616_CMD(MAX17616_SET_TSTOC), + &raw_value); + if (ret) + return ret; + + switch (raw_value & MAX17616_TIMEOUT_BITS_MASK) { + case MAX17616_TIMEOUT_400US_BITS: + *timeout = MAX17616_TIMEOUT_400US; + break; + case MAX17616_TIMEOUT_1MS_BITS: + *timeout = MAX17616_TIMEOUT_1MS; + break; + case MAX17616_TIMEOUT_4MS_BITS: + *timeout = MAX17616_TIMEOUT_4MS; + break; + case MAX17616_TIMEOUT_24MS_BITS: + *timeout = MAX17616_TIMEOUT_24MS; + break; + default: + return -EINVAL; + } + + return 0; +} + +/** + * @brief Set short-term overcurrent duration + * @param dev - Device structure + * @param timeout - Short-term overcurrent duration setting + * @return 0 on success, negative error code otherwise + */ +int max17616_set_overcurrent_timeout(struct max17616_dev *dev, + enum max17616_overcurrent_timeout timeout) +{ + if (!dev) + return -EINVAL; + + return max17616_write_byte(dev, MAX17616_CMD(MAX17616_SET_TSTOC), + (uint8_t)timeout); +} + +/** + * @brief Get the short-term overcurrent limit ratio + * @param dev - Device structure + * @param istlim - Pointer to store ISTLIM setting + * @return 0 on success, negative error code otherwise + */ +int max17616_get_overcurrent_limit(struct max17616_dev *dev, + enum max17616_overcurrent_limit *istlim) +{ + uint8_t raw_value; + int ret; + + if (!dev || !istlim) + return -EINVAL; + + ret = max17616_read_byte(dev, MAX17616_CMD(MAX17616_SET_ISTLIM), + &raw_value); + if (ret) + return ret; + + switch (raw_value & MAX17616_OC_LIMIT_BITS_MASK) { + case MAX17616_OC_LIMIT_1_25_BITS: + *istlim = MAX17616_OC_LIMIT_1_25; + break; + case MAX17616_OC_LIMIT_1_50_BITS: + *istlim = MAX17616_OC_LIMIT_1_50; + break; + case MAX17616_OC_LIMIT_1_75_BITS: + *istlim = MAX17616_OC_LIMIT_1_75; + break; + case MAX17616_OC_LIMIT_2_00_BITS: + *istlim = MAX17616_OC_LIMIT_2_00; + break; + default: + return -EINVAL; + } + + return 0; +} + +/** + * @brief Set the short-term overcurrent limit ratio + * @param dev - Device structure + * @param istlimit - Short-term overcurrent limit ratio setting + * @return 0 on success, negative error code otherwise + */ +int max17616_set_overcurrent_limit(struct max17616_dev *dev, + enum max17616_overcurrent_limit istlimit) +{ + if (!dev) + return -EINVAL; + + return max17616_write_byte(dev, MAX17616_CMD(MAX17616_SET_ISTLIM), + (uint8_t)istlimit); +} + +/** + * @brief Set VOUT UV fault limit configuration using enums + * @param dev - Device structure + * @param voltage - Nominal voltage selection (bits 4:2) + * @param threshold - PGOOD rising threshold (bits 1:0) + * @return 0 on success, negative error code otherwise + */ +int max17616_set_vout_uv_fault_limit_config(struct max17616_dev *dev, + enum max17616_nominal_voltage voltage, + enum max17616_pgood_threshold threshold) +{ + uint8_t reg_value; + + if (!dev) + return -EINVAL; + + /* Validate enum values */ + if (voltage > MAX17616_NOMINAL_72V + || threshold > MAX17616_PGOOD_MINUS_30_PERCENT) + return -EINVAL; + + /* Combine voltage selection (bits 4:2) and PGOOD threshold (bits 1:0) */ + reg_value = ((uint8_t)voltage << 2) | (uint8_t)threshold; + + return max17616_write_byte(dev, MAX17616_CMD(MAX17616_VOUT_UV_FAULT_LIMIT), + reg_value); +} + +/** + * @brief Get VOUT UV fault limit configuration using enums + * @param dev - Device structure + * @param voltage - Pointer to store nominal voltage selection + * @param threshold - Pointer to store PGOOD rising threshold + * @return 0 on success, negative error code otherwise + */ +int max17616_get_vout_uv_fault_limit_config(struct max17616_dev *dev, + enum max17616_nominal_voltage *voltage, + enum max17616_pgood_threshold *threshold) +{ + uint8_t raw_value; + int ret; + + if (!dev || !voltage || !threshold) + return -EINVAL; + + ret = max17616_read_byte(dev, MAX17616_CMD(MAX17616_VOUT_UV_FAULT_LIMIT), + &raw_value); + if (ret) + return ret; + + /* Extract voltage selection (bits 4:2) */ + uint8_t voltage_bits = (raw_value >> 2) & MAX17616_NOMINAL_VOLTAGE_BITS_MASK; + switch (voltage_bits) { + case MAX17616_NOMINAL_5V_BITS: + *voltage = MAX17616_NOMINAL_5V; + break; + case MAX17616_NOMINAL_9V_BITS: + *voltage = MAX17616_NOMINAL_9V; + break; + case MAX17616_NOMINAL_12V_BITS: + *voltage = MAX17616_NOMINAL_12V; + break; + case MAX17616_NOMINAL_24V_BITS: + *voltage = MAX17616_NOMINAL_24V; + break; + case MAX17616_NOMINAL_36V_BITS: + *voltage = MAX17616_NOMINAL_36V; + break; + case MAX17616_NOMINAL_48V_BITS: + *voltage = MAX17616_NOMINAL_48V; + break; + case MAX17616_NOMINAL_60V_BITS: + *voltage = MAX17616_NOMINAL_60V; + break; + case MAX17616_NOMINAL_72V_BITS: + *voltage = MAX17616_NOMINAL_72V; + break; + default: + return -EINVAL; + } + + /* Extract PGOOD threshold (bits 1:0) */ + uint8_t threshold_bits = raw_value & MAX17616_PGOOD_THRESHOLD_BITS_MASK; + switch (threshold_bits) { + case MAX17616_PGOOD_MINUS_10_PERCENT_BITS: + *threshold = MAX17616_PGOOD_MINUS_10_PERCENT; + break; + case MAX17616_PGOOD_MINUS_20_PERCENT_BITS: + *threshold = MAX17616_PGOOD_MINUS_20_PERCENT; + break; + case MAX17616_PGOOD_MINUS_30_PERCENT_BITS: + *threshold = MAX17616_PGOOD_MINUS_30_PERCENT; + break; + default: + return -EINVAL; + } + + return 0; +} + +/** + * @brief Read MAX17616 device status + * @param dev - Device structure + * @param status - Pointer to store status + * @return 0 on success, negative error code otherwise + */ +int max17616_read_status(struct max17616_dev *dev, + struct max17616_status *status) +{ + int ret; + + if (!dev || !status) + return -EINVAL; + + memset(status, 0, sizeof(*status)); + + /* Read STATUS_WORD first - it contains bit flags indicating which + * specific status registers have faults */ + ret = max17616_read_word(dev, MAX17616_CMD(MAX17616_STATUS_WORD), + &status->word); + if (ret) + return ret; + + /* STATUS_BYTE is the lower byte of STATUS_WORD + * Note: For compliance, use max17616_read_status_byte() to read STATUS_BYTE directly */ + status->byte = (uint8_t)(status->word & 0xFF); + + /* Only read individual status registers if their corresponding + * STATUS_WORD bits are asserted */ + + /* Check CML fault bit (bit 1 of STATUS_BYTE) */ + if (status->word & (1 << MAX17616_STATUS_BIT_CML)) { + ret = max17616_read_status_cml(dev, &status->cml); + if (ret) + return ret; + } + + /* Check Temperature fault bit (bit 2 of STATUS_BYTE) */ + if (status->word & (1 << MAX17616_STATUS_BIT_TEMPERATURE)) { + ret = max17616_read_status_temperature(dev, &status->temperature); + if (ret) + return ret; + } + + /* Check Input fault bit (bit 5 of STATUS_WORD high byte) */ + if (status->word & (1 << (8 + MAX17616_STATUS_BIT_INPUT))) { + ret = max17616_read_status_input(dev, &status->input); + if (ret) + return ret; + } + + /* Check IOUT/POUT fault bit (bit 6 of STATUS_WORD high byte) */ + if (status->word & (1 << (8 + MAX17616_STATUS_BIT_IOUT_POUT))) { + ret = max17616_read_status_iout(dev, &status->iout); + if (ret) + return ret; + } + + /* Check VOUT fault bit (bit 7 of STATUS_WORD high byte) */ + if (status->word & (1 << (8 + MAX17616_STATUS_BIT_VOUT))) { + ret = max17616_read_status_vout(dev, &status->vout); + if (ret) + return ret; + } + + /* Check Manufacturer Specific fault bit (bit 4 of STATUS_WORD high byte) */ + if (status->word & (1 << (8 + MAX17616_STATUS_BIT_MFR))) { + ret = max17616_read_status_mfr_specific(dev, &status->mfr_specific); + if (ret) + return ret; + } + + return 0; +} + +/** + * @brief Read comprehensive telemetry data + * @param dev - Device structure + * @param telemetry - Telemetry structure to populate + * @return 0 on success, negative error code otherwise + */ +int max17616_read_telemetry_all(struct max17616_dev *dev, + struct max17616_telemetry *telemetry) +{ + int ret; + + if (!dev || !telemetry) + return -EINVAL; + + /* Initialize telemetry structure */ + memset(telemetry, 0, sizeof(struct max17616_telemetry)); + + ret = max17616_read_value(dev, MAX17616_VIN, &telemetry->vin); + if (ret == 0) + telemetry->valid_mask |= NO_OS_BIT(0); + + ret = max17616_read_value(dev, MAX17616_VOUT, &telemetry->vout); + if (ret == 0) + telemetry->valid_mask |= NO_OS_BIT(1); + + ret = max17616_read_value(dev, MAX17616_IOUT, &telemetry->iout); + if (ret == 0) + telemetry->valid_mask |= NO_OS_BIT(3); + + ret = max17616_read_value(dev, MAX17616_TEMP, &telemetry->temp1); + if (ret == 0) + telemetry->valid_mask |= NO_OS_BIT(4); + + /* Calculate power (P = V * I) */ + if ((telemetry->valid_mask & NO_OS_BIT(1)) && + (telemetry->valid_mask & NO_OS_BIT(3))) { + telemetry->pout = (telemetry->vout * telemetry->iout); + telemetry->valid_mask |= NO_OS_BIT(5); + } + + return 0; +} + +/** + * @brief Initialize the device structure + * @param device - Device structure + * @param init_param - Initialization parameters + * @return 0 in case of success, negative error code otherwise + */ +int max17616_init(struct max17616_dev **device, + struct max17616_init_param *init_param) +{ + struct max17616_dev *dev; + int ret = -EINVAL; + + dev = (struct max17616_dev *)no_os_calloc(1, sizeof(struct max17616_dev)); + if (!dev) + return -ENOMEM; + + ret = no_os_i2c_init(&dev->i2c_desc, init_param->i2c_init); + if (ret) + goto i2c_err; + + dev->chip_info = (struct max17616_chip_info *)&max17616_info; + dev->chip_id = init_param->chip_id; + + ret = max17616_identify(dev); + if (ret) + goto dev_err; + + ret = max17616_clear_faults(dev); + if (ret) + goto dev_err; + + ret = max17616_set_operation_state(dev, true); + if (ret) + goto dev_err; + + *device = dev; + + return 0; + +dev_err: + no_os_i2c_remove(dev->i2c_desc); +i2c_err: + no_os_free(dev); + + return ret; +} + +/** + * @brief Free or remove device instance + * @param dev - The device structure + * @return 0 in case of success, negative error code otherwise + */ +int max17616_remove(struct max17616_dev *dev) +{ + int ret; + + ret = no_os_i2c_remove(dev->i2c_desc); + if (ret) + return ret; + + no_os_free(dev); + + return ret; +} + +/* Fault information lookup table */ +static const struct max17616_fault_info fault_descriptions[] = { + /* CML Faults */ + { + MAX17616_FAULT_GRP_CML, MAX17616_CML_FAULT_OTHER, + "Communications other error", true + }, + { + MAX17616_FAULT_GRP_CML, MAX17616_CML_FAULT_MEM_ERROR, + "Memory error detected", true + }, + { + MAX17616_FAULT_GRP_CML, MAX17616_CML_FAULT_PEC_FAIL, + "Packet error checking failed", true + }, + { + MAX17616_FAULT_GRP_CML, MAX17616_CML_FAULT_DATA, + "Invalid or unsupported data received", true + }, + { + MAX17616_FAULT_GRP_CML, MAX17616_CML_FAULT_CMD, + "Invalid or unsupported command received", true + }, + + /* Temperature Faults */ + { + MAX17616_FAULT_GRP_TEMPERATURE, MAX17616_TEMPERATURE_FAULT_OT_FAULT, + "Overtemperature fault occurred", true + }, + + /* Input Faults */ + { + MAX17616_FAULT_GRP_INPUT, MAX17616_INPUT_FAULT_VIN_UV_FAULT, + "Input undervoltage fault occurred", true + }, + { + MAX17616_FAULT_GRP_INPUT, MAX17616_INPUT_FAULT_VIN_OV_FAULT, + "Input overvoltage fault occurred", true + }, + + /* Output Current Faults */ + { + MAX17616_FAULT_GRP_IOUT_POUT, MAX17616_IOUT_FAULT_OUT_OC_UV_LO, + "Output overcurrent and low voltage fault occurred", true + }, + { + MAX17616_FAULT_GRP_IOUT_POUT, MAX17616_IOUT_FAULT_OUT_OC_FAULT, + "Output overcurrent fault occurred", true + }, + + /* Output Voltage Faults */ + { + MAX17616_FAULT_GRP_VOUT, MAX17616_VOUT_FAULT_VOUT_UV_WARNING, + "Output has gone below the output undervoltage threshold", true + }, + { + MAX17616_FAULT_GRP_VOUT, MAX17616_VOUT_FAULT_VOUT_OV_WARNING, + "Output regulation event has occurred", true + }, + + /* Manufacturer Specific Faults */ + { + MAX17616_FAULT_GRP_MFR_SPECIFIC, MAX17616_MFR_FAULT_REVERSE_CURRENT, + "Reverse current fault occurred", true + }, + { + MAX17616_FAULT_GRP_MFR_SPECIFIC, MAX17616_MFR_FAULT_OUTPUT_SHORT_CIRCUIT, + "Output short circuit fault occurred", true + }, + { + MAX17616_FAULT_GRP_MFR_SPECIFIC, MAX17616_MFR_FAULT_SOFT_START, + "Soft start failed", true + }, + { + MAX17616_FAULT_GRP_MFR_SPECIFIC, MAX17616_MFR_FAULT_IMON_PIN, + "IMON pin fault", true + }, + { + MAX17616_FAULT_GRP_MFR_SPECIFIC, MAX17616_MFR_FAULT_SETI_PIN, + "SETI pin fault", true + }, +}; + +/** + * @brief Get human-readable description for a specific fault + * @param group - Fault group identifier + * @param bit - Fault bit position + * @return Pointer to fault description string or NULL if not found + */ +const char *max17616_get_fault_description(uint16_t group, uint8_t bit) +{ + size_t num_faults = sizeof(fault_descriptions) / sizeof(fault_descriptions[0]); + + for (size_t i = 0; i < num_faults; i++) { + if (fault_descriptions[i].group == group && + fault_descriptions[i].bit == bit && + fault_descriptions[i].is_supported) { + return fault_descriptions[i].description; + } + } + + return NULL; /* Return NULL for unknown faults */ +} diff --git a/drivers/power/max17616/max17616.h b/drivers/power/max17616/max17616.h new file mode 100644 index 00000000000..ca530cba8eb --- /dev/null +++ b/drivers/power/max17616/max17616.h @@ -0,0 +1,484 @@ +/***************************************************************************//** +* @file max17616.h +* @brief Header file of the MAX17616 Driver +* @author Carlos Jones (carlosjr.jones@analog.com) +******************************************************************************** +* Copyright 2025(c) Analog Devices, Inc. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, +* this list of conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, +* this list of conditions and the following disclaimer in the documentation +* and/or other materials provided with the distribution. +* +* 3. Neither the name of Analog Devices, Inc. nor the names of its +* contributors may be used to endorse or promote products derived from this +* software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ + +#ifndef __MAX17616_H__ +#define __MAX17616_H__ + +#include +#include +#include +#include "no_os_util.h" +#include "no_os_i2c.h" + +#define MAX17616_DS_0B (0 << 8) /* Send-only command */ +#define MAX17616_DS_1B (1 << 8) /* Byte */ +#define MAX17616_DS_2B (2 << 8) /* Word */ +#define MAX17616_DS_3B (3 << 8) /* Block of size 3*/ +#define MAX17616_DS_6B (6 << 8) /* Block of size 6*/ +#define MAX17616_DS_10B (10 << 8) /* Block of size 10*/ +#define MAX17616_DF_NONE (0 << 12) /* None */ +#define MAX17616_DF_LINEAR11 (1 << 12) /* Linear 11 */ +#define MAX17616_DF_LINEAR16 (2 << 12) /* Linear 16 */ +#define MAX17616_DF_DIRECT (3 << 12) /* Direct */ +#define MAX17616_DF_VID (4 << 12) /* VID */ +#define MAX17616_DF_IEEE754 (5 << 12) /* IEEE754 */ + +#define MAX17616_CMD(x) ((uint8_t)(x & 0xFF)) +#define MAX17616_DATA_SIZE(x) no_os_field_get(NO_OS_GENMASK(11,8), x) +#define MAX17616_DATA_FORMAT(x) no_os_field_get(NO_OS_GENMASK(15,12), x) + +#define MAX17616_OPERATION (MAX17616_DS_1B | 0x01) +#define MAX17616_CLEAR_FAULTS (MAX17616_DS_0B | 0x03) +#define MAX17616_CAPABILITY (MAX17616_DS_1B | 0x19) +#define MAX17616_SMBALERT_MASK (MAX17616_DS_1B | 0x1B) +#define MAX17616_VOUT_UV_FAULT_LIMIT (MAX17616_DS_1B | 0x44) +#define MAX17616_STATUS_BYTE (MAX17616_DS_1B | 0x78) +#define MAX17616_STATUS_WORD (MAX17616_DS_2B | 0x79) +#define MAX17616_STATUS_VOUT (MAX17616_DS_1B | 0x7A) +#define MAX17616_STATUS_IOUT (MAX17616_DS_1B | 0x7B) +#define MAX17616_STATUS_INPUT (MAX17616_DS_1B | 0x7C) +#define MAX17616_STATUS_TEMPERATURE (MAX17616_DS_1B | 0x7D) +#define MAX17616_STATUS_CML (MAX17616_DS_1B | 0x7E) +#define MAX17616_STATUS_MFR_SPECIFIC (MAX17616_DS_1B | 0x80) +#define MAX17616_READ_VIN (MAX17616_DF_DIRECT | MAX17616_DS_2B | 0x88) +#define MAX17616_READ_VOUT (MAX17616_DF_DIRECT | MAX17616_DS_2B | 0x8B) +#define MAX17616_READ_IOUT (MAX17616_DF_DIRECT | MAX17616_DS_2B | 0x8C) +#define MAX17616_READ_TEMPERATURE_1 (MAX17616_DF_DIRECT | MAX17616_DS_2B | 0x8D) +#define MAX17616_PMBUS_REVISION (MAX17616_DS_2B | 0x98) + +#define MAX17616_MFR_ID (MAX17616_DS_6B | 0x99) +#define MAX17616_MFR_MODEL (MAX17616_DS_10B | 0x9A) +#define MAX17616_MFR_REVISION (MAX17616_DS_3B | 0x9B) +#define MAX17616_SET_CLMODE (MAX17616_DS_1B | 0xC4) +#define MAX17616_SET_ISTART_RATIO (MAX17616_DS_1B | 0xC5) +#define MAX17616_SET_TSTOC (MAX17616_DS_1B | 0xC6) +#define MAX17616_SET_ISTLIM (MAX17616_DS_1B | 0xC7) +#define MAX17616_IC_DEVICE_ID (MAX17616_DS_10B | 0xAD) +#define MAX17616_IC_DEVICE_REV (MAX17616_DS_3B | 0xAE) + +/* Status types masks */ +#define MAX17616_STATUS_BYTE_TYPE_MSK 0x01 +#define MAX17616_STATUS_VOUT_TYPE_MSK 0x02 +#define MAX17616_STATUS_IOUT_TYPE_MSK 0x04 +#define MAX17616_STATUS_INPUT_TYPE_MSK 0x08 +#define MAX17616_STATUS_TEMP_TYPE_MSK 0x10 +#define MAX17616_STATUS_CML_TYPE_MSK 0x20 +#define MAX17616_STATUS_MFR_SPECIFIC_TYPE_MSK 0x40 +#define MAX17616_STATUS_WORD_TYPE_MSK 0x80 +#define MAX17616_STATUS_ALL_TYPE_MSK 0xFF + +#ifdef TEST +#define STATIC +#else +#define STATIC static +#endif + +enum max17616_chip_id { + ID_MAX17616, + ID_MAX17616A, + ID_MAX17616_CHIP_COUNT +}; + +/* Current limit mode options */ +enum max17616_current_limit_mode { + MAX17616_CLMODE_LATCH_OFF = 0x00, /* 00b - latch-off mode */ + MAX17616_CLMODE_CONTINUOUS = 0x40, /* 01b - continuous mode */ + MAX17616_CLMODE_AUTO_RETRY = 0x80 /* 10b - auto-retry mode */ +}; + +/* Current start ratio options - fractions of hardware-configured current limit + * Note: The actual current limit is set by external resistor on SETI pin */ +enum max17616_istart_ratio { + MAX17616_ISTART_FULL, /* 000b = Current Limit (1/1) */ + MAX17616_ISTART_HALF, /* 001b = Current Limit / 2 */ + MAX17616_ISTART_QUARTER, /* 010b = Current Limit / 4 */ + MAX17616_ISTART_EIGHTH, /* 011b = Current Limit / 8 */ + MAX17616_ISTART_SIXTEENTH /* 100b = Current Limit / 16 */ +}; + +/* Overcurrent timeout duration options */ +enum max17616_overcurrent_timeout { + MAX17616_TIMEOUT_400US, /* 00b = 400 microseconds */ + MAX17616_TIMEOUT_1MS, /* 01b = 1 millisecond */ + MAX17616_TIMEOUT_4MS, /* 10b = 4 milliseconds */ + MAX17616_TIMEOUT_24MS /* 11b = 24 milliseconds */ +}; + +/* Overcurrent limit ratio options - multiples of hardware current limit */ +enum max17616_overcurrent_limit { + MAX17616_OC_LIMIT_1_25, /* 00b = 1.25:1 ratio */ + MAX17616_OC_LIMIT_1_50, /* 01b = 1.50:1 ratio */ + MAX17616_OC_LIMIT_1_75, /* 10b = 1.75:1 ratio */ + MAX17616_OC_LIMIT_2_00 /* 11b = 2.00:1 ratio */ +}; + +/* Nominal voltage selection options for VOUT UV fault limit (bits 4:2) */ +enum max17616_nominal_voltage { + MAX17616_NOMINAL_5V, /* 000b = 5V */ + MAX17616_NOMINAL_9V, /* 001b = 9V */ + MAX17616_NOMINAL_12V, /* 010b = 12V */ + MAX17616_NOMINAL_24V, /* 011b = 24V */ + MAX17616_NOMINAL_36V, /* 100b = 36V */ + MAX17616_NOMINAL_48V, /* 101b = 48V */ + MAX17616_NOMINAL_60V, /* 110b = 60V */ + MAX17616_NOMINAL_72V /* 111b = 72V */ +}; + +/* PGOOD rising threshold options for VOUT UV fault limit (bits 1:0) */ +enum max17616_pgood_threshold { + MAX17616_PGOOD_MINUS_10_PERCENT = 0x00, /* 00b = -10% */ + MAX17616_PGOOD_MINUS_20_PERCENT = 0x01, /* 01b = -20% */ + MAX17616_PGOOD_MINUS_30_PERCENT = 0x02 /* 10b = -30% */ +}; + +/* Bit field macros for current limit mode */ +#define MAX17616_CLMODE_BITS_MASK 0xC0 +#define MAX17616_CLMODE_LATCH_OFF_BITS 0x00 +#define MAX17616_CLMODE_CONTINUOUS_BITS 0x40 +#define MAX17616_CLMODE_AUTO_RETRY_BITS 0x80 + +/* Bit field macros for ISTART ratio */ +#define MAX17616_ISTART_BITS_MASK 0x0F +#define MAX17616_ISTART_FULL_BITS 0x00 +#define MAX17616_ISTART_HALF_BITS 0x01 +#define MAX17616_ISTART_QUARTER_BITS 0x02 +#define MAX17616_ISTART_EIGHTH_BITS 0x03 +#define MAX17616_ISTART_SIXTEENTH_BITS 0x04 + +/* Bit field macros for overcurrent timeout */ +#define MAX17616_TIMEOUT_BITS_MASK 0x03 +#define MAX17616_TIMEOUT_400US_BITS 0x00 +#define MAX17616_TIMEOUT_1MS_BITS 0x01 +#define MAX17616_TIMEOUT_4MS_BITS 0x02 +#define MAX17616_TIMEOUT_24MS_BITS 0x03 + +/* Bit field macros for overcurrent limit */ +#define MAX17616_OC_LIMIT_BITS_MASK 0x03 +#define MAX17616_OC_LIMIT_1_25_BITS 0x00 +#define MAX17616_OC_LIMIT_1_50_BITS 0x01 +#define MAX17616_OC_LIMIT_1_75_BITS 0x02 +#define MAX17616_OC_LIMIT_2_00_BITS 0x03 + +/* Bit field macros for nominal voltage configuration */ +#define MAX17616_NOMINAL_VOLTAGE_BITS_MASK 0x07 +#define MAX17616_NOMINAL_5V_BITS 0x00 +#define MAX17616_NOMINAL_9V_BITS 0x01 +#define MAX17616_NOMINAL_12V_BITS 0x02 +#define MAX17616_NOMINAL_24V_BITS 0x03 +#define MAX17616_NOMINAL_36V_BITS 0x04 +#define MAX17616_NOMINAL_48V_BITS 0x05 +#define MAX17616_NOMINAL_60V_BITS 0x06 +#define MAX17616_NOMINAL_72V_BITS 0x07 + +/* Bit field macros for PGOOD threshold configuration */ +#define MAX17616_PGOOD_THRESHOLD_BITS_MASK 0x03 +#define MAX17616_PGOOD_MINUS_10_PERCENT_BITS 0x00 +#define MAX17616_PGOOD_MINUS_20_PERCENT_BITS 0x01 +#define MAX17616_PGOOD_MINUS_30_PERCENT_BITS 0x02 + +/* Value types for high-level read/write functions */ +enum max17616_value_type { + MAX17616_VIN, /* Input voltage in volts */ + MAX17616_VOUT, /* Output voltage in volt */ + MAX17616_IOUT, /* Output current in amps */ + MAX17616_TEMP, /* Temperature in degreesCelsius */ + MAX17616_POWER, /* Power in watts */ +}; + +/* Status structure */ +struct max17616_status { + uint16_t word; + uint8_t byte; + uint8_t vout; + uint8_t iout; + uint8_t input; + uint8_t temperature; + uint8_t cml; + uint8_t other; + uint8_t mfr_specific; +}; + +struct max17616_chip_specific_info { + char *ic_dev_id; + uint8_t ic_dev_id_size; +}; + +struct max17616_chip_info { + char *mfr_id; + uint8_t mfr_id_size; + char *mfr_rev; + uint8_t mfr_rev_size; + uint8_t pmbus_rev; + struct max17616_chip_specific_info specific_info[ID_MAX17616_CHIP_COUNT]; +}; + +struct max17616_dev { + struct no_os_i2c_desc *i2c_desc; + enum max17616_chip_id chip_id; + struct max17616_chip_info *chip_info; +}; + +struct max17616_init_param { + struct no_os_i2c_init_param *i2c_init; + enum max17616_chip_id chip_id; + struct max17616_chip_info chip_info; +}; + +enum max17616_status_byte { + MAX17616_STATUS_BIT_GENERAL, // Not supported + MAX17616_STATUS_BIT_CML, // Comms, memory, or logic Fault + MAX17616_STATUS_BIT_TEMPERATURE, // Temperature Fault or Warning + MAX17616_STATUS_BIT_VIN_UV, // Input Under Voltage Fault + MAX17616_STATUS_BIT_IOUT_OC, // Output Over Current Fault + MAX17616_STATUS_BIT_VOUT_OV, // An output overvoltage fault occurred + MAX17616_STATUS_BIT_OFF, // Max17616 is not enabled + MAX17616_STATUS_BIT_BUSY // Not supported +}; + +enum max17616_status_word_byte_high { + MAX17616_STATUS_BIT_STARTUP, // Not supported + MAX17616_STATUS_BIT_OTHER, // Not supported + MAX17616_STATUS_BIT_FANS, // Not supported + MAX17616_STATUS_BIT_POWER_GOOD, // Not supported + MAX17616_STATUS_BIT_MFR, // Manufacturer specific Fault + MAX17616_STATUS_BIT_INPUT, // Input V, I, or P Fault + MAX17616_STATUS_BIT_IOUT_POUT, // Output current or power Fault + MAX17616_STATUS_BIT_VOUT // Output voltage Fault +}; + +enum max17616_general_bit_fault_byte { + MAX17616_GENERAL_FAULT_NS_BIT0, // Not supported + MAX17616_GENERAL_FAULT_NS_BIT1, // Not supported + MAX17616_GENERAL_FAULT_NS_BIT2, // Not supported + MAX17616_GENERAL_FAULT_NS_BIT3, // Not supported + MAX17616_GENERAL_FAULT_NS_BIT4, // Not supported + MAX17616_GENERAL_FAULT_NS_BIT5, // Not supported + MAX17616_GENERAL_FAULT_NS_BIT6, // Not supported + MAX17616_GENERAL_FAULT_NS_BIT7 // Not supported +}; + +enum max17616_cml_bit_fault_byte { + MAX17616_CML_FAULT_NS_BIT0, // Not supported + MAX17616_CML_FAULT_OTHER, // Communications other error + MAX17616_CML_FAULT_NS_BIT2, // Not supported + MAX17616_CML_FAULT_NS_BIT3, // Not supported + MAX17616_CML_FAULT_MEM_ERROR, // Memory Error detected + MAX17616_CML_FAULT_PEC_FAIL, // Packet error checking failed + MAX17616_CML_FAULT_DATA, // Invalid or unsupported data received + MAX17616_CML_FAULT_CMD // Invalid or unsupported command received +}; + +enum max17616_temperature_bit_fault_byte { + MAX17616_TEMPERATURE_FAULT_NS_BIT0, // Not supported + MAX17616_TEMPERATURE_FAULT_NS_BIT1, // Not supported + MAX17616_TEMPERATURE_FAULT_NS_BIT2, // Not supported + MAX17616_TEMPERATURE_FAULT_NS_BIT3, // Not supported + MAX17616_TEMPERATURE_FAULT_UT_FAULT, // Not supported + MAX17616_TEMPERATURE_FAULT_UT_WARNING, // Not supported + MAX17616_TEMPERATURE_FAULT_OT_WARNING, // Not supported + MAX17616_TEMPERATURE_FAULT_OT_FAULT // An overtemperature fault occurred +}; + +enum max17616_input_fault_bit { + MAX17616_INPUT_FAULT_PIN_OP_WARNING, // Not supported + MAX17616_INPUT_FAULT_IIN_OC_WARNING, // Not supported + MAX17616_INPUT_FAULT_IIN_OC_FAULT, // Not supported + MAX17616_INPUT_FAULT_UNIT_OFF, // Not supported + MAX17616_INPUT_FAULT_VIN_UV_FAULT, // An input undervoltage fault occurred + MAX17616_INPUT_FAULT_VIN_UV_WARNING, // Not supported + MAX17616_INPUT_FAULT_VIN_OV_WARNING, // Not supported + MAX17616_INPUT_FAULT_VIN_OV_FAULT // An input overvoltage fault occurred +}; + +enum max17616_iout_fault_bit { + MAX17616_IOUT_FAULT_NS_BIT0, // An output overcurrent fault occurred + MAX17616_IOUT_FAULT_NS_BIT1, // Not supported + MAX17616_IOUT_FAULT_NS_BIT2, // Not supported + MAX17616_IOUT_FAULT_NS_BIT3, // Not supported + MAX17616_IOUT_FAULT_NS_BIT4, // Not supported + MAX17616_IOUT_FAULT_OUT_OC_WARNING, // Not supported + MAX17616_IOUT_FAULT_OUT_OC_UV_LO, // An output overcurrent and low voltage fault occurred + MAX17616_IOUT_FAULT_OUT_OC_FAULT // An output overcurrent fault occurred +}; + +enum max17616_vout_fault_bit { + MAX17616_VOUT_FAULT_VOUT_TRACKING_ERROR, // Not supported + MAX17616_VOUT_FAULT_TOFF_MAX_WARNING, // Not supported + MAX17616_VOUT_FAULT_TON_MAX_FAULT, // Not supported + MAX17616_VOUT_FAULT_VOUT_MAX_WARNING, // Not supported + MAX17616_VOUT_FAULT_VOUT_UV_FAULT, // Not supported + MAX17616_VOUT_FAULT_VOUT_UV_WARNING, // Output has gone below the output undervoltage threshold + MAX17616_VOUT_FAULT_VOUT_OV_WARNING, // Output regulation event has occurred + MAX17616_VOUT_FAULT_VOUT_OV_FAULT // Not supported +}; + +enum max17616_mfr_specific_fault_bit { + MAX17616_MFR_FAULT_NS_BIT0, // Not supported + MAX17616_MFR_FAULT_NS_BIT1, // Not supported + MAX17616_MFR_FAULT_REVERSE_CURRENT, // A reverse current fault occurred + MAX17616_MFR_FAULT_OUTPUT_SHORT_CIRCUIT, // An output short circuit fault occurred + MAX17616_MFR_FAULT_NS_BIT4, // Not supported + MAX17616_MFR_FAULT_SOFT_START, // Soft start failed + MAX17616_MFR_FAULT_IMON_PIN, // IMON pin fault + MAX17616_MFR_FAULT_SETI_PIN // SETI pin fault +}; + +/* Fault Management Module Definitions */ + +/* Fault group identifiers matching STATUS_WORD bits */ +enum max17616_fault_group { + MAX17616_FAULT_GRP_NONE = 0x00, + MAX17616_FAULT_GRP_CML = 0x01, + MAX17616_FAULT_GRP_TEMPERATURE = 0x02, + MAX17616_FAULT_GRP_VIN_UV = 0x04, + MAX17616_FAULT_GRP_IOUT_OC = 0x08, + MAX17616_FAULT_GRP_VOUT_OV = 0x10, + MAX17616_FAULT_GRP_INPUT = 0x20, + MAX17616_FAULT_GRP_IOUT_POUT = 0x40, + MAX17616_FAULT_GRP_VOUT = 0x80, + MAX17616_FAULT_GRP_MFR_SPECIFIC = 0x100, + MAX17616_FAULT_GRP_ALL = 0xFFFF +}; + +/* Individual fault information structure */ +struct max17616_fault_info { + uint16_t group; + uint8_t bit; + const char *description; + bool is_supported; +}; + +/* MAX17616 telemetry data */ +struct max17616_telemetry { + int vin; /* Input voltage in volts */ + int vout; /* Output voltage in volts */ + int iout; /* Output current in amps */ + int pin; /* Input power in watts */ + int pout; /* Output power in watts */ + int temp1; /* Temperature in degrees Celsius */ + uint8_t valid_mask; /* Bitmask indicating which values are valid */ +}; + +/* Initialize the device structure */ +int max17616_init(struct max17616_dev **dev, + struct max17616_init_param *init_param); + +/* Free or remove device instance */ +int max17616_remove(struct max17616_dev *dev); + +/* Clear status registers */ +int max17616_clear_faults(struct max17616_dev *dev); + +/* Perform a PMBus write_byte operation */ +int max17616_write_byte(struct max17616_dev *dev, uint8_t cmd, uint8_t value); + +/* Read a block of bytes */ +int max17616_read_block_data(struct max17616_dev *dev, uint8_t cmd, + uint8_t *data, size_t nbytes); + +/* Perform a PMBus read_word operation */ +int max17616_read_word(struct max17616_dev *dev, uint8_t cmd, uint16_t *word); + +/* Send a PMBus command to the device */ +int max17616_send_byte(struct max17616_dev *dev, uint8_t cmd); + +/* Read a single byte from the device */ +int max17616_read_byte(struct max17616_dev *dev, uint8_t cmd, uint8_t *data); + +/* Fault Management Module Functions */ +int max17616_read_status(struct max17616_dev *dev, + struct max17616_status *status); + +/* Get human-readable description for a specific fault */ +const char *max17616_get_fault_description(uint16_t group, uint8_t bit); + +/* High-level value reading functions */ +int max17616_read_value(struct max17616_dev *dev, + enum max17616_value_type value_type, int *value); + +/* Enhanced operation control functions */ +int max17616_set_operation_state(struct max17616_dev *dev, bool enable); +int max17616_get_operation_state(struct max17616_dev *dev, bool *enabled); + +/* Manufacturer-specific command functions */ +int max17616_set_current_limit_mode(struct max17616_dev *dev, + enum max17616_current_limit_mode clmode); +int max17616_get_current_limit_mode(struct max17616_dev *dev, + enum max17616_current_limit_mode *clmode); +int max17616_set_istart_ratio(struct max17616_dev *dev, + enum max17616_istart_ratio ratio); +int max17616_get_istart_ratio(struct max17616_dev *dev, + enum max17616_istart_ratio *istart_ratio); +int max17616_set_overcurrent_timeout(struct max17616_dev *dev, + enum max17616_overcurrent_timeout timeout); +int max17616_get_overcurrent_timeout(struct max17616_dev *dev, + enum max17616_overcurrent_timeout *timeout); +int max17616_set_overcurrent_limit(struct max17616_dev *dev, + enum max17616_overcurrent_limit limit); +int max17616_get_overcurrent_limit(struct max17616_dev *dev, + enum max17616_overcurrent_limit *istlim); + +/* VOUT UV fault limit configuration functions */ +int max17616_set_vout_uv_fault_limit_config(struct max17616_dev *dev, + enum max17616_nominal_voltage voltage, + enum max17616_pgood_threshold threshold); +int max17616_get_vout_uv_fault_limit_config(struct max17616_dev *dev, + enum max17616_nominal_voltage *voltage, + enum max17616_pgood_threshold *threshold); + +/* PMBus capability function */ +int max17616_read_capability(struct max17616_dev *dev, uint8_t *capability); + +/* Comprehensive telemetry functions */ +int max17616_read_telemetry_all(struct max17616_dev *dev, + struct max17616_telemetry *telemetry); + +/* Read STATUS_BYTE register */ +int max17616_read_status_byte(struct max17616_dev *dev, uint8_t *status_byte); + +/* Read individual status registers */ +int max17616_read_status_vout(struct max17616_dev *dev, uint8_t *status_vout); +int max17616_read_status_iout(struct max17616_dev *dev, uint8_t *status_iout); +int max17616_read_status_input(struct max17616_dev *dev, uint8_t *status_input); +int max17616_read_status_temperature(struct max17616_dev *dev, + uint8_t *status_temperature); +int max17616_read_status_cml(struct max17616_dev *dev, uint8_t *status_cml); +int max17616_read_status_mfr_specific(struct max17616_dev *dev, + uint8_t *status_mfr); + +/* Device identification and verification functions */ +int max17616_verify_manufacturer_id(struct max17616_dev *dev); +int max17616_identify_chip_variant(struct max17616_dev *dev); +int max17616_verify_pmbus_revision(struct max17616_dev *dev); + +#endif /* __MAX17616_H__ */ diff --git a/projects/max17616/Makefile b/projects/max17616/Makefile new file mode 100644 index 00000000000..b5686d677dd --- /dev/null +++ b/projects/max17616/Makefile @@ -0,0 +1,9 @@ +EXAMPLE ?= basic + +include ../../tools/scripts/generic_variables.mk + +include ../../tools/scripts/examples.mk + +include src.mk + +include ../../tools/scripts/generic.mk diff --git a/projects/max17616/README.rst b/projects/max17616/README.rst new file mode 100644 index 00000000000..bb4ad8fc042 --- /dev/null +++ b/projects/max17616/README.rst @@ -0,0 +1,163 @@ +Evaluating the MAX17616 +======================= + +.. no-os-doxygen:: + +.. contents:: + :depth: 3 + +Supported Evaluation Boards +--------------------------- + +* `MAX17616EVKIT# `_ +* `MAX17616AEVKIT# `_ + +Overview +-------- + +The MAX17616EVKIT# evaluation circuit features the MAX17616 eFuse setup for 5V +to 28V operation with a 7A auto-retry current limit. A 3.3V buck regulator +provides a voltage for pull-ups and logic to run indicator LEDs on the board. + +While the MAX17616AEVKIT# evaluation kit (EV kit) features the MAX17616A eFuse +setup for 5V to 28V operation with a 2A auto-retry current limit. A 3.3V buck +regulator provides a voltage for pull-ups and logic to run indicator LEDs on the +board. + +Both boards include an additional external N-channel FET for reverse conduction +protection. + +Applications +------------ + +* Input Voltage and Output Overcurrent Protections +* Loss of Ground Protection +* Surge Protection + +Hardware Specifications +----------------------- + +Power Supply Requirements +^^^^^^^^^^^^^^^^^^^^^^^^^ + +For this specific project an external power supply with output of +4V to +75V +can be used to power up the demo board. + +**Pin Description** + + +----------+----------------------------+ + | Name | Description | + +----------+----------------------------+ + | VIN | Power Supply, +4V - +75V | + +----------+----------------------------+ + | GND | Connect to Ground | + +----------+----------------------------+ + | VOUT | Connect to Load | + +----------+----------------------------+ + | IMON | Do Not Connect | + +----------+----------------------------+ + | SETI | Do Not Connect | + +----------+----------------------------+ + | SCL | I2C Serial Clock | + +----------+----------------------------+ + | SDA | I2C Serial Data | + +----------+----------------------------+ + +**Hardware Bringup** + +For reference, consult the Quick Start Procedure section in the user guide for the corresponding demo board: +`MAX17616EVKIT user guide `_ +`MAX17616AEVKIT user guide `_ + +No-OS Build Setup +----------------- + +Please see: https://wiki.analog.com/resources/no-os/build + +No-OS Supported Examples +------------------------ + +The initialization data used in the examples is taken out from: +`Project Common Data Path `_ + +The macros used in Common Data are defined in platform specific files found in: +`Project Platform Configuration Path `_ + +Basic example +^^^^^^^^^^^^^ + +This is a simple example that initializes the MAX17616, and performs telemetry +readings of the voltage, current and temperature. Status bytes/words are also +monitored in the example. + +In order to build the basic example make sure you have the following +configuration in the Makefile +`Basic Example Makefile `_ + +.. code-block:: bash + + EXAMPLE ?= basic + +IIO example +^^^^^^^^^^^ + +This project is actually a IIOD demo for MAX32655FTHR evaluation board. +The project launches a IIOD server on the board so that the user may connect +to it via an IIO client. + +If you are not familiar with ADI IIO Application, please take a look at: +`IIO No-OS `_ + +If you are not familiar with ADI IIO-Oscilloscope Client, please take a look at: +`IIO Oscilloscope `_ + +The No-OS IIO Application together with the No-OS IIO MAX17616 driver take care of +all the back-end logic needed to setup the IIO server. + +This example initializes the IIO device and calls the IIO app as shown in: +`IIO Example `_ + +In order to build the IIO project make sure you have the following +configuration in the +`IIO Example Makefile `_ + +.. code-block:: bash + + EXAMPLE ?= iio_example + +No-OS Supported Platforms +------------------------- + +Maxim Platform +^^^^^^^^^^^^^^ + +**Used hardware** + +* `MAX32655FTHR `_ + +**Connections**: + ++-----------------------------+------------+------------------------------------+----------+-----------------------------+ +| MAX17616EVKIT# Pin Number | Mnemonic | Function | Mnemonic | MAX32655FTHR Pin Number | ++-----------------------------+------------+------------------------------------+----------+-----------------------------+ +| 1 | VEMI | External Power Supply, 4V - 75V | | Do Not Connect | ++-----------------------------+------------+------------------------------------+----------+-----------------------------+ +| 2 | GND | Connect to Ground | | GND | ++-----------------------------+------------+------------------------------------+----------+-----------------------------+ +| 3 | VOUT | May connect to Scopy/Load | | Do Not Connect | ++-----------------------------+------------+------------------------------------+----------+-----------------------------+ +| 10 | SCL | I2C Serial Clock | I2C2_SCL | P0_30 | ++-----------------------------+------------+------------------------------------+----------+-----------------------------+ +| 11 | SDA | I2C Serial Data | I2C2_SDA | P0_31 | ++-----------------------------+------------+------------------------------------+----------+-----------------------------+ + +**Build Command** + +.. code-block:: bash + + # to delete current build + make TARGET=max32655 reset && make TARGET=max32655 clean + # to build the project + make TARGET=max32655 + # to flash the code + make TARGET=max32655 run diff --git a/projects/max17616/builds.json b/projects/max17616/builds.json new file mode 100644 index 00000000000..3aebfdc2042 --- /dev/null +++ b/projects/max17616/builds.json @@ -0,0 +1,10 @@ +{ + "maxim": { + "basic_example_max32666": { + "flags" : "EXAMPLE=basic TARGET=max32665" + }, + "iio_example_max32666": { + "flags" : "EXAMPLE=iio_example TARGET=max32665" + } + } +} diff --git a/projects/max17616/src.mk b/projects/max17616/src.mk new file mode 100644 index 00000000000..de8058bb2dd --- /dev/null +++ b/projects/max17616/src.mk @@ -0,0 +1,33 @@ +INCS += $(INCLUDE)/no_os_delay.h \ + $(INCLUDE)/no_os_error.h \ + $(INCLUDE)/no_os_list.h \ + $(INCLUDE)/no_os_gpio.h \ + $(INCLUDE)/no_os_dma.h \ + $(INCLUDE)/no_os_print_log.h \ + $(INCLUDE)/no_os_i2c.h \ + $(INCLUDE)/no_os_irq.h \ + $(INCLUDE)/no_os_pwm.h \ + $(INCLUDE)/no_os_rtc.h \ + $(INCLUDE)/no_os_uart.h \ + $(INCLUDE)/no_os_lf256fifo.h \ + $(INCLUDE)/no_os_util.h \ + $(INCLUDE)/no_os_units.h \ + $(INCLUDE)/no_os_alloc.h \ + $(INCLUDE)/no_os_mutex.h \ + $(INCLUDE)/no_os_crc8.h + +SRCS += $(NO-OS)/util/no_os_lf256fifo.c \ + $(DRIVERS)/api/no_os_i2c.c \ + $(DRIVERS)/api/no_os_dma.c \ + $(DRIVERS)/api/no_os_uart.c \ + $(DRIVERS)/api/no_os_irq.c \ + $(DRIVERS)/api/no_os_gpio.c \ + $(DRIVERS)/api/no_os_pwm.c \ + $(NO-OS)/util/no_os_util.c \ + $(NO-OS)/util/no_os_list.c \ + $(NO-OS)/util/no_os_alloc.c \ + $(NO-OS)/util/no_os_mutex.c \ + $(NO-OS)/util/no_os_crc8.c + +INCS += $(DRIVERS)/power/max17616/max17616.h +SRCS += $(DRIVERS)/power/max17616/max17616.c diff --git a/projects/max17616/src/common/common_data.c b/projects/max17616/src/common/common_data.c new file mode 100644 index 00000000000..5dc8d8a40a4 --- /dev/null +++ b/projects/max17616/src/common/common_data.c @@ -0,0 +1,57 @@ +/***************************************************************************//** + * @file common_data.c + * @brief Defines common data to be used by max17616 examples. + * @author Carlos Jones (carlosjr.jones@analog.com) +******************************************************************************** + * Copyright 2025(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#include "common_data.h" + +struct no_os_uart_init_param uart_ip = { + .device_id = UART_DEVICE_ID, + .asynchronous_rx = UART_ASYNC_RX, + .baud_rate = UART_BAUDRATE, + .size = UART_SIZE, + .parity = UART_PARITY, + .stop = UART_STOP, + .extra = UART_EXTRA, + .platform_ops = UART_OPS, +}; + +struct no_os_i2c_init_param i2c_ip = { + .device_id = I2C_DEVICE_ID, + .max_speed_hz = I2C_CLK_SPEED, + .slave_address = I2C_ADDR, + .platform_ops = I2C_OPS, + .extra = I2C_EXTRA +}; + +struct max17616_init_param max17616_ip = { + .i2c_init = &i2c_ip, + .chip_id = ID_MAX17616, +}; diff --git a/projects/max17616/src/common/common_data.h b/projects/max17616/src/common/common_data.h new file mode 100644 index 00000000000..2fd7b47eed3 --- /dev/null +++ b/projects/max17616/src/common/common_data.h @@ -0,0 +1,45 @@ +/***************************************************************************//** + * @file common_data.h + * @brief Defines common data to be used by max17616 examples. + * @author Carlos Jones (carlosjr.jones@analog.com) +******************************************************************************** + * Copyright 2025(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef __COMMON_DATA_H__ +#define __COMMON_DATA_H__ + +#include "no_os_uart.h" +#include "no_os_i2c.h" +#include "max17616.h" +#include "parameters.h" + +extern struct no_os_uart_init_param uart_ip; +extern struct no_os_i2c_init_param i2c_ip; +extern struct max17616_init_param max17616_ip; + +#endif /* __COMMON_DATA_H__ */ diff --git a/projects/max17616/src/examples/basic/basic_example.c b/projects/max17616/src/examples/basic/basic_example.c new file mode 100644 index 00000000000..c43bda06182 --- /dev/null +++ b/projects/max17616/src/examples/basic/basic_example.c @@ -0,0 +1,390 @@ +/***************************************************************************//** + * @file basic_example.c + * @brief Basic example source file for max17616 project. + * @author Carlos Jones (carlosjr.jones@analog.com) +******************************************************************************** + * Copyright 2025(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#include "common_data.h" +#include "no_os_delay.h" +#include "no_os_print_log.h" +#include "max17616.h" +#include + +/** + * @brief Function pointer type for fault processing + * @param fault_group - Fault group identifier + * @param bit - Bit position + * @return Pointer to fault description string or NULL if not found + */ +typedef const char *(*fault_processor_t)(uint16_t fault_group, uint8_t bit); + +/** + * @brief Process fault bits using a function pointer + * @param fault_value - 8-bit fault register value + * @param fault_group - Fault group identifier + * @param fault_name - Name of the fault type for display + * @param processor - Function pointer to process individual faults + */ +static void process_fault_bits(uint8_t fault_value, uint16_t fault_group, + const char *fault_name, + fault_processor_t processor) +{ + const char *fault_desc; + + if (!fault_value) + return; + + pr_info("%s Faults: 0x%02X\n\r", fault_name, fault_value); + for (int bit = 0; bit < 8; bit++) { + if (fault_value & (1 << bit)) { + fault_desc = processor(fault_group, bit); + if (fault_desc) + pr_info(" [%d] %s\n\r", bit, fault_desc); + } + } +} + +/** + * @brief Display telemetry data in a formatted way + * @param telemetry - Telemetry structure to display + */ +static void display_telemetry(struct max17616_telemetry *telemetry) +{ + pr_info("=== MAX17616 Telemetry ===\n\r"); + + if (telemetry->valid_mask & NO_OS_BIT(0)) + pr_info("VIN: %d V\n\r", telemetry->vin); + + if (telemetry->valid_mask & NO_OS_BIT(1)) + pr_info("VOUT: %d V\n\r", telemetry->vout); + + if (telemetry->valid_mask & NO_OS_BIT(3)) + pr_info("IOUT: %d A\n\r", telemetry->iout); + + if (telemetry->valid_mask & NO_OS_BIT(4)) + pr_info("Temperature: %d °C\n\r", telemetry->temp1); + + if (telemetry->valid_mask & NO_OS_BIT(5)) + pr_info("Power: %d W\n\r", telemetry->pout); + + pr_info("\n\r"); +} + +/** + * @brief Display device-specific settings + * @param dev - MAX17616 device structure + */ +static void display_device_settings(struct max17616_dev *dev) +{ + enum max17616_current_limit_mode clmode; + enum max17616_istart_ratio istart_ratio; + enum max17616_overcurrent_timeout tstoc; + enum max17616_overcurrent_limit istlim; + bool operation_enabled; + int ret; + + pr_info("=== Device Settings ===\n\r"); + + ret = max17616_get_current_limit_mode(dev, &clmode); + if (ret == 0) { + const char *mode_str; + switch (clmode) { + case MAX17616_CLMODE_LATCH_OFF: + mode_str = "Latch-off"; + break; + case MAX17616_CLMODE_CONTINUOUS: + mode_str = "Continuous"; + break; + case MAX17616_CLMODE_AUTO_RETRY: + mode_str = "Auto-retry"; + break; + default: + mode_str = "Unknown"; + } + pr_info("Current Limit Mode: %s (0x%02X)\n\r", mode_str, (uint8_t)clmode); + } + + ret = max17616_get_istart_ratio(dev, &istart_ratio); + if (ret == 0) { + const char *ratio_str; + switch (istart_ratio) { + case MAX17616_ISTART_FULL: + ratio_str = "Full (I_limit)"; + break; + case MAX17616_ISTART_HALF: + ratio_str = "Half (I_limit/2)"; + break; + case MAX17616_ISTART_QUARTER: + ratio_str = "Quarter (I_limit/4)"; + break; + case MAX17616_ISTART_EIGHTH: + ratio_str = "Eighth (I_limit/8)"; + break; + case MAX17616_ISTART_SIXTEENTH: + ratio_str = "Sixteenth (I_limit/16)"; + break; + default: + ratio_str = "Unknown"; + } + pr_info("Current Start Ratio: %s (0x%02X)\n\r", ratio_str, + (uint8_t)istart_ratio); + } + + ret = max17616_get_overcurrent_timeout(dev, &tstoc); + if (ret == 0) { + const char *timeout_str; + switch (tstoc) { + case MAX17616_TIMEOUT_400US: + timeout_str = "400 microseconds"; + break; + case MAX17616_TIMEOUT_1MS: + timeout_str = "1 millisecond"; + break; + case MAX17616_TIMEOUT_4MS: + timeout_str = "4 milliseconds"; + break; + case MAX17616_TIMEOUT_24MS: + timeout_str = "24 milliseconds"; + break; + default: + timeout_str = "Unknown"; + } + pr_info("Overcurrent Timeout: %s (0x%02X)\n\r", timeout_str, (uint8_t)tstoc); + } + + ret = max17616_get_overcurrent_limit(dev, &istlim); + if (ret == 0) { + const char *limit_str; + switch (istlim) { + case MAX17616_OC_LIMIT_1_25: + limit_str = "1.25:1 ratio"; + break; + case MAX17616_OC_LIMIT_1_50: + limit_str = "1.50:1 ratio"; + break; + case MAX17616_OC_LIMIT_1_75: + limit_str = "1.75:1 ratio"; + break; + case MAX17616_OC_LIMIT_2_00: + limit_str = "2.00:1 ratio"; + break; + default: + limit_str = "Unknown"; + } + pr_info("Overcurrent Limit: %s (0x%02X)\n\r", limit_str, (uint8_t)istlim); + } + + /* Display VOUT UV fault limit configuration */ + enum max17616_nominal_voltage voltage; + enum max17616_pgood_threshold threshold; + ret = max17616_get_vout_uv_fault_limit_config(dev, &voltage, &threshold); + if (ret == 0) { + const char *voltage_str, *threshold_str; + + switch (voltage) { + case MAX17616_NOMINAL_5V: + voltage_str = "5V"; + break; + case MAX17616_NOMINAL_9V: + voltage_str = "9V"; + break; + case MAX17616_NOMINAL_12V: + voltage_str = "12V"; + break; + case MAX17616_NOMINAL_24V: + voltage_str = "24V"; + break; + case MAX17616_NOMINAL_36V: + voltage_str = "36V"; + break; + case MAX17616_NOMINAL_48V: + voltage_str = "48V"; + break; + case MAX17616_NOMINAL_60V: + voltage_str = "60V"; + break; + case MAX17616_NOMINAL_72V: + voltage_str = "72V"; + break; + default: + voltage_str = "Unknown"; + } + + switch (threshold) { + case MAX17616_PGOOD_MINUS_10_PERCENT: + threshold_str = "-10%"; + break; + case MAX17616_PGOOD_MINUS_20_PERCENT: + threshold_str = "-20%"; + break; + case MAX17616_PGOOD_MINUS_30_PERCENT: + threshold_str = "-30%"; + break; + default: + threshold_str = "Unknown"; + } + + pr_info("VOUT UV Fault Limit: %s nominal, %s PGOOD threshold (0x%02X)\n\r", + voltage_str, threshold_str, ((uint8_t)voltage << 2) | (uint8_t)threshold); + } + + ret = max17616_get_operation_state(dev, &operation_enabled); + if (ret == 0) + pr_info("Operation State: %s\n\r", + operation_enabled ? "ENABLED" : "DISABLED"); + + pr_info("\n\r"); +} + +/** + * @brief Display fault status in detail + * @param dev - MAX17616 device structure + */ +static void display_fault_status(struct max17616_dev *dev) +{ + struct max17616_status status; + int ret; + + pr_info("=== MAX17616 Status ===\n\r"); + ret = max17616_read_status(dev, &status); + if (ret) { + pr_err("Failed to read fault status: %d\n\r", ret); + pr_info("\n\r"); + return; + } + + if (status.word == 0) { + pr_info("No faults detected.\n\r"); + pr_info("\n\r"); + return; + } + + pr_info("=== FAULT STATUS ===\n\r"); + pr_info("STATUS_WORD: 0x%04X\n\r", status.word); + + /* Check individual fault registers */ + process_fault_bits(status.cml, MAX17616_FAULT_GRP_CML, + "CML", max17616_get_fault_description); + process_fault_bits(status.temperature, MAX17616_FAULT_GRP_TEMPERATURE, + "Temperature", max17616_get_fault_description); + process_fault_bits(status.input, MAX17616_FAULT_GRP_INPUT, + "Input", max17616_get_fault_description); + process_fault_bits(status.iout, MAX17616_FAULT_GRP_IOUT_POUT, + "Output Current", max17616_get_fault_description); + process_fault_bits(status.vout, MAX17616_FAULT_GRP_VOUT, + "Output Voltage", max17616_get_fault_description); + process_fault_bits(status.mfr_specific, MAX17616_FAULT_GRP_MFR_SPECIFIC, + "Manufacturer", max17616_get_fault_description); + + pr_info("\n\r"); +} + +int example_main(void) +{ + struct max17616_dev *max17616_dev; + struct no_os_uart_desc *uart_desc; + struct max17616_telemetry telemetry; + int ret; + + ret = no_os_uart_init(&uart_desc, &uart_ip); + if (ret) + return ret; + + no_os_uart_stdio(uart_desc); + pr_info("\e[2J\e[H"); + pr_info("MAX17616 basic example.\n\r"); + + ret = max17616_init(&max17616_dev, &max17616_ip); + if (ret) { + pr_err("Failed to initialize MAX17616: %d\n\r", ret); + goto exit; + } + + /* Display device settings once */ + display_device_settings(max17616_dev); + + while (1) { + /* Read telemetry */ + ret = max17616_read_telemetry_all(max17616_dev, &telemetry); + if (ret) + pr_err("Failed to read telemetry: %d\n\r", ret); + else + display_telemetry(&telemetry); + + /* Check for faults */ + display_fault_status(max17616_dev); + + pr_info("=== Manufacturer Features ===\n\r"); + + /* Read current limit mode */ + enum max17616_current_limit_mode clmode; + ret = max17616_get_current_limit_mode(max17616_dev, &clmode); + if (ret == 0) { + const char *mode_str; + switch (clmode) { + case MAX17616_CLMODE_LATCH_OFF: + mode_str = "Latch-off"; + break; + case MAX17616_CLMODE_CONTINUOUS: + mode_str = "Continuous"; + break; + case MAX17616_CLMODE_AUTO_RETRY: + mode_str = "Auto-retry"; + break; + default: + mode_str = "Unknown"; + } + pr_info("Current Limit Mode: %s (0x%02X)\n\r", mode_str, (uint8_t)clmode); + } + + /* Example of setting current limit mode */ + /* ret = max17616_set_current_limit_mode(max17616_dev, MAX17616_CLMODE_AUTO_RETRY); */ + + /* Example of setting current start ratio (hardware current limit / 2) */ + /* ret = max17616_set_istart_ratio(max17616_dev, MAX17616_ISTART_HALF); */ + + /* Example of setting overcurrent timeout */ + /* ret = max17616_set_overcurrent_timeout(max17616_dev, MAX17616_TIMEOUT_4MS); */ + + /* Example of setting overcurrent limit ratio */ + /* ret = max17616_set_overcurrent_limit(max17616_dev, MAX17616_OC_LIMIT_1_50); */ + + pr_info("\n\r"); + + no_os_mdelay(2000); + } + +exit: + if (ret) + pr_err("Error %d\n", ret); + if (max17616_dev) + max17616_remove(max17616_dev); + + return ret; +} diff --git a/projects/max17616/src/examples/iio_example/iio_example.c b/projects/max17616/src/examples/iio_example/iio_example.c new file mode 100644 index 00000000000..d1675a11b35 --- /dev/null +++ b/projects/max17616/src/examples/iio_example/iio_example.c @@ -0,0 +1,79 @@ +/***************************************************************************//** + * @file iio_example.c + * @brief IIO example source file for max17616 project. + * @author Carlos Jones (carlosjr.jones@analog.com) +******************************************************************************** + * Copyright 2025(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#include "iio_max17616.h" +#include "common_data.h" +#include "no_os_print_log.h" +#include "iio_app.h" + +int example_main() +{ + int ret; + struct max17616_iio_desc *max17616_iio_desc; + struct max17616_iio_desc_init_param max17616_iio_ip = { + .max17616_init_param = &max17616_ip, + }; + struct iio_app_desc *app; + struct iio_app_init_param app_init_param = { 0 }; + + ret = max17616_iio_init(&max17616_iio_desc, &max17616_iio_ip); + if (ret) + goto exit; + + struct iio_app_device iio_devices[] = { + { + .name = "max17616", + .dev = max17616_iio_desc, + .dev_descriptor = max17616_iio_desc->iio_dev, + } + }; + + app_init_param.devices = iio_devices; + app_init_param.nb_devices = NO_OS_ARRAY_SIZE(iio_devices); + app_init_param.uart_init_params = uart_ip; + + ret = iio_app_init(&app, app_init_param); + if (ret) + goto remove_iio_max17616; + + ret = iio_app_run(app); + + iio_app_remove(app); + +remove_iio_max17616: + max17616_iio_remove(max17616_iio_desc); +exit: + if (ret) + pr_info("Error!\n"); + + return ret; +} diff --git a/projects/max17616/src/examples/iio_example/iio_example.mk b/projects/max17616/src/examples/iio_example/iio_example.mk new file mode 100644 index 00000000000..7a99e4486d2 --- /dev/null +++ b/projects/max17616/src/examples/iio_example/iio_example.mk @@ -0,0 +1,3 @@ +IIOD=y +INCS += $(DRIVERS)/power/max17616/iio_max17616.h +SRCS += $(DRIVERS)/power/max17616/iio_max17616.c diff --git a/projects/max17616/src/platform/maxim/main.c b/projects/max17616/src/platform/maxim/main.c new file mode 100644 index 00000000000..1277c6f69f4 --- /dev/null +++ b/projects/max17616/src/platform/maxim/main.c @@ -0,0 +1,40 @@ +/***************************************************************************//** + * @file main.c + * @brief Main file for Maxim platform of max17616 project. + * @author Carlos Jones (carlosjr.jones@analog.com) +******************************************************************************** + * Copyright 2025(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#include "parameters.h" +#include "common_data.h" +#include "no_os_error.h" + +int main() +{ + return example_main(); +} diff --git a/projects/max17616/src/platform/maxim/parameters.c b/projects/max17616/src/platform/maxim/parameters.c new file mode 100644 index 00000000000..dcfd05194b5 --- /dev/null +++ b/projects/max17616/src/platform/maxim/parameters.c @@ -0,0 +1,43 @@ +/***************************************************************************//** + * @file parameters.c + * @brief Definition of Maxim platform data used by max17616 project. + * @author Carlos Jones (carlosjr.jones@analog.com) +******************************************************************************** + * Copyright 2025(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#include "parameters.h" + +/* UART */ +struct max_uart_init_param uart_extra = { + .flow = MAX_UART_FLOW_DIS +}; + +/* I2C */ +struct max_i2c_init_param i2c_extra = { + .vssel = MXC_GPIO_VSSEL_VDDIOH +}; diff --git a/projects/max17616/src/platform/maxim/parameters.h b/projects/max17616/src/platform/maxim/parameters.h new file mode 100644 index 00000000000..a3293251441 --- /dev/null +++ b/projects/max17616/src/platform/maxim/parameters.h @@ -0,0 +1,67 @@ +/***************************************************************************//** + * @file parameters.h + * @brief Definitions of Maxim platform data used by the max17616 project. + * @author Carlos Jones (carlosjr.jones@analog.com) +******************************************************************************** + * Copyright 2025(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*******************************************************************************/ +#ifndef __PARAMETERS_H__ +#define __PARAMETERS_H__ + +#include "maxim_irq.h" +#include "maxim_gpio.h" +#include "maxim_i2c.h" +#include "maxim_uart.h" +#include "maxim_uart_stdio.h" + +#ifdef IIO_SUPPORT +#define INTC_DEVICE_ID 0 +#endif + +/* UART */ +#define UART_DEVICE_ID 0 +#define UART_IRQ_ID UART1_IRQn +#define UART_ASYNC_RX false +#define UART_BAUDRATE 115200 +#define UART_SIZE NO_OS_UART_CS_8 +#define UART_PARITY NO_OS_UART_PAR_NO +#define UART_STOP NO_OS_UART_STOP_1_BIT +#define UART_OPS &max_uart_ops +#define UART_EXTRA &uart_extra + +/* I2C */ +#define I2C_OPS &max_i2c_ops +#define I2C_DEVICE_ID 2 +#define I2C_CLK_SPEED 100000 +#define I2C_ADDR 0x16 +#define I2C_EXTRA &i2c_extra + +extern struct max_uart_init_param uart_extra; +extern struct max_i2c_init_param i2c_extra; + +#endif /* __PARAMETERS_H__ */ diff --git a/projects/max17616/src/platform/maxim/platform_src.mk b/projects/max17616/src/platform/maxim/platform_src.mk new file mode 100644 index 00000000000..546839395db --- /dev/null +++ b/projects/max17616/src/platform/maxim/platform_src.mk @@ -0,0 +1,17 @@ +INCS += \ + $(PLATFORM_DRIVERS)/maxim_gpio.h \ + $(PLATFORM_DRIVERS)/maxim_gpio_irq.h \ + $(PLATFORM_DRIVERS)/maxim_irq.h \ + $(PLATFORM_DRIVERS)/../common/maxim_dma.h \ + $(PLATFORM_DRIVERS)/maxim_i2c.h \ + $(PLATFORM_DRIVERS)/maxim_uart.h \ + $(PLATFORM_DRIVERS)/maxim_uart_stdio.h + +SRCS += $(PLATFORM_DRIVERS)/maxim_delay.c \ + $(PLATFORM_DRIVERS)/maxim_gpio.c \ + $(PLATFORM_DRIVERS)/maxim_gpio_irq.c \ + $(PLATFORM_DRIVERS)/maxim_irq.c \ + $(PLATFORM_DRIVERS)/../common/maxim_dma.c \ + $(PLATFORM_DRIVERS)/maxim_i2c.c \ + $(PLATFORM_DRIVERS)/maxim_uart.c \ + $(PLATFORM_DRIVERS)/maxim_uart_stdio.c diff --git a/tests/drivers/power/max17616/project.yml b/tests/drivers/power/max17616/project.yml new file mode 100644 index 00000000000..446d4246645 --- /dev/null +++ b/tests/drivers/power/max17616/project.yml @@ -0,0 +1,106 @@ +--- +:project: + :use_exceptions: FALSE + :use_test_preprocessor: :all + :use_auxiliary_dependencies: TRUE + :build_root: build +# :release_build: TRUE + :test_file_prefix: test_ + :which_ceedling: gem + :ceedling_version: 1.0.1 + :default_tasks: + - test:all + +:environment: + +:extension: + :executable: .out + +:paths: + :test: + - test + :source: + - ../../../../drivers/power/max17616/ + :include: + - ../../../../include/** + - ../../../../drivers/power/max17616/** + - ../../../../iio/** + :support: + - test/support + :libraries: [] + +:files: + :test: + - test/test_max17616.c + - test/test_iio_max17616.c + :source: + - ../../../../drivers/power/max17616/max17616.c + - ../../../../drivers/power/max17616/iio_max17616.c + :support: + - test/support/test_max17616_support.c + - test/support/test_iio_max17616_support.c + +:defines: + # Original driver specific defines + :common: &common_defines [] + :test: + - *common_defines + - TEST + :test_preprocess: + - *common_defines + - TEST + +:cmock: + :mock_prefix: mock_ + :when_no_prototypes: :warn + :callback_include_count: TRUE + :callback_after_arg_check: TRUE + :enforce_strict_ordering: TRUE + :plugins: + - :ignore + - :callback + :treat_as: + uint8: HEX8 + uint16: HEX16 + uint32: UINT32 + int8: INT8 + bool: UINT8 + +# Add -gcov to the plugins list to make sure of the gcov plugin +# You will need to have gcov and gcovr both installed to make it work. +# For more information on these options, see docs in plugins/gcov +:gcov: + :reports: + - HtmlDetailed + :gcovr: + :html_medium_threshold: 75 + :html_high_threshold: 90 + :report_include: "../../../../drivers/power/max17616/.*" + +#:tools: +# Ceedling defaults to using gcc for compiling, linking, etc. +# As [:tools] is blank, gcc will be used (so long as it's in your system path) +# See documentation to configure a given toolchain for use + +# LIBRARIES +# These libraries are automatically injected into the build process. Those specified as +# common will be used in all types of builds. Otherwise, libraries can be injected in just +# tests or releases. These options are MERGED with the options in supplemental yaml files. +:libraries: + :placement: :end + :flag: "-l${1}" + :path_flag: "-L ${1}" + :system: [] # for example, you might list 'm' to grab the math library + :test: [] + :release: [] + +:junit_tests_report: + :artifact_filename: report_junit_original.xml + +:plugins: + :enabled: + - report_tests_pretty_stdout + - module_generator + - report_tests_raw_output_log + - gcov + - report_tests_log_factory diff --git a/tests/drivers/power/max17616/test/support/test_iio_max17616_support.c b/tests/drivers/power/max17616/test/support/test_iio_max17616_support.c new file mode 100644 index 00000000000..12757f76f1d --- /dev/null +++ b/tests/drivers/power/max17616/test/support/test_iio_max17616_support.c @@ -0,0 +1,60 @@ +/***************************************************************************//** + * @file test_iio_max17616_support.c + * @brief Support implementation for MAX17616 IIO Driver unit tests + * @author Carlos Jones (carlosjr.jones@analog.com) + ******************************************************************************* + * Copyright 2025(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************/ + +/******************************************************************************* + * INCLUDED FILES + ******************************************************************************/ + +#include "test_iio_max17616_support.h" + +/******************************************************************************* + * FUNCTION IMPLEMENTATIONS + ******************************************************************************/ + +/** + * @brief Setup function for IIO MAX17616 tests + */ +void iio_max17616_test_setup(void) +{ + // Any test setup code can go here + // Currently no specific setup needed +} + +/** + * @brief Teardown function for IIO MAX17616 tests + */ +void iio_max17616_test_teardown(void) +{ + // Any test teardown code can go here + // Currently no specific teardown needed +} diff --git a/tests/drivers/power/max17616/test/support/test_iio_max17616_support.h b/tests/drivers/power/max17616/test/support/test_iio_max17616_support.h new file mode 100644 index 00000000000..dc2b6288d03 --- /dev/null +++ b/tests/drivers/power/max17616/test/support/test_iio_max17616_support.h @@ -0,0 +1,51 @@ +/***************************************************************************//** + * @file test_iio_max17616_support.h + * @brief Support header for MAX17616 IIO Driver unit tests + * @author Carlos Jones (carlosjr.jones@analog.com) + ******************************************************************************* + * Copyright 2025(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************/ + +#ifndef TEST_IIO_MAX17616_SUPPORT_H_ +#define TEST_IIO_MAX17616_SUPPORT_H_ + +/******************************************************************************* + * FUNCTION DECLARATIONS + ******************************************************************************/ + +/** + * @brief Setup function for IIO MAX17616 tests + */ +void iio_max17616_test_setup(void); + +/** + * @brief Teardown function for IIO MAX17616 tests + */ +void iio_max17616_test_teardown(void); + +#endif /* TEST_IIO_MAX17616_SUPPORT_H_ */ diff --git a/tests/drivers/power/max17616/test/support/test_max17616_support.c b/tests/drivers/power/max17616/test/support/test_max17616_support.c new file mode 100644 index 00000000000..4e3f968512a --- /dev/null +++ b/tests/drivers/power/max17616/test/support/test_max17616_support.c @@ -0,0 +1,374 @@ +/***************************************************************************//** + * @file test_max17616_support.c + * @brief Support functions for MAX17616 testing + * @author Carlos Jones (carlosjr.jones@analog.com) + ******************************************************************************* + * Copyright 2025(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************/ +#include "unity.h" +#include "max17616.h" +#include "test_max17616_support.h" +#include + +/** + * @brief Setup test environment for MAX17616 driver tests + */ +void max17616_test_setup(void) +{ + /* Initialize test environment */ + /* No specific setup needed for basic driver tests */ +} + +/** + * @brief Teardown test environment for MAX17616 driver tests + */ +void max17616_test_teardown(void) +{ + /* Clean up test environment */ + /* No specific cleanup needed for basic driver tests */ +} + +/** + * @brief Setup mock device for testing + * @param device - Device structure to initialize + * @param i2c_desc - I2C descriptor to use + * @param chip_id - Chip ID to set + */ +void max17616_test_device_setup(struct max17616_dev *device, + struct no_os_i2c_desc *i2c_desc, + enum max17616_chip_id chip_id) +{ + if (device && i2c_desc) { + memset(device, 0, sizeof(*device)); + device->i2c_desc = i2c_desc; + device->chip_id = chip_id; + device->chip_info = max17616_test_get_chip_info(); + } +} + +/** + * @brief Validate telemetry structure + * @param telemetry - Telemetry structure to validate + * @return true if valid, false otherwise + */ +bool max17616_test_validate_telemetry(const struct max17616_telemetry + *telemetry) +{ + if (!telemetry) { + return false; + } + + /* Check if at least one value is valid */ + if (telemetry->valid_mask == 0) { + return false; + } + + /* Check reasonable ranges for valid values */ + if (telemetry->valid_mask & 0x01) { /* VIN */ + if (telemetry->vin < 0 || telemetry->vin > 100000) { /* 0-100V */ + return false; + } + } + + if (telemetry->valid_mask & 0x02) { /* VOUT */ + if (telemetry->vout < 0 || telemetry->vout > 50000) { /* 0-50V */ + return false; + } + } + + if (telemetry->valid_mask & 0x08) { /* IOUT */ + if (telemetry->iout < 0 || telemetry->iout > 100000) { /* 0-100A */ + return false; + } + } + + return true; +} + +/** + * @brief Create test chip info structure + * @return Pointer to test chip info + */ +const struct max17616_chip_info *max17616_test_get_chip_info(void) +{ + static const struct max17616_chip_specific_info + specific_info[ID_MAX17616_CHIP_COUNT] = { + [ID_MAX17616] = { + .ic_dev_id = "MAX17616", + .ic_dev_id_size = 8, + }, + [ID_MAX17616A] = { + .ic_dev_id = "MAX17616A", + .ic_dev_id_size = 9, + } + }; + + static const struct max17616_chip_info chip_info = { + .mfr_id = "MAXIM", + .mfr_id_size = 5, + .mfr_rev = "01", + .mfr_rev_size = 2, + .pmbus_rev = 0x33, + .specific_info = { + [ID_MAX17616] = { + .ic_dev_id = "MAX17616", + .ic_dev_id_size = 8, + }, + [ID_MAX17616A] = { + .ic_dev_id = "MAX17616A", + .ic_dev_id_size = 9, + } + } + }; + + return &chip_info; +} + +/** + * @brief Get test manufacturer ID string + * @return Pointer to test manufacturer ID + */ +const char *max17616_test_get_mfr_id(void) +{ + return "MAXIM"; +} + +/** + * @brief Get test device ID string + * @param chip_id - Chip ID to get device string for + * @return Pointer to test device ID string + */ +const char *max17616_test_get_device_id(enum max17616_chip_id chip_id) +{ + switch (chip_id) { + case ID_MAX17616: + return "MAX17616"; + case ID_MAX17616A: + return "MAX17616A"; + default: + return "UNKNOWN"; + } +} + +/** + * @brief Initialize a test MAX17616 device structure with default values + * @param dev - Device structure to initialize + * @param i2c_desc - I2C descriptor to use + */ +void max17616_test_init_device(struct max17616_dev *dev, + struct no_os_i2c_desc *i2c_desc) +{ + memset(dev, 0, sizeof(*dev)); + dev->i2c_desc = i2c_desc; + dev->chip_id = ID_MAX17616; +} + +/** + * @brief Initialize a test MAX17616 init parameter structure with default values + * @param init_param - Init parameter structure to initialize + * @param i2c_init - I2C init parameter to use + */ +void max17616_test_init_param(struct max17616_init_param *init_param, + struct no_os_i2c_init_param *i2c_init) +{ + memset(init_param, 0, sizeof(*init_param)); + init_param->i2c_init = i2c_init; + init_param->chip_id = ID_MAX17616; +} + +/** + * @brief Initialize a test I2C descriptor with default values + * @param i2c_desc - I2C descriptor to initialize + */ +void max17616_test_init_i2c_desc(struct no_os_i2c_desc *i2c_desc) +{ + memset(i2c_desc, 0, sizeof(*i2c_desc)); + i2c_desc->device_id = 0; + i2c_desc->slave_address = 0x36; + i2c_desc->max_speed_hz = 400000; +} + +/** + * @brief Initialize a test I2C init parameter with default values + * @param i2c_init - I2C init parameter to initialize + */ +void max17616_test_init_i2c_init(struct no_os_i2c_init_param *i2c_init) +{ + memset(i2c_init, 0, sizeof(*i2c_init)); + i2c_init->device_id = 0; + i2c_init->slave_address = 0x36; + i2c_init->max_speed_hz = 400000; +} + +/** + * @brief Create expected manufacturer ID data for testing + * @param data - Buffer to fill with expected data + * @param size - Size of the buffer (should be at least 7 bytes) + */ +void max17616_test_create_mfr_id_data(uint8_t *data, size_t size) +{ + if (size >= 7) { + data[0] = 6; // Length byte + data[1] = 'M'; + data[2] = 'A'; + data[3] = 'X'; + data[4] = 'I'; + data[5] = 'M'; + data[6] = 0; // Null terminator + } +} + +/** + * @brief Create expected manufacturer revision data for testing + * @param data - Buffer to fill with expected data + * @param size - Size of the buffer (should be at least 3 bytes) + */ +void max17616_test_create_mfr_rev_data(uint8_t *data, size_t size) +{ + if (size >= 3) { + data[0] = 2; // Length byte + data[1] = '0'; + data[2] = '1'; + } +} + +/** + * @brief Create expected device ID data for testing + * @param data - Buffer to fill with expected data + * @param size - Size of the buffer (should be at least 11 bytes) + * @param chip_id - Chip ID to create data for + */ +void max17616_test_create_dev_id_data(uint8_t *data, size_t size, + enum max17616_chip_id chip_id) +{ + if (size >= 11) { + data[0] = 10; // Length byte + if (chip_id == ID_MAX17616) { + memcpy(&data[1], "MAX17616", 8); + data[9] = 0; + data[10] = 0; + } else if (chip_id == ID_MAX17616A) { + memcpy(&data[1], "MAX17616A", 9); + data[10] = 0; + } + } +} + +/** + * @brief Create expected PMBus revision data for testing + * @param data - Buffer to fill with expected data + * @param size - Size of the buffer (should be at least 2 bytes) + */ +void max17616_test_create_pmbus_rev_data(uint8_t *data, size_t size) +{ + if (size >= 2) { + data[0] = 0x33; // PMBus revision 1.3 + data[1] = 0x00; + } +} + +/******************************************************************************* + * PMBus Test Support Functions + ******************************************************************************/ + +/** + * @brief PMBus test setup function + */ +void max17616_pmbus_test_setup(void) +{ + /* Initialize test environment for PMBus testing */ + /* No specific setup needed */ +} + +/** + * @brief PMBus test teardown function + */ +void max17616_pmbus_test_teardown(void) +{ + /* Clean up test environment */ + /* No specific cleanup needed */ +} + +/** + * @brief PMBus device setup function + */ +void max17616_pmbus_test_device_setup(void) +{ + /* Setup device for testing */ + /* No specific setup needed */ +} + +/** + * @brief PMBus device initialization function + */ +void max17616_pmbus_test_init_device(void) +{ + /* Initialize device for testing */ + /* No specific initialization needed */ +} + +/** + * @brief Verify chip info for MAX17616 + */ +int max17616_verify_chip_info_test(struct max17616_dev *dev) +{ + /* Return success for chip verification */ + (void)dev; /* Unused parameter */ + return 0; +} + +/******************************************************************************* + * Math Support Functions + ******************************************************************************/ + +/** + * @brief Integer power function for tests + * @param base - Base value + * @param exp - Exponent value + * @return base raised to the power of exp + */ +int test_int_pow(int base, int exp) +{ + int result = 1; + + if (exp < 0) { + /* For negative exponents, return 0 for integer math */ + return 0; + } + + while (exp > 0) { + if (exp & 1) { + result *= base; + } + base *= base; + exp >>= 1; + } + + return result; +} + diff --git a/tests/drivers/power/max17616/test/support/test_max17616_support.h b/tests/drivers/power/max17616/test/support/test_max17616_support.h new file mode 100644 index 00000000000..c64f7e8cc82 --- /dev/null +++ b/tests/drivers/power/max17616/test/support/test_max17616_support.h @@ -0,0 +1,115 @@ +/***************************************************************************//** + * @file test_max17616_support.h + * @brief Support header for MAX17616 Driver unit tests + * @author Carlos Jones (carlosjr.jones@analog.com) + ******************************************************************************* + * Copyright 2025(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************/ + +#ifndef __TEST_MAX17616_SUPPORT_H__ +#define __TEST_MAX17616_SUPPORT_H__ + +#include "max17616.h" + +/******************************************************************************* + * FUNCTION DECLARATIONS + ******************************************************************************/ + +/** + * @brief Setup test environment for MAX17616 driver tests + */ +void max17616_test_setup(void); + +/** + * @brief Teardown test environment for MAX17616 driver tests + */ +void max17616_test_teardown(void); + +/** + * @brief Setup mock device for testing + * @param device - Device structure to initialize + * @param i2c_desc - I2C descriptor to use + * @param chip_id - Chip ID to set + */ +void max17616_test_device_setup(struct max17616_dev *device, + struct no_os_i2c_desc *i2c_desc, + enum max17616_chip_id chip_id); + +/** + * @brief Validate telemetry structure + * @param telemetry - Telemetry structure to validate + * @return true if valid, false otherwise + */ +bool max17616_test_validate_telemetry(const struct max17616_telemetry + *telemetry); + +/** + * @brief Create test chip info structure + * @return Pointer to test chip info + */ +const struct max17616_chip_info *max17616_test_get_chip_info(void); + +/** + * @brief Get test manufacturer ID string + * @return Pointer to test manufacturer ID + */ +const char *max17616_test_get_mfr_id(void); + +/** + * @brief Get test device ID string + * @param chip_id - Chip ID to get device string for + * @return Pointer to test device ID string + */ +const char *max17616_test_get_device_id(enum max17616_chip_id chip_id); + +/******************************************************************************* + * INTERNAL FUNCTION DECLARATIONS FOR TESTING + ******************************************************************************/ + +/** + * @brief Read and verify manufacturer ID (internal function exposed for testing) + * @param dev - Device structure + * @return 0 on success, negative error code otherwise + */ +int max17616_verify_manufacturer_id(struct max17616_dev *dev); + +/** + * @brief Read device ID and identify chip variant (internal function exposed for testing) + * @param dev - Device structure + * @return 0 on success, negative error code otherwise + */ +int max17616_identify_chip_variant(struct max17616_dev *dev); + +/** + * @brief Verify PMBus revision (internal function exposed for testing) + * @param dev - Device structure + * @return 0 on success, negative error code otherwise + */ +int max17616_verify_pmbus_revision(struct max17616_dev *dev); + +#endif /* __TEST_MAX17616_SUPPORT_H__ */ diff --git a/tests/drivers/power/max17616/test/test_iio_max17616.c b/tests/drivers/power/max17616/test/test_iio_max17616.c new file mode 100644 index 00000000000..f165c9bbba1 --- /dev/null +++ b/tests/drivers/power/max17616/test/test_iio_max17616.c @@ -0,0 +1,2041 @@ +/***************************************************************************//** + * @file test_iio_max17616.c + * @brief Unit tests for MAX17616 IIO Driver (iio_max17616.c) + * @author Carlos Jones (carlosjr.jones@analog.com) + ******************************************************************************* + * Copyright 2025(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************/ + +/******************************************************************************* + * TEST FILE ORGANIZATION + ******************************************************************************/ +/* + * This test file is organized into the following main sections: + * + * 1. INCLUDED FILES & DEFINITIONS + * 2. TEST SUPPORT VARIABLES & MOCK FUNCTIONS + * 3. SETUP/TEARDOWN FUNCTIONS + * 4. INIT/REMOVE TESTS + * 5. TELEMETRY CHANNEL READ TESTS + * - Success Path Tests (VIN, VOUT, IOUT, TEMP, POUT) + * - Invalid Data Tests (all telemetry channels) + * - Driver Failure Tests (all telemetry channels) + * 6. STATUS CHANNEL READ TESTS + * - Success Path Tests (WORD, VOUT, IOUT, INPUT, TEMP, CML, MFR_SPECIFIC) + * - Driver Failure Tests (all status channels) + * 7. CONFIGURATION CHANNEL READ TESTS + * - Success Path Tests (CLMODE, ISTART_RATIO, NOMINAL_VOLTAGE, PGOOD_THRESHOLD) + * 8. CONFIGURATION CHANNEL WRITE TESTS + * 9. ERROR/EDGE CASE TESTS + * 10. INVALID CHANNEL TESTS + */ + +/******************************************************************************* + * INCLUDED FILES + ******************************************************************************/ + +#include "unity.h" +#include "iio_max17616.h" +#include "mock_max17616.h" +#include "mock_no_os_alloc.h" +#include "max17616.h" +#include "iio_types.h" +#include "no_os_util.h" +#include +#include + +/******************************************************************************* + * PRIVATE VARIABLES + ******************************************************************************/ + +static struct max17616_iio_desc *test_iio_desc; +static struct max17616_iio_desc_init_param test_iio_init_param; +static struct max17616_init_param test_max17616_init_param; +static struct max17616_dev test_max17616_dev; + +/* Mock memory allocation buffer */ +static char mock_memory[512] = {0}; + +/* Mock test data structures */ +static struct max17616_telemetry test_telemetry; +static struct max17616_status test_status; + +/* IIO Channel enumeration matching the actual implementation */ +enum max17616_iio_channels { + MAX17616_IIO_VIN_CHAN, + MAX17616_IIO_VOUT_CHAN, + MAX17616_IIO_IOUT_CHAN, + MAX17616_IIO_TEMP_CHAN, + MAX17616_IIO_POUT_CHAN, + MAX17616_IIO_STATUS_WORD_CHAN, + MAX17616_IIO_STATUS_VOUT_CHAN, + MAX17616_IIO_STATUS_IOUT_CHAN, + MAX17616_IIO_STATUS_INPUT_CHAN, + MAX17616_IIO_STATUS_TEMP_CHAN, + MAX17616_IIO_STATUS_CML_CHAN, + MAX17616_IIO_STATUS_MFR_SPECIFIC_CHAN, + MAX17616_IIO_CLMODE_CHAN, + MAX17616_IIO_ISTART_RATIO_CHAN, + MAX17616_IIO_TSTOC_CHAN, + MAX17616_IIO_ISTLIM_CHAN, + MAX17616_IIO_NOMINAL_VOLTAGE_CHAN, + MAX17616_IIO_PGOOD_THRESHOLD_CHAN, +}; + +/* External declarations for static functions (requires TEST defined in build) */ +extern int max17616_iio_read_attr(void *device, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv); + +extern int max17616_iio_write_attr(void *device, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv); + +extern int max17616_iio_read_global_attr(void *device, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv); + +extern int max17616_iio_write_global_attr(void *device, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv); + +/******************************************************************************* + * MOCK CALLBACK FUNCTIONS + ******************************************************************************/ + +/* Mock callback for telemetry reading */ +static int mock_read_telemetry_all_callback(struct max17616_dev *dev, + struct max17616_telemetry *telemetry, + int num_calls) +{ + if (telemetry && dev) { + *telemetry = test_telemetry; + return 0; + } + return -EINVAL; +} + +/* Mock callback for status reading */ +static int mock_read_status_callback(struct max17616_dev *dev, + struct max17616_status *status, + int num_calls) +{ + if (status && dev) { + *status = test_status; + return 0; + } + return -EINVAL; +} + +/* Mock callbacks for individual status register reads */ +static uint8_t mock_status_vout = 0; +static uint8_t mock_status_iout = 0; +static uint8_t mock_status_input = 0; +static uint8_t mock_status_temp = 0; +static uint8_t mock_status_cml = 0; +static uint8_t mock_status_mfr = 0; + +static int mock_read_status_vout_callback(struct max17616_dev *dev, + uint8_t *status_vout, int num_calls) +{ + if (status_vout && dev) { + *status_vout = mock_status_vout; + return 0; + } + return -EINVAL; +} + +static int mock_read_status_iout_callback(struct max17616_dev *dev, + uint8_t *status_iout, int num_calls) +{ + if (status_iout && dev) { + *status_iout = mock_status_iout; + return 0; + } + return -EINVAL; +} + +static int mock_read_status_input_callback(struct max17616_dev *dev, + uint8_t *status_input, int num_calls) +{ + if (status_input && dev) { + *status_input = mock_status_input; + return 0; + } + return -EINVAL; +} + +static int mock_read_status_temperature_callback(struct max17616_dev *dev, + uint8_t *status_temperature, int num_calls) +{ + if (status_temperature && dev) { + *status_temperature = mock_status_temp; + return 0; + } + return -EINVAL; +} + +static int mock_read_status_cml_callback(struct max17616_dev *dev, + uint8_t *status_cml, int num_calls) +{ + if (status_cml && dev) { + *status_cml = mock_status_cml; + return 0; + } + return -EINVAL; +} + +static int mock_read_status_mfr_specific_callback(struct max17616_dev *dev, + uint8_t *status_mfr, + int num_calls) +{ + if (status_mfr && dev) { + *status_mfr = mock_status_mfr; + return 0; + } + return -EINVAL; +} + +/* Mock callbacks for configuration parameter getters */ +static enum max17616_current_limit_mode mock_clmode = MAX17616_CLMODE_LATCH_OFF; +static enum max17616_istart_ratio mock_istart_ratio = MAX17616_ISTART_FULL; +static enum max17616_overcurrent_timeout mock_tstoc = MAX17616_TIMEOUT_400US; +static enum max17616_overcurrent_limit mock_istlim = MAX17616_OC_LIMIT_1_25; +static enum max17616_nominal_voltage mock_nominal_voltage = MAX17616_NOMINAL_5V; +static enum max17616_pgood_threshold mock_pgood_threshold = + MAX17616_PGOOD_MINUS_10_PERCENT; + +static int mock_get_current_limit_mode_callback(struct max17616_dev *dev, + enum max17616_current_limit_mode *clmode, + int num_calls) +{ + if (clmode && dev) { + *clmode = mock_clmode; + return 0; + } + return -EINVAL; +} + +static int mock_get_istart_ratio_callback(struct max17616_dev *dev, + enum max17616_istart_ratio *istart_ratio, + int num_calls) +{ + if (istart_ratio && dev) { + *istart_ratio = mock_istart_ratio; + return 0; + } + return -EINVAL; +} + +static int mock_get_overcurrent_timeout_callback(struct max17616_dev *dev, + enum max17616_overcurrent_timeout *timeout, + int num_calls) +{ + if (timeout && dev) { + *timeout = mock_tstoc; + return 0; + } + return -EINVAL; +} + +static int mock_get_overcurrent_limit_callback(struct max17616_dev *dev, + enum max17616_overcurrent_limit *istlim, + int num_calls) +{ + if (istlim && dev) { + *istlim = mock_istlim; + return 0; + } + return -EINVAL; +} + +static int mock_get_vout_uv_fault_limit_config_callback( + struct max17616_dev *dev, + enum max17616_nominal_voltage *voltage, + enum max17616_pgood_threshold *threshold, + int num_calls) +{ + if (voltage && threshold && dev) { + *voltage = mock_nominal_voltage; + *threshold = mock_pgood_threshold; + return 0; + } + return -EINVAL; +} + +/* Mock callbacks for global attributes */ +static bool mock_operation_state = false; +static uint8_t mock_capability = 0; + +static int mock_get_operation_state_callback(struct max17616_dev *dev, + bool *enabled, int num_calls) +{ + if (enabled && dev) { + *enabled = mock_operation_state; + return 0; + } + return -EINVAL; +} + +static int mock_read_capability_callback(struct max17616_dev *dev, + uint8_t *capability, int num_calls) +{ + if (capability && dev) { + *capability = mock_capability; + return 0; + } + return -EINVAL; +} + +/******************************************************************************* + * TEST SETUP AND TEARDOWN + ******************************************************************************/ + +void setUp(void) +{ + /* Initialize test structures */ + test_iio_desc = NULL; + memset(&test_iio_init_param, 0, sizeof(test_iio_init_param)); + memset(&test_max17616_init_param, 0, sizeof(test_max17616_init_param)); + memset(&test_max17616_dev, 0, sizeof(test_max17616_dev)); + memset(mock_memory, 0, sizeof(mock_memory)); + + /* Setup initialization parameters */ + test_iio_init_param.max17616_init_param = &test_max17616_init_param; + + /* Initialize test telemetry data */ + memset(&test_telemetry, 0, sizeof(test_telemetry)); + test_telemetry.vin = 12000; /* 12V in mV */ + test_telemetry.vout = 5000; /* 5V in mV */ + test_telemetry.iout = 2000; /* 2A in mA */ + test_telemetry.temp1 = 25; /* 25°C */ + test_telemetry.pout = 10000; /* 10W in mW */ + test_telemetry.valid_mask = 0x3F; /* All valid */ + + /* Initialize test status data */ + memset(&test_status, 0, sizeof(test_status)); + test_status.word = 0x0000; /* No faults */ + + /* Initialize mock status values */ + mock_status_vout = 0x00; + mock_status_iout = 0x00; + mock_status_input = 0x00; + mock_status_temp = 0x00; + mock_status_cml = 0x00; + mock_status_mfr = 0x00; + + /* Initialize mock configuration values */ + mock_clmode = MAX17616_CLMODE_LATCH_OFF; + mock_istart_ratio = MAX17616_ISTART_FULL; + mock_tstoc = MAX17616_TIMEOUT_400US; + mock_istlim = MAX17616_OC_LIMIT_1_25; + mock_nominal_voltage = MAX17616_NOMINAL_5V; + mock_pgood_threshold = MAX17616_PGOOD_MINUS_10_PERCENT; + + /* Initialize mock global attribute values */ + mock_operation_state = false; + mock_capability = 0x80; +} + +void tearDown(void) +{ + test_iio_desc = NULL; + /* Clear all CMock expectations between tests */ + mock_max17616_Verify(); + mock_max17616_Destroy(); + mock_max17616_Init(); +} + +/******************************************************************************* + * IIO INITIALIZATION/REMOVAL TESTS + ******************************************************************************/ + +/** + * Test max17616_iio_init with successful initialization + */ +void test_max17616_iio_init_success(void) +{ + struct max17616_iio_desc *iio_desc = NULL; + + /* Setup mock expectations */ + no_os_calloc_ExpectAndReturn(1, sizeof(struct max17616_iio_desc), mock_memory); + max17616_init_IgnoreAndReturn(0); + + /* Test the function */ + int result = max17616_iio_init(&iio_desc, &test_iio_init_param); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_NOT_NULL(iio_desc); +} + +/** + * Test max17616_iio_init with NULL parameters + */ +void test_max17616_iio_init_null_params(void) +{ + struct max17616_iio_desc *iio_desc = NULL; + + /* Test NULL iio_desc */ + int result = max17616_iio_init(NULL, &test_iio_init_param); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); + + /* Test NULL init_param */ + result = max17616_iio_init(&iio_desc, NULL); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); + + /* Test NULL max17616_init_param */ + test_iio_init_param.max17616_init_param = NULL; + result = max17616_iio_init(&iio_desc, &test_iio_init_param); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); +} + +/** + * Test max17616_iio_init with memory allocation failure + */ +void test_max17616_iio_init_malloc_failure(void) +{ + struct max17616_iio_desc *iio_desc = NULL; + + /* Setup mock to return NULL for calloc */ + no_os_calloc_ExpectAndReturn(1, sizeof(struct max17616_iio_desc), NULL); + + int result = max17616_iio_init(&iio_desc, &test_iio_init_param); + + TEST_ASSERT_EQUAL_INT(-ENOMEM, result); + TEST_ASSERT_NULL(iio_desc); +} + +/** + * Test max17616_iio_init with core driver init failure + */ +void test_max17616_iio_init_core_init_failure(void) +{ + struct max17616_iio_desc *iio_desc = NULL; + + /* Setup mock expectations */ + no_os_calloc_ExpectAndReturn(1, sizeof(struct max17616_iio_desc), mock_memory); + max17616_init_IgnoreAndReturn(-EIO); + no_os_free_Expect(mock_memory); + + int result = max17616_iio_init(&iio_desc, &test_iio_init_param); + + TEST_ASSERT_EQUAL_INT(-EIO, result); +} + +/** + * Test max17616_iio_remove with valid descriptor + */ +void test_max17616_iio_remove_success(void) +{ + struct max17616_iio_desc iio_desc; + iio_desc.max17616_dev = &test_max17616_dev; + iio_desc.iio_dev = (struct iio_device*)0x1234; /* Non-NULL pointer */ + + /* Setup mock expectations */ + max17616_remove_ExpectAndReturn(&test_max17616_dev, 0); + no_os_free_Expect(&iio_desc); + + int result = max17616_iio_remove(&iio_desc); + + TEST_ASSERT_EQUAL_INT(0, result); +} + +/** + * Test max17616_iio_remove with NULL descriptor + */ +void test_max17616_iio_remove_null_desc(void) +{ + int result = max17616_iio_remove(NULL); + + TEST_ASSERT_EQUAL_INT(-ENODEV, result); +} + +/******************************************************************************* + * TELEMETRY CHANNEL READ TESTS + ******************************************************************************/ +/* + * Success Path Tests: + * - test_max17616_iio_read_attr_vin_raw + * - test_max17616_iio_read_attr_vout_raw + * - test_max17616_iio_read_attr_iout_raw + * - test_max17616_iio_read_attr_temp_raw + * - test_max17616_iio_read_attr_pout_raw + * + * Invalid Data Tests: + * - test_max17616_iio_read_attr_telemetry_invalid_data (VIN) + * - test_max17616_iio_read_attr_vout_telemetry_invalid_data + * - test_max17616_iio_read_attr_iout_telemetry_invalid_data + * - test_max17616_iio_read_attr_temp_telemetry_invalid_data + * - test_max17616_iio_read_attr_pout_telemetry_invalid_data + * + * Driver Failure Tests: + * - test_max17616_iio_read_attr_telemetry_driver_failure (VIN) + * - test_max17616_iio_read_attr_vout_telemetry_driver_failure + * - test_max17616_iio_read_attr_iout_telemetry_driver_failure + * - test_max17616_iio_read_attr_temp_telemetry_driver_failure + * - test_max17616_iio_read_attr_pout_telemetry_driver_failure + */ + +/******************************************************************* + * TELEMETRY SUCCESS PATH TESTS + *******************************************************************/ + +/** + * Test reading VIN channel raw attribute + */ +void test_max17616_iio_read_attr_vin_raw(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_VIN_CHAN, + .address = MAX17616_IIO_VIN_CHAN + }; + + /* Setup test data */ + test_telemetry.vin = 12345; + test_telemetry.valid_mask = NO_OS_BIT(0); /* VIN valid */ + + /* Setup mock */ + max17616_read_telemetry_all_Stub(mock_read_telemetry_all_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(5, result); /* Length of "12345" */ + TEST_ASSERT_EQUAL_STRING("12345", buffer); +} + +/** + * Test reading VOUT channel raw attribute + */ +void test_max17616_iio_read_attr_vout_raw(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_VOUT_CHAN, + .address = MAX17616_IIO_VOUT_CHAN + }; + + /* Setup test data */ + test_telemetry.vout = 5678; + test_telemetry.valid_mask = NO_OS_BIT(1); /* VOUT valid */ + + /* Setup mock */ + max17616_read_telemetry_all_Stub(mock_read_telemetry_all_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(4, result); /* Length of "5678" */ + TEST_ASSERT_EQUAL_STRING("5678", buffer); +} + +/** + * Test reading IOUT channel raw attribute + */ +void test_max17616_iio_read_attr_iout_raw(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_IOUT_CHAN, + .address = MAX17616_IIO_IOUT_CHAN + }; + + /* Setup test data */ + test_telemetry.iout = 1500; + test_telemetry.valid_mask = NO_OS_BIT(3); /* IOUT valid */ + + /* Setup mock */ + max17616_read_telemetry_all_Stub(mock_read_telemetry_all_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(4, result); /* Length of "1500" */ + TEST_ASSERT_EQUAL_STRING("1500", buffer); +} + +/** + * Test reading TEMP channel raw attribute + */ +void test_max17616_iio_read_attr_temp_raw(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_TEMP_CHAN, + .address = MAX17616_IIO_TEMP_CHAN + }; + + /* Setup test data */ + test_telemetry.temp1 = 65; + test_telemetry.valid_mask = NO_OS_BIT(4); /* TEMP valid */ + + /* Setup mock */ + max17616_read_telemetry_all_Stub(mock_read_telemetry_all_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(2, result); /* Length of "65" */ + TEST_ASSERT_EQUAL_STRING("65", buffer); +} + +/** + * Test reading POUT channel raw attribute + */ +void test_max17616_iio_read_attr_pout_raw(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_POUT_CHAN, + .address = MAX17616_IIO_POUT_CHAN + }; + + /* Setup test data */ + test_telemetry.pout = 8500; + test_telemetry.valid_mask = NO_OS_BIT(5); /* POUT valid */ + + /* Setup mock */ + max17616_read_telemetry_all_Stub(mock_read_telemetry_all_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(4, result); /* Length of "8500" */ + TEST_ASSERT_EQUAL_STRING("8500", buffer); +} + +/******************************************************************* + * TELEMETRY INVALID DATA TESTS + *******************************************************************/ + +/** + * Test VIN telemetry read with invalid data (valid mask = 0) + */ +void test_max17616_iio_read_attr_telemetry_invalid_data(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_VIN_CHAN, + .address = MAX17616_IIO_VIN_CHAN + }; + + /* Setup test data with invalid mask */ + test_telemetry.vin = 12000; + test_telemetry.valid_mask = 0; /* No valid data */ + + /* Setup mock */ + max17616_read_telemetry_all_Stub(mock_read_telemetry_all_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Should return -ENODATA when data is invalid */ + TEST_ASSERT_EQUAL_INT(-ENODATA, result); +} + +/******************************************************************* + * TELEMETRY DRIVER FAILURE TESTS + *******************************************************************/ + +/** + * Test VIN telemetry read with driver failure + */ +void test_max17616_iio_read_attr_telemetry_driver_failure(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_VIN_CHAN, + .address = MAX17616_IIO_VIN_CHAN + }; + + /* Setup mock to return error */ + max17616_read_telemetry_all_IgnoreAndReturn(-EIO); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + TEST_ASSERT_EQUAL_INT(-EIO, result); +} + +/** + * Test VOUT telemetry read with invalid data + */ +void test_max17616_iio_read_attr_vout_telemetry_invalid_data(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_VOUT_CHAN, + .address = MAX17616_IIO_VOUT_CHAN + }; + + /* Setup test data with invalid mask for VOUT (bit 1) */ + test_telemetry.vout = 3300; + test_telemetry.valid_mask = 0; /* No valid data */ + + /* Setup mock */ + max17616_read_telemetry_all_Stub(mock_read_telemetry_all_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Should return -ENODATA when data is invalid */ + TEST_ASSERT_EQUAL_INT(-ENODATA, result); +} + +/** + * Test VOUT telemetry read with driver failure + */ +void test_max17616_iio_read_attr_vout_telemetry_driver_failure(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_VOUT_CHAN, + .address = MAX17616_IIO_VOUT_CHAN + }; + + /* Setup mock to return error */ + max17616_read_telemetry_all_IgnoreAndReturn(-EIO); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + TEST_ASSERT_EQUAL_INT(-EIO, result); +} + +/** + * Test IOUT telemetry read with invalid data + */ +void test_max17616_iio_read_attr_iout_telemetry_invalid_data(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_IOUT_CHAN, + .address = MAX17616_IIO_IOUT_CHAN + }; + + /* Setup test data with invalid mask for IOUT (bit 3) */ + test_telemetry.iout = 1500; + test_telemetry.valid_mask = 0; /* No valid data */ + + /* Setup mock */ + max17616_read_telemetry_all_Stub(mock_read_telemetry_all_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Should return -ENODATA when data is invalid */ + TEST_ASSERT_EQUAL_INT(-ENODATA, result); +} + +/** + * Test IOUT telemetry read with driver failure + */ +void test_max17616_iio_read_attr_iout_telemetry_driver_failure(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_IOUT_CHAN, + .address = MAX17616_IIO_IOUT_CHAN + }; + + /* Setup mock to return error */ + max17616_read_telemetry_all_IgnoreAndReturn(-EIO); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + TEST_ASSERT_EQUAL_INT(-EIO, result); +} + +/** + * Test TEMP telemetry read with invalid data + */ +void test_max17616_iio_read_attr_temp_telemetry_invalid_data(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_TEMP_CHAN, + .address = MAX17616_IIO_TEMP_CHAN + }; + + /* Setup test data with invalid mask for TEMP (bit 4) */ + test_telemetry.temp1 = 25; + test_telemetry.valid_mask = 0; /* No valid data */ + + /* Setup mock */ + max17616_read_telemetry_all_Stub(mock_read_telemetry_all_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Should return -ENODATA when data is invalid */ + TEST_ASSERT_EQUAL_INT(-ENODATA, result); +} + +/** + * Test TEMP telemetry read with driver failure + */ +void test_max17616_iio_read_attr_temp_telemetry_driver_failure(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_TEMP_CHAN, + .address = MAX17616_IIO_TEMP_CHAN + }; + + /* Setup mock to return error */ + max17616_read_telemetry_all_IgnoreAndReturn(-EIO); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + TEST_ASSERT_EQUAL_INT(-EIO, result); +} + +/** + * Test POUT telemetry read with invalid data + */ +void test_max17616_iio_read_attr_pout_telemetry_invalid_data(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_POUT_CHAN, + .address = MAX17616_IIO_POUT_CHAN + }; + + /* Setup test data with invalid mask for POUT (bit 5) */ + test_telemetry.pout = 4950; + test_telemetry.valid_mask = 0; /* No valid data */ + + /* Setup mock */ + max17616_read_telemetry_all_Stub(mock_read_telemetry_all_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Should return -ENODATA when data is invalid */ + TEST_ASSERT_EQUAL_INT(-ENODATA, result); +} + +/** + * Test POUT telemetry read with driver failure + */ +void test_max17616_iio_read_attr_pout_telemetry_driver_failure(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_POUT_CHAN, + .address = MAX17616_IIO_POUT_CHAN + }; + + /* Setup mock to return error */ + max17616_read_telemetry_all_IgnoreAndReturn(-EIO); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + TEST_ASSERT_EQUAL_INT(-EIO, result); +} + +/******************************************************************************* + * STATUS CHANNEL READ TESTS + ******************************************************************************/ +/* + * Success Path Tests: + * - test_max17616_iio_read_attr_status_word + * - test_max17616_iio_read_attr_status_vout + * - test_max17616_iio_read_attr_status_iout + * - test_max17616_iio_read_attr_status_input + * - test_max17616_iio_read_attr_status_temp + * - test_max17616_iio_read_attr_status_cml + * - test_max17616_iio_read_attr_status_mfr_specific + * + * Driver Failure Tests: + * - test_max17616_iio_read_attr_status_driver_failure (WORD) + * - test_max17616_iio_read_attr_status_vout_driver_failure + * - test_max17616_iio_read_attr_status_iout_driver_failure + * - test_max17616_iio_read_attr_status_input_driver_failure + * - test_max17616_iio_read_attr_status_temp_driver_failure + * - test_max17616_iio_read_attr_status_cml_driver_failure + * - test_max17616_iio_read_attr_status_mfr_specific_driver_failure + */ + +/******************************************************************* + * STATUS SUCCESS PATH TESTS + *******************************************************************/ + +/** + * Test reading STATUS_WORD channel + */ +void test_max17616_iio_read_attr_status_word(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_STATUS_WORD_CHAN, + .address = MAX17616_IIO_STATUS_WORD_CHAN + }; + + /* Setup test data */ + test_status.word = 0x1234; + + /* Setup mock */ + max17616_read_status_Stub(mock_read_status_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(6, result); /* Length of "0x1234" */ + TEST_ASSERT_EQUAL_STRING("0x1234", buffer); +} + +/** + * Test reading STATUS_VOUT channel + */ +void test_max17616_iio_read_attr_status_vout(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_STATUS_VOUT_CHAN, + .address = MAX17616_IIO_STATUS_VOUT_CHAN + }; + + /* Setup test data */ + mock_status_vout = 0xAB; + + /* Setup mock */ + max17616_read_status_vout_Stub(mock_read_status_vout_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(4, result); /* Length of "0xAB" */ + TEST_ASSERT_EQUAL_STRING("0xAB", buffer); +} + +/** + * Test reading STATUS_IOUT channel + */ +void test_max17616_iio_read_attr_status_iout(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_STATUS_IOUT_CHAN, + .address = MAX17616_IIO_STATUS_IOUT_CHAN + }; + + /* Setup test data */ + mock_status_iout = 0xCD; + + /* Setup mock */ + max17616_read_status_iout_Stub(mock_read_status_iout_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(4, result); /* Length of "0xCD" */ + TEST_ASSERT_EQUAL_STRING("0xCD", buffer); +} + +/******************************************************************* + * STATUS DRIVER FAILURE TESTS + *******************************************************************/ + +/** + * Test STATUS_WORD read with driver failure + */ +void test_max17616_iio_read_attr_status_driver_failure(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_STATUS_WORD_CHAN, + .address = MAX17616_IIO_STATUS_WORD_CHAN + }; + + /* Setup mock to return error */ + max17616_read_status_IgnoreAndReturn(-ECOMM); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + TEST_ASSERT_EQUAL_INT(-ECOMM, result); +} + +/** + * Test STATUS_VOUT read with driver failure + */ +void test_max17616_iio_read_attr_status_vout_driver_failure(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_STATUS_VOUT_CHAN, + .address = MAX17616_IIO_STATUS_VOUT_CHAN + }; + + /* Setup mock to return error */ + max17616_read_status_vout_IgnoreAndReturn(-ECOMM); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + TEST_ASSERT_EQUAL_INT(-ECOMM, result); +} + +/** + * Test STATUS_IOUT read with driver failure + */ +void test_max17616_iio_read_attr_status_iout_driver_failure(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_STATUS_IOUT_CHAN, + .address = MAX17616_IIO_STATUS_IOUT_CHAN + }; + + /* Setup mock to return error */ + max17616_read_status_iout_IgnoreAndReturn(-ECOMM); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + TEST_ASSERT_EQUAL_INT(-ECOMM, result); +} + +/** + * Test reading STATUS_INPUT channel + */ +void test_max17616_iio_read_attr_status_input(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_STATUS_INPUT_CHAN, + .address = MAX17616_IIO_STATUS_INPUT_CHAN + }; + + /* Setup test data */ + mock_status_input = 0x42; + + /* Setup mock */ + max17616_read_status_input_Stub(mock_read_status_input_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(4, result); /* Length of "0x42" */ + TEST_ASSERT_EQUAL_STRING("0x42", buffer); +} + +/** + * Test STATUS_INPUT read with driver failure + */ +void test_max17616_iio_read_attr_status_input_driver_failure(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_STATUS_INPUT_CHAN, + .address = MAX17616_IIO_STATUS_INPUT_CHAN + }; + + /* Setup mock to return error */ + max17616_read_status_input_IgnoreAndReturn(-ECOMM); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + TEST_ASSERT_EQUAL_INT(-ECOMM, result); +} + +/** + * Test reading STATUS_TEMP channel + */ +void test_max17616_iio_read_attr_status_temp(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_STATUS_TEMP_CHAN, + .address = MAX17616_IIO_STATUS_TEMP_CHAN + }; + + /* Setup test data */ + mock_status_temp = 0x85; + + /* Setup mock */ + max17616_read_status_temperature_Stub(mock_read_status_temperature_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(4, result); /* Length of "0x85" */ + TEST_ASSERT_EQUAL_STRING("0x85", buffer); +} + +/** + * Test STATUS_TEMP read with driver failure + */ +void test_max17616_iio_read_attr_status_temp_driver_failure(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_STATUS_TEMP_CHAN, + .address = MAX17616_IIO_STATUS_TEMP_CHAN + }; + + /* Setup mock to return error */ + max17616_read_status_temperature_IgnoreAndReturn(-ECOMM); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + TEST_ASSERT_EQUAL_INT(-ECOMM, result); +} + +/** + * Test reading STATUS_CML channel + */ +void test_max17616_iio_read_attr_status_cml(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_STATUS_CML_CHAN, + .address = MAX17616_IIO_STATUS_CML_CHAN + }; + + /* Setup test data */ + mock_status_cml = 0x1A; + + /* Setup mock */ + max17616_read_status_cml_Stub(mock_read_status_cml_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(4, result); /* Length of "0x1A" */ + TEST_ASSERT_EQUAL_STRING("0x1A", buffer); +} + +/** + * Test STATUS_CML read with driver failure + */ +void test_max17616_iio_read_attr_status_cml_driver_failure(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_STATUS_CML_CHAN, + .address = MAX17616_IIO_STATUS_CML_CHAN + }; + + /* Setup mock to return error */ + max17616_read_status_cml_IgnoreAndReturn(-ECOMM); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + TEST_ASSERT_EQUAL_INT(-ECOMM, result); +} + +/** + * Test reading STATUS_MFR_SPECIFIC channel + */ +void test_max17616_iio_read_attr_status_mfr_specific(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_STATUS_MFR_SPECIFIC_CHAN, + .address = MAX17616_IIO_STATUS_MFR_SPECIFIC_CHAN + }; + + /* Setup test data */ + mock_status_mfr = 0xF3; + + /* Setup mock */ + max17616_read_status_mfr_specific_Stub(mock_read_status_mfr_specific_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(4, result); /* Length of "0xF3" */ + TEST_ASSERT_EQUAL_STRING("0xF3", buffer); +} + +/** + * Test STATUS_MFR_SPECIFIC read with driver failure + */ +void test_max17616_iio_read_attr_status_mfr_specific_driver_failure(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_STATUS_MFR_SPECIFIC_CHAN, + .address = MAX17616_IIO_STATUS_MFR_SPECIFIC_CHAN + }; + + /* Setup mock to return error */ + max17616_read_status_mfr_specific_IgnoreAndReturn(-ECOMM); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + TEST_ASSERT_EQUAL_INT(-ECOMM, result); +} + +/******************************************************************************* + * CONFIGURATION CHANNEL READ TESTS + ******************************************************************************/ +/* + * Success Path Tests: + * - test_max17616_iio_read_attr_clmode + * - test_max17616_iio_read_attr_istart_ratio + * - test_max17616_iio_read_attr_tstoc + * - test_max17616_iio_read_attr_istlim + * - test_max17616_iio_read_attr_nominal_voltage + * - test_max17616_iio_read_attr_pgood_threshold + */ + +/******************************************************************* + * CONFIGURATION SUCCESS PATH TESTS + *******************************************************************/ + +/** + * Test reading CLMODE channel + */ +void test_max17616_iio_read_attr_clmode(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_CLMODE_CHAN, + .address = MAX17616_IIO_CLMODE_CHAN + }; + + /* Setup test data */ + mock_clmode = MAX17616_CLMODE_CONTINUOUS; /* Value 0x40 -> 64 */ + + /* Setup mock */ + max17616_get_current_limit_mode_Stub(mock_get_current_limit_mode_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(2, result); /* Length of "64" */ + TEST_ASSERT_EQUAL_STRING("64", buffer); +} + +/** + * Test reading ISTART_RATIO channel + */ +void test_max17616_iio_read_attr_istart_ratio(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_ISTART_RATIO_CHAN, + .address = MAX17616_IIO_ISTART_RATIO_CHAN + }; + + /* Setup test data */ + mock_istart_ratio = MAX17616_ISTART_HALF; /* Value 1 */ + + /* Setup mock */ + max17616_get_istart_ratio_Stub(mock_get_istart_ratio_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(1, result); /* Length of "1" */ + TEST_ASSERT_EQUAL_STRING("1", buffer); +} + +/** + * Test reading TSTOC (Overcurrent Timeout) channel + */ +void test_max17616_iio_read_attr_tstoc(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_TSTOC_CHAN, + .address = MAX17616_IIO_TSTOC_CHAN + }; + + /* Setup test data */ + mock_tstoc = MAX17616_TIMEOUT_1MS; /* Value 1 -> returns "1" */ + + /* Setup mock */ + max17616_get_overcurrent_timeout_Stub(mock_get_overcurrent_timeout_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(1, result); /* Length of "1" */ + TEST_ASSERT_EQUAL_STRING("1", buffer); +} + +/** + * Test reading ISTLIM (Overcurrent Limit) channel + */ +void test_max17616_iio_read_attr_istlim(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_ISTLIM_CHAN, + .address = MAX17616_IIO_ISTLIM_CHAN + }; + + /* Setup test data */ + mock_istlim = MAX17616_OC_LIMIT_1_50; /* Value 1 -> returns "1" */ + + /* Setup mock */ + max17616_get_overcurrent_limit_Stub(mock_get_overcurrent_limit_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(1, result); /* Length of "1" */ + TEST_ASSERT_EQUAL_STRING("1", buffer); +} + +/** + * Test reading NOMINAL_VOLTAGE channel + */ +void test_max17616_iio_read_attr_nominal_voltage(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = 16, /* nominal_voltage channel index */ + .address = 17 /* MAX17616_IIO_NOMINAL_VOLTAGE_CHAN enum value */ + }; + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + /* Set mock values for nominal voltage test */ + mock_nominal_voltage = MAX17616_NOMINAL_12V; /* enum value 2 -> returns "2" */ + mock_pgood_threshold = MAX17616_PGOOD_MINUS_20_PERCENT; /* enum value 1 */ + + /* Setup mock to use callback for this test only */ + max17616_get_vout_uv_fault_limit_config_Stub( + mock_get_vout_uv_fault_limit_config_callback); + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Clean up the stub immediately */ + max17616_get_vout_uv_fault_limit_config_Stub(NULL); + + /* Verify results */ + TEST_ASSERT_GREATER_THAN(0, result); /* Should return positive length */ + TEST_ASSERT_EQUAL_STRING("2", buffer); /* MAX17616_NOMINAL_12V = 2 */ +} + +/** + * Test reading PGOOD_THRESHOLD channel + */ +void test_max17616_iio_read_attr_pgood_threshold(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = 17, /* pgood_threshold channel index */ + .address = 18 /* MAX17616_IIO_PGOOD_THRESHOLD_CHAN enum value */ + }; + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + /* Set mock values for pgood threshold test */ + mock_nominal_voltage = MAX17616_NOMINAL_24V; /* enum value 2 */ + mock_pgood_threshold = + MAX17616_PGOOD_MINUS_30_PERCENT; /* enum value 2 -> returns "2" */ + + /* Setup mock to use callback for this test only */ + max17616_get_vout_uv_fault_limit_config_Stub( + mock_get_vout_uv_fault_limit_config_callback); + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + /* Clean up the stub immediately */ + max17616_get_vout_uv_fault_limit_config_Stub(NULL); + + /* Verify results */ + TEST_ASSERT_GREATER_THAN(0, result); /* Should return positive length */ + TEST_ASSERT_EQUAL_STRING("2", buffer); /* MAX17616_PGOOD_MINUS_30_PERCENT = 2 */ +} + +/******************************************************************************* + * CONFIGURATION CHANNEL WRITE TESTS + ******************************************************************************/ + +/** + * Test writing CLMODE channel - Note: Due to channel address shift issue mentioned in code + */ +void test_max17616_iio_write_attr_clmode(void) +{ + char input[] = "128"; /* MAX17616_CLMODE_AUTO_RETRY = 0x80 = 128 */ + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_CLMODE_CHAN, + .address = MAX17616_IIO_CLMODE_CHAN + }; + + /* Setup mock expectation - Note: per the IIO code comment, there's a channel shift issue */ + max17616_set_current_limit_mode_ExpectAndReturn(&test_max17616_dev, + (enum max17616_current_limit_mode)128, 0); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_write_attr(&iio_desc, input, strlen(input), &channel, + 0); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(strlen(input), result); +} + +/** + * Test writing TSTOC (Overcurrent Timeout) channel + */ +void test_max17616_iio_write_attr_tstoc(void) +{ + char input[] = "2"; /* MAX17616_TIMEOUT_4MS = 2 */ + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_TSTOC_CHAN, + .address = MAX17616_IIO_TSTOC_CHAN + }; + + /* Setup mock to expect the set call */ + max17616_set_overcurrent_timeout_IgnoreAndReturn(0); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_write_attr(&iio_desc, input, strlen(input), &channel, + 0); + + /* Should return number of characters written */ + TEST_ASSERT_EQUAL_INT(strlen(input), result); +} + +/** + * Test writing ISTLIM (Overcurrent Limit) channel + */ +void test_max17616_iio_write_attr_istlim(void) +{ + char input[] = "2"; /* MAX17616_OC_LIMIT_1_75 = 2 */ + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_ISTLIM_CHAN, + .address = MAX17616_IIO_ISTLIM_CHAN + }; + + /* Setup mock to expect the set call */ + max17616_set_overcurrent_limit_IgnoreAndReturn(0); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_write_attr(&iio_desc, input, strlen(input), &channel, + 0); + + /* Should return number of characters written */ + TEST_ASSERT_EQUAL_INT(strlen(input), result); +} + +/** + * Test writing ISTART_RATIO channel + */ +void test_max17616_iio_write_attr_istart_ratio(void) +{ + char input[] = "3"; /* MAX17616_ISTART_EIGHTH = 3 */ + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_ISTART_RATIO_CHAN, + .address = MAX17616_IIO_ISTART_RATIO_CHAN + }; + + /* Setup mock to expect the set call */ + max17616_set_istart_ratio_IgnoreAndReturn(0); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_write_attr(&iio_desc, input, strlen(input), &channel, + 0); + + /* Should return number of characters written */ + TEST_ASSERT_EQUAL_INT(strlen(input), result); +} + +/** + * Test write with invalid input format + */ +void test_max17616_iio_write_attr_invalid_format(void) +{ + char input[] = "abc"; /* Non-numeric input */ + struct iio_ch_info channel = { + .ch_num = MAX17616_IIO_CLMODE_CHAN, + .address = MAX17616_IIO_CLMODE_CHAN + }; + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_write_attr(&iio_desc, input, strlen(input), &channel, + 0); + + TEST_ASSERT_EQUAL_INT(-EINVAL, result); +} + +/** + * Test write with invalid channel + */ +void test_max17616_iio_write_attr_invalid_channel(void) +{ + char input[] = "5"; + struct iio_ch_info channel = { + .ch_num = 99, /* Invalid channel */ + .address = 99 + }; + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_write_attr(&iio_desc, input, strlen(input), &channel, + 0); + + TEST_ASSERT_EQUAL_INT(-EINVAL, result); +} + +/******************************************************************************* + * GLOBAL ATTRIBUTE TESTS + ******************************************************************************/ + +/** + * Test reading operation global attribute (enabled) + */ +void test_max17616_iio_read_global_attr_operation_enabled(void) +{ + char buffer[32]; + struct iio_ch_info channel = {0}; /* Not used for global attributes */ + + /* Setup test data */ + mock_operation_state = true; + + /* Setup mock */ + max17616_get_operation_state_Stub(mock_get_operation_state_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_global_attr(&iio_desc, buffer, sizeof(buffer), + &channel, 0); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(7, result); /* Length of "enabled" */ + TEST_ASSERT_EQUAL_STRING("enabled", buffer); +} + +/** + * Test reading operation global attribute (disabled) + */ +void test_max17616_iio_read_global_attr_operation_disabled(void) +{ + char buffer[32]; + struct iio_ch_info channel = {0}; + + /* Setup test data */ + mock_operation_state = false; + + /* Setup mock */ + max17616_get_operation_state_Stub(mock_get_operation_state_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_global_attr(&iio_desc, buffer, sizeof(buffer), + &channel, 0); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(8, result); /* Length of "disabled" */ + TEST_ASSERT_EQUAL_STRING("disabled", buffer); +} + +/** + * Test reading device_info global attribute + */ +void test_max17616_iio_read_global_attr_device_info(void) +{ + char buffer[128]; + struct iio_ch_info channel = {0}; + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_global_attr(&iio_desc, buffer, sizeof(buffer), + &channel, 2); + + /* Verify results */ + const char *expected = "MAX17616/MAX17616A Protection IC"; + TEST_ASSERT_EQUAL_INT(strlen(expected), result); + TEST_ASSERT_EQUAL_STRING(expected, buffer); +} + +/** + * Test reading fault_summary global attribute (no faults) + */ +void test_max17616_iio_read_global_attr_fault_summary_no_faults(void) +{ + char buffer[128]; + struct iio_ch_info channel = {0}; + + /* Setup test data */ + test_status.word = 0; /* No faults */ + + /* Setup mock */ + max17616_read_status_Stub(mock_read_status_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_global_attr(&iio_desc, buffer, sizeof(buffer), + &channel, 3); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(9, result); /* Length of "No faults" */ + TEST_ASSERT_EQUAL_STRING("No faults", buffer); +} + +/** + * Test reading fault_summary global attribute (multiple faults) + */ +void test_max17616_iio_read_global_attr_fault_summary_faults(void) +{ + char buffer[256]; + struct iio_ch_info channel = {0}; + + /* Setup test data with faults */ + test_status.word = 0x1234; /* Has faults */ + test_status.vout = 1; /* VOUT fault */ + test_status.iout = 1; /* IOUT fault */ + test_status.input = 0; + test_status.temperature = 1; /* TEMP fault */ + test_status.cml = 0; + test_status.mfr_specific = 0; + + /* Setup mock */ + max17616_read_status_Stub(mock_read_status_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_global_attr(&iio_desc, buffer, sizeof(buffer), + &channel, 3); + + /* Verify results */ + const char *expected = "VOUT_FAULT IOUT_FAULT TEMP_FAULT "; + TEST_ASSERT_EQUAL_INT(strlen(expected), result); + TEST_ASSERT_EQUAL_STRING(expected, buffer); +} + +/** + * Test reading capability global attribute + */ +void test_max17616_iio_read_global_attr_capability(void) +{ + char buffer[32]; + struct iio_ch_info channel = {0}; + + /* Setup test data */ + mock_capability = 0x80; /* 128 in decimal */ + + /* Setup mock */ + max17616_read_capability_Stub(mock_read_capability_callback); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_global_attr(&iio_desc, buffer, sizeof(buffer), + &channel, 4); + + /* Verify results */ + TEST_ASSERT_EQUAL_INT(3, result); /* Length of "128" */ + TEST_ASSERT_EQUAL_STRING("128", buffer); +} + +/** + * Test reading global attribute with invalid priv + */ +void test_max17616_iio_read_global_attr_invalid_priv(void) +{ + char buffer[32]; + struct iio_ch_info channel = {0}; + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_global_attr(&iio_desc, buffer, sizeof(buffer), + &channel, 99); + + TEST_ASSERT_EQUAL_INT(-EINVAL, result); +} + +/** + * Test writing operation global attribute (enable with "1") + */ +void test_max17616_iio_write_global_attr_operation_enable_1(void) +{ + char input[] = "1"; + struct iio_ch_info channel = {0}; + + /* Setup mock expectation */ + max17616_set_operation_state_ExpectAndReturn(&test_max17616_dev, 1, 0); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_write_global_attr(&iio_desc, input, strlen(input), + &channel, 0); + + TEST_ASSERT_EQUAL_INT(0, result); +} + +/** + * Test writing operation global attribute (enable with "enable") + */ +void test_max17616_iio_write_global_attr_operation_enable_string(void) +{ + char input[] = "enable"; + struct iio_ch_info channel = {0}; + + /* Setup mock expectation */ + max17616_set_operation_state_ExpectAndReturn(&test_max17616_dev, 1, 0); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_write_global_attr(&iio_desc, input, strlen(input), + &channel, 0); + + TEST_ASSERT_EQUAL_INT(0, result); +} + +/** + * Test writing operation global attribute (disable with "0") + */ +void test_max17616_iio_write_global_attr_operation_disable_0(void) +{ + char input[] = "0"; + struct iio_ch_info channel = {0}; + + /* Setup mock expectation */ + max17616_set_operation_state_ExpectAndReturn(&test_max17616_dev, 0, 0); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_write_global_attr(&iio_desc, input, strlen(input), + &channel, 0); + + TEST_ASSERT_EQUAL_INT(0, result); +} + +/** + * Test writing clear_faults global attribute + */ +void test_max17616_iio_write_global_attr_clear_faults(void) +{ + char input[] = "1"; /* Input value doesn't matter for clear_faults */ + struct iio_ch_info channel = {0}; + + /* Setup mock expectation */ + max17616_clear_faults_ExpectAndReturn(&test_max17616_dev, 0); + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_write_global_attr(&iio_desc, input, strlen(input), + &channel, 1); + + TEST_ASSERT_EQUAL_INT(0, result); +} + +/** + * Test writing global attribute with invalid priv + */ +void test_max17616_iio_write_global_attr_invalid_priv(void) +{ + char input[] = "test"; + struct iio_ch_info channel = {0}; + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_write_global_attr(&iio_desc, input, strlen(input), + &channel, 99); + + TEST_ASSERT_EQUAL_INT(-EINVAL, result); +} + +/******************************************************************************* + * ERROR CONDITION TESTS + ******************************************************************************/ + +/** + * Test invalid channel address + */ +void test_max17616_iio_read_attr_invalid_channel(void) +{ + char buffer[32]; + struct iio_ch_info channel = { + .ch_num = 99, /* Invalid channel */ + .address = 99 + }; + + /* Create IIO descriptor */ + struct max17616_iio_desc iio_desc = { + .max17616_dev = &test_max17616_dev + }; + + int result = max17616_iio_read_attr(&iio_desc, buffer, sizeof(buffer), &channel, + 0); + + TEST_ASSERT_EQUAL_INT(-EINVAL, result); +} diff --git a/tests/drivers/power/max17616/test/test_iio_max17616_internal.h b/tests/drivers/power/max17616/test/test_iio_max17616_internal.h new file mode 100644 index 00000000000..b016ab804a6 --- /dev/null +++ b/tests/drivers/power/max17616/test/test_iio_max17616_internal.h @@ -0,0 +1,92 @@ +/***************************************************************************//** + * @file test_iio_max17616_internal.h + * @brief Internal declarations for MAX17616 IIO Driver testing + * @author Carlos Jones (carlosjr.jones@analog.com) + ******************************************************************************* + * Copyright 2025(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************/ + +#ifndef __TEST_IIO_MAX17616_INTERNAL_H__ +#define __TEST_IIO_MAX17616_INTERNAL_H__ + +#include "iio_types.h" + +/******************************************************************************* + * TEST-SPECIFIC DECLARATIONS FOR STATIC FUNCTIONS + ******************************************************************************/ + +/* + * Note: These external declarations allow testing of static functions + * They require TEST to be defined during compilation to make the functions non-static + */ + +/* External declaration for testing static function max17616_iio_read_attr */ +extern int max17616_iio_read_attr(void *device, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv); + +/* External declaration for testing static function max17616_iio_write_attr */ +extern int max17616_iio_write_attr(void *device, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv); + +/* External declaration for testing static function max17616_iio_read_global_attr */ +extern int max17616_iio_read_global_attr(void *device, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv); + +/* External declaration for testing static function max17616_iio_write_global_attr */ +extern int max17616_iio_write_global_attr(void *device, char *buf, uint32_t len, + const struct iio_ch_info *channel, + intptr_t priv); + +/* Channel enumeration from iio_max17616.c - matches actual implementation */ +enum max17616_iio_channels { + MAX17616_IIO_VIN_CHAN, + MAX17616_IIO_VOUT_CHAN, + MAX17616_IIO_IOUT_CHAN, + MAX17616_IIO_TEMP_CHAN, + MAX17616_IIO_POUT_CHAN, + MAX17616_IIO_STATUS_WORD_CHAN, + MAX17616_IIO_STATUS_VOUT_CHAN, + MAX17616_IIO_STATUS_IOUT_CHAN, + MAX17616_IIO_STATUS_INPUT_CHAN, + MAX17616_IIO_STATUS_TEMP_CHAN, + MAX17616_IIO_STATUS_CML_CHAN, + MAX17616_IIO_STATUS_MFR_SPECIFIC_CHAN, + /* Output channels for control settings */ + MAX17616_IIO_CLMODE_CHAN, + MAX17616_IIO_ISTART_RATIO_CHAN, + MAX17616_IIO_TSTOC_CHAN, + MAX17616_IIO_ISTLIM_CHAN, + /* VOUT UV fault limit configuration channels */ + MAX17616_IIO_NOMINAL_VOLTAGE_CHAN, + MAX17616_IIO_PGOOD_THRESHOLD_CHAN, +}; + +#endif /* __TEST_IIO_MAX17616_INTERNAL_H__ */ diff --git a/tests/drivers/power/max17616/test/test_max17616.c b/tests/drivers/power/max17616/test/test_max17616.c new file mode 100644 index 00000000000..6160a933636 --- /dev/null +++ b/tests/drivers/power/max17616/test/test_max17616.c @@ -0,0 +1,1546 @@ +/***************************************************************************//** + * @file test_max17616.c + * @brief Unit tests for MAX17616 Driver (max17616.c) + * @author Carlos Jones (carlosjr.jones@analog.com) + ******************************************************************************* + * Copyright 2025(c) Analog Devices, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************/ + +/******************************************************************************* + * INCLUDED FILES + ******************************************************************************/ + +#include "unity.h" +#include "max17616.h" +#include "mock_no_os_delay.h" +#include "mock_no_os_util.h" +#include "mock_no_os_i2c.h" +#include "mock_no_os_alloc.h" +#include "mock_no_os_crc8.h" +#include "support/test_max17616_support.h" +#include +#include + +/******************************************************************************* + * PRIVATE VARIABLES + ******************************************************************************/ + +static struct max17616_dev *test_device; +static struct max17616_init_param test_init_param; +static struct no_os_i2c_desc test_i2c_desc; +static struct no_os_i2c_init_param test_i2c_init; + +// Test helper variables for mock callbacks +static uint8_t test_expected_read_data; +static uint8_t test_expected_read_buffer[16]; // Buffer for multi-byte reads +static uint8_t test_expected_read_length; +static int test_i2c_read_call_count = 0; // Track which call we're on + +char os_malloc[512] = {0}; + +/******************************************************************************* + * MOCK CALLBACK FUNCTIONS + ******************************************************************************/ + +/** +* @brief Mock callback for no_os_i2c_read to simulate reading data +*/ +static int32_t test_i2c_read_callback(struct no_os_i2c_desc* desc, + uint8_t* data, + uint8_t bytes_number, uint8_t stop_bit, + int cmock_num_calls) +{ + if (data && bytes_number > 0) { + if (bytes_number == 1) { + data[0] = test_expected_read_data; + } else { + // Multi-byte read - copy from buffer + uint8_t copy_length = (bytes_number <= test_expected_read_length) ? + bytes_number : test_expected_read_length; + memcpy(data, test_expected_read_buffer, copy_length); + } + } + return 0; // Success +} + +/** + * @brief Mock callback for no_os_i2c_read specific to init test with multiple + * sequential calls + */ +static int32_t test_i2c_read_init_callback(struct no_os_i2c_desc* desc, + uint8_t* data, uint8_t bytes_number, + uint8_t stop_bit, + int cmock_num_calls) +{ + // Handle different calls based on call count or cmock_num_calls + switch (cmock_num_calls) { + case 0: // First call - manufacturer ID (7 bytes with length prefix) + if (data && bytes_number == 7) { + // Response: [0x05, 'M', 'A', 'X', 'I', 'M', 0x00] + data[0] = 0x05; // Length + data[1] = 'M'; + data[2] = 'A'; + data[3] = 'X'; + data[4] = 'I'; + data[5] = 'M'; + data[6] = 0x00; + } + break; + case 1: // Second call - chip variant ID (11 bytes with length prefix) + if (data && bytes_number == 11) { + // Response: [0x08, 'M', 'A', 'X', '1', '7', '6', '1', '6', 0x00, 0x00] + data[0] = 0x08; // Length + data[1] = 'M'; + data[2] = 'A'; + data[3] = 'X'; + data[4] = '1'; + data[5] = '7'; + data[6] = '6'; + data[7] = '1'; + data[8] = '6'; + data[9] = 0x00; + data[10] = 0x00; + } + break; + case 2: // Third call - PMBus revision (2 bytes) + if (data && bytes_number == 2) { + // Response: [0x33, 0x00] (little-endian for 0x0033) + data[0] = 0x33; + data[1] = 0x00; + } + break; + default: + // For any other calls, return 0 + if (data && bytes_number > 0) { + memset(data, 0, bytes_number); + } + break; + } + return 0; // Success +} + +/** + * @brief Mock callback for I2C read that returns unknown device variant + */ +static int32_t test_i2c_read_unknown_device_callback(struct no_os_i2c_desc* + desc, + uint8_t* data, uint8_t bytes_number, + uint8_t stop_bit, + int cmock_num_calls) +{ + switch (cmock_num_calls) { + case 0: // First call - manufacturer ID (7 bytes) - succeeds with "MAXIM" + if (data && bytes_number == 7) { + data[0] = 0x05; // Length + data[1] = 'M'; + data[2] = 'A'; + data[3] = 'X'; + data[4] = 'I'; + data[5] = 'M'; + data[6] = 0x00; + } + break; + case 1: // Second call - chip variant ID (11 bytes) - returns unknown device + if (data && bytes_number == 11) { + data[0] = 0x08; // Length + data[1] = 'U'; // Unknown device + data[2] = 'N'; + data[3] = 'K'; + data[4] = 'N'; + data[5] = 'O'; + data[6] = 'W'; + data[7] = 'N'; + data[8] = '1'; + data[9] = 0x00; + data[10] = 0x00; + } + break; + default: + if (data && bytes_number > 0) { + memset(data, 0, bytes_number); + } + break; + } + return 0; +} + +/** + * @brief Mock callback for I2C read that returns wrong manufacturer + */ +static int32_t test_i2c_read_wrong_mfr_callback(struct no_os_i2c_desc* desc, + uint8_t* data, uint8_t bytes_number, + uint8_t stop_bit, + int cmock_num_calls) +{ + switch (cmock_num_calls) { + case 0: // First call - manufacturer ID (7 bytes) - returns wrong manufacturer + if (data && bytes_number == 7) { + data[0] = 0x05; // Length + data[1] = 'W'; // Wrong manufacturer + data[2] = 'R'; + data[3] = 'O'; + data[4] = 'N'; + data[5] = 'G'; + data[6] = 0x00; + } + break; + default: + if (data && bytes_number > 0) { + memset(data, 0, bytes_number); + } + break; + } + return 0; +} + +/** + * @brief Mock callback for I2C read that returns wrong PMBus revision + */ +static int32_t test_i2c_read_wrong_pmbus_callback(struct no_os_i2c_desc* desc, + uint8_t* data, uint8_t bytes_number, + uint8_t stop_bit, + int cmock_num_calls) +{ + switch (cmock_num_calls) { + case 0: // First call - manufacturer ID (7 bytes) - succeeds with "MAXIM" + if (data && bytes_number == 7) { + data[0] = 0x05; // Length + data[1] = 'M'; + data[2] = 'A'; + data[3] = 'X'; + data[4] = 'I'; + data[5] = 'M'; + data[6] = 0x00; + } + break; + case 1: // Second call - chip variant ID (11 bytes) - succeeds with "MAX17616" + if (data && bytes_number == 11) { + data[0] = 0x08; // Length + data[1] = 'M'; + data[2] = 'A'; + data[3] = 'X'; + data[4] = '1'; + data[5] = '7'; + data[6] = '6'; + data[7] = '1'; + data[8] = '6'; + data[9] = 0x00; + data[10] = 0x00; + } + break; + case 2: // Third call - PMBus revision (2 bytes) - returns wrong revision + if (data && bytes_number == 2) { + // Response: [0x32, 0x00] (wrong revision, expected 0x33) + data[0] = 0x32; + data[1] = 0x00; + } + break; + default: + if (data && bytes_number > 0) { + memset(data, 0, bytes_number); + } + break; + } + return 0; +} + +/******************************************************************************* + * TEST SETUP AND TEARDOWN + ******************************************************************************/ + +/** + * @brief Setup function called before each test + */ +void setUp(void) +{ + // Initialize test device structure + test_device = NULL; + memset(&test_init_param, 0, sizeof(test_init_param)); + memset(&test_i2c_desc, 0, sizeof(test_i2c_desc)); + memset(&test_i2c_init, 0, sizeof(test_i2c_init)); + + // Reset mock callback data + test_expected_read_data = 0; + memset(test_expected_read_buffer, 0, sizeof(test_expected_read_buffer)); + test_expected_read_length = 0; + test_i2c_read_call_count = 0; // Reset call count + + // Setup test parameters + test_init_param.chip_id = ID_MAX17616; + test_init_param.i2c_init = &test_i2c_init; + test_i2c_init.device_id = 1; + test_i2c_init.slave_address = 0x54; + + // Setup test support + max17616_test_setup(); +} + +/** + * @brief Teardown function called after each test + */ +void tearDown(void) +{ + max17616_test_teardown(); + test_device = NULL; +} + +/******************************************************************************* + * LOW-LEVEL I2C OPERATION TESTS + ******************************************************************************/ + +/** + * @brief Test max17616_send_byte function with successful I2C write + */ +void test_max17616_send_byte_success(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + uint8_t cmd = 0x03; // CLEAR_FAULTS command + + // Setup mock expectations + no_os_i2c_write_IgnoreAndReturn(0); + + // Test the function + int result = max17616_send_byte(&device, cmd); + + // Verify result + TEST_ASSERT_EQUAL_INT(0, result); +} + +/** + * @brief Test max17616_read_byte function with successful operation + */ +void test_max17616_read_byte_success(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + uint8_t cmd = 0x01; // OPERATION command + uint8_t data = 0; + uint8_t expected_data = 0x80; + + // Setup mock expectations - write command then read response + no_os_i2c_write_IgnoreAndReturn(0); + + // Use a callback to simulate reading data + no_os_i2c_read_Stub(test_i2c_read_callback); + + // Set the expected data for the callback to return + test_expected_read_data = expected_data; + + // Test the function + int result = max17616_read_byte(&device, cmd, &data); + + // Verify result and data + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_UINT8(expected_data, data); +} + +/** + * @brief Test max17616_read_byte function with I2C failures + */ +void test_max17616_read_byte_failures(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + uint8_t cmd = 0x01; + uint8_t data = 0; + + // Test write failure + no_os_i2c_write_IgnoreAndReturn(-EIO); + int result = max17616_read_byte(&device, cmd, &data); + TEST_ASSERT_EQUAL_INT(-EIO, result); + + // Test read failure (write succeeds, read fails) + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_IgnoreAndReturn(-EIO); + result = max17616_read_byte(&device, cmd, &data); + TEST_ASSERT_EQUAL_INT(-EIO, result); +} + +/** + * @brief Test max17616_read_word function with successful operation + */ +void test_max17616_read_word_success(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + uint8_t cmd = 0x88; // READ_VIN command + uint16_t word = 0; + uint8_t response_data[2] = {0x40, 0x30}; // Little-endian: 0x3040 + uint16_t expected_word = 0x3040; + + // Setup mock expectations + no_os_i2c_write_IgnoreAndReturn(0); + + // Setup multi-byte read callback + no_os_i2c_read_Stub(test_i2c_read_callback); + memcpy(test_expected_read_buffer, response_data, 2); + test_expected_read_length = 2; + + // Mock the little-endian conversion + no_os_get_unaligned_le16_ExpectAndReturn(response_data, expected_word); + + // Test the function + int result = max17616_read_word(&device, cmd, &word); + + // Verify result and data + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_UINT16(expected_word, word); +} + +/** + * @brief Test max17616_read_block_data function with successful operation + */ +void test_max17616_read_block_data_success(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + uint8_t cmd = 0x99; // MFR_ID command + uint8_t data[6] = {0}; + uint8_t response_data[7] = {0x05, 'M', 'A', 'X', 'I', 'M', 0x00}; // Length + data + size_t nbytes = 6; + + // Setup mock expectations + no_os_i2c_write_IgnoreAndReturn(0); + + // Setup multi-byte read callback for nbytes + 1 (7 bytes total) + no_os_i2c_read_Stub(test_i2c_read_callback); + memcpy(test_expected_read_buffer, response_data, 7); + test_expected_read_length = 7; + + // Test the function + int result = max17616_read_block_data(&device, cmd, data, nbytes); + + // Verify result and data + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_CHAR_ARRAY(&response_data[1], data, + 5); // Compare first 5 bytes +} + +/** + * @brief Test max17616_read_block_data function with oversized response + */ +void test_max17616_read_block_data_oversized(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + uint8_t cmd = 0x99; + uint8_t data[6] = {0}; + uint8_t response_data[7] = {0x10, 'M', 'A', 'X', 'I', 'M', 0x00}; // Length > nbytes + size_t nbytes = 6; + + // Setup mock expectations + no_os_i2c_write_IgnoreAndReturn(0); + + // Setup multi-byte read callback + no_os_i2c_read_Stub(test_i2c_read_callback); + memcpy(test_expected_read_buffer, response_data, 7); + test_expected_read_length = 7; + + // Test the function + int result = max17616_read_block_data(&device, cmd, data, nbytes); + + // Verify error is returned + TEST_ASSERT_EQUAL_INT(-EMSGSIZE, result); +} + +/******************************************************************************* + * DEVICE INITIALIZATION TESTS + ******************************************************************************/ + +/** + * @brief Test max17616_init function with successful flow (separate test for success case) + */ +void test_max17616_init_success_flow(void) +{ + struct max17616_dev *device = NULL; + + // Step 1: Mock memory allocation + no_os_calloc_ExpectAndReturn(0, sizeof(struct max17616_dev), (void*)os_malloc); + + // Step 2: Mock I2C initialization - must succeed + no_os_i2c_init_IgnoreAndReturn(0); + + // Step 3: Mock device identification sequence + + // 3a: Mock manufacturer ID verification + no_os_field_get_ExpectAndReturn(NO_OS_GENMASK(11, 8), MAX17616_MFR_ID, 6); + no_os_i2c_write_IgnoreAndReturn(0); // Write MFR_ID command + + // 3b: Mock chip variant identification + no_os_field_get_ExpectAndReturn(NO_OS_GENMASK(11, 8), MAX17616_IC_DEVICE_ID, + 10); + no_os_i2c_write_IgnoreAndReturn(0); // Write IC_DEVICE_ID command + + // 3c: Mock PMBus revision verification + no_os_i2c_write_IgnoreAndReturn(0); // Write PMBUS_REVISION command + no_os_get_unaligned_le16_IgnoreAndReturn(0x33); // Correct PMBus revision + + // Step 4: Mock clear faults + no_os_i2c_write_IgnoreAndReturn(0); // Clear faults command + + // Step 5: Mock set operation + no_os_i2c_write_IgnoreAndReturn(0); // Set operation command + + // Use the enhanced callback to handle all three read calls properly + no_os_i2c_read_Stub(test_i2c_read_init_callback); + + // Test the function + int result = max17616_init(&device, &test_init_param); + + // Verify successful initialization + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_NOT_NULL(device); +} + +/** + * @brief Test max17616_init function with I2C initialization failure + */ +void test_max17616_init_i2c_failure(void) +{ + struct max17616_dev *device = NULL; + + // Setup mock expectations + no_os_calloc_IgnoreAndReturn((void*)0x1000); + no_os_i2c_init_IgnoreAndReturn(-EIO); + no_os_free_Ignore(); + + // Test the function + int result = max17616_init(&device, &test_init_param); + + // Verify failure is returned + TEST_ASSERT_EQUAL_INT(-EIO, result); +} + +/** + * @brief Test max17616_init function with chip identification failure - unknown + * device variant + */ +void test_max17616_init_unknown_device_variant(void) +{ + struct max17616_dev *device = NULL; + + // Step 1: Mock memory allocation - succeeds + no_os_calloc_ExpectAndReturn(0, sizeof(struct max17616_dev), (void*)os_malloc); + + // Step 2: Mock I2C initialization - succeeds + no_os_i2c_init_IgnoreAndReturn(0); + + // Step 3: Mock device identification sequence - fails at chip variant identification + + // 3a: Mock manufacturer ID verification - succeeds + no_os_field_get_ExpectAndReturn(NO_OS_GENMASK(11, 8), MAX17616_MFR_ID, 6); + no_os_i2c_write_IgnoreAndReturn(0); // Write MFR_ID command + + // 3b: Mock chip variant identification - returns unknown device + no_os_field_get_ExpectAndReturn(NO_OS_GENMASK(11, 8), MAX17616_IC_DEVICE_ID, + 10); + no_os_i2c_write_IgnoreAndReturn(0); // Write IC_DEVICE_ID command + + // Setup callback for I2C reads - manufacturer ID succeeds, chip variant returns unknown + no_os_i2c_read_Stub(test_i2c_read_unknown_device_callback); + + // Expect cleanup on failure + no_os_i2c_remove_IgnoreAndReturn(0); + no_os_free_Ignore(); + + // Test the function + int result = max17616_init(&device, &test_init_param); + + // Verify failure is returned due to unknown device variant + TEST_ASSERT_EQUAL_INT(-ENODEV, result); + TEST_ASSERT_NULL(device); +} + +/** + * @brief Test max17616_init function with manufacturer ID verification failure + */ +void test_max17616_init_wrong_manufacturer(void) +{ + struct max17616_dev *device = NULL; + + // Step 1: Mock memory allocation - succeeds + no_os_calloc_ExpectAndReturn(0, sizeof(struct max17616_dev), (void*)os_malloc); + + // Step 2: Mock I2C initialization - succeeds + no_os_i2c_init_IgnoreAndReturn(0); + + // Step 3: Mock device identification sequence - fails at manufacturer ID verification + + // 3a: Mock manufacturer ID verification - fails with wrong manufacturer + no_os_field_get_ExpectAndReturn(NO_OS_GENMASK(11, 8), MAX17616_MFR_ID, 6); + no_os_i2c_write_IgnoreAndReturn(0); // Write MFR_ID command + + // Setup callback for I2C read - returns wrong manufacturer + no_os_i2c_read_Stub(test_i2c_read_wrong_mfr_callback); + + // Expect cleanup on failure + no_os_i2c_remove_IgnoreAndReturn(0); + no_os_free_Ignore(); + + // Test the function + int result = max17616_init(&device, &test_init_param); + + // Verify failure is returned due to wrong manufacturer + TEST_ASSERT_EQUAL_INT(-ENODEV, result); + TEST_ASSERT_NULL(device); +} + +/** + * @brief Test max17616_init function with PMBus revision verification failure + */ +void test_max17616_init_wrong_pmbus_revision(void) +{ + struct max17616_dev *device = NULL; + + // Step 1: Mock memory allocation - succeeds + no_os_calloc_ExpectAndReturn(0, sizeof(struct max17616_dev), (void*)os_malloc); + + // Step 2: Mock I2C initialization - succeeds + no_os_i2c_init_IgnoreAndReturn(0); + + // Step 3: Mock device identification sequence - fails at PMBus revision verification + + // 3a: Mock manufacturer ID verification - succeeds + no_os_field_get_ExpectAndReturn(NO_OS_GENMASK(11, 8), MAX17616_MFR_ID, 6); + no_os_i2c_write_IgnoreAndReturn(0); // Write MFR_ID command + + // 3b: Mock chip variant identification - succeeds + no_os_field_get_ExpectAndReturn(NO_OS_GENMASK(11, 8), MAX17616_IC_DEVICE_ID, + 10); + no_os_i2c_write_IgnoreAndReturn(0); // Write IC_DEVICE_ID command + + // 3c: Mock PMBus revision verification - fails with wrong revision + no_os_i2c_write_IgnoreAndReturn(0); // Write PMBUS_REVISION command + no_os_get_unaligned_le16_IgnoreAndReturn( + 0x32); // Wrong PMBus revision (expected 0x33) + + // Setup callback for I2C reads - manufacturer ID and chip variant succeed, PMBus revision returns wrong value + no_os_i2c_read_Stub(test_i2c_read_wrong_pmbus_callback); + + // Expect cleanup on failure + no_os_i2c_remove_IgnoreAndReturn(0); + no_os_free_Ignore(); + + // Test the function + int result = max17616_init(&device, &test_init_param); + + // Verify failure is returned due to wrong PMBus revision + TEST_ASSERT_EQUAL_INT(-ENODEV, result); + TEST_ASSERT_NULL(device); +} + +/** + * @brief Test max17616_remove function + */ +void test_max17616_remove_success(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + + // Setup mock expectations + no_os_i2c_remove_ExpectAndReturn(&test_i2c_desc, 0); + no_os_free_Expect(&device); + + // Test the function + int result = max17616_remove(&device); + + // Verify result + TEST_ASSERT_EQUAL_INT(0, result); +} + +/** + * @brief Test max17616_read_value function for VIN and power calculation + */ +void test_max17616_read_value_vin_and_power(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + int value = 0; + uint8_t response_data[2] = {0x40, 0x30}; // Little-endian: 0x3040 + + // Test VIN read + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_Stub(test_i2c_read_callback); + memcpy(test_expected_read_buffer, response_data, 2); + test_expected_read_length = 2; + no_os_get_unaligned_le16_ExpectAndReturn(response_data, 0x3040); + + int result = max17616_read_value(&device, MAX17616_VIN, &value); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_TRUE(value > 0); // Should be a positive voltage value + + // Test power calculation (VOUT * IOUT) + // First call for VOUT + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_IgnoreAndReturn(0); + no_os_get_unaligned_le16_IgnoreAndReturn(0x1000); // VOUT value + + // Second call for IOUT + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_IgnoreAndReturn(0); + no_os_get_unaligned_le16_IgnoreAndReturn(0x2000); // IOUT value + + result = max17616_read_value(&device, MAX17616_POWER, &value); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_TRUE(value >= 0); // Power should be non-negative +} + +/** + * @brief Test max17616_read_value function with invalid parameters + */ +void test_max17616_read_value_invalid_params(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + int value = 0; + + // Test with NULL device + int result = max17616_read_value(NULL, MAX17616_VIN, &value); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); + + // Test with NULL value pointer + result = max17616_read_value(&device, MAX17616_VIN, NULL); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); + + // Test with invalid value type + result = max17616_read_value(&device, 999, &value); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); +} + +/******************************************************************************* + * ENHANCED FUNCTION TESTS + ******************************************************************************/ + +/** + * @brief Test max17616_get_operation_state function + */ +void test_max17616_get_operation_state(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + bool enabled = false; + uint8_t operation_byte = 0x80; // Enabled + + // Setup mock expectations + no_os_i2c_write_IgnoreAndReturn(0); + + // Use callback for single-byte read + no_os_i2c_read_Stub(test_i2c_read_callback); + test_expected_read_data = operation_byte; + + // Test the function + int result = max17616_get_operation_state(&device, &enabled); + + // Verify result + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_TRUE(enabled); +} + +/** + * @brief Test max17616_read_telemetry_all function + */ +void test_max17616_read_telemetry_all_success(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + struct max17616_telemetry telemetry; + + // Setup mock expectations for multiple reads + // VIN read + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_IgnoreAndReturn(0); + no_os_get_unaligned_le16_IgnoreAndReturn(0x3040); + + // VOUT read + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_IgnoreAndReturn(0); + no_os_get_unaligned_le16_IgnoreAndReturn(0x1000); + + // IOUT read + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_IgnoreAndReturn(0); + no_os_get_unaligned_le16_IgnoreAndReturn(0x2000); + + // Temperature read + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_IgnoreAndReturn(0); + no_os_get_unaligned_le16_IgnoreAndReturn(0x1500); + + // Test the function + int result = max17616_read_telemetry_all(&device, &telemetry); + + // Verify result + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_TRUE(telemetry.valid_mask != 0); // Some values should be valid +} + +/** + * @brief Test max17616_get_fault_description function + */ +void test_max17616_get_fault_description(void) +{ + // Test known fault description + const char *desc = max17616_get_fault_description(MAX17616_FAULT_GRP_CML, + MAX17616_CML_FAULT_CMD); + TEST_ASSERT_EQUAL_STRING("Invalid or unsupported command received", desc); + + // Test unknown fault description + desc = max17616_get_fault_description(0xFFFF, 0xFF); + TEST_ASSERT_NULL(desc); +} + +/******************************************************************************* + * ADDITIONAL COVERAGE TESTS + ******************************************************************************/ + +/* Test for max17616_read_status with comprehensive fault testing */ +void test_max17616_read_status_comprehensive_faults(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + struct max17616_status status; + + // Mock STATUS_WORD read with selected fault bits set for testing conditional reads + no_os_i2c_write_CMockIgnoreAndReturn(1040, 0); + no_os_i2c_read_CMockIgnoreAndReturn(1041, 0); + + // Set CML, TEMP, and VOUT fault bits to test conditional register reads + uint16_t fault_word = (1 << MAX17616_STATUS_BIT_CML) | + (1 << MAX17616_STATUS_BIT_TEMPERATURE) | + (1 << (8 + MAX17616_STATUS_BIT_VOUT)); + no_os_get_unaligned_le16_CMockIgnoreAndReturn(1042, fault_word); + + // Mock individual status register reads (only for set fault bits) + // CML status read + no_os_i2c_write_CMockIgnoreAndReturn(1043, 0); + no_os_i2c_read_CMockIgnoreAndReturn(1044, 0); + + // Temperature status read + no_os_i2c_write_CMockIgnoreAndReturn(1045, 0); + no_os_i2c_read_CMockIgnoreAndReturn(1046, 0); + + // VOUT status read + no_os_i2c_write_CMockIgnoreAndReturn(1047, 0); + no_os_i2c_read_CMockIgnoreAndReturn(1048, 0); + + int result = max17616_read_status(&device, &status); + + TEST_ASSERT_EQUAL(0, result); + TEST_ASSERT_EQUAL(fault_word, status.word); + TEST_ASSERT_EQUAL((uint8_t)(fault_word & 0xFF), status.byte); +} + +/******************************************************************************* + * VOUT UV FAULT LIMIT TESTS + ******************************************************************************/ + +/** + * @brief Test max17616_get_vout_uv_fault_limit_config function with success + */ +void test_max17616_get_vout_uv_fault_limit_config_success(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + enum max17616_nominal_voltage voltage; + enum max17616_pgood_threshold threshold; + uint8_t test_value = + 0x14; // bits 4:2 = 101 (MAX17616_NOMINAL_48V), bits 1:0 = 00 (MAX17616_PGOOD_MINUS_10_PERCENT) + + // Setup mock expectations + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_Stub(test_i2c_read_callback); + test_expected_read_data = test_value; + + // Test the function + int result = max17616_get_vout_uv_fault_limit_config(&device, &voltage, + &threshold); + + // Verify result + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_NOMINAL_48V, voltage); + TEST_ASSERT_EQUAL_INT(MAX17616_PGOOD_MINUS_10_PERCENT, threshold); +} + +/** + * @brief Test parameter validation for key functions + */ +void test_max17616_parameter_validation(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + + // Test NULL device parameter + TEST_ASSERT_EQUAL_INT(-EINVAL, max17616_set_vout_uv_fault_limit_config(NULL, + MAX17616_NOMINAL_5V, MAX17616_PGOOD_MINUS_10_PERCENT)); + + // Test invalid enum parameters + TEST_ASSERT_EQUAL_INT(-EINVAL, max17616_set_vout_uv_fault_limit_config(&device, + (enum max17616_nominal_voltage)99, MAX17616_PGOOD_MINUS_10_PERCENT)); + TEST_ASSERT_EQUAL_INT(-EINVAL, max17616_set_vout_uv_fault_limit_config(&device, + MAX17616_NOMINAL_5V, (enum max17616_pgood_threshold)99)); +} + +/** + * @brief Test max17616_get_overcurrent_limit function - all branches + */ +void test_max17616_get_overcurrent_limit_all_branches(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + enum max17616_overcurrent_limit istlim; + int result; + + // Test NULL device parameter + result = max17616_get_overcurrent_limit(NULL, &istlim); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); + + // Test NULL istlim parameter + result = max17616_get_overcurrent_limit(&device, NULL); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); + + // Test I2C read failure + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_IgnoreAndReturn(-EIO); + result = max17616_get_overcurrent_limit(&device, &istlim); + TEST_ASSERT_EQUAL_INT(-EIO, result); + + // Test case 0x00 - MAX17616_OC_LIMIT_1_25 + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_Stub(test_i2c_read_callback); + test_expected_read_data = 0x00; // Bits 1:0 = 00 + result = max17616_get_overcurrent_limit(&device, &istlim); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_OC_LIMIT_1_25, istlim); + + // Test case 0x01 - MAX17616_OC_LIMIT_1_50 + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x01; // Bits 1:0 = 01 + result = max17616_get_overcurrent_limit(&device, &istlim); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_OC_LIMIT_1_50, istlim); + + // Test case 0x02 - MAX17616_OC_LIMIT_1_75 + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x02; // Bits 1:0 = 10 + result = max17616_get_overcurrent_limit(&device, &istlim); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_OC_LIMIT_1_75, istlim); + + // Test case 0x03 - MAX17616_OC_LIMIT_2_00 + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x03; // Bits 1:0 = 11 + result = max17616_get_overcurrent_limit(&device, &istlim); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_OC_LIMIT_2_00, istlim); + + // Note: Since we only check 2 bits (0x03 mask), all possible values 0x00-0x03 + // are valid, so the default case in the switch statement is unreachable. +} + +/** + * @brief Test max17616_get_overcurrent_timeout function - all branches + */ +void test_max17616_get_overcurrent_timeout_all_branches(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + enum max17616_overcurrent_timeout timeout; + int result; + + // Test NULL device parameter + result = max17616_get_overcurrent_timeout(NULL, &timeout); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); + + // Test NULL timeout parameter + result = max17616_get_overcurrent_timeout(&device, NULL); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); + + // Test I2C read failure + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_IgnoreAndReturn(-EIO); + result = max17616_get_overcurrent_timeout(&device, &timeout); + TEST_ASSERT_EQUAL_INT(-EIO, result); + + // Test case 0x00 - MAX17616_TIMEOUT_400US + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_Stub(test_i2c_read_callback); + test_expected_read_data = 0x00; // Bits 1:0 = 00 + result = max17616_get_overcurrent_timeout(&device, &timeout); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_TIMEOUT_400US, timeout); + + // Test case 0x01 - MAX17616_TIMEOUT_1MS + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x01; // Bits 1:0 = 01 + result = max17616_get_overcurrent_timeout(&device, &timeout); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_TIMEOUT_1MS, timeout); + + // Test case 0x02 - MAX17616_TIMEOUT_4MS + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x02; // Bits 1:0 = 10 + result = max17616_get_overcurrent_timeout(&device, &timeout); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_TIMEOUT_4MS, timeout); + + // Test case 0x03 - MAX17616_TIMEOUT_24MS + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x03; // Bits 1:0 = 11 + result = max17616_get_overcurrent_timeout(&device, &timeout); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_TIMEOUT_24MS, timeout); + + // Note: Since we only check 2 bits (0x03 mask), all possible values 0x00-0x03 + // are valid, so the default case in the switch statement is unreachable. + // However, if there were invalid enum values, we could test with: + // test_expected_read_data = 0xFF; // This would still result in 0x03 after mask +} + +/** + * @brief Test max17616_get_istart_ratio function - all branches + */ +void test_max17616_get_istart_ratio_all_branches(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + enum max17616_istart_ratio istart_ratio; + int result; + + // Test NULL device parameter + result = max17616_get_istart_ratio(NULL, &istart_ratio); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); + + // Test NULL istart_ratio parameter + result = max17616_get_istart_ratio(&device, NULL); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); + + // Test I2C read failure + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_IgnoreAndReturn(-EIO); + result = max17616_get_istart_ratio(&device, &istart_ratio); + TEST_ASSERT_EQUAL_INT(-EIO, result); + + // Test case 0x00 - MAX17616_ISTART_FULL + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_Stub(test_i2c_read_callback); + test_expected_read_data = 0x00; // Bits 3:0 = 0000 + result = max17616_get_istart_ratio(&device, &istart_ratio); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_ISTART_FULL, istart_ratio); + + // Test case 0x01 - MAX17616_ISTART_HALF + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x01; // Bits 3:0 = 0001 + result = max17616_get_istart_ratio(&device, &istart_ratio); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_ISTART_HALF, istart_ratio); + + // Test case 0x02 - MAX17616_ISTART_QUARTER + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x02; // Bits 3:0 = 0010 + result = max17616_get_istart_ratio(&device, &istart_ratio); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_ISTART_QUARTER, istart_ratio); + + // Test case 0x03 - MAX17616_ISTART_EIGHTH + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x03; // Bits 3:0 = 0011 + result = max17616_get_istart_ratio(&device, &istart_ratio); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_ISTART_EIGHTH, istart_ratio); + + // Test case 0x04 - MAX17616_ISTART_SIXTEENTH + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x04; // Bits 3:0 = 0100 + result = max17616_get_istart_ratio(&device, &istart_ratio); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_ISTART_SIXTEENTH, istart_ratio); + + // Test default case - invalid value (0x0F would be bits 3:0 = 1111) + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x0F; // Bits 3:0 = 1111 (invalid) + result = max17616_get_istart_ratio(&device, &istart_ratio); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); +} + +/** + * @brief Test max17616_get_current_limit_mode function - all branches + */ +void test_max17616_get_current_limit_mode_all_branches(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + enum max17616_current_limit_mode clmode; + int result; + + // Test NULL device parameter + result = max17616_get_current_limit_mode(NULL, &clmode); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); + + // Test NULL clmode parameter + result = max17616_get_current_limit_mode(&device, NULL); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); + + // Test I2C read failure + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_IgnoreAndReturn(-EIO); + result = max17616_get_current_limit_mode(&device, &clmode); + TEST_ASSERT_EQUAL_INT(-EIO, result); + + // Test case 0x00 - MAX17616_CLMODE_LATCH_OFF + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_Stub(test_i2c_read_callback); + test_expected_read_data = 0x00; // Bits 7:6 = 00 + result = max17616_get_current_limit_mode(&device, &clmode); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_CLMODE_LATCH_OFF, clmode); + + // Test case 0x40 - MAX17616_CLMODE_CONTINUOUS + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x40; // Bits 7:6 = 01 + result = max17616_get_current_limit_mode(&device, &clmode); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_CLMODE_CONTINUOUS, clmode); + + // Test case 0x80 - MAX17616_CLMODE_AUTO_RETRY + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x80; // Bits 7:6 = 10 + result = max17616_get_current_limit_mode(&device, &clmode); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_CLMODE_AUTO_RETRY, clmode); + + // Test default case - invalid value (0xC0 would be bits 7:6 = 11) + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0xC0; // Bits 7:6 = 11 (invalid) + result = max17616_get_current_limit_mode(&device, &clmode); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); +} + +/** + * @brief Test enum getter functions for coverage + */ +void test_max17616_enum_getters(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + uint8_t test_value; + int result; + + // Test istart ratio getter + enum max17616_istart_ratio istart_ratio; + test_value = 0x02; // MAX17616_ISTART_QUARTER + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_Stub(test_i2c_read_callback); + test_expected_read_data = test_value; + + result = max17616_get_istart_ratio(&device, &istart_ratio); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_ISTART_QUARTER, istart_ratio); + + // Test overcurrent timeout getter + enum max17616_overcurrent_timeout timeout; + test_value = 0x01; // MAX17616_TIMEOUT_1MS + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = test_value; + + result = max17616_get_overcurrent_timeout(&device, &timeout); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_TIMEOUT_1MS, timeout); + + // Test overcurrent limit getter + enum max17616_overcurrent_limit istlim; + test_value = 0x01; // MAX17616_OC_LIMIT_1_50 + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = test_value; + + result = max17616_get_overcurrent_limit(&device, &istlim); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_OC_LIMIT_1_50, istlim); +} + +/** + * @brief Test enum setter functions for coverage + */ +void test_max17616_enum_setters(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + + // Test current limit mode setter + no_os_i2c_write_IgnoreAndReturn(0); + int result = max17616_set_current_limit_mode(&device, + MAX17616_CLMODE_CONTINUOUS); + TEST_ASSERT_EQUAL_INT(0, result); + + // Test istart ratio setter + no_os_i2c_write_IgnoreAndReturn(0); + result = max17616_set_istart_ratio(&device, MAX17616_ISTART_HALF); + TEST_ASSERT_EQUAL_INT(0, result); + + // Test overcurrent timeout setter + no_os_i2c_write_IgnoreAndReturn(0); + result = max17616_set_overcurrent_timeout(&device, MAX17616_TIMEOUT_4MS); + TEST_ASSERT_EQUAL_INT(0, result); + + // Test overcurrent limit setter + no_os_i2c_write_IgnoreAndReturn(0); + result = max17616_set_overcurrent_limit(&device, MAX17616_OC_LIMIT_1_75); + TEST_ASSERT_EQUAL_INT(0, result); + + // Test vout uv fault limit config setter + no_os_i2c_write_IgnoreAndReturn(0); + result = max17616_set_vout_uv_fault_limit_config(&device, MAX17616_NOMINAL_12V, + MAX17616_PGOOD_MINUS_20_PERCENT); + TEST_ASSERT_EQUAL_INT(0, result); +} + +/** + * @brief Test individual status register read functions + */ +void test_max17616_individual_status_reads(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + uint8_t status_value; + + // Test read status byte + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_Stub(test_i2c_read_callback); + test_expected_read_data = 0x80; + + int result = max17616_read_status_byte(&device, &status_value); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_UINT8(0x80, status_value); + + // Test read status vout + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x01; + + result = max17616_read_status_vout(&device, &status_value); + TEST_ASSERT_EQUAL_INT(0, result); + + // Test read status iout + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x02; + + result = max17616_read_status_iout(&device, &status_value); + TEST_ASSERT_EQUAL_INT(0, result); + + // Test read status input + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x04; + + result = max17616_read_status_input(&device, &status_value); + TEST_ASSERT_EQUAL_INT(0, result); + + // Test read status temperature + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x08; + + result = max17616_read_status_temperature(&device, &status_value); + TEST_ASSERT_EQUAL_INT(0, result); + + // Test read status cml + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x10; + + result = max17616_read_status_cml(&device, &status_value); + TEST_ASSERT_EQUAL_INT(0, result); + + // Test read status mfr specific + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x20; + + result = max17616_read_status_mfr_specific(&device, &status_value); + TEST_ASSERT_EQUAL_INT(0, result); +} + +/** + * @brief Test additional value types for coverage + */ +void test_max17616_read_additional_value_types(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + int value; + + // Test VOUT value type + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_IgnoreAndReturn(0); + no_os_get_unaligned_le16_IgnoreAndReturn(0x2000); + + int result = max17616_read_value(&device, MAX17616_VOUT, &value); + TEST_ASSERT_EQUAL_INT(0, result); + + // Test IOUT value type + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_IgnoreAndReturn(0); + no_os_get_unaligned_le16_IgnoreAndReturn(0x1500); + + result = max17616_read_value(&device, MAX17616_IOUT, &value); + TEST_ASSERT_EQUAL_INT(0, result); + + // Test TEMP value type + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_IgnoreAndReturn(0); + no_os_get_unaligned_le16_IgnoreAndReturn(0x3000); + + result = max17616_read_value(&device, MAX17616_TEMP, &value); + TEST_ASSERT_EQUAL_INT(0, result); +} + +/** + * @brief Test capability and clear faults functions + */ +void test_max17616_capability_and_clear_faults(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + uint8_t capability; + + // Test read capability + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_Stub(test_i2c_read_callback); + test_expected_read_data = 0xA0; + + int result = max17616_read_capability(&device, &capability); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_UINT8(0xA0, capability); + + // Test clear faults + no_os_i2c_write_IgnoreAndReturn(0); + result = max17616_clear_faults(&device); + TEST_ASSERT_EQUAL_INT(0, result); +} + +/** + * @brief Test max17616_get_vout_uv_fault_limit_config function - all branches + */ +void test_max17616_get_vout_uv_fault_limit_config_all_branches(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + enum max17616_nominal_voltage voltage; + enum max17616_pgood_threshold threshold; + int result; + + // Test NULL device parameter + result = max17616_get_vout_uv_fault_limit_config(NULL, &voltage, &threshold); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); + + // Test NULL voltage parameter + result = max17616_get_vout_uv_fault_limit_config(&device, NULL, &threshold); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); + + // Test NULL threshold parameter + result = max17616_get_vout_uv_fault_limit_config(&device, &voltage, NULL); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); + + // Test I2C read failure + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_IgnoreAndReturn(-EIO); + result = max17616_get_vout_uv_fault_limit_config(&device, &voltage, &threshold); + TEST_ASSERT_EQUAL_INT(-EIO, result); + + // Test voltage case 0x00 (bits 4:2 = 000) with threshold 0x00 (bits 1:0 = 00) + no_os_i2c_write_IgnoreAndReturn(0); + no_os_i2c_read_Stub(test_i2c_read_callback); + test_expected_read_data = 0x00; // voltage bits 000, threshold bits 00 + result = max17616_get_vout_uv_fault_limit_config(&device, &voltage, &threshold); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_NOMINAL_5V, voltage); + TEST_ASSERT_EQUAL_INT(MAX17616_PGOOD_MINUS_10_PERCENT, threshold); + + // Test voltage case 0x01 (bits 4:2 = 001) with threshold 0x01 (bits 1:0 = 01) + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x05; // voltage bits 001, threshold bits 01 + result = max17616_get_vout_uv_fault_limit_config(&device, &voltage, &threshold); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_NOMINAL_9V, voltage); + TEST_ASSERT_EQUAL_INT(MAX17616_PGOOD_MINUS_20_PERCENT, threshold); + + // Test voltage case 0x02 (bits 4:2 = 010) with threshold 0x02 (bits 1:0 = 10) + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x0A; // voltage bits 010, threshold bits 10 + result = max17616_get_vout_uv_fault_limit_config(&device, &voltage, &threshold); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_NOMINAL_12V, voltage); + TEST_ASSERT_EQUAL_INT(MAX17616_PGOOD_MINUS_30_PERCENT, threshold); + + // Test voltage case 0x03 (bits 4:2 = 011) + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x0C; // voltage bits 011, threshold bits 00 + result = max17616_get_vout_uv_fault_limit_config(&device, &voltage, &threshold); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_NOMINAL_24V, voltage); + + // Test voltage case 0x04 (bits 4:2 = 100) + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x10; // voltage bits 100, threshold bits 00 + result = max17616_get_vout_uv_fault_limit_config(&device, &voltage, &threshold); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_NOMINAL_36V, voltage); + + // Test voltage case 0x05 (bits 4:2 = 101) + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x14; // voltage bits 101, threshold bits 00 + result = max17616_get_vout_uv_fault_limit_config(&device, &voltage, &threshold); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_NOMINAL_48V, voltage); + + // Test voltage case 0x06 (bits 4:2 = 110) + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x18; // voltage bits 110, threshold bits 00 + result = max17616_get_vout_uv_fault_limit_config(&device, &voltage, &threshold); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_NOMINAL_60V, voltage); + + // Test voltage case 0x07 (bits 4:2 = 111) + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x1C; // voltage bits 111, threshold bits 00 + result = max17616_get_vout_uv_fault_limit_config(&device, &voltage, &threshold); + TEST_ASSERT_EQUAL_INT(0, result); + TEST_ASSERT_EQUAL_INT(MAX17616_NOMINAL_72V, voltage); + + // Test threshold case 0x03 (bits 1:0 = 11) - invalid, should return -EINVAL + no_os_i2c_write_IgnoreAndReturn(0); + test_expected_read_data = 0x03; // voltage bits 000, threshold bits 11 (invalid) + result = max17616_get_vout_uv_fault_limit_config(&device, &voltage, &threshold); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); +} + +/** + * @brief Test max17616_read_status function with additional fault conditions + */ +void test_max17616_read_status_additional_faults(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + struct max17616_status status; + + // Mock STATUS_WORD read with INPUT, IOUT/POUT, and MFR_SPECIFIC fault bits set + no_os_i2c_write_CMockIgnoreAndReturn(1050, 0); + no_os_i2c_read_CMockIgnoreAndReturn(1051, 0); + + // Set INPUT (bit 5 of high byte), IOUT_POUT (bit 6 of high byte), and MFR (bit 4 of high byte) + uint16_t fault_word = (1 << (8 + MAX17616_STATUS_BIT_INPUT)) | + (1 << (8 + MAX17616_STATUS_BIT_IOUT_POUT)) | + (1 << (8 + MAX17616_STATUS_BIT_MFR)); + no_os_get_unaligned_le16_CMockIgnoreAndReturn(1052, fault_word); + + // Mock individual status register reads (only for set fault bits) + + // Input status read (triggered by INPUT bit) + no_os_i2c_write_CMockIgnoreAndReturn(1053, 0); + no_os_i2c_read_CMockIgnoreAndReturn(1054, 0); + + // IOUT status read (triggered by IOUT_POUT bit) + no_os_i2c_write_CMockIgnoreAndReturn(1055, 0); + no_os_i2c_read_CMockIgnoreAndReturn(1056, 0); + + // MFR specific status read (triggered by MFR bit) + no_os_i2c_write_CMockIgnoreAndReturn(1057, 0); + no_os_i2c_read_CMockIgnoreAndReturn(1058, 0); + + int result = max17616_read_status(&device, &status); + + TEST_ASSERT_EQUAL(0, result); + TEST_ASSERT_EQUAL(fault_word, status.word); + TEST_ASSERT_EQUAL((uint8_t)(fault_word & 0xFF), status.byte); +} + +/** + * @brief Test max17616_read_value error paths for maximum coverage efficiency + */ +void test_max17616_read_value_power_error_path(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + int value; + + /* Test MAX17616_POWER case where VOUT read fails - covers uncovered branch in line 532-533 */ + /* Mock the first read_value call (VOUT) to fail */ + no_os_i2c_write_CMockIgnoreAndReturn(2001, -EIO); + + int result = max17616_read_value(&device, MAX17616_POWER, &value); + + TEST_ASSERT_EQUAL_INT(-EIO, result); +} + +/** + * @brief Test max17616_write_byte I2C failure - used by multiple setter functions + */ +void test_max17616_write_byte_failure(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + uint8_t cmd = MAX17616_CMD(MAX17616_OPERATION); + uint8_t value = 0x80; + + /* Mock I2C write failure */ + no_os_i2c_write_CMockIgnoreAndReturn(2002, -EIO); + + int result = max17616_write_byte(&device, cmd, value); + + TEST_ASSERT_EQUAL_INT(-EIO, result); +} + +/** + * @brief Test setter functions with NULL dev parameter for validation coverage + */ +void test_max17616_setters_null_dev_validation(void) +{ + /* These functions don't validate NULL dev parameters - they pass through to max17616_write_byte + which doesn't have NULL validation. So we'll test other parameter validation instead. */ + + /* Test max17616_get_operation_state with NULL parameters (this function does validate) */ + bool enabled; + int result = max17616_get_operation_state(NULL, &enabled); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); + + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + result = max17616_get_operation_state(&device, NULL); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); +} + +/** + * @brief Test invalid enum validation in max17616_set_vout_uv_fault_limit_config + */ +void test_max17616_set_vout_uv_fault_limit_config_invalid_params(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + + /* Test with invalid voltage enum (> MAX17616_NOMINAL_72V) */ + int result = max17616_set_vout_uv_fault_limit_config(&device, + (enum max17616_nominal_voltage)8, MAX17616_PGOOD_MINUS_10_PERCENT); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); + + /* Test with invalid threshold enum (> MAX17616_PGOOD_MINUS_30_PERCENT) */ + result = max17616_set_vout_uv_fault_limit_config(&device, MAX17616_NOMINAL_12V, + (enum max17616_pgood_threshold)4); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); + + /* Test with NULL dev */ + result = max17616_set_vout_uv_fault_limit_config(NULL, MAX17616_NOMINAL_12V, + MAX17616_PGOOD_MINUS_10_PERCENT); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); +} + +/** + * @brief Test invalid raw values in max17616_get_vout_uv_fault_limit_config switch statements + */ +void test_max17616_get_vout_uv_fault_limit_config_invalid_raw_values(void) +{ + struct max17616_dev device = {.i2c_desc = &test_i2c_desc}; + enum max17616_nominal_voltage voltage; + enum max17616_pgood_threshold threshold; + + /* Test with NULL pointers for additional coverage */ + int result = max17616_get_vout_uv_fault_limit_config(&device, NULL, &threshold); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); + + result = max17616_get_vout_uv_fault_limit_config(&device, &voltage, NULL); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); + + result = max17616_get_vout_uv_fault_limit_config(NULL, &voltage, &threshold); + TEST_ASSERT_EQUAL_INT(-EINVAL, result); +}