PageRenderTime 55ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/sound/soc/codecs/rt5640_ioctl.c

https://gitlab.com/T-Firefly/fireprime-kernel
C | 468 lines | 402 code | 56 blank | 10 comment | 87 complexity | db8ae70deb7f01e9291e3d7d3ecbd851 MD5 | raw file
  1. /*
  2. * rt5640_ioctl.h -- RT5640 ALSA SoC audio driver IO control
  3. *
  4. * Copyright 2012 Realtek Microelectronics
  5. * Author: Bard <bardliao@realtek.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. */
  11. #include <linux/spi/spi.h>
  12. #include <sound/soc.h>
  13. #include "rt56xx_ioctl.h"
  14. #include "rt5640_ioctl.h"
  15. #include "rt5640.h"
  16. #if defined(CONFIG_SND_SOC_RT5642_MODULE) || defined(CONFIG_SND_SOC_RT5642)
  17. #include "rt5640-dsp.h"
  18. #endif
  19. static hweq_t hweq_param[] = {
  20. {/* NORMAL */
  21. {0},
  22. {0},
  23. 0x0000,
  24. },
  25. {/* SPK */
  26. {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2},
  27. {0x1c10,0x01f4, 0xc5e9, 0x1a98, 0x1d2c, 0xc882, 0x1c10, 0x01f4, 0xe904, 0x1c10, 0x01f4, 0xe904, 0x1c10, 0x01f4, 0x1c10, 0x01f4, 0x2000, 0x0000, 0x2000},
  28. 0x0000,
  29. },
  30. {/* HP */
  31. {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2},
  32. {0x1c10,0x01f4, 0xc5e9, 0x1a98, 0x1d2c, 0xc882, 0x1c10, 0x01f4, 0xe904, 0x1c10, 0x01f4, 0xe904, 0x1c10, 0x01f4, 0x1c10, 0x01f4, 0x2000, 0x0000, 0x2000},
  33. 0x0000,
  34. },
  35. };
  36. #define RT5640_HWEQ_LEN ARRAY_SIZE(hweq_param)
  37. int rt5640_update_eqmode(
  38. struct snd_soc_codec *codec, int mode)
  39. {
  40. struct rt56xx_ops *ioctl_ops = rt56xx_get_ioctl_ops();
  41. int i;
  42. static int eqmode;
  43. if(codec == NULL || mode >= RT5640_HWEQ_LEN)
  44. return -EINVAL;
  45. dev_dbg(codec->dev, "%s(): mode=%d\n", __func__, mode);
  46. if(mode == eqmode)
  47. return 0;
  48. for(i = 0; i <= EQ_REG_NUM; i++) {
  49. if(hweq_param[mode].reg[i])
  50. ioctl_ops->index_write(codec, hweq_param[mode].reg[i],
  51. hweq_param[mode].value[i]);
  52. else
  53. break;
  54. }
  55. snd_soc_update_bits(codec, RT5640_EQ_CTRL2, RT5640_EQ_CTRL_MASK,
  56. hweq_param[mode].ctrl);
  57. snd_soc_update_bits(codec, RT5640_EQ_CTRL1,
  58. RT5640_EQ_UPD, RT5640_EQ_UPD);
  59. snd_soc_update_bits(codec, RT5640_EQ_CTRL1, RT5640_EQ_UPD, 0);
  60. eqmode = mode;
  61. return 0;
  62. }
  63. static void set_drc_agc_enable(struct snd_soc_codec *codec, int enable, int path)
  64. {
  65. snd_soc_update_bits(codec, RT5640_DRC_AGC_1, RT5640_DRC_AGC_P_MASK |
  66. RT5640_DRC_AGC_MASK | RT5640_DRC_AGC_UPD,
  67. enable << RT5640_DRC_AGC_SFT | path << RT5640_DRC_AGC_P_SFT |
  68. 1 << RT5640_DRC_AGC_UPD_BIT);
  69. }
  70. static void set_drc_agc_parameters(struct snd_soc_codec *codec, int attack_rate,
  71. int sample_rate, int recovery_rate, int limit_level)
  72. {
  73. snd_soc_update_bits(codec, RT5640_DRC_AGC_3, RT5640_DRC_AGC_TAR_MASK,
  74. limit_level << RT5640_DRC_AGC_TAR_SFT);
  75. snd_soc_update_bits(codec, RT5640_DRC_AGC_1, RT5640_DRC_AGC_AR_MASK |
  76. RT5640_DRC_AGC_R_MASK | RT5640_DRC_AGC_UPD |
  77. RT5640_DRC_AGC_RC_MASK, attack_rate << RT5640_DRC_AGC_AR_SFT |
  78. sample_rate << RT5640_DRC_AGC_R_SFT |
  79. recovery_rate << RT5640_DRC_AGC_RC_SFT |
  80. 0x1 << RT5640_DRC_AGC_UPD_BIT);
  81. }
  82. static void set_digital_boost_gain(struct snd_soc_codec *codec,
  83. int post_gain, int pre_gain)
  84. {
  85. snd_soc_update_bits(codec, RT5640_DRC_AGC_2,
  86. RT5640_DRC_AGC_POB_MASK | RT5640_DRC_AGC_PRB_MASK,
  87. post_gain << RT5640_DRC_AGC_POB_SFT |
  88. pre_gain << RT5640_DRC_AGC_PRB_SFT);
  89. snd_soc_update_bits(codec, RT5640_DRC_AGC_1,
  90. RT5640_DRC_AGC_UPD, 1 << RT5640_DRC_AGC_UPD_BIT);
  91. }
  92. static void set_noise_gate(struct snd_soc_codec *codec, int noise_gate_en,
  93. int noise_gate_hold_en, int compression_gain, int noise_gate_th)
  94. {
  95. snd_soc_update_bits(codec, RT5640_DRC_AGC_3,
  96. RT5640_DRC_AGC_NGB_MASK | RT5640_DRC_AGC_NG_MASK |
  97. RT5640_DRC_AGC_NGH_MASK | RT5640_DRC_AGC_NGT_MASK,
  98. noise_gate_en << RT5640_DRC_AGC_NG_SFT |
  99. noise_gate_hold_en << RT5640_DRC_AGC_NGH_SFT |
  100. compression_gain << RT5640_DRC_AGC_NGB_SFT |
  101. noise_gate_th << RT5640_DRC_AGC_NGT_SFT);
  102. snd_soc_update_bits(codec, RT5640_DRC_AGC_1,
  103. RT5640_DRC_AGC_UPD, 1 << RT5640_DRC_AGC_UPD_BIT);
  104. }
  105. static void set_drc_agc_compression(struct snd_soc_codec *codec,
  106. int compression_en, int compression_ratio)
  107. {
  108. snd_soc_update_bits(codec, RT5640_DRC_AGC_2,
  109. RT5640_DRC_AGC_CP_MASK | RT5640_DRC_AGC_CPR_MASK,
  110. compression_en << RT5640_DRC_AGC_CP_SFT |
  111. compression_ratio << RT5640_DRC_AGC_CPR_SFT);
  112. snd_soc_update_bits(codec, RT5640_DRC_AGC_1,
  113. RT5640_DRC_AGC_UPD, 1 << RT5640_DRC_AGC_UPD_BIT);
  114. }
  115. static void get_drc_agc_enable(struct snd_soc_codec *codec, int *enable, int *path)
  116. {
  117. unsigned int reg = snd_soc_read(codec, RT5640_DRC_AGC_1);
  118. *enable = (reg & RT5640_DRC_AGC_MASK) >> RT5640_DRC_AGC_SFT;
  119. *path = (reg & RT5640_DRC_AGC_P_MASK) >> RT5640_DRC_AGC_P_SFT;
  120. }
  121. static void get_drc_agc_parameters(struct snd_soc_codec *codec, int *attack_rate,
  122. int *sample_rate, int *recovery_rate, int *limit_level)
  123. {
  124. unsigned int reg = snd_soc_read(codec, RT5640_DRC_AGC_3);
  125. *limit_level = (reg & RT5640_DRC_AGC_TAR_MASK) >>
  126. RT5640_DRC_AGC_TAR_SFT;
  127. reg = snd_soc_read(codec, RT5640_DRC_AGC_1);
  128. *attack_rate = (reg & RT5640_DRC_AGC_AR_MASK) >> RT5640_DRC_AGC_AR_SFT;
  129. *sample_rate = (reg & RT5640_DRC_AGC_R_MASK) >> RT5640_DRC_AGC_R_SFT;
  130. *recovery_rate = (reg & RT5640_DRC_AGC_RC_MASK) >>
  131. RT5640_DRC_AGC_RC_SFT;
  132. }
  133. static void get_digital_boost_gain(struct snd_soc_codec *codec,
  134. int *post_gain, int *pre_gain)
  135. {
  136. unsigned int reg = snd_soc_read(codec, RT5640_DRC_AGC_2);
  137. *post_gain = (reg & RT5640_DRC_AGC_POB_MASK) >> RT5640_DRC_AGC_POB_SFT;
  138. *pre_gain = (reg & RT5640_DRC_AGC_PRB_MASK) >> RT5640_DRC_AGC_PRB_SFT;
  139. }
  140. static void get_noise_gate(struct snd_soc_codec *codec, int *noise_gate_en,
  141. int *noise_gate_hold_en, int *compression_gain, int *noise_gate_th)
  142. {
  143. unsigned int reg = snd_soc_read(codec, RT5640_DRC_AGC_3);
  144. printk("get_noise_gate reg=0x%04x\n",reg);
  145. *noise_gate_en = (reg & RT5640_DRC_AGC_NG_MASK) >>
  146. RT5640_DRC_AGC_NG_SFT;
  147. *noise_gate_hold_en = (reg & RT5640_DRC_AGC_NGH_MASK) >>
  148. RT5640_DRC_AGC_NGH_SFT;
  149. *compression_gain = (reg & RT5640_DRC_AGC_NGB_MASK) >>
  150. RT5640_DRC_AGC_NGB_SFT;
  151. *noise_gate_th = (reg & RT5640_DRC_AGC_NGT_MASK) >>
  152. RT5640_DRC_AGC_NGT_SFT;
  153. }
  154. static void get_drc_agc_compression(struct snd_soc_codec *codec,
  155. int *compression_en, int *compression_ratio)
  156. {
  157. unsigned int reg = snd_soc_read(codec, RT5640_DRC_AGC_2);
  158. *compression_en = (reg & RT5640_DRC_AGC_CP_MASK) >>
  159. RT5640_DRC_AGC_CP_SFT;
  160. *compression_ratio = (reg & RT5640_DRC_AGC_CPR_MASK) >>
  161. RT5640_DRC_AGC_CPR_SFT;
  162. }
  163. int rt5640_ioctl_common(struct snd_hwdep *hw, struct file *file,
  164. unsigned int cmd, unsigned long arg)
  165. {
  166. struct snd_soc_codec *codec = hw->private_data;
  167. struct rt56xx_cmd __user *_rt56xx = (struct rt56xx_cmd *)arg;
  168. struct rt56xx_cmd rt56xx;
  169. struct rt56xx_ops *ioctl_ops = rt56xx_get_ioctl_ops();
  170. int *buf, mask1 = 0, mask2 = 0;
  171. static int eq_mode;
  172. if (copy_from_user(&rt56xx, _rt56xx, sizeof(rt56xx))) {
  173. dev_err(codec->dev,"copy_from_user faild\n");
  174. return -EFAULT;
  175. }
  176. dev_dbg(codec->dev, "%s(): rt56xx.number=%d, cmd=%d\n",
  177. __func__, rt56xx.number, cmd);
  178. buf = kmalloc(sizeof(*buf) * rt56xx.number, GFP_KERNEL);
  179. if (buf == NULL)
  180. return -ENOMEM;
  181. if (copy_from_user(buf, rt56xx.buf, sizeof(*buf) * rt56xx.number)) {
  182. goto err;
  183. }
  184. switch (cmd) {
  185. case RT_SET_CODEC_HWEQ_IOCTL:
  186. if (eq_mode == *buf)
  187. break;
  188. eq_mode = *buf;
  189. rt5640_update_eqmode(codec, eq_mode);
  190. break;
  191. case RT_GET_CODEC_ID:
  192. *buf = snd_soc_read(codec, RT5640_VENDOR_ID2);
  193. if (copy_to_user(rt56xx.buf, buf, sizeof(*buf) * rt56xx.number))
  194. goto err;
  195. break;
  196. case RT_SET_CODEC_SPK_VOL_IOCTL:
  197. if(*(buf) <= 0x27) {
  198. snd_soc_update_bits(codec, RT5640_SPK_VOL,
  199. RT5640_L_VOL_MASK | RT5640_R_VOL_MASK,
  200. *(buf) << RT5640_L_VOL_SFT |
  201. *(buf) << RT5640_R_VOL_SFT);
  202. }
  203. break;
  204. case RT_SET_CODEC_MIC_GAIN_IOCTL:
  205. if(*(buf) <= 0x8) {
  206. snd_soc_update_bits(codec, RT5640_IN1_IN2,
  207. RT5640_BST_MASK1, *(buf) << RT5640_BST_SFT1);
  208. snd_soc_update_bits(codec, RT5640_IN3_IN4,
  209. RT5640_BST_MASK2, *(buf) << RT5640_BST_SFT2);
  210. }
  211. break;
  212. case RT_SET_CODEC_3D_SPK_IOCTL:
  213. if(rt56xx.number < 4)
  214. break;
  215. if (NULL == ioctl_ops->index_update_bits)
  216. break;
  217. mask1 = 0;
  218. if(*buf != -1)
  219. mask1 |= RT5640_3D_SPK_MASK;
  220. if(*(buf + 1) != -1)
  221. mask1 |= RT5640_3D_SPK_M_MASK;
  222. if(*(buf + 2) != -1)
  223. mask1 |= RT5640_3D_SPK_CG_MASK;
  224. if(*(buf + 3) != -1)
  225. mask1 |= RT5640_3D_SPK_SG_MASK;
  226. ioctl_ops->index_update_bits(codec, RT5640_3D_SPK, mask1,
  227. *(buf) << RT5640_3D_SPK_SFT |
  228. *(buf + 1) << RT5640_3D_SPK_M_SFT |
  229. *(buf + 2) << RT5640_3D_SPK_CG_SFT |
  230. *(buf + 3) << RT5640_3D_SPK_SG_SFT);
  231. break;
  232. case RT_SET_CODEC_MP3PLUS_IOCTL:
  233. if(rt56xx.number < 5)
  234. break;
  235. mask1 = mask2 = 0;
  236. if(*buf != -1)
  237. mask1 |= RT5640_M_MP3_MASK;
  238. if(*(buf + 1) != -1)
  239. mask1 |= RT5640_EG_MP3_MASK;
  240. if(*(buf + 2) != -1)
  241. mask2 |= RT5640_OG_MP3_MASK;
  242. if(*(buf + 3) != -1)
  243. mask2 |= RT5640_HG_MP3_MASK;
  244. if(*(buf + 4) != -1)
  245. mask2 |= RT5640_MP3_WT_MASK;
  246. snd_soc_update_bits(codec, RT5640_MP3_PLUS1, mask1,
  247. *(buf) << RT5640_M_MP3_SFT |
  248. *(buf + 1) << RT5640_EG_MP3_SFT);
  249. snd_soc_update_bits(codec, RT5640_MP3_PLUS2, mask2,
  250. *(buf + 2) << RT5640_OG_MP3_SFT |
  251. *(buf + 3) << RT5640_HG_MP3_SFT |
  252. *(buf + 4) << RT5640_MP3_WT_SFT);
  253. break;
  254. case RT_SET_CODEC_3D_HEADPHONE_IOCTL:
  255. if(rt56xx.number < 4)
  256. break;
  257. if (NULL == ioctl_ops->index_update_bits)
  258. break;
  259. mask1 = 0;
  260. if(*buf != -1)
  261. mask1 |= RT5640_3D_HP_MASK;
  262. if(*(buf + 1) != -1)
  263. mask1 |= RT5640_3D_BT_MASK;
  264. if(*(buf + 2) != -1)
  265. mask1 |= RT5640_3D_1F_MIX_MASK;
  266. if(*(buf + 3) != -1)
  267. mask1 |= RT5640_3D_HP_M_MASK;
  268. snd_soc_update_bits(codec, RT5640_3D_HP, mask1,
  269. *(buf)<<RT5640_3D_HP_SFT |
  270. *(buf + 1) << RT5640_3D_BT_SFT |
  271. *(buf + 2) << RT5640_3D_1F_MIX_SFT |
  272. *(buf + 3) << RT5640_3D_HP_M_SFT);
  273. if(*(buf + 4) != -1)
  274. ioctl_ops->index_update_bits(codec,
  275. 0x59, 0x1f, *(buf+4));
  276. break;
  277. case RT_SET_CODEC_BASS_BACK_IOCTL:
  278. if(rt56xx.number < 3)
  279. break;
  280. mask1 = 0;
  281. if(*buf != -1)
  282. mask1 |= RT5640_BB_MASK;
  283. if(*(buf + 1) != -1)
  284. mask1 |= RT5640_BB_CT_MASK;
  285. if(*(buf + 2) != -1)
  286. mask1 |= RT5640_G_BB_BST_MASK;
  287. snd_soc_update_bits(codec, RT5640_BASE_BACK, mask1,
  288. *(buf) << RT5640_BB_SFT |
  289. *(buf + 1) << RT5640_BB_CT_SFT |
  290. *(buf + 2) << RT5640_G_BB_BST_SFT);
  291. break;
  292. case RT_SET_CODEC_DIPOLE_SPK_IOCTL:
  293. if(rt56xx.number < 2)
  294. break;
  295. if (NULL == ioctl_ops->index_update_bits)
  296. break;
  297. mask1 = 0;
  298. if(*buf != -1)
  299. mask1 |= RT5640_DP_SPK_MASK;
  300. if(*(buf + 1) != -1)
  301. mask1 |= RT5640_DP_ATT_MASK;
  302. ioctl_ops->index_update_bits(codec, RT5640_DIP_SPK_INF,
  303. mask1, *(buf) << RT5640_DP_SPK_SFT |
  304. *(buf + 1) << RT5640_DP_ATT_SFT );
  305. break;
  306. case RT_SET_CODEC_DRC_AGC_ENABLE_IOCTL:
  307. if(rt56xx.number < 2)
  308. break;
  309. set_drc_agc_enable(codec, *(buf), *(buf + 1));
  310. break;
  311. case RT_SET_CODEC_DRC_AGC_PAR_IOCTL:
  312. if(rt56xx.number < 4)
  313. break;
  314. set_drc_agc_parameters(codec, *(buf), *(buf + 1),
  315. *(buf + 2), *(buf + 3));
  316. break;
  317. case RT_SET_CODEC_DIGI_BOOST_GAIN_IOCTL:
  318. if(rt56xx.number < 2)
  319. break;
  320. set_digital_boost_gain(codec, *(buf), *(buf + 1));
  321. break;
  322. case RT_SET_CODEC_NOISE_GATE_IOCTL:
  323. if(rt56xx.number < 4)
  324. break;
  325. set_noise_gate(codec, *(buf), *(buf + 1),
  326. *(buf + 2), *(buf + 3));
  327. break;
  328. case RT_SET_CODEC_DRC_AGC_COMP_IOCTL:
  329. if(rt56xx.number < 2)
  330. break;
  331. set_drc_agc_compression(codec, *(buf), *(buf + 1));
  332. break;
  333. case RT_SET_CODEC_WNR_ENABLE_IOCTL:
  334. if (NULL == ioctl_ops->index_update_bits)
  335. break;
  336. ioctl_ops->index_update_bits(codec, RT5640_WND_1,
  337. RT5640_WND_MASK, *(buf) << RT5640_WND_SFT );
  338. break;
  339. case RT_GET_CODEC_DRC_AGC_ENABLE_IOCTL:
  340. if(rt56xx.number < 2)
  341. break;
  342. get_drc_agc_enable(codec, (buf), (buf + 1));
  343. if (copy_to_user(rt56xx.buf, buf, sizeof(*buf) * rt56xx.number))
  344. goto err;
  345. break;
  346. case RT_GET_CODEC_DRC_AGC_PAR_IOCTL:
  347. if(rt56xx.number < 4)
  348. break;
  349. get_drc_agc_parameters(codec, (buf), (buf + 1),
  350. (buf + 2), (buf + 3));
  351. if (copy_to_user(rt56xx.buf, buf,
  352. sizeof(*buf) * rt56xx.number))
  353. goto err;
  354. break;
  355. case RT_GET_CODEC_DIGI_BOOST_GAIN_IOCTL:
  356. if(rt56xx.number < 2)
  357. break;
  358. get_digital_boost_gain(codec, (buf), (buf + 1));
  359. if (copy_to_user(rt56xx.buf, buf,
  360. sizeof(*buf) * rt56xx.number))
  361. goto err;
  362. break;
  363. case RT_GET_CODEC_NOISE_GATE_IOCTL:
  364. if(rt56xx.number < 4)
  365. break;
  366. get_noise_gate(codec, (buf), (buf + 1), (buf + 2), (buf + 3));
  367. if (copy_to_user(rt56xx.buf, buf,
  368. sizeof(*buf) * rt56xx.number))
  369. goto err;
  370. break;
  371. case RT_GET_CODEC_DRC_AGC_COMP_IOCTL:
  372. if(rt56xx.number < 2)
  373. break;
  374. get_drc_agc_compression(codec, (buf), (buf + 1));
  375. if (copy_to_user(rt56xx.buf, buf,
  376. sizeof(*buf) * rt56xx.number))
  377. goto err;
  378. break;
  379. case RT_GET_CODEC_SPK_VOL_IOCTL:
  380. *buf = (snd_soc_read(codec, RT5640_SPK_VOL) & RT5640_L_VOL_MASK)
  381. >> RT5640_L_VOL_SFT;
  382. if (copy_to_user(rt56xx.buf, buf, sizeof(*buf) * rt56xx.number))
  383. goto err;
  384. break;
  385. case RT_GET_CODEC_MIC_GAIN_IOCTL:
  386. *buf = (snd_soc_read(codec, RT5640_IN1_IN2) & RT5640_BST_MASK1)
  387. >> RT5640_BST_SFT1;
  388. if (copy_to_user(rt56xx.buf, buf, sizeof(*buf) * rt56xx.number))
  389. goto err;
  390. break;
  391. #if defined(CONFIG_SND_SOC_RT5642_MODULE) || defined(CONFIG_SND_SOC_RT5642)
  392. case RT_READ_CODEC_DSP_IOCTL:
  393. case RT_WRITE_CODEC_DSP_IOCTL:
  394. case RT_GET_CODEC_DSP_MODE_IOCTL:
  395. return rt56xx_dsp_ioctl_common(hw, file, cmd, arg);
  396. #endif
  397. case RT_GET_CODEC_HWEQ_IOCTL:
  398. case RT_GET_CODEC_3D_SPK_IOCTL:
  399. case RT_GET_CODEC_MP3PLUS_IOCTL:
  400. case RT_GET_CODEC_3D_HEADPHONE_IOCTL:
  401. case RT_GET_CODEC_BASS_BACK_IOCTL:
  402. case RT_GET_CODEC_DIPOLE_SPK_IOCTL:
  403. default:
  404. break;
  405. }
  406. kfree(buf);
  407. return 0;
  408. err:
  409. kfree(buf);
  410. return -EFAULT;
  411. }
  412. EXPORT_SYMBOL_GPL(rt5640_ioctl_common);