// SPDX-License-Identifier: GPL-2.0
#include <linux/bitfield.h>
#include <linux/completion.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/power_supply.h>
#include <linux/regmap.h>
#include <linux/usb/pd.h>
#include <linux/usb/role.h>
#include <linux/usb/typec.h>
#define RT1719_REG_TXCTRL1 0x03
#define RT1719_REG_TXCTRL2 0x04
#define RT1719_REG_POLICYINFO 0x0E
#define RT1719_REG_SRCPDO1 0x11
#define RT1719_REG_MASKS 0x2D
#define RT1719_REG_EVENTS 0x33
#define RT1719_REG_STATS 0x37
#define RT1719_REG_PSELINFO 0x3C
#define RT1719_REG_USBSETINFO 0x3E
#define RT1719_REG_VENID 0x82
#define RT1719_UNIQUE_PID 0x1719
#define RT1719_REQDRSWAP_MASK BIT(7)
#define RT1719_EVALMODE_MASK BIT(4)
#define RT1719_REQSRCPDO_MASK GENMASK(2, 0)
#define RT1719_TXSPDOREQ_MASK BIT(7)
#define RT1719_INT_DRSW_ACCEPT BIT(23)
#define RT1719_INT_RX_SRCCAP BIT(21)
#define RT1719_INT_VBUS_DCT BIT(6)
#define RT1719_INT_VBUS_PRESENT BIT(5)
#define RT1719_INT_PE_SNK_RDY BIT(2)
#define RT1719_CC1_STAT GENMASK(9, 8)
#define RT1719_CC2_STAT GENMASK(11, 10)
#define RT1719_POLARITY_MASK BIT(23)
#define RT1719_DATAROLE_MASK BIT(22)
#define RT1719_PDSPECREV_MASK GENMASK(21, 20)
#define RT1719_SPDOSEL_MASK GENMASK(18, 16)
#define RT1719_SPDONUM_MASK GENMASK(15, 13)
#define RT1719_ATTACH_VBUS BIT(12)
#define RT1719_ATTACH_DBG BIT(10)
#define RT1719_ATTACH_SNK BIT(9)
#define RT1719_ATTACHDEV_MASK (RT1719_ATTACH_VBUS | RT1719_ATTACH_DBG | \
RT1719_ATTACH_SNK)
#define RT1719_PE_EXP_CONTRACT BIT(2)
#define RT1719_PSEL_SUPPORT BIT(15)
#define RT1719_TBLSEL_MASK BIT(6)
#define RT1719_LATPSEL_MASK GENMASK(5, 0)
#define RT1719_USBINFO_MASK GENMASK(1, 0)
#define RT1719_USB_DFPUFP 3
#define RT1719_MAX_SRCPDO 7
enum {
SNK_PWR_OPEN = 0,
SNK_PWR_DEF,
SNK_PWR_1P5A,
SNK_PWR_3A
};
enum {
USBPD_SPECREV_1_0 = 0,
USBPD_SPECREV_2_0,
USBPD_SPECREV_3_0
};
enum rt1719_snkcap {
RT1719_SNKCAP_5V = 0,
RT1719_SNKCAP_9V,
RT1719_SNKCAP_12V,
RT1719_SNKCAP_15V,
RT1719_SNKCAP_20V,
RT1719_MAX_SNKCAP
};
struct rt1719_psel_cap {
u8 lomask;
u8 himask;
u32 milliwatt;
u32 milliamp;
};
struct rt1719_data {
struct device *dev;
struct regmap *regmap;
struct typec_port *port;
struct usb_role_switch *role_sw;
struct power_supply *psy;
struct typec_partner *partner;
struct power_supply_desc psy_desc;
struct usb_pd_identity partner_ident;
struct typec_partner_desc partner_desc;
struct completion req_completion;
enum power_supply_usb_type usb_type;
bool attached;
bool pd_capable;
bool drswap_support;
u32 voltage;
u32 req_voltage;
u32 max_current;
u32 op_current;
u32 spdos[RT1719_MAX_SRCPDO];
u16 snkcaps[RT1719_MAX_SNKCAP];
int spdo_num;
int spdo_sel;
u32 conn_info;
u16 conn_stat;
};
static const enum power_supply_property rt1719_psy_properties[] = {
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_USB_TYPE,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CURRENT_MAX,
POWER_SUPPLY_PROP_CURRENT_NOW
};
static int rt1719_read16(struct rt1719_data *data, unsigned int reg, u16 *val)
{
__le16 regval;
int ret;
ret = regmap_raw_read(data->regmap, reg, ®val, sizeof(regval));
if (ret)
return ret;
*val = le16_to_cpu(regval);
return 0;
}
static int rt1719_read32(struct rt1719_data *data, unsigned int reg, u32 *val)
{
__le32 regval;
int ret;
ret = regmap_raw_read(data->regmap, reg, ®val, sizeof(regval));
if (ret)
return ret;
*val = le32_to_cpu(regval);
return 0;
}
static int rt1719_write32(struct rt1719_data *data, unsigned int reg, u32 val)
{
__le32 regval = cpu_to_le32(val);
return regmap_raw_write(data->regmap, reg, ®val, sizeof(regval));
}
static enum typec_pwr_opmode rt1719_get_pwr_opmode(u32 conn, u16 stat)
{
u16 cc1, cc2, cc_stat;
cc1 = FIELD_GET(RT1719_CC1_STAT, stat);
cc2 = FIELD_GET(RT1719_CC2_STAT, stat);
if (conn & RT1719_ATTACH_SNK) {
if (conn & RT1719_POLARITY_MASK)
cc_stat = cc2;
else
cc_stat = cc1;
switch (cc_stat) {
case SNK_PWR_3A:
return TYPEC_PWR_MODE_3_0A;
case SNK_PWR_1P5A:
return TYPEC_PWR_MODE_1_5A;
}
} else if (conn & RT1719_ATTACH_DBG) {
if ((cc1 == SNK_PWR_1P5A && cc2 == SNK_PWR_DEF) ||
(cc1 == SNK_PWR_DEF && cc2 == SNK_PWR_1P5A))
return TYPEC_PWR_MODE_1_5A;
else if ((cc1 == SNK_PWR_3A && cc2 == SNK_PWR_DEF) ||
(cc1 == SNK_PWR_DEF && cc2 == SNK_PWR_3A))
return TYPEC_PWR_MODE_3_0A;
}
return TYPEC_PWR_MODE_USB;
}
static enum typec_data_role rt1719_get_data_role(u32 conn)
{
if (conn & RT1719_DATAROLE_MASK