usb: typec: ucsi: acpi: Move to the new API
Replacing the old "cmd" and "sync" callbacks with an implementation of struct ucsi_operations. The ACPI notification (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. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Link: https://lore.kernel.org/r/20191104142435.29960-13-heikki.krogerus@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
bdc62f2bae
commit
f56de278e8
@ -19,7 +19,9 @@
|
|||||||
struct ucsi_acpi {
|
struct ucsi_acpi {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct ucsi *ucsi;
|
struct ucsi *ucsi;
|
||||||
struct ucsi_ppm ppm;
|
void __iomem *base;
|
||||||
|
struct completion complete;
|
||||||
|
unsigned long flags;
|
||||||
guid_t guid;
|
guid_t guid;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -39,27 +41,73 @@ static int ucsi_acpi_dsm(struct ucsi_acpi *ua, int func)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ucsi_acpi_cmd(struct ucsi_ppm *ppm, struct ucsi_control *ctrl)
|
static int ucsi_acpi_read(struct ucsi *ucsi, unsigned int offset,
|
||||||
|
void *val, size_t val_len)
|
||||||
{
|
{
|
||||||
struct ucsi_acpi *ua = container_of(ppm, struct ucsi_acpi, ppm);
|
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
|
||||||
|
int ret;
|
||||||
|
|
||||||
ppm->data->ctrl.raw_cmd = ctrl->raw_cmd;
|
ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
memcpy(val, (const void __force *)(ua->base + offset), val_len);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ucsi_acpi_async_write(struct ucsi *ucsi, unsigned int offset,
|
||||||
|
const void *val, size_t val_len)
|
||||||
|
{
|
||||||
|
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
|
||||||
|
|
||||||
|
memcpy((void __force *)(ua->base + offset), val, val_len);
|
||||||
|
|
||||||
return ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_WRITE);
|
return ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_WRITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ucsi_acpi_sync(struct ucsi_ppm *ppm)
|
static int ucsi_acpi_sync_write(struct ucsi *ucsi, unsigned int offset,
|
||||||
|
const void *val, size_t val_len)
|
||||||
{
|
{
|
||||||
struct ucsi_acpi *ua = container_of(ppm, struct ucsi_acpi, ppm);
|
struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi);
|
||||||
|
int ret;
|
||||||
|
|
||||||
return ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ);
|
set_bit(COMMAND_PENDING, &ua->flags);
|
||||||
|
|
||||||
|
ret = ucsi_acpi_async_write(ucsi, offset, val, val_len);
|
||||||
|
if (ret)
|
||||||
|
goto out_clear_bit;
|
||||||
|
|
||||||
|
if (!wait_for_completion_timeout(&ua->complete, msecs_to_jiffies(5000)))
|
||||||
|
ret = -ETIMEDOUT;
|
||||||
|
|
||||||
|
out_clear_bit:
|
||||||
|
clear_bit(COMMAND_PENDING, &ua->flags);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct ucsi_operations ucsi_acpi_ops = {
|
||||||
|
.read = ucsi_acpi_read,
|
||||||
|
.sync_write = ucsi_acpi_sync_write,
|
||||||
|
.async_write = ucsi_acpi_async_write
|
||||||
|
};
|
||||||
|
|
||||||
static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data)
|
static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data)
|
||||||
{
|
{
|
||||||
struct ucsi_acpi *ua = data;
|
struct ucsi_acpi *ua = data;
|
||||||
|
u32 cci;
|
||||||
|
int ret;
|
||||||
|
|
||||||
ucsi_notify(ua->ucsi);
|
ret = ucsi_acpi_read(ua->ucsi, UCSI_CCI, &cci, sizeof(cci));
|
||||||
|
if (ret)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (test_bit(COMMAND_PENDING, &ua->flags) &&
|
||||||
|
cci & (UCSI_CCI_ACK_COMPLETE | UCSI_CCI_COMMAND_COMPLETE))
|
||||||
|
complete(&ua->complete);
|
||||||
|
else if (UCSI_CCI_CONNECTOR(cci))
|
||||||
|
ucsi_connector_change(ua->ucsi, UCSI_CCI_CONNECTOR(cci));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ucsi_acpi_probe(struct platform_device *pdev)
|
static int ucsi_acpi_probe(struct platform_device *pdev)
|
||||||
@ -90,35 +138,39 @@ static int ucsi_acpi_probe(struct platform_device *pdev)
|
|||||||
* it can not be requested here, and we can not use
|
* it can not be requested here, and we can not use
|
||||||
* devm_ioremap_resource().
|
* devm_ioremap_resource().
|
||||||
*/
|
*/
|
||||||
ua->ppm.data = devm_ioremap(&pdev->dev, res->start, resource_size(res));
|
ua->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
|
||||||
if (!ua->ppm.data)
|
if (!ua->base)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (!ua->ppm.data->version)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
ret = guid_parse(UCSI_DSM_UUID, &ua->guid);
|
ret = guid_parse(UCSI_DSM_UUID, &ua->guid);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ua->ppm.cmd = ucsi_acpi_cmd;
|
init_completion(&ua->complete);
|
||||||
ua->ppm.sync = ucsi_acpi_sync;
|
|
||||||
ua->dev = &pdev->dev;
|
ua->dev = &pdev->dev;
|
||||||
|
|
||||||
|
ua->ucsi = ucsi_create(&pdev->dev, &ucsi_acpi_ops);
|
||||||
|
if (IS_ERR(ua->ucsi))
|
||||||
|
return PTR_ERR(ua->ucsi);
|
||||||
|
|
||||||
|
ucsi_set_drvdata(ua->ucsi, ua);
|
||||||
|
|
||||||
status = acpi_install_notify_handler(ACPI_HANDLE(&pdev->dev),
|
status = acpi_install_notify_handler(ACPI_HANDLE(&pdev->dev),
|
||||||
ACPI_DEVICE_NOTIFY,
|
ACPI_DEVICE_NOTIFY,
|
||||||
ucsi_acpi_notify, ua);
|
ucsi_acpi_notify, ua);
|
||||||
if (ACPI_FAILURE(status)) {
|
if (ACPI_FAILURE(status)) {
|
||||||
dev_err(&pdev->dev, "failed to install notify handler\n");
|
dev_err(&pdev->dev, "failed to install notify handler\n");
|
||||||
|
ucsi_destroy(ua->ucsi);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
ua->ucsi = ucsi_register_ppm(&pdev->dev, &ua->ppm);
|
ret = ucsi_register(ua->ucsi);
|
||||||
if (IS_ERR(ua->ucsi)) {
|
if (ret) {
|
||||||
acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev),
|
acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev),
|
||||||
ACPI_DEVICE_NOTIFY,
|
ACPI_DEVICE_NOTIFY,
|
||||||
ucsi_acpi_notify);
|
ucsi_acpi_notify);
|
||||||
return PTR_ERR(ua->ucsi);
|
ucsi_destroy(ua->ucsi);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
platform_set_drvdata(pdev, ua);
|
platform_set_drvdata(pdev, ua);
|
||||||
@ -130,7 +182,8 @@ static int ucsi_acpi_remove(struct platform_device *pdev)
|
|||||||
{
|
{
|
||||||
struct ucsi_acpi *ua = platform_get_drvdata(pdev);
|
struct ucsi_acpi *ua = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
ucsi_unregister_ppm(ua->ucsi);
|
ucsi_unregister(ua->ucsi);
|
||||||
|
ucsi_destroy(ua->ucsi);
|
||||||
|
|
||||||
acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), ACPI_DEVICE_NOTIFY,
|
acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), ACPI_DEVICE_NOTIFY,
|
||||||
ucsi_acpi_notify);
|
ucsi_acpi_notify);
|
||||||
|
Loading…
Reference in New Issue
Block a user