Exemple #1
0
/**
 * 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;
}
Exemple #3
0
/**
 * 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);
}