summaryrefslogtreecommitdiff
path: root/drivers/mxc/xuvi/xuvi_mu.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mxc/xuvi/xuvi_mu.c')
-rw-r--r--drivers/mxc/xuvi/xuvi_mu.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/drivers/mxc/xuvi/xuvi_mu.c b/drivers/mxc/xuvi/xuvi_mu.c
new file mode 100644
index 000000000000..bbfa9d7268c9
--- /dev/null
+++ b/drivers/mxc/xuvi/xuvi_mu.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2020 NXP
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*
+ *
+ * @file xuvi_mu.c
+ *
+ */
+
+#include "xuvi_mu.h"
+
+static void xuvi_rx_callback(struct mbox_client *c, void *msg)
+{
+ struct xuvi_mu_chan *mu_chan =
+ container_of(c, struct xuvi_mu_chan, cl);
+ struct ppm_dev *dev = mu_chan->dev;
+ static uint32_t msg_mu[4], msg_mask;
+ u32 *data = msg;
+
+ msg_mu[mu_chan->idx] = *data;
+ msg_mask |= 1 << mu_chan->idx;
+
+ if (msg_mask == 0xF) {
+ msg_mask = 0;
+ if (kfifo_in(&dev->msg_fifo, msg_mu, sizeof(uint32_t) * 4)
+ != sizeof(uint32_t) * 4) {
+ return;
+ }
+
+ queue_work(dev->workqueue, &dev->msg_work);
+ }
+}
+
+int xuvi_mu_request(struct ppm_dev *dev)
+{
+ struct xuvi_mu_chan *mu_chan;
+ struct mbox_client *cl;
+ char *chan_name;
+ int ret = 0;
+ int i;
+
+ for (i = 0; i < MU_CHANNEL; i++) {
+ if (i < 4)
+ chan_name = kasprintf(GFP_KERNEL, "ts_tx%d", i);
+ else
+ chan_name =
+ kasprintf(GFP_KERNEL, "ts_rx%d", i - 4);
+
+ if (!chan_name)
+ return -ENOMEM;
+
+ mu_chan = &dev->mu_chans[i];
+ cl = &mu_chan->cl;
+ cl->dev = &dev->plat_dev->dev;
+ if (i == 1 || i == 2 || i == 3) {
+ cl->tx_block = false;
+ } else {
+ cl->tx_block = true;
+ cl->tx_tout = 1000;
+ }
+ cl->knows_txdone = false;
+ cl->rx_callback = xuvi_rx_callback;
+
+ mu_chan->dev = dev;
+ mu_chan->idx = i % 4;
+ mu_chan->ch = mbox_request_channel_byname(cl, chan_name);
+ if (IS_ERR(mu_chan->ch)) {
+ ret = PTR_ERR(mu_chan->ch);
+ if (ret != -EPROBE_DEFER)
+ printk
+ ("Failed to request mbox chan %s ret %d\n",
+ chan_name, ret);
+ kfree(chan_name);
+ return ret;
+ }
+
+ kfree(chan_name);
+ }
+
+ return ret;
+}
+
+void xuvi_mu_free(struct ppm_dev *dev)
+{
+ int i;
+
+ for (i = 0; i < MU_CHANNEL; i++) {
+ if (dev->mu_chans[i].ch && !IS_ERR(dev->mu_chans[i].ch))
+ mbox_free_channel(dev->mu_chans[i].ch);
+ dev->mu_chans[i].ch = NULL;
+ }
+}
+
+void xuvi_mu_send_msg(struct ppm_dev *dev, uint32_t value0,
+ uint32_t value1, uint32_t value2, uint32_t value3)
+{
+ mbox_send_message(dev->mu_chans[3].ch, &value3);
+ mbox_send_message(dev->mu_chans[2].ch, &value2);
+ mbox_send_message(dev->mu_chans[1].ch, &value1);
+ mbox_send_message(dev->mu_chans[0].ch, &value0);
+}