]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
HSI: omap_ssi_port: prepare start_tx/stop_tx for blocking pm_runtime calls
authorSebastian Reichel <sre@kernel.org>
Wed, 11 May 2016 18:33:45 +0000 (20:33 +0200)
committerSebastian Reichel <sre@kernel.org>
Mon, 27 Jun 2016 22:39:15 +0000 (00:39 +0200)
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>
drivers/hsi/controllers/omap_ssi.h
drivers/hsi/controllers/omap_ssi_port.c

index 6cdaad8805f7693ac94b0699c1528b3579fc6be6..5467f61e5086e95c4f7b0f78fc79a37e251199e5 100644 (file)
@@ -79,6 +79,7 @@ struct omap_ssm_ctx {
  * @pio_tasklet: Bottom half for PIO transfers and events
  * @flags: flags to keep track of states
  * @wk_refcount: Reference count for output wake line
+ * @work: worker for starting TX
  * @sys_mpu_enable: Context for the interrupt enable register for irq 0
  * @sst: Context for the synchronous serial transmitter
  * @ssr: Context for the synchronous serial receiver
@@ -103,6 +104,7 @@ struct omap_ssi_port {
        bool                    wktest:1; /* FIXME: HACK to be removed */
        unsigned long           flags;
        unsigned int            wk_refcount;
+       struct work_struct      work;
        /* OMAP SSI port context */
        u32                     sys_mpu_enable; /* We use only one irq */
        struct omap_ssm_ctx     sst;
index 0d3452393670ea7abdb248560cdb77299d5857b4..cc56d0ee82a22ab244130255a6f374c490782960 100644 (file)
@@ -567,12 +567,22 @@ static int ssi_flush(struct hsi_client *cl)
        return 0;
 }
 
+static void start_tx_work(struct work_struct *work)
+{
+       struct omap_ssi_port *omap_port =
+                               container_of(work, struct omap_ssi_port, work);
+       struct hsi_port *port = to_hsi_port(omap_port->dev);
+       struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
+       struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
+
+       pm_runtime_get_sync(omap_port->pdev); /* Grab clocks */
+       writel(SSI_WAKE(0), omap_ssi->sys + SSI_SET_WAKE_REG(port->num));
+}
+
 static int ssi_start_tx(struct hsi_client *cl)
 {
        struct hsi_port *port = hsi_get_port(cl);
        struct omap_ssi_port *omap_port = hsi_port_drvdata(port);
-       struct hsi_controller *ssi = to_hsi_controller(port->device.parent);
-       struct omap_ssi_controller *omap_ssi = hsi_controller_drvdata(ssi);
 
        dev_dbg(&port->device, "Wake out high %d\n", omap_port->wk_refcount);
 
@@ -581,10 +591,10 @@ static int ssi_start_tx(struct hsi_client *cl)
                spin_unlock_bh(&omap_port->wk_lock);
                return 0;
        }
-       pm_runtime_get_sync(omap_port->pdev); /* Grab clocks */
-       writel(SSI_WAKE(0), omap_ssi->sys + SSI_SET_WAKE_REG(port->num));
        spin_unlock_bh(&omap_port->wk_lock);
 
+       schedule_work(&omap_port->work);
+
        return 0;
 }
 
@@ -604,9 +614,10 @@ static int ssi_stop_tx(struct hsi_client *cl)
                return 0;
        }
        writel(SSI_WAKE(0), omap_ssi->sys + SSI_CLEAR_WAKE_REG(port->num));
-       pm_runtime_put_sync(omap_port->pdev); /* Release clocks */
        spin_unlock_bh(&omap_port->wk_lock);
 
+       pm_runtime_put(omap_port->pdev); /* Release clocks */
+
        return 0;
 }
 
@@ -1149,6 +1160,8 @@ static int ssi_port_probe(struct platform_device *pd)
        omap_port->pdev = &pd->dev;
        omap_port->port_id = port_id;
 
+       INIT_WORK(&omap_port->work, start_tx_work);
+
        /* initialize HSI port */
        port->async     = ssi_async;
        port->setup     = ssi_setup;