diff options
Diffstat (limited to 'drivers/rpmsg/qcom_glink_smem.c')
-rw-r--r-- | drivers/rpmsg/qcom_glink_smem.c | 55 |
1 files changed, 53 insertions, 2 deletions
diff --git a/drivers/rpmsg/qcom_glink_smem.c b/drivers/rpmsg/qcom_glink_smem.c index a9c477df4d68..05b4fe0a7387 100644 --- a/drivers/rpmsg/qcom_glink_smem.c +++ b/drivers/rpmsg/qcom_glink_smem.c @@ -7,8 +7,10 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/of_irq.h> #include <linux/interrupt.h> #include <linux/platform_device.h> +#include <linux/mailbox_client.h> #include <linux/mfd/syscon.h> #include <linux/slab.h> #include <linux/rpmsg.h> @@ -36,8 +38,12 @@ struct qcom_glink_smem { struct device dev; + int irq; struct qcom_glink *glink; + struct mbox_client mbox_client; + struct mbox_chan *mbox_chan; + u32 remote_pid; }; @@ -186,6 +192,24 @@ static void glink_smem_tx_write(struct qcom_glink_pipe *glink_pipe, *pipe->head = cpu_to_le32(head); } +static void glink_smem_tx_kick(struct qcom_glink_pipe *glink_pipe) +{ + struct glink_smem_pipe *pipe = to_smem_pipe(glink_pipe); + struct qcom_glink_smem *smem = pipe->smem; + + mbox_send_message(smem->mbox_chan, NULL); + mbox_client_txdone(smem->mbox_chan, 0); +} + +static irqreturn_t qcom_glink_smem_intr(int irq, void *data) +{ + struct qcom_glink_smem *smem = data; + + qcom_glink_native_rx(smem->glink); + + return IRQ_HANDLED; +} + static void qcom_glink_smem_release(struct device *dev) { struct qcom_glink_smem *smem = container_of(dev, struct qcom_glink_smem, dev); @@ -280,6 +304,24 @@ struct qcom_glink_smem *qcom_glink_smem_register(struct device *parent, goto err_put_dev; } + smem->irq = of_irq_get(smem->dev.of_node, 0); + ret = devm_request_irq(&smem->dev, smem->irq, qcom_glink_smem_intr, + IRQF_NO_SUSPEND | IRQF_NO_AUTOEN, + "glink-smem", smem); + if (ret) { + dev_err(&smem->dev, "failed to request IRQ\n"); + goto err_put_dev; + } + + smem->mbox_client.dev = &smem->dev; + smem->mbox_client.knows_txdone = true; + smem->mbox_chan = mbox_request_channel(&smem->mbox_client, 0); + if (IS_ERR(smem->mbox_chan)) { + ret = dev_err_probe(&smem->dev, PTR_ERR(smem->mbox_chan), + "failed to acquire IPC channel\n"); + goto err_put_dev; + } + rx_pipe->smem = smem; rx_pipe->native.avail = glink_smem_rx_avail; rx_pipe->native.peak = glink_smem_rx_peak; @@ -288,6 +330,7 @@ struct qcom_glink_smem *qcom_glink_smem_register(struct device *parent, tx_pipe->smem = smem; tx_pipe->native.avail = glink_smem_tx_avail; tx_pipe->native.write = glink_smem_tx_write; + tx_pipe->native.kick = glink_smem_tx_kick; *rx_pipe->tail = 0; *tx_pipe->head = 0; @@ -298,13 +341,17 @@ struct qcom_glink_smem *qcom_glink_smem_register(struct device *parent, false); if (IS_ERR(glink)) { ret = PTR_ERR(glink); - goto err_put_dev; + goto err_free_mbox; } smem->glink = glink; + enable_irq(smem->irq); + return smem; +err_free_mbox: + mbox_free_channel(smem->mbox_chan); err_put_dev: device_unregister(dev); @@ -317,8 +364,12 @@ void qcom_glink_smem_unregister(struct qcom_glink_smem *smem) { struct qcom_glink *glink = smem->glink; + disable_irq(smem->irq); + qcom_glink_native_remove(glink); - qcom_glink_native_unregister(glink); + + mbox_free_channel(smem->mbox_chan); + device_unregister(&smem->dev); } EXPORT_SYMBOL_GPL(qcom_glink_smem_unregister); |