mt6630_fm_cmd.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981
  1. #include <linux/kernel.h>
  2. #include <linux/types.h>
  3. #include "fm_typedef.h"
  4. #include "fm_dbg.h"
  5. #include "fm_err.h"
  6. #include "fm_rds.h"
  7. #include "fm_config.h"
  8. #include "fm_link.h"
  9. #include "mt6630_fm_reg.h"
  10. /* #include "mt6630_fm_link.h" */
  11. #include "mt6630_fm.h"
  12. #include "mt6630_fm_cmd.h"
  13. #include "mt6630_fm_cust_cfg.h"
  14. static fm_s32 fm_bop_write(fm_u8 addr, fm_u16 value, fm_u8 *buf, fm_s32 size)
  15. {
  16. if (size < (FM_WRITE_BASIC_OP_SIZE + 2))
  17. return -1;
  18. if (buf == NULL)
  19. return -2;
  20. buf[0] = FM_WRITE_BASIC_OP;
  21. buf[1] = FM_WRITE_BASIC_OP_SIZE;
  22. buf[2] = addr;
  23. buf[3] = (fm_u8) ((value) & 0x00FF);
  24. buf[4] = (fm_u8) ((value >> 8) & 0x00FF);
  25. WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4]);
  26. return FM_WRITE_BASIC_OP_SIZE + 2;
  27. }
  28. static fm_s32 fm_bop_udelay(fm_u32 value, fm_u8 *buf, fm_s32 size)
  29. {
  30. if (size < (FM_UDELAY_BASIC_OP_SIZE + 2))
  31. return -1;
  32. if (buf == NULL)
  33. return -2;
  34. buf[0] = FM_UDELAY_BASIC_OP;
  35. buf[1] = FM_UDELAY_BASIC_OP_SIZE;
  36. buf[2] = (fm_u8) ((value) & 0x000000FF);
  37. buf[3] = (fm_u8) ((value >> 8) & 0x000000FF);
  38. buf[4] = (fm_u8) ((value >> 16) & 0x000000FF);
  39. buf[5] = (fm_u8) ((value >> 24) & 0x000000FF);
  40. WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
  41. return FM_UDELAY_BASIC_OP_SIZE + 2;
  42. }
  43. static fm_s32 fm_bop_rd_until(fm_u8 addr, fm_u16 mask, fm_u16 value, fm_u8 *buf, fm_s32 size)
  44. {
  45. if (size < (FM_RD_UNTIL_BASIC_OP_SIZE + 2))
  46. return -1;
  47. if (buf == NULL)
  48. return -2;
  49. buf[0] = FM_RD_UNTIL_BASIC_OP;
  50. buf[1] = FM_RD_UNTIL_BASIC_OP_SIZE;
  51. buf[2] = addr;
  52. buf[3] = (fm_u8) ((mask) & 0x00FF);
  53. buf[4] = (fm_u8) ((mask >> 8) & 0x00FF);
  54. buf[5] = (fm_u8) ((value) & 0x00FF);
  55. buf[6] = (fm_u8) ((value >> 8) & 0x00FF);
  56. WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2],
  57. buf[3], buf[4], buf[5], buf[6]);
  58. return FM_RD_UNTIL_BASIC_OP_SIZE + 2;
  59. }
  60. static fm_s32 fm_bop_modify(fm_u8 addr, fm_u16 mask_and, fm_u16 mask_or, fm_u8 *buf, fm_s32 size)
  61. {
  62. if (size < (FM_MODIFY_BASIC_OP_SIZE + 2))
  63. return -1;
  64. if (buf == NULL)
  65. return -2;
  66. buf[0] = FM_MODIFY_BASIC_OP;
  67. buf[1] = FM_MODIFY_BASIC_OP_SIZE;
  68. buf[2] = addr;
  69. buf[3] = (fm_u8) ((mask_and) & 0x00FF);
  70. buf[4] = (fm_u8) ((mask_and >> 8) & 0x00FF);
  71. buf[5] = (fm_u8) ((mask_or) & 0x00FF);
  72. buf[6] = (fm_u8) ((mask_or >> 8) & 0x00FF);
  73. WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2],
  74. buf[3], buf[4], buf[5], buf[6]);
  75. return FM_MODIFY_BASIC_OP_SIZE + 2;
  76. }
  77. /*
  78. * mt6630_pwrup_clock_on - Wholechip FM Power Up: step 1, FM Digital Clock enable
  79. * @buf - target buf
  80. * @buf_size - buffer size
  81. * return package size
  82. */
  83. fm_s32 mt6630_pwrup_clock_on(fm_u8 *buf, fm_s32 buf_size)
  84. {
  85. fm_s32 pkt_size = 0;
  86. fm_u16 de_emphasis;
  87. /* fm_u16 osc_freq; */
  88. if (buf_size < TX_BUF_SIZE)
  89. return -1;
  90. de_emphasis = mt6630_fm_config.rx_cfg.deemphasis; /* MT6630fm_cust_config_fetch(FM_CFG_RX_DEEMPHASIS); */
  91. de_emphasis &= 0x0001; /* rang 0~1 */
  92. /* osc_freq = mt6630_fm_config.rx_cfg.osc_freq;//MT6628fm_cust_config_fetch(FM_CFG_RX_OSC_FREQ); */
  93. /* osc_freq &= 0x0007; //rang 0~5 */
  94. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  95. buf[1] = FM_ENABLE_OPCODE;
  96. pkt_size = 4;
  97. /* B1.1 Enable digital OSC */
  98. pkt_size += fm_bop_write(0x60, 0x0003, &buf[pkt_size], buf_size - pkt_size); /* wr 60 3 */
  99. pkt_size += fm_bop_udelay(100, &buf[pkt_size], buf_size - pkt_size); /* delay 100us */
  100. /* B1.3 Release HW clock gating */
  101. pkt_size += fm_bop_write(0x60, 0x0007, &buf[pkt_size], buf_size - pkt_size); /* wr 60 7 */
  102. /* B1.4 Set FM long/short antenna:1: short_antenna 0: long antenna(default) */
  103. pkt_size += fm_bop_modify(0x61, 0xFFEF, 0x0000, &buf[pkt_size], buf_size - pkt_size);
  104. /* B1.5 Set audio output mode (lineout/I2S) 0:lineout, 1:I2S */
  105. if (mt6630_fm_config.aud_cfg.aud_path == FM_AUD_ANALOG)
  106. pkt_size += fm_bop_modify(0x61, 0xFF7F, 0x0000, &buf[pkt_size], buf_size - pkt_size);
  107. else
  108. pkt_size += fm_bop_modify(0x61, 0xFF7F, 0x0080, &buf[pkt_size], buf_size - pkt_size);
  109. /* B1.6 Set deemphasis setting */
  110. pkt_size += fm_bop_modify(0x61, ~DE_EMPHASIS, (de_emphasis << 12), &buf[pkt_size], buf_size - pkt_size);
  111. /* pkt_size += fm_bop_modify(0x60, OSC_FREQ_MASK, (osc_freq << 4), &buf[pkt_size], buf_size - pkt_size); */
  112. buf[2] = (fm_u8) ((pkt_size - 4) & 0x00FF);
  113. buf[3] = (fm_u8) (((pkt_size - 4) >> 8) & 0x00FF);
  114. return pkt_size;
  115. }
  116. /*
  117. * mt6630_patch_download - Wholechip FM Power Up: step 3, download patch to f/w,
  118. * @buf - target buf
  119. * @buf_size - buffer size
  120. * @seg_num - total segments that this patch divided into
  121. * @seg_id - No. of Segments: segment that will now be sent
  122. * @src - patch source buffer
  123. * @seg_len - segment size: segment that will now be sent
  124. * return package size
  125. */
  126. fm_s32 mt6630_patch_download(fm_u8 *buf, fm_s32 buf_size, fm_u8 seg_num, fm_u8 seg_id,
  127. const fm_u8 *src, fm_s32 seg_len)
  128. {
  129. fm_s32 pkt_size = 0;
  130. fm_u8 *dst = NULL;
  131. if (buf_size < TX_BUF_SIZE)
  132. return -1;
  133. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  134. buf[1] = FM_PATCH_DOWNLOAD_OPCODE;
  135. pkt_size = 4;
  136. buf[pkt_size++] = seg_num;
  137. buf[pkt_size++] = seg_id;
  138. if (seg_len > (buf_size - pkt_size))
  139. return -1;
  140. dst = &buf[pkt_size];
  141. pkt_size += seg_len;
  142. /* copy patch to tx buffer */
  143. while (seg_len--) {
  144. *dst = *src;
  145. /* pr_debug("%02x ", *dst); */
  146. src++;
  147. dst++;
  148. }
  149. buf[2] = (fm_u8) ((pkt_size - 4) & 0x00FF);
  150. buf[3] = (fm_u8) (((pkt_size - 4) >> 8) & 0x00FF);
  151. WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2],
  152. buf[3], buf[4], buf[5], buf[6]);
  153. return pkt_size;
  154. }
  155. /*
  156. * mt6630_coeff_download - Wholechip FM Power Up: step 3,download coeff to f/w,
  157. * @buf - target buf
  158. * @buf_size - buffer size
  159. * @seg_num - total segments that this patch divided into
  160. * @seg_id - No. of Segments: segment that will now be sent
  161. * @src - patch source buffer
  162. * @seg_len - segment size: segment that will now be sent
  163. * return package size
  164. */
  165. fm_s32 mt6630_coeff_download(fm_u8 *buf, fm_s32 buf_size, fm_u8 seg_num, fm_u8 seg_id,
  166. const fm_u8 *src, fm_s32 seg_len)
  167. {
  168. fm_s32 pkt_size = 0;
  169. fm_u8 *dst = NULL;
  170. if (buf_size < TX_BUF_SIZE)
  171. return -1;
  172. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  173. buf[1] = FM_COEFF_DOWNLOAD_OPCODE;
  174. pkt_size = 4;
  175. buf[pkt_size++] = seg_num;
  176. buf[pkt_size++] = seg_id;
  177. if (seg_len > (buf_size - pkt_size))
  178. return -1;
  179. dst = &buf[pkt_size];
  180. pkt_size += seg_len;
  181. /* copy patch to tx buffer */
  182. while (seg_len--) {
  183. *dst = *src;
  184. /* pr_debug("%02x ", *dst); */
  185. src++;
  186. dst++;
  187. }
  188. buf[2] = (fm_u8) ((pkt_size - 4) & 0x00FF);
  189. buf[3] = (fm_u8) (((pkt_size - 4) >> 8) & 0x00FF);
  190. WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2],
  191. buf[3], buf[4], buf[5], buf[6]);
  192. return pkt_size;
  193. }
  194. /*
  195. * mt6630_pwrup_digital_init - Wholechip FM Power Up: step 4, FM Digital Init: fm_rgf_maincon
  196. * @buf - target buf
  197. * @buf_size - buffer size
  198. * return package size
  199. */
  200. fm_s32 mt6630_pwrup_digital_init(fm_u8 *buf, fm_s32 buf_size)
  201. {
  202. fm_s32 pkt_size = 0;
  203. if (buf_size < TX_BUF_SIZE)
  204. return -1;
  205. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  206. buf[1] = FM_ENABLE_OPCODE;
  207. pkt_size = 4;
  208. /* update FM ADPLL fast tracking mode gain */
  209. pkt_size += fm_bop_modify(0xF, 0xF800, 0x0455, &buf[pkt_size], buf_size - pkt_size);
  210. /* F1.4 Set appropriate interrupt mask behavior as desired(RX) */
  211. /* pkt_size += fm_bop_write(0x6A, 0x0021, &buf[pkt_size], buf_size - pkt_size);//wr 6A 0021 */
  212. pkt_size += fm_bop_write(0x6B, 0x0021, &buf[pkt_size], buf_size - pkt_size); /* wr 6B 0021 */
  213. /* F1.9 Enable HW auto control */
  214. pkt_size += fm_bop_write(0x60, 0x000F, &buf[pkt_size], buf_size - pkt_size); /* wr 60 f */
  215. /* F1.10 Release ASIP reset */
  216. pkt_size += fm_bop_modify(0x61, 0xFFFD, 0x0002, &buf[pkt_size], buf_size - pkt_size); /* wr 61 D1=1 */
  217. /* F1.11 Enable ASIP power */
  218. pkt_size += fm_bop_modify(0x61, 0xFFFE, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 61 D0=0 */
  219. pkt_size += fm_bop_udelay(100000, &buf[pkt_size], buf_size - pkt_size); /* delay 100ms */
  220. /* F1.13 Check HW intitial complete */
  221. pkt_size += fm_bop_rd_until(0x64, 0x001F, 0x0002, &buf[pkt_size], buf_size - pkt_size); /* Poll 64[0~4] = 2 */
  222. buf[2] = (fm_u8) ((pkt_size - 4) & 0x00FF);
  223. buf[3] = (fm_u8) (((pkt_size - 4) >> 8) & 0x00FF);
  224. return pkt_size;
  225. }
  226. /*
  227. * mt6630_pwrdown - Wholechip FM Power down: Digital Modem Power Down
  228. * @buf - target buf
  229. * @buf_size - buffer size
  230. * return package size
  231. */
  232. fm_s32 mt6630_pwrdown(fm_u8 *buf, fm_s32 buf_size)
  233. {
  234. fm_s32 pkt_size = 0;
  235. if (buf_size < TX_BUF_SIZE)
  236. return -1;
  237. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  238. buf[1] = FM_ENABLE_OPCODE;
  239. pkt_size = 4;
  240. /* Disable HW clock control */
  241. pkt_size += fm_bop_write(0x60, 0x0107, &buf[pkt_size], buf_size - pkt_size); /* wr 60 107 */
  242. /* Reset ASIP */
  243. pkt_size += fm_bop_write(0x61, 0x0001, &buf[pkt_size], buf_size - pkt_size); /* wr 61 0001 */
  244. /* digital core + digital rgf reset */
  245. pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 6E[0~2] 0 */
  246. pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 6E[0~2] 0 */
  247. pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 6E[0~2] 0 */
  248. pkt_size += fm_bop_modify(0x6E, 0xFFF8, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 6E[0~2] 0 */
  249. /* Disable all clock */
  250. pkt_size += fm_bop_write(0x60, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 60 0000 */
  251. /* Reset rgfrf */
  252. pkt_size += fm_bop_write(0x60, 0x4000, &buf[pkt_size], buf_size - pkt_size); /* wr 60 4000 */
  253. pkt_size += fm_bop_write(0x60, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr 60 0000 */
  254. buf[2] = (fm_u8) ((pkt_size - 4) & 0x00FF);
  255. buf[3] = (fm_u8) (((pkt_size - 4) >> 8) & 0x00FF);
  256. return pkt_size;
  257. }
  258. /*
  259. * mt6630_rampdown - f/w will wait for STC_DONE interrupt
  260. * @buf - target buf
  261. * @buf_size - buffer size
  262. * return package size
  263. */
  264. fm_s32 mt6630_rampdown(fm_u8 *buf, fm_s32 buf_size)
  265. {
  266. fm_s32 pkt_size = 0;
  267. if (buf_size < TX_BUF_SIZE)
  268. return -1;
  269. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  270. buf[1] = FM_RAMPDOWN_OPCODE;
  271. pkt_size = 4;
  272. /* Clear DSP state */
  273. pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFF0, 0x0000, &buf[pkt_size], buf_size - pkt_size);
  274. /* Set DSP ramp down state */
  275. pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFFF, RAMP_DOWN, &buf[pkt_size], buf_size - pkt_size);
  276. /* @Wait for STC_DONE interrupt@ */
  277. pkt_size += fm_bop_rd_until(FM_MAIN_INTR, FM_INTR_STC_DONE, FM_INTR_STC_DONE, &buf[pkt_size],
  278. buf_size - pkt_size);
  279. /* Clear DSP ramp down state */
  280. pkt_size += fm_bop_modify(FM_MAIN_CTRL, (~RAMP_DOWN), 0x0000, &buf[pkt_size], buf_size - pkt_size);
  281. /* Write 1 clear the STC_DONE interrupt status flag */
  282. pkt_size += fm_bop_modify(FM_MAIN_INTR, 0xFFFF, FM_INTR_STC_DONE, &buf[pkt_size], buf_size - pkt_size);
  283. buf[2] = (fm_u8) ((pkt_size - 4) & 0x00FF);
  284. buf[3] = (fm_u8) (((pkt_size - 4) >> 8) & 0x00FF);
  285. return pkt_size;
  286. }
  287. /*
  288. * mt6630_tune - execute tune action,
  289. * @buf - target buf
  290. * @buf_size - buffer size
  291. * @freq - 760 ~ 1080, 100KHz unit
  292. * return package size
  293. */
  294. fm_s32 mt6630_tune(fm_u8 *buf, fm_s32 buf_size, fm_u16 freq, fm_u16 chan_para)
  295. {
  296. /* #define FM_TUNE_USE_POLL */
  297. fm_s32 pkt_size = 0;
  298. if (buf_size < TX_BUF_SIZE)
  299. return -1;
  300. if (0 == fm_get_channel_space(freq))
  301. freq *= 10;
  302. freq = (freq - 6400) * 2 / 10;
  303. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  304. buf[1] = FM_TUNE_OPCODE;
  305. pkt_size = 4;
  306. /* Set desired channel & channel parameter */
  307. #ifdef FM_TUNE_USE_POLL
  308. pkt_size += fm_bop_write(0x6A, 0x0000, &buf[pkt_size], buf_size - pkt_size);
  309. pkt_size += fm_bop_write(0x6B, 0x0000, &buf[pkt_size], buf_size - pkt_size);
  310. #endif
  311. pkt_size += fm_bop_modify(FM_CHANNEL_SET, 0xFC00, freq, &buf[pkt_size], buf_size - pkt_size);
  312. /* channel para setting, D15~D12, D15: ATJ, D13: HL, D12: FA */
  313. pkt_size += fm_bop_modify(FM_CHANNEL_SET, 0x0FFF, (chan_para << 12), &buf[pkt_size], buf_size - pkt_size);
  314. /* Enable hardware controlled tuning sequence */
  315. pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFF8, TUNE, &buf[pkt_size], buf_size - pkt_size);
  316. /* Wait for STC_DONE interrupt */
  317. #ifdef FM_TUNE_USE_POLL
  318. pkt_size += fm_bop_rd_until(FM_MAIN_INTR, FM_INTR_STC_DONE, FM_INTR_STC_DONE, &buf[pkt_size],
  319. buf_size - pkt_size);
  320. /* Write 1 clear the STC_DONE interrupt status flag */
  321. pkt_size += fm_bop_modify(FM_MAIN_INTR, 0xFFFF, FM_INTR_STC_DONE, &buf[pkt_size], buf_size - pkt_size);
  322. #endif
  323. buf[2] = (fm_u8) ((pkt_size - 4) & 0x00FF);
  324. buf[3] = (fm_u8) (((pkt_size - 4) >> 8) & 0x00FF);
  325. return pkt_size;
  326. }
  327. /*
  328. * mt6630_full_cqi_req - execute request cqi info action,
  329. * @buf - target buf
  330. * @buf_size - buffer size
  331. * @freq - 7600 ~ 10800, freq array
  332. * @cnt - channel count
  333. * @type - request type, 1: a single channel; 2: multi channel; 3:multi channel with 100Khz step; 4: multi channel with 50Khz step
  334. *
  335. * return package size
  336. */
  337. fm_s32 mt6630_full_cqi_req(fm_u8 *buf, fm_s32 buf_size, fm_u16 *freq, fm_s32 cnt, fm_s32 type)
  338. {
  339. fm_s32 pkt_size = 0;
  340. if (buf_size < TX_BUF_SIZE)
  341. return -1;
  342. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  343. buf[1] = FM_SOFT_MUTE_TUNE_OPCODE;
  344. pkt_size = 4;
  345. switch (type) {
  346. case 1:
  347. buf[pkt_size] = 0x0001;
  348. pkt_size++;
  349. buf[pkt_size] = (fm_u8) ((*freq) & 0x00FF);
  350. pkt_size++;
  351. buf[pkt_size] = (fm_u8) ((*freq >> 8) & 0x00FF);
  352. pkt_size++;
  353. break;
  354. case 2:
  355. buf[pkt_size] = 0x0002;
  356. pkt_size++;
  357. break;
  358. case 3:
  359. buf[pkt_size] = 0x0003;
  360. pkt_size++;
  361. break;
  362. case 4:
  363. buf[pkt_size] = 0x0004;
  364. pkt_size++;
  365. break;
  366. default:
  367. buf[pkt_size] = (fm_u16) type;
  368. pkt_size++;
  369. break;
  370. }
  371. buf[2] = (fm_u8) ((pkt_size - 4) & 0x00FF);
  372. buf[3] = (fm_u8) (((pkt_size - 4) >> 8) & 0x00FF);
  373. return pkt_size;
  374. }
  375. /*
  376. * mt6630_seek - execute seek action,
  377. * @buf - target buf
  378. * @buf_size - buffer size
  379. * @seekdir - 0=seek up, 1=seek down
  380. * @space - step, 50KHz:001, 100KHz:010, 200KHz:100
  381. * @max_freq - upper bound
  382. * @min_freq - lower bound
  383. * return package size
  384. */
  385. fm_s32 mt6630_seek(fm_u8 *buf, fm_s32 buf_size, fm_u16 seekdir, fm_u16 space, fm_u16 max_freq, fm_u16 min_freq)
  386. {
  387. fm_s32 pkt_size = 0;
  388. if (buf_size < TX_BUF_SIZE)
  389. return -1;
  390. if (0 == fm_get_channel_space(max_freq))
  391. max_freq *= 10;
  392. if (0 == fm_get_channel_space(min_freq))
  393. min_freq *= 10;
  394. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  395. buf[1] = FM_SEEK_OPCODE;
  396. pkt_size = 4;
  397. /* Program seek direction */
  398. if (seekdir == 0) {
  399. pkt_size += fm_bop_modify(FM_MAIN_CFG1, 0xFBFF, 0x0000, &buf[pkt_size], buf_size - pkt_size);
  400. /* 0x66[10] = 0, seek up */
  401. } else {
  402. pkt_size += fm_bop_modify(FM_MAIN_CFG1, 0xFBFF, 0x0400, &buf[pkt_size], buf_size - pkt_size);
  403. /* 0x66[10] = 1, seek down */
  404. }
  405. /* Program scan channel spacing */
  406. if (space == 1) {
  407. pkt_size += fm_bop_modify(FM_MAIN_CFG1, 0x8FFF, 0x1000, &buf[pkt_size], buf_size - pkt_size);
  408. /* clear 0x66[14:12] then 0x66[14:12]=001 */
  409. } else if (space == 2) {
  410. pkt_size += fm_bop_modify(FM_MAIN_CFG1, 0x8FFF, 0x2000, &buf[pkt_size], buf_size - pkt_size);
  411. /* clear 0x66[14:12] then 0x66[14:12]=010 */
  412. } else if (space == 4) {
  413. pkt_size += fm_bop_modify(FM_MAIN_CFG1, 0x8FFF, 0x4000, &buf[pkt_size], buf_size - pkt_size);
  414. /* clear 0x66[14:12] then 0x66[14:12]=100 */
  415. }
  416. /* enable wrap , if it is not auto scan function, 0x66[11] 0=no wrarp, 1=wrap */
  417. pkt_size += fm_bop_modify(FM_MAIN_CFG1, 0xF7FF, 0x0800, &buf[pkt_size], buf_size - pkt_size);
  418. /* 0x66[11] = 1, wrap */
  419. /* 0x66[9:0] freq upper bound */
  420. max_freq = (max_freq - 6400) * 2 / 10;
  421. pkt_size += fm_bop_modify(FM_MAIN_CFG1, 0xFC00, max_freq, &buf[pkt_size], buf_size - pkt_size);
  422. /* 0x67[9:0] freq lower bound */
  423. min_freq = (min_freq - 6400) * 2 / 10;
  424. pkt_size += fm_bop_modify(FM_MAIN_CFG2, 0xFC00, min_freq, &buf[pkt_size], buf_size - pkt_size);
  425. /* Enable hardware controlled seeking sequence */
  426. pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFF8, SEEK, &buf[pkt_size], buf_size - pkt_size);
  427. buf[2] = (fm_u8) ((pkt_size - 4) & 0x00FF);
  428. buf[3] = (fm_u8) (((pkt_size - 4) >> 8) & 0x00FF);
  429. return pkt_size;
  430. }
  431. /*
  432. * mt6630_scan - execute scan action,
  433. * @buf - target buf
  434. * @buf_size - buffer size
  435. * @scandir - 0=seek up, 1=seek down
  436. * @space - step, 50KHz:001, 100KHz:010, 200KHz:100
  437. * @max_freq - upper bound
  438. * @min_freq - lower bound
  439. * return package size
  440. */
  441. fm_s32 mt6630_scan(fm_u8 *buf, fm_s32 buf_size, fm_u16 scandir, fm_u16 space, fm_u16 max_freq, fm_u16 min_freq)
  442. {
  443. fm_s32 pkt_size = 0;
  444. if (buf_size < TX_BUF_SIZE)
  445. return -1;
  446. if (0 == fm_get_channel_space(max_freq))
  447. max_freq *= 10;
  448. if (0 == fm_get_channel_space(min_freq))
  449. min_freq *= 10;
  450. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  451. buf[1] = FM_SCAN_OPCODE;
  452. pkt_size = 4;
  453. /* Program seek direction */
  454. if (scandir == 0) {
  455. pkt_size += fm_bop_modify(FM_MAIN_CFG1, 0xFBFF, 0x0000, &buf[pkt_size], buf_size - pkt_size);
  456. /* 0x66[10] = 0, seek up */
  457. } else {
  458. pkt_size += fm_bop_modify(FM_MAIN_CFG1, 0xFFFF, 0x0400, &buf[pkt_size], buf_size - pkt_size);
  459. /* 0x66[10] = 1, seek down */
  460. }
  461. /* Program scan channel spacing */
  462. if (space == 1)
  463. pkt_size += fm_bop_modify(FM_MAIN_CFG1, 0x8FFF, 0x1000, &buf[pkt_size], buf_size - pkt_size);
  464. /* clear 0x66[14:12] then 0x66[14:12]=001 */
  465. else if (space == 2)
  466. pkt_size += fm_bop_modify(FM_MAIN_CFG1, 0x8FFF, 0x2000, &buf[pkt_size], buf_size - pkt_size);
  467. /* clear 0x66[14:12] then 0x66[14:12]=010 */
  468. else if (space == 4)
  469. pkt_size += fm_bop_modify(FM_MAIN_CFG1, 0x8FFF, 0x4000, &buf[pkt_size], buf_size - pkt_size);
  470. /* clear 0x66[14:12] then 0x66[14:12]=100 */
  471. /* disable wrap , if it is auto scan function, 0x66[11] 0=no wrarp, 1=wrap */
  472. pkt_size += fm_bop_modify(FM_MAIN_CFG1, 0xF7FF, 0x0000, &buf[pkt_size], buf_size - pkt_size);
  473. /* 0x66[11] = 0, no wrap */
  474. /* 0x66[9:0] freq upper bound */
  475. max_freq = (max_freq - 6400) * 2 / 10;
  476. pkt_size += fm_bop_modify(FM_MAIN_CFG1, 0xFC00, max_freq, &buf[pkt_size], buf_size - pkt_size);
  477. /* 0x67[9:0] freq lower bound */
  478. min_freq = (min_freq - 6400) * 2 / 10;
  479. pkt_size += fm_bop_modify(FM_MAIN_CFG2, 0xFC00, min_freq, &buf[pkt_size], buf_size - pkt_size);
  480. /* Enable hardware controlled scanning sequence */
  481. pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFF8, SCAN, &buf[pkt_size], buf_size - pkt_size);
  482. buf[2] = (fm_u8) ((pkt_size - 4) & 0x00FF);
  483. buf[3] = (fm_u8) (((pkt_size - 4) >> 8) & 0x00FF);
  484. return pkt_size;
  485. }
  486. fm_s32 mt6630_cqi_get(fm_u8 *buf, fm_s32 buf_size)
  487. {
  488. fm_s32 pkt_size = 0;
  489. if (buf_size < TX_BUF_SIZE)
  490. return -1;
  491. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  492. buf[1] = FM_SCAN_OPCODE;
  493. pkt_size = 4;
  494. pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFF0, 0x0000, &buf[pkt_size], buf_size - pkt_size);
  495. /* wr 63 bit0~2 0 */
  496. pkt_size += fm_bop_modify(FM_MAIN_CTRL, ~CQI_READ, CQI_READ, &buf[pkt_size], buf_size - pkt_size);
  497. /* wr 63 bit3 1 */
  498. buf[2] = (fm_u8) ((pkt_size - 4) & 0x00FF);
  499. buf[3] = (fm_u8) (((pkt_size - 4) >> 8) & 0x00FF);
  500. return pkt_size;
  501. }
  502. fm_s32 mt6630_get_reg(fm_u8 *buf, fm_s32 buf_size, fm_u8 addr)
  503. {
  504. if (buf_size < TX_BUF_SIZE)
  505. return -1;
  506. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  507. buf[1] = FSPI_READ_OPCODE;
  508. buf[2] = 0x01;
  509. buf[3] = 0x00;
  510. buf[4] = addr;
  511. WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4]);
  512. return 5;
  513. }
  514. fm_s32 mt6630_set_reg(fm_u8 *buf, fm_s32 buf_size, fm_u8 addr, fm_u16 value)
  515. {
  516. if (buf_size < TX_BUF_SIZE)
  517. return -1;
  518. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  519. buf[1] = FSPI_WRITE_OPCODE;
  520. buf[2] = 0x03;
  521. buf[3] = 0x00;
  522. buf[4] = addr;
  523. buf[5] = (fm_u8) ((value) & 0x00FF);
  524. buf[6] = (fm_u8) ((value >> 8) & 0x00FF);
  525. WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2],
  526. buf[3], buf[4], buf[5], buf[6]);
  527. return 7;
  528. }
  529. fm_s32 mt6630_set_bits_reg(fm_u8 *buf, fm_s32 buf_size, fm_u8 addr, fm_u16 bits, fm_u16 mask)
  530. {
  531. fm_s32 pkt_size = 0;
  532. if (buf_size < TX_BUF_SIZE)
  533. return -1;
  534. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  535. buf[1] = 0x11; /* 0x11 this opcode won't be parsed as an opcode, so set here as spcial case. */
  536. pkt_size = 4;
  537. pkt_size += fm_bop_modify(addr, mask, bits, &buf[pkt_size], buf_size - pkt_size);
  538. buf[2] = (fm_u8) ((pkt_size - 4) & 0x00FF);
  539. buf[3] = (fm_u8) (((pkt_size - 4) >> 8) & 0x00FF);
  540. return pkt_size;
  541. }
  542. /*top register read*/
  543. fm_s32 mt6630_top_get_reg(fm_u8 *buf, fm_s32 buf_size, fm_u16 addr)
  544. {
  545. if (buf_size < TX_BUF_SIZE)
  546. return -1;
  547. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  548. buf[1] = CSPI_READ_OPCODE;
  549. buf[2] = 0x03;
  550. buf[3] = 0x00;
  551. buf[4] = 0x04; /* top 04,fm 02 */
  552. buf[5] = (fm_u8) ((addr) & 0x00FF);
  553. buf[6] = (fm_u8) ((addr >> 8) & 0x00FF);
  554. WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2],
  555. buf[3], buf[4], buf[5], buf[6]);
  556. return 7;
  557. }
  558. fm_s32 mt6630_top_set_reg(fm_u8 *buf, fm_s32 buf_size, fm_u16 addr, fm_u32 value)
  559. {
  560. if (buf_size < TX_BUF_SIZE)
  561. return -1;
  562. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  563. buf[1] = CSPI_WRITE_OPCODE;
  564. buf[2] = 0x07;
  565. buf[3] = 0x00;
  566. buf[4] = 0x04; /* top 04,fm 02 */
  567. buf[5] = (fm_u8) ((addr) & 0x00FF);
  568. buf[6] = (fm_u8) ((addr >> 8) & 0x00FF);
  569. buf[7] = (fm_u8) ((value) & 0x00FF);
  570. buf[8] = (fm_u8) ((value >> 8) & 0x00FF);
  571. buf[9] = (fm_u8) ((value >> 16) & 0x00FF);
  572. buf[10] = (fm_u8) ((value >> 24) & 0x00FF);
  573. WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", buf[0],
  574. buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10]);
  575. return 11;
  576. }
  577. /*host register read*/
  578. fm_s32 mt6630_host_get_reg(fm_u8 *buf, fm_s32 buf_size, fm_u32 addr)
  579. {
  580. if (buf_size < TX_BUF_SIZE)
  581. return -1;
  582. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  583. buf[1] = FM_HOST_READ_OPCODE;
  584. buf[2] = 0x04;
  585. buf[3] = 0x00;
  586. buf[4] = (fm_u8) ((addr) & 0x00FF);
  587. buf[5] = (fm_u8) ((addr >> 8) & 0x00FF);
  588. buf[6] = (fm_u8) ((addr >> 16) & 0x00FF);
  589. buf[7] = (fm_u8) ((addr >> 24) & 0x00FF);
  590. WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2],
  591. buf[3], buf[4], buf[5], buf[6], buf[7]);
  592. return 8;
  593. }
  594. fm_s32 mt6630_host_set_reg(fm_u8 *buf, fm_s32 buf_size, fm_u32 addr, fm_u32 value)
  595. {
  596. if (buf_size < TX_BUF_SIZE)
  597. return -1;
  598. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  599. buf[1] = FM_HOST_WRITE_OPCODE;
  600. buf[2] = 0x08;
  601. buf[3] = 0x00;
  602. buf[4] = (fm_u8) ((addr) & 0x00FF);
  603. buf[5] = (fm_u8) ((addr >> 8) & 0x00FF);
  604. buf[6] = (fm_u8) ((addr >> 16) & 0x00FF);
  605. buf[7] = (fm_u8) ((addr >> 24) & 0x00FF);
  606. buf[8] = (fm_u8) ((value) & 0x00FF);
  607. buf[9] = (fm_u8) ((value >> 8) & 0x00FF);
  608. buf[10] = (fm_u8) ((value >> 16) & 0x00FF);
  609. buf[11] = (fm_u8) ((value >> 24) & 0x00FF);
  610. WCN_DBG(FM_DBG | CHIP, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
  611. buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]);
  612. return 12;
  613. }
  614. /********************************Tx function***********************************************/
  615. /*
  616. * mt6630_pwrup_clock_on_tx - FM tx Digital Clock enable
  617. * @buf - target buf
  618. * @buf_size - buffer size
  619. * return package size
  620. */
  621. fm_s32 mt6630_pwrup_clock_on_tx(fm_u8 *buf, fm_s32 buf_size)
  622. {
  623. fm_s32 pkt_size = 0;
  624. if (buf_size < TX_BUF_SIZE)
  625. return -1;
  626. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  627. buf[1] = FM_ENABLE_OPCODE;
  628. pkt_size = 4;
  629. /* B1.0 Enable digital OSC */
  630. pkt_size += fm_bop_write(0x60, 0x0003, &buf[pkt_size], buf_size - pkt_size); /* wr 60 3 */
  631. pkt_size += fm_bop_udelay(100, &buf[pkt_size], buf_size - pkt_size); /* delay 100us */
  632. /* B1.2 Release HW clock gating */
  633. pkt_size += fm_bop_write(0x60, 0x0007, &buf[pkt_size], buf_size - pkt_size); /* wr 60 7 */
  634. if (mt6630_fm_config.aud_cfg.aud_path == FM_AUD_ANALOG)
  635. pkt_size += fm_bop_modify(0x61, 0xFF7F, 0x0000, &buf[pkt_size], buf_size - pkt_size);
  636. else
  637. pkt_size += fm_bop_modify(0x61, 0xFF7F, 0x0080, &buf[pkt_size], buf_size - pkt_size);
  638. /* B1.4 set TX mode: 0909 sequence */
  639. pkt_size += fm_bop_write(0xC7, 0x8286, &buf[pkt_size], buf_size - pkt_size); /* wr C7 8286 */
  640. buf[2] = (fm_u8) ((pkt_size - 4) & 0x00FF);
  641. buf[3] = (fm_u8) (((pkt_size - 4) >> 8) & 0x00FF);
  642. return pkt_size;
  643. }
  644. /*
  645. * mt6630_pwrup_tx_deviation - default deviation (RDS off)
  646. * @buf - target buf
  647. * @buf_size - buffer size
  648. * return package size
  649. */
  650. fm_s32 mt6630_pwrup_tx_deviation(fm_u8 *buf, fm_s32 buf_size)
  651. {
  652. fm_s32 pkt_size = 0;
  653. if (buf_size < TX_BUF_SIZE)
  654. return -1;
  655. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  656. buf[1] = FM_ENABLE_OPCODE;
  657. pkt_size = 4;
  658. /* A1 switch to host control */
  659. pkt_size += fm_bop_write(0x60, 0x0007, &buf[pkt_size], buf_size - pkt_size); /* wr 60 0007 */
  660. /* set rgf_tx_beta_sum */
  661. pkt_size += fm_bop_write(0xCD, 0x72D2, &buf[pkt_size], buf_size - pkt_size); /* wr CD 72D2 */
  662. /* set rgf_tx_beta_diff */
  663. pkt_size += fm_bop_write(0xCF, 0x787B, &buf[pkt_size], buf_size - pkt_size); /* wr CF 787B */
  664. /* set rgf_tx_beta_rds */
  665. pkt_size += fm_bop_write(0xCE, 0x0785, &buf[pkt_size], buf_size - pkt_size); /* wr CE 785 */
  666. /* set rgf_tx_beta_pilot */
  667. pkt_size += fm_bop_write(0xCC, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr CC 0 */
  668. /* set rgf_phase_gen_rsh */
  669. pkt_size += fm_bop_modify(0xAD, 0xFFE8, 0x0001, &buf[pkt_size], buf_size - pkt_size); /* wr AD D4 D2:D0=1 */
  670. /* set rgf_phase_gen_wb */
  671. pkt_size += fm_bop_modify(0xA8, 0xF000, 0x0F16, &buf[pkt_size], buf_size - pkt_size); /* wr A8 D11:D0=F16 */
  672. /* set agc */
  673. pkt_size += fm_bop_modify(0xAE, 0xFC00, 0x020B, &buf[pkt_size], buf_size - pkt_size); /* wr AE D9:D0=20B */
  674. /* set rgf_beta_fm */
  675. pkt_size += fm_bop_write(0xEE, 0x623D, &buf[pkt_size], buf_size - pkt_size); /* wr EE 623D */
  676. /* switch to DSP control */
  677. pkt_size += fm_bop_write(0x60, 0x000F, &buf[pkt_size], buf_size - pkt_size); /* wr 60 000F */
  678. buf[2] = (fm_u8) ((pkt_size - 4) & 0x00FF);
  679. buf[3] = (fm_u8) (((pkt_size - 4) >> 8) & 0x00FF);
  680. return pkt_size;
  681. }
  682. /*
  683. * mt6630_tx_rdsoff_deviation - deviation (RDS on)
  684. * @buf - target buf
  685. * @buf_size - buffer size
  686. * return package size
  687. */
  688. fm_s32 mt6630_tx_rdson_deviation(fm_u8 *buf, fm_s32 buf_size)
  689. {
  690. fm_s32 pkt_size = 0;
  691. if (buf_size < TX_BUF_SIZE)
  692. return -1;
  693. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  694. buf[1] = RDS_TX_OPCODE;
  695. pkt_size = 4;
  696. /* A1 switch to host control */
  697. pkt_size += fm_bop_write(0x60, 0x0007, &buf[pkt_size], buf_size - pkt_size); /* wr 60 0007 */
  698. /* set rgf_tx_beta_sum */
  699. pkt_size += fm_bop_write(0xCD, 0x70E3, &buf[pkt_size], buf_size - pkt_size); /* wr CD 70E3 */
  700. /* set rgf_tx_beta_diff */
  701. pkt_size += fm_bop_write(0xCF, 0x7675, &buf[pkt_size], buf_size - pkt_size); /* wr CF 7675 */
  702. /* set rgf_tx_beta_rds:0909 sequence */
  703. pkt_size += fm_bop_write(0xCC, 0x0227, &buf[pkt_size], buf_size - pkt_size); /* wr CC 227 */
  704. /* set rgf_tx_beta_pilot :0909 sequence */
  705. pkt_size += fm_bop_write(0xCE, 0x0764, &buf[pkt_size], buf_size - pkt_size); /* wr CE 764 */
  706. /* set rgf_phase_gen_rsh */
  707. pkt_size += fm_bop_modify(0xAD, 0xFFEF, 0x0000, &buf[pkt_size], buf_size - pkt_size); /* wr AD D4 =0 */
  708. pkt_size += fm_bop_modify(0xAD, 0xFFF8, 0x0001, &buf[pkt_size], buf_size - pkt_size); /* wr AD D2:D0=1 */
  709. /* set rgf_phase_gen_wb */
  710. pkt_size += fm_bop_modify(0xA8, 0xF000, 0x0222, &buf[pkt_size], buf_size - pkt_size); /* wr A8 D11:D0=222 */
  711. /* set agc */
  712. pkt_size += fm_bop_modify(0xAE, 0xFC00, 0x0203, &buf[pkt_size], buf_size - pkt_size); /* wr AE D9:D0=203 */
  713. /* set rgf_beta_fm */
  714. pkt_size += fm_bop_write(0xEE, 0x63EB, &buf[pkt_size], buf_size - pkt_size); /* wr EE 63EB */
  715. /* switch to DSP control */
  716. pkt_size += fm_bop_write(0x60, 0x000F, &buf[pkt_size], buf_size - pkt_size); /* wr 60 000F */
  717. buf[2] = (fm_u8) ((pkt_size - 4) & 0x00FF);
  718. buf[3] = (fm_u8) (((pkt_size - 4) >> 8) & 0x00FF);
  719. return pkt_size;
  720. }
  721. /*
  722. * mt6630_tune_tx - execute tx tune action,
  723. * @buf - target buf
  724. * @buf_size - buffer size
  725. * @freq - 760 ~ 1080, 100KHz unit
  726. * return package size
  727. */
  728. fm_s32 mt6630_tune_tx(fm_u8 *buf, fm_s32 buf_size, fm_u16 freq, fm_u16 chan_para)
  729. {
  730. /* #define FM_TUNE_USE_POLL */
  731. fm_s32 pkt_size = 0;
  732. if (buf_size < TX_BUF_SIZE)
  733. return -1;
  734. if (0 == fm_get_channel_space(freq))
  735. freq *= 10;
  736. freq = (freq - 6400) * 2 / 10;
  737. buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  738. buf[1] = FM_TUNE_OPCODE;
  739. pkt_size = 4;
  740. /* Set desired channel & channel parameter */
  741. #ifdef FM_TUNE_USE_POLL
  742. pkt_size += fm_bop_write(0x6B, 0x0000, &buf[pkt_size], buf_size - pkt_size);
  743. #endif
  744. /* sequence 09/16:0x65 D12=1 for iq switch */
  745. pkt_size += fm_bop_modify(FM_CHANNEL_SET, 0xEC00, freq | 0x1000, &buf[pkt_size], buf_size - pkt_size);
  746. /* set 0x65[9:0] = 0x029e, => ((97.5 - 64) * 20) */
  747. /* set iq switch, D12 */
  748. /* pkt_size += fm_bop_modify(FM_CHANNEL_SET, 0x0FFF, (chan_para << 12), &buf[pkt_size], buf_size - pkt_size); */
  749. /* Enable hardware controlled tuning sequence */
  750. pkt_size += fm_bop_modify(FM_MAIN_CTRL, 0xFFF8, TUNE, &buf[pkt_size], buf_size - pkt_size);
  751. /* Wait for STC_DONE interrupt */
  752. #ifdef FM_TUNE_USE_POLL
  753. pkt_size += fm_bop_rd_until(FM_MAIN_INTR, FM_INTR_STC_DONE, FM_INTR_STC_DONE, &buf[pkt_size],
  754. buf_size - pkt_size);
  755. /* Write 1 clear the STC_DONE interrupt status flag */
  756. pkt_size += fm_bop_modify(FM_MAIN_INTR, 0xFFFF, FM_INTR_STC_DONE, &buf[pkt_size], buf_size - pkt_size);
  757. #endif
  758. buf[2] = (fm_u8) ((pkt_size - 4) & 0x00FF);
  759. buf[3] = (fm_u8) (((pkt_size - 4) >> 8) & 0x00FF);
  760. return pkt_size;
  761. }
  762. /*
  763. pi: pi code
  764. ps: block B,C,D
  765. other_rds: unused
  766. other_rds_cnt: unused
  767. */
  768. fm_s32 mt6630_rds_tx(fm_u8 *tx_buf, fm_s32 tx_buf_size, fm_u16 pi, fm_u16 *ps, fm_u16 *other_rds,
  769. fm_u8 other_rds_cnt)
  770. {
  771. fm_s32 pkt_size = 0;
  772. fm_s32 i;
  773. if (tx_buf_size < TX_BUF_SIZE)
  774. return -1;
  775. tx_buf[0] = FM_TASK_COMMAND_PKT_TYPE;
  776. tx_buf[1] = RDS_TX_OPCODE;
  777. pkt_size = 4;
  778. /* set repeat mode */
  779. pkt_size += fm_bop_modify(0x88, 0xFFFE, 0x0001, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);
  780. /* wr 88[0] = b'1, repeat mode */
  781. pkt_size += fm_bop_modify(0x88, 0xFFFB, 0x0004, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);
  782. /* wr 88[2] = b'1, PI_reg mode */
  783. pkt_size += fm_bop_write(0x8A, pi, &tx_buf[pkt_size], tx_buf_size - pkt_size);
  784. /* write PI to PI_reg */
  785. pkt_size += fm_bop_modify(0x88, 0xFFFD, 0x0002, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);
  786. /* wr 88[1] = b'1, addr from host */
  787. for (i = 0; i < 12; i++) {
  788. pkt_size += fm_bop_write(0x8B, (0x0063 + i), &tx_buf[pkt_size], tx_buf_size - pkt_size);
  789. /* 8B = mem_addr */
  790. pkt_size += fm_bop_write(0x8C, ps[i], &tx_buf[pkt_size], tx_buf_size - pkt_size);
  791. /* 8C = RDS Tx data */
  792. }
  793. pkt_size += fm_bop_modify(0x88, 0xFFFD, 0x0000, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);
  794. /* wr 88[1] = b'0, clear mem_addr */
  795. pkt_size += fm_bop_modify(0x88, 0xFFEF, 0x0010, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);
  796. /* wr 88[4] = b'1, switch to ps buf */
  797. /* work around: write at leat one group to normal buffer, otherwise ps buffer can be sent out. */
  798. pkt_size += fm_bop_write(0x8C, 0, &tx_buf[pkt_size], tx_buf_size - pkt_size);
  799. pkt_size += fm_bop_write(0x8C, 0, &tx_buf[pkt_size], tx_buf_size - pkt_size);
  800. pkt_size += fm_bop_write(0x8C, 0, &tx_buf[pkt_size], tx_buf_size - pkt_size);
  801. pkt_size += fm_bop_write(0x8C, 0, &tx_buf[pkt_size], tx_buf_size - pkt_size);
  802. pkt_size += fm_bop_modify(0x88, 0xFFDF, 0x0020, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);
  803. /* wr 88[5] = b'1,clear in_ptr */
  804. pkt_size += fm_bop_modify(0x88, 0xFFDF, 0x0000, &tx_buf[pkt_size], TX_BUF_SIZE - pkt_size);
  805. /* wr 88[5] = b'0,clear in_ptr */
  806. tx_buf[2] = (fm_u8) ((pkt_size - 4) & 0x00FF);
  807. tx_buf[3] = (fm_u8) (((pkt_size - 4) >> 8) & 0x00FF);
  808. return pkt_size;
  809. }