wm8750.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  1. /*
  2. * WM8750 audio CODEC.
  3. *
  4. * Copyright (c) 2006 Openedhand Ltd.
  5. * Written by Andrzej Zaborowski <balrog@zabor.org>
  6. *
  7. * This file is licensed under GNU GPL.
  8. */
  9. #include "qemu/osdep.h"
  10. #include "hw/i2c/i2c.h"
  11. #include "migration/vmstate.h"
  12. #include "qemu/module.h"
  13. #include "hw/audio/wm8750.h"
  14. #include "audio/audio.h"
  15. #include "qom/object.h"
  16. #define IN_PORT_N 3
  17. #define OUT_PORT_N 3
  18. #define CODEC "wm8750"
  19. typedef struct {
  20. int adc;
  21. int adc_hz;
  22. int dac;
  23. int dac_hz;
  24. } WMRate;
  25. OBJECT_DECLARE_SIMPLE_TYPE(WM8750State, WM8750)
  26. struct WM8750State {
  27. I2CSlave parent_obj;
  28. uint8_t i2c_data[2];
  29. int i2c_len;
  30. QEMUSoundCard card;
  31. SWVoiceIn *adc_voice[IN_PORT_N];
  32. SWVoiceOut *dac_voice[OUT_PORT_N];
  33. int enable;
  34. void (*data_req)(void *, int, int);
  35. void *opaque;
  36. uint8_t data_in[4096];
  37. uint8_t data_out[4096];
  38. int idx_in, req_in;
  39. int idx_out, req_out;
  40. SWVoiceOut **out[2];
  41. uint8_t outvol[7], outmute[2];
  42. SWVoiceIn **in[2];
  43. uint8_t invol[4], inmute[2];
  44. uint8_t diff[2], pol, ds, monomix[2], alc, mute;
  45. uint8_t path[4], mpath[2], power, format;
  46. const WMRate *rate;
  47. uint8_t rate_vmstate;
  48. int adc_hz, dac_hz, ext_adc_hz, ext_dac_hz, master;
  49. };
  50. /* pow(10.0, -i / 20.0) * 255, i = 0..42 */
  51. static const uint8_t wm8750_vol_db_table[] = {
  52. 255, 227, 203, 181, 161, 143, 128, 114, 102, 90, 81, 72, 64, 57, 51, 45,
  53. 40, 36, 32, 29, 26, 23, 20, 18, 16, 14, 13, 11, 10, 9, 8, 7, 6, 6, 5, 5,
  54. 4, 4, 3, 3, 3, 2, 2
  55. };
  56. #define WM8750_OUTVOL_TRANSFORM(x) wm8750_vol_db_table[(0x7f - x) / 3]
  57. #define WM8750_INVOL_TRANSFORM(x) (x << 2)
  58. static inline void wm8750_in_load(WM8750State *s)
  59. {
  60. if (s->idx_in + s->req_in <= sizeof(s->data_in))
  61. return;
  62. s->idx_in = MAX(0, (int) sizeof(s->data_in) - s->req_in);
  63. AUD_read(*s->in[0], s->data_in + s->idx_in,
  64. sizeof(s->data_in) - s->idx_in);
  65. }
  66. static inline void wm8750_out_flush(WM8750State *s)
  67. {
  68. int sent = 0;
  69. while (sent < s->idx_out)
  70. sent += AUD_write(*s->out[0], s->data_out + sent, s->idx_out - sent)
  71. ?: s->idx_out;
  72. s->idx_out = 0;
  73. }
  74. static void wm8750_audio_in_cb(void *opaque, int avail_b)
  75. {
  76. WM8750State *s = (WM8750State *) opaque;
  77. s->req_in = avail_b;
  78. s->data_req(s->opaque, s->req_out >> 2, avail_b >> 2);
  79. }
  80. static void wm8750_audio_out_cb(void *opaque, int free_b)
  81. {
  82. WM8750State *s = (WM8750State *) opaque;
  83. if (s->idx_out >= free_b) {
  84. s->idx_out = free_b;
  85. s->req_out = 0;
  86. wm8750_out_flush(s);
  87. } else
  88. s->req_out = free_b - s->idx_out;
  89. s->data_req(s->opaque, s->req_out >> 2, s->req_in >> 2);
  90. }
  91. static const WMRate wm_rate_table[] = {
  92. { 256, 48000, 256, 48000 }, /* SR: 00000 */
  93. { 384, 48000, 384, 48000 }, /* SR: 00001 */
  94. { 256, 48000, 1536, 8000 }, /* SR: 00010 */
  95. { 384, 48000, 2304, 8000 }, /* SR: 00011 */
  96. { 1536, 8000, 256, 48000 }, /* SR: 00100 */
  97. { 2304, 8000, 384, 48000 }, /* SR: 00101 */
  98. { 1536, 8000, 1536, 8000 }, /* SR: 00110 */
  99. { 2304, 8000, 2304, 8000 }, /* SR: 00111 */
  100. { 1024, 12000, 1024, 12000 }, /* SR: 01000 */
  101. { 1526, 12000, 1536, 12000 }, /* SR: 01001 */
  102. { 768, 16000, 768, 16000 }, /* SR: 01010 */
  103. { 1152, 16000, 1152, 16000 }, /* SR: 01011 */
  104. { 384, 32000, 384, 32000 }, /* SR: 01100 */
  105. { 576, 32000, 576, 32000 }, /* SR: 01101 */
  106. { 128, 96000, 128, 96000 }, /* SR: 01110 */
  107. { 192, 96000, 192, 96000 }, /* SR: 01111 */
  108. { 256, 44100, 256, 44100 }, /* SR: 10000 */
  109. { 384, 44100, 384, 44100 }, /* SR: 10001 */
  110. { 256, 44100, 1408, 8018 }, /* SR: 10010 */
  111. { 384, 44100, 2112, 8018 }, /* SR: 10011 */
  112. { 1408, 8018, 256, 44100 }, /* SR: 10100 */
  113. { 2112, 8018, 384, 44100 }, /* SR: 10101 */
  114. { 1408, 8018, 1408, 8018 }, /* SR: 10110 */
  115. { 2112, 8018, 2112, 8018 }, /* SR: 10111 */
  116. { 1024, 11025, 1024, 11025 }, /* SR: 11000 */
  117. { 1536, 11025, 1536, 11025 }, /* SR: 11001 */
  118. { 512, 22050, 512, 22050 }, /* SR: 11010 */
  119. { 768, 22050, 768, 22050 }, /* SR: 11011 */
  120. { 512, 24000, 512, 24000 }, /* SR: 11100 */
  121. { 768, 24000, 768, 24000 }, /* SR: 11101 */
  122. { 128, 88200, 128, 88200 }, /* SR: 11110 */
  123. { 192, 88200, 192, 88200 }, /* SR: 11111 */
  124. };
  125. static void wm8750_vol_update(WM8750State *s)
  126. {
  127. /* FIXME: multiply all volumes by s->invol[2], s->invol[3] */
  128. AUD_set_volume_in(s->adc_voice[0], s->mute,
  129. s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]),
  130. s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]));
  131. AUD_set_volume_in(s->adc_voice[1], s->mute,
  132. s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]),
  133. s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]));
  134. AUD_set_volume_in(s->adc_voice[2], s->mute,
  135. s->inmute[0] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[0]),
  136. s->inmute[1] ? 0 : WM8750_INVOL_TRANSFORM(s->invol[1]));
  137. /* FIXME: multiply all volumes by s->outvol[0], s->outvol[1] */
  138. /* Speaker: LOUT2VOL ROUT2VOL */
  139. AUD_set_volume_out(s->dac_voice[0], s->mute,
  140. s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[4]),
  141. s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[5]));
  142. /* Headphone: LOUT1VOL ROUT1VOL */
  143. AUD_set_volume_out(s->dac_voice[1], s->mute,
  144. s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[2]),
  145. s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[3]));
  146. /* MONOOUT: MONOVOL MONOVOL */
  147. AUD_set_volume_out(s->dac_voice[2], s->mute,
  148. s->outmute[0] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6]),
  149. s->outmute[1] ? 0 : WM8750_OUTVOL_TRANSFORM(s->outvol[6]));
  150. }
  151. static void wm8750_set_format(WM8750State *s)
  152. {
  153. int i;
  154. struct audsettings in_fmt;
  155. struct audsettings out_fmt;
  156. wm8750_out_flush(s);
  157. if (s->in[0] && *s->in[0])
  158. AUD_set_active_in(*s->in[0], 0);
  159. if (s->out[0] && *s->out[0])
  160. AUD_set_active_out(*s->out[0], 0);
  161. for (i = 0; i < IN_PORT_N; i ++)
  162. if (s->adc_voice[i]) {
  163. AUD_close_in(&s->card, s->adc_voice[i]);
  164. s->adc_voice[i] = NULL;
  165. }
  166. for (i = 0; i < OUT_PORT_N; i ++)
  167. if (s->dac_voice[i]) {
  168. AUD_close_out(&s->card, s->dac_voice[i]);
  169. s->dac_voice[i] = NULL;
  170. }
  171. if (!s->enable)
  172. return;
  173. /* Setup input */
  174. in_fmt.endianness = 0;
  175. in_fmt.nchannels = 2;
  176. in_fmt.freq = s->adc_hz;
  177. in_fmt.fmt = AUDIO_FORMAT_S16;
  178. s->adc_voice[0] = AUD_open_in(&s->card, s->adc_voice[0],
  179. CODEC ".input1", s, wm8750_audio_in_cb, &in_fmt);
  180. s->adc_voice[1] = AUD_open_in(&s->card, s->adc_voice[1],
  181. CODEC ".input2", s, wm8750_audio_in_cb, &in_fmt);
  182. s->adc_voice[2] = AUD_open_in(&s->card, s->adc_voice[2],
  183. CODEC ".input3", s, wm8750_audio_in_cb, &in_fmt);
  184. /* Setup output */
  185. out_fmt.endianness = 0;
  186. out_fmt.nchannels = 2;
  187. out_fmt.freq = s->dac_hz;
  188. out_fmt.fmt = AUDIO_FORMAT_S16;
  189. s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
  190. CODEC ".speaker", s, wm8750_audio_out_cb, &out_fmt);
  191. s->dac_voice[1] = AUD_open_out(&s->card, s->dac_voice[1],
  192. CODEC ".headphone", s, wm8750_audio_out_cb, &out_fmt);
  193. /* MONOMIX is also in stereo for simplicity */
  194. s->dac_voice[2] = AUD_open_out(&s->card, s->dac_voice[2],
  195. CODEC ".monomix", s, wm8750_audio_out_cb, &out_fmt);
  196. /* no sense emulating OUT3 which is a mix of other outputs */
  197. wm8750_vol_update(s);
  198. /* We should connect the left and right channels to their
  199. * respective inputs/outputs but we have completely no need
  200. * for mixing or combining paths to different ports, so we
  201. * connect both channels to where the left channel is routed. */
  202. if (s->in[0] && *s->in[0])
  203. AUD_set_active_in(*s->in[0], 1);
  204. if (s->out[0] && *s->out[0])
  205. AUD_set_active_out(*s->out[0], 1);
  206. }
  207. static void wm8750_clk_update(WM8750State *s, int ext)
  208. {
  209. if (s->master || !s->ext_dac_hz)
  210. s->dac_hz = s->rate->dac_hz;
  211. else
  212. s->dac_hz = s->ext_dac_hz;
  213. if (s->master || !s->ext_adc_hz)
  214. s->adc_hz = s->rate->adc_hz;
  215. else
  216. s->adc_hz = s->ext_adc_hz;
  217. if (s->master || (!s->ext_dac_hz && !s->ext_adc_hz)) {
  218. if (!ext)
  219. wm8750_set_format(s);
  220. } else {
  221. if (ext)
  222. wm8750_set_format(s);
  223. }
  224. }
  225. static void wm8750_reset(I2CSlave *i2c)
  226. {
  227. WM8750State *s = WM8750(i2c);
  228. s->rate = &wm_rate_table[0];
  229. s->enable = 0;
  230. wm8750_clk_update(s, 1);
  231. s->diff[0] = 0;
  232. s->diff[1] = 0;
  233. s->ds = 0;
  234. s->alc = 0;
  235. s->in[0] = &s->adc_voice[0];
  236. s->invol[0] = 0x17;
  237. s->invol[1] = 0x17;
  238. s->invol[2] = 0xc3;
  239. s->invol[3] = 0xc3;
  240. s->out[0] = &s->dac_voice[0];
  241. s->outvol[0] = 0xff;
  242. s->outvol[1] = 0xff;
  243. s->outvol[2] = 0x79;
  244. s->outvol[3] = 0x79;
  245. s->outvol[4] = 0x79;
  246. s->outvol[5] = 0x79;
  247. s->outvol[6] = 0x79;
  248. s->inmute[0] = 0;
  249. s->inmute[1] = 0;
  250. s->outmute[0] = 0;
  251. s->outmute[1] = 0;
  252. s->mute = 1;
  253. s->path[0] = 0;
  254. s->path[1] = 0;
  255. s->path[2] = 0;
  256. s->path[3] = 0;
  257. s->mpath[0] = 0;
  258. s->mpath[1] = 0;
  259. s->format = 0x0a;
  260. s->idx_in = sizeof(s->data_in);
  261. s->req_in = 0;
  262. s->idx_out = 0;
  263. s->req_out = 0;
  264. wm8750_vol_update(s);
  265. s->i2c_len = 0;
  266. }
  267. static int wm8750_event(I2CSlave *i2c, enum i2c_event event)
  268. {
  269. WM8750State *s = WM8750(i2c);
  270. switch (event) {
  271. case I2C_START_SEND:
  272. s->i2c_len = 0;
  273. break;
  274. case I2C_FINISH:
  275. #ifdef VERBOSE
  276. if (s->i2c_len < 2)
  277. printf("%s: message too short (%i bytes)\n",
  278. __func__, s->i2c_len);
  279. #endif
  280. break;
  281. default:
  282. break;
  283. }
  284. return 0;
  285. }
  286. #define WM8750_LINVOL 0x00
  287. #define WM8750_RINVOL 0x01
  288. #define WM8750_LOUT1V 0x02
  289. #define WM8750_ROUT1V 0x03
  290. #define WM8750_ADCDAC 0x05
  291. #define WM8750_IFACE 0x07
  292. #define WM8750_SRATE 0x08
  293. #define WM8750_LDAC 0x0a
  294. #define WM8750_RDAC 0x0b
  295. #define WM8750_BASS 0x0c
  296. #define WM8750_TREBLE 0x0d
  297. #define WM8750_RESET 0x0f
  298. #define WM8750_3D 0x10
  299. #define WM8750_ALC1 0x11
  300. #define WM8750_ALC2 0x12
  301. #define WM8750_ALC3 0x13
  302. #define WM8750_NGATE 0x14
  303. #define WM8750_LADC 0x15
  304. #define WM8750_RADC 0x16
  305. #define WM8750_ADCTL1 0x17
  306. #define WM8750_ADCTL2 0x18
  307. #define WM8750_PWR1 0x19
  308. #define WM8750_PWR2 0x1a
  309. #define WM8750_ADCTL3 0x1b
  310. #define WM8750_ADCIN 0x1f
  311. #define WM8750_LADCIN 0x20
  312. #define WM8750_RADCIN 0x21
  313. #define WM8750_LOUTM1 0x22
  314. #define WM8750_LOUTM2 0x23
  315. #define WM8750_ROUTM1 0x24
  316. #define WM8750_ROUTM2 0x25
  317. #define WM8750_MOUTM1 0x26
  318. #define WM8750_MOUTM2 0x27
  319. #define WM8750_LOUT2V 0x28
  320. #define WM8750_ROUT2V 0x29
  321. #define WM8750_MOUTV 0x2a
  322. static int wm8750_tx(I2CSlave *i2c, uint8_t data)
  323. {
  324. WM8750State *s = WM8750(i2c);
  325. uint8_t cmd;
  326. uint16_t value;
  327. if (s->i2c_len >= 2) {
  328. #ifdef VERBOSE
  329. printf("%s: long message (%i bytes)\n", __func__, s->i2c_len);
  330. #endif
  331. return 1;
  332. }
  333. s->i2c_data[s->i2c_len ++] = data;
  334. if (s->i2c_len != 2)
  335. return 0;
  336. cmd = s->i2c_data[0] >> 1;
  337. value = ((s->i2c_data[0] << 8) | s->i2c_data[1]) & 0x1ff;
  338. switch (cmd) {
  339. case WM8750_LADCIN: /* ADC Signal Path Control (Left) */
  340. s->diff[0] = (((value >> 6) & 3) == 3); /* LINSEL */
  341. if (s->diff[0])
  342. s->in[0] = &s->adc_voice[0 + s->ds * 1];
  343. else
  344. s->in[0] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
  345. break;
  346. case WM8750_RADCIN: /* ADC Signal Path Control (Right) */
  347. s->diff[1] = (((value >> 6) & 3) == 3); /* RINSEL */
  348. if (s->diff[1])
  349. s->in[1] = &s->adc_voice[0 + s->ds * 1];
  350. else
  351. s->in[1] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
  352. break;
  353. case WM8750_ADCIN: /* ADC Input Mode */
  354. s->ds = (value >> 8) & 1; /* DS */
  355. if (s->diff[0])
  356. s->in[0] = &s->adc_voice[0 + s->ds * 1];
  357. if (s->diff[1])
  358. s->in[1] = &s->adc_voice[0 + s->ds * 1];
  359. s->monomix[0] = (value >> 6) & 3; /* MONOMIX */
  360. break;
  361. case WM8750_ADCTL1: /* Additional Control (1) */
  362. s->monomix[1] = (value >> 1) & 1; /* DMONOMIX */
  363. break;
  364. case WM8750_PWR1: /* Power Management (1) */
  365. s->enable = ((value >> 6) & 7) == 3; /* VMIDSEL, VREF */
  366. wm8750_set_format(s);
  367. break;
  368. case WM8750_LINVOL: /* Left Channel PGA */
  369. s->invol[0] = value & 0x3f; /* LINVOL */
  370. s->inmute[0] = (value >> 7) & 1; /* LINMUTE */
  371. wm8750_vol_update(s);
  372. break;
  373. case WM8750_RINVOL: /* Right Channel PGA */
  374. s->invol[1] = value & 0x3f; /* RINVOL */
  375. s->inmute[1] = (value >> 7) & 1; /* RINMUTE */
  376. wm8750_vol_update(s);
  377. break;
  378. case WM8750_ADCDAC: /* ADC and DAC Control */
  379. s->pol = (value >> 5) & 3; /* ADCPOL */
  380. s->mute = (value >> 3) & 1; /* DACMU */
  381. wm8750_vol_update(s);
  382. break;
  383. case WM8750_ADCTL3: /* Additional Control (3) */
  384. break;
  385. case WM8750_LADC: /* Left ADC Digital Volume */
  386. s->invol[2] = value & 0xff; /* LADCVOL */
  387. wm8750_vol_update(s);
  388. break;
  389. case WM8750_RADC: /* Right ADC Digital Volume */
  390. s->invol[3] = value & 0xff; /* RADCVOL */
  391. wm8750_vol_update(s);
  392. break;
  393. case WM8750_ALC1: /* ALC Control (1) */
  394. s->alc = (value >> 7) & 3; /* ALCSEL */
  395. break;
  396. case WM8750_NGATE: /* Noise Gate Control */
  397. case WM8750_3D: /* 3D enhance */
  398. break;
  399. case WM8750_LDAC: /* Left Channel Digital Volume */
  400. s->outvol[0] = value & 0xff; /* LDACVOL */
  401. wm8750_vol_update(s);
  402. break;
  403. case WM8750_RDAC: /* Right Channel Digital Volume */
  404. s->outvol[1] = value & 0xff; /* RDACVOL */
  405. wm8750_vol_update(s);
  406. break;
  407. case WM8750_BASS: /* Bass Control */
  408. break;
  409. case WM8750_LOUTM1: /* Left Mixer Control (1) */
  410. s->path[0] = (value >> 8) & 1; /* LD2LO */
  411. /* TODO: mute/unmute respective paths */
  412. wm8750_vol_update(s);
  413. break;
  414. case WM8750_LOUTM2: /* Left Mixer Control (2) */
  415. s->path[1] = (value >> 8) & 1; /* RD2LO */
  416. /* TODO: mute/unmute respective paths */
  417. wm8750_vol_update(s);
  418. break;
  419. case WM8750_ROUTM1: /* Right Mixer Control (1) */
  420. s->path[2] = (value >> 8) & 1; /* LD2RO */
  421. /* TODO: mute/unmute respective paths */
  422. wm8750_vol_update(s);
  423. break;
  424. case WM8750_ROUTM2: /* Right Mixer Control (2) */
  425. s->path[3] = (value >> 8) & 1; /* RD2RO */
  426. /* TODO: mute/unmute respective paths */
  427. wm8750_vol_update(s);
  428. break;
  429. case WM8750_MOUTM1: /* Mono Mixer Control (1) */
  430. s->mpath[0] = (value >> 8) & 1; /* LD2MO */
  431. /* TODO: mute/unmute respective paths */
  432. wm8750_vol_update(s);
  433. break;
  434. case WM8750_MOUTM2: /* Mono Mixer Control (2) */
  435. s->mpath[1] = (value >> 8) & 1; /* RD2MO */
  436. /* TODO: mute/unmute respective paths */
  437. wm8750_vol_update(s);
  438. break;
  439. case WM8750_LOUT1V: /* LOUT1 Volume */
  440. s->outvol[2] = value & 0x7f; /* LOUT1VOL */
  441. wm8750_vol_update(s);
  442. break;
  443. case WM8750_LOUT2V: /* LOUT2 Volume */
  444. s->outvol[4] = value & 0x7f; /* LOUT2VOL */
  445. wm8750_vol_update(s);
  446. break;
  447. case WM8750_ROUT1V: /* ROUT1 Volume */
  448. s->outvol[3] = value & 0x7f; /* ROUT1VOL */
  449. wm8750_vol_update(s);
  450. break;
  451. case WM8750_ROUT2V: /* ROUT2 Volume */
  452. s->outvol[5] = value & 0x7f; /* ROUT2VOL */
  453. wm8750_vol_update(s);
  454. break;
  455. case WM8750_MOUTV: /* MONOOUT Volume */
  456. s->outvol[6] = value & 0x7f; /* MONOOUTVOL */
  457. wm8750_vol_update(s);
  458. break;
  459. case WM8750_ADCTL2: /* Additional Control (2) */
  460. break;
  461. case WM8750_PWR2: /* Power Management (2) */
  462. s->power = value & 0x7e;
  463. /* TODO: mute/unmute respective paths */
  464. wm8750_vol_update(s);
  465. break;
  466. case WM8750_IFACE: /* Digital Audio Interface Format */
  467. s->format = value;
  468. s->master = (value >> 6) & 1; /* MS */
  469. wm8750_clk_update(s, s->master);
  470. break;
  471. case WM8750_SRATE: /* Clocking and Sample Rate Control */
  472. s->rate = &wm_rate_table[(value >> 1) & 0x1f];
  473. wm8750_clk_update(s, 0);
  474. break;
  475. case WM8750_RESET: /* Reset */
  476. wm8750_reset(I2C_SLAVE(s));
  477. break;
  478. #ifdef VERBOSE
  479. default:
  480. printf("%s: unknown register %02x\n", __func__, cmd);
  481. #endif
  482. }
  483. return 0;
  484. }
  485. static uint8_t wm8750_rx(I2CSlave *i2c)
  486. {
  487. return 0x00;
  488. }
  489. static int wm8750_pre_save(void *opaque)
  490. {
  491. WM8750State *s = opaque;
  492. s->rate_vmstate = s->rate - wm_rate_table;
  493. return 0;
  494. }
  495. static int wm8750_post_load(void *opaque, int version_id)
  496. {
  497. WM8750State *s = opaque;
  498. s->rate = &wm_rate_table[s->rate_vmstate & 0x1f];
  499. return 0;
  500. }
  501. static const VMStateDescription vmstate_wm8750 = {
  502. .name = CODEC,
  503. .version_id = 0,
  504. .minimum_version_id = 0,
  505. .pre_save = wm8750_pre_save,
  506. .post_load = wm8750_post_load,
  507. .fields = (const VMStateField[]) {
  508. VMSTATE_UINT8_ARRAY(i2c_data, WM8750State, 2),
  509. VMSTATE_INT32(i2c_len, WM8750State),
  510. VMSTATE_INT32(enable, WM8750State),
  511. VMSTATE_INT32(idx_in, WM8750State),
  512. VMSTATE_INT32(req_in, WM8750State),
  513. VMSTATE_INT32(idx_out, WM8750State),
  514. VMSTATE_INT32(req_out, WM8750State),
  515. VMSTATE_UINT8_ARRAY(outvol, WM8750State, 7),
  516. VMSTATE_UINT8_ARRAY(outmute, WM8750State, 2),
  517. VMSTATE_UINT8_ARRAY(invol, WM8750State, 4),
  518. VMSTATE_UINT8_ARRAY(inmute, WM8750State, 2),
  519. VMSTATE_UINT8_ARRAY(diff, WM8750State, 2),
  520. VMSTATE_UINT8(pol, WM8750State),
  521. VMSTATE_UINT8(ds, WM8750State),
  522. VMSTATE_UINT8_ARRAY(monomix, WM8750State, 2),
  523. VMSTATE_UINT8(alc, WM8750State),
  524. VMSTATE_UINT8(mute, WM8750State),
  525. VMSTATE_UINT8_ARRAY(path, WM8750State, 4),
  526. VMSTATE_UINT8_ARRAY(mpath, WM8750State, 2),
  527. VMSTATE_UINT8(format, WM8750State),
  528. VMSTATE_UINT8(power, WM8750State),
  529. VMSTATE_UINT8(rate_vmstate, WM8750State),
  530. VMSTATE_I2C_SLAVE(parent_obj, WM8750State),
  531. VMSTATE_END_OF_LIST()
  532. }
  533. };
  534. static void wm8750_realize(DeviceState *dev, Error **errp)
  535. {
  536. WM8750State *s = WM8750(dev);
  537. if (!AUD_register_card(CODEC, &s->card, errp)) {
  538. return;
  539. }
  540. wm8750_reset(I2C_SLAVE(s));
  541. }
  542. #if 0
  543. static void wm8750_fini(I2CSlave *i2c)
  544. {
  545. WM8750State *s = WM8750(i2c);
  546. wm8750_reset(I2C_SLAVE(s));
  547. AUD_remove_card(&s->card);
  548. g_free(s);
  549. }
  550. #endif
  551. void wm8750_data_req_set(DeviceState *dev, data_req_cb *data_req, void *opaque)
  552. {
  553. WM8750State *s = WM8750(dev);
  554. s->data_req = data_req;
  555. s->opaque = opaque;
  556. }
  557. void wm8750_dac_dat(void *opaque, uint32_t sample)
  558. {
  559. WM8750State *s = (WM8750State *) opaque;
  560. *(uint32_t *) &s->data_out[s->idx_out] = sample;
  561. s->req_out -= 4;
  562. s->idx_out += 4;
  563. if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0)
  564. wm8750_out_flush(s);
  565. }
  566. void *wm8750_dac_buffer(void *opaque, int samples)
  567. {
  568. WM8750State *s = (WM8750State *) opaque;
  569. /* XXX: Should check if there are <i>samples</i> free samples available */
  570. void *ret = s->data_out + s->idx_out;
  571. s->idx_out += samples << 2;
  572. s->req_out -= samples << 2;
  573. return ret;
  574. }
  575. void wm8750_dac_commit(void *opaque)
  576. {
  577. WM8750State *s = (WM8750State *) opaque;
  578. wm8750_out_flush(s);
  579. }
  580. uint32_t wm8750_adc_dat(void *opaque)
  581. {
  582. WM8750State *s = (WM8750State *) opaque;
  583. uint32_t *data;
  584. if (s->idx_in >= sizeof(s->data_in)) {
  585. wm8750_in_load(s);
  586. if (s->idx_in >= sizeof(s->data_in)) {
  587. return 0x80008000; /* silence in AUDIO_FORMAT_S16 sample format */
  588. }
  589. }
  590. data = (uint32_t *) &s->data_in[s->idx_in];
  591. s->req_in -= 4;
  592. s->idx_in += 4;
  593. return *data;
  594. }
  595. void wm8750_set_bclk_in(void *opaque, int new_hz)
  596. {
  597. WM8750State *s = (WM8750State *) opaque;
  598. s->ext_adc_hz = new_hz;
  599. s->ext_dac_hz = new_hz;
  600. wm8750_clk_update(s, 1);
  601. }
  602. static const Property wm8750_properties[] = {
  603. DEFINE_AUDIO_PROPERTIES(WM8750State, card),
  604. };
  605. static void wm8750_class_init(ObjectClass *klass, void *data)
  606. {
  607. DeviceClass *dc = DEVICE_CLASS(klass);
  608. I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
  609. dc->realize = wm8750_realize;
  610. sc->event = wm8750_event;
  611. sc->recv = wm8750_rx;
  612. sc->send = wm8750_tx;
  613. dc->vmsd = &vmstate_wm8750;
  614. device_class_set_props(dc, wm8750_properties);
  615. }
  616. static const TypeInfo wm8750_info = {
  617. .name = TYPE_WM8750,
  618. .parent = TYPE_I2C_SLAVE,
  619. .instance_size = sizeof(WM8750State),
  620. .class_init = wm8750_class_init,
  621. };
  622. static void wm8750_register_types(void)
  623. {
  624. type_register_static(&wm8750_info);
  625. }
  626. type_init(wm8750_register_types)