diff options
Diffstat (limited to 'arch/arm/plat-omap/omap_device.c')
| -rw-r--r-- | arch/arm/plat-omap/omap_device.c | 135 | 
1 files changed, 118 insertions, 17 deletions
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c index 5b697426910..cee85a55bd8 100644 --- a/arch/arm/plat-omap/omap_device.c +++ b/arch/arm/plat-omap/omap_device.c @@ -365,6 +365,14 @@ static int omap_device_build_from_dt(struct platform_device *pdev)  		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 (of_get_property(node, "ti,no_idle_on_suspend", NULL))  		omap_device_disable_idle_on_suspend(pdev); @@ -380,17 +388,21 @@ static int _omap_device_notifier_call(struct notifier_block *nb,  				      unsigned long event, void *dev)  {  	struct platform_device *pdev = to_platform_device(dev); +	struct omap_device *od;  	switch (event) { -	case BUS_NOTIFY_ADD_DEVICE: -		if (pdev->dev.of_node) -			omap_device_build_from_dt(pdev); -		break; -  	case BUS_NOTIFY_DEL_DEVICE:  		if (pdev->archdata.od)  			omap_device_delete(pdev->archdata.od);  		break; +	case BUS_NOTIFY_ADD_DEVICE: +		if (pdev->dev.of_node) +			omap_device_build_from_dt(pdev); +		/* fall through */ +	default: +		od = to_omap_device(pdev); +		if (od) +			od->_driver_status = event;  	}  	return NOTIFY_DONE; @@ -481,6 +493,33 @@ static int omap_device_fill_resources(struct omap_device *od,  }  /** + * _od_fill_dma_resources - fill in array of struct resource with dma resources + * @od: struct omap_device * + * @res: pointer to an array of struct resource to be filled in + * + * Populate one or more empty struct resource pointed to by @res with + * the dma resource data for this omap_device @od.  Used by + * omap_device_alloc() after calling omap_device_count_resources(). + * + * Ideally this function would not be needed at all.  If we have + * mechanism to get dma resources from DT. + * + * Returns 0. + */ +static int _od_fill_dma_resources(struct omap_device *od, +				      struct resource *res) +{ +	int i, r; + +	for (i = 0; i < od->hwmods_cnt; i++) { +		r = omap_hwmod_fill_dma_resources(od->hwmods[i], res); +		res += r; +	} + +	return 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 @@ -519,24 +558,44 @@ struct omap_device *omap_device_alloc(struct platform_device *pdev,  	od->hwmods = hwmods;  	od->pdev = pdev; +	res_count = omap_device_count_resources(od);  	/* -	 * 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. +	 * 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.  	 */ -	if (pdev->num_resources && pdev->resource) -		dev_warn(&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); +	if (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; -		omap_device_fill_resources(od, res); +		/* +		 * 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 && pdev->resource) { +			dev_dbg(&pdev->dev, "%s(): resources already allocated %d\n", +				__func__, res_count); +			memcpy(res, pdev->resource, +			       sizeof(struct resource) * pdev->num_resources); +			_od_fill_dma_resources(od, &res[pdev->num_resources]); +		} else { +			dev_dbg(&pdev->dev, "%s(): using resources from hwmod %d\n", +				__func__, res_count); +			omap_device_fill_resources(od, res); +		}  		ret = platform_device_add_resources(pdev, res, res_count);  		kfree(res); @@ -747,6 +806,10 @@ static int _od_suspend_noirq(struct device *dev)  	struct omap_device *od = to_omap_device(pdev);  	int ret; +	/* Don't attempt late suspend on a driver that is not bound */ +	if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) +		return 0; +  	ret = pm_generic_suspend_noirq(dev);  	if (!ret && !pm_runtime_status_suspended(dev)) { @@ -1175,3 +1238,41 @@ static int __init omap_device_init(void)  	return 0;  }  core_initcall(omap_device_init); + +/** + * omap_device_late_idle - idle devices without drivers + * @dev: struct device * associated with omap_device + * @data: unused + * + * Check the driver bound status of this device, and idle it + * if there is no driver attached. + */ +static int __init omap_device_late_idle(struct device *dev, void *data) +{ +	struct platform_device *pdev = to_platform_device(dev); +	struct omap_device *od = to_omap_device(pdev); + +	if (!od) +		return 0; + +	/* +	 * If omap_device state is enabled, but has no driver bound, +	 * idle it. +	 */ +	if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) { +		if (od->_state == OMAP_DEVICE_STATE_ENABLED) { +			dev_warn(dev, "%s: enabled but no driver.  Idling\n", +				 __func__); +			omap_device_idle(pdev); +		} +	} + +	return 0; +} + +static int __init omap_device_late_init(void) +{ +	bus_for_each_dev(&platform_bus_type, NULL, NULL, omap_device_late_idle); +	return 0; +} +late_initcall(omap_device_late_init);  |