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