diff --git a/drivers/mfd/fusb302.c b/drivers/mfd/fusb302.c index 3c1190f3f6a7..1044b5958c01 100644 --- a/drivers/mfd/fusb302.c +++ b/drivers/mfd/fusb302.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include "fusb302.h" @@ -929,6 +931,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 +965,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 +2662,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 +2721,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; @@ -3190,22 +3244,22 @@ static void state_machine_typec(struct fusb30x_chip *chip) BACK: if (chip->work_continue) { - queue_work(chip->fusb30x_wq, &chip->work); + kthread_queue_work(chip->irq_worker, &chip->irq_work); return; } if (!platform_get_device_irq_state(chip)) fusb_irq_enable(chip); else - queue_work(chip->fusb30x_wq, &chip->work); + kthread_queue_work(chip->irq_worker, &chip->irq_work); } static irqreturn_t cc_interrupt_handler(int irq, void *dev_id) { struct fusb30x_chip *chip = dev_id; - queue_work(chip->fusb30x_wq, &chip->work); fusb_irq_disable(chip); + kthread_queue_work(chip->irq_worker, &chip->irq_work); return IRQ_HANDLED; } @@ -3267,8 +3321,8 @@ static enum hrtimer_restart fusb_timer_handler(struct hrtimer *timer) } if (i != fusb30x_port_used) - queue_work(fusb30x_port_info[i]->fusb30x_wq, - &fusb30x_port_info[i]->work); + kthread_queue_work(fusb30x_port_info[i]->irq_worker, + &fusb30x_port_info[i]->irq_work); return HRTIMER_NORESTART; } @@ -3287,11 +3341,11 @@ static void fusb_initialize_timer(struct fusb30x_chip *chip) chip->timer_mux = T_DISABLED; } -static void fusb302_work_func(struct work_struct *work) +static void fusb302_work_func(struct kthread_work *work) { struct fusb30x_chip *chip; - chip = container_of(work, struct fusb30x_chip, work); + chip = container_of(work, struct fusb30x_chip, irq_work); if (!chip->suspended) state_machine_typec(chip); } @@ -3301,6 +3355,7 @@ static int fusb30x_probe(struct i2c_client *client, { struct fusb30x_chip *chip; struct PD_CAP_INFO *pd_cap_info; + struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; int ret; char *string[2]; @@ -3327,8 +3382,11 @@ static int fusb30x_probe(struct i2c_client *client, fusb_initialize_timer(chip); - chip->fusb30x_wq = create_workqueue("fusb302_wq"); - INIT_WORK(&chip->work, fusb302_work_func); + chip->irq_worker = kthread_create_worker(0, dev_name(chip->dev)); + if (IS_ERR(chip->irq_worker)) + return PTR_ERR(chip->irq_worker); + sched_setscheduler_nocheck(chip->irq_worker->task, SCHED_FIFO, ¶m); + kthread_init_work(&chip->irq_work, fusb302_work_func); chip->role = ROLE_MODE_NONE; chip->try_role = ROLE_MODE_NONE; @@ -3369,6 +3427,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; @@ -3469,13 +3529,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; @@ -3504,7 +3559,7 @@ static int fusb30x_probe(struct i2c_client *client, } return 0; IRQ_ERR: - destroy_workqueue(chip->fusb30x_wq); + kthread_destroy_worker(chip->irq_worker); return ret; } @@ -3512,7 +3567,8 @@ static int fusb30x_remove(struct i2c_client *client) { struct fusb30x_chip *chip = i2c_get_clientdata(client); - destroy_workqueue(chip->fusb30x_wq); + free_irq(chip->gpio_int_irq, chip); + kthread_destroy_worker(chip->irq_worker); return 0; } @@ -3535,7 +3591,7 @@ static int fusb30x_pm_suspend(struct device *dev) fusb_irq_disable(chip); chip->suspended = true; - cancel_work_sync(&chip->work); + kthread_cancel_work_sync(&chip->irq_work); return 0; } @@ -3546,7 +3602,7 @@ static int fusb30x_pm_resume(struct device *dev) fusb_irq_enable(chip); chip->suspended = false; - queue_work(chip->fusb30x_wq, &chip->work); + kthread_queue_work(chip->irq_worker, &chip->irq_work); return 0; } diff --git a/drivers/mfd/fusb302.h b/drivers/mfd/fusb302.h index 3f40abfbd482..9b162f5d4246 100644 --- a/drivers/mfd/fusb302.h +++ b/drivers/mfd/fusb302.h @@ -482,8 +482,8 @@ struct fusb30x_chip { struct i2c_client *client; struct device *dev; struct regmap *regmap; - struct work_struct work; - struct workqueue_struct *fusb30x_wq; + struct kthread_work irq_work; + struct kthread_worker *irq_worker; struct hrtimer timer_state_machine; struct hrtimer timer_mux_machine; struct PD_CAP_INFO pd_cap_info; @@ -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