blob: 75f3bbb5062be5e5704b7b54dd1062eec4e0df24 [file] [log] [blame]
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301/* Copyright (c) 2016-2017, 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/module.h>
14#include <linux/slab.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053015#include <soc/qcom/service-locator.h>
16#include <soc/qcom/service-notifier.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053017#include "audio_pdr.h"
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053018
19static struct pd_qmi_client_data audio_pdr_services[AUDIO_PDR_DOMAIN_MAX] = {
20 { /* AUDIO_PDR_DOMAIN_ADSP */
21 .client_name = "audio_pdr_adsp",
22 .service_name = "avs/audio"
23 }
24};
25
26struct srcu_notifier_head audio_pdr_cb_list;
27
28static int audio_pdr_locator_callback(struct notifier_block *this,
29 unsigned long opcode, void *data)
30{
31 unsigned long pdr_state = AUDIO_PDR_FRAMEWORK_DOWN;
32
33 if (opcode == LOCATOR_DOWN) {
34 pr_debug("%s: Service %s is down!", __func__,
35 audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].
36 service_name);
37 goto done;
38 }
39
40 memcpy(&audio_pdr_services, data,
41 sizeof(audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP]));
42 if (audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].total_domains == 1) {
43 pr_debug("%s: Service %s, returned total domains %d, ",
44 __func__,
45 audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].service_name,
46 audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].
47 total_domains);
48 pdr_state = AUDIO_PDR_FRAMEWORK_UP;
49 goto done;
50 } else
51 pr_err("%s: Service %s returned invalid total domains %d",
52 __func__,
53 audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].service_name,
54 audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].
55 total_domains);
56done:
57 srcu_notifier_call_chain(&audio_pdr_cb_list, pdr_state, NULL);
58 return NOTIFY_OK;
59}
60
61static struct notifier_block audio_pdr_locator_nb = {
62 .notifier_call = audio_pdr_locator_callback,
63 .priority = 0,
64};
65
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053066/**
67 * audio_pdr_register -
68 * register to PDR framework
69 *
70 * @nb: notifier block
71 *
72 * Returns 0 on success or error on failure
73 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053074int audio_pdr_register(struct notifier_block *nb)
75{
76 if (nb == NULL) {
77 pr_err("%s: Notifier block is NULL\n", __func__);
78 return -EINVAL;
79 }
80 return srcu_notifier_chain_register(&audio_pdr_cb_list, nb);
81}
82EXPORT_SYMBOL(audio_pdr_register);
83
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053084/**
85 * audio_pdr_deregister -
86 * Deregister from PDR framework
87 *
88 * @nb: notifier block
89 *
90 * Returns 0 on success or error on failure
91 */
92int audio_pdr_deregister(struct notifier_block *nb)
93{
94 if (nb == NULL) {
95 pr_err("%s: Notifier block is NULL\n", __func__);
96 return -EINVAL;
97 }
98 return srcu_notifier_chain_unregister(&audio_pdr_cb_list, nb);
99}
100EXPORT_SYMBOL(audio_pdr_deregister);
101
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530102void *audio_pdr_service_register(int domain_id,
103 struct notifier_block *nb, int *curr_state)
104{
105 void *handle;
106
107 if ((domain_id < 0) ||
108 (domain_id >= AUDIO_PDR_DOMAIN_MAX)) {
109 pr_err("%s: Invalid service ID %d\n", __func__, domain_id);
110 return ERR_PTR(-EINVAL);
111 }
112
113 handle = service_notif_register_notifier(
114 audio_pdr_services[domain_id].domain_list[0].name,
115 audio_pdr_services[domain_id].domain_list[0].instance_id,
116 nb, curr_state);
117 if (IS_ERR_OR_NULL(handle)) {
118 pr_err("%s: Failed to register for service %s, instance %d\n",
119 __func__,
120 audio_pdr_services[domain_id].domain_list[0].name,
121 audio_pdr_services[domain_id].domain_list[0].
122 instance_id);
123 }
124 return handle;
125}
126EXPORT_SYMBOL(audio_pdr_service_register);
127
128int audio_pdr_service_deregister(void *service_handle,
129 struct notifier_block *nb)
130{
131 int ret;
132
133 if (service_handle == NULL) {
134 pr_err("%s: service handle is NULL\n", __func__);
135 ret = -EINVAL;
136 goto done;
137 }
138
139 ret = service_notif_unregister_notifier(
140 service_handle, nb);
141 if (ret < 0)
142 pr_err("%s: Failed to deregister service ret %d\n",
143 __func__, ret);
144done:
145 return ret;
146}
147EXPORT_SYMBOL(audio_pdr_service_deregister);
148
149static int __init audio_pdr_subsys_init(void)
150{
151 srcu_init_notifier_head(&audio_pdr_cb_list);
152 return 0;
153}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530154
155static int __init audio_pdr_late_init(void)
156{
157 int ret;
158
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530159 audio_pdr_subsys_init();
160
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530161 ret = get_service_location(
162 audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].client_name,
163 audio_pdr_services[AUDIO_PDR_DOMAIN_ADSP].service_name,
164 &audio_pdr_locator_nb);
165 if (ret < 0) {
166 pr_err("%s get_service_location failed ret %d\n",
167 __func__, ret);
168 srcu_notifier_call_chain(&audio_pdr_cb_list,
169 AUDIO_PDR_FRAMEWORK_DOWN, NULL);
170 }
171
172 return ret;
173}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530174module_init(audio_pdr_late_init);
175
176static void __exit audio_pdr_late_exit(void)
177{
178}
179module_exit(audio_pdr_late_exit);
180
181MODULE_DESCRIPTION("PDR framework driver");
182MODULE_LICENSE("GPL v2");