From: "Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>
To: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Cc: Sebastian Reichel <sre@kernel.org>, Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Bjorn Andersson <andersson@kernel.org>,
Hans de Goede <hdegoede@redhat.com>,
Bryan O'Donoghue <bryan.odonoghue@linaro.org>,
Heikki Krogerus <heikki.krogerus@linux.intel.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Konrad Dybcio <konrad.dybcio@linaro.org>,
linux-pm@vger.kernel.org, devicetree@vger.kernel.org,
LKML <linux-kernel@vger.kernel.org>,
platform-driver-x86@vger.kernel.org, linux-usb@vger.kernel.org,
linux-arm-msm@vger.kernel.org, Nikita Travkin <nikita@trvn.ru>
Subject: Re: [PATCH v6 3/6] usb: typec: ucsi: add Lenovo Yoga C630 glue driver
Date: Thu, 13 Jun 2024 10:30:23 +0300 (EEST) [thread overview]
Message-ID: <c8c81617-4391-2c4c-1009-4a8a667a14dc@linux.intel.com> (raw)
In-Reply-To: <20240612-yoga-ec-driver-v6-3-8e76ba060439@linaro.org>
On Wed, 12 Jun 2024, Dmitry Baryshkov wrote:
> The Lenovo Yoga C630 WOS laptop provides implements UCSI interface in
> the onboard EC. Add glue driver to interface the platform's UCSI
> implementation.
>
> Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
> +static int yoga_c630_ucsi_read(struct ucsi *ucsi, unsigned int offset,
> + void *val, size_t val_len)
> +{
> + struct yoga_c630_ucsi *uec = ucsi_get_drvdata(ucsi);
> + u8 buf[YOGA_C630_UCSI_READ_SIZE];
> + int ret;
> +
> + ret = yoga_c630_ec_ucsi_read(uec->ec, buf);
> + if (ret)
> + return ret;
> +
> + if (offset == UCSI_VERSION) {
> + memcpy(val, &uec->version, min(val_len, sizeof(uec->version)));
> + return 0;
> + }
> +
> + if (offset == UCSI_CCI)
> + memcpy(val, buf, min(val_len, YOGA_C630_UCSI_CCI_SIZE));
> + else if (offset == UCSI_MESSAGE_IN)
> + memcpy(val, buf + YOGA_C630_UCSI_CCI_SIZE,
> + min(val_len, YOGA_C630_UCSI_DATA_SIZE));
> + else
> + return -EINVAL;
> +
> + return 0;
Hmm, the inconsistency when to do return 0 is a bit odd. Also, using
switch (offset) would probably be better here anyway to replace all the
ifs.
> +}
> +
> +static int yoga_c630_ucsi_async_write(struct ucsi *ucsi, unsigned int offset,
> + const void *val, size_t val_len)
> +{
> + struct yoga_c630_ucsi *uec = ucsi_get_drvdata(ucsi);
> +
> + if (offset != UCSI_CONTROL ||
> + val_len != YOGA_C630_UCSI_WRITE_SIZE)
> + return -EINVAL;
> +
> + return yoga_c630_ec_ucsi_write(uec->ec, val);
> +}
> +
> +static int yoga_c630_ucsi_sync_write(struct ucsi *ucsi, unsigned int offset,
> + const void *val, size_t val_len)
> +{
> + struct yoga_c630_ucsi *uec = ucsi_get_drvdata(ucsi);
> + bool ack = UCSI_COMMAND(*(u64 *)val) == UCSI_ACK_CC_CI;
> + int ret;
> +
> + if (ack)
> + set_bit(UCSI_C630_ACK_PENDING, &uec->flags);
> + else
> + set_bit(UCSI_C630_COMMAND_PENDING, &uec->flags);
> +
> + reinit_completion(&uec->complete);
> +
> + ret = yoga_c630_ucsi_async_write(ucsi, offset, val, val_len);
> + if (ret)
> + goto out_clear_bit;
> +
> + if (!wait_for_completion_timeout(&uec->complete, 5 * HZ))
> + ret = -ETIMEDOUT;
> +
> +out_clear_bit:
> + if (ack)
> + clear_bit(UCSI_C630_ACK_PENDING, &uec->flags);
> + else
> + clear_bit(UCSI_C630_COMMAND_PENDING, &uec->flags);
> +
> + return ret;
> +}
> +
> +const struct ucsi_operations yoga_c630_ucsi_ops = {
> + .read = yoga_c630_ucsi_read,
> + .sync_write = yoga_c630_ucsi_sync_write,
> + .async_write = yoga_c630_ucsi_async_write,
> +};
> +
> +static void yoga_c630_ucsi_notify_ucsi(struct yoga_c630_ucsi *uec, u32 cci)
> +{
> + if (UCSI_CCI_CONNECTOR(cci))
> + ucsi_connector_change(uec->ucsi, UCSI_CCI_CONNECTOR(cci));
> +
> + if (cci & UCSI_CCI_ACK_COMPLETE &&
> + test_bit(UCSI_C630_ACK_PENDING, &uec->flags))
> + complete(&uec->complete);
> +
> + if (cci & UCSI_CCI_COMMAND_COMPLETE &&
> + test_bit(UCSI_C630_COMMAND_PENDING, &uec->flags))
> + complete(&uec->complete);
Is this racy? Can another command start after an ACK in between these two
ifs and complete() is called prematurely for the new command? (Or will
different value in cci protect against that?)
> +}
> +
> +static int yoga_c630_ucsi_notify(struct notifier_block *nb,
> + unsigned long action, void *data)
> +{
> + struct yoga_c630_ucsi *uec = container_of(nb, struct yoga_c630_ucsi, nb);
> + u32 cci;
> + int ret;
> +
> + switch (action) {
> + case LENOVO_EC_EVENT_USB:
> + case LENOVO_EC_EVENT_HPD:
> + ucsi_connector_change(uec->ucsi, 1);
> + return NOTIFY_OK;
> +
> + case LENOVO_EC_EVENT_UCSI:
> + ret = uec->ucsi->ops->read(uec->ucsi, UCSI_CCI, &cci, sizeof(cci));
> + if (ret)
> + return NOTIFY_DONE;
> +
> + yoga_c630_ucsi_notify_ucsi(uec, cci);
> +
> + return NOTIFY_OK;
> +
> + default:
> + return NOTIFY_DONE;
> + }
> +}
> +
> +static int yoga_c630_ucsi_probe(struct auxiliary_device *adev,
> + const struct auxiliary_device_id *id)
> +{
> + struct yoga_c630_ec *ec = adev->dev.platform_data;
> + struct yoga_c630_ucsi *uec;
> + int ret;
> +
> + uec = devm_kzalloc(&adev->dev, sizeof(*uec), GFP_KERNEL);
> + if (!uec)
> + return -ENOMEM;
> +
> + uec->ec = ec;
> + init_completion(&uec->complete);
> + uec->nb.notifier_call = yoga_c630_ucsi_notify;
> +
> + uec->ucsi = ucsi_create(&adev->dev, &yoga_c630_ucsi_ops);
> + if (IS_ERR(uec->ucsi))
> + return PTR_ERR(uec->ucsi);
> +
> + ucsi_set_drvdata(uec->ucsi, uec);
> +
> + uec->version = yoga_c630_ec_ucsi_get_version(uec->ec);
> +
> + auxiliary_set_drvdata(adev, uec);
> +
> + ret = yoga_c630_ec_register_notify(ec, &uec->nb);
> + if (ret)
> + return ret;
> +
> + return ucsi_register(uec->ucsi);
> +}
> +
> +static void yoga_c630_ucsi_remove(struct auxiliary_device *adev)
> +{
> + struct yoga_c630_ucsi *uec = auxiliary_get_drvdata(adev);
> +
> + yoga_c630_ec_unregister_notify(uec->ec, &uec->nb);
> + ucsi_unregister(uec->ucsi);
Usually, the remove should tear down in reverse order than the probe side.
Is the divergence from that here intentional?
--
i.
next prev parent reply other threads:[~2024-06-13 7:30 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-06-12 9:59 [PATCH v6 0/6] power: supply: Lenovo Yoga C630 EC Dmitry Baryshkov
2024-06-12 9:59 ` [PATCH v6 1/6] dt-bindings: platform: Add " Dmitry Baryshkov
2024-06-12 9:59 ` [PATCH v6 2/6] platform: arm64: add Lenovo Yoga C630 WOS EC driver Dmitry Baryshkov
2024-06-12 9:59 ` [PATCH v6 3/6] usb: typec: ucsi: add Lenovo Yoga C630 glue driver Dmitry Baryshkov
2024-06-13 7:30 ` Ilpo Järvinen [this message]
2024-06-13 8:26 ` Dmitry Baryshkov
2024-06-12 9:59 ` [PATCH v6 4/6] power: supply: lenovo_yoga_c630_battery: add Lenovo C630 driver Dmitry Baryshkov
2024-06-13 7:57 ` Ilpo Järvinen
2024-06-14 1:47 ` Sebastian Reichel
2024-06-14 1:35 ` Sebastian Reichel
2024-06-14 10:24 ` Dmitry Baryshkov
2024-06-12 9:59 ` [PATCH v6 5/6] arm64: dts: qcom: sdm845: describe connections of USB/DP port Dmitry Baryshkov
2024-06-12 9:59 ` [PATCH v6 6/6] arm64: dts: qcom: c630: Add Embedded Controller node Dmitry Baryshkov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=c8c81617-4391-2c4c-1009-4a8a667a14dc@linux.intel.com \
--to=ilpo.jarvinen@linux.intel.com \
--cc=andersson@kernel.org \
--cc=bryan.odonoghue@linaro.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=dmitry.baryshkov@linaro.org \
--cc=gregkh@linuxfoundation.org \
--cc=hdegoede@redhat.com \
--cc=heikki.krogerus@linux.intel.com \
--cc=konrad.dybcio@linaro.org \
--cc=krzk+dt@kernel.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=nikita@trvn.ru \
--cc=platform-driver-x86@vger.kernel.org \
--cc=robh@kernel.org \
--cc=sre@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox