]> git.karo-electronics.de Git - karo-tx-linux.git/blob - sound/soc/qcom/qdsp6/core/apr_tal.c
Bluetooth: Introduce Qualcomm WCNSS SMD based HCI driver
[karo-tx-linux.git] / sound / soc / qcom / qdsp6 / core / apr_tal.c
1 /* Copyright (c) 2015, The Linux Foundation. All rights reserved.
2  *
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.
6  *
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.
11  */
12
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>
27 #include <linux/io.h>
28
29 struct apr_svc_ch_dev apr_svc_ch[APR_DL_MAX][APR_DEST_MAX][APR_CLIENT_MAX];
30
31 int apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data, int len)
32 {
33         int ret;
34         ret = qcom_smd_send(apr_ch->ch, data, len);
35         if (ret) { 
36                 pr_err("apr_tal: Error in write %d\n", ret);
37                 return ret;;
38         }
39         return len;
40 }
41
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)
44 {
45         int rc;
46         pr_err("apr_tal:open\n");
47         if ((svc >= APR_CLIENT_MAX) || (dest >= APR_DEST_MAX) ||
48                                                 (dl >= APR_DL_MAX)) {
49                 pr_err("apr_tal: Invalid params\n");
50                 return NULL;
51         }
52
53         if (apr_svc_ch[dl][dest][svc].ch) {
54                 pr_err("apr_tal: This channel alreday openend\n");
55                 return NULL;
56         }
57
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));
62                 if (rc == 0) {
63                         pr_err("apr_tal:open timeout\n");
64                         return NULL;
65                 }
66                 pr_info("apr_tal:Wakeup done\n");
67                 apr_svc_ch[dl][dest][svc].dest_state = 0;
68         }
69
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);
72         if (rc == 0) {
73                 pr_err("apr_tal:TIMEOUT for OPEN event\n");
74                 apr_tal_close(&apr_svc_ch[dl][dest][svc]);
75                 return NULL;
76         }
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");
80                 msleep(200);
81                 pr_info("apr_tal:apr svc init done\n");
82         }
83         apr_svc_ch[dl][dest][svc].func = func;
84         apr_svc_ch[dl][dest][svc].priv = priv;
85
86
87         return &apr_svc_ch[dl][dest][svc];
88 }
89
90 int apr_tal_close(struct apr_svc_ch_dev *apr_ch)
91 {
92         if (!apr_ch->ch)
93                 return -EINVAL;
94
95         apr_ch->ch = NULL;
96         apr_ch->func = NULL;
97         apr_ch->priv = NULL;
98         return 0;
99 }
100
101
102 static int qcom_smd_q6_callback(struct qcom_smd_device *sdev,
103                                  const void *data,
104                                  size_t count)
105 {
106         struct apr_svc_ch_dev *apr_ch = dev_get_drvdata(&sdev->dev);
107
108         memcpy_fromio(apr_ch->data, data, count);
109
110         if (apr_ch->func)
111                 apr_ch->func(apr_ch->data, count, apr_ch->priv);
112
113         return 0;
114 }
115
116 static int qcom_smd_q6_probe(struct qcom_smd_device *sdev)
117 {
118         int dest = APR_DEST_QDSP6;
119         int clnt = APR_CLIENT_AUDIO;
120
121         apr_svc_ch[APR_DL_SMD][APR_DEST_QDSP6][APR_CLIENT_AUDIO].ch = sdev->channel;
122
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);
126
127         dev_set_drvdata(&sdev->dev, &apr_svc_ch[APR_DL_SMD][APR_DEST_QDSP6][APR_CLIENT_AUDIO]);
128
129         return 0;
130 }
131
132 static void qcom_smd_q6_remove(struct qcom_smd_device *sdev)
133 {
134 }
135
136
137 static const struct of_device_id qcom_smd_q6_of_match[] = {
138         { .compatible = "qcom,apr" },
139         {}
140 };
141
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,
146         .driver  = {
147                 .name  = "qcom_smd_q6",
148                 .owner = THIS_MODULE,
149                 .of_match_table = qcom_smd_q6_of_match,
150         },
151 };
152
153 static void __exit qcom_smd_q6_exit(void)
154 {
155         qcom_smd_driver_unregister(&qcom_smd_q6_driver);
156 }
157 module_exit(qcom_smd_q6_exit);
158
159 static int __init apr_tal_init(void)
160 {
161
162         int i, j, k;
163
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);
169                         }
170         qcom_smd_driver_register(&qcom_smd_q6_driver);
171         return 0;
172 }
173 device_initcall(apr_tal_init);
174
175 MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
176 MODULE_DESCRIPTION("Qualcomm SMD backed apr driver");
177 MODULE_LICENSE("GPL v2");