aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hsi
diff options
context:
space:
mode:
authorSebastian Reichel <sre@kernel.org>2016-05-11 14:33:45 -0400
committerSebastian Reichel <sre@kernel.org>2016-06-27 18:39:15 -0400
commit7c5d81620ecd37702e86232de819eb1dd4c738e0 (patch)
tree6d47fa843b20df8ce67b842f454d07b6cefbde95 /drivers/hsi
parentde5a3774dde2c2f3b3a9a48b880fd820142706f0 (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.h2
-rw-r--r--drivers/hsi/controllers/omap_ssi_port.c23
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
570static 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
570static int ssi_start_tx(struct hsi_client *cl) 582static 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;