diff options
| author | Sebastian Reichel <sre@kernel.org> | 2016-05-11 14:33:45 -0400 |
|---|---|---|
| committer | Sebastian Reichel <sre@kernel.org> | 2016-06-27 18:39:15 -0400 |
| commit | 7c5d81620ecd37702e86232de819eb1dd4c738e0 (patch) | |
| tree | 6d47fa843b20df8ce67b842f454d07b6cefbde95 /drivers/hsi/controllers | |
| parent | de5a3774dde2c2f3b3a9a48b880fd820142706f0 (diff) | |
HSI: omap_ssi_port: prepare start_tx/stop_tx for blocking pm_runtime calls
ssi_start_tx and ssi_stop_tx may be called from atomic context. Once
pm_runtime_irq_safe() is removed for omap-ssi, this will fail, due
to blocking pm_runtime_*_sync() calls.
This fixes ssi_stop_tx by using non-sync API and ssi_start_tx by
using a worker thread.
Signed-off-by: Sebastian Reichel <sre@kernel.org>
Tested-by: Pavel Machek <pavel@ucw.cz>
Diffstat (limited to 'drivers/hsi/controllers')
| -rw-r--r-- | drivers/hsi/controllers/omap_ssi.h | 2 | ||||
| -rw-r--r-- | drivers/hsi/controllers/omap_ssi_port.c | 23 |
2 files changed, 20 insertions, 5 deletions
diff --git a/drivers/hsi/controllers/omap_ssi.h b/drivers/hsi/controllers/omap_ssi.h index 6cdaad8805f7..5467f61e5086 100644 --- a/drivers/hsi/controllers/omap_ssi.h +++ b/drivers/hsi/controllers/omap_ssi.h | |||
| @@ -79,6 +79,7 @@ struct omap_ssm_ctx { | |||
| 79 | * @pio_tasklet: Bottom half for PIO transfers and events | 79 | * @pio_tasklet: Bottom half for PIO transfers and events |
| 80 | * @flags: flags to keep track of states | 80 | * @flags: flags to keep track of states |
| 81 | * @wk_refcount: Reference count for output wake line | 81 | * @wk_refcount: Reference count for output wake line |
| 82 | * @work: worker for starting TX | ||
| 82 | * @sys_mpu_enable: Context for the interrupt enable register for irq 0 | 83 | * @sys_mpu_enable: Context for the interrupt enable register for irq 0 |
| 83 | * @sst: Context for the synchronous serial transmitter | 84 | * @sst: Context for the synchronous serial transmitter |
| 84 | * @ssr: Context for the synchronous serial receiver | 85 | * @ssr: Context for the synchronous serial receiver |
| @@ -103,6 +104,7 @@ struct omap_ssi_port { | |||
| 103 | bool wktest:1; /* FIXME: HACK to be removed */ | 104 | bool wktest:1; /* FIXME: HACK to be removed */ |
| 104 | unsigned long flags; | 105 | unsigned long flags; |
| 105 | unsigned int wk_refcount; | 106 | unsigned int wk_refcount; |
| 107 | struct work_struct work; | ||
| 106 | /* OMAP SSI port context */ | 108 | /* OMAP SSI port context */ |
| 107 | u32 sys_mpu_enable; /* We use only one irq */ | 109 | u32 sys_mpu_enable; /* We use only one irq */ |
| 108 | struct omap_ssm_ctx sst; | 110 | struct omap_ssm_ctx sst; |
diff --git a/drivers/hsi/controllers/omap_ssi_port.c b/drivers/hsi/controllers/omap_ssi_port.c index 0d3452393670..cc56d0ee82a2 100644 --- a/drivers/hsi/controllers/omap_ssi_port.c +++ b/drivers/hsi/controllers/omap_ssi_port.c | |||
| @@ -567,12 +567,22 @@ static int ssi_flush(struct hsi_client *cl) | |||
| 567 | return 0; | 567 | return 0; |
| 568 | } | 568 | } |
| 569 | 569 | ||
| 570 | static void start_tx_work(struct work_struct *work) | ||
| 571 | { | ||
| 572 | struct omap_ssi_port *omap_port = | ||
| 573 | container_of(work, struct omap_ssi_port, work); | ||
| 574 | struct hsi_port *port = to_hsi_port(omap_port->dev); | ||
| 575 | struct hsi_controller *ssi = to_hsi_controller(port->device.parent); | ||
| 576 | struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi); | ||
| 577 | |||
| 578 | pm_runtime_get_sync(omap_port->pdev); /* Grab clocks */ | ||
| 579 | writel(SSI_WAKE(0), omap_ssi->sys + SSI_SET_WAKE_REG(port->num)); | ||
| 580 | } | ||
| 581 | |||
| 570 | static int ssi_start_tx(struct hsi_client *cl) | 582 | static int ssi_start_tx(struct hsi_client *cl) |
| 571 | { | 583 | { |
| 572 | struct hsi_port *port = hsi_get_port(cl); | 584 | struct hsi_port *port = hsi_get_port(cl); |
| 573 | struct omap_ssi_port *omap_port = hsi_port_drvdata(port); | 585 | struct omap_ssi_port *omap_port = hsi_port_drvdata(port); |
| 574 | struct hsi_controller *ssi = to_hsi_controller(port->device.parent); | ||
| 575 | struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi); | ||
| 576 | 586 | ||
| 577 | dev_dbg(&port->device, "Wake out high %d\n", omap_port->wk_refcount); | 587 | dev_dbg(&port->device, "Wake out high %d\n", omap_port->wk_refcount); |
| 578 | 588 | ||
| @@ -581,10 +591,10 @@ static int ssi_start_tx(struct hsi_client *cl) | |||
| 581 | spin_unlock_bh(&omap_port->wk_lock); | 591 | spin_unlock_bh(&omap_port->wk_lock); |
| 582 | return 0; | 592 | return 0; |
| 583 | } | 593 | } |
| 584 | pm_runtime_get_sync(omap_port->pdev); /* Grab clocks */ | ||
| 585 | writel(SSI_WAKE(0), omap_ssi->sys + SSI_SET_WAKE_REG(port->num)); | ||
| 586 | spin_unlock_bh(&omap_port->wk_lock); | 594 | spin_unlock_bh(&omap_port->wk_lock); |
| 587 | 595 | ||
| 596 | schedule_work(&omap_port->work); | ||
| 597 | |||
| 588 | return 0; | 598 | return 0; |
| 589 | } | 599 | } |
| 590 | 600 | ||
| @@ -604,9 +614,10 @@ static int ssi_stop_tx(struct hsi_client *cl) | |||
| 604 | return 0; | 614 | return 0; |
| 605 | } | 615 | } |
| 606 | writel(SSI_WAKE(0), omap_ssi->sys + SSI_CLEAR_WAKE_REG(port->num)); | 616 | writel(SSI_WAKE(0), omap_ssi->sys + SSI_CLEAR_WAKE_REG(port->num)); |
| 607 | pm_runtime_put_sync(omap_port->pdev); /* Release clocks */ | ||
| 608 | spin_unlock_bh(&omap_port->wk_lock); | 617 | spin_unlock_bh(&omap_port->wk_lock); |
| 609 | 618 | ||
| 619 | pm_runtime_put(omap_port->pdev); /* Release clocks */ | ||
| 620 | |||
| 610 | return 0; | 621 | return 0; |
| 611 | } | 622 | } |
| 612 | 623 | ||
| @@ -1149,6 +1160,8 @@ static int ssi_port_probe(struct platform_device *pd) | |||
| 1149 | omap_port->pdev = &pd->dev; | 1160 | omap_port->pdev = &pd->dev; |
| 1150 | omap_port->port_id = port_id; | 1161 | omap_port->port_id = port_id; |
| 1151 | 1162 | ||
| 1163 | INIT_WORK(&omap_port->work, start_tx_work); | ||
| 1164 | |||
| 1152 | /* initialize HSI port */ | 1165 | /* initialize HSI port */ |
| 1153 | port->async = ssi_async; | 1166 | port->async = ssi_async; |
| 1154 | port->setup = ssi_setup; | 1167 | port->setup = ssi_setup; |
