/arch/arm/mach-msm/board-mahimahi-audio.c

https://github.com/AICP/kernel_google_msm · C · 283 lines · 226 code · 38 blank · 19 comment · 39 complexity · 7015f101937b4aee690ce0635c286ab5 MD5 · raw file

  1. /* 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. #include <linux/gpio.h>
  17. #include <linux/delay.h>
  18. #include <mach/msm_qdsp6_audio.h>
  19. #include <mach/htc_acoustic_qsd.h>
  20. #include <mach/proc_comm.h>
  21. #include "board-mahimahi.h"
  22. #include "pmic.h"
  23. #include "board-mahimahi-tpa2018d1.h"
  24. #if 0
  25. #define D(fmt, args...) printk(KERN_INFO "Audio: "fmt, ##args)
  26. #else
  27. #define D(fmt, args...) do {} while (0)
  28. #endif
  29. static struct mutex mic_lock;
  30. static struct mutex bt_sco_lock;
  31. static struct q6_hw_info q6_audio_hw[Q6_HW_COUNT] = {
  32. [Q6_HW_HANDSET] = {
  33. .min_gain = -2000,
  34. .max_gain = 0,
  35. },
  36. [Q6_HW_HEADSET] = {
  37. .min_gain = -2000,
  38. .max_gain = 0,
  39. },
  40. [Q6_HW_SPEAKER] = {
  41. .min_gain = -1500,
  42. .max_gain = 0,
  43. },
  44. [Q6_HW_TTY] = {
  45. .min_gain = -2000,
  46. .max_gain = 0,
  47. },
  48. [Q6_HW_BT_SCO] = {
  49. .min_gain = -2000,
  50. .max_gain = 0,
  51. },
  52. [Q6_HW_BT_A2DP] = {
  53. .min_gain = -2000,
  54. .max_gain = 0,
  55. },
  56. };
  57. void mahimahi_headset_enable(int en)
  58. {
  59. D("%s %d\n", __func__, en);
  60. /* enable audio amp */
  61. if (en) mdelay(15);
  62. gpio_set_value(MAHIMAHI_AUD_JACKHP_EN, !!en);
  63. }
  64. void mahimahi_speaker_enable(int en)
  65. {
  66. struct spkr_config_mode scm;
  67. memset(&scm, 0, sizeof(scm));
  68. D("%s %d\n", __func__, en);
  69. if (en) {
  70. scm.is_right_chan_en = 0;
  71. scm.is_left_chan_en = 1;
  72. scm.is_stereo_en = 0;
  73. scm.is_hpf_en = 1;
  74. pmic_spkr_en_mute(LEFT_SPKR, 0);
  75. pmic_spkr_en_mute(RIGHT_SPKR, 0);
  76. pmic_set_spkr_configuration(&scm);
  77. pmic_spkr_en(LEFT_SPKR, 1);
  78. pmic_spkr_en(RIGHT_SPKR, 0);
  79. /* unmute */
  80. pmic_spkr_en_mute(LEFT_SPKR, 1);
  81. } else {
  82. pmic_spkr_en_mute(LEFT_SPKR, 0);
  83. pmic_spkr_en(LEFT_SPKR, 0);
  84. pmic_spkr_en(RIGHT_SPKR, 0);
  85. pmic_set_spkr_configuration(&scm);
  86. }
  87. if (is_cdma_version(system_rev))
  88. tpa2018d1_set_speaker_amp(en);
  89. }
  90. void mahimahi_receiver_enable(int en)
  91. {
  92. if (is_cdma_version(system_rev) &&
  93. ((system_rev == 0xC1) || (system_rev == 0xC2))) {
  94. struct spkr_config_mode scm;
  95. memset(&scm, 0, sizeof(scm));
  96. D("%s %d\n", __func__, en);
  97. if (en) {
  98. scm.is_right_chan_en = 1;
  99. scm.is_left_chan_en = 0;
  100. scm.is_stereo_en = 0;
  101. scm.is_hpf_en = 1;
  102. pmic_spkr_en_mute(RIGHT_SPKR, 0);
  103. pmic_set_spkr_configuration(&scm);
  104. pmic_spkr_en(RIGHT_SPKR, 1);
  105. /* unmute */
  106. pmic_spkr_en_mute(RIGHT_SPKR, 1);
  107. } else {
  108. pmic_spkr_en_mute(RIGHT_SPKR, 0);
  109. pmic_spkr_en(RIGHT_SPKR, 0);
  110. pmic_set_spkr_configuration(&scm);
  111. }
  112. }
  113. }
  114. static void config_gpio_table(uint32_t *table, int len)
  115. {
  116. int n;
  117. unsigned id;
  118. for (n = 0; n < len; n++) {
  119. id = table[n];
  120. msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
  121. }
  122. }
  123. static uint32_t bt_sco_enable[] = {
  124. PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_OUT, 1, GPIO_OUTPUT,
  125. GPIO_NO_PULL, GPIO_2MA),
  126. PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_IN, 1, GPIO_INPUT,
  127. GPIO_NO_PULL, GPIO_2MA),
  128. PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_SYNC, 2, GPIO_INPUT,
  129. GPIO_NO_PULL, GPIO_2MA),
  130. PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_CLK, 2, GPIO_INPUT,
  131. GPIO_NO_PULL, GPIO_2MA),
  132. };
  133. static uint32_t bt_sco_disable[] = {
  134. PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_OUT, 0, GPIO_OUTPUT,
  135. GPIO_NO_PULL, GPIO_2MA),
  136. PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_IN, 0, GPIO_INPUT,
  137. GPIO_NO_PULL, GPIO_2MA),
  138. PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_SYNC, 0, GPIO_INPUT,
  139. GPIO_NO_PULL, GPIO_2MA),
  140. PCOM_GPIO_CFG(MAHIMAHI_BT_PCM_CLK, 0, GPIO_INPUT,
  141. GPIO_NO_PULL, GPIO_2MA),
  142. };
  143. void mahimahi_bt_sco_enable(int en)
  144. {
  145. static int bt_sco_refcount;
  146. D("%s %d\n", __func__, en);
  147. mutex_lock(&bt_sco_lock);
  148. if (en) {
  149. if (++bt_sco_refcount == 1)
  150. config_gpio_table(bt_sco_enable,
  151. ARRAY_SIZE(bt_sco_enable));
  152. } else {
  153. if (--bt_sco_refcount == 0) {
  154. config_gpio_table(bt_sco_disable,
  155. ARRAY_SIZE(bt_sco_disable));
  156. gpio_set_value(MAHIMAHI_BT_PCM_OUT, 0);
  157. }
  158. }
  159. mutex_unlock(&bt_sco_lock);
  160. }
  161. void mahimahi_mic_enable(int en)
  162. {
  163. static int old_state = 0, new_state = 0;
  164. D("%s %d\n", __func__, en);
  165. mutex_lock(&mic_lock);
  166. if (!!en)
  167. new_state++;
  168. else
  169. new_state--;
  170. if (new_state == 1 && old_state == 0) {
  171. gpio_set_value(MAHIMAHI_AUD_2V5_EN, 1);
  172. mdelay(60);
  173. } else if (new_state == 0 && old_state == 1)
  174. gpio_set_value(MAHIMAHI_AUD_2V5_EN, 0);
  175. else
  176. D("%s: do nothing %d %d\n", __func__, old_state, new_state);
  177. old_state = new_state;
  178. mutex_unlock(&mic_lock);
  179. }
  180. void mahimahi_analog_init(void)
  181. {
  182. D("%s\n", __func__);
  183. /* stereo pmic init */
  184. pmic_spkr_set_gain(LEFT_SPKR, SPKR_GAIN_PLUS12DB);
  185. pmic_spkr_set_gain(RIGHT_SPKR, SPKR_GAIN_PLUS12DB);
  186. pmic_spkr_en_right_chan(OFF_CMD);
  187. pmic_spkr_en_left_chan(OFF_CMD);
  188. pmic_spkr_add_right_left_chan(OFF_CMD);
  189. pmic_spkr_en_stereo(OFF_CMD);
  190. pmic_spkr_select_usb_with_hpf_20hz(OFF_CMD);
  191. pmic_spkr_bypass_mux(OFF_CMD);
  192. pmic_spkr_en_hpf(ON_CMD);
  193. pmic_spkr_en_sink_curr_from_ref_volt_cir(OFF_CMD);
  194. pmic_spkr_set_mux_hpf_corner_freq(SPKR_FREQ_0_73KHZ);
  195. pmic_mic_set_volt(MIC_VOLT_1_80V);
  196. gpio_request(MAHIMAHI_AUD_JACKHP_EN, "aud_jackhp_en");
  197. gpio_request(MAHIMAHI_BT_PCM_OUT, "bt_pcm_out");
  198. gpio_direction_output(MAHIMAHI_AUD_JACKHP_EN, 0);
  199. mutex_lock(&bt_sco_lock);
  200. config_gpio_table(bt_sco_disable,
  201. ARRAY_SIZE(bt_sco_disable));
  202. gpio_direction_output(MAHIMAHI_BT_PCM_OUT, 0);
  203. mutex_unlock(&bt_sco_lock);
  204. }
  205. int mahimahi_get_rx_vol(uint8_t hw, int level)
  206. {
  207. int vol;
  208. if (level > 100)
  209. level = 100;
  210. else if (level < 0)
  211. level = 0;
  212. if (is_cdma_version(system_rev) && hw == Q6_HW_HANDSET) {
  213. int handset_volume[6] = { -1600, -1300, -1000, -600, -300, 0 };
  214. vol = handset_volume[5 * level / 100];
  215. } else {
  216. struct q6_hw_info *info;
  217. info = &q6_audio_hw[hw];
  218. vol = info->min_gain + ((info->max_gain - info->min_gain) * level) / 100;
  219. }
  220. D("%s %d\n", __func__, vol);
  221. return vol;
  222. }
  223. static struct qsd_acoustic_ops acoustic = {
  224. .enable_mic_bias = mahimahi_mic_enable,
  225. };
  226. static struct q6audio_analog_ops ops = {
  227. .init = mahimahi_analog_init,
  228. .speaker_enable = mahimahi_speaker_enable,
  229. .headset_enable = mahimahi_headset_enable,
  230. .receiver_enable = mahimahi_receiver_enable,
  231. .bt_sco_enable = mahimahi_bt_sco_enable,
  232. .int_mic_enable = mahimahi_mic_enable,
  233. .ext_mic_enable = mahimahi_mic_enable,
  234. .get_rx_vol = mahimahi_get_rx_vol,
  235. };
  236. void __init mahimahi_audio_init(void)
  237. {
  238. mutex_init(&mic_lock);
  239. mutex_init(&bt_sco_lock);
  240. q6audio_register_analog_ops(&ops);
  241. acoustic_register_ops(&acoustic);
  242. if (is_cdma_version(system_rev) &&
  243. ((system_rev == 0xC1) || (system_rev == 0xC2)))
  244. q6audio_set_acdb_file("default_PMIC.acdb");
  245. }