mfd: fusb302: Fix no response to get sink cap from source

The fusb302 use the legacy driver on RK3399 kernel-4.4/4.19 platforms.
The legacy driver doesn't support to send sink capabilities message,
it cause RK3399 Type-C USB ADB fail to connected to MacBook with a
Type-C to Type-C cable.

This patch adds the sink capabilities message and use non-threaded
interrupt handler.

1. Add sink capabilities message for fixed supply and battery supply.
2. Move the interrupt handling from a threaded interrupt handler to
   a non-threaded interrupt handler which normally queues the new
   interrupt handling work directly.

Signed-off-by: William Wu <william.wu@rock-chips.com>
Change-Id: I13df67d71d1f0c11f4256daacd2243dcfb8ae414
This commit is contained in:
William Wu
2022-12-22 14:59:33 +08:00
parent 96fef83b06
commit 05fedf45f0
2 changed files with 77 additions and 18 deletions

View File

@@ -929,6 +929,7 @@ static void set_state_unattached(struct fusb30x_chip *chip)
static void set_mesg(struct fusb30x_chip *chip, int cmd, int is_DMT)
{
int i;
uint32_t rec_load;
struct PD_CAP_INFO *pd_cap_info = &chip->pd_cap_info;
chip->send_head = ((chip->msg_id & 0x7) << 9) |
@@ -962,24 +963,62 @@ static void set_mesg(struct fusb30x_chip *chip, int cmd, int is_DMT)
(0 << 25) |
(0 << 24);
switch (CAP_POWER_TYPE(chip->rec_load[chip->pos_power - 1])) {
rec_load = chip->rec_load[chip->pos_power - 1];
switch (CAP_POWER_TYPE(rec_load)) {
case 0:
/* Fixed Supply */
chip->send_load[0] |= CAP_FPDO_VOLTAGE(chip->rec_load[chip->pos_power - 1]) << 10;
chip->send_load[0] |= CAP_FPDO_CURRENT(chip->rec_load[chip->pos_power - 1]);
chip->sink_supply_type = 0;
chip->sink_volt = CAP_FPDO_VOLTAGE(rec_load);
chip->sink_opr_cur = CAP_FPDO_CURRENT(rec_load);
chip->send_load[0] |= chip->sink_volt << 10;
chip->send_load[0] |= chip->sink_opr_cur;
break;
case 1:
/* Battery */
chip->send_load[0] |= CAP_VPDO_MAX_VOLTAGE(chip->rec_load[chip->pos_power - 1]) << 20;
chip->send_load[0] |= CAP_VPDO_MIN_VOLTAGE(chip->rec_load[chip->pos_power - 1]) << 10;
chip->send_load[0] |= CAP_VPDO_CURRENT(chip->rec_load[chip->pos_power - 1]);
/* Battery Supply */
chip->sink_supply_type = 1;
chip->sink_max_volt =
CAP_VPDO_MAX_VOLTAGE(rec_load);
chip->sink_min_volt =
CAP_VPDO_MIN_VOLTAGE(rec_load);
chip->sink_opr_power =
CAP_VPDO_CURRENT(rec_load);
chip->send_load[0] |= chip->sink_max_volt << 20;
chip->send_load[0] |= chip->sink_min_volt << 10;
chip->send_load[0] |= chip->sink_opr_power;
break;
default:
/* not meet battery caps */
dev_warn(chip->dev, "No support supply req type %d\n",
CAP_POWER_TYPE(rec_load));
break;
}
break;
case DMT_SINKCAPABILITIES:
chip->send_head |= (1 << 12) | (cmd & 0xf);
switch (chip->sink_supply_type) {
case 0:
/*
* Fixed Supply
* bit26 for 'USB Communiications Capable'
*/
chip->send_load[0] =
(chip->sink_supply_type << 30) |
(1 << 26) |
(chip->sink_volt << 10) |
(chip->sink_opr_cur);
break;
case 1:
/* Battery Supply */
chip->send_load[0] =
(chip->sink_supply_type << 30) |
(chip->sink_max_volt << 20) |
(chip->sink_min_volt << 10) |
(chip->sink_opr_cur);
break;
default:
dev_warn(chip->dev, "No support sink supply type %d\n",
chip->sink_supply_type);
break;
}
break;
case DMT_VENDERDEFINED:
break;
@@ -2621,6 +2660,14 @@ static void fusb_state_snk_transition_sink(struct fusb30x_chip *chip, u32 evt)
chip->notify.is_pd_connected = true;
dev_info(chip->dev,
"PD connected as UFP, fetching 5V\n");
tcpm_get_message(chip);
if (PACKET_IS_CONTROL_MSG(chip->rec_head,
CMT_GETSINKCAP)) {
set_mesg(chip, DMT_SINKCAPABILITIES,
DATAMESSAGE);
chip->tx_state = tx_idle;
policy_send_data(chip);
}
set_state(chip, policy_snk_ready);
} else if (PACKET_IS_DATA_MSG(chip->rec_head,
DMT_SOURCECAPABILITIES)) {
@@ -2672,7 +2719,12 @@ static void fusb_state_snk_transition_default(struct fusb30x_chip *chip,
static void fusb_state_snk_ready(struct fusb30x_chip *chip, u32 evt)
{
if (evt & EVENT_RX) {
if (PACKET_IS_DATA_MSG(chip->rec_head, DMT_VENDERDEFINED)) {
if (PACKET_IS_CONTROL_MSG(chip->rec_head, CMT_GETSINKCAP)) {
set_mesg(chip, DMT_SINKCAPABILITIES, DATAMESSAGE);
chip->tx_state = tx_idle;
policy_send_data(chip);
} else if (PACKET_IS_DATA_MSG(chip->rec_head,
DMT_VENDERDEFINED)) {
process_vdm_msg(chip);
chip->work_continue |= EVENT_WORK_CONTINUE;
chip->timer_state = T_DISABLED;
@@ -3365,6 +3417,8 @@ static int fusb30x_probe(struct i2c_client *client,
chip->n_caps_used = 1;
chip->source_power_supply[0] = 0x64;
chip->source_max_current[0] = 0x96;
chip->sink_volt = 100;
chip->sink_opr_cur = 200;
pd_cap_info = &chip->pd_cap_info;
pd_cap_info->dual_role_power = 1;
@@ -3465,13 +3519,8 @@ static int fusb30x_probe(struct i2c_client *client,
goto IRQ_ERR;
}
ret = devm_request_threaded_irq(&client->dev,
chip->gpio_int_irq,
NULL,
cc_interrupt_handler,
IRQF_ONESHOT | IRQF_TRIGGER_LOW,
client->name,
chip);
ret = request_irq(chip->gpio_int_irq, cc_interrupt_handler,
IRQF_TRIGGER_LOW, "fsc_interrupt_int_n", chip);
if (ret) {
dev_err(&client->dev, "irq request failed\n");
goto IRQ_ERR;
@@ -3508,6 +3557,7 @@ static int fusb30x_remove(struct i2c_client *client)
{
struct fusb30x_chip *chip = i2c_get_clientdata(client);
free_irq(chip->gpio_int_irq, chip);
destroy_workqueue(chip->fusb30x_wq);
return 0;
}

View File

@@ -525,10 +525,19 @@ struct fusb30x_chip {
int msg_id;
enum tx_state tx_state;
int hardrst_count;
u32 source_power_supply[7];
/* 50mv unit */
u32 source_max_current[7];
u32 source_power_supply[7];
/* 10ma uint*/
u32 source_max_current[7];
/* Fixed supply = 0, Battery supply = 1 */
u32 sink_supply_type;
/* Sink Fixed Supply */
u32 sink_volt;
u32 sink_opr_cur;
/* Sink Battery Supply */
u32 sink_max_volt;
u32 sink_min_volt;
u32 sink_opr_power;
int pos_power;
/*
* if PartnerCap[0] == 0xffffffff