#include <linux/i2c.h>
#include <linux/acpi.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/power_supply.h>
#include <linux/regmap.h>
#include <linux/interrupt.h>
#include <linux/usb/typec.h>
#include <linux/usb/typec_altmode.h>
#include <linux/usb/role.h>
#include <linux/workqueue.h>
#include <linux/firmware.h>
#include "tps6598x.h"
#include "trace.h"
#define TPS_REG_VID …
#define TPS_REG_MODE …
#define TPS_REG_CMD1 …
#define TPS_REG_DATA1 …
#define TPS_REG_VERSION …
#define TPS_REG_INT_EVENT1 …
#define TPS_REG_INT_EVENT2 …
#define TPS_REG_INT_MASK1 …
#define TPS_REG_INT_MASK2 …
#define TPS_REG_INT_CLEAR1 …
#define TPS_REG_INT_CLEAR2 …
#define TPS_REG_SYSTEM_POWER_STATE …
#define TPS_REG_STATUS …
#define TPS_REG_SYSTEM_CONF …
#define TPS_REG_CTRL_CONF …
#define TPS_REG_BOOT_STATUS …
#define TPS_REG_POWER_STATUS …
#define TPS_REG_PD_STATUS …
#define TPS_REG_RX_IDENTITY_SOP …
#define TPS_REG_DATA_STATUS …
#define TPS_REG_SLEEP_CONF …
#define TPS_SYSCONF_PORTINFO(c) …
#define TPS_BUNDLE_TIMEOUT …
#define TPS_TASK_BPMS_INVALID_BUNDLE_SIZE …
#define TPS_TASK_BPMS_INVALID_SLAVE_ADDR …
#define TPS_TASK_BPMS_INVALID_TIMEOUT …
#define TPS_PBMC_RC …
#define TPS_PBMC_DPCS …
#define TPS_SETUP_MS …
enum { … };
struct tps6598x_rx_identity_reg { … } __packed;
#define TPS_TASK_TIMEOUT …
#define TPS_TASK_REJECTED …
enum { … };
static const char *const modes[] = …;
#define INVALID_CMD(_cmd_) …
struct tps6598x;
struct tipd_data { … };
struct tps6598x { … };
static enum power_supply_property tps6598x_psy_props[] = …;
static enum power_supply_usb_type tps6598x_psy_usb_types[] = …;
static const char *tps6598x_psy_name_prefix = …;
#define TPS_MAX_LEN …
static int
tps6598x_block_read(struct tps6598x *tps, u8 reg, void *val, size_t len)
{ … }
static int tps6598x_block_write(struct tps6598x *tps, u8 reg,
const void *val, size_t len)
{ … }
static inline int tps6598x_read8(struct tps6598x *tps, u8 reg, u8 *val)
{ … }
static inline int tps6598x_read16(struct tps6598x *tps, u8 reg, u16 *val)
{ … }
static inline int tps6598x_read32(struct tps6598x *tps, u8 reg, u32 *val)
{ … }
static inline int tps6598x_read64(struct tps6598x *tps, u8 reg, u64 *val)
{ … }
static inline int tps6598x_write8(struct tps6598x *tps, u8 reg, u8 val)
{ … }
static inline int tps6598x_write64(struct tps6598x *tps, u8 reg, u64 val)
{ … }
static inline int
tps6598x_write_4cc(struct tps6598x *tps, u8 reg, const char *val)
{ … }
static int tps6598x_read_partner_identity(struct tps6598x *tps)
{ … }
static void tps6598x_set_data_role(struct tps6598x *tps,
enum typec_data_role role, bool connected)
{ … }
static int tps6598x_connect(struct tps6598x *tps, u32 status)
{ … }
static void tps6598x_disconnect(struct tps6598x *tps, u32 status)
{ … }
static int tps6598x_exec_cmd_tmo(struct tps6598x *tps, const char *cmd,
size_t in_len, const u8 *in_data,
size_t out_len, u8 *out_data,
u32 cmd_timeout_ms, u32 res_delay_ms)
{ … }
static int tps6598x_exec_cmd(struct tps6598x *tps, const char *cmd,
size_t in_len, const u8 *in_data,
size_t out_len, u8 *out_data)
{ … }
static int tps6598x_dr_set(struct typec_port *port, enum typec_data_role role)
{ … }
static int tps6598x_pr_set(struct typec_port *port, enum typec_role role)
{ … }
static const struct typec_operations tps6598x_ops = …;
static bool tps6598x_read_status(struct tps6598x *tps, u32 *status)
{ … }
static bool tps6598x_read_data_status(struct tps6598x *tps)
{ … }
static bool tps6598x_read_power_status(struct tps6598x *tps)
{ … }
static void tps6598x_handle_plug_event(struct tps6598x *tps, u32 status)
{ … }
static irqreturn_t cd321x_interrupt(int irq, void *data)
{ … }
static bool tps6598x_has_role_changed(struct tps6598x *tps, u32 status)
{ … }
static irqreturn_t tps25750_interrupt(int irq, void *data)
{ … }
static irqreturn_t tps6598x_interrupt(int irq, void *data)
{ … }
#define POLL_INTERVAL …
static void tps6598x_poll_work(struct work_struct *work)
{ … }
static int tps6598x_check_mode(struct tps6598x *tps)
{ … }
static const struct regmap_config tps6598x_regmap_config = …;
static int tps6598x_psy_get_online(struct tps6598x *tps,
union power_supply_propval *val)
{ … }
static int tps6598x_psy_get_prop(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{ … }
static int cd321x_switch_power_state(struct tps6598x *tps, u8 target_state)
{ … }
static int devm_tps6598_psy_register(struct tps6598x *tps)
{ … }
static int
tps6598x_register_port(struct tps6598x *tps, struct fwnode_handle *fwnode)
{ … }
static int tps_request_firmware(struct tps6598x *tps, const struct firmware **fw,
const char **firmware_name)
{ … }
static int
tps25750_write_firmware(struct tps6598x *tps,
u8 bpms_addr, const u8 *data, size_t len)
{ … }
static int
tps25750_exec_pbms(struct tps6598x *tps, u8 *in_data, size_t in_len)
{ … }
static int tps25750_abort_patch_process(struct tps6598x *tps)
{ … }
static int tps25750_start_patch_burst_mode(struct tps6598x *tps)
{ … }
static int tps25750_complete_patch_process(struct tps6598x *tps)
{ … }
static int tps25750_apply_patch(struct tps6598x *tps)
{
int ret;
unsigned long timeout;
u64 status = 0;
ret = tps6598x_block_read(tps, TPS_REG_BOOT_STATUS, &status, 5);
if (ret)
return ret;
if (status & TPS_BOOT_STATUS_I2C_EEPROM_PRESENT)
goto wait_for_app;
ret = tps25750_start_patch_burst_mode(tps);
if (ret) {
tps25750_abort_patch_process(tps);
return ret;
}
ret = tps25750_complete_patch_process(tps);
if (ret)
return ret;
wait_for_app:
timeout = jiffies + msecs_to_jiffies(1000);
do {
ret = tps6598x_check_mode(tps);
if (ret < 0)
return ret;
if (time_is_before_jiffies(timeout))
return -ETIMEDOUT;
} while (ret != TPS_MODE_APP);
if (status & TPS_BOOT_STATUS_DEAD_BATTERY_FLAG) {
ret = tps6598x_exec_cmd(tps, "DBfg", 0, NULL, 0, NULL);
if (ret) {
dev_err(tps->dev, "failed to clear dead battery %d\n", ret);
return ret;
}
}
dev_info(tps->dev, "controller switched to \"APP\" mode\n");
return 0;
};
static int tps6598x_apply_patch(struct tps6598x *tps)
{
u8 in = TPS_PTCS_CONTENT_DEV | TPS_PTCS_CONTENT_APP;
u8 out[TPS_MAX_LEN] = {0};
size_t in_len = sizeof(in);
size_t copied_bytes = 0;
size_t bytes_left;
const struct firmware *fw;
const char *firmware_name;
int ret;
ret = tps_request_firmware(tps, &fw, &firmware_name);
if (ret)
return ret;
ret = tps6598x_exec_cmd(tps, "PTCs", in_len, &in,
TPS_PTCS_OUT_BYTES, out);
if (ret || out[TPS_PTCS_STATUS] == TPS_PTCS_STATUS_FAIL) {
if (!ret)
ret = -EBUSY;
dev_err(tps->dev, "Update start failed (%d)\n", ret);
goto release_fw;
}
bytes_left = fw->size;
while (bytes_left) {
in_len = min(bytes_left, TPS_MAX_LEN);
ret = tps6598x_exec_cmd(tps, "PTCd", in_len,
fw->data + copied_bytes,
TPS_PTCD_OUT_BYTES, out);
if (ret || out[TPS_PTCD_TRANSFER_STATUS] ||
out[TPS_PTCD_LOADING_STATE] == TPS_PTCD_LOAD_ERR) {
if (!ret)
ret = -EBUSY;
dev_err(tps->dev, "Patch download failed (%d)\n", ret);
goto release_fw;
}
copied_bytes += in_len;
bytes_left -= in_len;
}
ret = tps6598x_exec_cmd(tps, "PTCc", 0, NULL, TPS_PTCC_OUT_BYTES, out);
if (ret || out[TPS_PTCC_DEV] || out[TPS_PTCC_APP]) {
if (!ret)
ret = -EBUSY;
dev_err(tps->dev, "Update completion failed (%d)\n", ret);
goto release_fw;
}
msleep(TPS_SETUP_MS);
dev_info(tps->dev, "Firmware update succeeded\n");
release_fw:
release_firmware(fw);
if (ret) {
dev_err(tps->dev, "Failed to write patch %s of %zu bytes\n",
firmware_name, fw->size);
}
return ret;
};
static int cd321x_init(struct tps6598x *tps)
{ … }
static int tps25750_init(struct tps6598x *tps)
{ … }
static int tps6598x_init(struct tps6598x *tps)
{ … }
static int cd321x_reset(struct tps6598x *tps)
{ … }
static int tps25750_reset(struct tps6598x *tps)
{ … }
static int tps6598x_reset(struct tps6598x *tps)
{ … }
static int
tps25750_register_port(struct tps6598x *tps, struct fwnode_handle *fwnode)
{ … }
static int tps6598x_probe(struct i2c_client *client)
{ … }
static void tps6598x_remove(struct i2c_client *client)
{ … }
static int __maybe_unused tps6598x_suspend(struct device *dev)
{ … }
static int __maybe_unused tps6598x_resume(struct device *dev)
{ … }
static const struct dev_pm_ops tps6598x_pm_ops = …;
static const struct tipd_data cd321x_data = …;
static const struct tipd_data tps6598x_data = …;
static const struct tipd_data tps25750_data = …;
static const struct of_device_id tps6598x_of_match[] = …;
MODULE_DEVICE_TABLE(of, tps6598x_of_match);
static const struct i2c_device_id tps6598x_id[] = …;
MODULE_DEVICE_TABLE(i2c, tps6598x_id);
static struct i2c_driver tps6598x_i2c_driver = …;
module_i2c_driver(…) …;
MODULE_AUTHOR(…) …;
MODULE_LICENSE(…) …;
MODULE_DESCRIPTION(…) …;