aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-omap/omap_device.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-omap/omap_device.c')
-rw-r--r--arch/arm/plat-omap/omap_device.c160
1 files changed, 128 insertions, 32 deletions
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index c490240bb82c..d5f617c542d3 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -1,4 +1,3 @@
1
2/* 1/*
3 * omap_device implementation 2 * omap_device implementation
4 * 3 *
@@ -153,21 +152,19 @@ static int _omap_device_activate(struct omap_device *od, u8 ignore_lat)
153 act_lat = timespec_to_ns(&c); 152 act_lat = timespec_to_ns(&c);
154 153
155 dev_dbg(&od->pdev->dev, 154 dev_dbg(&od->pdev->dev,
156 "omap_device: pm_lat %d: activate: elapsed time " 155 "omap_device: pm_lat %d: activate: elapsed time %llu nsec\n",
157 "%llu nsec\n", od->pm_lat_level, act_lat); 156 od->pm_lat_level, act_lat);
158 157
159 if (act_lat > odpl->activate_lat) { 158 if (act_lat > odpl->activate_lat) {
160 odpl->activate_lat_worst = act_lat; 159 odpl->activate_lat_worst = act_lat;
161 if (odpl->flags & OMAP_DEVICE_LATENCY_AUTO_ADJUST) { 160 if (odpl->flags & OMAP_DEVICE_LATENCY_AUTO_ADJUST) {
162 odpl->activate_lat = act_lat; 161 odpl->activate_lat = act_lat;
163 dev_dbg(&od->pdev->dev, 162 dev_dbg(&od->pdev->dev,
164 "new worst case activate latency " 163 "new worst case activate latency %d: %llu\n",
165 "%d: %llu\n",
166 od->pm_lat_level, act_lat); 164 od->pm_lat_level, act_lat);
167 } else 165 } else
168 dev_warn(&od->pdev->dev, 166 dev_warn(&od->pdev->dev,
169 "activate latency %d " 167 "activate latency %d higher than expected. (%llu > %d)\n",
170 "higher than exptected. (%llu > %d)\n",
171 od->pm_lat_level, act_lat, 168 od->pm_lat_level, act_lat,
172 odpl->activate_lat); 169 odpl->activate_lat);
173 } 170 }
@@ -220,21 +217,19 @@ static int _omap_device_deactivate(struct omap_device *od, u8 ignore_lat)
220 deact_lat = timespec_to_ns(&c); 217 deact_lat = timespec_to_ns(&c);
221 218
222 dev_dbg(&od->pdev->dev, 219 dev_dbg(&od->pdev->dev,
223 "omap_device: pm_lat %d: deactivate: elapsed time " 220 "omap_device: pm_lat %d: deactivate: elapsed time %llu nsec\n",
224 "%llu nsec\n", od->pm_lat_level, deact_lat); 221 od->pm_lat_level, deact_lat);
225 222
226 if (deact_lat > odpl->deactivate_lat) { 223 if (deact_lat > odpl->deactivate_lat) {
227 odpl->deactivate_lat_worst = deact_lat; 224 odpl->deactivate_lat_worst = deact_lat;
228 if (odpl->flags & OMAP_DEVICE_LATENCY_AUTO_ADJUST) { 225 if (odpl->flags & OMAP_DEVICE_LATENCY_AUTO_ADJUST) {
229 odpl->deactivate_lat = deact_lat; 226 odpl->deactivate_lat = deact_lat;
230 dev_dbg(&od->pdev->dev, 227 dev_dbg(&od->pdev->dev,
231 "new worst case deactivate latency " 228 "new worst case deactivate latency %d: %llu\n",
232 "%d: %llu\n",
233 od->pm_lat_level, deact_lat); 229 od->pm_lat_level, deact_lat);
234 } else 230 } else
235 dev_warn(&od->pdev->dev, 231 dev_warn(&od->pdev->dev,
236 "deactivate latency %d " 232 "deactivate latency %d higher than expected. (%llu > %d)\n",
237 "higher than exptected. (%llu > %d)\n",
238 od->pm_lat_level, deact_lat, 233 od->pm_lat_level, deact_lat,
239 odpl->deactivate_lat); 234 odpl->deactivate_lat);
240 } 235 }
@@ -370,6 +365,14 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
370 goto odbfd_exit1; 365 goto odbfd_exit1;
371 } 366 }
372 367
368 /* Fix up missing resource names */
369 for (i = 0; i < pdev->num_resources; i++) {
370 struct resource *r = &pdev->resource[i];
371
372 if (r->name == NULL)
373 r->name = dev_name(&pdev->dev);
374 }
375
373 if (of_get_property(node, "ti,no_idle_on_suspend", NULL)) 376 if (of_get_property(node, "ti,no_idle_on_suspend", NULL))
374 omap_device_disable_idle_on_suspend(pdev); 377 omap_device_disable_idle_on_suspend(pdev);
375 378
@@ -385,17 +388,21 @@ static int _omap_device_notifier_call(struct notifier_block *nb,
385 unsigned long event, void *dev) 388 unsigned long event, void *dev)
386{ 389{
387 struct platform_device *pdev = to_platform_device(dev); 390 struct platform_device *pdev = to_platform_device(dev);
391 struct omap_device *od;
388 392
389 switch (event) { 393 switch (event) {
390 case BUS_NOTIFY_ADD_DEVICE:
391 if (pdev->dev.of_node)
392 omap_device_build_from_dt(pdev);
393 break;
394
395 case BUS_NOTIFY_DEL_DEVICE: 394 case BUS_NOTIFY_DEL_DEVICE:
396 if (pdev->archdata.od) 395 if (pdev->archdata.od)
397 omap_device_delete(pdev->archdata.od); 396 omap_device_delete(pdev->archdata.od);
398 break; 397 break;
398 case BUS_NOTIFY_ADD_DEVICE:
399 if (pdev->dev.of_node)
400 omap_device_build_from_dt(pdev);
401 /* fall through */
402 default:
403 od = to_omap_device(pdev);
404 if (od)
405 od->_driver_status = event;
399 } 406 }
400 407
401 return NOTIFY_DONE; 408 return NOTIFY_DONE;
@@ -449,8 +456,8 @@ static int omap_device_count_resources(struct omap_device *od)
449 for (i = 0; i < od->hwmods_cnt; i++) 456 for (i = 0; i < od->hwmods_cnt; i++)
450 c += omap_hwmod_count_resources(od->hwmods[i]); 457 c += omap_hwmod_count_resources(od->hwmods[i]);
451 458
452 pr_debug("omap_device: %s: counted %d total resources across %d " 459 pr_debug("omap_device: %s: counted %d total resources across %d hwmods\n",
453 "hwmods\n", od->pdev->name, c, od->hwmods_cnt); 460 od->pdev->name, c, od->hwmods_cnt);
454 461
455 return c; 462 return c;
456} 463}
@@ -486,6 +493,33 @@ static int omap_device_fill_resources(struct omap_device *od,
486} 493}
487 494
488/** 495/**
496 * _od_fill_dma_resources - fill in array of struct resource with dma resources
497 * @od: struct omap_device *
498 * @res: pointer to an array of struct resource to be filled in
499 *
500 * Populate one or more empty struct resource pointed to by @res with
501 * the dma resource data for this omap_device @od. Used by
502 * omap_device_alloc() after calling omap_device_count_resources().
503 *
504 * Ideally this function would not be needed at all. If we have
505 * mechanism to get dma resources from DT.
506 *
507 * Returns 0.
508 */
509static int _od_fill_dma_resources(struct omap_device *od,
510 struct resource *res)
511{
512 int i, r;
513
514 for (i = 0; i < od->hwmods_cnt; i++) {
515 r = omap_hwmod_fill_dma_resources(od->hwmods[i], res);
516 res += r;
517 }
518
519 return 0;
520}
521
522/**
489 * omap_device_alloc - allocate an omap_device 523 * omap_device_alloc - allocate an omap_device
490 * @pdev: platform_device that will be included in this omap_device 524 * @pdev: platform_device that will be included in this omap_device
491 * @oh: ptr to the single omap_hwmod that backs this omap_device 525 * @oh: ptr to the single omap_hwmod that backs this omap_device
@@ -524,24 +558,44 @@ struct omap_device *omap_device_alloc(struct platform_device *pdev,
524 od->hwmods = hwmods; 558 od->hwmods = hwmods;
525 od->pdev = pdev; 559 od->pdev = pdev;
526 560
561 res_count = omap_device_count_resources(od);
527 /* 562 /*
528 * HACK: Ideally the resources from DT should match, and hwmod 563 * DT Boot:
529 * should just add the missing ones. Since the name is not 564 * OF framework will construct the resource structure (currently
530 * properly populated by DT, stick to hwmod resources only. 565 * does for MEM & IRQ resource) and we should respect/use these
566 * resources, killing hwmod dependency.
567 * If pdev->num_resources > 0, we assume that MEM & IRQ resources
568 * have been allocated by OF layer already (through DTB).
569 *
570 * Non-DT Boot:
571 * Here, pdev->num_resources = 0, and we should get all the
572 * resources from hwmod.
573 *
574 * TODO: Once DMA resource is available from OF layer, we should
575 * kill filling any resources from hwmod.
531 */ 576 */
532 if (pdev->num_resources && pdev->resource) 577 if (res_count > pdev->num_resources) {
533 dev_warn(&pdev->dev, "%s(): resources already allocated %d\n", 578 /* Allocate resources memory to account for new resources */
534 __func__, pdev->num_resources);
535
536 res_count = omap_device_count_resources(od);
537 if (res_count > 0) {
538 dev_dbg(&pdev->dev, "%s(): resources allocated from hwmod %d\n",
539 __func__, res_count);
540 res = kzalloc(sizeof(struct resource) * res_count, GFP_KERNEL); 579 res = kzalloc(sizeof(struct resource) * res_count, GFP_KERNEL);
541 if (!res) 580 if (!res)
542 goto oda_exit3; 581 goto oda_exit3;
543 582
544 omap_device_fill_resources(od, res); 583 /*
584 * If pdev->num_resources > 0, then assume that,
585 * MEM and IRQ resources will only come from DT and only
586 * fill DMA resource from hwmod layer.
587 */
588 if (pdev->num_resources && pdev->resource) {
589 dev_dbg(&pdev->dev, "%s(): resources already allocated %d\n",
590 __func__, res_count);
591 memcpy(res, pdev->resource,
592 sizeof(struct resource) * pdev->num_resources);
593 _od_fill_dma_resources(od, &res[pdev->num_resources]);
594 } else {
595 dev_dbg(&pdev->dev, "%s(): using resources from hwmod %d\n",
596 __func__, res_count);
597 omap_device_fill_resources(od, res);
598 }
545 599
546 ret = platform_device_add_resources(pdev, res, res_count); 600 ret = platform_device_add_resources(pdev, res, res_count);
547 kfree(res); 601 kfree(res);
@@ -752,6 +806,10 @@ static int _od_suspend_noirq(struct device *dev)
752 struct omap_device *od = to_omap_device(pdev); 806 struct omap_device *od = to_omap_device(pdev);
753 int ret; 807 int ret;
754 808
809 /* Don't attempt late suspend on a driver that is not bound */
810 if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER)
811 return 0;
812
755 ret = pm_generic_suspend_noirq(dev); 813 ret = pm_generic_suspend_noirq(dev);
756 814
757 if (!ret && !pm_runtime_status_suspended(dev)) { 815 if (!ret && !pm_runtime_status_suspended(dev)) {
@@ -1125,3 +1183,41 @@ static int __init omap_device_init(void)
1125 return 0; 1183 return 0;
1126} 1184}
1127core_initcall(omap_device_init); 1185core_initcall(omap_device_init);
1186
1187/**
1188 * omap_device_late_idle - idle devices without drivers
1189 * @dev: struct device * associated with omap_device
1190 * @data: unused
1191 *
1192 * Check the driver bound status of this device, and idle it
1193 * if there is no driver attached.
1194 */
1195static int __init omap_device_late_idle(struct device *dev, void *data)
1196{
1197 struct platform_device *pdev = to_platform_device(dev);
1198 struct omap_device *od = to_omap_device(pdev);
1199
1200 if (!od)
1201 return 0;
1202
1203 /*
1204 * If omap_device state is enabled, but has no driver bound,
1205 * idle it.
1206 */
1207 if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) {
1208 if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
1209 dev_warn(dev, "%s: enabled but no driver. Idling\n",
1210 __func__);
1211 omap_device_idle(pdev);
1212 }
1213 }
1214
1215 return 0;
1216}
1217
1218static int __init omap_device_late_init(void)
1219{
1220 bus_for_each_dev(&platform_bus_type, NULL, NULL, omap_device_late_idle);
1221 return 0;
1222}
1223late_initcall(omap_device_late_init);