/arch/arm/mach-msm/qdsp6/msm8k_ard_adie.c

https://github.com/drakaz/GalaxoKernel · C · 442 lines · 332 code · 80 blank · 30 comment · 68 complexity · a310375ec252039abe094e6c32aa6456 MD5 · raw file

  1. /*
  2. *
  3. * Copyright (c) 2009 QUALCOMM USA, INC.
  4. *
  5. * All source code in this file is licensed under the following license
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * version 2 as published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. * See the GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you can find it at http://www.fsf.org
  18. *
  19. */
  20. #include <linux/kernel.h>
  21. #include <mach/pmic.h>
  22. #include <mach/qdsp6/msm8k_cad_ioctl.h>
  23. #include <mach/qdsp6/msm8k_ard_adiei.h>
  24. #include <mach/qdsp6/msm8k_adie_codec_rpc.h>
  25. #include <mach/qdsp6/msm8k_adie_codec_dev.h>
  26. #include <mach/qdsp6/msm8k_cad_devices.h>
  27. struct adie_state_struct_type adie_state;
  28. #if 0
  29. #define D(fmt, args...) printk(KERN_INFO "adie: " fmt, ##args)
  30. #else
  31. #define D(fmt, args...) do {} while (0)
  32. #endif
  33. u32 get_path_id(u32 dev_id)
  34. {
  35. u32 adie_path_id = 0;
  36. switch (dev_id) {
  37. case CAD_HW_DEVICE_ID_HANDSET_MIC:
  38. adie_path_id = DAL_ADIE_CODEC_HANDSET_TX;
  39. break;
  40. case CAD_HW_DEVICE_ID_HANDSET_SPKR:
  41. adie_path_id = DAL_ADIE_CODEC_HANDSET_RX;
  42. break;
  43. case CAD_HW_DEVICE_ID_HEADSET_MIC:
  44. adie_path_id = DAL_ADIE_CODEC_HEADSET_MONO_TX;
  45. break;
  46. case CAD_HW_DEVICE_ID_HEADSET_SPKR_MONO:
  47. adie_path_id = DAL_ADIE_CODEC_HEADSET_MONO_RX;
  48. break;
  49. case CAD_HW_DEVICE_ID_HEADSET_SPKR_STEREO:
  50. adie_path_id = DAL_ADIE_CODEC_HEADSET_STEREO_RX;
  51. break;
  52. case CAD_HW_DEVICE_ID_SPKR_PHONE_MIC:
  53. adie_path_id = DAL_ADIE_CODEC_SPEAKER_TX;
  54. break;
  55. case CAD_HW_DEVICE_ID_SPKR_PHONE_MONO:
  56. case CAD_HW_DEVICE_ID_SPKR_PHONE_STEREO:
  57. adie_path_id = DAL_ADIE_CODEC_SPEAKER_RX;
  58. break;
  59. case CAD_HW_DEVICE_ID_TTY_HEADSET_MIC:
  60. adie_path_id = DAL_ADIE_CODEC_TTY_HEADSET_TX;
  61. break;
  62. case CAD_HW_DEVICE_ID_TTY_HEADSET_SPKR:
  63. adie_path_id = DAL_ADIE_CODEC_TTY_HEADSET_RX;
  64. break;
  65. case CAD_HW_DEVICE_ID_BT_SCO_MIC:
  66. case CAD_HW_DEVICE_ID_BT_SCO_SPKR:
  67. case CAD_HW_DEVICE_ID_BT_A2DP_SPKR:
  68. default:
  69. pr_err("ARD ADIE Paths not supported for dev_id %d\n", dev_id);
  70. break;
  71. }
  72. return adie_path_id;
  73. }
  74. u32 get_path_type(u32 cad_dev_type)
  75. {
  76. u32 adie_dev_type;
  77. switch (cad_dev_type) {
  78. case CAD_RX_DEVICE:
  79. adie_dev_type = ADIE_CODEC_RX;
  80. break;
  81. case CAD_TX_DEVICE:
  82. adie_dev_type = ADIE_CODEC_TX;
  83. break;
  84. default:
  85. adie_dev_type = ADIE_CODEC_LB;
  86. break;
  87. }
  88. D("ARD ADIE DEV TYPE = %d\n", adie_dev_type);
  89. return adie_dev_type;
  90. }
  91. s32 adie_init(void)
  92. {
  93. s32 dal_rc;
  94. u8 dev_type;
  95. dal_rc = CAD_RES_SUCCESS;
  96. dev_type = 0;
  97. dal_rc = daldevice_attach(DALDEVICEID_ADIE_CODEC, ADIE_CODEC_PORT_NAME,
  98. ADIE_CODEC_CPU, &adie_state.adie_handle);
  99. if (CAD_RES_SUCCESS != dal_rc)
  100. pr_err("ARD: ADIE Device Attach failed\n");
  101. adie_state.adie_opened = ADIE_FALSE;
  102. /* Initialize the rest of the state variables */
  103. for (dev_type = 0; dev_type < MAX_ADIE_PATH_TYPES; dev_type++) {
  104. adie_state.adie_path_type[dev_type].enabled = ADIE_FALSE;
  105. adie_state.adie_path_type[dev_type].enable_request = ADIE_FALSE;
  106. adie_state.adie_path_type[dev_type].state = ADIE_STATE_RESET;
  107. }
  108. /* Initialize the PMIC MIC and SPKR */
  109. set_speaker_gain(SPKR_GAIN_PLUS04DB);
  110. mic_set_volt(MIC_VOLT_1_80V);
  111. speaker_cmd(SPKR_ENABLE);
  112. return dal_rc;
  113. }
  114. s32 adie_dinit(void)
  115. {
  116. s32 dal_rc;
  117. u8 dev_type;
  118. dal_rc = CAD_RES_SUCCESS;
  119. dev_type = 0;
  120. dal_rc = daldevice_detach(adie_state.adie_handle);
  121. if (CAD_RES_SUCCESS != dal_rc)
  122. pr_err("ARD: ADIE Device Detach failed\n");
  123. for (dev_type = 0; dev_type < MAX_ADIE_PATH_TYPES; dev_type++) {
  124. adie_state.adie_path_type[dev_type].enabled = ADIE_FALSE;
  125. adie_state.adie_path_type[dev_type].enable_request = ADIE_FALSE;
  126. adie_state.adie_path_type[dev_type].state = ADIE_STATE_RESET;
  127. }
  128. speaker_cmd(SPKR_DISABLE);
  129. adie_state.adie_opened = ADIE_FALSE;
  130. return dal_rc;
  131. }
  132. s32 adie_open(u32 dev_type)
  133. {
  134. s32 cad_rc, dal_rc;
  135. cad_rc = dal_rc = CAD_RES_SUCCESS;
  136. if (adie_state.adie_opened != ADIE_TRUE) {
  137. dal_rc = daldevice_open(adie_state.adie_handle, 0);
  138. if (dal_rc != CAD_RES_SUCCESS) {
  139. pr_err("ARD ADIE DAL Open failed, dev_type = %d\n",
  140. dev_type);
  141. cad_rc = CAD_RES_FAILURE;
  142. } else {
  143. adie_state.adie_opened = ADIE_TRUE;
  144. D("ARD ADIE DRIVER OPENED\n");
  145. }
  146. }
  147. return cad_rc;
  148. }
  149. s32 adie_close(u32 dev_type)
  150. {
  151. s32 rc;
  152. rc = CAD_RES_SUCCESS;
  153. if (adie_state.adie_opened != ADIE_TRUE)
  154. goto done;
  155. /* Do not close if at least 1 path is still enabled */
  156. if (((adie_state.adie_path_type[0]).enabled != ADIE_TRUE) &&
  157. ((adie_state.adie_path_type[1]).enabled != ADIE_TRUE)) {
  158. daldevice_close(adie_state.adie_handle);
  159. adie_state.adie_opened = ADIE_FALSE;
  160. }
  161. done:
  162. return rc;
  163. }
  164. s32 adie_enable(u32 dev_type, u32 dev_id)
  165. {
  166. s32 rc = CAD_RES_SUCCESS;
  167. if (adie_state.adie_path_type[dev_type].enabled == ADIE_TRUE) {
  168. rc = CAD_RES_FAILURE;
  169. goto done;
  170. }
  171. adie_state.adie_path_type[dev_type].enable_request = ADIE_TRUE;
  172. rc = adie_state_control(dev_type, dev_id);
  173. if (rc != CAD_RES_SUCCESS)
  174. pr_err("ADIE STATE M/C FAILED, dev_id = %d\n", dev_id);
  175. else
  176. D("ADIE ENABLED - PATH %d\n", dev_type);
  177. done:
  178. return rc;
  179. }
  180. s32 adie_disable(u32 dev_type, u32 dev_id)
  181. {
  182. s32 rc = CAD_RES_SUCCESS;
  183. if (adie_state.adie_path_type[dev_type].enabled == ADIE_FALSE) {
  184. pr_err("ADIE ALREADY DISABLED, dev_id = %d\n", dev_id);
  185. rc = CAD_RES_FAILURE;
  186. goto done;
  187. }
  188. adie_state.adie_path_type[dev_type].enabled = ADIE_FALSE;
  189. rc = adie_state_control(dev_type, dev_id);
  190. if (rc != CAD_RES_SUCCESS)
  191. pr_err("ADIE STATE M/C FAILED, dev_id = %d\n", dev_id);
  192. else
  193. D("ADIE DISABLED\n");
  194. done:
  195. return rc;
  196. }
  197. u32 adie_state_control(u32 dev_type, u32 dev_id)
  198. {
  199. s32 cad_res;
  200. enum adie_state_ret_enum_type rc;
  201. cad_res = CAD_RES_SUCCESS;
  202. rc = ADIE_STATE_RC_SUCCESS;
  203. do {
  204. D("ARD ADIE dev_type %d, adie state %d",
  205. dev_type, adie_state.adie_path_type[dev_type].state);
  206. switch (adie_state.adie_path_type[dev_type].state) {
  207. case ADIE_STATE_RESET:
  208. rc = adie_state_reset(dev_type, dev_id);
  209. break;
  210. case ADIE_STATE_DIGITAL_ACTIVE:
  211. rc = adie_state_digital_active(dev_type, dev_id);
  212. break;
  213. case ADIE_STATE_DIGITAL_ANALOG_ACTIVE:
  214. rc = adie_state_digital_analog_active(dev_type, dev_id);
  215. break;
  216. default:
  217. break;
  218. }
  219. } while (rc == ADIE_STATE_RC_CONTINUE);
  220. if (rc == ADIE_STATE_RC_FAILURE)
  221. cad_res = CAD_RES_FAILURE;
  222. return cad_res;
  223. }
  224. enum adie_state_ret_enum_type adie_state_reset(u32 dev_type, u32 dev_id)
  225. {
  226. enum adie_state_ret_enum_type rc;
  227. s32 dal_rc;
  228. enum adie_codec_path_type_enum path_type;
  229. u32 path_id;
  230. u32 freq_plan;
  231. rc = ADIE_STATE_RC_SUCCESS;
  232. dal_rc = CAD_RES_SUCCESS;
  233. if (adie_state.adie_path_type[dev_type].enable_request != ADIE_TRUE) {
  234. rc = ADIE_STATE_RC_SUCCESS;
  235. adie_state.adie_path_type[dev_type].enabled = ADIE_FALSE;
  236. goto done;
  237. }
  238. path_id = get_path_id(dev_id);
  239. path_type = get_path_type(dev_type);
  240. if (path_type == ADIE_CODEC_RX)
  241. freq_plan = 48000;
  242. else
  243. freq_plan = 8000;
  244. /* Set the path */
  245. dal_rc = rpc_adie_codec_set_path(adie_state.adie_handle, path_id,
  246. path_type);
  247. if (dal_rc != CAD_RES_SUCCESS) {
  248. pr_err("ARD ADIE Set Path failed for dev_type %d\n", dev_type);
  249. rc = ADIE_STATE_RC_FAILURE;
  250. goto done;
  251. }
  252. /* Set the freq plan */
  253. dal_rc = rpc_adie_codec_set_path_freq_plan(adie_state.adie_handle,
  254. path_type, freq_plan);
  255. if (dal_rc != CAD_RES_SUCCESS) {
  256. pr_err("ARD ADIE Set Path Freq Plan failed for dev_type %d\n",
  257. dev_type);
  258. rc = ADIE_STATE_RC_FAILURE;
  259. goto done;
  260. }
  261. /* Proceed to stage */
  262. dal_rc = rpc_adie_codec_proceed_to_stage(adie_state.adie_handle,
  263. path_type, ADIE_CODEC_DIGITAL_READY);
  264. if (dal_rc != CAD_RES_SUCCESS) {
  265. pr_err("ARD ADIE Proceed to Stage failed for dev_type %d\n",
  266. dev_type);
  267. rc = ADIE_STATE_RC_FAILURE;
  268. goto done;
  269. }
  270. adie_state.adie_path_type[dev_type].state = ADIE_STATE_DIGITAL_ACTIVE;
  271. rc = ADIE_STATE_RC_CONTINUE;
  272. done:
  273. return rc;
  274. }
  275. enum adie_state_ret_enum_type adie_state_digital_active(u32 dev_type,
  276. u32 dev_id)
  277. {
  278. enum adie_state_ret_enum_type rc;
  279. enum adie_codec_path_type_enum path_type;
  280. s32 dal_rc;
  281. rc = ADIE_STATE_RC_SUCCESS;
  282. dal_rc = CAD_RES_SUCCESS;
  283. path_type = get_path_type(dev_type);
  284. if (adie_state.adie_path_type[dev_type].enable_request == ADIE_TRUE) {
  285. /* Proceed to next stage */
  286. dal_rc = rpc_adie_codec_proceed_to_stage(adie_state.adie_handle,
  287. path_type, ADIE_CODEC_DIGITAL_ANALOG_READY);
  288. if (dal_rc != CAD_RES_SUCCESS) {
  289. pr_err("ARD ADIE Proceed to Stage failed,"
  290. " dev_type %d\n", dev_type);
  291. rc = ADIE_STATE_RC_FAILURE;
  292. goto done;
  293. }
  294. adie_state.adie_path_type[dev_type].state =
  295. ADIE_STATE_DIGITAL_ANALOG_ACTIVE;
  296. adie_state.adie_path_type[dev_type].enabled = ADIE_TRUE;
  297. adie_state.adie_path_type[dev_type].enable_request = ADIE_FALSE;
  298. rc = ADIE_STATE_RC_CONTINUE;
  299. } else {
  300. /* Proceed to digital off stage */
  301. dal_rc = rpc_adie_codec_proceed_to_stage(adie_state.adie_handle,
  302. path_type, ADIE_CODEC_DIGITAL_OFF);
  303. if (dal_rc != CAD_RES_SUCCESS) {
  304. pr_err("ARD ADIE Proceed to Stage failed,"
  305. " dev_type %d\n", dev_type);
  306. rc = ADIE_STATE_RC_FAILURE;
  307. goto done;
  308. }
  309. adie_state.adie_path_type[dev_type].state = ADIE_STATE_RESET;
  310. rc = ADIE_STATE_RC_CONTINUE;
  311. }
  312. done:
  313. return rc;
  314. }
  315. enum adie_state_ret_enum_type adie_state_digital_analog_active(u32 dev_type,
  316. u32 dev_id)
  317. {
  318. s32 dal_rc;
  319. enum adie_state_ret_enum_type rc;
  320. enum adie_codec_path_type_enum path_type;
  321. dal_rc = CAD_RES_SUCCESS;
  322. rc = ADIE_STATE_RC_SUCCESS;
  323. path_type = get_path_type(dev_type);
  324. if (adie_state.adie_path_type[dev_type].enabled == ADIE_TRUE) {
  325. /* Stay in this state till teardown or reconfigure */
  326. if (path_type == ADIE_CODEC_TX) {
  327. mic_en(1);
  328. } else if ((path_type == ADIE_CODEC_RX) &&
  329. (dev_id == CAD_HW_DEVICE_ID_SPKR_PHONE_MONO)) {
  330. speaker_cmd(SPKR_ON);
  331. spkr_en_left_chan(1);
  332. } else {
  333. D("ARD ADIE Loopback Device\n");
  334. }
  335. } else {
  336. /*Turn off the PMIC if it's a TX*/
  337. if (path_type == ADIE_CODEC_TX) {
  338. mic_en(0);
  339. } else if ((path_type == ADIE_CODEC_RX) &&
  340. (dev_id == CAD_HW_DEVICE_ID_SPKR_PHONE_MONO)) {
  341. speaker_cmd(SPKR_OFF);
  342. spkr_en_left_chan(0);
  343. } else {
  344. D("ARD ADIE Loopback Device\n");
  345. }
  346. /* Proceed to digital off stage */
  347. dal_rc = rpc_adie_codec_proceed_to_stage(adie_state.adie_handle,
  348. path_type, ADIE_CODEC_ANALOG_OFF);
  349. if (dal_rc != CAD_RES_SUCCESS) {
  350. pr_err("ARD ADIE Proceed to Stage failed,"
  351. " dev_type %d\n", dev_type);
  352. rc = ADIE_STATE_RC_FAILURE;
  353. goto done;
  354. }
  355. adie_state.adie_path_type[dev_type].state =
  356. ADIE_STATE_DIGITAL_ACTIVE;
  357. adie_state.adie_path_type[dev_type].enable_request = ADIE_FALSE;
  358. rc = ADIE_STATE_RC_CONTINUE;
  359. }
  360. done:
  361. return rc;
  362. }