1 /* Copyright (c) 2015, The Linux Foundation. All rights reserved.
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/types.h>
16 #include <linux/uaccess.h>
17 #include <linux/spinlock.h>
18 #include <linux/mutex.h>
19 #include <linux/list.h>
20 #include <linux/sched.h>
21 #include <linux/wait.h>
22 #include <linux/errno.h>
23 #include <linux/platform_device.h>
24 #include <linux/delay.h>
25 #include <sound/qdsp6v2/apr_tal.h>
26 #include <linux/soc/qcom/smd.h>
29 struct apr_svc_ch_dev apr_svc_ch[APR_DL_MAX][APR_DEST_MAX][APR_CLIENT_MAX];
31 int apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data, int len)
34 ret = qcom_smd_send(apr_ch->ch, data, len);
36 pr_err("apr_tal: Error in write %d\n", ret);
42 struct apr_svc_ch_dev *apr_tal_open(uint32_t svc, uint32_t dest,
43 uint32_t dl, apr_svc_cb_fn func, void *priv)
46 pr_err("apr_tal:open\n");
47 if ((svc >= APR_CLIENT_MAX) || (dest >= APR_DEST_MAX) ||
49 pr_err("apr_tal: Invalid params\n");
53 if (apr_svc_ch[dl][dest][svc].ch) {
54 pr_err("apr_tal: This channel alreday openend\n");
58 if (!apr_svc_ch[dl][dest][svc].dest_state) {
59 rc = wait_event_timeout(apr_svc_ch[dl][dest][svc].dest,
60 apr_svc_ch[dl][dest][svc].dest_state,
61 msecs_to_jiffies(APR_OPEN_TIMEOUT_MS));
63 pr_err("apr_tal:open timeout\n");
66 pr_info("apr_tal:Wakeup done\n");
67 apr_svc_ch[dl][dest][svc].dest_state = 0;
70 rc = wait_event_timeout(apr_svc_ch[dl][dest][svc].wait,
71 (apr_svc_ch[dl][dest][svc].ch->state == SMD_CHANNEL_OPENED), 5 * HZ);
73 pr_err("apr_tal:TIMEOUT for OPEN event\n");
74 apr_tal_close(&apr_svc_ch[dl][dest][svc]);
77 if (!apr_svc_ch[dl][dest][svc].dest_state) {
78 apr_svc_ch[dl][dest][svc].dest_state = 1;
79 pr_info("apr_tal:Waiting for apr svc init\n");
81 pr_info("apr_tal:apr svc init done\n");
83 apr_svc_ch[dl][dest][svc].func = func;
84 apr_svc_ch[dl][dest][svc].priv = priv;
87 return &apr_svc_ch[dl][dest][svc];
90 int apr_tal_close(struct apr_svc_ch_dev *apr_ch)
102 static int qcom_smd_q6_callback(struct qcom_smd_device *sdev,
106 struct apr_svc_ch_dev *apr_ch = dev_get_drvdata(&sdev->dev);
108 memcpy_fromio(apr_ch->data, data, count);
111 apr_ch->func(apr_ch->data, count, apr_ch->priv);
116 static int qcom_smd_q6_probe(struct qcom_smd_device *sdev)
118 int dest = APR_DEST_QDSP6;
119 int clnt = APR_CLIENT_AUDIO;
121 apr_svc_ch[APR_DL_SMD][APR_DEST_QDSP6][APR_CLIENT_AUDIO].ch = sdev->channel;
123 pr_info("apr_tal:Q6 Is Up\n");
124 apr_svc_ch[APR_DL_SMD][dest][clnt].dest_state = 1;
125 wake_up(&apr_svc_ch[APR_DL_SMD][dest][clnt].dest);
127 dev_set_drvdata(&sdev->dev, &apr_svc_ch[APR_DL_SMD][APR_DEST_QDSP6][APR_CLIENT_AUDIO]);
132 static void qcom_smd_q6_remove(struct qcom_smd_device *sdev)
137 static const struct of_device_id qcom_smd_q6_of_match[] = {
138 { .compatible = "qcom,apr" },
142 static struct qcom_smd_driver qcom_smd_q6_driver = {
143 .probe = qcom_smd_q6_probe,
144 .remove = qcom_smd_q6_remove,
145 .callback = qcom_smd_q6_callback,
147 .name = "qcom_smd_q6",
148 .owner = THIS_MODULE,
149 .of_match_table = qcom_smd_q6_of_match,
153 static void __exit qcom_smd_q6_exit(void)
155 qcom_smd_driver_unregister(&qcom_smd_q6_driver);
157 module_exit(qcom_smd_q6_exit);
159 static int __init apr_tal_init(void)
164 for (i = 0; i < APR_DL_MAX; i++)
165 for (j = 0; j < APR_DEST_MAX; j++)
166 for (k = 0; k < APR_CLIENT_MAX; k++) {
167 init_waitqueue_head(&apr_svc_ch[i][j][k].wait);
168 init_waitqueue_head(&apr_svc_ch[i][j][k].dest);
170 qcom_smd_driver_register(&qcom_smd_q6_driver);
173 device_initcall(apr_tal_init);
175 MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
176 MODULE_DESCRIPTION("Qualcomm SMD backed apr driver");
177 MODULE_LICENSE("GPL v2");