/* we don't use an IDA since we already have a link ID */
auxdev->id = link_id;
/* * keep a handle on the allocated memory, to be used in all other functions. * Since the same pattern is used to skip links that are not enabled, there is * no need to check if ctx->ldev[i] is NULL later on.
*/
ctx->ldev[link_id] = ldev;
/* now follow the two-step init/add sequence */
ret = auxiliary_device_init(auxdev); if (ret < 0) {
dev_err(res->parent, "failed to initialize link dev %s link_id %d\n",
name, link_id);
kfree(ldev); return ERR_PTR(ret);
}
ret = auxiliary_device_add(&ldev->auxdev); if (ret < 0) {
dev_err(res->parent, "failed to add link dev %s link_id %d\n",
ldev->auxdev.name, link_id); /* ldev will be freed with the put_device() and .release sequence */
auxiliary_device_uninit(&ldev->auxdev); return ERR_PTR(ret);
}
adev = acpi_fetch_acpi_dev(res->handle); if (!adev) return NULL;
if (!res->count) return NULL;
count = res->count;
dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count);
/* * we need to alloc/free memory manually and can't use devm: * this routine may be called from a workqueue, and not from * the parent .probe. * If devm_ was used, the memory might never be freed on errors.
*/
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return NULL;
ctx->count = count;
/* * allocate the array of pointers. The link-specific data is allocated * as part of the first loop below and released with the auxiliary_device_uninit(). * If some links are disabled, the link pointer will remain NULL. Given that the * number of links is small, this is simpler than using a list to keep track of links.
*/
ctx->ldev = kcalloc(ctx->count, sizeof(*ctx->ldev), GFP_KERNEL); if (!ctx->ldev) {
kfree(ctx); return NULL;
}
for (i = 0; i < count; i++) { if (!(link_mask & BIT(i))) continue;
/* * init and add a device for each link * * The name of the device will be soundwire_intel.link.[i], * with the "soundwire_intel" module prefix automatically added * by the auxiliary bus core.
*/
ldev = intel_link_dev_register(res,
ctx,
acpi_fwnode_handle(adev), "link",
i); if (IS_ERR(ldev)) goto err;
link = &ldev->link_res;
link->cdns = auxiliary_get_drvdata(&ldev->auxdev);
if (!link->cdns) {
dev_err(&adev->dev, "failed to get link->cdns\n"); /* * 1 will be subtracted from i in the err label, but we need to call * intel_link_dev_unregister for this ldev, so plus 1 now
*/
i++; goto err;
}
list_add_tail(&link->list, &ctx->link_list);
bus = &link->cdns->bus; /* Calculate number of slaves */
list_for_each(node, &bus->slaves)
num_slaves++;
}
/* Startup SDW Master devices */ for (i = 0; i < ctx->count; i++) { if (!(link_mask & BIT(i))) continue;
ldev = ctx->ldev[i];
intel_link_startup(&ldev->auxdev);
if (!ldev->link_res.clock_stop_quirks) { /* * we need to prevent the parent PCI device * from entering pm_runtime suspend, so that * power rails to the SoundWire IP are not * turned off.
*/
pm_runtime_get_noresume(ldev->link_res.dev);
}
}
return 0;
}
/** * sdw_intel_probe() - SoundWire Intel probe routine * @res: resource data * * This registers an auxiliary device for each Master handled by the controller, * and SoundWire Master and Slave devices will be created by the auxiliary * device probe. All the information necessary is stored in the context, and * the res argument pointer can be freed after this step. * This function will be called after sdw_intel_acpi_scan() by SOF probe.
*/ struct sdw_intel_ctx
*sdw_intel_probe(struct sdw_intel_res *res)
{ return sdw_intel_probe_controller(res);
}
EXPORT_SYMBOL_NS(sdw_intel_probe, "SOUNDWIRE_INTEL_INIT");
/** * sdw_intel_startup() - SoundWire Intel startup * @ctx: SoundWire context allocated in the probe * * Startup Intel SoundWire controller. This function will be called after * Intel Audio DSP is powered up.
*/ int sdw_intel_startup(struct sdw_intel_ctx *ctx)
{ return sdw_intel_startup_controller(ctx);
}
EXPORT_SYMBOL_NS(sdw_intel_startup, "SOUNDWIRE_INTEL_INIT"); /** * sdw_intel_exit() - SoundWire Intel exit * @ctx: SoundWire context allocated in the probe * * Delete the controller instances created and cleanup
*/ void sdw_intel_exit(struct sdw_intel_ctx *ctx)
{ struct sdw_intel_link_res *link;
/* we first resume links and devices and wait synchronously before the cleanup */
list_for_each_entry(link, &ctx->link_list, list) { struct sdw_bus *bus = &link->cdns->bus; int ret;
ret = device_for_each_child(bus->dev, NULL, intel_resume_child_device); if (ret < 0)
dev_err(bus->dev, "%s: intel_resume_child_device failed: %d\n",
__func__, ret);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.