cx25840-audio.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. /* cx25840 audio functions
  2. *
  3. * This program is free software; you can redistribute it and/or
  4. * modify it under the terms of the GNU General Public License
  5. * as published by the Free Software Foundation; either version 2
  6. * of the License, or (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program; if not, write to the Free Software
  15. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  16. */
  17. #include <linux/videodev2.h>
  18. #include <linux/i2c.h>
  19. #include <media/audiochip.h>
  20. #include <media/v4l2-common.h>
  21. #include "cx25840.h"
  22. static int set_audclk_freq(struct i2c_client *client, u32 freq)
  23. {
  24. struct cx25840_state *state = i2c_get_clientdata(client);
  25. if (freq != 32000 && freq != 44100 && freq != 48000)
  26. return -EINVAL;
  27. /* assert soft reset */
  28. cx25840_and_or(client, 0x810, ~0x1, 0x01);
  29. /* common for all inputs and rates */
  30. /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
  31. cx25840_write(client, 0x127, 0x50);
  32. if (state->aud_input != CX25840_AUDIO_SERIAL) {
  33. switch (freq) {
  34. case 32000:
  35. /* VID_PLL and AUX_PLL */
  36. cx25840_write4(client, 0x108, 0x0f040610);
  37. /* AUX_PLL_FRAC */
  38. cx25840_write4(client, 0x110, 0xee39bb01);
  39. /* src3/4/6_ctl = 0x0801f77f */
  40. cx25840_write4(client, 0x900, 0x7ff70108);
  41. cx25840_write4(client, 0x904, 0x7ff70108);
  42. cx25840_write4(client, 0x90c, 0x7ff70108);
  43. break;
  44. case 44100:
  45. /* VID_PLL and AUX_PLL */
  46. cx25840_write4(client, 0x108, 0x0f040910);
  47. /* AUX_PLL_FRAC */
  48. cx25840_write4(client, 0x110, 0xd66bec00);
  49. /* src3/4/6_ctl = 0x08016d59 */
  50. cx25840_write4(client, 0x900, 0x596d0108);
  51. cx25840_write4(client, 0x904, 0x596d0108);
  52. cx25840_write4(client, 0x90c, 0x596d0108);
  53. break;
  54. case 48000:
  55. /* VID_PLL and AUX_PLL */
  56. cx25840_write4(client, 0x108, 0x0f040a10);
  57. /* AUX_PLL_FRAC */
  58. cx25840_write4(client, 0x110, 0xe5d69800);
  59. /* src3/4/6_ctl = 0x08014faa */
  60. cx25840_write4(client, 0x900, 0xaa4f0108);
  61. cx25840_write4(client, 0x904, 0xaa4f0108);
  62. cx25840_write4(client, 0x90c, 0xaa4f0108);
  63. break;
  64. }
  65. } else {
  66. switch (freq) {
  67. case 32000:
  68. /* VID_PLL and AUX_PLL */
  69. cx25840_write4(client, 0x108, 0x0f04081e);
  70. /* AUX_PLL_FRAC */
  71. cx25840_write4(client, 0x110, 0x69082a01);
  72. /* src1_ctl = 0x08010000 */
  73. cx25840_write4(client, 0x8f8, 0x00000108);
  74. /* src3/4/6_ctl = 0x08020000 */
  75. cx25840_write4(client, 0x900, 0x00000208);
  76. cx25840_write4(client, 0x904, 0x00000208);
  77. cx25840_write4(client, 0x90c, 0x00000208);
  78. /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
  79. cx25840_write(client, 0x127, 0x54);
  80. break;
  81. case 44100:
  82. /* VID_PLL and AUX_PLL */
  83. cx25840_write4(client, 0x108, 0x0f040918);
  84. /* AUX_PLL_FRAC */
  85. cx25840_write4(client, 0x110, 0xd66bec00);
  86. /* src1_ctl = 0x08010000 */
  87. cx25840_write4(client, 0x8f8, 0xcd600108);
  88. /* src3/4/6_ctl = 0x08020000 */
  89. cx25840_write4(client, 0x900, 0x85730108);
  90. cx25840_write4(client, 0x904, 0x85730108);
  91. cx25840_write4(client, 0x90c, 0x85730108);
  92. break;
  93. case 48000:
  94. /* VID_PLL and AUX_PLL */
  95. cx25840_write4(client, 0x108, 0x0f040a18);
  96. /* AUX_PLL_FRAC */
  97. cx25840_write4(client, 0x110, 0xe5d69800);
  98. /* src1_ctl = 0x08010000 */
  99. cx25840_write4(client, 0x8f8, 0x00800108);
  100. /* src3/4/6_ctl = 0x08020000 */
  101. cx25840_write4(client, 0x900, 0x55550108);
  102. cx25840_write4(client, 0x904, 0x55550108);
  103. cx25840_write4(client, 0x90c, 0x55550108);
  104. break;
  105. }
  106. }
  107. /* deassert soft reset */
  108. cx25840_and_or(client, 0x810, ~0x1, 0x00);
  109. state->audclk_freq = freq;
  110. return 0;
  111. }
  112. void cx25840_audio_set_path(struct i2c_client *client)
  113. {
  114. struct cx25840_state *state = i2c_get_clientdata(client);
  115. /* stop microcontroller */
  116. cx25840_and_or(client, 0x803, ~0x10, 0);
  117. /* Mute everything to prevent the PFFT! */
  118. cx25840_write(client, 0x8d3, 0x1f);
  119. if (state->aud_input == CX25840_AUDIO_SERIAL) {
  120. /* Set Path1 to Serial Audio Input */
  121. cx25840_write4(client, 0x8d0, 0x12100101);
  122. /* The microcontroller should not be started for the
  123. * non-tuner inputs: autodetection is specific for
  124. * TV audio. */
  125. } else {
  126. /* Set Path1 to Analog Demod Main Channel */
  127. cx25840_write4(client, 0x8d0, 0x7038061f);
  128. /* When the microcontroller detects the
  129. * audio format, it will unmute the lines */
  130. cx25840_and_or(client, 0x803, ~0x10, 0x10);
  131. }
  132. set_audclk_freq(client, state->audclk_freq);
  133. }
  134. static int get_volume(struct i2c_client *client)
  135. {
  136. /* Volume runs +18dB to -96dB in 1/2dB steps
  137. * change to fit the msp3400 -114dB to +12dB range */
  138. /* check PATH1_VOLUME */
  139. int vol = 228 - cx25840_read(client, 0x8d4);
  140. vol = (vol / 2) + 23;
  141. return vol << 9;
  142. }
  143. static void set_volume(struct i2c_client *client, int volume)
  144. {
  145. /* First convert the volume to msp3400 values (0-127) */
  146. int vol = volume >> 9;
  147. /* now scale it up to cx25840 values
  148. * -114dB to -96dB maps to 0
  149. * this should be 19, but in my testing that was 4dB too loud */
  150. if (vol <= 23) {
  151. vol = 0;
  152. } else {
  153. vol -= 23;
  154. }
  155. /* PATH1_VOLUME */
  156. cx25840_write(client, 0x8d4, 228 - (vol * 2));
  157. }
  158. static int get_bass(struct i2c_client *client)
  159. {
  160. /* bass is 49 steps +12dB to -12dB */
  161. /* check PATH1_EQ_BASS_VOL */
  162. int bass = cx25840_read(client, 0x8d9) & 0x3f;
  163. bass = (((48 - bass) * 0xffff) + 47) / 48;
  164. return bass;
  165. }
  166. static void set_bass(struct i2c_client *client, int bass)
  167. {
  168. /* PATH1_EQ_BASS_VOL */
  169. cx25840_and_or(client, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
  170. }
  171. static int get_treble(struct i2c_client *client)
  172. {
  173. /* treble is 49 steps +12dB to -12dB */
  174. /* check PATH1_EQ_TREBLE_VOL */
  175. int treble = cx25840_read(client, 0x8db) & 0x3f;
  176. treble = (((48 - treble) * 0xffff) + 47) / 48;
  177. return treble;
  178. }
  179. static void set_treble(struct i2c_client *client, int treble)
  180. {
  181. /* PATH1_EQ_TREBLE_VOL */
  182. cx25840_and_or(client, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
  183. }
  184. static int get_balance(struct i2c_client *client)
  185. {
  186. /* balance is 7 bit, 0 to -96dB */
  187. /* check PATH1_BAL_LEVEL */
  188. int balance = cx25840_read(client, 0x8d5) & 0x7f;
  189. /* check PATH1_BAL_LEFT */
  190. if ((cx25840_read(client, 0x8d5) & 0x80) == 0)
  191. balance = 0x80 - balance;
  192. else
  193. balance = 0x80 + balance;
  194. return balance << 8;
  195. }
  196. static void set_balance(struct i2c_client *client, int balance)
  197. {
  198. int bal = balance >> 8;
  199. if (bal > 0x80) {
  200. /* PATH1_BAL_LEFT */
  201. cx25840_and_or(client, 0x8d5, 0x7f, 0x80);
  202. /* PATH1_BAL_LEVEL */
  203. cx25840_and_or(client, 0x8d5, ~0x7f, bal & 0x7f);
  204. } else {
  205. /* PATH1_BAL_LEFT */
  206. cx25840_and_or(client, 0x8d5, 0x7f, 0x00);
  207. /* PATH1_BAL_LEVEL */
  208. cx25840_and_or(client, 0x8d5, ~0x7f, 0x80 - bal);
  209. }
  210. }
  211. static int get_mute(struct i2c_client *client)
  212. {
  213. /* check SRC1_MUTE_EN */
  214. return cx25840_read(client, 0x8d3) & 0x2 ? 1 : 0;
  215. }
  216. static void set_mute(struct i2c_client *client, int mute)
  217. {
  218. struct cx25840_state *state = i2c_get_clientdata(client);
  219. if (state->aud_input != CX25840_AUDIO_SERIAL) {
  220. /* Must turn off microcontroller in order to mute sound.
  221. * Not sure if this is the best method, but it does work.
  222. * If the microcontroller is running, then it will undo any
  223. * changes to the mute register. */
  224. if (mute) {
  225. /* disable microcontroller */
  226. cx25840_and_or(client, 0x803, ~0x10, 0x00);
  227. cx25840_write(client, 0x8d3, 0x1f);
  228. } else {
  229. /* enable microcontroller */
  230. cx25840_and_or(client, 0x803, ~0x10, 0x10);
  231. }
  232. } else {
  233. /* SRC1_MUTE_EN */
  234. cx25840_and_or(client, 0x8d3, ~0x2, mute ? 0x02 : 0x00);
  235. }
  236. }
  237. int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
  238. {
  239. struct v4l2_control *ctrl = arg;
  240. switch (cmd) {
  241. case VIDIOC_INT_AUDIO_CLOCK_FREQ:
  242. return set_audclk_freq(client, *(u32 *)arg);
  243. case VIDIOC_G_CTRL:
  244. switch (ctrl->id) {
  245. case V4L2_CID_AUDIO_VOLUME:
  246. ctrl->value = get_volume(client);
  247. break;
  248. case V4L2_CID_AUDIO_BASS:
  249. ctrl->value = get_bass(client);
  250. break;
  251. case V4L2_CID_AUDIO_TREBLE:
  252. ctrl->value = get_treble(client);
  253. break;
  254. case V4L2_CID_AUDIO_BALANCE:
  255. ctrl->value = get_balance(client);
  256. break;
  257. case V4L2_CID_AUDIO_MUTE:
  258. ctrl->value = get_mute(client);
  259. break;
  260. default:
  261. return -EINVAL;
  262. }
  263. break;
  264. case VIDIOC_S_CTRL:
  265. switch (ctrl->id) {
  266. case V4L2_CID_AUDIO_VOLUME:
  267. set_volume(client, ctrl->value);
  268. break;
  269. case V4L2_CID_AUDIO_BASS:
  270. set_bass(client, ctrl->value);
  271. break;
  272. case V4L2_CID_AUDIO_TREBLE:
  273. set_treble(client, ctrl->value);
  274. break;
  275. case V4L2_CID_AUDIO_BALANCE:
  276. set_balance(client, ctrl->value);
  277. break;
  278. case V4L2_CID_AUDIO_MUTE:
  279. set_mute(client, ctrl->value);
  280. break;
  281. default:
  282. return -EINVAL;
  283. }
  284. break;
  285. default:
  286. return -EINVAL;
  287. }
  288. return 0;
  289. }