12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
28ea4484dSLee Jones /*
38ea4484dSLee Jones * Copyright (C) 2015 ST Microelectronics
48ea4484dSLee Jones *
58ea4484dSLee Jones * Author: Lee Jones <lee.jones@linaro.org>
68ea4484dSLee Jones */
78ea4484dSLee Jones
88ea4484dSLee Jones #include <linux/debugfs.h>
98ea4484dSLee Jones #include <linux/err.h>
10baef9a35SSudeep Holla #include <linux/fs.h>
11a133f8b6SLee Jones #include <linux/io.h>
128ea4484dSLee Jones #include <linux/kernel.h>
138ea4484dSLee Jones #include <linux/mailbox_client.h>
148ea4484dSLee Jones #include <linux/module.h>
152d1e952aSLee Jones #include <linux/mutex.h>
168ea4484dSLee Jones #include <linux/of.h>
178ea4484dSLee Jones #include <linux/platform_device.h>
18baef9a35SSudeep Holla #include <linux/poll.h>
198ea4484dSLee Jones #include <linux/slab.h>
20be884585SLee Jones #include <linux/spinlock.h>
218ea4484dSLee Jones #include <linux/uaccess.h>
22174cd4b1SIngo Molnar #include <linux/sched/signal.h>
238ea4484dSLee Jones
248ea4484dSLee Jones #define MBOX_MAX_SIG_LEN 8
258ea4484dSLee Jones #define MBOX_MAX_MSG_LEN 128
268ea4484dSLee Jones #define MBOX_BYTES_PER_LINE 16
278ea4484dSLee Jones #define MBOX_HEXDUMP_LINE_LEN ((MBOX_BYTES_PER_LINE * 4) + 2)
288ea4484dSLee Jones #define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * \
298ea4484dSLee Jones (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE))
308ea4484dSLee Jones
31e339c80aSSudeep Holla static bool mbox_data_ready;
328ea4484dSLee Jones
338ea4484dSLee Jones struct mbox_test_device {
348ea4484dSLee Jones struct device *dev;
352d74ffdcSSudeep Holla void __iomem *tx_mmio;
362d74ffdcSSudeep Holla void __iomem *rx_mmio;
378ea4484dSLee Jones struct mbox_chan *tx_channel;
388ea4484dSLee Jones struct mbox_chan *rx_channel;
398ea4484dSLee Jones char *rx_buffer;
408ea4484dSLee Jones char *signal;
418ea4484dSLee Jones char *message;
428ea4484dSLee Jones spinlock_t lock;
432d1e952aSLee Jones struct mutex mutex;
44baef9a35SSudeep Holla wait_queue_head_t waitq;
45baef9a35SSudeep Holla struct fasync_struct *async_queue;
4610cfc5a9SFabien Dessenne struct dentry *root_debugfs_dir;
478ea4484dSLee Jones };
488ea4484dSLee Jones
mbox_test_signal_write(struct file * filp,const char __user * userbuf,size_t count,loff_t * ppos)498ea4484dSLee Jones static ssize_t mbox_test_signal_write(struct file *filp,
508ea4484dSLee Jones const char __user *userbuf,
518ea4484dSLee Jones size_t count, loff_t *ppos)
528ea4484dSLee Jones {
538ea4484dSLee Jones struct mbox_test_device *tdev = filp->private_data;
548ea4484dSLee Jones
558ea4484dSLee Jones if (!tdev->tx_channel) {
568ea4484dSLee Jones dev_err(tdev->dev, "Channel cannot do Tx\n");
578ea4484dSLee Jones return -EINVAL;
588ea4484dSLee Jones }
598ea4484dSLee Jones
608ea4484dSLee Jones if (count > MBOX_MAX_SIG_LEN) {
618ea4484dSLee Jones dev_err(tdev->dev,
626c03663fSLee Jones "Signal length %zd greater than max allowed %d\n",
638ea4484dSLee Jones count, MBOX_MAX_SIG_LEN);
648ea4484dSLee Jones return -EINVAL;
658ea4484dSLee Jones }
668ea4484dSLee Jones
67d1c2f87cSLee Jones /* Only allocate memory if we need to */
68d1c2f87cSLee Jones if (!tdev->signal) {
698ea4484dSLee Jones tdev->signal = kzalloc(MBOX_MAX_SIG_LEN, GFP_KERNEL);
708ea4484dSLee Jones if (!tdev->signal)
718ea4484dSLee Jones return -ENOMEM;
72d1c2f87cSLee Jones }
738ea4484dSLee Jones
7417f5f28fSLee Jones if (copy_from_user(tdev->signal, userbuf, count)) {
758ea4484dSLee Jones kfree(tdev->signal);
7617f5f28fSLee Jones tdev->signal = NULL;
778ea4484dSLee Jones return -EFAULT;
788ea4484dSLee Jones }
798ea4484dSLee Jones
8017f5f28fSLee Jones return count;
818ea4484dSLee Jones }
828ea4484dSLee Jones
838ea4484dSLee Jones static const struct file_operations mbox_test_signal_ops = {
848ea4484dSLee Jones .write = mbox_test_signal_write,
858ea4484dSLee Jones .open = simple_open,
868ea4484dSLee Jones .llseek = generic_file_llseek,
878ea4484dSLee Jones };
888ea4484dSLee Jones
mbox_test_message_fasync(int fd,struct file * filp,int on)89baef9a35SSudeep Holla static int mbox_test_message_fasync(int fd, struct file *filp, int on)
90baef9a35SSudeep Holla {
91baef9a35SSudeep Holla struct mbox_test_device *tdev = filp->private_data;
92baef9a35SSudeep Holla
93baef9a35SSudeep Holla return fasync_helper(fd, filp, on, &tdev->async_queue);
94baef9a35SSudeep Holla }
95baef9a35SSudeep Holla
mbox_test_message_write(struct file * filp,const char __user * userbuf,size_t count,loff_t * ppos)968ea4484dSLee Jones static ssize_t mbox_test_message_write(struct file *filp,
978ea4484dSLee Jones const char __user *userbuf,
988ea4484dSLee Jones size_t count, loff_t *ppos)
998ea4484dSLee Jones {
1008ea4484dSLee Jones struct mbox_test_device *tdev = filp->private_data;
1018fe72b76SDan Carpenter char *message;
1028ea4484dSLee Jones void *data;
1038ea4484dSLee Jones int ret;
1048ea4484dSLee Jones
1058ea4484dSLee Jones if (!tdev->tx_channel) {
1068ea4484dSLee Jones dev_err(tdev->dev, "Channel cannot do Tx\n");
1078ea4484dSLee Jones return -EINVAL;
1088ea4484dSLee Jones }
1098ea4484dSLee Jones
1108ea4484dSLee Jones if (count > MBOX_MAX_MSG_LEN) {
1118ea4484dSLee Jones dev_err(tdev->dev,
1126c03663fSLee Jones "Message length %zd greater than max allowed %d\n",
1138ea4484dSLee Jones count, MBOX_MAX_MSG_LEN);
1148ea4484dSLee Jones return -EINVAL;
1158ea4484dSLee Jones }
1168ea4484dSLee Jones
1178fe72b76SDan Carpenter message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL);
1188fe72b76SDan Carpenter if (!message)
1198ea4484dSLee Jones return -ENOMEM;
1208ea4484dSLee Jones
1218fe72b76SDan Carpenter mutex_lock(&tdev->mutex);
1228fe72b76SDan Carpenter
1238fe72b76SDan Carpenter tdev->message = message;
1248ea4484dSLee Jones ret = copy_from_user(tdev->message, userbuf, count);
1258ea4484dSLee Jones if (ret) {
1268ea4484dSLee Jones ret = -EFAULT;
1278ea4484dSLee Jones goto out;
1288ea4484dSLee Jones }
1298ea4484dSLee Jones
1308ea4484dSLee Jones /*
1318ea4484dSLee Jones * A separate signal is only of use if there is
1328ea4484dSLee Jones * MMIO to subsequently pass the message through
1338ea4484dSLee Jones */
1342d74ffdcSSudeep Holla if (tdev->tx_mmio && tdev->signal) {
13527fa680fSSudeep Holla print_hex_dump_bytes("Client: Sending: Signal: ", DUMP_PREFIX_ADDRESS,
13627fa680fSSudeep Holla tdev->signal, MBOX_MAX_SIG_LEN);
1378ea4484dSLee Jones
1388ea4484dSLee Jones data = tdev->signal;
1398ea4484dSLee Jones } else
1408ea4484dSLee Jones data = tdev->message;
1418ea4484dSLee Jones
14227fa680fSSudeep Holla print_hex_dump_bytes("Client: Sending: Message: ", DUMP_PREFIX_ADDRESS,
14327fa680fSSudeep Holla tdev->message, MBOX_MAX_MSG_LEN);
1448ea4484dSLee Jones
1458ea4484dSLee Jones ret = mbox_send_message(tdev->tx_channel, data);
1468ea4484dSLee Jones if (ret < 0)
1478ea4484dSLee Jones dev_err(tdev->dev, "Failed to send message via mailbox\n");
1488ea4484dSLee Jones
1498ea4484dSLee Jones out:
1508ea4484dSLee Jones kfree(tdev->signal);
1518ea4484dSLee Jones kfree(tdev->message);
1529ef3c511SSudeep Holla tdev->signal = NULL;
1538ea4484dSLee Jones
1542d1e952aSLee Jones mutex_unlock(&tdev->mutex);
1552d1e952aSLee Jones
1568ea4484dSLee Jones return ret < 0 ? ret : count;
1578ea4484dSLee Jones }
1588ea4484dSLee Jones
mbox_test_message_data_ready(struct mbox_test_device * tdev)159baef9a35SSudeep Holla static bool mbox_test_message_data_ready(struct mbox_test_device *tdev)
160baef9a35SSudeep Holla {
161e339c80aSSudeep Holla bool data_ready;
162baef9a35SSudeep Holla unsigned long flags;
163baef9a35SSudeep Holla
164baef9a35SSudeep Holla spin_lock_irqsave(&tdev->lock, flags);
165e339c80aSSudeep Holla data_ready = mbox_data_ready;
166baef9a35SSudeep Holla spin_unlock_irqrestore(&tdev->lock, flags);
167baef9a35SSudeep Holla
168e339c80aSSudeep Holla return data_ready;
169baef9a35SSudeep Holla }
170baef9a35SSudeep Holla
mbox_test_message_read(struct file * filp,char __user * userbuf,size_t count,loff_t * ppos)1718ea4484dSLee Jones static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf,
1728ea4484dSLee Jones size_t count, loff_t *ppos)
1738ea4484dSLee Jones {
1748ea4484dSLee Jones struct mbox_test_device *tdev = filp->private_data;
1758ea4484dSLee Jones unsigned long flags;
1768ea4484dSLee Jones char *touser, *ptr;
1778ea4484dSLee Jones int l = 0;
1788ea4484dSLee Jones int ret;
1798ea4484dSLee Jones
180baef9a35SSudeep Holla DECLARE_WAITQUEUE(wait, current);
181baef9a35SSudeep Holla
182c3ac54a6SDan Carpenter touser = kzalloc(MBOX_HEXDUMP_MAX_LEN + 1, GFP_KERNEL);
1838ea4484dSLee Jones if (!touser)
1848ea4484dSLee Jones return -ENOMEM;
1858ea4484dSLee Jones
1868ea4484dSLee Jones if (!tdev->rx_channel) {
1878ea4484dSLee Jones ret = snprintf(touser, 20, "<NO RX CAPABILITY>\n");
1888ea4484dSLee Jones ret = simple_read_from_buffer(userbuf, count, ppos,
1898ea4484dSLee Jones touser, ret);
190baef9a35SSudeep Holla goto kfree_err;
1918ea4484dSLee Jones }
1928ea4484dSLee Jones
193baef9a35SSudeep Holla add_wait_queue(&tdev->waitq, &wait);
194baef9a35SSudeep Holla
195baef9a35SSudeep Holla do {
196baef9a35SSudeep Holla __set_current_state(TASK_INTERRUPTIBLE);
197baef9a35SSudeep Holla
198baef9a35SSudeep Holla if (mbox_test_message_data_ready(tdev))
199baef9a35SSudeep Holla break;
200baef9a35SSudeep Holla
201baef9a35SSudeep Holla if (filp->f_flags & O_NONBLOCK) {
202baef9a35SSudeep Holla ret = -EAGAIN;
203baef9a35SSudeep Holla goto waitq_err;
2048ea4484dSLee Jones }
2058ea4484dSLee Jones
206baef9a35SSudeep Holla if (signal_pending(current)) {
207baef9a35SSudeep Holla ret = -ERESTARTSYS;
208baef9a35SSudeep Holla goto waitq_err;
209baef9a35SSudeep Holla }
210baef9a35SSudeep Holla schedule();
211baef9a35SSudeep Holla
212baef9a35SSudeep Holla } while (1);
213baef9a35SSudeep Holla
2148ea4484dSLee Jones spin_lock_irqsave(&tdev->lock, flags);
2158ea4484dSLee Jones
2168ea4484dSLee Jones ptr = tdev->rx_buffer;
2178ea4484dSLee Jones while (l < MBOX_HEXDUMP_MAX_LEN) {
2188ea4484dSLee Jones hex_dump_to_buffer(ptr,
2198ea4484dSLee Jones MBOX_BYTES_PER_LINE,
2208ea4484dSLee Jones MBOX_BYTES_PER_LINE, 1, touser + l,
2218ea4484dSLee Jones MBOX_HEXDUMP_LINE_LEN, true);
2228ea4484dSLee Jones
2238ea4484dSLee Jones ptr += MBOX_BYTES_PER_LINE;
2248ea4484dSLee Jones l += MBOX_HEXDUMP_LINE_LEN;
2258ea4484dSLee Jones *(touser + (l - 1)) = '\n';
2268ea4484dSLee Jones }
2278ea4484dSLee Jones *(touser + l) = '\0';
2288ea4484dSLee Jones
2298ea4484dSLee Jones memset(tdev->rx_buffer, 0, MBOX_MAX_MSG_LEN);
230e339c80aSSudeep Holla mbox_data_ready = false;
2318ea4484dSLee Jones
2328ea4484dSLee Jones spin_unlock_irqrestore(&tdev->lock, flags);
2338ea4484dSLee Jones
2348ea4484dSLee Jones ret = simple_read_from_buffer(userbuf, count, ppos, touser, MBOX_HEXDUMP_MAX_LEN);
235baef9a35SSudeep Holla waitq_err:
236baef9a35SSudeep Holla __set_current_state(TASK_RUNNING);
237baef9a35SSudeep Holla remove_wait_queue(&tdev->waitq, &wait);
238baef9a35SSudeep Holla kfree_err:
2398ea4484dSLee Jones kfree(touser);
2408ea4484dSLee Jones return ret;
2418ea4484dSLee Jones }
2428ea4484dSLee Jones
243afc9a42bSAl Viro static __poll_t
mbox_test_message_poll(struct file * filp,struct poll_table_struct * wait)244baef9a35SSudeep Holla mbox_test_message_poll(struct file *filp, struct poll_table_struct *wait)
245baef9a35SSudeep Holla {
246baef9a35SSudeep Holla struct mbox_test_device *tdev = filp->private_data;
247baef9a35SSudeep Holla
248baef9a35SSudeep Holla poll_wait(filp, &tdev->waitq, wait);
249baef9a35SSudeep Holla
250baef9a35SSudeep Holla if (mbox_test_message_data_ready(tdev))
251a9a08845SLinus Torvalds return EPOLLIN | EPOLLRDNORM;
252baef9a35SSudeep Holla return 0;
253baef9a35SSudeep Holla }
254baef9a35SSudeep Holla
2558ea4484dSLee Jones static const struct file_operations mbox_test_message_ops = {
2568ea4484dSLee Jones .write = mbox_test_message_write,
2578ea4484dSLee Jones .read = mbox_test_message_read,
258baef9a35SSudeep Holla .fasync = mbox_test_message_fasync,
259baef9a35SSudeep Holla .poll = mbox_test_message_poll,
2608ea4484dSLee Jones .open = simple_open,
2618ea4484dSLee Jones .llseek = generic_file_llseek,
2628ea4484dSLee Jones };
2638ea4484dSLee Jones
mbox_test_add_debugfs(struct platform_device * pdev,struct mbox_test_device * tdev)2648ea4484dSLee Jones static int mbox_test_add_debugfs(struct platform_device *pdev,
2658ea4484dSLee Jones struct mbox_test_device *tdev)
2668ea4484dSLee Jones {
2678ea4484dSLee Jones if (!debugfs_initialized())
2688ea4484dSLee Jones return 0;
2698ea4484dSLee Jones
27010cfc5a9SFabien Dessenne tdev->root_debugfs_dir = debugfs_create_dir(dev_name(&pdev->dev), NULL);
27110cfc5a9SFabien Dessenne if (!tdev->root_debugfs_dir) {
2728ea4484dSLee Jones dev_err(&pdev->dev, "Failed to create Mailbox debugfs\n");
2738ea4484dSLee Jones return -EINVAL;
2748ea4484dSLee Jones }
2758ea4484dSLee Jones
27610cfc5a9SFabien Dessenne debugfs_create_file("message", 0600, tdev->root_debugfs_dir,
2778ea4484dSLee Jones tdev, &mbox_test_message_ops);
2788ea4484dSLee Jones
27910cfc5a9SFabien Dessenne debugfs_create_file("signal", 0200, tdev->root_debugfs_dir,
2808ea4484dSLee Jones tdev, &mbox_test_signal_ops);
2818ea4484dSLee Jones
2828ea4484dSLee Jones return 0;
2838ea4484dSLee Jones }
2848ea4484dSLee Jones
mbox_test_receive_message(struct mbox_client * client,void * message)2858ea4484dSLee Jones static void mbox_test_receive_message(struct mbox_client *client, void *message)
2868ea4484dSLee Jones {
2878ea4484dSLee Jones struct mbox_test_device *tdev = dev_get_drvdata(client->dev);
2888ea4484dSLee Jones unsigned long flags;
2898ea4484dSLee Jones
2908ea4484dSLee Jones spin_lock_irqsave(&tdev->lock, flags);
2912d74ffdcSSudeep Holla if (tdev->rx_mmio) {
2922d74ffdcSSudeep Holla memcpy_fromio(tdev->rx_buffer, tdev->rx_mmio, MBOX_MAX_MSG_LEN);
29327fa680fSSudeep Holla print_hex_dump_bytes("Client: Received [MMIO]: ", DUMP_PREFIX_ADDRESS,
29427fa680fSSudeep Holla tdev->rx_buffer, MBOX_MAX_MSG_LEN);
2958ea4484dSLee Jones } else if (message) {
29627fa680fSSudeep Holla print_hex_dump_bytes("Client: Received [API]: ", DUMP_PREFIX_ADDRESS,
29727fa680fSSudeep Holla message, MBOX_MAX_MSG_LEN);
2988ea4484dSLee Jones memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN);
2998ea4484dSLee Jones }
300e339c80aSSudeep Holla mbox_data_ready = true;
3018ea4484dSLee Jones spin_unlock_irqrestore(&tdev->lock, flags);
302baef9a35SSudeep Holla
303baef9a35SSudeep Holla wake_up_interruptible(&tdev->waitq);
304baef9a35SSudeep Holla
305baef9a35SSudeep Holla kill_fasync(&tdev->async_queue, SIGIO, POLL_IN);
3068ea4484dSLee Jones }
3078ea4484dSLee Jones
mbox_test_prepare_message(struct mbox_client * client,void * message)3088ea4484dSLee Jones static void mbox_test_prepare_message(struct mbox_client *client, void *message)
3098ea4484dSLee Jones {
3108ea4484dSLee Jones struct mbox_test_device *tdev = dev_get_drvdata(client->dev);
3118ea4484dSLee Jones
3122d74ffdcSSudeep Holla if (tdev->tx_mmio) {
3138ea4484dSLee Jones if (tdev->signal)
3142d74ffdcSSudeep Holla memcpy_toio(tdev->tx_mmio, tdev->message, MBOX_MAX_MSG_LEN);
3158ea4484dSLee Jones else
3162d74ffdcSSudeep Holla memcpy_toio(tdev->tx_mmio, message, MBOX_MAX_MSG_LEN);
3178ea4484dSLee Jones }
3188ea4484dSLee Jones }
3198ea4484dSLee Jones
mbox_test_message_sent(struct mbox_client * client,void * message,int r)3208ea4484dSLee Jones static void mbox_test_message_sent(struct mbox_client *client,
3218ea4484dSLee Jones void *message, int r)
3228ea4484dSLee Jones {
3238ea4484dSLee Jones if (r)
3248ea4484dSLee Jones dev_warn(client->dev,
3258ea4484dSLee Jones "Client: Message could not be sent: %d\n", r);
3268ea4484dSLee Jones else
3278ea4484dSLee Jones dev_info(client->dev,
3288ea4484dSLee Jones "Client: Message sent\n");
3298ea4484dSLee Jones }
3308ea4484dSLee Jones
3318ea4484dSLee Jones static struct mbox_chan *
mbox_test_request_channel(struct platform_device * pdev,const char * name)3328ea4484dSLee Jones mbox_test_request_channel(struct platform_device *pdev, const char *name)
3338ea4484dSLee Jones {
3348ea4484dSLee Jones struct mbox_client *client;
3358ea4484dSLee Jones struct mbox_chan *channel;
3368ea4484dSLee Jones
3378ea4484dSLee Jones client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL);
3388ea4484dSLee Jones if (!client)
3398ea4484dSLee Jones return ERR_PTR(-ENOMEM);
3408ea4484dSLee Jones
3418ea4484dSLee Jones client->dev = &pdev->dev;
3428ea4484dSLee Jones client->rx_callback = mbox_test_receive_message;
3438ea4484dSLee Jones client->tx_prepare = mbox_test_prepare_message;
3448ea4484dSLee Jones client->tx_done = mbox_test_message_sent;
3458ea4484dSLee Jones client->tx_block = true;
3468ea4484dSLee Jones client->knows_txdone = false;
3478ea4484dSLee Jones client->tx_tout = 500;
3488ea4484dSLee Jones
3498ea4484dSLee Jones channel = mbox_request_channel_byname(client, name);
3508ea4484dSLee Jones if (IS_ERR(channel)) {
3518ea4484dSLee Jones dev_warn(&pdev->dev, "Failed to request %s channel\n", name);
3528ea4484dSLee Jones return NULL;
3538ea4484dSLee Jones }
3548ea4484dSLee Jones
3558ea4484dSLee Jones return channel;
3568ea4484dSLee Jones }
3578ea4484dSLee Jones
mbox_test_probe(struct platform_device * pdev)3588ea4484dSLee Jones static int mbox_test_probe(struct platform_device *pdev)
3598ea4484dSLee Jones {
3608ea4484dSLee Jones struct mbox_test_device *tdev;
3618ea4484dSLee Jones struct resource *res;
362db4d22c0SSudeep Holla resource_size_t size;
3638ea4484dSLee Jones int ret;
3648ea4484dSLee Jones
3658ea4484dSLee Jones tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL);
3668ea4484dSLee Jones if (!tdev)
3678ea4484dSLee Jones return -ENOMEM;
3688ea4484dSLee Jones
3698ea4484dSLee Jones /* It's okay for MMIO to be NULL */
370f7fdb53cSYangtao Li tdev->tx_mmio = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
3716899b4f7SFabien Dessenne if (PTR_ERR(tdev->tx_mmio) == -EBUSY) {
372db4d22c0SSudeep Holla /* if reserved area in SRAM, try just ioremap */
3736899b4f7SFabien Dessenne size = resource_size(res);
374db4d22c0SSudeep Holla tdev->tx_mmio = devm_ioremap(&pdev->dev, res->start, size);
3756899b4f7SFabien Dessenne } else if (IS_ERR(tdev->tx_mmio)) {
3762d74ffdcSSudeep Holla tdev->tx_mmio = NULL;
3776899b4f7SFabien Dessenne }
3782d74ffdcSSudeep Holla
3792d74ffdcSSudeep Holla /* If specified, second reg entry is Rx MMIO */
380f7fdb53cSYangtao Li tdev->rx_mmio = devm_platform_get_and_ioremap_resource(pdev, 1, &res);
3816899b4f7SFabien Dessenne if (PTR_ERR(tdev->rx_mmio) == -EBUSY) {
3826899b4f7SFabien Dessenne size = resource_size(res);
383db4d22c0SSudeep Holla tdev->rx_mmio = devm_ioremap(&pdev->dev, res->start, size);
3846899b4f7SFabien Dessenne } else if (IS_ERR(tdev->rx_mmio)) {
3852d74ffdcSSudeep Holla tdev->rx_mmio = tdev->tx_mmio;
3866899b4f7SFabien Dessenne }
3878ea4484dSLee Jones
3888ea4484dSLee Jones tdev->tx_channel = mbox_test_request_channel(pdev, "tx");
3898ea4484dSLee Jones tdev->rx_channel = mbox_test_request_channel(pdev, "rx");
3908ea4484dSLee Jones
391*9b63a810SMinjie Du if (IS_ERR_OR_NULL(tdev->tx_channel) && IS_ERR_OR_NULL(tdev->rx_channel))
3928ea4484dSLee Jones return -EPROBE_DEFER;
3938ea4484dSLee Jones
3942d74ffdcSSudeep Holla /* If Rx is not specified but has Rx MMIO, then Rx = Tx */
3952d74ffdcSSudeep Holla if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio))
3962d74ffdcSSudeep Holla tdev->rx_channel = tdev->tx_channel;
3972d74ffdcSSudeep Holla
3988ea4484dSLee Jones tdev->dev = &pdev->dev;
3998ea4484dSLee Jones platform_set_drvdata(pdev, tdev);
4008ea4484dSLee Jones
4018ea4484dSLee Jones spin_lock_init(&tdev->lock);
4022d1e952aSLee Jones mutex_init(&tdev->mutex);
4038ea4484dSLee Jones
4048ea4484dSLee Jones if (tdev->rx_channel) {
4058ea4484dSLee Jones tdev->rx_buffer = devm_kzalloc(&pdev->dev,
4068ea4484dSLee Jones MBOX_MAX_MSG_LEN, GFP_KERNEL);
4078ea4484dSLee Jones if (!tdev->rx_buffer)
4088ea4484dSLee Jones return -ENOMEM;
4098ea4484dSLee Jones }
4108ea4484dSLee Jones
4118ea4484dSLee Jones ret = mbox_test_add_debugfs(pdev, tdev);
4128ea4484dSLee Jones if (ret)
4138ea4484dSLee Jones return ret;
4148ea4484dSLee Jones
415baef9a35SSudeep Holla init_waitqueue_head(&tdev->waitq);
4168ea4484dSLee Jones dev_info(&pdev->dev, "Successfully registered\n");
4178ea4484dSLee Jones
4188ea4484dSLee Jones return 0;
4198ea4484dSLee Jones }
4208ea4484dSLee Jones
mbox_test_remove(struct platform_device * pdev)4218ea4484dSLee Jones static int mbox_test_remove(struct platform_device *pdev)
4228ea4484dSLee Jones {
4238ea4484dSLee Jones struct mbox_test_device *tdev = platform_get_drvdata(pdev);
4248ea4484dSLee Jones
42510cfc5a9SFabien Dessenne debugfs_remove_recursive(tdev->root_debugfs_dir);
4268ea4484dSLee Jones
4278ea4484dSLee Jones if (tdev->tx_channel)
4288ea4484dSLee Jones mbox_free_channel(tdev->tx_channel);
4298ea4484dSLee Jones if (tdev->rx_channel)
4308ea4484dSLee Jones mbox_free_channel(tdev->rx_channel);
4318ea4484dSLee Jones
4328ea4484dSLee Jones return 0;
4338ea4484dSLee Jones }
4348ea4484dSLee Jones
4358ea4484dSLee Jones static const struct of_device_id mbox_test_match[] = {
436c4280137SSudeep Holla { .compatible = "mailbox-test" },
4378ea4484dSLee Jones {},
4388ea4484dSLee Jones };
439f42cce3cSJavier Martinez Canillas MODULE_DEVICE_TABLE(of, mbox_test_match);
4408ea4484dSLee Jones
4418ea4484dSLee Jones static struct platform_driver mbox_test_driver = {
4428ea4484dSLee Jones .driver = {
443adf06ba9SSudeep Holla .name = "mailbox_test",
4448ea4484dSLee Jones .of_match_table = mbox_test_match,
4458ea4484dSLee Jones },
4468ea4484dSLee Jones .probe = mbox_test_probe,
4478ea4484dSLee Jones .remove = mbox_test_remove,
4488ea4484dSLee Jones };
4498ea4484dSLee Jones module_platform_driver(mbox_test_driver);
4508ea4484dSLee Jones
4518ea4484dSLee Jones MODULE_DESCRIPTION("Generic Mailbox Testing Facility");
4528ea4484dSLee Jones MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org");
4538ea4484dSLee Jones MODULE_LICENSE("GPL v2");
454