layout.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167
  1. /*
  2. * Apple Onboard Audio driver -- layout/machine id fabric
  3. *
  4. * Copyright 2006-2008 Johannes Berg <johannes@sipsolutions.net>
  5. *
  6. * GPL v2, can be found in COPYING.
  7. *
  8. *
  9. * This fabric module looks for sound codecs based on the
  10. * layout-id or device-id property in the device tree.
  11. */
  12. #include <asm/prom.h>
  13. #include <linux/list.h>
  14. #include <linux/module.h>
  15. #include "../aoa.h"
  16. #include "../soundbus/soundbus.h"
  17. MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
  18. MODULE_LICENSE("GPL");
  19. MODULE_DESCRIPTION("Layout-ID fabric for snd-aoa");
  20. #define MAX_CODECS_PER_BUS 2
  21. /* These are the connections the layout fabric
  22. * knows about. It doesn't really care about the
  23. * input ones, but I thought I'd separate them
  24. * to give them proper names. The thing is that
  25. * Apple usually will distinguish the active output
  26. * by GPIOs, while the active input is set directly
  27. * on the codec. Hence we here tell the codec what
  28. * we think is connected. This information is hard-
  29. * coded below ... */
  30. #define CC_SPEAKERS (1<<0)
  31. #define CC_HEADPHONE (1<<1)
  32. #define CC_LINEOUT (1<<2)
  33. #define CC_DIGITALOUT (1<<3)
  34. #define CC_LINEIN (1<<4)
  35. #define CC_MICROPHONE (1<<5)
  36. #define CC_DIGITALIN (1<<6)
  37. /* pretty bogus but users complain...
  38. * This is a flag saying that the LINEOUT
  39. * should be renamed to HEADPHONE.
  40. * be careful with input detection! */
  41. #define CC_LINEOUT_LABELLED_HEADPHONE (1<<7)
  42. struct codec_connection {
  43. /* CC_ flags from above */
  44. int connected;
  45. /* codec dependent bit to be set in the aoa_codec.connected field.
  46. * This intentionally doesn't have any generic flags because the
  47. * fabric has to know the codec anyway and all codecs might have
  48. * different connectors */
  49. int codec_bit;
  50. };
  51. struct codec_connect_info {
  52. char *name;
  53. struct codec_connection *connections;
  54. };
  55. #define LAYOUT_FLAG_COMBO_LINEOUT_SPDIF (1<<0)
  56. struct layout {
  57. unsigned int layout_id, device_id;
  58. struct codec_connect_info codecs[MAX_CODECS_PER_BUS];
  59. int flags;
  60. /* if busname is not assigned, we use 'Master' below,
  61. * so that our layout table doesn't need to be filled
  62. * too much.
  63. * We only assign these two if we expect to find more
  64. * than one soundbus, i.e. on those machines with
  65. * multiple layout-ids */
  66. char *busname;
  67. int pcmid;
  68. };
  69. MODULE_ALIAS("sound-layout-36");
  70. MODULE_ALIAS("sound-layout-41");
  71. MODULE_ALIAS("sound-layout-45");
  72. MODULE_ALIAS("sound-layout-47");
  73. MODULE_ALIAS("sound-layout-48");
  74. MODULE_ALIAS("sound-layout-49");
  75. MODULE_ALIAS("sound-layout-50");
  76. MODULE_ALIAS("sound-layout-51");
  77. MODULE_ALIAS("sound-layout-56");
  78. MODULE_ALIAS("sound-layout-57");
  79. MODULE_ALIAS("sound-layout-58");
  80. MODULE_ALIAS("sound-layout-60");
  81. MODULE_ALIAS("sound-layout-61");
  82. MODULE_ALIAS("sound-layout-62");
  83. MODULE_ALIAS("sound-layout-64");
  84. MODULE_ALIAS("sound-layout-65");
  85. MODULE_ALIAS("sound-layout-66");
  86. MODULE_ALIAS("sound-layout-67");
  87. MODULE_ALIAS("sound-layout-68");
  88. MODULE_ALIAS("sound-layout-69");
  89. MODULE_ALIAS("sound-layout-70");
  90. MODULE_ALIAS("sound-layout-72");
  91. MODULE_ALIAS("sound-layout-76");
  92. MODULE_ALIAS("sound-layout-80");
  93. MODULE_ALIAS("sound-layout-82");
  94. MODULE_ALIAS("sound-layout-84");
  95. MODULE_ALIAS("sound-layout-86");
  96. MODULE_ALIAS("sound-layout-90");
  97. MODULE_ALIAS("sound-layout-92");
  98. MODULE_ALIAS("sound-layout-94");
  99. MODULE_ALIAS("sound-layout-96");
  100. MODULE_ALIAS("sound-layout-98");
  101. MODULE_ALIAS("sound-layout-100");
  102. MODULE_ALIAS("aoa-device-id-14");
  103. MODULE_ALIAS("aoa-device-id-22");
  104. MODULE_ALIAS("aoa-device-id-35");
  105. /* onyx with all but microphone connected */
  106. static struct codec_connection onyx_connections_nomic[] = {
  107. {
  108. .connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT,
  109. .codec_bit = 0,
  110. },
  111. {
  112. .connected = CC_DIGITALOUT,
  113. .codec_bit = 1,
  114. },
  115. {
  116. .connected = CC_LINEIN,
  117. .codec_bit = 2,
  118. },
  119. {} /* terminate array by .connected == 0 */
  120. };
  121. /* onyx on machines without headphone */
  122. static struct codec_connection onyx_connections_noheadphones[] = {
  123. {
  124. .connected = CC_SPEAKERS | CC_LINEOUT |
  125. CC_LINEOUT_LABELLED_HEADPHONE,
  126. .codec_bit = 0,
  127. },
  128. {
  129. .connected = CC_DIGITALOUT,
  130. .codec_bit = 1,
  131. },
  132. /* FIXME: are these correct? probably not for all the machines
  133. * below ... If not this will need separating. */
  134. {
  135. .connected = CC_LINEIN,
  136. .codec_bit = 2,
  137. },
  138. {
  139. .connected = CC_MICROPHONE,
  140. .codec_bit = 3,
  141. },
  142. {} /* terminate array by .connected == 0 */
  143. };
  144. /* onyx on machines with real line-out */
  145. static struct codec_connection onyx_connections_reallineout[] = {
  146. {
  147. .connected = CC_SPEAKERS | CC_LINEOUT | CC_HEADPHONE,
  148. .codec_bit = 0,
  149. },
  150. {
  151. .connected = CC_DIGITALOUT,
  152. .codec_bit = 1,
  153. },
  154. {
  155. .connected = CC_LINEIN,
  156. .codec_bit = 2,
  157. },
  158. {} /* terminate array by .connected == 0 */
  159. };
  160. /* tas on machines without line out */
  161. static struct codec_connection tas_connections_nolineout[] = {
  162. {
  163. .connected = CC_SPEAKERS | CC_HEADPHONE,
  164. .codec_bit = 0,
  165. },
  166. {
  167. .connected = CC_LINEIN,
  168. .codec_bit = 2,
  169. },
  170. {
  171. .connected = CC_MICROPHONE,
  172. .codec_bit = 3,
  173. },
  174. {} /* terminate array by .connected == 0 */
  175. };
  176. /* tas on machines with neither line out nor line in */
  177. static struct codec_connection tas_connections_noline[] = {
  178. {
  179. .connected = CC_SPEAKERS | CC_HEADPHONE,
  180. .codec_bit = 0,
  181. },
  182. {
  183. .connected = CC_MICROPHONE,
  184. .codec_bit = 3,
  185. },
  186. {} /* terminate array by .connected == 0 */
  187. };
  188. /* tas on machines without microphone */
  189. static struct codec_connection tas_connections_nomic[] = {
  190. {
  191. .connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT,
  192. .codec_bit = 0,
  193. },
  194. {
  195. .connected = CC_LINEIN,
  196. .codec_bit = 2,
  197. },
  198. {} /* terminate array by .connected == 0 */
  199. };
  200. /* tas on machines with everything connected */
  201. static struct codec_connection tas_connections_all[] = {
  202. {
  203. .connected = CC_SPEAKERS | CC_HEADPHONE | CC_LINEOUT,
  204. .codec_bit = 0,
  205. },
  206. {
  207. .connected = CC_LINEIN,
  208. .codec_bit = 2,
  209. },
  210. {
  211. .connected = CC_MICROPHONE,
  212. .codec_bit = 3,
  213. },
  214. {} /* terminate array by .connected == 0 */
  215. };
  216. static struct codec_connection toonie_connections[] = {
  217. {
  218. .connected = CC_SPEAKERS | CC_HEADPHONE,
  219. .codec_bit = 0,
  220. },
  221. {} /* terminate array by .connected == 0 */
  222. };
  223. static struct codec_connection topaz_input[] = {
  224. {
  225. .connected = CC_DIGITALIN,
  226. .codec_bit = 0,
  227. },
  228. {} /* terminate array by .connected == 0 */
  229. };
  230. static struct codec_connection topaz_output[] = {
  231. {
  232. .connected = CC_DIGITALOUT,
  233. .codec_bit = 1,
  234. },
  235. {} /* terminate array by .connected == 0 */
  236. };
  237. static struct codec_connection topaz_inout[] = {
  238. {
  239. .connected = CC_DIGITALIN,
  240. .codec_bit = 0,
  241. },
  242. {
  243. .connected = CC_DIGITALOUT,
  244. .codec_bit = 1,
  245. },
  246. {} /* terminate array by .connected == 0 */
  247. };
  248. static struct layout layouts[] = {
  249. /* last PowerBooks (15" Oct 2005) */
  250. { .layout_id = 82,
  251. .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF,
  252. .codecs[0] = {
  253. .name = "onyx",
  254. .connections = onyx_connections_noheadphones,
  255. },
  256. .codecs[1] = {
  257. .name = "topaz",
  258. .connections = topaz_input,
  259. },
  260. },
  261. /* PowerMac9,1 */
  262. { .layout_id = 60,
  263. .codecs[0] = {
  264. .name = "onyx",
  265. .connections = onyx_connections_reallineout,
  266. },
  267. },
  268. /* PowerMac9,1 */
  269. { .layout_id = 61,
  270. .codecs[0] = {
  271. .name = "topaz",
  272. .connections = topaz_input,
  273. },
  274. },
  275. /* PowerBook5,7 */
  276. { .layout_id = 64,
  277. .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF,
  278. .codecs[0] = {
  279. .name = "onyx",
  280. .connections = onyx_connections_noheadphones,
  281. },
  282. },
  283. /* PowerBook5,7 */
  284. { .layout_id = 65,
  285. .codecs[0] = {
  286. .name = "topaz",
  287. .connections = topaz_input,
  288. },
  289. },
  290. /* PowerBook5,9 [17" Oct 2005] */
  291. { .layout_id = 84,
  292. .flags = LAYOUT_FLAG_COMBO_LINEOUT_SPDIF,
  293. .codecs[0] = {
  294. .name = "onyx",
  295. .connections = onyx_connections_noheadphones,
  296. },
  297. .codecs[1] = {
  298. .name = "topaz",
  299. .connections = topaz_input,
  300. },
  301. },
  302. /* PowerMac8,1 */
  303. { .layout_id = 45,
  304. .codecs[0] = {
  305. .name = "onyx",
  306. .connections = onyx_connections_noheadphones,
  307. },
  308. .codecs[1] = {
  309. .name = "topaz",
  310. .connections = topaz_input,
  311. },
  312. },
  313. /* Quad PowerMac (analog in, analog/digital out) */
  314. { .layout_id = 68,
  315. .codecs[0] = {
  316. .name = "onyx",
  317. .connections = onyx_connections_nomic,
  318. },
  319. },
  320. /* Quad PowerMac (digital in) */
  321. { .layout_id = 69,
  322. .codecs[0] = {
  323. .name = "topaz",
  324. .connections = topaz_input,
  325. },
  326. .busname = "digital in", .pcmid = 1 },
  327. /* Early 2005 PowerBook (PowerBook 5,6) */
  328. { .layout_id = 70,
  329. .codecs[0] = {
  330. .name = "tas",
  331. .connections = tas_connections_nolineout,
  332. },
  333. },
  334. /* PowerBook 5,4 */
  335. { .layout_id = 51,
  336. .codecs[0] = {
  337. .name = "tas",
  338. .connections = tas_connections_nolineout,
  339. },
  340. },
  341. /* PowerBook6,7 */
  342. { .layout_id = 80,
  343. .codecs[0] = {
  344. .name = "tas",
  345. .connections = tas_connections_noline,
  346. },
  347. },
  348. /* PowerBook6,8 */
  349. { .layout_id = 72,
  350. .codecs[0] = {
  351. .name = "tas",
  352. .connections = tas_connections_nolineout,
  353. },
  354. },
  355. /* PowerMac8,2 */
  356. { .layout_id = 86,
  357. .codecs[0] = {
  358. .name = "onyx",
  359. .connections = onyx_connections_nomic,
  360. },
  361. .codecs[1] = {
  362. .name = "topaz",
  363. .connections = topaz_input,
  364. },
  365. },
  366. /* PowerBook6,7 */
  367. { .layout_id = 92,
  368. .codecs[0] = {
  369. .name = "tas",
  370. .connections = tas_connections_nolineout,
  371. },
  372. },
  373. /* PowerMac10,1 (Mac Mini) */
  374. { .layout_id = 58,
  375. .codecs[0] = {
  376. .name = "toonie",
  377. .connections = toonie_connections,
  378. },
  379. },
  380. {
  381. .layout_id = 96,
  382. .codecs[0] = {
  383. .name = "onyx",
  384. .connections = onyx_connections_noheadphones,
  385. },
  386. },
  387. /* unknown, untested, but this comes from Apple */
  388. { .layout_id = 41,
  389. .codecs[0] = {
  390. .name = "tas",
  391. .connections = tas_connections_all,
  392. },
  393. },
  394. { .layout_id = 36,
  395. .codecs[0] = {
  396. .name = "tas",
  397. .connections = tas_connections_nomic,
  398. },
  399. .codecs[1] = {
  400. .name = "topaz",
  401. .connections = topaz_inout,
  402. },
  403. },
  404. { .layout_id = 47,
  405. .codecs[0] = {
  406. .name = "onyx",
  407. .connections = onyx_connections_noheadphones,
  408. },
  409. },
  410. { .layout_id = 48,
  411. .codecs[0] = {
  412. .name = "topaz",
  413. .connections = topaz_input,
  414. },
  415. },
  416. { .layout_id = 49,
  417. .codecs[0] = {
  418. .name = "onyx",
  419. .connections = onyx_connections_nomic,
  420. },
  421. },
  422. { .layout_id = 50,
  423. .codecs[0] = {
  424. .name = "topaz",
  425. .connections = topaz_input,
  426. },
  427. },
  428. { .layout_id = 56,
  429. .codecs[0] = {
  430. .name = "onyx",
  431. .connections = onyx_connections_noheadphones,
  432. },
  433. },
  434. { .layout_id = 57,
  435. .codecs[0] = {
  436. .name = "topaz",
  437. .connections = topaz_input,
  438. },
  439. },
  440. { .layout_id = 62,
  441. .codecs[0] = {
  442. .name = "onyx",
  443. .connections = onyx_connections_noheadphones,
  444. },
  445. .codecs[1] = {
  446. .name = "topaz",
  447. .connections = topaz_output,
  448. },
  449. },
  450. { .layout_id = 66,
  451. .codecs[0] = {
  452. .name = "onyx",
  453. .connections = onyx_connections_noheadphones,
  454. },
  455. },
  456. { .layout_id = 67,
  457. .codecs[0] = {
  458. .name = "topaz",
  459. .connections = topaz_input,
  460. },
  461. },
  462. { .layout_id = 76,
  463. .codecs[0] = {
  464. .name = "tas",
  465. .connections = tas_connections_nomic,
  466. },
  467. .codecs[1] = {
  468. .name = "topaz",
  469. .connections = topaz_inout,
  470. },
  471. },
  472. { .layout_id = 90,
  473. .codecs[0] = {
  474. .name = "tas",
  475. .connections = tas_connections_noline,
  476. },
  477. },
  478. { .layout_id = 94,
  479. .codecs[0] = {
  480. .name = "onyx",
  481. /* but it has an external mic?? how to select? */
  482. .connections = onyx_connections_noheadphones,
  483. },
  484. },
  485. { .layout_id = 98,
  486. .codecs[0] = {
  487. .name = "toonie",
  488. .connections = toonie_connections,
  489. },
  490. },
  491. { .layout_id = 100,
  492. .codecs[0] = {
  493. .name = "topaz",
  494. .connections = topaz_input,
  495. },
  496. .codecs[1] = {
  497. .name = "onyx",
  498. .connections = onyx_connections_noheadphones,
  499. },
  500. },
  501. /* PowerMac3,4 */
  502. { .device_id = 14,
  503. .codecs[0] = {
  504. .name = "tas",
  505. .connections = tas_connections_noline,
  506. },
  507. },
  508. /* PowerMac3,6 */
  509. { .device_id = 22,
  510. .codecs[0] = {
  511. .name = "tas",
  512. .connections = tas_connections_all,
  513. },
  514. },
  515. /* PowerBook5,2 */
  516. { .device_id = 35,
  517. .codecs[0] = {
  518. .name = "tas",
  519. .connections = tas_connections_all,
  520. },
  521. },
  522. {}
  523. };
  524. static struct layout *find_layout_by_id(unsigned int id)
  525. {
  526. struct layout *l;
  527. l = layouts;
  528. while (l->codecs[0].name) {
  529. if (l->layout_id == id)
  530. return l;
  531. l++;
  532. }
  533. return NULL;
  534. }
  535. static struct layout *find_layout_by_device(unsigned int id)
  536. {
  537. struct layout *l;
  538. l = layouts;
  539. while (l->codecs[0].name) {
  540. if (l->device_id == id)
  541. return l;
  542. l++;
  543. }
  544. return NULL;
  545. }
  546. static void use_layout(struct layout *l)
  547. {
  548. int i;
  549. for (i=0; i<MAX_CODECS_PER_BUS; i++) {
  550. if (l->codecs[i].name) {
  551. request_module("snd-aoa-codec-%s", l->codecs[i].name);
  552. }
  553. }
  554. /* now we wait for the codecs to call us back */
  555. }
  556. struct layout_dev;
  557. struct layout_dev_ptr {
  558. struct layout_dev *ptr;
  559. };
  560. struct layout_dev {
  561. struct list_head list;
  562. struct soundbus_dev *sdev;
  563. struct device_node *sound;
  564. struct aoa_codec *codecs[MAX_CODECS_PER_BUS];
  565. struct layout *layout;
  566. struct gpio_runtime gpio;
  567. /* we need these for headphone/lineout detection */
  568. struct snd_kcontrol *headphone_ctrl;
  569. struct snd_kcontrol *lineout_ctrl;
  570. struct snd_kcontrol *speaker_ctrl;
  571. struct snd_kcontrol *master_ctrl;
  572. struct snd_kcontrol *headphone_detected_ctrl;
  573. struct snd_kcontrol *lineout_detected_ctrl;
  574. struct layout_dev_ptr selfptr_headphone;
  575. struct layout_dev_ptr selfptr_lineout;
  576. u32 have_lineout_detect:1,
  577. have_headphone_detect:1,
  578. switch_on_headphone:1,
  579. switch_on_lineout:1;
  580. };
  581. static LIST_HEAD(layouts_list);
  582. static int layouts_list_items;
  583. /* this can go away but only if we allow multiple cards,
  584. * make the fabric handle all the card stuff, etc... */
  585. static struct layout_dev *layout_device;
  586. #define control_info snd_ctl_boolean_mono_info
  587. #define AMP_CONTROL(n, description) \
  588. static int n##_control_get(struct snd_kcontrol *kcontrol, \
  589. struct snd_ctl_elem_value *ucontrol) \
  590. { \
  591. struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol); \
  592. if (gpio->methods && gpio->methods->get_##n) \
  593. ucontrol->value.integer.value[0] = \
  594. gpio->methods->get_##n(gpio); \
  595. return 0; \
  596. } \
  597. static int n##_control_put(struct snd_kcontrol *kcontrol, \
  598. struct snd_ctl_elem_value *ucontrol) \
  599. { \
  600. struct gpio_runtime *gpio = snd_kcontrol_chip(kcontrol); \
  601. if (gpio->methods && gpio->methods->get_##n) \
  602. gpio->methods->set_##n(gpio, \
  603. !!ucontrol->value.integer.value[0]); \
  604. return 1; \
  605. } \
  606. static struct snd_kcontrol_new n##_ctl = { \
  607. .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
  608. .name = description, \
  609. .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
  610. .info = control_info, \
  611. .get = n##_control_get, \
  612. .put = n##_control_put, \
  613. }
  614. AMP_CONTROL(headphone, "Headphone Switch");
  615. AMP_CONTROL(speakers, "Speakers Switch");
  616. AMP_CONTROL(lineout, "Line-Out Switch");
  617. AMP_CONTROL(master, "Master Switch");
  618. static int detect_choice_get(struct snd_kcontrol *kcontrol,
  619. struct snd_ctl_elem_value *ucontrol)
  620. {
  621. struct layout_dev *ldev = snd_kcontrol_chip(kcontrol);
  622. switch (kcontrol->private_value) {
  623. case 0:
  624. ucontrol->value.integer.value[0] = ldev->switch_on_headphone;
  625. break;
  626. case 1:
  627. ucontrol->value.integer.value[0] = ldev->switch_on_lineout;
  628. break;
  629. default:
  630. return -ENODEV;
  631. }
  632. return 0;
  633. }
  634. static int detect_choice_put(struct snd_kcontrol *kcontrol,
  635. struct snd_ctl_elem_value *ucontrol)
  636. {
  637. struct layout_dev *ldev = snd_kcontrol_chip(kcontrol);
  638. switch (kcontrol->private_value) {
  639. case 0:
  640. ldev->switch_on_headphone = !!ucontrol->value.integer.value[0];
  641. break;
  642. case 1:
  643. ldev->switch_on_lineout = !!ucontrol->value.integer.value[0];
  644. break;
  645. default:
  646. return -ENODEV;
  647. }
  648. return 1;
  649. }
  650. static struct snd_kcontrol_new headphone_detect_choice = {
  651. .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  652. .name = "Headphone Detect Autoswitch",
  653. .info = control_info,
  654. .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
  655. .get = detect_choice_get,
  656. .put = detect_choice_put,
  657. .private_value = 0,
  658. };
  659. static struct snd_kcontrol_new lineout_detect_choice = {
  660. .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  661. .name = "Line-Out Detect Autoswitch",
  662. .info = control_info,
  663. .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
  664. .get = detect_choice_get,
  665. .put = detect_choice_put,
  666. .private_value = 1,
  667. };
  668. static int detected_get(struct snd_kcontrol *kcontrol,
  669. struct snd_ctl_elem_value *ucontrol)
  670. {
  671. struct layout_dev *ldev = snd_kcontrol_chip(kcontrol);
  672. int v;
  673. switch (kcontrol->private_value) {
  674. case 0:
  675. v = ldev->gpio.methods->get_detect(&ldev->gpio,
  676. AOA_NOTIFY_HEADPHONE);
  677. break;
  678. case 1:
  679. v = ldev->gpio.methods->get_detect(&ldev->gpio,
  680. AOA_NOTIFY_LINE_OUT);
  681. break;
  682. default:
  683. return -ENODEV;
  684. }
  685. ucontrol->value.integer.value[0] = v;
  686. return 0;
  687. }
  688. static struct snd_kcontrol_new headphone_detected = {
  689. .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  690. .name = "Headphone Detected",
  691. .info = control_info,
  692. .access = SNDRV_CTL_ELEM_ACCESS_READ,
  693. .get = detected_get,
  694. .private_value = 0,
  695. };
  696. static struct snd_kcontrol_new lineout_detected = {
  697. .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  698. .name = "Line-Out Detected",
  699. .info = control_info,
  700. .access = SNDRV_CTL_ELEM_ACCESS_READ,
  701. .get = detected_get,
  702. .private_value = 1,
  703. };
  704. static int check_codec(struct aoa_codec *codec,
  705. struct layout_dev *ldev,
  706. struct codec_connect_info *cci)
  707. {
  708. const u32 *ref;
  709. char propname[32];
  710. struct codec_connection *cc;
  711. /* if the codec has a 'codec' node, we require a reference */
  712. if (codec->node && (strcmp(codec->node->name, "codec") == 0)) {
  713. snprintf(propname, sizeof(propname),
  714. "platform-%s-codec-ref", codec->name);
  715. ref = of_get_property(ldev->sound, propname, NULL);
  716. if (!ref) {
  717. printk(KERN_INFO "snd-aoa-fabric-layout: "
  718. "required property %s not present\n", propname);
  719. return -ENODEV;
  720. }
  721. if (*ref != codec->node->linux_phandle) {
  722. printk(KERN_INFO "snd-aoa-fabric-layout: "
  723. "%s doesn't match!\n", propname);
  724. return -ENODEV;
  725. }
  726. } else {
  727. if (layouts_list_items != 1) {
  728. printk(KERN_INFO "snd-aoa-fabric-layout: "
  729. "more than one soundbus, but no references.\n");
  730. return -ENODEV;
  731. }
  732. }
  733. codec->soundbus_dev = ldev->sdev;
  734. codec->gpio = &ldev->gpio;
  735. cc = cci->connections;
  736. if (!cc)
  737. return -EINVAL;
  738. printk(KERN_INFO "snd-aoa-fabric-layout: can use this codec\n");
  739. codec->connected = 0;
  740. codec->fabric_data = cc;
  741. while (cc->connected) {
  742. codec->connected |= 1<<cc->codec_bit;
  743. cc++;
  744. }
  745. return 0;
  746. }
  747. static int layout_found_codec(struct aoa_codec *codec)
  748. {
  749. struct layout_dev *ldev;
  750. int i;
  751. list_for_each_entry(ldev, &layouts_list, list) {
  752. for (i=0; i<MAX_CODECS_PER_BUS; i++) {
  753. if (!ldev->layout->codecs[i].name)
  754. continue;
  755. if (strcmp(ldev->layout->codecs[i].name, codec->name) == 0) {
  756. if (check_codec(codec,
  757. ldev,
  758. &ldev->layout->codecs[i]) == 0)
  759. return 0;
  760. }
  761. }
  762. }
  763. return -ENODEV;
  764. }
  765. static void layout_remove_codec(struct aoa_codec *codec)
  766. {
  767. int i;
  768. /* here remove the codec from the layout dev's
  769. * codec reference */
  770. codec->soundbus_dev = NULL;
  771. codec->gpio = NULL;
  772. for (i=0; i<MAX_CODECS_PER_BUS; i++) {
  773. }
  774. }
  775. static void layout_notify(void *data)
  776. {
  777. struct layout_dev_ptr *dptr = data;
  778. struct layout_dev *ldev;
  779. int v, update;
  780. struct snd_kcontrol *detected, *c;
  781. struct snd_card *card = aoa_get_card();
  782. ldev = dptr->ptr;
  783. if (data == &ldev->selfptr_headphone) {
  784. v = ldev->gpio.methods->get_detect(&ldev->gpio, AOA_NOTIFY_HEADPHONE);
  785. detected = ldev->headphone_detected_ctrl;
  786. update = ldev->switch_on_headphone;
  787. if (update) {
  788. ldev->gpio.methods->set_speakers(&ldev->gpio, !v);
  789. ldev->gpio.methods->set_headphone(&ldev->gpio, v);
  790. ldev->gpio.methods->set_lineout(&ldev->gpio, 0);
  791. }
  792. } else if (data == &ldev->selfptr_lineout) {
  793. v = ldev->gpio.methods->get_detect(&ldev->gpio, AOA_NOTIFY_LINE_OUT);
  794. detected = ldev->lineout_detected_ctrl;
  795. update = ldev->switch_on_lineout;
  796. if (update) {
  797. ldev->gpio.methods->set_speakers(&ldev->gpio, !v);
  798. ldev->gpio.methods->set_headphone(&ldev->gpio, 0);
  799. ldev->gpio.methods->set_lineout(&ldev->gpio, v);
  800. }
  801. } else
  802. return;
  803. if (detected)
  804. snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &detected->id);
  805. if (update) {
  806. c = ldev->headphone_ctrl;
  807. if (c)
  808. snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id);
  809. c = ldev->speaker_ctrl;
  810. if (c)
  811. snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id);
  812. c = ldev->lineout_ctrl;
  813. if (c)
  814. snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &c->id);
  815. }
  816. }
  817. static void layout_attached_codec(struct aoa_codec *codec)
  818. {
  819. struct codec_connection *cc;
  820. struct snd_kcontrol *ctl;
  821. int headphones, lineout;
  822. struct layout_dev *ldev = layout_device;
  823. /* need to add this codec to our codec array! */
  824. cc = codec->fabric_data;
  825. headphones = codec->gpio->methods->get_detect(codec->gpio,
  826. AOA_NOTIFY_HEADPHONE);
  827. lineout = codec->gpio->methods->get_detect(codec->gpio,
  828. AOA_NOTIFY_LINE_OUT);
  829. if (codec->gpio->methods->set_master) {
  830. ctl = snd_ctl_new1(&master_ctl, codec->gpio);
  831. ldev->master_ctrl = ctl;
  832. aoa_snd_ctl_add(ctl);
  833. }
  834. while (cc->connected) {
  835. if (cc->connected & CC_SPEAKERS) {
  836. if (headphones <= 0 && lineout <= 0)
  837. ldev->gpio.methods->set_speakers(codec->gpio, 1);
  838. ctl = snd_ctl_new1(&speakers_ctl, codec->gpio);
  839. ldev->speaker_ctrl = ctl;
  840. aoa_snd_ctl_add(ctl);
  841. }
  842. if (cc->connected & CC_HEADPHONE) {
  843. if (headphones == 1)
  844. ldev->gpio.methods->set_headphone(codec->gpio, 1);
  845. ctl = snd_ctl_new1(&headphone_ctl, codec->gpio);
  846. ldev->headphone_ctrl = ctl;
  847. aoa_snd_ctl_add(ctl);
  848. ldev->have_headphone_detect =
  849. !ldev->gpio.methods
  850. ->set_notify(&ldev->gpio,
  851. AOA_NOTIFY_HEADPHONE,
  852. layout_notify,
  853. &ldev->selfptr_headphone);
  854. if (ldev->have_headphone_detect) {
  855. ctl = snd_ctl_new1(&headphone_detect_choice,
  856. ldev);
  857. aoa_snd_ctl_add(ctl);
  858. ctl = snd_ctl_new1(&headphone_detected,
  859. ldev);
  860. ldev->headphone_detected_ctrl = ctl;
  861. aoa_snd_ctl_add(ctl);
  862. }
  863. }
  864. if (cc->connected & CC_LINEOUT) {
  865. if (lineout == 1)
  866. ldev->gpio.methods->set_lineout(codec->gpio, 1);
  867. ctl = snd_ctl_new1(&lineout_ctl, codec->gpio);
  868. if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
  869. strlcpy(ctl->id.name,
  870. "Headphone Switch", sizeof(ctl->id.name));
  871. ldev->lineout_ctrl = ctl;
  872. aoa_snd_ctl_add(ctl);
  873. ldev->have_lineout_detect =
  874. !ldev->gpio.methods
  875. ->set_notify(&ldev->gpio,
  876. AOA_NOTIFY_LINE_OUT,
  877. layout_notify,
  878. &ldev->selfptr_lineout);
  879. if (ldev->have_lineout_detect) {
  880. ctl = snd_ctl_new1(&lineout_detect_choice,
  881. ldev);
  882. if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
  883. strlcpy(ctl->id.name,
  884. "Headphone Detect Autoswitch",
  885. sizeof(ctl->id.name));
  886. aoa_snd_ctl_add(ctl);
  887. ctl = snd_ctl_new1(&lineout_detected,
  888. ldev);
  889. if (cc->connected & CC_LINEOUT_LABELLED_HEADPHONE)
  890. strlcpy(ctl->id.name,
  891. "Headphone Detected",
  892. sizeof(ctl->id.name));
  893. ldev->lineout_detected_ctrl = ctl;
  894. aoa_snd_ctl_add(ctl);
  895. }
  896. }
  897. cc++;
  898. }
  899. /* now update initial state */
  900. if (ldev->have_headphone_detect)
  901. layout_notify(&ldev->selfptr_headphone);
  902. if (ldev->have_lineout_detect)
  903. layout_notify(&ldev->selfptr_lineout);
  904. }
  905. static struct aoa_fabric layout_fabric = {
  906. .name = "SoundByLayout",
  907. .owner = THIS_MODULE,
  908. .found_codec = layout_found_codec,
  909. .remove_codec = layout_remove_codec,
  910. .attached_codec = layout_attached_codec,
  911. };
  912. static int aoa_fabric_layout_probe(struct soundbus_dev *sdev)
  913. {
  914. struct device_node *sound = NULL;
  915. const unsigned int *id;
  916. struct layout *layout = NULL;
  917. struct layout_dev *ldev = NULL;
  918. int err;
  919. /* hm, currently we can only have one ... */
  920. if (layout_device)
  921. return -ENODEV;
  922. /* by breaking out we keep a reference */
  923. while ((sound = of_get_next_child(sdev->ofdev.node, sound))) {
  924. if (sound->type && strcasecmp(sound->type, "soundchip") == 0)
  925. break;
  926. }
  927. if (!sound)
  928. return -ENODEV;
  929. id = of_get_property(sound, "layout-id", NULL);
  930. if (id) {
  931. layout = find_layout_by_id(*id);
  932. } else {
  933. id = of_get_property(sound, "device-id", NULL);
  934. if (id)
  935. layout = find_layout_by_device(*id);
  936. }
  937. if (!layout) {
  938. printk(KERN_ERR "snd-aoa-fabric-layout: unknown layout\n");
  939. goto outnodev;
  940. }
  941. ldev = kzalloc(sizeof(struct layout_dev), GFP_KERNEL);
  942. if (!ldev)
  943. goto outnodev;
  944. layout_device = ldev;
  945. ldev->sdev = sdev;
  946. ldev->sound = sound;
  947. ldev->layout = layout;
  948. ldev->gpio.node = sound->parent;
  949. switch (layout->layout_id) {
  950. case 0: /* anything with device_id, not layout_id */
  951. case 41: /* that unknown machine no one seems to have */
  952. case 51: /* PowerBook5,4 */
  953. case 58: /* Mac Mini */
  954. ldev->gpio.methods = ftr_gpio_methods;
  955. printk(KERN_DEBUG
  956. "snd-aoa-fabric-layout: Using direct GPIOs\n");
  957. break;
  958. default:
  959. ldev->gpio.methods = pmf_gpio_methods;
  960. printk(KERN_DEBUG
  961. "snd-aoa-fabric-layout: Using PMF GPIOs\n");
  962. }
  963. ldev->selfptr_headphone.ptr = ldev;
  964. ldev->selfptr_lineout.ptr = ldev;
  965. dev_set_drvdata(&sdev->ofdev.dev, ldev);
  966. list_add(&ldev->list, &layouts_list);
  967. layouts_list_items++;
  968. /* assign these before registering ourselves, so
  969. * callbacks that are done during registration
  970. * already have the values */
  971. sdev->pcmid = ldev->layout->pcmid;
  972. if (ldev->layout->busname) {
  973. sdev->pcmname = ldev->layout->busname;
  974. } else {
  975. sdev->pcmname = "Master";
  976. }
  977. ldev->gpio.methods->init(&ldev->gpio);
  978. err = aoa_fabric_register(&layout_fabric, &sdev->ofdev.dev);
  979. if (err && err != -EALREADY) {
  980. printk(KERN_INFO "snd-aoa-fabric-layout: can't use,"
  981. " another fabric is active!\n");
  982. goto outlistdel;
  983. }
  984. use_layout(layout);
  985. ldev->switch_on_headphone = 1;
  986. ldev->switch_on_lineout = 1;
  987. return 0;
  988. outlistdel:
  989. /* we won't be using these then... */
  990. ldev->gpio.methods->exit(&ldev->gpio);
  991. /* reset if we didn't use it */
  992. sdev->pcmname = NULL;
  993. sdev->pcmid = -1;
  994. list_del(&ldev->list);
  995. layouts_list_items--;
  996. outnodev:
  997. of_node_put(sound);
  998. layout_device = NULL;
  999. kfree(ldev);
  1000. return -ENODEV;
  1001. }
  1002. static int aoa_fabric_layout_remove(struct soundbus_dev *sdev)
  1003. {
  1004. struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev);
  1005. int i;
  1006. for (i=0; i<MAX_CODECS_PER_BUS; i++) {
  1007. if (ldev->codecs[i]) {
  1008. aoa_fabric_unlink_codec(ldev->codecs[i]);
  1009. }
  1010. ldev->codecs[i] = NULL;
  1011. }
  1012. list_del(&ldev->list);
  1013. layouts_list_items--;
  1014. of_node_put(ldev->sound);
  1015. ldev->gpio.methods->set_notify(&ldev->gpio,
  1016. AOA_NOTIFY_HEADPHONE,
  1017. NULL,
  1018. NULL);
  1019. ldev->gpio.methods->set_notify(&ldev->gpio,
  1020. AOA_NOTIFY_LINE_OUT,
  1021. NULL,
  1022. NULL);
  1023. ldev->gpio.methods->exit(&ldev->gpio);
  1024. layout_device = NULL;
  1025. kfree(ldev);
  1026. sdev->pcmid = -1;
  1027. sdev->pcmname = NULL;
  1028. return 0;
  1029. }
  1030. #ifdef CONFIG_PM
  1031. static int aoa_fabric_layout_suspend(struct soundbus_dev *sdev, pm_message_t state)
  1032. {
  1033. struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev);
  1034. if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
  1035. ldev->gpio.methods->all_amps_off(&ldev->gpio);
  1036. return 0;
  1037. }
  1038. static int aoa_fabric_layout_resume(struct soundbus_dev *sdev)
  1039. {
  1040. struct layout_dev *ldev = dev_get_drvdata(&sdev->ofdev.dev);
  1041. if (ldev->gpio.methods && ldev->gpio.methods->all_amps_off)
  1042. ldev->gpio.methods->all_amps_restore(&ldev->gpio);
  1043. return 0;
  1044. }
  1045. #endif
  1046. static struct soundbus_driver aoa_soundbus_driver = {
  1047. .name = "snd_aoa_soundbus_drv",
  1048. .owner = THIS_MODULE,
  1049. .probe = aoa_fabric_layout_probe,
  1050. .remove = aoa_fabric_layout_remove,
  1051. #ifdef CONFIG_PM
  1052. .suspend = aoa_fabric_layout_suspend,
  1053. .resume = aoa_fabric_layout_resume,
  1054. #endif
  1055. .driver = {
  1056. .owner = THIS_MODULE,
  1057. }
  1058. };
  1059. static int __init aoa_fabric_layout_init(void)
  1060. {
  1061. int err;
  1062. err = soundbus_register_driver(&aoa_soundbus_driver);
  1063. if (err)
  1064. return err;
  1065. return 0;
  1066. }
  1067. static void __exit aoa_fabric_layout_exit(void)
  1068. {
  1069. soundbus_unregister_driver(&aoa_soundbus_driver);
  1070. aoa_fabric_unregister(&layout_fabric);
  1071. }
  1072. module_init(aoa_fabric_layout_init);
  1073. module_exit(aoa_fabric_layout_exit);