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 | |
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')
-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; |