/** * omap_device_build_ss - build and register an omap_device with multiple hwmods * @pdev_name: name of the platform_device driver to use * @pdev_id: this platform_device's connection ID * @oh: ptr to the single omap_hwmod that backs this omap_device * @pdata: platform_data ptr to associate with the platform_device * @pdata_len: amount of memory pointed to by @pdata * @pm_lats: pointer to a omap_device_pm_latency array for this device * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats * @is_early_device: should the device be registered as an early device or not * * Convenience function for building and registering an omap_device * subsystem record. Subsystem records consist of multiple * omap_hwmods. This function in turn builds and registers a * platform_device record. Returns an ERR_PTR() on error, or passes * along the return value of omap_device_register(). */ struct omap_device *omap_device_build_ss(const char *pdev_name, int pdev_id, struct omap_hwmod **ohs, int oh_cnt, void *pdata, int pdata_len, struct omap_device_pm_latency *pm_lats, int pm_lats_cnt, int is_early_device) { int ret = -ENOMEM; struct omap_device *od; char *pdev_name2; struct resource *res = NULL; int i, res_count; struct omap_hwmod **hwmods; if (!ohs || oh_cnt == 0 || !pdev_name) return ERR_PTR(-EINVAL); if (!pdata && pdata_len > 0) return ERR_PTR(-EINVAL); pr_debug("omap_device: %s: building with %d hwmods\n", pdev_name, oh_cnt); od = kzalloc(sizeof(struct omap_device), GFP_KERNEL); if (!od) return ERR_PTR(-ENOMEM); od->hwmods_cnt = oh_cnt; hwmods = kzalloc(sizeof(struct omap_hwmod *) * oh_cnt, GFP_KERNEL); if (!hwmods) goto odbs_exit1; memcpy(hwmods, ohs, sizeof(struct omap_hwmod *) * oh_cnt); od->hwmods = hwmods; pdev_name2 = kzalloc(strlen(pdev_name) + 1, GFP_KERNEL); if (!pdev_name2) goto odbs_exit2; strcpy(pdev_name2, pdev_name); od->pdev.name = pdev_name2; od->pdev.id = pdev_id; res_count = omap_device_count_resources(od); if (res_count > 0) { res = kzalloc(sizeof(struct resource) * res_count, GFP_KERNEL); if (!res) goto odbs_exit3; } omap_device_fill_resources(od, res); od->pdev.num_resources = res_count; od->pdev.resource = res; ret = platform_device_add_data(&od->pdev, pdata, pdata_len); if (ret) goto odbs_exit4; od->pm_lats = pm_lats; od->pm_lats_cnt = pm_lats_cnt; if (is_early_device) ret = omap_early_device_register(od); else ret = omap_device_register(od); for (i = 0; i < oh_cnt; i++) { hwmods[i]->od = od; _add_optional_clock_clkdev(od, hwmods[i]); } if (ret) goto odbs_exit4; return od; odbs_exit4: kfree(res); odbs_exit3: kfree(pdev_name2); odbs_exit2: kfree(hwmods); odbs_exit1: kfree(od); pr_err("omap_device: %s: build failed (%d)\n", pdev_name, ret); return ERR_PTR(ret); }
/** * omap_device_fixup_resources - Fix platform device resources * @od: struct omap_device * * * Fixup the platform device resources so that the resources * from the hwmods are included for. */ static int omap_device_fixup_resources(struct omap_device *od) { struct platform_device *pdev = od->pdev; int i, j, ret, res_count; struct resource *res, *r, *rnew, *rn; unsigned long type; /* * DT Boot: * OF framework will construct the resource structure (currently * does for MEM & IRQ resource) and we should respect/use these * resources, killing hwmod dependency. * If pdev->num_resources > 0, we assume that MEM & IRQ resources * have been allocated by OF layer already (through DTB). * * Non-DT Boot: * Here, pdev->num_resources = 0, and we should get all the * resources from hwmod. * * TODO: Once DMA resource is available from OF layer, we should * kill filling any resources from hwmod. */ /* count number of resources hwmod provides */ res_count = omap_device_count_resources(od, IORESOURCE_IRQ | IORESOURCE_DMA | IORESOURCE_MEM); /* if no resources from hwmod, we're done already */ if (res_count == 0) return 0; /* Allocate resources memory to account for all hwmod resources */ res = kzalloc(sizeof(struct resource) * res_count, GFP_KERNEL); if (!res) { ret = -ENOMEM; goto fail_no_res; } /* fill all the resources */ ret = omap_device_fill_resources(od, res); if (ret != 0) goto fail_no_fill; /* * If pdev->num_resources > 0, then assume that, * MEM and IRQ resources will only come from DT and only * fill DMA resource from hwmod layer. */ if (pdev->num_resources > 0) { dev_dbg(&pdev->dev, "%s(): resources allocated %d hwmod #%d\n", __func__, pdev->num_resources, res_count); /* find number of resources needing to be inserted */ for (i = 0, j = 0, r = res; i < res_count; i++, r++) { type = resource_type(r); if (type == IORESOURCE_DMA) j++; } /* no need to insert anything, just return */ if (j == 0) { kfree(res); return 0; } /* we need to insert j additional resources */ rnew = kzalloc(sizeof(*rnew) * (pdev->num_resources + j), GFP_KERNEL); if (rnew == NULL) goto fail_no_rnew; /* * Unlink any resources from any lists. * This is important since the copying destroys any * linkage */ for (i = 0, r = pdev->resource; i < pdev->num_resources; i++, r++) { if (!r->parent) continue; dev_dbg(&pdev->dev, "Releasing resource %p\n", r); release_resource(r); r->parent = NULL; r->sibling = NULL; r->child = NULL; } memcpy(rnew, pdev->resource, sizeof(*rnew) * pdev->num_resources); /* now append the resources from the hwmods */ rn = rnew + pdev->num_resources; for (i = 0, r = res; i < res_count; i++, r++) { type = resource_type(r); if (type != IORESOURCE_DMA) continue; /* append the hwmod resource */ memcpy(rn, r, sizeof(*r)); /* make sure these are zeroed out */ rn->parent = NULL; rn->child = NULL; rn->sibling = NULL; rn++; } kfree(res); /* we don't need res anymore */ /* this is our new resource table */ res = rnew; res_count = j + pdev->num_resources; } else { dev_dbg(&pdev->dev, "%s(): using resources from hwmod %d\n", __func__, res_count); } ret = platform_device_add_resources(pdev, res, res_count); kfree(res); /* failed to add the resources? */ if (ret != 0) return ret; /* finally link all the resources again */ ret = platform_device_link_resources(pdev); if (ret != 0) return ret; return 0; fail_no_rnew: /* nothing */ fail_no_fill: kfree(res); fail_no_res: return ret; }
/** * omap_device_alloc - allocate an omap_device * @pdev: platform_device that will be included in this omap_device * @oh: ptr to the single omap_hwmod that backs this omap_device * @pdata: platform_data ptr to associate with the platform_device * @pdata_len: amount of memory pointed to by @pdata * * Convenience function for allocating an omap_device structure and filling * hwmods, and resources. * * Returns an struct omap_device pointer or ERR_PTR() on error; */ struct omap_device *omap_device_alloc(struct platform_device *pdev, struct omap_hwmod **ohs, int oh_cnt) { int ret = -ENOMEM; struct omap_device *od; struct resource *res = NULL; int i, res_count; struct omap_hwmod **hwmods; od = kzalloc(sizeof(struct omap_device), GFP_KERNEL); if (!od) { ret = -ENOMEM; goto oda_exit1; } od->hwmods_cnt = oh_cnt; hwmods = kmemdup(ohs, sizeof(struct omap_hwmod *) * oh_cnt, GFP_KERNEL); if (!hwmods) goto oda_exit2; od->hwmods = hwmods; od->pdev = pdev; /* * Non-DT Boot: * Here, pdev->num_resources = 0, and we should get all the * resources from hwmod. * * DT Boot: * OF framework will construct the resource structure (currently * does for MEM & IRQ resource) and we should respect/use these * resources, killing hwmod dependency. * If pdev->num_resources > 0, we assume that MEM & IRQ resources * have been allocated by OF layer already (through DTB). * As preparation for the future we examine the OF provided resources * to see if we have DMA resources provided already. In this case * there is no need to update the resources for the device, we use the * OF provided ones. * * TODO: Once DMA resource is available from OF layer, we should * kill filling any resources from hwmod. */ if (!pdev->num_resources) { /* Count all resources for the device */ res_count = omap_device_count_resources(od, IORESOURCE_IRQ | IORESOURCE_DMA | IORESOURCE_MEM); } else { /* Take a look if we already have DMA resource via DT */ for (i = 0; i < pdev->num_resources; i++) { struct resource *r = &pdev->resource[i]; /* We have it, no need to touch the resources */ if (r->flags == IORESOURCE_DMA) goto have_everything; } /* Count only DMA resources for the device */ res_count = omap_device_count_resources(od, IORESOURCE_DMA); /* The device has no DMA resource, no need for update */ if (!res_count) goto have_everything; res_count += pdev->num_resources; } /* Allocate resources memory to account for new resources */ res = kzalloc(sizeof(struct resource) * res_count, GFP_KERNEL); if (!res) goto oda_exit3; if (!pdev->num_resources) { dev_dbg(&pdev->dev, "%s: using %d resources from hwmod\n", __func__, res_count); omap_device_fill_resources(od, res); } else { dev_dbg(&pdev->dev, "%s: appending %d DMA resources from hwmod\n", __func__, res_count - pdev->num_resources); memcpy(res, pdev->resource, sizeof(struct resource) * pdev->num_resources); _od_fill_dma_resources(od, &res[pdev->num_resources]); } ret = platform_device_add_resources(pdev, res, res_count); kfree(res); if (ret) goto oda_exit3; have_everything: pdev->archdata.od = od; for (i = 0; i < oh_cnt; i++) { hwmods[i]->od = od; _add_hwmod_clocks_clkdev(od, hwmods[i]); } return od; oda_exit3: kfree(hwmods); oda_exit2: kfree(od); oda_exit1: dev_err(&pdev->dev, "omap_device: build failed (%d)\n", ret); return ERR_PTR(ret); }
/** * omap_device_alloc - allocate an omap_device * @pdev: platform_device that will be included in this omap_device * @oh: ptr to the single omap_hwmod that backs this omap_device * @pdata: platform_data ptr to associate with the platform_device * @pdata_len: amount of memory pointed to by @pdata * @pm_lats: pointer to a omap_device_pm_latency array for this device * @pm_lats_cnt: ARRAY_SIZE() of @pm_lats * * Convenience function for allocating an omap_device structure and filling * hwmods, resources and pm_latency attributes. * * Returns an struct omap_device pointer or ERR_PTR() on error; */ static struct omap_device *omap_device_alloc(struct platform_device *pdev, struct omap_hwmod **ohs, int oh_cnt, struct omap_device_pm_latency *pm_lats, int pm_lats_cnt) { int ret = -ENOMEM; struct omap_device *od; struct resource *res = NULL; int i, res_count; struct omap_hwmod **hwmods; od = kzalloc(sizeof(struct omap_device), GFP_KERNEL); if (!od) { ret = -ENOMEM; goto oda_exit1; } od->hwmods_cnt = oh_cnt; hwmods = kmemdup(ohs, sizeof(struct omap_hwmod *) * oh_cnt, GFP_KERNEL); if (!hwmods) goto oda_exit2; od->hwmods = hwmods; od->pdev = pdev; /* * HACK: Ideally the resources from DT should match, and hwmod * should just add the missing ones. Since the name is not * properly populated by DT, stick to hwmod resources only. */ if (pdev->num_resources && pdev->resource) dev_err(&pdev->dev, "%s(): resources already allocated %d\n", __func__, pdev->num_resources); res_count = omap_device_count_resources(od); if (res_count > 0) { dev_dbg(&pdev->dev, "%s(): resources allocated from hwmod %d\n", __func__, res_count); res = kzalloc(sizeof(struct resource) * res_count, GFP_KERNEL); if (!res) goto oda_exit3; omap_device_fill_resources(od, res); ret = platform_device_add_resources(pdev, res, res_count); kfree(res); if (ret) goto oda_exit3; } if (!pm_lats) { pm_lats = omap_default_latency; pm_lats_cnt = ARRAY_SIZE(omap_default_latency); } od->pm_lats_cnt = pm_lats_cnt; od->pm_lats = kmemdup(pm_lats, sizeof(struct omap_device_pm_latency) * pm_lats_cnt, GFP_KERNEL); if (!od->pm_lats) goto oda_exit3; pdev->archdata.od = od; for (i = 0; i < oh_cnt; i++) { hwmods[i]->od = od; _add_hwmod_clocks_clkdev(od, hwmods[i]); } return od; oda_exit3: kfree(hwmods); oda_exit2: kfree(od); oda_exit1: dev_err(&pdev->dev, "omap_device: build failed (%d)\n", ret); return ERR_PTR(ret); }