Hi Heikki > -----Original Message----- > From: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx> > Sent: Wednesday, October 23, 2019 7:40 AM > To: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> > Cc: Guenter Roeck <linux@xxxxxxxxxxxx>; Ajay Gupta <ajayg@xxxxxxxxxx>; > linux-usb@xxxxxxxxxxxxxxx > Subject: [PATCH v2 13/18] usb: typec: ucsi: ccg: Move to the new API > > Replacing the old "cmd" and "sync" callbacks with an implementation of struct > ucsi_operations. The interrupt handler will from now on read the CCI > (Command Status and Connector Change Indication) register, and call > ucsi_connector_change() function and/or complete pending command > completions based on it. I have tested the entire set for ucsi_ccg controller on NVIDIA GPU. Tested-by: Ajay Gupta <ajayg@xxxxxxxxxx> thanks > nvpublic > > Signed-off-by: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx> > --- > drivers/usb/typec/ucsi/ucsi_ccg.c | 170 +++++++++++++++--------------- > 1 file changed, 85 insertions(+), 85 deletions(-) > > diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c > b/drivers/usb/typec/ucsi/ucsi_ccg.c > index d772fce51905..43442580a13c 100644 > --- a/drivers/usb/typec/ucsi/ucsi_ccg.c > +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c > @@ -176,8 +176,8 @@ struct ccg_resp { > struct ucsi_ccg { > struct device *dev; > struct ucsi *ucsi; > - struct ucsi_ppm ppm; > struct i2c_client *client; > + > struct ccg_dev_info info; > /* version info for boot, primary and secondary */ > struct version_info version[FW2 + 1]; > @@ -196,6 +196,8 @@ struct ucsi_ccg { > /* fw build with vendor information */ > u16 fw_build; > struct work_struct pm_work; > + > + struct completion complete; > }; > > static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len) @@ -243,7 > +245,7 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len) > return 0; > } > > -static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len) > +static int ccg_write(struct ucsi_ccg *uc, u16 rab, const u8 *data, u32 > +len) > { > struct i2c_client *client = uc->client; > unsigned char *buf; > @@ -317,88 +319,89 @@ static int ucsi_ccg_init(struct ucsi_ccg *uc) > return -ETIMEDOUT; > } > > -static int ucsi_ccg_send_data(struct ucsi_ccg *uc) > +static int ucsi_ccg_read(struct ucsi *ucsi, unsigned int offset, > + void *val, size_t val_len) > { > - u8 *ppm = (u8 *)uc->ppm.data; > - int status; > - u16 rab; > + u16 reg = CCGX_RAB_UCSI_DATA_BLOCK(offset); > > - rab = CCGX_RAB_UCSI_DATA_BLOCK(offsetof(struct ucsi_data, > message_out)); > - status = ccg_write(uc, rab, ppm + > - offsetof(struct ucsi_data, message_out), > - sizeof(uc->ppm.data->message_out)); > - if (status < 0) > - return status; > - > - rab = CCGX_RAB_UCSI_DATA_BLOCK(offsetof(struct ucsi_data, ctrl)); > - return ccg_write(uc, rab, ppm + offsetof(struct ucsi_data, ctrl), > - sizeof(uc->ppm.data->ctrl)); > + return ccg_read(ucsi_get_drvdata(ucsi), reg, val, val_len); > } > > -static int ucsi_ccg_recv_data(struct ucsi_ccg *uc) > +static int ucsi_ccg_async_write(struct ucsi *ucsi, unsigned int offset, > + const void *val, size_t val_len) > { > - u8 *ppm = (u8 *)uc->ppm.data; > - int status; > - u16 rab; > + u16 reg = CCGX_RAB_UCSI_DATA_BLOCK(offset); > > - rab = CCGX_RAB_UCSI_DATA_BLOCK(offsetof(struct ucsi_data, cci)); > - status = ccg_read(uc, rab, ppm + offsetof(struct ucsi_data, cci), > - sizeof(uc->ppm.data->cci)); > - if (status < 0) > - return status; > - > - rab = CCGX_RAB_UCSI_DATA_BLOCK(offsetof(struct ucsi_data, > message_in)); > - return ccg_read(uc, rab, ppm + offsetof(struct ucsi_data, message_in), > - sizeof(uc->ppm.data->message_in)); > + return ccg_write(ucsi_get_drvdata(ucsi), reg, val, val_len); > } > > -static int ucsi_ccg_ack_interrupt(struct ucsi_ccg *uc) > +static int ucsi_ccg_sync_write(struct ucsi *ucsi, unsigned int offset, > + const void *val, size_t val_len) > { > - int status; > - unsigned char data; > + struct ucsi_ccg *uc = ucsi_get_drvdata(ucsi); > + int ret; > > - status = ccg_read(uc, CCGX_RAB_INTR_REG, &data, sizeof(data)); > - if (status < 0) > - return status; > + mutex_lock(&uc->lock); > + pm_runtime_get_sync(uc->dev); > + set_bit(DEV_CMD_PENDING, &uc->flags); > > - return ccg_write(uc, CCGX_RAB_INTR_REG, &data, sizeof(data)); > -} > + ret = ucsi_ccg_async_write(ucsi, offset, val, val_len); > + if (ret) > + goto err_clear_bit; > > -static int ucsi_ccg_sync(struct ucsi_ppm *ppm) -{ > - struct ucsi_ccg *uc = container_of(ppm, struct ucsi_ccg, ppm); > - int status; > + if (!wait_for_completion_timeout(&uc->complete, > msecs_to_jiffies(5000))) > + ret = -ETIMEDOUT; > > - status = ucsi_ccg_recv_data(uc); > - if (status < 0) > - return status; > +err_clear_bit: > + clear_bit(DEV_CMD_PENDING, &uc->flags); > + pm_runtime_put_sync(uc->dev); > + mutex_unlock(&uc->lock); > > - /* ack interrupt to allow next command to run */ > - return ucsi_ccg_ack_interrupt(uc); > + return ret; > } > > -static int ucsi_ccg_cmd(struct ucsi_ppm *ppm, struct ucsi_control *ctrl) -{ > - struct ucsi_ccg *uc = container_of(ppm, struct ucsi_ccg, ppm); > - > - ppm->data->ctrl.raw_cmd = ctrl->raw_cmd; > - return ucsi_ccg_send_data(uc); > -} > +static const struct ucsi_operations ucsi_ccg_ops = { > + .read = ucsi_ccg_read, > + .sync_write = ucsi_ccg_sync_write, > + .async_write = ucsi_ccg_async_write > +}; > > static irqreturn_t ccg_irq_handler(int irq, void *data) { > + u16 reg = CCGX_RAB_UCSI_DATA_BLOCK(UCSI_CCI); > struct ucsi_ccg *uc = data; > + u8 intr_reg; > + u32 cci; > + int ret; > + > + ret = ccg_read(uc, CCGX_RAB_INTR_REG, &intr_reg, sizeof(intr_reg)); > + if (ret) > + return ret; > + > + ret = ccg_read(uc, reg, (void *)&cci, sizeof(cci)); > + if (ret) { > + dev_err(uc->dev, "failed to read CCI\n"); > + goto err_clear_irq; > + } > + > + if (UCSI_CCI_CONNECTOR(cci)) > + ucsi_connector_change(uc->ucsi, UCSI_CCI_CONNECTOR(cci)); > > - ucsi_notify(uc->ucsi); > + if (test_bit(DEV_CMD_PENDING, &uc->flags) && > + cci & (UCSI_CCI_ACK_COMPLETE | > UCSI_CCI_COMMAND_COMPLETE)) > + complete(&uc->complete); > + > +err_clear_irq: > + ret = ccg_write(uc, CCGX_RAB_INTR_REG, &intr_reg, sizeof(intr_reg)); > + if (ret) > + dev_err(uc->dev, "failed to clear interrupt\n"); > > return IRQ_HANDLED; > } > > static void ccg_pm_workaround_work(struct work_struct *pm_work) { > - struct ucsi_ccg *uc = container_of(pm_work, struct ucsi_ccg, > pm_work); > - > - ucsi_notify(uc->ucsi); > + ccg_irq_handler(0, container_of(pm_work, struct ucsi_ccg, > pm_work)); > } > > static int get_fw_info(struct ucsi_ccg *uc) @@ -1027,10 +1030,10 @@ static > int ccg_restart(struct ucsi_ccg *uc) > return status; > } > > - uc->ucsi = ucsi_register_ppm(dev, &uc->ppm); > - if (IS_ERR(uc->ucsi)) { > - dev_err(uc->dev, "ucsi_register_ppm failed\n"); > - return PTR_ERR(uc->ucsi); > + status = ucsi_register(uc->ucsi); > + if (status) { > + dev_err(uc->dev, "failed to register the interface\n"); > + return status; > } > > return 0; > @@ -1047,7 +1050,7 @@ static void ccg_update_firmware(struct work_struct > *work) > return; > > if (flash_mode != FLASH_NOT_NEEDED) { > - ucsi_unregister_ppm(uc->ucsi); > + ucsi_unregister(uc->ucsi); > free_irq(uc->irq, uc); > > ccg_fw_update(uc, flash_mode); > @@ -1091,21 +1094,15 @@ static int ucsi_ccg_probe(struct i2c_client *client, > struct device *dev = &client->dev; > struct ucsi_ccg *uc; > int status; > - u16 rab; > > uc = devm_kzalloc(dev, sizeof(*uc), GFP_KERNEL); > if (!uc) > return -ENOMEM; > > - uc->ppm.data = devm_kzalloc(dev, sizeof(struct ucsi_data), > GFP_KERNEL); > - if (!uc->ppm.data) > - return -ENOMEM; > - > - uc->ppm.cmd = ucsi_ccg_cmd; > - uc->ppm.sync = ucsi_ccg_sync; > uc->dev = dev; > uc->client = client; > mutex_init(&uc->lock); > + init_completion(&uc->complete); > INIT_WORK(&uc->work, ccg_update_firmware); > INIT_WORK(&uc->pm_work, ccg_pm_workaround_work); > > @@ -1133,30 +1130,25 @@ static int ucsi_ccg_probe(struct i2c_client *client, > if (uc->info.mode & CCG_DEVINFO_PDPORTS_MASK) > uc->port_num++; > > + uc->ucsi = ucsi_create(dev, &ucsi_ccg_ops); > + if (IS_ERR(uc->ucsi)) > + return PTR_ERR(uc->ucsi); > + > + ucsi_set_drvdata(uc->ucsi, uc); > + > status = request_threaded_irq(client->irq, NULL, ccg_irq_handler, > IRQF_ONESHOT | IRQF_TRIGGER_HIGH, > dev_name(dev), uc); > if (status < 0) { > dev_err(uc->dev, "request_threaded_irq failed - %d\n", > status); > - return status; > + goto out_ucsi_destroy; > } > > uc->irq = client->irq; > > - uc->ucsi = ucsi_register_ppm(dev, &uc->ppm); > - if (IS_ERR(uc->ucsi)) { > - dev_err(uc->dev, "ucsi_register_ppm failed\n"); > - return PTR_ERR(uc->ucsi); > - } > - > - rab = CCGX_RAB_UCSI_DATA_BLOCK(offsetof(struct ucsi_data, > version)); > - status = ccg_read(uc, rab, (u8 *)(uc->ppm.data) + > - offsetof(struct ucsi_data, version), > - sizeof(uc->ppm.data->version)); > - if (status < 0) { > - ucsi_unregister_ppm(uc->ucsi); > - return status; > - } > + status = ucsi_register(uc->ucsi); > + if (status) > + goto out_free_irq; > > i2c_set_clientdata(client, uc); > > @@ -1167,6 +1159,13 @@ static int ucsi_ccg_probe(struct i2c_client *client, > pm_runtime_idle(uc->dev); > > return 0; > + > +out_free_irq: > + free_irq(uc->irq, uc); > +out_ucsi_destroy: > + ucsi_destroy(uc->ucsi); > + > + return status; > } > > static int ucsi_ccg_remove(struct i2c_client *client) @@ -1175,8 +1174,9 @@ > static int ucsi_ccg_remove(struct i2c_client *client) > > cancel_work_sync(&uc->pm_work); > cancel_work_sync(&uc->work); > - ucsi_unregister_ppm(uc->ucsi); > pm_runtime_disable(uc->dev); > + ucsi_unregister(uc->ucsi); > + ucsi_destroy(uc->ucsi); > free_irq(uc->irq, uc); > > return 0; > -- > 2.23.0