1 /* Copyright (c) 2014, The Linux Foundation. All rights reserved.
2  *
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are
5  * met:
6  *     * Redistributions of source code must retain the above copyright
7  *       notice, this list of conditions and the following disclaimer.
8  *     * Redistributions in binary form must reproduce the above
9  *       copyright notice, this list of conditions and the following
10  *       disclaimer in the documentation and/or other materials provided
11  *       with the distribution.
12  *     * Neither the name of The Linux Foundation nor the names of its
13  *       contributors may be used to endorse or promote products derived
14  *       from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  */
29 
30 #define LOG_TAG "audio_hw_pm"
31 /*#define LOG_NDEBUG 0*/
32 
33 #include "pm.h"
34 #include <cutils/log.h>
35 
36 static s_audio_subsys audio_ss;
37 
audio_extn_pm_vote(void)38 int audio_extn_pm_vote(void)
39 {
40     int err, intfd, ret;
41     FILE *fd;
42     enum pm_event subsys_state;
43     char halPropVal[PROPERTY_VALUE_MAX];
44     bool prop_unload_image = false;
45     bool pm_reg = false;
46     bool pm_supp = false;
47 
48     platform_get_subsys_image_name((char *)&audio_ss.img_name);
49     ALOGD("%s: register with peripheral manager for %s",__func__, audio_ss.img_name);
50     ret = pm_client_register(audio_extn_pm_event_notifier,
51                       &audio_ss,
52                       audio_ss.img_name,
53                       PM_CLIENT_NAME,
54                       &subsys_state,
55                       &audio_ss.pm_handle);
56     if (ret == PM_RET_SUCCESS) {
57         pm_reg = true;
58         pm_supp = true;
59         ALOGV("%s: registered with peripheral manager for %s",
60                   __func__, audio_ss.img_name);
61     } else if (ret == PM_RET_UNSUPPORTED) {
62         pm_reg = true;
63         pm_supp = false;
64         ALOGV("%s: peripheral mgr unsupported for %s",
65               __func__, audio_ss.img_name);
66         return ret;
67     } else {
68        return ret;
69     }
70     if (pm_supp == true &&
71        pm_reg == true) {
72        ALOGD("%s: Voting for subsystem power up", __func__);
73        pm_client_connect(audio_ss.pm_handle);
74 
75        if (property_get("sys.audio.init", halPropVal, NULL)) {
76            prop_unload_image = !(strncmp("false", halPropVal, sizeof("false")));
77        }
78        /*
79         * adsp-loader loads modem/adsp image at boot up to play boot tone,
80         * before peripheral manager service is up. Once PM is up, vote to PM
81         * and unload the image to give control to PM to load/unload image
82         */
83        if (prop_unload_image) {
84            intfd = open(BOOT_IMG_SYSFS_PATH, O_WRONLY);
85            if (intfd == -1) {
86                ALOGE("failed to open fd in write mode, %d", errno);
87            } else {
88                ALOGD("%s: write to sysfs to unload image", __func__);
89                err = write(intfd, UNLOAD_IMAGE, 1);
90                close(intfd);
91                property_set("sys.audio.init", "true");
92           }
93        }
94     }
95     return 0;
96 }
97 
audio_extn_pm_unvote(void)98 void audio_extn_pm_unvote(void)
99 {
100     ALOGD("%s", __func__);
101     if (audio_ss.pm_handle) {
102         pm_client_disconnect(audio_ss.pm_handle);
103         pm_client_unregister(audio_ss.pm_handle);
104     }
105 }
106 
audio_extn_pm_set_parameters(struct str_parms * parms)107 void audio_extn_pm_set_parameters(struct str_parms *parms)
108 {
109     int ret;
110     char value[32];
111 
112     ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_DEV_SHUTDOWN, value, sizeof(value));
113     if (ret >= 0) {
114         if (strstr(value, "true")) {
115             ALOGD("Device shutdown notification received, unregister with PM");
116             audio_extn_pm_unvote();
117         }
118     }
119 }
120 
audio_extn_pm_event_notifier(void * client_data,enum pm_event event)121 void audio_extn_pm_event_notifier(void *client_data, enum pm_event event)
122 {
123     pm_client_event_acknowledge(audio_ss.pm_handle, event);
124 
125     /* Closing and re-opening of session is done based on snd card status given
126      * by AudioDaemon during SS offline/online (legacy code). Just return for now.
127      */
128     switch (event) {
129     case EVENT_PERIPH_GOING_OFFLINE:
130         ALOGV("%s: %s is going offline", __func__, audio_ss.img_name);
131     break;
132 
133     case EVENT_PERIPH_IS_OFFLINE:
134         ALOGV("%s: %s is offline", __func__, audio_ss.img_name);
135     break;
136 
137     case EVENT_PERIPH_GOING_ONLINE:
138         ALOGV("%s: %s is going online", __func__, audio_ss.img_name);
139     break;
140 
141     case EVENT_PERIPH_IS_ONLINE:
142         ALOGV("%s: %s is online", __func__, audio_ss.img_name);
143     break;
144 
145     default:
146         ALOGV("%s: invalid event received from PM", __func__);
147     break;
148     }
149 }
150