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
= PTR_ERR(adsp_chan
->ch
);
99 if (ret
!= -EPROBE_DEFER
)
100 dev_err(dev
, "Failed to request mbox chan %s ret %d\n",
101 adsp_mbox_ch_names
[i
], ret
);
103 for (j
= 0; j
< i
; j
++) {
104 adsp_chan
= &adsp_ipc
->chans
[j
];
105 mbox_free_channel(adsp_chan
->ch
);
113 dev_set_drvdata(dev
, adsp_ipc
);
114 dev_dbg(dev
, "MTK ADSP IPC initialized\n");
119 static void mtk_adsp_ipc_remove(struct platform_device
*pdev
)
121 struct mtk_adsp_ipc
*adsp_ipc
= dev_get_drvdata(&pdev
->dev
);
122 struct mtk_adsp_chan
*adsp_chan
;
125 for (i
= 0; i
< MTK_ADSP_MBOX_NUM
; i
++) {
126 adsp_chan
= &adsp_ipc
->chans
[i
];
127 mbox_free_channel(adsp_chan
->ch
);
131 static struct platform_driver mtk_adsp_ipc_driver
= {
133 .name
= "mtk-adsp-ipc",
135 .probe
= mtk_adsp_ipc_probe
,
136 .remove_new
= mtk_adsp_ipc_remove
,
138 builtin_platform_driver(mtk_adsp_ipc_driver
);
140 MODULE_AUTHOR("Allen-KH Cheng <allen-kh.cheng@mediatek.com>");
141 MODULE_DESCRIPTION("MTK ADSP IPC Driver");
142 MODULE_LICENSE("GPL");