oh_cnt = of_property_count_strings(node, "ti,hwmods"); if (oh_cnt <= 0) {
dev_dbg(&pdev->dev, "No 'hwmods' to build omap_device\n"); return -ENODEV;
}
/* SDMA still needs special handling for omap_device_build() */
ret = of_property_read_string_index(node, "ti,hwmods", 0, &oh_name); if (!ret && (!strncmp("dma_system", oh_name, 10) ||
!strncmp("dma", oh_name, 3)))
skip_pm_domain = true;
/* Use ti-sysc driver instead of omap_device? */ if (!skip_pm_domain &&
!omap_hwmod_parse_module_range(NULL, node, &res)) return -ENODEV;
hwmods = kcalloc(oh_cnt, sizeof(struct omap_hwmod *), GFP_KERNEL); if (!hwmods) {
ret = -ENOMEM; goto odbfd_exit;
}
for (i = 0; i < oh_cnt; i++) {
of_property_read_string_index(node, "ti,hwmods", i, &oh_name);
oh = omap_hwmod_lookup(oh_name); if (!oh) {
dev_err(&pdev->dev, "Cannot lookup hwmod '%s'\n",
oh_name);
ret = -EINVAL; goto odbfd_exit1;
}
hwmods[i] = oh; if (oh->flags & HWMOD_INIT_NO_IDLE)
device_active = true;
}
od = omap_device_alloc(pdev, hwmods, oh_cnt); if (IS_ERR(od)) {
dev_err(&pdev->dev, "Cannot allocate omap_device for :%s\n",
oh_name);
ret = PTR_ERR(od); goto odbfd_exit1;
}
/* Fix up missing resource names */ for (i = 0; i < pdev->num_resources; i++) { struct resource *r = &pdev->resource[i];
if (r->name == NULL)
r->name = dev_name(&pdev->dev);
}
if (!skip_pm_domain) {
dev_pm_domain_set(&pdev->dev, &omap_device_pm_domain); if (device_active) {
omap_device_enable(pdev);
pm_runtime_set_active(&pdev->dev);
}
}
odbfd_exit1:
kfree(hwmods);
odbfd_exit: /* if data/we are at fault.. load up a fail handler */ if (ret)
dev_pm_domain_set(&pdev->dev, &omap_device_fail_pm_domain);
switch (event) { case BUS_NOTIFY_REMOVED_DEVICE: if (pdev->archdata.od)
omap_device_delete(pdev->archdata.od); break; case BUS_NOTIFY_UNBOUND_DRIVER:
od = to_omap_device(pdev); if (od && (od->_state == OMAP_DEVICE_STATE_ENABLED)) {
dev_info(dev, "enabled after unload, idling\n");
err = omap_device_idle(pdev); if (err)
dev_err(dev, "failed to idle\n");
} break; case BUS_NOTIFY_BIND_DRIVER:
od = to_omap_device(pdev); if (od) {
od->_driver_status = BUS_NOTIFY_BIND_DRIVER; if (od->_state == OMAP_DEVICE_STATE_ENABLED &&
pm_runtime_status_suspended(dev)) {
pm_runtime_set_active(dev);
}
} break; case BUS_NOTIFY_ADD_DEVICE: if (pdev->dev.of_node)
omap_device_build_from_dt(pdev);
fallthrough; default:
od = to_omap_device(pdev); if (od)
od->_driver_status = event;
}
return NOTIFY_DONE;
}
/** *_omap_device_enable_hwmods-callomap_hwmod_enable()onallhwmods *@od:structomap_device*od * *Enableallunderlyinghwmods.Returns0.
*/ staticint _omap_device_enable_hwmods(struct omap_device *od)
{ int ret = 0; int i;
for (i = 0; i < od->hwmods_cnt; i++)
ret |= omap_hwmod_enable(od->hwmods[i]);
return ret;
}
/** *_omap_device_idle_hwmods-callomap_hwmod_idle()onallhwmods *@od:structomap_device*od * *Idleallunderlyinghwmods.Returns0.
*/ staticint _omap_device_idle_hwmods(struct omap_device *od)
{ int ret = 0; int i;
for (i = 0; i < od->hwmods_cnt; i++)
ret |= omap_hwmod_idle(od->hwmods[i]);
return ret;
}
/* Public functions for use by core code */
/** *omap_device_alloc-allocateanomap_device *@pdev:platform_devicethatwillbeincludedinthisomap_device *@ohs:ptrtotheomap_hwmodforthisomap_device *@oh_cnt:thesizeoftheohslist * *Conveniencefunctionforallocatinganomap_devicestructureandfilling *hwmods,andresources. * *Returnsanstructomap_devicepointerorERR_PTR()onerror;
*/ staticstruct omap_device *omap_device_alloc(struct platform_device *pdev, struct omap_hwmod **ohs, int oh_cnt)
{ int ret = -ENOMEM; struct omap_device *od; int i; struct omap_hwmod **hwmods;
od = kzalloc(sizeof(struct omap_device), GFP_KERNEL); if (!od) goto oda_exit1;
od->hwmods_cnt = oh_cnt;
hwmods = kmemdup_array(ohs, oh_cnt, sizeof(*hwmods), GFP_KERNEL); if (!hwmods) goto oda_exit2;
if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
dev_warn(&pdev->dev, "omap_device: %s() called from invalid state %d\n",
__func__, od->_state); return -EINVAL;
}
ret = _omap_device_enable_hwmods(od);
if (ret == 0)
od->_state = OMAP_DEVICE_STATE_ENABLED;
return ret;
}
/** *omap_device_idle-idleanomap_device *@pdev:Theplatform_device(omap_device)toidle * *Idleomap_device@od.Devicedriverscallthisfunctionindirectly *viapm_runtime_put*().Returns-EINVALiftheomap_deviceisnot *currentlyenabled,orpassesalongthereturnvalueof *_omap_device_idle_hwmods().
*/ int omap_device_idle(struct platform_device *pdev)
{ int ret; struct omap_device *od;
od = to_omap_device(pdev);
if (od->_state != OMAP_DEVICE_STATE_ENABLED) {
dev_warn(&pdev->dev, "omap_device: %s() called from invalid state %d\n",
__func__, od->_state); return -EINVAL;
}
ret = _omap_device_idle_hwmods(od);
if (ret == 0)
od->_state = OMAP_DEVICE_STATE_IDLE;
return ret;
}
/** *omap_device_assert_hardreset-setadevice'shardresetline *@pdev:structplatform_device*toreset *@name:constchar*nameoftheresetline * *Setthehardresetlineidentifiedby@nameontheIPblocks *associatedwiththehwmodsbackingtheplatform_device@pdev.All *ofthehwmodsassociatedwith@pdevmusthavethesamehardreset *linelinkedtothemforthistowork.Passesalongthereturnvalue *ofomap_hwmod_assert_hardreset()intheeventofanyfailure,or *returns0uponsuccess.
*/ int omap_device_assert_hardreset(struct platform_device *pdev, constchar *name)
{ struct omap_device *od = to_omap_device(pdev); int ret = 0; int i;
for (i = 0; i < od->hwmods_cnt; i++) {
ret = omap_hwmod_assert_hardreset(od->hwmods[i], name); if (ret) break;
}
return ret;
}
/** *omap_device_deassert_hardreset-releaseadevice'shardresetline *@pdev:structplatform_device*toreset *@name:constchar*nameoftheresetline * *Releasethehardresetlineidentifiedby@nameontheIPblocks *associatedwiththehwmodsbackingtheplatform_device@pdev.All *ofthehwmodsassociatedwith@pdevmusthavethesamehardreset *linelinkedtothemforthistowork.Passesalongthereturn *valueofomap_hwmod_deassert_hardreset()intheeventofany *failure,orreturns0uponsuccess.
*/ int omap_device_deassert_hardreset(struct platform_device *pdev, constchar *name)
{ struct omap_device *od = to_omap_device(pdev); int ret = 0; int i;
for (i = 0; i < od->hwmods_cnt; i++) {
ret = omap_hwmod_deassert_hardreset(od->hwmods[i], name); if (ret) break;
}
/* *Somedevices(likememorycontrollers)arealwayskept *enabled,andshouldnotbeidledevenwithnodrivers.
*/ for (i = 0; i < od->hwmods_cnt; i++) if (od->hwmods[i]->flags & HWMOD_INIT_NO_IDLE) return0;
if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER &&
od->_driver_status != BUS_NOTIFY_BIND_DRIVER) { if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
dev_warn(dev, "%s: enabled but no driver. Idling\n",
__func__);
omap_device_idle(pdev);
}
}
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.