/*
* fusb302 usb phy driver for type-c and PD
*
* Copyright (C) 2015, 2016 Fairchild Semiconductor Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Seee the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
*/
#include
#include // File permission masks
#include // Kernel datatypes
#include // I2C access, mutex
#include // Linux kernel error definitions
#include // hrtimer
#include // work_struct, delayed_work
#include // udelay, usleep_range, msleep
#include
#include
#include
#include
#include
#include
#include
#include
#include "fusb30x_global.h" // Chip structure access
#include "../core/core.h" // Core access
#include "../core/fusb30X.h"
#include "platform_helpers.h"
#ifdef FSC_DEBUG
#include "hostcomm.h"
#include "../core/PD_Types.h" // State Log states
#include "../core/TypeC_Types.h" // State Log states
#endif // FSC_DEBUG
/*********************************************************************************************************************/
/*********************************************************************************************************************/
/******************************************** GPIO Interface ******************************************/
/*********************************************************************************************************************/
/*********************************************************************************************************************/
const char* FUSB_DT_INTERRUPT_INTN = "fsc_interrupt_int_n"; // Name of the INT_N interrupt in the Device Tree
#define FUSB_DT_GPIO_INTN "fairchild,int_n" // Name of the Int_N GPIO pin in the Device Tree
#define FUSB_DT_GPIO_VBUS_5V "fairchild,vbus5v" // Name of the VBus 5V GPIO pin in the Device Tree
#define FUSB_DT_GPIO_VBUS_OTHER "fairchild,vbusOther" // Name of the VBus Other GPIO pin in the Device Tree
#define FUSB_I2C_RETRY_DELAY 50 // in ms
#ifdef FSC_DEBUG
#define FUSB_DT_GPIO_DEBUG_SM_TOGGLE "fairchild,dbg_sm" // Name of the debug State Machine toggle GPIO pin in the Device Tree
#endif // FSC_DEBUG
#ifdef FSC_INTERRUPT_TRIGGERED
/* Internal forward declarations */
static irqreturn_t _fusb_isr_intn(int irq, void *dev_id);
#endif // FSC_INTERRUPT_TRIGGERED
extern FSC_BOOL VCONN_enabled;
extern DeviceReg_t Registers;
FSC_S32 fusb_InitializeGPIO(void)
{
FSC_S32 ret = 0;
struct device_node* node;
struct pinctrl_state *set_state;
struct fusb30x_chip* chip = fusb30x_GetChip();
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
return -ENOMEM;
}
/* Get our device tree node */
node = chip->client->dev.of_node;
chip->fusb302_pinctrl = devm_pinctrl_get(&chip->client->dev);
if (IS_ERR(chip->fusb302_pinctrl)) {
if (of_property_read_bool(node, "pinctrl-names")) {
dev_err(&chip->client->dev, "Error encountered while getting pinctrl");
ret = PTR_ERR(chip->fusb302_pinctrl);
}
dev_dbg(&chip->client->dev, "Target does not use pinctrl\n");
chip->fusb302_pinctrl = NULL;
}
if (chip->fusb302_pinctrl) {
set_state = pinctrl_lookup_state(chip->fusb302_pinctrl, "default");
if (IS_ERR(set_state)) {
pr_err("FUSB: cannot get fusb302 pinctrl default state");
return PTR_ERR(set_state);
}
pinctrl_select_state(chip->fusb302_pinctrl, set_state);
set_state = pinctrl_lookup_state(chip->fusb302_pinctrl, "vconn_disable");
if (IS_ERR(set_state)) {
pr_err("FUSB: cannot get fusb302 pinctrl vconn_disable state");
return PTR_ERR(set_state);
}
pinctrl_select_state(chip->fusb302_pinctrl, set_state);
}
/* Get our GPIO pins from the device tree, allocate them, and then set their direction (input/output) */
chip->gpio_IntN = of_get_named_gpio(node, FUSB_DT_GPIO_INTN, 0);
if (!gpio_is_valid(chip->gpio_IntN))
{
dev_err(&chip->client->dev, "%s - Error: Could not get named GPIO for Int_N! Error code: %d\n", __func__, chip->gpio_IntN);
return chip->gpio_IntN;
}
// Request our GPIO to reserve it in the system - this should help ensure we have exclusive access (not guaranteed)
ret = gpio_request(chip->gpio_IntN, FUSB_DT_GPIO_INTN);
if (ret < 0)
{
dev_err(&chip->client->dev, "%s - Error: Could not request GPIO for Int_N! Error code: %d\n", __func__, ret);
return ret;
}
ret = gpio_direction_input(chip->gpio_IntN);
if (ret < 0)
{
dev_err(&chip->client->dev, "%s - Error: Could not set GPIO direction to input for Int_N! Error code: %d\n", __func__, ret);
return ret;
}
#ifdef FSC_DEBUG
/* Export to sysfs */
gpio_export(chip->gpio_IntN, false);
gpio_export_link(&chip->client->dev, FUSB_DT_GPIO_INTN, chip->gpio_IntN);
#endif // FSC_DEBUG
pr_info("FUSB %s - INT_N GPIO initialized as pin '%d'\n", __func__, chip->gpio_IntN);
#ifdef VBUS_5V_SUPPORTED
// VBus 5V
chip->gpio_VBus5V = of_get_named_gpio(node, FUSB_DT_GPIO_VBUS_5V, 0);
if (!gpio_is_valid(chip->gpio_VBus5V))
{
dev_err(&chip->client->dev, "%s - Error: Could not get named GPIO for VBus5V! Error code: %d\n", __func__, chip->gpio_VBus5V);
fusb_GPIO_Cleanup();
return chip->gpio_VBus5V;
}
// Request our GPIO to reserve it in the system - this should help ensure we have exclusive access (not guaranteed)
ret = gpio_request(chip->gpio_VBus5V, FUSB_DT_GPIO_VBUS_5V);
if (ret < 0)
{
dev_err(&chip->client->dev, "%s - Error: Could not request GPIO for VBus5V! Error code: %d\n", __func__, ret);
return ret;
}
ret = gpio_direction_output(chip->gpio_VBus5V, chip->gpio_VBus5V_value);
if (ret < 0)
{
dev_err(&chip->client->dev, "%s - Error: Could not set GPIO direction to output for VBus5V! Error code: %d\n", __func__, ret);
fusb_GPIO_Cleanup();
return ret;
}
#ifdef FSC_DEBUG
// Export to sysfs
gpio_export(chip->gpio_VBus5V, false);
gpio_export_link(&chip->client->dev, FUSB_DT_GPIO_VBUS_5V, chip->gpio_VBus5V);
#endif // FSC_DEBUG
pr_info("FUSB %s - VBus 5V initialized as pin '%d' and is set to '%d'\n", __func__, chip->gpio_VBus5V, chip->gpio_VBus5V_value ? 1 : 0);
#endif
#ifdef VBUS_OTHER_SUPPORTED
// VBus other (eg. 12V)
// NOTE - This VBus is optional, so if it doesn't exist then fake it like it's on.
chip->gpio_VBusOther = of_get_named_gpio(node, FUSB_DT_GPIO_VBUS_OTHER, 0);
if (!gpio_is_valid(chip->gpio_VBusOther))
{
// Soft fail - provide a warning, but don't quit because we don't really need this VBus if only using VBus5v
pr_warning("%s - Warning: Could not get GPIO for VBusOther! Error code: %d\n", __func__, chip->gpio_VBusOther);
}
else
{
// Request our GPIO to reserve it in the system - this should help ensure we have exclusive access (not guaranteed)
ret = gpio_request(chip->gpio_VBusOther, FUSB_DT_GPIO_VBUS_OTHER);
if (ret < 0)
{
dev_err(&chip->client->dev, "%s - Error: Could not request GPIO for VBusOther! Error code: %d\n", __func__, ret);
return ret;
}
ret = gpio_direction_output(chip->gpio_VBusOther, chip->gpio_VBusOther_value);
if (ret != 0)
{
dev_err(&chip->client->dev, "%s - Error: Could not set GPIO direction to output for VBusOther! Error code: %d\n", __func__, ret);
return ret;
}
else
{
pr_info("FUSB %s - VBusOther initialized as pin '%d' and is set to '%d'\n", __func__, chip->gpio_VBusOther, chip->gpio_VBusOther_value ? 1 : 0);
}
}
#endif
#ifdef FSC_DEBUG
// State Machine Debug Notification
// Optional GPIO - toggles each time the state machine is called
chip->dbg_gpio_StateMachine = of_get_named_gpio(node, FUSB_DT_GPIO_DEBUG_SM_TOGGLE, 0);
if (!gpio_is_valid(chip->dbg_gpio_StateMachine))
{
// Soft fail - provide a warning, but don't quit because we don't really need this VBus if only using VBus5v
pr_warning("%s - Warning: Could not get GPIO for Debug GPIO! Error code: %d\n", __func__, chip->dbg_gpio_StateMachine);
}
else
{
// Request our GPIO to reserve it in the system - this should help ensure we have exclusive access (not guaranteed)
ret = gpio_request(chip->dbg_gpio_StateMachine, FUSB_DT_GPIO_DEBUG_SM_TOGGLE);
if (ret < 0)
{
dev_err(&chip->client->dev, "%s - Error: Could not request GPIO for Debug GPIO! Error code: %d\n", __func__, ret);
return ret;
}
ret = gpio_direction_output(chip->dbg_gpio_StateMachine, chip->dbg_gpio_StateMachine_value);
if (ret != 0)
{
dev_err(&chip->client->dev, "%s - Error: Could not set GPIO direction to output for Debug GPIO! Error code: %d\n", __func__, ret);
return ret;
}
else
{
pr_info("FUSB %s - Debug GPIO initialized as pin '%d' and is set to '%d'\n", __func__, chip->dbg_gpio_StateMachine, chip->dbg_gpio_StateMachine_value ? 1 : 0);
}
// Export to sysfs
gpio_export(chip->dbg_gpio_StateMachine, true); // Allow direction to change to provide max debug flexibility
gpio_export_link(&chip->client->dev, FUSB_DT_GPIO_DEBUG_SM_TOGGLE, chip->dbg_gpio_StateMachine);
}
#endif // FSC_DEBUG
return 0; // Success!
}
extern FSC_BOOL IsPRSwap; // Variable indicating that a PRSwap is occurring
extern ConnectionState ConnState; // Variable indicating the current connection state
extern PolicyState_t PolicyState;
void fusb_GPIO_Set_VBus5v(FSC_BOOL set)
{
struct fusb30x_chip* chip = fusb30x_GetChip();
int ret = -1, retry = 0;
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
return;
}
do {
pr_info("FUSB %s: set vbus ctrl: %d, typec_state(0x%x), pd_state(0x%x), retry: %d\n", __func__, set, ConnState, PolicyState, retry);
if (chip->uc && chip->uc->pd_vbus_ctrl)
ret = chip->uc->pd_vbus_ctrl(set ? 1 : 0, IsPRSwap);
if (ret < 0) {
msleep(1000);
retry++;
}
} while(ret < 0 && retry < 5);
#ifdef VBUS_5V_SUPPORTED
// GPIO must be valid by this point
if (gpio_cansleep(chip->gpio_VBus5V))
{
/*
* If your system routes GPIO calls through a queue of some kind, then
* it may need to be able to sleep. If so, this call must be used.
*/
gpio_set_value_cansleep(chip->gpio_VBus5V, set ? 1 : 0);
}
else
{
gpio_set_value(chip->gpio_VBus5V, set ? 1 : 0);
}
chip->gpio_VBus5V_value = set;
pr_debug("FUSB %s - VBus 5V set to: %d\n", __func__, chip->gpio_VBus5V_value ? 1 : 0);
#endif
}
void fusb_GPIO_Set_VBusOther(FSC_BOOL set)
{
struct fusb30x_chip* chip = fusb30x_GetChip();
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
}
#ifdef VBUS_OTHER_SUPPORTED
// Only try to set if feature is enabled, otherwise just fake it
if (gpio_is_valid(chip->gpio_VBusOther))
{
/*
* If your system routes GPIO calls through a queue of some kind, then
* it may need to be able to sleep. If so, this call must be used.
*/
if (gpio_cansleep(chip->gpio_VBusOther))
{
gpio_set_value_cansleep(chip->gpio_VBusOther, set ? 1 : 0);
}
else
{
gpio_set_value(chip->gpio_VBusOther, set ? 1 : 0);
}
}
chip->gpio_VBusOther_value = set;
#endif
}
FSC_BOOL fusb_GPIO_Get_VBus5v(void)
{
struct fusb30x_chip* chip = fusb30x_GetChip();
FSC_BOOL ret = false;
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
return false;
}
if (chip->uc && chip->uc->vbus_boost_enabled)
ret = chip->uc->vbus_boost_enabled();
return ret;
#ifdef VBUS_5V_SUPPORTED
if (!gpio_is_valid(chip->gpio_VBus5V))
{
pr_debug("FUSB %s - Error: VBus 5V pin invalid! Pin value: %d\n", __func__, chip->gpio_VBus5V);
}
return chip->gpio_VBus5V_value;
#endif
}
FSC_BOOL fusb_GPIO_Get_VBusOther(void)
{
struct fusb30x_chip* chip = fusb30x_GetChip();
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
return false;
}
return false;
#ifdef VBUS_OTHER_SUPPORTED
return chip->gpio_VBusOther_value;
#endif
}
FSC_BOOL fusb_GPIO_Get_IntN(void)
{
FSC_S32 ret = 0;
struct fusb30x_chip* chip = fusb30x_GetChip();
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
return false;
}
else
{
/*
* If your system routes GPIO calls through a queue of some kind, then
* it may need to be able to sleep. If so, this call must be used.
*/
if (gpio_cansleep(chip->gpio_IntN))
{
ret = !gpio_get_value_cansleep(chip->gpio_IntN);
}
else
{
ret = !gpio_get_value(chip->gpio_IntN); // Int_N is active low
}
return (ret != 0);
}
}
FSC_BOOL fusb_Power_Vconn(FSC_BOOL set)
{
struct fusb30x_chip *chip = fusb30x_GetChip();
struct pinctrl_state *set_state;
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
}
if (!chip->boost_5v) {
chip->boost_5v = devm_regulator_get(&chip->client->dev, "V_USB_boost");
if (IS_ERR(chip->boost_5v)) {
pr_err("FUSB %s: still unable to get boost_5v regulator\n", __func__);
return FALSE;
}
}
pr_info("FUSB %s: typec_state(0x%x), pd_state(0x%x), set=%d\n", __func__, ConnState, PolicyState, set);
if (set) {
if (regulator_enable(chip->boost_5v)) {
pr_err("FUSB %s: Unable to disable boost_5v regulator\n", __func__);
return FALSE;
}
pr_info("FUSB : Vconn enabled\n");
} else {
if (regulator_disable(chip->boost_5v)) {
pr_err("FUSB %s: Unable to enable boost_5v regulator\n", __func__);
return FALSE;
}
pr_info("FUSB : Vconn disabled\n");
}
if (chip->fusb302_pinctrl) {
set_state = pinctrl_lookup_state(chip->fusb302_pinctrl, set ? "vconn_enable" : "vconn_disable");
if (IS_ERR(set_state)) {
pr_err("FUSB : cannot get fusb302 pinctrl vconn_contrl state");
return FALSE;
}
pinctrl_select_state(chip->fusb302_pinctrl, set_state);
}
return TRUE;
}
#ifdef FSC_DEBUG
void dbg_fusb_GPIO_Set_SM_Toggle(FSC_BOOL set)
{
struct fusb30x_chip* chip = fusb30x_GetChip();
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
}
if (gpio_is_valid(chip->dbg_gpio_StateMachine))
{
/*
* If your system routes GPIO calls through a queue of some kind, then
* it may need to be able to sleep. If so, this call must be used.
*/
if (gpio_cansleep(chip->dbg_gpio_StateMachine))
{
gpio_set_value_cansleep(chip->dbg_gpio_StateMachine, set ? 1 : 0);
}
else
{
gpio_set_value(chip->dbg_gpio_StateMachine, set ? 1 : 0);
}
chip->dbg_gpio_StateMachine_value = set;
}
}
FSC_BOOL dbg_fusb_GPIO_Get_SM_Toggle(void)
{
struct fusb30x_chip* chip = fusb30x_GetChip();
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
return false;
}
return chip->dbg_gpio_StateMachine_value;
}
#endif // FSC_DEBUG
void fusb_GPIO_Cleanup(void)
{
struct fusb30x_chip* chip = fusb30x_GetChip();
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
return;
}
#ifdef FSC_INTERRUPT_TRIGGERED
if (gpio_is_valid(chip->gpio_IntN) && chip->gpio_IntN_irq != -1) // -1 indicates that we don't have an IRQ to free
{
devm_free_irq(&chip->client->dev, chip->gpio_IntN_irq, chip);
}
#endif // FSC_INTERRUPT_TRIGGERED
if (gpio_is_valid(chip->gpio_IntN) >= 0)
{
#ifdef FSC_DEBUG
gpio_unexport(chip->gpio_IntN);
#endif // FSC_DEBUG
gpio_free(chip->gpio_IntN);
}
#ifdef VBUS_5V_SUPPORTED
if (gpio_is_valid(chip->gpio_VBus5V) >= 0)
{
#ifdef FSC_DEBUG
gpio_unexport(chip->gpio_VBus5V);
#endif // FSC_DEBUG
gpio_free(chip->gpio_VBus5V);
}
#endif
#ifdef VBUS_OTHER_SUPPORTED
if (gpio_is_valid(chip->gpio_VBusOther) >= 0)
{
gpio_free(chip->gpio_VBusOther);
}
#endif
#ifdef FSC_DEBUG
if (gpio_is_valid(chip->dbg_gpio_StateMachine) >= 0)
{
gpio_unexport(chip->dbg_gpio_StateMachine);
gpio_free(chip->dbg_gpio_StateMachine);
}
#endif // FSC_DEBUG
}
/*********************************************************************************************************************/
/*********************************************************************************************************************/
/******************************************** I2C Interface ******************************************/
/*********************************************************************************************************************/
/*********************************************************************************************************************/
FSC_BOOL fusb_I2C_WriteData(FSC_U8 address, FSC_U8 length, FSC_U8* data)
{
FSC_S32 i = 0;
FSC_S32 ret = 0;
struct fusb30x_chip* chip = fusb30x_GetChip();
if (chip == NULL || chip->client == NULL || data == NULL) // Sanity check
{
pr_err("FUSB %s - Error: %s is NULL!\n", __func__, (chip == NULL ? "Internal chip structure"
: (chip->client == NULL ? "I2C Client"
: "Write data buffer")));
return false;
}
mutex_lock(&chip->lock);
// Retry on failure up to the retry limit
for (i = 0; i <= chip->numRetriesI2C; i++)
{
if (atomic_read(&chip->pm_suspended)) {
pr_debug("FUSB %s: pm_suspended, retry\n", __func__);
msleep(FUSB_I2C_RETRY_DELAY);
continue;
}
ret = i2c_smbus_write_i2c_block_data(chip->client, // Perform the actual I2C write on our client
address, // Register address to write to
length, // Number of bytes to write
data); // Ptr to unsigned char data
if (ret < 0) // Errors report as negative
{
if (ret == -ERANGE) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ERANGE. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EINVAL) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EINVAL. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EAGAIN) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EAGAIN. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EALREADY) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EALREADY. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EBADE) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EBADE. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EBADMSG) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EBADMSG. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EBUSY) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EBUSY. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ECANCELED) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ECANCELED. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ECOMM) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ECOMM. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ECONNABORTED) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ECONNABORTED. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ECONNREFUSED) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ECONNREFUSED. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ECONNRESET) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ECONNRESET. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EDEADLK) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EDEADLK. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EDEADLOCK) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EDEADLOCK. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EDESTADDRREQ) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EDESTADDRREQ. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EFAULT) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EFAULT. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EHOSTDOWN) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EHOSTDOWN. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EHOSTUNREACH) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EHOSTUNREACH. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EILSEQ) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EILSEQ. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EINPROGRESS) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EINPROGRESS. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EINTR) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EINTR. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EIO) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EIO. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ELIBACC) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ELIBACC. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ELIBBAD) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ELIBBAD. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ELIBMAX) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ELIBMAX. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ELOOP) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ELOOP. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EMSGSIZE) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EMSGSIZE. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EMULTIHOP) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EMULTIHOP. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOBUFS) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ENOBUFS. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENODATA) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ENODATA. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENODEV) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ENODEV. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOLCK) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ENOLCK. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOMEM) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ENOMEM. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOMSG) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ENOMSG. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOPROTOOPT) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ENOPROTOOPT. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOSPC) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ENOSPC. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOSYS) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ENOSYS. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOTBLK) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ENOTBLK. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOTTY) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ENOTTY. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOTUNIQ) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ENOTUNIQ. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENXIO) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ENXIO. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EOVERFLOW) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EOVERFLOW. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EPERM) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EPERM. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EPFNOSUPPORT) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EPFNOSUPPORT. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EPIPE) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EPIPE. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EPROTO) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EPROTO. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EPROTONOSUPPORT) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EPROTONOSUPPORT. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ERANGE) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ERANGE. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EREMCHG) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EREMCHG. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EREMOTE) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EREMOTE. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EREMOTEIO) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EREMOTEIO. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ERESTART) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ERESTART. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ESRCH) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ESRCH. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ETIME) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ETIME. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ETIMEDOUT) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ETIMEDOUT. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ETXTBSY) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -ETXTBSY. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EUCLEAN) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EUCLEAN. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EUNATCH) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EUNATCH. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EUSERS) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EUSERS. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EWOULDBLOCK) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EWOULDBLOCK. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EXDEV) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EXDEV. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EXFULL) { dev_err(&chip->client->dev, "%s - I2C Error block writing byte data. Address: '0x%02x', Return: -EXFULL. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EOPNOTSUPP) { dev_err(&chip->client->dev, "%s - I2C Error writing byte data. Address: '0x%02x', Return: -EOPNOTSUPP. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EPROBE_DEFER) { dev_err(&chip->client->dev, "%s - I2C Error writing byte data. Address: '0x%02x', Return: -EPROBE_DEFER. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOENT) { dev_err(&chip->client->dev, "%s - I2C Error writing byte data. Address: '0x%02x', Return: -ENOENT. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else { dev_err(&chip->client->dev, "%s - Unexpected I2C error block writing byte data. Address: '0x%02x', Return: '%d'. Attempt #%d / %d...\n", __func__, address, ret, i, chip->numRetriesI2C); }
}
else // Successful i2c writes should always return 0
{
break;
}
}
mutex_unlock(&chip->lock);
return (ret >= 0);
}
FSC_BOOL fusb_I2C_ReadData(FSC_U8 address, FSC_U8* data)
{
FSC_S32 i = 0;
FSC_S32 ret = 0;
struct fusb30x_chip* chip = fusb30x_GetChip();
if (chip == NULL || chip->client == NULL || data == NULL)
{
pr_err("FUSB %s - Error: %s is NULL!\n", __func__, (chip == NULL ? "Internal chip structure"
: (chip->client == NULL ? "I2C Client"
: "read data buffer")));
return false;
}
mutex_lock(&chip->lock);
// Retry on failure up to the retry limit
for (i = 0; i <= chip->numRetriesI2C; i++)
{
if (atomic_read(&chip->pm_suspended)) {
pr_debug("FUSB %s: pm_suspended, retry\n", __func__);
msleep(FUSB_I2C_RETRY_DELAY);
continue;
}
ret = i2c_smbus_read_byte_data(chip->client, (u8)address); // Read a byte of data from address
if (ret < 0) // Errors report as negative
{
if (ret == -ERANGE) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ERANGE. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EINVAL) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EINVAL. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EAGAIN) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EAGAIN. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EALREADY) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EALREADY. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EBADE) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EBADE. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EBADMSG) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EBADMSG. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EBUSY) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EBUSY. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ECANCELED) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ECANCELED. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ECOMM) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ECOMM. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ECONNABORTED) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ECONNABORTED. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ECONNREFUSED) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ECONNREFUSED. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ECONNRESET) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ECONNRESET. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EDEADLK) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EDEADLK. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EDEADLOCK) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EDEADLOCK. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EDESTADDRREQ) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EDESTADDRREQ. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EFAULT) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EFAULT. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EHOSTDOWN) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EHOSTDOWN. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EHOSTUNREACH) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EHOSTUNREACH. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EILSEQ) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EILSEQ. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EINPROGRESS) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EINPROGRESS. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EINTR) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EINTR. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EIO) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EIO. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ELIBACC) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ELIBACC. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ELIBBAD) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ELIBBAD. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ELIBMAX) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ELIBMAX. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ELOOP) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ELOOP. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EMSGSIZE) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EMSGSIZE. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EMULTIHOP) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EMULTIHOP. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOBUFS) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ENOBUFS. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENODATA) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ENODATA. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENODEV) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ENODEV. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOLCK) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ENOLCK. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOMEM) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ENOMEM. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOMSG) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ENOMSG. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOPROTOOPT) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ENOPROTOOPT. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOSPC) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ENOSPC. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOSYS) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ENOSYS. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOTBLK) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ENOTBLK. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOTTY) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ENOTTY. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOTUNIQ) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ENOTUNIQ. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENXIO) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ENXIO. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EOVERFLOW) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EOVERFLOW. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EPERM) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EPERM. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EPFNOSUPPORT) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EPFNOSUPPORT. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EPIPE) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EPIPE. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EPROTO) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EPROTO. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EPROTONOSUPPORT) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EPROTONOSUPPORT. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ERANGE) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ERANGE. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EREMCHG) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EREMCHG. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EREMOTE) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EREMOTE. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EREMOTEIO) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EREMOTEIO. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ERESTART) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ERESTART. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ESRCH) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ESRCH. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ETIME) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ETIME. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ETIMEDOUT) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ETIMEDOUT. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ETXTBSY) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ETXTBSY. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EUCLEAN) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EUCLEAN. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EUNATCH) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EUNATCH. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EUSERS) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EUSERS. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EWOULDBLOCK) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EWOULDBLOCK. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EXDEV) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EXDEV. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EXFULL) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EXFULL. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EOPNOTSUPP) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EOPNOTSUPP. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EPROBE_DEFER) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EPROBE_DEFER. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOENT) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ENOENT. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else { dev_err(&chip->client->dev, "%s - Unexpected I2C error reading byte data. Address: '0x%02x', Return: '%d'. Attempt #%d / %d...\n", __func__, address, ret, i, chip->numRetriesI2C); }
}
else // Successful i2c writes should always return 0
{
*data = (FSC_U8)ret;
break;
}
}
mutex_unlock(&chip->lock);
return (ret >= 0);
}
FSC_BOOL fusb_I2C_ReadBlockData(FSC_U8 address, FSC_U8 length, FSC_U8* data)
{
FSC_S32 i = 0;
FSC_S32 ret = 0;
struct fusb30x_chip* chip = fusb30x_GetChip();
if (chip == NULL || chip->client == NULL || data == NULL)
{
pr_err("FUSB %s - Error: %s is NULL!\n", __func__, (chip == NULL ? "Internal chip structure"
: (chip->client == NULL ? "I2C Client"
: "block read data buffer")));
return false;
}
mutex_lock(&chip->lock);
// Retry on failure up to the retry limit
for (i = 0; i <= chip->numRetriesI2C; i++)
{
if (atomic_read(&chip->pm_suspended)) {
pr_debug("FUSB %s: pm_suspended, retry\n", __func__);
msleep(FUSB_I2C_RETRY_DELAY);
continue;
}
ret = i2c_smbus_read_i2c_block_data(chip->client, (u8)address, (u8)length, (u8*)data); // Read a byte of data from address
if (ret < 0) // Errors report as negative
{
if (ret == -ERANGE) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ERANGE. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EINVAL) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EINVAL. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EAGAIN) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EAGAIN. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EALREADY) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EALREADY. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EBADE) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EBADE. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EBADMSG) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EBADMSG. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EBUSY) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EBUSY. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ECANCELED) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ECANCELED. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ECOMM) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ECOMM. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ECONNABORTED) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ECONNABORTED. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ECONNREFUSED) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ECONNREFUSED. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ECONNRESET) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ECONNRESET. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EDEADLK) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EDEADLK. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EDEADLOCK) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EDEADLOCK. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EDESTADDRREQ) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EDESTADDRREQ. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EFAULT) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EFAULT. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EHOSTDOWN) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EHOSTDOWN. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EHOSTUNREACH) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EHOSTUNREACH. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EILSEQ) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EILSEQ. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EINPROGRESS) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EINPROGRESS. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EINTR) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EINTR. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EIO) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EIO. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ELIBACC) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ELIBACC. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ELIBBAD) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ELIBBAD. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ELIBMAX) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ELIBMAX. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ELOOP) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ELOOP. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EMSGSIZE) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EMSGSIZE. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EMULTIHOP) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EMULTIHOP. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOBUFS) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ENOBUFS. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENODATA) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ENODATA. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENODEV) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ENODEV. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOLCK) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ENOLCK. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOMEM) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ENOMEM. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOMSG) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ENOMSG. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOPROTOOPT) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ENOPROTOOPT. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOSPC) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ENOSPC. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOSYS) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ENOSYS. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOTBLK) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ENOTBLK. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOTTY) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ENOTTY. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOTUNIQ) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ENOTUNIQ. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENXIO) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ENXIO. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EOVERFLOW) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EOVERFLOW. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EPERM) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EPERM. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EPFNOSUPPORT) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EPFNOSUPPORT. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EPIPE) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EPIPE. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EPROTO) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EPROTO. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EPROTONOSUPPORT) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EPROTONOSUPPORT. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ERANGE) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ERANGE. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EREMCHG) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EREMCHG. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EREMOTE) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EREMOTE. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EREMOTEIO) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EREMOTEIO. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ERESTART) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ERESTART. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ESRCH) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ESRCH. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ETIME) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ETIME. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ETIMEDOUT) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ETIMEDOUT. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ETXTBSY) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -ETXTBSY. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EUCLEAN) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EUCLEAN. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EUNATCH) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EUNATCH. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EUSERS) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EUSERS. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EWOULDBLOCK) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EWOULDBLOCK. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EXDEV) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EXDEV. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EXFULL) { dev_err(&chip->client->dev, "%s - I2C Error block reading byte data. Address: '0x%02x', Return: -EXFULL. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EOPNOTSUPP) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EOPNOTSUPP. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -EPROBE_DEFER) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -EPROBE_DEFER. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else if (ret == -ENOENT) { dev_err(&chip->client->dev, "%s - I2C Error reading byte data. Address: '0x%02x', Return: -ENOENT. Attempt #%d / %d...\n", __func__, address, i, chip->numRetriesI2C); }
else { dev_err(&chip->client->dev, "%s - Unexpected I2C error block reading byte data. Address: '0x%02x', Return: '%d'. Attempt #%d / %d...\n", __func__, address, ret, i, chip->numRetriesI2C); }
}
else if (ret != length) // We didn't read everything we wanted
{
dev_err(&chip->client->dev, "%s - Error: Block read request of %u bytes truncated to %u bytes.\n", __func__, length, I2C_SMBUS_BLOCK_MAX);
}
else
{
break; // Success, don't retry
}
}
mutex_unlock(&chip->lock);
return (ret == length);
}
/*********************************************************************************************************************/
/*********************************************************************************************************************/
/******************************************** Timer Interface ******************************************/
/*********************************************************************************************************************/
/*********************************************************************************************************************/
static const unsigned long g_fusb_timer_tick_period_ns = 1000000; // Tick SM every 1ms -> 1000000ns
/*******************************************************************************
* Function: _fusb_TimerHandler
* Input: timer: hrtimer struct to be handled
* Return: HRTIMER_RESTART to restart the timer, or HRTIMER_NORESTART otherwise
* Description: Ticks state machine timer counters and rearms itself
********************************************************************************/
enum hrtimer_restart _fusb_TimerHandler(struct hrtimer* timer)
{
struct fusb30x_chip* chip = fusb30x_GetChip();
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
return HRTIMER_NORESTART;
}
if (!timer)
{
pr_err("FUSB %s - Error: High-resolution timer is NULL!\n", __func__);
return HRTIMER_NORESTART;
}
core_tick();
#ifdef FSC_DEBUG
if (chip->dbgTimerTicks++ >= U8_MAX)
{
chip->dbgTimerRollovers++;
}
#endif // FSC_DEBUG
// Reset the timer expiration
hrtimer_forward(timer, ktime_get(), ktime_set(0, g_fusb_timer_tick_period_ns));
return HRTIMER_RESTART; // Requeue the timer
}
void fusb_InitializeTimer(void)
{
struct fusb30x_chip* chip = fusb30x_GetChip();
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
return;
}
hrtimer_init(&chip->timer_state_machine, CLOCK_MONOTONIC, HRTIMER_MODE_REL); // Init the timer structure
chip->timer_state_machine.function = _fusb_TimerHandler; // Assign the callback to call when time runs out
pr_debug("FUSB %s - Timer initialized!\n", __func__);
}
void fusb_StartTimers(void)
{
ktime_t ktime;
struct fusb30x_chip* chip;
int ret;
chip = fusb30x_GetChip();
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
return;
}
#ifdef FSC_DEBUG
/* Reset our debug timer counters */
chip->dbgTimerTicks = 0;
chip->dbgTimerRollovers = 0;
#endif // FSC_DEBUG
ktime = ktime_set(0, g_fusb_timer_tick_period_ns); // Convert our timer period (in ns) to ktime
pr_debug("FUSB %s - Timer starting!\n", __func__);
mutex_lock(&chip->lock);
if (hrtimer_active(&chip->timer_state_machine) != 0)
{
ret = hrtimer_cancel(&chip->timer_state_machine);
pr_info("FUSB %s - Active state machine hrtimer canceled: %d\n", __func__, ret);
}
if (hrtimer_is_queued(&chip->timer_state_machine) != 0)
{
ret = hrtimer_cancel(&chip->timer_state_machine);
pr_info("FUSB %s - Queued state machine hrtimer canceled: %d\n", __func__, ret);
}
hrtimer_start(&chip->timer_state_machine, ktime, HRTIMER_MODE_REL); // Start the timer
mutex_unlock(&chip->lock);
}
void fusb_StopTimers(void)
{
FSC_S32 ret = 0;
struct fusb30x_chip* chip = fusb30x_GetChip();
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
return;
}
mutex_lock(&chip->lock);
if (hrtimer_active(&chip->timer_state_machine) != 0)
{
ret = hrtimer_cancel(&chip->timer_state_machine);
pr_debug("%s - Active state machine hrtimer canceled: %d\n", __func__, ret);
}
if (hrtimer_is_queued(&chip->timer_state_machine) != 0)
{
ret = hrtimer_cancel(&chip->timer_state_machine);
pr_debug("%s - Queued state machine hrtimer canceled: %d\n", __func__, ret);
}
mutex_unlock(&chip->lock);
pr_debug("FUSB %s - Timer stopped!\n", __func__);
}
// Get the max value that we can delay in 10us increments at compile time
static const FSC_U32 MAX_DELAY_10US = (UINT_MAX / 10);
void fusb_Delay10us(FSC_U32 delay10us)
{
FSC_U32 us = 0;
if (delay10us > MAX_DELAY_10US)
{
pr_err("FUSB %s - Error: Delay of '%u' is too long! Must be less than '%u'.\n", __func__, delay10us, MAX_DELAY_10US);
return;
}
us = delay10us * 10; // Convert to microseconds (us)
if (us <= 10) // Best practice is to use udelay() for < ~10us times
{
udelay(us); // BLOCKING delay for < 10us
}
else if (us < 20000) // Best practice is to use usleep_range() for 10us-20ms
{
// TODO - optimize this range, probably per-platform
usleep_range(us, us + (us / 10)); // Non-blocking sleep for at least the requested time, and up to the requested time + 10%
}
else // Best practice is to use msleep() for > 20ms
{
msleep(us / 1000); // Convert to ms. Non-blocking, low-precision sleep
}
}
FSC_S32 fusb_battery_select_source_capability(u8 obj_cnt, doDataObject_t pd_data[7], int *device_max_ma)
{
u8 i;
FSC_S32 sel_voltage_pdo_index;
struct htc_pd_data htc_pdo_data;
for (i = 0; i <= obj_cnt; i++) {
if (i > 5) {
obj_cnt = 6;
break;
}
if (pd_data[i].PDO.SupplyType == pdoTypeFixed) {
htc_pdo_data.pd_list[i][0] = pd_data[i].FPDOSupply.Voltage * 50; // voltage (mV)
htc_pdo_data.pd_list[i][1] = pd_data[i].FPDOSupply.MaxCurrent * 10; // current (mA)
} else if (pd_data[i].PDO.SupplyType == pdoTypeVariable) {
htc_pdo_data.pd_list[i][0] = pd_data[i].VPDO.MinVoltage * 50; // voltage (mV)
htc_pdo_data.pd_list[i][1] = pd_data[i].VPDO.MaxCurrent * 10; // current (mA)
}
}
sel_voltage_pdo_index = htc_battery_pd_charger_support(obj_cnt, htc_pdo_data, device_max_ma);
return sel_voltage_pdo_index;
}
#ifdef FSC_DEBUG
/*********************************************************************************************************************/
/*********************************************************************************************************************/
/******************************************** SysFS Interface ******************************************/
/*********************************************************************************************************************/
/*********************************************************************************************************************/
/*******************************************************************************
* Function: fusb_timestamp_bytes_to_time
* Input: outSec: Seconds part of output is stored here
* outMS10ths: 10ths of MS part of output is stored here
* inBuf: Ptr to first of 4 timestamp bytes, where the timestamp is in this format:
* [HI-10thsMS LO-10thsMS HI-Sec LO-Sec]
* Return: None
* Description: Parses the 4 bytes in inBuf into a 2-part timestamp: Seconds and 10ths of MS
********************************************************************************/
void fusb_timestamp_bytes_to_time(FSC_U32* outSec, FSC_U32* outMS10ths, FSC_U8* inBuf)
{
if (outSec && outMS10ths && inBuf)
{
*outMS10ths = inBuf[0];
*outMS10ths = *outMS10ths << 8;
*outMS10ths |= inBuf[1];
*outSec = inBuf[2];
*outSec = *outSec << 8;
*outSec |= inBuf[3];
}
}
/*******************************************************************************
* Function: fusb_get_pd_message_type
* Input: header: PD message header. Bits 4..0 are the pd message type, bits 14..12 are num data objs
* out: Buffer to which the message type will be written, should be at least 32 bytes long
* Return: int - Number of chars written to out, negative on error
* Description: Parses both PD message header bytes for the message type as a null-terminated string.
********************************************************************************/
FSC_S32 fusb_get_pd_message_type(FSC_U16 header, FSC_U8* out)
{
FSC_S32 numChars = -1; // Number of chars written, return value
if ((!out) || !(out + 31)) // Check for our 32 byte buffer
{
pr_err("%s FUSB - Error: Invalid input buffer! header: 0x%x\n", __func__, header);
return -1;
}
// Bits 14..12 give num of data obj. This is a data message if there are data objects, otherwise it's a control message
// See the PD spec, Table 6-1 "Message Header", for more details.
if ((header & 0x7000) > 0)
{
switch (header & 0x0F)
{
case DMTSourceCapabilities: // Source Capabilities
{
numChars = sprintf(out, "Source Capabilities");
break;
}
case DMTRequest: // Request
{
numChars = sprintf(out, "Request");
break;
}
case DMTBIST: // BIST
{
numChars = sprintf(out, "BIST");
break;
}
case DMTSinkCapabilities: // Sink Capabilities
{
numChars = sprintf(out, "Sink Capabilities");
break;
}
case 0b00101: // Battery Status
{
numChars = sprintf(out, "Battery Status");
break;
}
case 0b00110: // Source Alert
{
numChars = sprintf(out, "Source Alert");
break;
}
case DMTVenderDefined: // Vendor Defined
{
numChars = sprintf(out, "Vendor Defined");
break;
}
default: // Reserved/unused/unknown
{
numChars = sprintf(out, "Reserved (Data) (0x%x)", header);
break;
}
}
}
else
{
switch (header & 0x0F)
{
case CMTGoodCRC: // Good CRC
{
numChars = sprintf(out, "Good CRC");
break;
}
case CMTGotoMin: // Go to min
{
numChars = sprintf(out, "Go to Min");
break;
}
case CMTAccept: // Accept
{
numChars = sprintf(out, "Accept");
break;
}
case CMTReject: // Reject
{
numChars = sprintf(out, "Reject");
break;
}
case CMTPing: // Ping
{
numChars = sprintf(out, "Ping");
break;
}
case CMTPS_RDY: // PS_RDY
{
numChars = sprintf(out, "PS_RDY");
break;
}
case CMTGetSourceCap: // Get Source Cap
{
numChars = sprintf(out, "Get Source Capabilities");
break;
}
case CMTGetSinkCap: // Get Sink Cap
{
numChars = sprintf(out, "Get Sink Capabilities");
break;
}
case CMTDR_Swap: // Data Role Swap
{
numChars = sprintf(out, "Data Role Swap");
break;
}
case CMTPR_Swap: // Power Role Swap
{
numChars = sprintf(out, "Power Role Swap");
break;
}
case CMTVCONN_Swap: // VConn Swap
{
numChars = sprintf(out, "VConn Swap");
break;
}
case CMTWait: // Wait
{
numChars = sprintf(out, "Wait");
break;
}
case CMTSoftReset: // Soft Reset
{
numChars = sprintf(out, "Soft Reset");
break;
}
case 0b01110: // Not Supported
{
numChars = sprintf(out, "Not Supported");
break;
}
case 0b01111: // Get Source Cap Extended
{
numChars = sprintf(out, "Get Source Cap Ext");
break;
}
case 0b10000: // Get Source Status
{
numChars = sprintf(out, "Get Source Status");
break;
}
case 0b10001: // FR Swap
{
numChars = sprintf(out, "FR Swap");
break;
}
default: // Reserved/unused/unknown
{
numChars = sprintf(out, "Reserved (CMD) (0x%x)", header);
break;
}
}
}
return numChars;
}
/*******************************************************************************
* Function: fusb_Sysfs_Handle_Read
* Input: output: Buffer to which the output will be written
* Return: Number of chars written to output
* Description: Reading this file will output the most recently saved hostcomm output buffer
********************************************************************************/
#define FUSB_MAX_BUF_SIZE 256 // Arbitrary temp buffer for parsing out driver data to sysfs
static ssize_t _fusb_Sysfs_Hostcomm_show(struct device* dev, struct device_attribute* attr, char* buf)
{
FSC_S32 i = 0;
FSC_S32 numLogs = 0;
FSC_S32 numChars = 0;
FSC_U32 TimeStampSeconds = 0; // Timestamp value in seconds
FSC_U32 TimeStampMS10ths = 0; // Timestamp fraction in 10ths of milliseconds
FSC_S8 tempBuf[FUSB_MAX_BUF_SIZE] = { 0 };
struct fusb30x_chip* chip = fusb30x_GetChip();
if (chip == NULL)
{
pr_err("%s - Chip structure is null!\n", __func__);
}
else if (buf == NULL || chip->HostCommBuf == NULL)
{
pr_err("%s - Buffer is null!\n", __func__);
}
else if (chip->HostCommBuf[0] == CMD_READ_PD_STATE_LOG) // Parse out the PD state log
{
numLogs = chip->HostCommBuf[3];
/* First byte echos the command, 4th byte is number of logs (2nd and 3rd bytes reserved as 0) */
numChars += sprintf(tempBuf, "PD State Log has %u entries:\n", numLogs); // Copy string + null terminator
strcat(buf, tempBuf);
/* Relevant data starts at 5th byte in this format: CMD 0 0 #Logs PDState time time time time */
for (i = 4; (i + 4 < FSC_HOSTCOMM_BUFFER_SIZE) && (numChars < PAGE_SIZE) && (numLogs > 0); i += 5, numLogs--) // Must be able to peek 4 bytes ahead, and don't overflow the output buffer (PAGE_SIZE)
{
fusb_timestamp_bytes_to_time(&TimeStampSeconds, &TimeStampMS10ths, &chip->HostCommBuf[i + 1]);
// sprintf should be safe here because we're controlling the strings being printed, just make sure the strings are less than FUSB_MAX_BUF_SIZE+1
switch (chip->HostCommBuf[i])
{
case peDisabled: // Policy engine is disabled
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDisabled\t\tPolicy engine is disabled\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peErrorRecovery: // Error recovery state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeErrorRecovery\t\tError recovery state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceHardReset: // Received a hard reset
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceHardReset\t\tReceived a hard reset\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceSendHardReset: // Source send a hard reset
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceSendHardReset\t\tSource send a hard reset\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceSoftReset: // Received a soft reset
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceSoftReset\t\tReceived a soft reset\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceSendSoftReset: // Send a soft reset
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceSendSoftReset\t\tSend a soft reset\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceStartup: // Initial state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceStartup\t\tInitial state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceSendCaps: // Send the source capabilities
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceSendCaps\t\tSend the source capabilities\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceDiscovery: // Waiting to detect a USB PD sink
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceDiscovery\t\tWaiting to detect a USB PD sink\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceDisabled: // Disabled state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceDisabled\t\tDisabled state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceTransitionDefault: // Transition to default 5V state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceTransitionDefault\t\tTransition to default 5V state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceNegotiateCap: // Negotiate capability and PD contract
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceNegotiateCap\t\tNegotiate capability and PD contract\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceCapabilityResponse: // Respond to a request message with a reject/wait
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceCapabilityResponse\t\tRespond to a request message with a reject/wait\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceTransitionSupply: // Transition the power supply to the new setting (accept request)
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceTransitionSupply\t\tTransition the power supply to the new setting (accept request)\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceReady: // Contract is in place and output voltage is stable
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceReady\t\tContract is in place and output voltage is stable\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceGiveSourceCaps: // State to resend source capabilities
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceGiveSourceCaps\t\tState to resend source capabilities\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceGetSinkCaps: // State to request the sink capabilities
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceGetSinkCaps\t\tState to request the sink capabilities\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceSendPing: // State to send a ping message
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceSendPing\t\tState to send a ping message\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceGotoMin: // State to send the gotoMin and ready the power supply
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceGotoMin\t\tState to send the gotoMin and ready the power supply\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceGiveSinkCaps: // State to send the sink capabilities if dual-role
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceGiveSinkCaps\t\tState to send the sink capabilities if dual-role\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceGetSourceCaps: // State to request the source caps from the UFP
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceGetSourceCaps\t\tState to request the source caps from the UFP\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceSendDRSwap: // State to send a DR_Swap message
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceSendDRSwap\t\tState to send a DR_Swap message\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceEvaluateDRSwap: // Evaluate whether we are going to accept or reject the swap
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceEvaluateDRSwap\t\tEvaluate whether we are going to accept or reject the swap\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkHardReset: // Received a hard reset
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkHardReset\t\tReceived a hard reset\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkSendHardReset: // Sink send hard reset
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkSendHardReset\t\tSink send hard reset\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkSoftReset: // Sink soft reset
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkSoftReset\t\tSink soft reset\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkSendSoftReset: // Sink send soft reset
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkSendSoftReset\t\tSink send soft reset\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkTransitionDefault: // Transition to the default state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkTransitionDefault\t\tTransition to the default state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkStartup: // Initial sink state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkStartup\t\tInitial sink state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkDiscovery: // Sink discovery state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkDiscovery\t\tSink discovery state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkWaitCaps: // Sink wait for capabilities state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkWaitCaps\t\tSink wait for capabilities state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkEvaluateCaps: // Sink state to evaluate the received source capabilities
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkEvaluateCaps\t\tSink state to evaluate the received source capabilities\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkSelectCapability: // Sink state for selecting a capability
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkSelectCapability\t\tSink state for selecting a capability\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkTransitionSink: // Sink state for transitioning the current power
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkTransitionSink\t\tSink state for transitioning the current power\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkReady: // Sink ready state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkReady\t\tSink ready state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkGiveSinkCap: // Sink send capabilities state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkGiveSinkCap\t\tSink send capabilities state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkGetSourceCap: // Sink get source capabilities state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkGetSourceCap\t\tSink get source capabilities state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkGetSinkCap: // Sink state to get the sink capabilities of the connected source
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkGetSinkCap\t\tSink state to get the sink capabilities of the connected source\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkGiveSourceCap: // Sink state to send the source capabilities if dual-role
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkGiveSourceCap\t\tSink state to send the source capabilities if dual-role\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkSendDRSwap: // State to send a DR_Swap message
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkSendDRSwap\t\tState to send a DR_Swap message\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkEvaluateDRSwap: // Evaluate whether we are going to accept or reject the swap
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkEvaluateDRSwap\t\tEvaluate whether we are going to accept or reject the swap\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceSendVCONNSwap: // Initiate a VCONN swap sequence
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceSendVCONNSwap\t\tInitiate a VCONN swap sequence\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkEvaluateVCONNSwap: // Evaluate whether we are going to accept or reject the swap
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkEvaluateVCONNSwap\t\tEvaluate whether we are going to accept or reject the swap\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceSendPRSwap: // Initiate a PR_Swap sequence
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceSendPRSwap\t\tInitiate a PR_Swap sequence\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceEvaluatePRSwap: // Evaluate whether we are going to accept or reject the swap
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceEvaluatePRSwap\t\tEvaluate whether we are going to accept or reject the swap\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkSendPRSwap: // Initiate a PR_Swap sequence
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkSendPRSwap\t\tInitiate a PR_Swap sequence\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkEvaluatePRSwap: // Evaluate whether we are going to accept or reject the swap
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkEvaluatePRSwap\t\tEvaluate whether we are going to accept or reject the swap\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peGiveVdm: // Send VDM data
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeGiveVdm\t\tSend VDM data\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmGetIdentity: // Requesting Identity information from DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmGetIdentity\t\tRequesting Identity information from DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmSendIdentity: // Sending Discover Identity ACK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmSendIdentity\t\tSending Discover Identity ACK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmGetSvids: // Requesting SVID info from DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmGetSvids\t\tRequesting SVID info from DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmSendSvids: // Sending Discover SVIDs ACK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmSendSvids\t\tSending Discover SVIDs ACK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmGetModes: // Requesting Mode info from DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmGetModes\t\tRequesting Mode info from DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmSendModes: // Sending Discover Modes ACK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmSendModes\t\tSending Discover Modes ACK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmEvaluateModeEntry: // Requesting DPM to evaluate request to enter a mode, and enter if OK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmEvaluateModeEntry\t\tRequesting DPM to evaluate request to enter a mode, and enter if OK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmModeEntryNak: // Sending Enter Mode NAK response
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmModeEntryNak\t\tSending Enter Mode NAK response\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmModeEntryAck: // Sending Enter Mode ACK response
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmModeEntryAck\t\tSending Enter Mode ACK response\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmModeExit: // Requesting DPM to evalute request to exit mode
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmModeExit\t\tRequesting DPM to evalute request to exit mode\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmModeExitNak: // Sending Exit Mode NAK reponse
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmModeExitNak\t\tSending Exit Mode NAK reponse\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmModeExitAck: // Sending Exit Mode ACK Response
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmModeExitAck\t\tSending Exit Mode ACK Response\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmAttentionRequest: // Sending Attention Command
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmAttentionRequest\t\tSending Attention Command\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpUfpVdmIdentityRequest: // Sending Identity Request
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpUfpVdmIdentityRequest\t\tSending Identity Request\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpUfpVdmIdentityAcked: // Inform DPM of Identity
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpUfpVdmIdentityAcked\t\tInform DPM of Identity\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpUfpVdmIdentityNaked: // Inform DPM of result
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpUfpVdmIdentityNaked\t\tInform DPM of result\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpCblVdmIdentityRequest: // Sending Identity Request
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpCblVdmIdentityRequest\t\tSending Identity Request\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpCblVdmIdentityAcked: // Inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpCblVdmIdentityAcked\t\tInform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpCblVdmIdentityNaked: // Inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpCblVdmIdentityNaked\t\tInform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmSvidsRequest: // Sending Discover SVIDs request
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmSvidsRequest\t\tSending Discover SVIDs request\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmSvidsAcked: // Inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmSvidsAcked\t\tInform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmSvidsNaked: // Inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmSvidsNaked\t\tInform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmModesRequest: // Sending Discover Modes request
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmModesRequest\t\tSending Discover Modes request\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmModesAcked: // Inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmModesAcked\t\tInform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmModesNaked: // Inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmModesNaked\t\tInform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmModeEntryRequest: // Sending Mode Entry request
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmModeEntryRequest\t\tSending Mode Entry request\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmModeEntryAcked: // Inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmModeEntryAcked\t\tInform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmModeEntryNaked: // Inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmModeEntryNaked\t\tInform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmModeExitRequest: // Sending Exit Mode request
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmModeExitRequest\t\tSending Exit Mode request\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmExitModeAcked: // Inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmExitModeAcked\t\tInform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSrcVdmIdentityRequest: // sending Discover Identity request
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSrcVdmIdentityRequest\t\tsending Discover Identity request\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSrcVdmIdentityAcked: // inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSrcVdmIdentityAcked\t\tinform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSrcVdmIdentityNaked: // inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSrcVdmIdentityNaked\t\tinform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmAttentionRequest: // Attention Request received
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmAttentionRequest\t\tAttention Request received\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblReady: // Cable power up state?
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblReady\t\tCable power up state?\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblGetIdentity: // Discover Identity request received
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblGetIdentity\t\tDiscover Identity request received\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblGetIdentityNak: // Respond with NAK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblGetIdentityNak\t\tRespond with NAK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblSendIdentity: // Respond with Ack
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblSendIdentity\t\tRespond with Ack\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblGetSvids: // Discover SVIDs request received
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblGetSvids\t\tDiscover SVIDs request received\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblGetSvidsNak: // Respond with NAK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblGetSvidsNak\t\tRespond with NAK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblSendSvids: // Respond with ACK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblSendSvids\t\tRespond with ACK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblGetModes: // Discover Modes request received
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblGetModes\t\tDiscover Modes request received\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblGetModesNak: // Respond with NAK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblGetModesNak\t\tRespond with NAK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblSendModes: // Respond with ACK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblSendModes\t\tRespond with ACK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblEvaluateModeEntry: // Enter Mode request received
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblEvaluateModeEntry\t\tEnter Mode request received\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblModeEntryAck: // Respond with NAK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblModeEntryAck\t\tRespond with NAK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblModeEntryNak: // Respond with ACK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblModeEntryNak\t\tRespond with ACK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblModeExit: // Exit Mode request received
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblModeExit\t\tExit Mode request received\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblModeExitAck: // Respond with NAK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblModeExitAck\t\tRespond with NAK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblModeExitNak: // Respond with ACK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblModeExitNak\t\tRespond with ACK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDpRequestStatus: // Requesting PP Status
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDpRequestStatus\t\tRequesting PP Status\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case PE_BIST_Receive_Mode: // Bist Receive Mode
{
numChars += sprintf(tempBuf, "[%u.%04u]\tPE_BIST_Receive_Mode\t\tBist Receive Mode\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case PE_BIST_Frame_Received: // Test Frame received by Protocol layer
{
numChars += sprintf(tempBuf, "[%u.%04u]\tPE_BIST_Frame_Received\t\tTest Frame received by Protocol layer\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case PE_BIST_Carrier_Mode_2: // BIST Carrier Mode 2
{
numChars += sprintf(tempBuf, "[%u.%04u]\tPE_BIST_Carrier_Mode_2\t\tBIST Carrier Mode 2\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceWaitNewCapabilities: // Wait for new Source Capabilities from Policy Manager
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceWaitNewCapabilities\t\tWait for new Source Capabilities from Policy Manager\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case dbgGetRxPacket: // Debug point for measuring Rx packet handling in ProtocolGetRxPacket()
{
// Special parsing for this state - TimeStampSeconds is really the number of I2C reads performed, and TimeStampMS10ths is the time elapsed (in ms)
numChars += sprintf(tempBuf, "%02u|0.%04u\tdbgGetRxPacket\t\t\tNumber of I2C bytes read | Time elapsed\n", TimeStampSeconds, TimeStampMS10ths);
// numChars += sprintf(tempBuf, "%u | %u\tdbgGetRxPacket\t\t\tHeader[0] | Header[1]", chip->HostCommBuf[i + 1], chip->HostCommBuf[i + 3]);
strcat(buf, tempBuf);
break;
}
case dbgSendTxPacket: // Debug point for measuring Tx packet handling in ProtocolTransmitMessage()
{
// Special parsing for this state - TimeStampSeconds is really the number of I2C reads performed, and TimeStampMS10ths is the time elapsed (in ms)
numChars += sprintf(tempBuf, "%02u|0.%04u\tdbgGetTxPacket\t\t\tNumber of I2C bytes sent | Time elapsed\n", TimeStampSeconds, TimeStampMS10ths);
// numChars += sprintf(tempBuf, "%u | %u\tdbgGetRxPacket\t\t\tHeader[0] | Header[1]", chip->HostCommBuf[i + 1], chip->HostCommBuf[i + 3]);
strcat(buf, tempBuf);
break;
}
default:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tUKNOWN STATE: 0x%02x\n", TimeStampSeconds, TimeStampMS10ths, chip->HostCommBuf[i]);
strcat(buf, tempBuf);
break;
}
}
}
strcat(buf, "\n"); // Append a newline for pretty++
numChars++; // Account for newline
}
else if (chip->HostCommBuf[0] == CMD_READ_STATE_LOG) // Parse out the Type-C state log
{
numLogs = chip->HostCommBuf[3];
/* First byte echos the command, 4th byte is number of logs (2nd and 3rd bytes reserved as 0) */
numChars += sprintf(tempBuf, "Type-C State Log has %u entries:\n", numLogs); // Copy string + null terminator
strcat(buf, tempBuf);
/* Relevant data starts at 5th byte in this format: CMD 0 0 #Logs State time time time time */
for (i = 4; (i + 4 < FSC_HOSTCOMM_BUFFER_SIZE) && (numChars < PAGE_SIZE) && (numLogs > 0); i += 5, numLogs--) // Must be able to peek 4 bytes ahead, and don't overflow the output buffer (PAGE_SIZE), only print logs we have
{
// Parse out the timestamp
fusb_timestamp_bytes_to_time(&TimeStampSeconds, &TimeStampMS10ths, &chip->HostCommBuf[i + 1]);
// sprintf should be safe here because we're controlling the strings being printed, just make sure the strings are less than FUSB_MAX_BUF_SIZE+1
switch (chip->HostCommBuf[i])
{
case Disabled:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tDisabled\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case ErrorRecovery:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tErrorRecovery\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case Unattached:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tUnattached\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case AttachWaitSink:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tAttachWaitSink\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case AttachedSink:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tAttachedSink\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case AttachWaitSource:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tAttachWaitSource\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case AttachedSource:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tAttachedSource\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case TrySource:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tTrySource\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case TryWaitSink:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tTryWaitSink\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case TrySink:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tTrySink\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case TryWaitSource:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tTryWaitSource\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case AudioAccessory:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tAudioAccessory\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case DebugAccessory:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tDebugAccessory\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case AttachWaitAccessory:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tAttachWaitAccessory\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case PoweredAccessory:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tPoweredAccessory\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case UnsupportedAccessory:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tUnsupportedAccessory\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case DelayUnattached:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tDelayUnattached\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case UnattachedSource:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tUnattachedSource\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
default:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tUKNOWN STATE: 0x%02x\n", TimeStampSeconds, TimeStampMS10ths, chip->HostCommBuf[i]);
strcat(buf, tempBuf);
break;
}
}
}
strcat(buf, "\n"); // Append a newline for pretty++
numChars++; // Account for newline
}
else
{
for (i = 0; i < FSC_HOSTCOMM_BUFFER_SIZE; i++)
{
numChars += scnprintf(tempBuf, 6 * sizeof(char), "0x%02x ", chip->HostCommBuf[i]); // Copy 1 byte + null term
strcat(buf, tempBuf); // Append each number to the output buffer
}
strcat(buf, "\n"); // Append a newline for pretty++
numChars++; // Account for newline
}
return numChars;
}
/*******************************************************************************
* Function: fusb_Sysfs_Handle_Write
* Input: input: Buffer passed in from OS (space-separated list of 8-bit hex values)
* size: Number of chars in input
* output: Buffer to which the output will be written
* Return: Number of chars written to output
* Description: Performs hostcomm duties, and stores output buffer in chip structure
********************************************************************************/
static ssize_t _fusb_Sysfs_Hostcomm_store(struct device* dev, struct device_attribute* attr, const char* input, size_t size)
{
FSC_S32 ret = 0;
FSC_S32 i = 0;
FSC_S32 j = 0;
FSC_S8 tempByte = 0;
FSC_S32 numBytes = 0;
FSC_S8 temp[6] = { 0 }; // Temp buffer to parse out individual hex numbers, +1 for null terminator
FSC_S8 temp_input[FSC_HOSTCOMM_BUFFER_SIZE] = { 0 };
FSC_S8 output[FSC_HOSTCOMM_BUFFER_SIZE] = { 0 };
struct fusb30x_chip* chip = fusb30x_GetChip();
if (chip == NULL)
{
pr_err("%s - Chip structure is null!\n", __func__);
}
else if (input == NULL)
{
pr_err("%s - Error: Input buffer is NULL!\n", __func__);
}
else
{
// Convert the buffer to hex values
for (i = 0; i < size; i = i + j)
{
// Parse out a hex number (at most 5 chars: "0x## ")
for (j = 0; (j < 5) && (j + i < size); j++)
{
// End of the hex number (space-delimited)
if (input[i + j] == ' ')
{
break; // We found a space, stop copying this number and convert it
}
temp[j] = input[i + j]; // Copy the non-space byte into the temp buffer
}
temp[++j] = 0; // Add a null terminator and move past the space
// We have a hex digit (hopefully), now convert it
ret = kstrtou8(temp, 16, &tempByte);
if (ret != 0)
{
pr_err("FUSB %s - Error: Hostcomm input is not a valid hex value! Return: '%d'\n", __func__, ret);
return 0; // Quit on error
}
else
{
temp_input[numBytes++] = tempByte;
if (numBytes >= FSC_HOSTCOMM_BUFFER_SIZE)
{
break;
}
}
}
fusb_ProcessMsg(temp_input, output); // Handle the message
memcpy(chip->HostCommBuf, output, FSC_HOSTCOMM_BUFFER_SIZE); // Copy input into temp buffer
}
return size;
}
/* Fetch and display the PD state log */
static ssize_t _fusb_Sysfs_PDStateLog_show(struct device* dev, struct device_attribute* attr, char* buf)
{
FSC_S32 i = 0;
FSC_S32 numChars = 0;
FSC_S32 numLogs = 0;
FSC_U16 PDMessageHeader = 0; // PD Message header bytes
FSC_U32 TimeStampSeconds = 0; // Timestamp value in seconds
FSC_U32 TimeStampMS10ths = 0; // Timestamp fraction in 10ths of milliseconds
FSC_U8 MessageType[32] = { 0 }; // Temp buffer to parse the PD message type from the PD message header
FSC_U8 output[FSC_HOSTCOMM_BUFFER_SIZE] = { 0 };
FSC_U8 tempBuf[FUSB_MAX_BUF_SIZE] = { 0 };
tempBuf[0] = CMD_READ_PD_STATE_LOG; // To request the PD statelog from Hostcomm
/* Get the PD State Log */
fusb_ProcessMsg(tempBuf, output);
numLogs = output[3];
/* First byte echos the command, 4th byte is number of logs (2nd and 3rd bytes reserved as 0) */
numChars += sprintf(tempBuf, "PD State Log has %u entries:\n", numLogs); // Copy string + null terminator
strcat(buf, tempBuf);
/* Relevant data starts at 5th byte in this format: CMD 0 0 #Logs PDState time time time time */
for (i = 4; (i + 4 < FSC_HOSTCOMM_BUFFER_SIZE) && (numChars < PAGE_SIZE) && (numLogs > 0); i += 5, numLogs--) // Must be able to peek 4 bytes ahead, and don't overflow the output buffer (PAGE_SIZE)
{
// Parse out the timestamp
// Parse out the timestamp
if (output[i] != dbgGetRxPacket)
{
fusb_timestamp_bytes_to_time(&TimeStampSeconds, &TimeStampMS10ths, &output[i + 1]);
}
// sprintf should be safe here because we're controlling the strings being printed, just make sure the strings are less than FUSB_MAX_BUF_SIZE+1
switch (output[i])
{
case peDisabled: // Policy engine is disabled
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDisabled\t\tPolicy engine is disabled\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peErrorRecovery: // Error recovery state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeErrorRecovery\t\tError recovery state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceHardReset: // Received a hard reset
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceHardReset\t\tReceived a hard reset\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceSendHardReset: // Source send a hard reset
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceSendHardReset\t\tSource send a hard reset\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceSoftReset: // Received a soft reset
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceSoftReset\t\tReceived a soft reset\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceSendSoftReset: // Send a soft reset
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceSendSoftReset\t\tSend a soft reset\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceStartup: // Initial state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceStartup\t\tInitial state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceSendCaps: // Send the source capabilities
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceSendCaps\t\tSend the source capabilities\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceDiscovery: // Waiting to detect a USB PD sink
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceDiscovery\t\tWaiting to detect a USB PD sink\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceDisabled: // Disabled state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceDisabled\t\tDisabled state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceTransitionDefault: // Transition to default 5V state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceTransitionDefault\t\tTransition to default 5V state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceNegotiateCap: // Negotiate capability and PD contract
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceNegotiateCap\t\tNegotiate capability and PD contract\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceCapabilityResponse: // Respond to a request message with a reject/wait
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceCapabilityResponse\t\tRespond to a request message with a reject/wait\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceTransitionSupply: // Transition the power supply to the new setting (accept request)
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceTransitionSupply\t\tTransition the power supply to the new setting (accept request)\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceReady: // Contract is in place and output voltage is stable
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceReady\t\tContract is in place and output voltage is stable\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceGiveSourceCaps: // State to resend source capabilities
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceGiveSourceCaps\t\tState to resend source capabilities\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceGetSinkCaps: // State to request the sink capabilities
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceGetSinkCaps\t\tState to request the sink capabilities\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceSendPing: // State to send a ping message
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceSendPing\t\tState to send a ping message\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceGotoMin: // State to send the gotoMin and ready the power supply
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceGotoMin\t\tState to send the gotoMin and ready the power supply\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceGiveSinkCaps: // State to send the sink capabilities if dual-role
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceGiveSinkCaps\t\tState to send the sink capabilities if dual-role\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceGetSourceCaps: // State to request the source caps from the UFP
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceGetSourceCaps\t\tState to request the source caps from the UFP\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceSendDRSwap: // State to send a DR_Swap message
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceSendDRSwap\t\tState to send a DR_Swap message\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceEvaluateDRSwap: // Evaluate whether we are going to accept or reject the swap
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceEvaluateDRSwap\t\tEvaluate whether we are going to accept or reject the swap\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkHardReset: // Received a hard reset
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkHardReset\t\tReceived a hard reset\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkSendHardReset: // Sink send hard reset
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkSendHardReset\t\tSink send hard reset\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkSoftReset: // Sink soft reset
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkSoftReset\t\tSink soft reset\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkSendSoftReset: // Sink send soft reset
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkSendSoftReset\t\tSink send soft reset\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkTransitionDefault: // Transition to the default state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkTransitionDefault\t\tTransition to the default state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkStartup: // Initial sink state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkStartup\t\tInitial sink state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkDiscovery: // Sink discovery state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkDiscovery\t\tSink discovery state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkWaitCaps: // Sink wait for capabilities state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkWaitCaps\t\tSink wait for capabilities state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkEvaluateCaps: // Sink state to evaluate the received source capabilities
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkEvaluateCaps\t\tSink state to evaluate the received source capabilities\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkSelectCapability: // Sink state for selecting a capability
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkSelectCapability\t\tSink state for selecting a capability\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkTransitionSink: // Sink state for transitioning the current power
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkTransitionSink\t\tSink state for transitioning the current power\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkReady: // Sink ready state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkReady\t\tSink ready state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkGiveSinkCap: // Sink send capabilities state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkGiveSinkCap\t\tSink send capabilities state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkGetSourceCap: // Sink get source capabilities state
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkGetSourceCap\t\tSink get source capabilities state\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkGetSinkCap: // Sink state to get the sink capabilities of the connected source
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkGetSinkCap\t\tSink state to get the sink capabilities of the connected source\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkGiveSourceCap: // Sink state to send the source capabilities if dual-role
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkGiveSourceCap\t\tSink state to send the source capabilities if dual-role\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkSendDRSwap: // State to send a DR_Swap message
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkSendDRSwap\t\tState to send a DR_Swap message\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkEvaluateDRSwap: // Evaluate whether we are going to accept or reject the swap
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkEvaluateDRSwap\t\tEvaluate whether we are going to accept or reject the swap\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceSendVCONNSwap: // Initiate a VCONN swap sequence
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceSendVCONNSwap\t\tInitiate a VCONN swap sequence\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkEvaluateVCONNSwap: // Evaluate whether we are going to accept or reject the swap
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkEvaluateVCONNSwap\t\tEvaluate whether we are going to accept or reject the swap\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceSendPRSwap: // Initiate a PR_Swap sequence
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceSendPRSwap\t\tInitiate a PR_Swap sequence\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceEvaluatePRSwap: // Evaluate whether we are going to accept or reject the swap
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceEvaluatePRSwap\t\tEvaluate whether we are going to accept or reject the swap\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkSendPRSwap: // Initiate a PR_Swap sequence
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkSendPRSwap\t\tInitiate a PR_Swap sequence\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSinkEvaluatePRSwap: // Evaluate whether we are going to accept or reject the swap
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSinkEvaluatePRSwap\t\tEvaluate whether we are going to accept or reject the swap\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peGiveVdm: // Send VDM data
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeGiveVdm\t\tSend VDM data\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmGetIdentity: // Requesting Identity information from DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmGetIdentity\t\tRequesting Identity information from DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmSendIdentity: // Sending Discover Identity ACK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmSendIdentity\t\tSending Discover Identity ACK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmGetSvids: // Requesting SVID info from DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmGetSvids\t\tRequesting SVID info from DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmSendSvids: // Sending Discover SVIDs ACK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmSendSvids\t\tSending Discover SVIDs ACK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmGetModes: // Requesting Mode info from DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmGetModes\t\tRequesting Mode info from DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmSendModes: // Sending Discover Modes ACK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmSendModes\t\tSending Discover Modes ACK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmEvaluateModeEntry: // Requesting DPM to evaluate request to enter a mode, and enter if OK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmEvaluateModeEntry\t\tRequesting DPM to evaluate request to enter a mode, and enter if OK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmModeEntryNak: // Sending Enter Mode NAK response
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmModeEntryNak\t\tSending Enter Mode NAK response\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmModeEntryAck: // Sending Enter Mode ACK response
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmModeEntryAck\t\tSending Enter Mode ACK response\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmModeExit: // Requesting DPM to evalute request to exit mode
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmModeExit\t\tRequesting DPM to evalute request to exit mode\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmModeExitNak: // Sending Exit Mode NAK reponse
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmModeExitNak\t\tSending Exit Mode NAK reponse\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmModeExitAck: // Sending Exit Mode ACK Response
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmModeExitAck\t\tSending Exit Mode ACK Response\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peUfpVdmAttentionRequest: // Sending Attention Command
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeUfpVdmAttentionRequest\t\tSending Attention Command\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpUfpVdmIdentityRequest: // Sending Identity Request
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpUfpVdmIdentityRequest\t\tSending Identity Request\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpUfpVdmIdentityAcked: // Inform DPM of Identity
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpUfpVdmIdentityAcked\t\tInform DPM of Identity\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpUfpVdmIdentityNaked: // Inform DPM of result
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpUfpVdmIdentityNaked\t\tInform DPM of result\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpCblVdmIdentityRequest: // Sending Identity Request
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpCblVdmIdentityRequest\t\tSending Identity Request\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpCblVdmIdentityAcked: // Inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpCblVdmIdentityAcked\t\tInform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpCblVdmIdentityNaked: // Inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpCblVdmIdentityNaked\t\tInform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmSvidsRequest: // Sending Discover SVIDs request
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmSvidsRequest\t\tSending Discover SVIDs request\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmSvidsAcked: // Inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmSvidsAcked\t\tInform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmSvidsNaked: // Inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmSvidsNaked\t\tInform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmModesRequest: // Sending Discover Modes request
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmModesRequest\t\tSending Discover Modes request\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmModesAcked: // Inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmModesAcked\t\tInform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmModesNaked: // Inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmModesNaked\t\tInform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmModeEntryRequest: // Sending Mode Entry request
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmModeEntryRequest\t\tSending Mode Entry request\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmModeEntryAcked: // Inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmModeEntryAcked\t\tInform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmModeEntryNaked: // Inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmModeEntryNaked\t\tInform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmModeExitRequest: // Sending Exit Mode request
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmModeExitRequest\t\tSending Exit Mode request\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmExitModeAcked: // Inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmExitModeAcked\t\tInform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSrcVdmIdentityRequest: // sending Discover Identity request
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSrcVdmIdentityRequest\t\tsending Discover Identity request\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSrcVdmIdentityAcked: // inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSrcVdmIdentityAcked\t\tinform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSrcVdmIdentityNaked: // inform DPM
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSrcVdmIdentityNaked\t\tinform DPM\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDfpVdmAttentionRequest: // Attention Request received
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDfpVdmAttentionRequest\t\tAttention Request received\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblReady: // Cable power up state?
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblReady\t\tCable power up state?\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblGetIdentity: // Discover Identity request received
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblGetIdentity\t\tDiscover Identity request received\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblGetIdentityNak: // Respond with NAK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblGetIdentityNak\t\tRespond with NAK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblSendIdentity: // Respond with Ack
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblSendIdentity\t\tRespond with Ack\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblGetSvids: // Discover SVIDs request received
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblGetSvids\t\tDiscover SVIDs request received\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblGetSvidsNak: // Respond with NAK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblGetSvidsNak\t\tRespond with NAK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblSendSvids: // Respond with ACK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblSendSvids\t\tRespond with ACK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblGetModes: // Discover Modes request received
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblGetModes\t\tDiscover Modes request received\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblGetModesNak: // Respond with NAK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblGetModesNak\t\tRespond with NAK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblSendModes: // Respond with ACK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblSendModes\t\tRespond with ACK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblEvaluateModeEntry: // Enter Mode request received
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblEvaluateModeEntry\t\tEnter Mode request received\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblModeEntryAck: // Respond with NAK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblModeEntryAck\t\tRespond with NAK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblModeEntryNak: // Respond with ACK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblModeEntryNak\t\tRespond with ACK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblModeExit: // Exit Mode request received
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblModeExit\t\tExit Mode request received\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblModeExitAck: // Respond with NAK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblModeExitAck\t\tRespond with NAK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peCblModeExitNak: // Respond with ACK
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeCblModeExitNak\t\tRespond with ACK\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peDpRequestStatus: // Requesting PP Status
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeDpRequestStatus\t\tRequesting PP Status\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case PE_BIST_Receive_Mode: // Bist Receive Mode
{
numChars += sprintf(tempBuf, "[%u.%04u]\tPE_BIST_Receive_Mode\t\tBist Receive Mode\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case PE_BIST_Frame_Received: // Test Frame received by Protocol layer
{
numChars += sprintf(tempBuf, "[%u.%04u]\tPE_BIST_Frame_Received\t\tTest Frame received by Protocol layer\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case PE_BIST_Carrier_Mode_2: // BIST Carrier Mode 2
{
numChars += sprintf(tempBuf, "[%u.%04u]\tPE_BIST_Carrier_Mode_2\t\tBIST Carrier Mode 2\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case peSourceWaitNewCapabilities: // Wait for new Source Capabilities from Policy Manager
{
numChars += sprintf(tempBuf, "[%u.%04u]\tpeSourceWaitNewCapabilities\t\tWait for new Source Capabilities from Policy Manager\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case dbgSendTxPacket: // Treat the same as Rx packet, just change "Rx" to "Tx"
case dbgGetRxPacket: // Debug point for measuring Rx packet handling time in ProtocolGetRxPacket()
{
// Special parsing for this state - TimeStampSeconds is really the number of I2C reads performed, and TimeStampMS10ths is the time elapsed (in ms)
// numChars += sprintf(tempBuf, "%02u|0.%04u\tdbgGetRxPacket\t\t\tNumber of I2C bytes read | Time elapsed\n", TimeStampSeconds, TimeStampMS10ths);
// Recombine the 2 header bytes into a u16
PDMessageHeader = output[i + 4]; // Get MSByte
PDMessageHeader = PDMessageHeader << 8; // Shift into MS position
PDMessageHeader |= output[i + 2]; // Get LSByte
// Parse out the message type to make the log easier to read
if (fusb_get_pd_message_type(PDMessageHeader, MessageType) > -1)
{
numChars += sprintf(tempBuf, "0x%x\t\t%s\t\tMessage Type: %s\n", PDMessageHeader, (output[i] == dbgGetRxPacket) ? "dbgGetRxPacket" : "dbgSendTxPacket", MessageType);
}
else
{
numChars += sprintf(tempBuf, "0x%x\t\t%s\t\tMessage Type: UNKNOWN\n", PDMessageHeader, (output[i] == dbgGetRxPacket) ? "dbgGetRxPacket" : "dbgSendTxPacket");
}
strcat(buf, tempBuf);
break;
}
default:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tUKNOWN STATE: 0x%02x\n", TimeStampSeconds, TimeStampMS10ths, output[i]);
strcat(buf, tempBuf);
break;
}
}
}
strcat(buf, "\n"); // Append a newline for pretty++
return ++numChars; // Account for newline and return number of bytes to be shown
}
/* Fetch and display the Type-C state log */
static ssize_t _fusb_Sysfs_TypeCStateLog_show(struct device* dev, struct device_attribute* attr, char* buf)
{
FSC_S32 i = 0;
FSC_S32 numChars = 0;
FSC_S32 numLogs = 0;
FSC_U32 TimeStampSeconds = 0; // Timestamp value in seconds
FSC_U32 TimeStampMS10ths = 0; // Timestamp fraction in 10ths of milliseconds
FSC_S8 output[FSC_HOSTCOMM_BUFFER_SIZE] = { 0 };
FSC_S8 tempBuf[FUSB_MAX_BUF_SIZE] = { 0 };
tempBuf[0] = CMD_READ_STATE_LOG; // To request the Type-C statelog from Hostcomm
/* Get the PD State Log */
fusb_ProcessMsg(tempBuf, output);
numLogs = output[3];
/* First byte echos the command, 4th byte is number of logs (2nd and 3rd bytes reserved as 0) */
numChars += sprintf(tempBuf, "Type-C State Log has %u entries:\n", numLogs); // Copy string + null terminator
strcat(buf, tempBuf);
/* Relevant data starts at 5th byte in this format: CMD 0 0 #Logs State time time time time */
for (i = 4; (i + 4 < FSC_HOSTCOMM_BUFFER_SIZE) && (numChars < PAGE_SIZE) && (numLogs > 0); i += 5, numLogs--) // Must be able to peek 4 bytes ahead, and don't overflow the output buffer (PAGE_SIZE), only print logs we have
{
// Parse out the timestamp
fusb_timestamp_bytes_to_time(&TimeStampSeconds, &TimeStampMS10ths, &output[i + 1]);
// sprintf should be safe here because we're controlling the strings being printed, just make sure the strings are less than FUSB_MAX_BUF_SIZE+1
switch (output[i])
{
case Disabled:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tDisabled\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case ErrorRecovery:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tErrorRecovery\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case Unattached:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tUnattached\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case AttachWaitSink:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tAttachWaitSink\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case AttachedSink:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tAttachedSink\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case AttachWaitSource:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tAttachWaitSource\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case AttachedSource:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tAttachedSource\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case TrySource:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tTrySource\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case TryWaitSink:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tTryWaitSink\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case TrySink:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tTrySink\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case TryWaitSource:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tTryWaitSource\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case AudioAccessory:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tAudioAccessory\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case DebugAccessory:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tDebugAccessory\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case AttachWaitAccessory:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tAttachWaitAccessory\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case PoweredAccessory:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tPoweredAccessory\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case UnsupportedAccessory:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tUnsupportedAccessory\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case DelayUnattached:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tDelayUnattached\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
case UnattachedSource:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tUnattachedSource\n", TimeStampSeconds, TimeStampMS10ths);
strcat(buf, tempBuf);
break;
}
default:
{
numChars += sprintf(tempBuf, "[%u.%04u]\tUKNOWN STATE: 0x%02x\n", TimeStampSeconds, TimeStampMS10ths, output[i]);
strcat(buf, tempBuf);
break;
}
}
}
strcat(buf, "\n"); // Append a newline for pretty++
return ++numChars; // Account for newline and return number of bytes to be shown
}
/* Reinitialize the FUSB302 */
static ssize_t _fusb_Sysfs_Reinitialize_fusb302(struct device* dev, struct device_attribute* attr, char* buf)
{
struct fusb30x_chip* chip = fusb30x_GetChip();
if (chip == NULL)
{
return sprintf(buf, "FUSB302 Error: Internal chip structure pointer is NULL!\n");
}
/* Make sure that we are doing this in a thread-safe manner */
#ifdef FSC_INTERRUPT_TRIGGERED
disable_irq(chip->gpio_IntN_irq); // Waits for current IRQ handler to return, then disables it
#else
fusb_StopThreads(); // Waits for current work to complete, then cancels scheduled work and flushed the work queue
#endif // FSC_INTERRUPT_TRIGGERED
fusb_StopTimers();
core_initialize();
pr_debug ("FUSB %s - Core is initialized!\n", __func__);
fusb_StartTimers();
core_enable_typec(TRUE);
pr_debug ("FUSB %s - Type-C State Machine is enabled!\n", __func__);
#ifdef FSC_INTERRUPT_TRIGGERED
enable_irq(chip->gpio_IntN_irq);
#else
// Schedule to kick off the main working thread
schedule_work(&chip->worker);
#endif // FSC_INTERRUPT_TRIGGERED
return sprintf(buf, "FUSB302 Reinitialized!\n");
}
static ssize_t _fusb_Sysfs_vconn_en_store(struct device* dev, struct device_attribute* attr, const char* input, size_t size)
{
int vconn_input = 0;
sscanf(input, "%d", &vconn_input);
pr_info("FUSB [%s]: input: %d\n", __func__, vconn_input);
switch (vconn_input) {
case DISABLE_VCONN: // Disable VCONN
{
if (VCONN_enabled) {
if (!fusb_Power_Vconn(FALSE))
pr_err("FUSB [%s]: Error: Unable to force power off VCONN\n", __func__);
else {
Registers.Switches.byte[0] = Registers.Switches_temp.byte[0]; // restore Switch0 register status
Registers.Switches.VCONN_CC1 = 0;
Registers.Switches.VCONN_CC2 = 0;
DeviceWrite(regSwitches0, 1, &Registers.Switches.byte[0]);
VCONN_enabled = FALSE;
pr_info("FUSB [%s]: Force power off the VCONN done, and now Registers.Switches(0x02): 0x%x\n", __func__, Registers.Switches.byte[0]);
}
} else {
pr_info("FUSB [%s]: VCONN is already disabled, so we just break\n", __func__);
}
break;
}
case ENABLE_VCONN_CC1:
{
if (!fusb_Power_Vconn(TRUE))
pr_err("FUSB [%s]: Error: Unable to force power on VCONN %d\n", __func__, vconn_input);
else {
DeviceRead(regSwitches0, 1, &Registers.Switches_temp.byte[0]); // Backup current Switch0 register status
Registers.Switches.VCONN_CC1 = 1;
Registers.Switches.VCONN_CC2 = 0;
DeviceWrite(regSwitches0, 1, &Registers.Switches.byte[0]);
VCONN_enabled = TRUE;
pr_info("FUSB [%s]: Force power on the VCONN %d done, and now Registers.Switches(0x02): 0x%x\n", __func__, vconn_input, Registers.Switches.byte[0]);
}
break;
}
case ENABLE_VCONN_CC2:
{
if (!fusb_Power_Vconn(TRUE))
pr_err("FUSB [%s]: Error: Unable to force power on VCONN %d\n", __func__, vconn_input);
else {
DeviceRead(regSwitches0, 1, &Registers.Switches_temp.byte[0]); // Backup current Switch0 register status
Registers.Switches.VCONN_CC1 = 0;
Registers.Switches.VCONN_CC2 = 1;
DeviceWrite(regSwitches0, 1, &Registers.Switches.byte[0]);
VCONN_enabled = TRUE;
pr_info("FUSB [%s]: Force power on the VCONN %d done, and now Registers.Switches(0x02): 0x%x\n", __func__, vconn_input, Registers.Switches.byte[0]);
}
break;
}
default:
pr_err("FUSB [%s]: Error: Unable to handle the input: %d\n", __func__, vconn_input);
break;
}
return size;
}
// Define our device attributes to export them to sysfs
static DEVICE_ATTR(fusb30x_hostcomm, S_IRWXU | S_IRWXG | S_IROTH, _fusb_Sysfs_Hostcomm_show, _fusb_Sysfs_Hostcomm_store);
static DEVICE_ATTR(pd_state_log, S_IRUSR | S_IRGRP | S_IROTH, _fusb_Sysfs_PDStateLog_show, NULL);
static DEVICE_ATTR(typec_state_log, S_IRUSR | S_IRGRP | S_IROTH, _fusb_Sysfs_TypeCStateLog_show, NULL);
static DEVICE_ATTR(reinitialize, S_IRUSR | S_IRGRP | S_IROTH, _fusb_Sysfs_Reinitialize_fusb302, NULL);
static DEVICE_ATTR(vconn_en, S_IWUSR | S_IRUGO, NULL, _fusb_Sysfs_vconn_en_store);
static struct attribute *fusb302_sysfs_attrs[] = {
&dev_attr_fusb30x_hostcomm.attr,
&dev_attr_pd_state_log.attr,
&dev_attr_typec_state_log.attr,
&dev_attr_reinitialize.attr,
&dev_attr_vconn_en.attr,
NULL
};
static struct attribute_group fusb302_sysfs_attr_grp = {
.name = "control",
.attrs = fusb302_sysfs_attrs,
};
void fusb_Sysfs_Init(void)
{
FSC_S32 ret = 0;
struct fusb30x_chip* chip = fusb30x_GetChip();
if (chip == NULL)
{
pr_err("%s - Chip structure is null!\n", __func__);
return;
}
/* create attribute group for accessing the FUSB302 */
ret = sysfs_create_group(&chip->client->dev.kobj, &fusb302_sysfs_attr_grp);
if (ret)
{
pr_err("FUSB %s - Error creating sysfs attributes!\n", __func__);
}
}
#endif // FSC_DEBUG
/*********************************************************************************************************************/
/*********************************************************************************************************************/
/******************************************** Driver Helpers ******************************************/
/*********************************************************************************************************************/
/*********************************************************************************************************************/
void fusb_InitializeCore(void)
{
#ifndef FSC_INTERRUPT_TRIGGERED
fusb_StartTimers();
pr_debug("FUSB %s - Timers are started!\n", __func__);
#endif
core_initialize();
pr_debug("FUSB %s - Core is initialized!\n", __func__);
core_enable_typec(TRUE);
pr_debug("FUSB %s - Type-C State Machine is enabled!\n", __func__);
}
FSC_BOOL fusb_IsDeviceValid(void)
{
FSC_U8 val = 0;
struct fusb30x_chip* chip = fusb30x_GetChip();
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
return FALSE;
}
// Test to see if we can do a successful I2C read
if (!fusb_I2C_ReadData((FSC_U8)0x01, &val))
{
pr_err("FUSB %s - Error: Could not communicate with device over I2C!\n", __func__);
return FALSE;
}
return TRUE;
}
void fusb_InitChipData(void)
{
struct fusb30x_chip* chip = fusb30x_GetChip();
if (chip == NULL)
{
pr_err("%s - Chip structure is null!\n", __func__);
return;
}
#ifdef FSC_DEBUG
chip->dbgTimerTicks = 0;
chip->dbgTimerRollovers = 0;
chip->dbgSMTicks = 0;
chip->dbgSMRollovers = 0;
chip->dbg_gpio_StateMachine = -1;
chip->dbg_gpio_StateMachine_value = false;
#endif // FSC_DEBUG
/* GPIO Defaults */
chip->gpio_VBus5V = -1;
chip->gpio_VBus5V_value = false;
chip->gpio_VBusOther = -1;
chip->gpio_VBusOther_value = false;
chip->gpio_IntN = -1;
#ifdef FSC_INTERRUPT_TRIGGERED
chip->gpio_IntN_irq = -1;
#endif // FSC_INTERRUPT_TRIGGERED
/* I2C Configuration */
chip->InitDelayMS = INIT_DELAY_MS; // Time to wait before device init
chip->numRetriesI2C = RETRIES_I2C; // Number of times to retry I2C reads and writes
chip->use_i2c_blocks = false; // Assume failure
chip->pmode = DUAL_ROLE_PROP_MODE_NONE;
chip->prole = DUAL_ROLE_PROP_PR_NONE;
chip->drole = DUAL_ROLE_PROP_DR_NONE;
chip->vconn = DUAL_ROLE_PROP_VCONN_SUPPLY_NO;
}
/*********************************************************************************************************************/
/*********************************************************************************************************************/
/****************************************** IRQ/Threading Helpers *****************************************/
/*********************************************************************************************************************/
/*********************************************************************************************************************/
#ifdef FSC_INTERRUPT_TRIGGERED
FSC_S32 fusb_EnableInterrupts(void)
{
FSC_S32 ret = 0;
struct fusb30x_chip* chip = fusb30x_GetChip();
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
return -ENOMEM;
}
wake_lock_init(&chip->fusb_wlock, WAKE_LOCK_SUSPEND, "fusb_wlock");
/* Set up IRQ for INT_N GPIO */
ret = gpio_to_irq(chip->gpio_IntN); // Returns negative errno on error
if (ret < 0)
{
dev_err(&chip->client->dev, "%s - Error: Unable to request IRQ for INT_N GPIO! Error code: %d\n", __func__, ret);
chip->gpio_IntN_irq = -1; // Set to indicate error
fusb_GPIO_Cleanup();
return ret;
}
chip->gpio_IntN_irq = ret;
pr_debug("%s - Success: Requested INT_N IRQ: '%d'\n", __func__, chip->gpio_IntN_irq);
/* Request threaded IRQ because we will likely sleep while handling the interrupt, trigger is active-low, don't handle concurrent interrupts */
ret = devm_request_threaded_irq(&chip->client->dev, chip->gpio_IntN_irq, NULL, _fusb_isr_intn, IRQF_ONESHOT | IRQF_TRIGGER_LOW, FUSB_DT_INTERRUPT_INTN, chip); // devm_* allocation/free handled by system
if (ret)
{
dev_err(&chip->client->dev, "%s - Error: Unable to request threaded IRQ for INT_N GPIO! Error code: %d\n", __func__, ret);
fusb_GPIO_Cleanup();
return ret;
}
if (chip->gpio_IntN_irq)
enable_irq_wake(chip->gpio_IntN_irq);
return 0;
}
/*******************************************************************************
* Function: _fusb_isr_intn
* Input: irq - IRQ that was triggered
* dev_id - Ptr to driver data structure
* Return: irqreturn_t - IRQ_HANDLED on success, IRQ_NONE on failure
* Description: Activates the core
********************************************************************************/
static irqreturn_t _fusb_isr_intn(FSC_S32 irq, void *dev_id)
{
struct fusb30x_chip* chip = dev_id;
printk(KERN_INFO "FUSB [%s]: FUSB-interrupt triggered ++ \n", __func__);
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
return IRQ_NONE;
}
#ifdef FSC_DEBUG
dbg_fusb_GPIO_Set_SM_Toggle(!chip->dbg_gpio_StateMachine_value); // Optionally toggle debug GPIO when SM is called to measure thread tick rate
if (chip->dbgSMTicks++ >= U8_MAX) // Tick our state machine tick counter
{
chip->dbgSMRollovers++; // Record a moderate amount of rollovers
}
#endif // FSC_DEBUG
mutex_lock(&chip->statemachine_lock);
wake_lock(&chip->fusb_wlock);
core_state_machine(); // Run the state machine
wake_unlock(&chip->fusb_wlock);
mutex_unlock(&chip->statemachine_lock);
pr_info("FUSB [%s]: FUSB-interrupt handled ++ \n", __func__);
return IRQ_HANDLED;
}
#else
/*******************************************************************************
* Function: _fusb_InitWorker
* Input: delayed_work - passed in from OS
* Return: none
* Description: Callback for the init worker, kicks off the main worker
********************************************************************************/
void _fusb_InitWorker(struct work_struct* delayed_work)
{
struct fusb30x_chip* chip = container_of(delayed_work, struct fusb30x_chip, init_worker.work);
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
return;
}
// Schedule to kick off the main working thread
schedule_work(&chip->worker);
}
/*******************************************************************************
* Function: _fusb_MainWorker
* Input: delayed_work - passed in from OS
* Return: none
* Description: Activates the core
********************************************************************************/
void _fusb_MainWorker(struct work_struct* work)
{
struct fusb30x_chip* chip = container_of(work, struct fusb30x_chip, worker);
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
return;
}
#ifdef FSC_DEBUG
dbg_fusb_GPIO_Set_SM_Toggle(!chip->dbg_gpio_StateMachine_value); // Optionally toggle debug GPIO when SM is called to measure thread tick rate
if (chip->dbgSMTicks++ >= U8_MAX) // Tick our state machine tick counter
{
chip->dbgSMRollovers++; // Record a moderate amount of rollovers
}
#endif // FSC_DEBUG
core_state_machine(); // Run the state machine
schedule_work(&chip->worker); // Reschedule ourselves to run again
}
void fusb_InitializeWorkers(void)
{
struct fusb30x_chip* chip = fusb30x_GetChip();
pr_debug("FUSB %s - Initializing threads!\n", __func__);
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
return;
}
// Initialize our delayed_work and work structs
INIT_DELAYED_WORK(&chip->init_worker, _fusb_InitWorker);
INIT_WORK(&chip->worker, _fusb_MainWorker);
}
void fusb_StopThreads(void)
{
struct fusb30x_chip* chip = fusb30x_GetChip();
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
return;
}
// Cancel the initial delayed work
cancel_delayed_work_sync(&chip->init_worker);
flush_delayed_work(&chip->init_worker);
// Cancel the main worker
flush_work(&chip->worker);
cancel_work_sync(&chip->worker);
if (chip->gpio_IntN_irq)
disable_irq_wake(chip->gpio_IntN_irq);
wake_lock_destroy(&chip->fusb_wlock);
}
void fusb_ScheduleWork(void)
{
struct fusb30x_chip* chip = fusb30x_GetChip();
if (!chip)
{
pr_err("FUSB %s - Error: Chip structure is NULL!\n", __func__);
return;
}
schedule_delayed_work(&chip->init_worker, msecs_to_jiffies(chip->InitDelayMS));
}
#endif // FSC_INTERRUPT_TRIGGERED, else