a5xelte: overlay: Disable config_cleanupUnusedFingerprints
[GitHub/LineageOS/android_device_samsung_a7xelte.git] / amplifier / amplifier.c
CommitLineData
85a78b61
CH
1/*
2 * Copyright (C) 2017 Christopher N. Hesse <raymanfx@gmail.com>
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "audio_hw_amplifier"
18#define LOG_NDEBUG 0
19
20#include <cutils/log.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <errno.h>
24#include <dlfcn.h>
25#include <fcntl.h>
26#include <stdlib.h>
27#include <unistd.h>
28
29#include <audio_hw.h>
30#include <hardware/audio_amplifier.h>
31
32#include "tfa.h"
33
db132bfa
CH
34typedef enum amp_state {
35 AMP_STATE_DISABLED = 0,
36 AMP_STATE_ENABLED,
37 AMP_STATE_MAX = AMP_STATE_ENABLED
38} amp_state_t;
39
85a78b61
CH
40typedef struct amp_device {
41 amplifier_device_t amp_dev;
42 tfa_device_t *tfa_dev;
43 audio_mode_t current_mode;
db132bfa
CH
44 int refcount[Audio_Mode_Max];
45 amp_state_t amp_state;
85a78b61
CH
46} amp_device_t;
47
48static amp_device_t *amp_dev = NULL;
49
50/*
51 * Returns the internal TFA mode appropriate for the device.
52 *
53 * @param snd_device The current sound device.
54 *
55 * @return tfa_mode_t identifying the internal amplifier mode.
56 */
57static tfa_mode_t classify_snd_device(uint32_t snd_device) {
58 tfa_mode_t mode = Audio_Mode_None;
59
60 switch (snd_device) {
61 case SND_DEVICE_OUT_SPEAKER:
62 // our audio HAL splits this up
63 //case SND_DEVICE_OUT_SPEAKER_AND_HEADPHONES:
64 mode = Audio_Mode_Music_Normal;
65 break;
66 case SND_DEVICE_OUT_VOICE_SPEAKER:
67 case SND_DEVICE_OUT_VOICE_SPEAKER_WB:
68 mode = Audio_Mode_Voice;
69 break;
70 default:
71 break;
72 }
73
74 return mode;
75}
76
77/*
78 * Hook into amplifier HAL
79 */
80static int amp_enable_output_devices(amplifier_device_t *device,
81 uint32_t devices, bool enable)
82{
83 amp_device_t *dev = (amp_device_t *) device;
84 tfa_mode_t tfa_mode = classify_snd_device(devices);
85a78b61
CH
85 int rc = 0;
86
87 ALOGV("%s: devices=0x%x, enable=%d, tfa_mode=%d", __func__, devices, enable, tfa_mode);
88
db132bfa 89 if (tfa_mode == Audio_Mode_None) {
85a78b61
CH
90 return 0;
91 }
92
93 if (enable) {
db132bfa
CH
94 dev->refcount[tfa_mode]++;
95 } else if (!enable && dev->refcount[tfa_mode] > 0) {
96 dev->refcount[tfa_mode]--;
85a78b61
CH
97 }
98
db132bfa
CH
99 ALOGV("%s: enable=%d, dev->refcount=%d, amp_state=%d", __func__, enable,
100 dev->refcount[tfa_mode], dev->amp_state);
85a78b61 101
db132bfa 102 if (enable && dev->amp_state == AMP_STATE_DISABLED && dev->refcount[tfa_mode] == 1) {
85a78b61 103 rc = tfa_power(dev->tfa_dev, true);
db132bfa
CH
104 if (rc == 0) {
105 dev->amp_state = AMP_STATE_ENABLED;
106 }
107 ALOGV("%s: tfa_power(true) with rc=%d", __func__, rc);
108 } else if (!enable && dev->amp_state == AMP_STATE_ENABLED && dev->refcount[tfa_mode] == 0) {
85a78b61 109 rc = tfa_power(dev->tfa_dev, false);
db132bfa
CH
110 if (rc == 0) {
111 dev->amp_state = AMP_STATE_DISABLED;
112 }
113 ALOGV("%s: tfa_power(false) with rc=%d", __func__, rc);
85a78b61
CH
114 }
115
116 // TODO: Distinguish between tfa modes
117
118 return rc;
119}
120
121static int amp_set_mode(amplifier_device_t *device, audio_mode_t mode)
122{
123 amp_device_t *dev = (amp_device_t *) device;
124
125 dev->current_mode = mode;
126
127 return 0;
128}
129
130static int amp_dev_close(hw_device_t *device)
131{
132 amp_device_t *dev = (amp_device_t *) device;
133
134 tfa_device_close(dev->tfa_dev);
135
136 free(dev);
137
138 return 0;
139}
140
141static int amp_module_open(const hw_module_t *module, const char *name,
142 hw_device_t **device)
143{
144 tfa_device_t *tfa_dev;
145
146 if (strcmp(name, AMPLIFIER_HARDWARE_INTERFACE)) {
147 ALOGE("%s: %s does not match amplifier hardware interface name",
148 __func__, name);
149 return -ENODEV;
150 }
151
152 if (amp_dev) {
153 ALOGE("%s: Unable to open second instance of the amplifier", __func__);
154 return -EBUSY;
155 }
156
157 tfa_dev = tfa_device_open();
158 if (tfa_dev == NULL) {
159 ALOGE("%s: Unable to open amplifier device", __func__);
160 return -ENOENT;
161 }
162
163 amp_dev = calloc(1, sizeof(amp_device_t));
164 if (!amp_dev) {
165 ALOGE("%s: Unable to allocate memory for amplifier device", __func__);
166 return -ENOMEM;
167 }
168
169 amp_dev->amp_dev.common.tag = HARDWARE_DEVICE_TAG;
170 amp_dev->amp_dev.common.module = (hw_module_t *) module;
171 amp_dev->amp_dev.common.version = HARDWARE_DEVICE_API_VERSION(1, 0);
172 amp_dev->amp_dev.common.close = amp_dev_close;
173
174 amp_dev->amp_dev.set_input_devices = NULL;
175 amp_dev->amp_dev.set_output_devices = NULL;
176 amp_dev->amp_dev.enable_input_devices = NULL;
177 amp_dev->amp_dev.enable_output_devices = amp_enable_output_devices;
178 amp_dev->amp_dev.set_mode = amp_set_mode;
179 amp_dev->amp_dev.output_stream_start = NULL;
180 amp_dev->amp_dev.input_stream_start = NULL;
181 amp_dev->amp_dev.output_stream_standby = NULL;
182 amp_dev->amp_dev.input_stream_standby = NULL;
183 amp_dev->amp_dev.set_parameters = NULL;
184
185 amp_dev->current_mode = AUDIO_MODE_NORMAL;
db132bfa
CH
186 memset(amp_dev->refcount, 0, Audio_Mode_Max);
187 amp_dev->amp_state = AMP_STATE_DISABLED;
85a78b61
CH
188
189 amp_dev->tfa_dev = tfa_dev;
190
191 *device = (hw_device_t *) amp_dev;
192
193 return 0;
194}
195
196static struct hw_module_methods_t hal_module_methods = {
197 .open = amp_module_open,
198};
199
200amplifier_module_t HAL_MODULE_INFO_SYM = {
201 .common = {
202 .tag = HARDWARE_MODULE_TAG,
203 .module_api_version = AMPLIFIER_MODULE_API_VERSION_0_1,
204 .hal_api_version = HARDWARE_HAL_API_VERSION,
205 .id = AMPLIFIER_HARDWARE_MODULE_ID,
206 .name = "Samsung TFA9896 amplifier HAL",
207 .author = "Christopher N. Hesse",
208 .methods = &hal_module_methods,
209 },
210};