blob: 523d187794c1c0fb80c7c2fcbed1768723141760 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* arch/arm/mach-msm/board-mahimahi-audio.c
2 *
3 * Copyright (C) 2009 HTC Corporation
4 * Copyright (C) 2009 Google Inc.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/gpio.h>
18#include <linux/delay.h>
19#include <mach/msm_qdsp6_audio.h>
20#include <mach/htc_acoustic_qsd.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070021#include <mach/proc_comm.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070022
23#include "board-mahimahi.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070024#include "pmic.h"
25#include "board-mahimahi-tpa2018d1.h"
26
27#if 0
28#define D(fmt, args...) printk(KERN_INFO "Audio: "fmt, ##args)
29#else
30#define D(fmt, args...) do {} while (0)
31#endif
32
33static struct mutex mic_lock;
34static struct mutex bt_sco_lock;
35
36static struct q6_hw_info q6_audio_hw[Q6_HW_COUNT] = {
37 [Q6_HW_HANDSET] = {
38 .min_gain = -2000,
39 .max_gain = 0,
40 },
41 [Q6_HW_HEADSET] = {
42 .min_gain = -2000,
43 .max_gain = 0,
44 },
45 [Q6_HW_SPEAKER] = {
46 .min_gain = -1500,
47 .max_gain = 0,
48 },
49 [Q6_HW_TTY] = {
50 .min_gain = -2000,
51 .max_gain = 0,
52 },
53 [Q6_HW_BT_SCO] = {
54 .min_gain = -2000,
55 .max_gain = 0,
56 },
57 [Q6_HW_BT_A2DP] = {
58 .min_gain = -2000,
59 .max_gain = 0,
60 },
61};
62
63void mahimahi_headset_enable(int en)
64{
65 D("%s %d\n", __func__, en);
66 /* enable audio amp */
67 if (en) mdelay(15);
68 gpio_set_value(MAHIMAHI_AUD_JACKHP_EN, !!en);
69}
70
71void mahimahi_speaker_enable(int en)
72{
73 struct spkr_config_mode scm;
74 memset(&scm, 0, sizeof(scm));
75
76 D("%s %d\n", __func__, en);
77 if (en) {
78 scm.is_right_chan_en = 0;
79 scm.is_left_chan_en = 1;
80 scm.is_stereo_en = 0;
81 scm.is_hpf_en = 1;
82 pmic_spkr_en_mute(LEFT_SPKR, 0);
83 pmic_spkr_en_mute(RIGHT_SPKR, 0);
84 pmic_set_spkr_configuration(&scm);
85 pmic_spkr_en(LEFT_SPKR, 1);
86 pmic_spkr_en(RIGHT_SPKR, 0);
87
88 /* unmute */
89 pmic_spkr_en_mute(LEFT_SPKR, 1);
90 } else {
91 pmic_spkr_en_mute(LEFT_SPKR, 0);
92
93 pmic_spkr_en(LEFT_SPKR, 0);
94 pmic_spkr_en(RIGHT_SPKR, 0);
95
96 pmic_set_spkr_configuration(&scm);
97 }
98
99 if (is_cdma_version(system_rev))
100 tpa2018d1_set_speaker_amp(en);
101}
102
103void mahimahi_receiver_enable(int en)
104{
105 if (is_cdma_version(system_rev) &&
106 ((system_rev == 0xC1) || (system_rev == 0xC2))) {
107 struct spkr_config_mode scm;
108 memset(&scm, 0, sizeof(scm));
109
110 D("%s %d\n", __func__, en);
111 if (en) {
112 scm.is_right_chan_en = 1;
113 scm.is_left_chan_en = 0;
114 scm.is_stereo_en = 0;
115 scm.is_hpf_en = 1;
116 pmic_spkr_en_mute(RIGHT_SPKR, 0);
117 pmic_set_spkr_configuration(&scm);
118 pmic_spkr_en(RIGHT_SPKR, 1);
119
120 /* unmute */
121 pmic_spkr_en_mute(RIGHT_SPKR, 1);
122 } else {
123 pmic_spkr_en_mute(RIGHT_SPKR, 0);
124
125 pmic_spkr_en(RIGHT_SPKR, 0);
126
127 pmic_set_spkr_configuration(&scm);
128 }
129 }
130}
131
132static void config_gpio_table(uint32_t *table, int len)
133{
134 int n;
135 unsigned id;
136 for (n = 0; n < len; n++) {
137 id = table[n];
138 msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
139 }
140}
141
142static uint32_t bt_sco_enable[] = {
143 PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_OUT, 1, GPIO_OUTPUT,
144 GPIO_NO_PULL, GPIO_2MA),
145 PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_IN, 1, GPIO_INPUT,
146 GPIO_NO_PULL, GPIO_2MA),
147 PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_SYNC, 2, GPIO_INPUT,
148 GPIO_NO_PULL, GPIO_2MA),
149 PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_CLK, 2, GPIO_INPUT,
150 GPIO_NO_PULL, GPIO_2MA),
151};
152
153static uint32_t bt_sco_disable[] = {
154 PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_OUT, 0, GPIO_OUTPUT,
155 GPIO_NO_PULL, GPIO_2MA),
156 PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_IN, 0, GPIO_INPUT,
157 GPIO_NO_PULL, GPIO_2MA),
158 PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_SYNC, 0, GPIO_INPUT,
159 GPIO_NO_PULL, GPIO_2MA),
160 PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_CLK, 0, GPIO_INPUT,
161 GPIO_NO_PULL, GPIO_2MA),
162};
163
164void mahimahi_bt_sco_enable(int en)
165{
166 static int bt_sco_refcount;
167 D("%s %d\n", __func__, en);
168
169 mutex_lock(&bt_sco_lock);
170 if (en) {
171 if (++bt_sco_refcount == 1)
172 config_gpio_table(bt_sco_enable,
173 ARRAY_SIZE(bt_sco_enable));
174 } else {
175 if (--bt_sco_refcount == 0) {
176 config_gpio_table(bt_sco_disable,
177 ARRAY_SIZE(bt_sco_disable));
178 gpio_set_value(MAHIMAHI_BT_PCM_OUT, 0);
179 }
180 }
181 mutex_unlock(&bt_sco_lock);
182}
183
184void mahimahi_mic_enable(int en)
185{
186 static int old_state = 0, new_state = 0;
187
188 D("%s %d\n", __func__, en);
189
190 mutex_lock(&mic_lock);
191 if (!!en)
192 new_state++;
193 else
194 new_state--;
195
196 if (new_state == 1 && old_state == 0) {
197 gpio_set_value(MAHIMAHI_AUD_2V5_EN, 1);
198 mdelay(60);
199 } else if (new_state == 0 && old_state == 1)
200 gpio_set_value(MAHIMAHI_AUD_2V5_EN, 0);
201 else
202 D("%s: do nothing %d %d\n", __func__, old_state, new_state);
203
204 old_state = new_state;
205 mutex_unlock(&mic_lock);
206}
207
208void mahimahi_analog_init(void)
209{
210 D("%s\n", __func__);
211 /* stereo pmic init */
212 pmic_spkr_set_gain(LEFT_SPKR, SPKR_GAIN_PLUS12DB);
213 pmic_spkr_set_gain(RIGHT_SPKR, SPKR_GAIN_PLUS12DB);
214 pmic_spkr_en_right_chan(OFF_CMD);
215 pmic_spkr_en_left_chan(OFF_CMD);
216 pmic_spkr_add_right_left_chan(OFF_CMD);
217 pmic_spkr_en_stereo(OFF_CMD);
218 pmic_spkr_select_usb_with_hpf_20hz(OFF_CMD);
219 pmic_spkr_bypass_mux(OFF_CMD);
220 pmic_spkr_en_hpf(ON_CMD);
221 pmic_spkr_en_sink_curr_from_ref_volt_cir(OFF_CMD);
222 pmic_spkr_set_mux_hpf_corner_freq(SPKR_FREQ_0_73KHZ);
223 pmic_mic_set_volt(MIC_VOLT_1_80V);
224
225 gpio_request(MAHIMAHI_AUD_JACKHP_EN, "aud_jackhp_en");
226 gpio_request(MAHIMAHI_BT_PCM_OUT, "bt_pcm_out");
227
228 gpio_direction_output(MAHIMAHI_AUD_JACKHP_EN, 0);
229
230 mutex_lock(&bt_sco_lock);
231 config_gpio_table(bt_sco_disable,
232 ARRAY_SIZE(bt_sco_disable));
233 gpio_direction_output(MAHIMAHI_BT_PCM_OUT, 0);
234 mutex_unlock(&bt_sco_lock);
235}
236
237int mahimahi_get_rx_vol(uint8_t hw, int level)
238{
239 int vol;
240
241 if (level > 100)
242 level = 100;
243 else if (level < 0)
244 level = 0;
245
246 if (is_cdma_version(system_rev) && hw == Q6_HW_HANDSET) {
247 int handset_volume[6] = { -1600, -1300, -1000, -600, -300, 0 };
248 vol = handset_volume[5 * level / 100];
249 } else {
250 struct q6_hw_info *info;
251 info = &q6_audio_hw[hw];
252 vol = info->min_gain + ((info->max_gain - info->min_gain) * level) / 100;
253 }
254
255 D("%s %d\n", __func__, vol);
256 return vol;
257}
258
259static struct qsd_acoustic_ops acoustic = {
260 .enable_mic_bias = mahimahi_mic_enable,
261};
262
263static struct q6audio_analog_ops ops = {
264 .init = mahimahi_analog_init,
265 .speaker_enable = mahimahi_speaker_enable,
266 .headset_enable = mahimahi_headset_enable,
267 .receiver_enable = mahimahi_receiver_enable,
268 .bt_sco_enable = mahimahi_bt_sco_enable,
269 .int_mic_enable = mahimahi_mic_enable,
270 .ext_mic_enable = mahimahi_mic_enable,
271 .get_rx_vol = mahimahi_get_rx_vol,
272};
273
274void __init mahimahi_audio_init(void)
275{
276 mutex_init(&mic_lock);
277 mutex_init(&bt_sco_lock);
278 q6audio_register_analog_ops(&ops);
279 acoustic_register_ops(&acoustic);
280 if (is_cdma_version(system_rev) &&
281 ((system_rev == 0xC1) || (system_rev == 0xC2)))
282 q6audio_set_acdb_file("default_PMIC.acdb");
283}