1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2022 MediaTek Corporation. All rights reserved.
4 * Author: Allen-KH Cheng <allen-kh.cheng@mediatek.com>
7 #include <linux/firmware/mediatek/mtk-adsp-ipc.h>
8 #include <linux/kernel.h>
9 #include <linux/mailbox_client.h>
10 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 #include <linux/slab.h>
14 static const char * const adsp_mbox_ch_names
[MTK_ADSP_MBOX_NUM
] = { "rx", "tx" };
17 * mtk_adsp_ipc_send - send ipc cmd to MTK ADSP
19 * @ipc: ADSP IPC handle
20 * @idx: index of the mailbox channel
21 * @msg: IPC cmd (reply or request)
23 * Returns zero for success from mbox_send_message
24 * negative value for error
26 int mtk_adsp_ipc_send(struct mtk_adsp_ipc
*ipc
, unsigned int idx
, uint32_t msg
)
28 struct mtk_adsp_chan
*adsp_chan
;
31 if (idx
>= MTK_ADSP_MBOX_NUM
)
34 adsp_chan
= &ipc
->chans
[idx
];
35 ret
= mbox_send_message(adsp_chan
->ch
, &msg
);
41 EXPORT_SYMBOL_GPL(mtk_adsp_ipc_send
);
44 * mtk_adsp_ipc_recv - recv callback used by MTK ADSP mailbox
47 * @msg: message received
49 * Users of ADSP IPC will need to privde handle_reply and handle_request
52 static void mtk_adsp_ipc_recv(struct mbox_client
*c
, void *msg
)
54 struct mtk_adsp_chan
*chan
= container_of(c
, struct mtk_adsp_chan
, cl
);
55 struct device
*dev
= c
->dev
;
58 case MTK_ADSP_MBOX_REPLY
:
59 chan
->ipc
->ops
->handle_reply(chan
->ipc
);
61 case MTK_ADSP_MBOX_REQUEST
:
62 chan
->ipc
->ops
->handle_request(chan
->ipc
);
65 dev_err(dev
, "wrong mbox chan %d\n", chan
->idx
);
70 static int mtk_adsp_ipc_probe(struct platform_device
*pdev
)
72 struct device
*dev
= &pdev
->dev
;
73 struct mtk_adsp_ipc
*adsp_ipc
;
74 struct mtk_adsp_chan
*adsp_chan
;
75 struct mbox_client
*cl
;
79 device_set_of_node_from_dev(&pdev
->dev
, pdev
->dev
.parent
);
81 adsp_ipc
= devm_kzalloc(dev
, sizeof(*adsp_ipc
), GFP_KERNEL
);
85 for (i
= 0; i
< MTK_ADSP_MBOX_NUM
; i
++) {
86 adsp_chan
= &adsp_ipc
->chans
[i
];
88 cl
->dev
= dev
->parent
;
90 cl
->knows_txdone
= false;
91 cl
->tx_prepare
= NULL
;
92 cl
->rx_callback
= mtk_adsp_ipc_recv
;
94 adsp_chan
->ipc
= adsp_ipc
;
96 adsp_chan
->ch
= mbox_request_channel_byname(cl
, adsp_mbox_ch_names
[i
]);
97 if (IS_ERR(adsp_chan
->ch
)) {
98 ret
= dev_err_probe(dev
, PTR_ERR(adsp_chan
->ch
),
99 "Failed to request mbox channel %s\n",
100 adsp_mbox_ch_names
[i
]);
102 for (j
= 0; j
< i
; j
++) {
103 adsp_chan
= &adsp_ipc
->chans
[j
];
104 mbox_free_channel(adsp_chan
->ch
);
112 dev_set_drvdata(dev
, adsp_ipc
);
113 dev_dbg(dev
, "MTK ADSP IPC initialized\n");
118 static void mtk_adsp_ipc_remove(struct platform_device
*pdev
)
120 struct mtk_adsp_ipc
*adsp_ipc
= dev_get_drvdata(&pdev
->dev
);
121 struct mtk_adsp_chan
*adsp_chan
;
124 for (i
= 0; i
< MTK_ADSP_MBOX_NUM
; i
++) {
125 adsp_chan
= &adsp_ipc
->chans
[i
];
126 mbox_free_channel(adsp_chan
->ch
);
130 static struct platform_driver mtk_adsp_ipc_driver
= {
132 .name
= "mtk-adsp-ipc",
134 .probe
= mtk_adsp_ipc_probe
,
135 .remove
= mtk_adsp_ipc_remove
,
137 builtin_platform_driver(mtk_adsp_ipc_driver
);
139 MODULE_AUTHOR("Allen-KH Cheng <allen-kh.cheng@mediatek.com>");
140 MODULE_DESCRIPTION("MTK ADSP IPC Driver");
141 MODULE_LICENSE("GPL");