1 // SPDX-License-Identifier: GPL-2.0+
4 * Author: Daniel Baluta <daniel.baluta@nxp.com>
6 * Implementation of the DSP IPC interface (host side)
9 #include <linux/firmware/imx/dsp.h>
10 #include <linux/kernel.h>
11 #include <linux/mailbox_client.h>
12 #include <linux/module.h>
13 #include <linux/of_platform.h>
14 #include <linux/platform_device.h>
15 #include <linux/slab.h>
18 * imx_dsp_ring_doorbell - triggers an interrupt on the other side (DSP)
20 * @dsp: DSP IPC handle
21 * @chan_idx: index of the channel where to trigger the interrupt
23 * Returns non-negative value for success, negative value for error
25 int imx_dsp_ring_doorbell(struct imx_dsp_ipc
*ipc
, unsigned int idx
)
28 struct imx_dsp_chan
*dsp_chan
;
30 if (idx
>= DSP_MU_CHAN_NUM
)
33 dsp_chan
= &ipc
->chans
[idx
];
34 ret
= mbox_send_message(dsp_chan
->ch
, NULL
);
40 EXPORT_SYMBOL(imx_dsp_ring_doorbell
);
43 * imx_dsp_handle_rx - rx callback used by imx mailbox
46 * @msg: message received
48 * Users of DSP IPC will need to privde handle_reply and handle_request
51 static void imx_dsp_handle_rx(struct mbox_client
*c
, void *msg
)
53 struct imx_dsp_chan
*chan
= container_of(c
, struct imx_dsp_chan
, cl
);
56 chan
->ipc
->ops
->handle_reply(chan
->ipc
);
58 chan
->ipc
->ops
->handle_request(chan
->ipc
);
59 imx_dsp_ring_doorbell(chan
->ipc
, 1);
63 static int imx_dsp_probe(struct platform_device
*pdev
)
65 struct device
*dev
= &pdev
->dev
;
66 struct imx_dsp_ipc
*dsp_ipc
;
67 struct imx_dsp_chan
*dsp_chan
;
68 struct mbox_client
*cl
;
73 device_set_of_node_from_dev(&pdev
->dev
, pdev
->dev
.parent
);
75 dsp_ipc
= devm_kzalloc(dev
, sizeof(*dsp_ipc
), GFP_KERNEL
);
79 for (i
= 0; i
< DSP_MU_CHAN_NUM
; i
++) {
81 chan_name
= kasprintf(GFP_KERNEL
, "txdb%d", i
);
83 chan_name
= kasprintf(GFP_KERNEL
, "rxdb%d", i
- 2);
88 dsp_chan
= &dsp_ipc
->chans
[i
];
92 cl
->knows_txdone
= true;
93 cl
->rx_callback
= imx_dsp_handle_rx
;
95 dsp_chan
->ipc
= dsp_ipc
;
96 dsp_chan
->idx
= i
% 2;
97 dsp_chan
->ch
= mbox_request_channel_byname(cl
, chan_name
);
98 if (IS_ERR(dsp_chan
->ch
)) {
99 ret
= PTR_ERR(dsp_chan
->ch
);
100 if (ret
!= -EPROBE_DEFER
)
101 dev_err(dev
, "Failed to request mbox chan %s ret %d\n",
106 dev_dbg(dev
, "request mbox chan %s\n", chan_name
);
107 /* chan_name is not used anymore by framework */
113 dev_set_drvdata(dev
, dsp_ipc
);
115 dev_info(dev
, "NXP i.MX DSP IPC initialized\n");
120 for (j
= 0; j
< i
; j
++) {
121 dsp_chan
= &dsp_ipc
->chans
[j
];
122 mbox_free_channel(dsp_chan
->ch
);
128 static int imx_dsp_remove(struct platform_device
*pdev
)
130 struct imx_dsp_chan
*dsp_chan
;
131 struct imx_dsp_ipc
*dsp_ipc
;
134 dsp_ipc
= dev_get_drvdata(&pdev
->dev
);
136 for (i
= 0; i
< DSP_MU_CHAN_NUM
; i
++) {
137 dsp_chan
= &dsp_ipc
->chans
[i
];
138 mbox_free_channel(dsp_chan
->ch
);
144 static struct platform_driver imx_dsp_driver
= {
148 .probe
= imx_dsp_probe
,
149 .remove
= imx_dsp_remove
,
151 builtin_platform_driver(imx_dsp_driver
);
153 MODULE_AUTHOR("Daniel Baluta <daniel.baluta@nxp.com>");
154 MODULE_DESCRIPTION("IMX DSP IPC protocol driver");
155 MODULE_LICENSE("GPL v2");