burgundy.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. /*
  2. * PMac Burgundy lowlevel functions
  3. *
  4. * Copyright (c) by Takashi Iwai <tiwai@suse.de>
  5. * code based on dmasound.c.
  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 as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. */
  21. #include <asm/io.h>
  22. #include <linux/init.h>
  23. #include <linux/slab.h>
  24. #include <linux/delay.h>
  25. #include <sound/core.h>
  26. #include "pmac.h"
  27. #include "burgundy.h"
  28. /* Waits for busy flag to clear */
  29. static inline void
  30. snd_pmac_burgundy_busy_wait(struct snd_pmac *chip)
  31. {
  32. int timeout = 50;
  33. while ((in_le32(&chip->awacs->codec_ctrl) & MASK_NEWECMD) && timeout--)
  34. udelay(1);
  35. if (timeout < 0)
  36. printk(KERN_DEBUG "burgundy_busy_wait: timeout\n");
  37. }
  38. static inline void
  39. snd_pmac_burgundy_extend_wait(struct snd_pmac *chip)
  40. {
  41. int timeout;
  42. timeout = 50;
  43. while (!(in_le32(&chip->awacs->codec_stat) & MASK_EXTEND) && timeout--)
  44. udelay(1);
  45. if (! timeout)
  46. printk(KERN_DEBUG "burgundy_extend_wait: timeout #1\n");
  47. timeout = 50;
  48. while ((in_le32(&chip->awacs->codec_stat) & MASK_EXTEND) && timeout--)
  49. udelay(1);
  50. if (! timeout)
  51. printk(KERN_DEBUG "burgundy_extend_wait: timeout #2\n");
  52. }
  53. static void
  54. snd_pmac_burgundy_wcw(struct snd_pmac *chip, unsigned addr, unsigned val)
  55. {
  56. out_le32(&chip->awacs->codec_ctrl, addr + 0x200c00 + (val & 0xff));
  57. snd_pmac_burgundy_busy_wait(chip);
  58. out_le32(&chip->awacs->codec_ctrl, addr + 0x200d00 +((val>>8) & 0xff));
  59. snd_pmac_burgundy_busy_wait(chip);
  60. out_le32(&chip->awacs->codec_ctrl, addr + 0x200e00 +((val>>16) & 0xff));
  61. snd_pmac_burgundy_busy_wait(chip);
  62. out_le32(&chip->awacs->codec_ctrl, addr + 0x200f00 +((val>>24) & 0xff));
  63. snd_pmac_burgundy_busy_wait(chip);
  64. }
  65. static unsigned
  66. snd_pmac_burgundy_rcw(struct snd_pmac *chip, unsigned addr)
  67. {
  68. unsigned val = 0;
  69. unsigned long flags;
  70. spin_lock_irqsave(&chip->reg_lock, flags);
  71. out_le32(&chip->awacs->codec_ctrl, addr + 0x100000);
  72. snd_pmac_burgundy_busy_wait(chip);
  73. snd_pmac_burgundy_extend_wait(chip);
  74. val += (in_le32(&chip->awacs->codec_stat) >> 4) & 0xff;
  75. out_le32(&chip->awacs->codec_ctrl, addr + 0x100100);
  76. snd_pmac_burgundy_busy_wait(chip);
  77. snd_pmac_burgundy_extend_wait(chip);
  78. val += ((in_le32(&chip->awacs->codec_stat)>>4) & 0xff) <<8;
  79. out_le32(&chip->awacs->codec_ctrl, addr + 0x100200);
  80. snd_pmac_burgundy_busy_wait(chip);
  81. snd_pmac_burgundy_extend_wait(chip);
  82. val += ((in_le32(&chip->awacs->codec_stat)>>4) & 0xff) <<16;
  83. out_le32(&chip->awacs->codec_ctrl, addr + 0x100300);
  84. snd_pmac_burgundy_busy_wait(chip);
  85. snd_pmac_burgundy_extend_wait(chip);
  86. val += ((in_le32(&chip->awacs->codec_stat)>>4) & 0xff) <<24;
  87. spin_unlock_irqrestore(&chip->reg_lock, flags);
  88. return val;
  89. }
  90. static void
  91. snd_pmac_burgundy_wcb(struct snd_pmac *chip, unsigned int addr,
  92. unsigned int val)
  93. {
  94. out_le32(&chip->awacs->codec_ctrl, addr + 0x300000 + (val & 0xff));
  95. snd_pmac_burgundy_busy_wait(chip);
  96. }
  97. static unsigned
  98. snd_pmac_burgundy_rcb(struct snd_pmac *chip, unsigned int addr)
  99. {
  100. unsigned val = 0;
  101. unsigned long flags;
  102. spin_lock_irqsave(&chip->reg_lock, flags);
  103. out_le32(&chip->awacs->codec_ctrl, addr + 0x100000);
  104. snd_pmac_burgundy_busy_wait(chip);
  105. snd_pmac_burgundy_extend_wait(chip);
  106. val += (in_le32(&chip->awacs->codec_stat) >> 4) & 0xff;
  107. spin_unlock_irqrestore(&chip->reg_lock, flags);
  108. return val;
  109. }
  110. #define BASE2ADDR(base) ((base) << 12)
  111. #define ADDR2BASE(addr) ((addr) >> 12)
  112. /*
  113. * Burgundy volume: 0 - 100, stereo, word reg
  114. */
  115. static void
  116. snd_pmac_burgundy_write_volume(struct snd_pmac *chip, unsigned int address,
  117. long *volume, int shift)
  118. {
  119. int hardvolume, lvolume, rvolume;
  120. if (volume[0] < 0 || volume[0] > 100 ||
  121. volume[1] < 0 || volume[1] > 100)
  122. return; /* -EINVAL */
  123. lvolume = volume[0] ? volume[0] + BURGUNDY_VOLUME_OFFSET : 0;
  124. rvolume = volume[1] ? volume[1] + BURGUNDY_VOLUME_OFFSET : 0;
  125. hardvolume = lvolume + (rvolume << shift);
  126. if (shift == 8)
  127. hardvolume |= hardvolume << 16;
  128. snd_pmac_burgundy_wcw(chip, address, hardvolume);
  129. }
  130. static void
  131. snd_pmac_burgundy_read_volume(struct snd_pmac *chip, unsigned int address,
  132. long *volume, int shift)
  133. {
  134. int wvolume;
  135. wvolume = snd_pmac_burgundy_rcw(chip, address);
  136. volume[0] = wvolume & 0xff;
  137. if (volume[0] >= BURGUNDY_VOLUME_OFFSET)
  138. volume[0] -= BURGUNDY_VOLUME_OFFSET;
  139. else
  140. volume[0] = 0;
  141. volume[1] = (wvolume >> shift) & 0xff;
  142. if (volume[1] >= BURGUNDY_VOLUME_OFFSET)
  143. volume[1] -= BURGUNDY_VOLUME_OFFSET;
  144. else
  145. volume[1] = 0;
  146. }
  147. static int snd_pmac_burgundy_info_volume(struct snd_kcontrol *kcontrol,
  148. struct snd_ctl_elem_info *uinfo)
  149. {
  150. uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  151. uinfo->count = 2;
  152. uinfo->value.integer.min = 0;
  153. uinfo->value.integer.max = 100;
  154. return 0;
  155. }
  156. static int snd_pmac_burgundy_get_volume(struct snd_kcontrol *kcontrol,
  157. struct snd_ctl_elem_value *ucontrol)
  158. {
  159. struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
  160. unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
  161. int shift = (kcontrol->private_value >> 8) & 0xff;
  162. snd_pmac_burgundy_read_volume(chip, addr,
  163. ucontrol->value.integer.value, shift);
  164. return 0;
  165. }
  166. static int snd_pmac_burgundy_put_volume(struct snd_kcontrol *kcontrol,
  167. struct snd_ctl_elem_value *ucontrol)
  168. {
  169. struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
  170. unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
  171. int shift = (kcontrol->private_value >> 8) & 0xff;
  172. long nvoices[2];
  173. snd_pmac_burgundy_write_volume(chip, addr,
  174. ucontrol->value.integer.value, shift);
  175. snd_pmac_burgundy_read_volume(chip, addr, nvoices, shift);
  176. return (nvoices[0] != ucontrol->value.integer.value[0] ||
  177. nvoices[1] != ucontrol->value.integer.value[1]);
  178. }
  179. #define BURGUNDY_VOLUME_W(xname, xindex, addr, shift) \
  180. { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
  181. .info = snd_pmac_burgundy_info_volume,\
  182. .get = snd_pmac_burgundy_get_volume,\
  183. .put = snd_pmac_burgundy_put_volume,\
  184. .private_value = ((ADDR2BASE(addr) & 0xff) | ((shift) << 8)) }
  185. /*
  186. * Burgundy volume: 0 - 100, stereo, 2-byte reg
  187. */
  188. static void
  189. snd_pmac_burgundy_write_volume_2b(struct snd_pmac *chip, unsigned int address,
  190. long *volume, int off)
  191. {
  192. int lvolume, rvolume;
  193. off |= off << 2;
  194. lvolume = volume[0] ? volume[0] + BURGUNDY_VOLUME_OFFSET : 0;
  195. rvolume = volume[1] ? volume[1] + BURGUNDY_VOLUME_OFFSET : 0;
  196. snd_pmac_burgundy_wcb(chip, address + off, lvolume);
  197. snd_pmac_burgundy_wcb(chip, address + off + 0x500, rvolume);
  198. }
  199. static void
  200. snd_pmac_burgundy_read_volume_2b(struct snd_pmac *chip, unsigned int address,
  201. long *volume, int off)
  202. {
  203. volume[0] = snd_pmac_burgundy_rcb(chip, address + off);
  204. if (volume[0] >= BURGUNDY_VOLUME_OFFSET)
  205. volume[0] -= BURGUNDY_VOLUME_OFFSET;
  206. else
  207. volume[0] = 0;
  208. volume[1] = snd_pmac_burgundy_rcb(chip, address + off + 0x100);
  209. if (volume[1] >= BURGUNDY_VOLUME_OFFSET)
  210. volume[1] -= BURGUNDY_VOLUME_OFFSET;
  211. else
  212. volume[1] = 0;
  213. }
  214. static int snd_pmac_burgundy_info_volume_2b(struct snd_kcontrol *kcontrol,
  215. struct snd_ctl_elem_info *uinfo)
  216. {
  217. uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  218. uinfo->count = 2;
  219. uinfo->value.integer.min = 0;
  220. uinfo->value.integer.max = 100;
  221. return 0;
  222. }
  223. static int snd_pmac_burgundy_get_volume_2b(struct snd_kcontrol *kcontrol,
  224. struct snd_ctl_elem_value *ucontrol)
  225. {
  226. struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
  227. unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
  228. int off = kcontrol->private_value & 0x300;
  229. snd_pmac_burgundy_read_volume_2b(chip, addr,
  230. ucontrol->value.integer.value, off);
  231. return 0;
  232. }
  233. static int snd_pmac_burgundy_put_volume_2b(struct snd_kcontrol *kcontrol,
  234. struct snd_ctl_elem_value *ucontrol)
  235. {
  236. struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
  237. unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
  238. int off = kcontrol->private_value & 0x300;
  239. long nvoices[2];
  240. snd_pmac_burgundy_write_volume_2b(chip, addr,
  241. ucontrol->value.integer.value, off);
  242. snd_pmac_burgundy_read_volume_2b(chip, addr, nvoices, off);
  243. return (nvoices[0] != ucontrol->value.integer.value[0] ||
  244. nvoices[1] != ucontrol->value.integer.value[1]);
  245. }
  246. #define BURGUNDY_VOLUME_2B(xname, xindex, addr, off) \
  247. { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
  248. .info = snd_pmac_burgundy_info_volume_2b,\
  249. .get = snd_pmac_burgundy_get_volume_2b,\
  250. .put = snd_pmac_burgundy_put_volume_2b,\
  251. .private_value = ((ADDR2BASE(addr) & 0xff) | ((off) << 8)) }
  252. /*
  253. * Burgundy gain/attenuation: 0 - 15, mono/stereo, byte reg
  254. */
  255. static int snd_pmac_burgundy_info_gain(struct snd_kcontrol *kcontrol,
  256. struct snd_ctl_elem_info *uinfo)
  257. {
  258. int stereo = (kcontrol->private_value >> 24) & 1;
  259. uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  260. uinfo->count = stereo + 1;
  261. uinfo->value.integer.min = 0;
  262. uinfo->value.integer.max = 15;
  263. return 0;
  264. }
  265. static int snd_pmac_burgundy_get_gain(struct snd_kcontrol *kcontrol,
  266. struct snd_ctl_elem_value *ucontrol)
  267. {
  268. struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
  269. unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
  270. int stereo = (kcontrol->private_value >> 24) & 1;
  271. int atten = (kcontrol->private_value >> 25) & 1;
  272. int oval;
  273. oval = snd_pmac_burgundy_rcb(chip, addr);
  274. if (atten)
  275. oval = ~oval & 0xff;
  276. ucontrol->value.integer.value[0] = oval & 0xf;
  277. if (stereo)
  278. ucontrol->value.integer.value[1] = (oval >> 4) & 0xf;
  279. return 0;
  280. }
  281. static int snd_pmac_burgundy_put_gain(struct snd_kcontrol *kcontrol,
  282. struct snd_ctl_elem_value *ucontrol)
  283. {
  284. struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
  285. unsigned int addr = BASE2ADDR(kcontrol->private_value & 0xff);
  286. int stereo = (kcontrol->private_value >> 24) & 1;
  287. int atten = (kcontrol->private_value >> 25) & 1;
  288. int oval, val;
  289. oval = snd_pmac_burgundy_rcb(chip, addr);
  290. if (atten)
  291. oval = ~oval & 0xff;
  292. val = ucontrol->value.integer.value[0];
  293. if (stereo)
  294. val |= ucontrol->value.integer.value[1] << 4;
  295. else
  296. val |= ucontrol->value.integer.value[0] << 4;
  297. if (atten)
  298. val = ~val & 0xff;
  299. snd_pmac_burgundy_wcb(chip, addr, val);
  300. return val != oval;
  301. }
  302. #define BURGUNDY_VOLUME_B(xname, xindex, addr, stereo, atten) \
  303. { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
  304. .info = snd_pmac_burgundy_info_gain,\
  305. .get = snd_pmac_burgundy_get_gain,\
  306. .put = snd_pmac_burgundy_put_gain,\
  307. .private_value = (ADDR2BASE(addr) | ((stereo) << 24) | ((atten) << 25)) }
  308. /*
  309. * Burgundy switch: 0/1, mono/stereo, word reg
  310. */
  311. static int snd_pmac_burgundy_info_switch_w(struct snd_kcontrol *kcontrol,
  312. struct snd_ctl_elem_info *uinfo)
  313. {
  314. int stereo = (kcontrol->private_value >> 24) & 1;
  315. uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
  316. uinfo->count = stereo + 1;
  317. uinfo->value.integer.min = 0;
  318. uinfo->value.integer.max = 1;
  319. return 0;
  320. }
  321. static int snd_pmac_burgundy_get_switch_w(struct snd_kcontrol *kcontrol,
  322. struct snd_ctl_elem_value *ucontrol)
  323. {
  324. struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
  325. unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff);
  326. int lmask = 1 << (kcontrol->private_value & 0xff);
  327. int rmask = 1 << ((kcontrol->private_value >> 8) & 0xff);
  328. int stereo = (kcontrol->private_value >> 24) & 1;
  329. int val = snd_pmac_burgundy_rcw(chip, addr);
  330. ucontrol->value.integer.value[0] = (val & lmask) ? 1 : 0;
  331. if (stereo)
  332. ucontrol->value.integer.value[1] = (val & rmask) ? 1 : 0;
  333. return 0;
  334. }
  335. static int snd_pmac_burgundy_put_switch_w(struct snd_kcontrol *kcontrol,
  336. struct snd_ctl_elem_value *ucontrol)
  337. {
  338. struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
  339. unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff);
  340. int lmask = 1 << (kcontrol->private_value & 0xff);
  341. int rmask = 1 << ((kcontrol->private_value >> 8) & 0xff);
  342. int stereo = (kcontrol->private_value >> 24) & 1;
  343. int val, oval;
  344. oval = snd_pmac_burgundy_rcw(chip, addr);
  345. val = oval & ~(lmask | (stereo ? rmask : 0));
  346. if (ucontrol->value.integer.value[0])
  347. val |= lmask;
  348. if (stereo && ucontrol->value.integer.value[1])
  349. val |= rmask;
  350. snd_pmac_burgundy_wcw(chip, addr, val);
  351. return val != oval;
  352. }
  353. #define BURGUNDY_SWITCH_W(xname, xindex, addr, lbit, rbit, stereo) \
  354. { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
  355. .info = snd_pmac_burgundy_info_switch_w,\
  356. .get = snd_pmac_burgundy_get_switch_w,\
  357. .put = snd_pmac_burgundy_put_switch_w,\
  358. .private_value = ((lbit) | ((rbit) << 8)\
  359. | (ADDR2BASE(addr) << 16) | ((stereo) << 24)) }
  360. /*
  361. * Burgundy switch: 0/1, mono/stereo, byte reg, bit mask
  362. */
  363. static int snd_pmac_burgundy_info_switch_b(struct snd_kcontrol *kcontrol,
  364. struct snd_ctl_elem_info *uinfo)
  365. {
  366. int stereo = (kcontrol->private_value >> 24) & 1;
  367. uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
  368. uinfo->count = stereo + 1;
  369. uinfo->value.integer.min = 0;
  370. uinfo->value.integer.max = 1;
  371. return 0;
  372. }
  373. static int snd_pmac_burgundy_get_switch_b(struct snd_kcontrol *kcontrol,
  374. struct snd_ctl_elem_value *ucontrol)
  375. {
  376. struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
  377. unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff);
  378. int lmask = kcontrol->private_value & 0xff;
  379. int rmask = (kcontrol->private_value >> 8) & 0xff;
  380. int stereo = (kcontrol->private_value >> 24) & 1;
  381. int val = snd_pmac_burgundy_rcb(chip, addr);
  382. ucontrol->value.integer.value[0] = (val & lmask) ? 1 : 0;
  383. if (stereo)
  384. ucontrol->value.integer.value[1] = (val & rmask) ? 1 : 0;
  385. return 0;
  386. }
  387. static int snd_pmac_burgundy_put_switch_b(struct snd_kcontrol *kcontrol,
  388. struct snd_ctl_elem_value *ucontrol)
  389. {
  390. struct snd_pmac *chip = snd_kcontrol_chip(kcontrol);
  391. unsigned int addr = BASE2ADDR((kcontrol->private_value >> 16) & 0xff);
  392. int lmask = kcontrol->private_value & 0xff;
  393. int rmask = (kcontrol->private_value >> 8) & 0xff;
  394. int stereo = (kcontrol->private_value >> 24) & 1;
  395. int val, oval;
  396. oval = snd_pmac_burgundy_rcb(chip, addr);
  397. val = oval & ~(lmask | rmask);
  398. if (ucontrol->value.integer.value[0])
  399. val |= lmask;
  400. if (stereo && ucontrol->value.integer.value[1])
  401. val |= rmask;
  402. snd_pmac_burgundy_wcb(chip, addr, val);
  403. return val != oval;
  404. }
  405. #define BURGUNDY_SWITCH_B(xname, xindex, addr, lmask, rmask, stereo) \
  406. { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex,\
  407. .info = snd_pmac_burgundy_info_switch_b,\
  408. .get = snd_pmac_burgundy_get_switch_b,\
  409. .put = snd_pmac_burgundy_put_switch_b,\
  410. .private_value = ((lmask) | ((rmask) << 8)\
  411. | (ADDR2BASE(addr) << 16) | ((stereo) << 24)) }
  412. /*
  413. * Burgundy mixers
  414. */
  415. static struct snd_kcontrol_new snd_pmac_burgundy_mixers[] __initdata = {
  416. BURGUNDY_VOLUME_W("Master Playback Volume", 0,
  417. MASK_ADDR_BURGUNDY_MASTER_VOLUME, 8),
  418. BURGUNDY_VOLUME_W("CD Capture Volume", 0,
  419. MASK_ADDR_BURGUNDY_VOLCD, 16),
  420. BURGUNDY_VOLUME_2B("Input Capture Volume", 0,
  421. MASK_ADDR_BURGUNDY_VOLMIX01, 2),
  422. BURGUNDY_VOLUME_2B("Mixer Playback Volume", 0,
  423. MASK_ADDR_BURGUNDY_VOLMIX23, 0),
  424. BURGUNDY_VOLUME_B("CD Gain Capture Volume", 0,
  425. MASK_ADDR_BURGUNDY_GAINCD, 1, 0),
  426. BURGUNDY_SWITCH_W("Master Capture Switch", 0,
  427. MASK_ADDR_BURGUNDY_OUTPUTENABLES, 24, 0, 0),
  428. BURGUNDY_SWITCH_W("CD Capture Switch", 0,
  429. MASK_ADDR_BURGUNDY_CAPTURESELECTS, 0, 16, 1),
  430. BURGUNDY_SWITCH_W("CD Playback Switch", 0,
  431. MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 0, 16, 1),
  432. /* BURGUNDY_SWITCH_W("Loop Capture Switch", 0,
  433. * MASK_ADDR_BURGUNDY_CAPTURESELECTS, 8, 24, 1),
  434. * BURGUNDY_SWITCH_B("Mixer out Capture Switch", 0,
  435. * MASK_ADDR_BURGUNDY_HOSTIFAD, 0x02, 0, 0),
  436. * BURGUNDY_SWITCH_B("Mixer Capture Switch", 0,
  437. * MASK_ADDR_BURGUNDY_HOSTIFAD, 0x01, 0, 0),
  438. * BURGUNDY_SWITCH_B("PCM out Capture Switch", 0,
  439. * MASK_ADDR_BURGUNDY_HOSTIFEH, 0x02, 0, 0),
  440. */ BURGUNDY_SWITCH_B("PCM Capture Switch", 0,
  441. MASK_ADDR_BURGUNDY_HOSTIFEH, 0x01, 0, 0)
  442. };
  443. static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] __initdata = {
  444. BURGUNDY_VOLUME_W("Line in Capture Volume", 0,
  445. MASK_ADDR_BURGUNDY_VOLLINE, 16),
  446. BURGUNDY_VOLUME_W("Mic Capture Volume", 0,
  447. MASK_ADDR_BURGUNDY_VOLMIC, 16),
  448. BURGUNDY_VOLUME_B("Line in Gain Capture Volume", 0,
  449. MASK_ADDR_BURGUNDY_GAINLINE, 1, 0),
  450. BURGUNDY_VOLUME_B("Mic Gain Capture Volume", 0,
  451. MASK_ADDR_BURGUNDY_GAINMIC, 1, 0),
  452. BURGUNDY_VOLUME_B("PC Speaker Playback Volume", 0,
  453. MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1, 1),
  454. BURGUNDY_VOLUME_B("Line out Playback Volume", 0,
  455. MASK_ADDR_BURGUNDY_ATTENLINEOUT, 1, 1),
  456. BURGUNDY_VOLUME_B("Headphone Playback Volume", 0,
  457. MASK_ADDR_BURGUNDY_ATTENHP, 1, 1),
  458. BURGUNDY_SWITCH_W("Line in Capture Switch", 0,
  459. MASK_ADDR_BURGUNDY_CAPTURESELECTS, 1, 17, 1),
  460. BURGUNDY_SWITCH_W("Mic Capture Switch", 0,
  461. MASK_ADDR_BURGUNDY_CAPTURESELECTS, 2, 18, 1),
  462. BURGUNDY_SWITCH_W("Line in Playback Switch", 0,
  463. MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 1, 17, 1),
  464. BURGUNDY_SWITCH_W("Mic Playback Switch", 0,
  465. MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 2, 18, 1),
  466. BURGUNDY_SWITCH_B("Mic Boost Capture Switch", 0,
  467. MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1)
  468. };
  469. static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] __initdata = {
  470. BURGUNDY_VOLUME_W("Line in Capture Volume", 0,
  471. MASK_ADDR_BURGUNDY_VOLMIC, 16),
  472. BURGUNDY_VOLUME_B("Line in Gain Capture Volume", 0,
  473. MASK_ADDR_BURGUNDY_GAINMIC, 1, 0),
  474. BURGUNDY_VOLUME_B("PC Speaker Playback Volume", 0,
  475. MASK_ADDR_BURGUNDY_ATTENMONO, 0, 1),
  476. BURGUNDY_VOLUME_B("Line out Playback Volume", 0,
  477. MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1, 1),
  478. BURGUNDY_SWITCH_W("Line in Capture Switch", 0,
  479. MASK_ADDR_BURGUNDY_CAPTURESELECTS, 2, 18, 1),
  480. BURGUNDY_SWITCH_W("Line in Playback Switch", 0,
  481. MASK_ADDR_BURGUNDY_OUTPUTSELECTS, 2, 18, 1),
  482. /* BURGUNDY_SWITCH_B("Line in Boost Capture Switch", 0,
  483. * MASK_ADDR_BURGUNDY_INPBOOST, 0x40, 0x80, 1) */
  484. };
  485. static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_imac __initdata =
  486. BURGUNDY_SWITCH_B("Master Playback Switch", 0,
  487. MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
  488. BURGUNDY_OUTPUT_LEFT | BURGUNDY_LINEOUT_LEFT | BURGUNDY_HP_LEFT,
  489. BURGUNDY_OUTPUT_RIGHT | BURGUNDY_LINEOUT_RIGHT | BURGUNDY_HP_RIGHT, 1);
  490. static struct snd_kcontrol_new snd_pmac_burgundy_master_sw_pmac __initdata =
  491. BURGUNDY_SWITCH_B("Master Playback Switch", 0,
  492. MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
  493. BURGUNDY_OUTPUT_INTERN
  494. | BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
  495. static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_imac __initdata =
  496. BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0,
  497. MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
  498. BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
  499. static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_pmac __initdata =
  500. BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0,
  501. MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
  502. BURGUNDY_OUTPUT_INTERN, 0, 0);
  503. static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_imac __initdata =
  504. BURGUNDY_SWITCH_B("Line out Playback Switch", 0,
  505. MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
  506. BURGUNDY_LINEOUT_LEFT, BURGUNDY_LINEOUT_RIGHT, 1);
  507. static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_pmac __initdata =
  508. BURGUNDY_SWITCH_B("Line out Playback Switch", 0,
  509. MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
  510. BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1);
  511. static struct snd_kcontrol_new snd_pmac_burgundy_hp_sw_imac __initdata =
  512. BURGUNDY_SWITCH_B("Headphone Playback Switch", 0,
  513. MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
  514. BURGUNDY_HP_LEFT, BURGUNDY_HP_RIGHT, 1);
  515. #ifdef PMAC_SUPPORT_AUTOMUTE
  516. /*
  517. * auto-mute stuffs
  518. */
  519. static int snd_pmac_burgundy_detect_headphone(struct snd_pmac *chip)
  520. {
  521. return (in_le32(&chip->awacs->codec_stat) & chip->hp_stat_mask) ? 1 : 0;
  522. }
  523. static void snd_pmac_burgundy_update_automute(struct snd_pmac *chip, int do_notify)
  524. {
  525. if (chip->auto_mute) {
  526. int imac = machine_is_compatible("iMac");
  527. int reg, oreg;
  528. reg = oreg = snd_pmac_burgundy_rcb(chip,
  529. MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES);
  530. reg &= imac ? ~(BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT
  531. | BURGUNDY_HP_LEFT | BURGUNDY_HP_RIGHT)
  532. : ~(BURGUNDY_OUTPUT_LEFT | BURGUNDY_OUTPUT_RIGHT
  533. | BURGUNDY_OUTPUT_INTERN);
  534. if (snd_pmac_burgundy_detect_headphone(chip))
  535. reg |= imac ? (BURGUNDY_HP_LEFT | BURGUNDY_HP_RIGHT)
  536. : (BURGUNDY_OUTPUT_LEFT
  537. | BURGUNDY_OUTPUT_RIGHT);
  538. else
  539. reg |= imac ? (BURGUNDY_OUTPUT_LEFT
  540. | BURGUNDY_OUTPUT_RIGHT)
  541. : (BURGUNDY_OUTPUT_INTERN);
  542. if (do_notify && reg == oreg)
  543. return;
  544. snd_pmac_burgundy_wcb(chip,
  545. MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, reg);
  546. if (do_notify) {
  547. snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
  548. &chip->master_sw_ctl->id);
  549. snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
  550. &chip->speaker_sw_ctl->id);
  551. snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
  552. &chip->hp_detect_ctl->id);
  553. }
  554. }
  555. }
  556. #endif /* PMAC_SUPPORT_AUTOMUTE */
  557. /*
  558. * initialize burgundy
  559. */
  560. int __init snd_pmac_burgundy_init(struct snd_pmac *chip)
  561. {
  562. int imac = machine_is_compatible("iMac");
  563. int i, err;
  564. /* Checks to see the chip is alive and kicking */
  565. if ((in_le32(&chip->awacs->codec_ctrl) & MASK_ERRCODE) == 0xf0000) {
  566. printk(KERN_WARNING "pmac burgundy: disabled by MacOS :-(\n");
  567. return 1;
  568. }
  569. snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_OUTPUTENABLES,
  570. DEF_BURGUNDY_OUTPUTENABLES);
  571. snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES,
  572. DEF_BURGUNDY_MORE_OUTPUTENABLES);
  573. snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_OUTPUTSELECTS,
  574. DEF_BURGUNDY_OUTPUTSELECTS);
  575. snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_INPSEL21,
  576. DEF_BURGUNDY_INPSEL21);
  577. snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_INPSEL3,
  578. imac ? DEF_BURGUNDY_INPSEL3_IMAC
  579. : DEF_BURGUNDY_INPSEL3_PMAC);
  580. snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINCD,
  581. DEF_BURGUNDY_GAINCD);
  582. snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINLINE,
  583. DEF_BURGUNDY_GAINLINE);
  584. snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINMIC,
  585. DEF_BURGUNDY_GAINMIC);
  586. snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_GAINMODEM,
  587. DEF_BURGUNDY_GAINMODEM);
  588. snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_ATTENSPEAKER,
  589. DEF_BURGUNDY_ATTENSPEAKER);
  590. snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_ATTENLINEOUT,
  591. DEF_BURGUNDY_ATTENLINEOUT);
  592. snd_pmac_burgundy_wcb(chip, MASK_ADDR_BURGUNDY_ATTENHP,
  593. DEF_BURGUNDY_ATTENHP);
  594. snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_MASTER_VOLUME,
  595. DEF_BURGUNDY_MASTER_VOLUME);
  596. snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_VOLCD,
  597. DEF_BURGUNDY_VOLCD);
  598. snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_VOLLINE,
  599. DEF_BURGUNDY_VOLLINE);
  600. snd_pmac_burgundy_wcw(chip, MASK_ADDR_BURGUNDY_VOLMIC,
  601. DEF_BURGUNDY_VOLMIC);
  602. if (chip->hp_stat_mask == 0) {
  603. /* set headphone-jack detection bit */
  604. if (imac)
  605. chip->hp_stat_mask = BURGUNDY_HPDETECT_IMAC_UPPER
  606. | BURGUNDY_HPDETECT_IMAC_LOWER
  607. | BURGUNDY_HPDETECT_IMAC_SIDE;
  608. else
  609. chip->hp_stat_mask = BURGUNDY_HPDETECT_PMAC_BACK;
  610. }
  611. /*
  612. * build burgundy mixers
  613. */
  614. strcpy(chip->card->mixername, "PowerMac Burgundy");
  615. for (i = 0; i < ARRAY_SIZE(snd_pmac_burgundy_mixers); i++) {
  616. err = snd_ctl_add(chip->card,
  617. snd_ctl_new1(&snd_pmac_burgundy_mixers[i], chip));
  618. if (err < 0)
  619. return err;
  620. }
  621. for (i = 0; i < (imac ? ARRAY_SIZE(snd_pmac_burgundy_mixers_imac)
  622. : ARRAY_SIZE(snd_pmac_burgundy_mixers_pmac)); i++) {
  623. err = snd_ctl_add(chip->card,
  624. snd_ctl_new1(imac ? &snd_pmac_burgundy_mixers_imac[i]
  625. : &snd_pmac_burgundy_mixers_pmac[i], chip));
  626. if (err < 0)
  627. return err;
  628. }
  629. chip->master_sw_ctl = snd_ctl_new1(imac
  630. ? &snd_pmac_burgundy_master_sw_imac
  631. : &snd_pmac_burgundy_master_sw_pmac, chip);
  632. err = snd_ctl_add(chip->card, chip->master_sw_ctl);
  633. if (err < 0)
  634. return err;
  635. chip->master_sw_ctl = snd_ctl_new1(imac
  636. ? &snd_pmac_burgundy_line_sw_imac
  637. : &snd_pmac_burgundy_line_sw_pmac, chip);
  638. err = snd_ctl_add(chip->card, chip->master_sw_ctl);
  639. if (err < 0)
  640. return err;
  641. if (imac) {
  642. chip->master_sw_ctl = snd_ctl_new1(
  643. &snd_pmac_burgundy_hp_sw_imac, chip);
  644. err = snd_ctl_add(chip->card, chip->master_sw_ctl);
  645. if (err < 0)
  646. return err;
  647. }
  648. chip->speaker_sw_ctl = snd_ctl_new1(imac
  649. ? &snd_pmac_burgundy_speaker_sw_imac
  650. : &snd_pmac_burgundy_speaker_sw_pmac, chip);
  651. err = snd_ctl_add(chip->card, chip->speaker_sw_ctl);
  652. if (err < 0)
  653. return err;
  654. #ifdef PMAC_SUPPORT_AUTOMUTE
  655. err = snd_pmac_add_automute(chip);
  656. if (err < 0)
  657. return err;
  658. chip->detect_headphone = snd_pmac_burgundy_detect_headphone;
  659. chip->update_automute = snd_pmac_burgundy_update_automute;
  660. snd_pmac_burgundy_update_automute(chip, 0); /* update the status only */
  661. #endif
  662. return 0;
  663. }