soc-dapm.c 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531
  1. /*
  2. * soc-dapm.c -- ALSA SoC Dynamic Audio Power Management
  3. *
  4. * Copyright 2005 Wolfson Microelectronics PLC.
  5. * Author: Liam Girdwood
  6. * liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License as published by the
  10. * Free Software Foundation; either version 2 of the License, or (at your
  11. * option) any later version.
  12. *
  13. * Features:
  14. * o Changes power status of internal codec blocks depending on the
  15. * dynamic configuration of codec internal audio paths and active
  16. * DAC's/ADC's.
  17. * o Platform power domain - can support external components i.e. amps and
  18. * mic/meadphone insertion events.
  19. * o Automatic Mic Bias support
  20. * o Jack insertion power event initiation - e.g. hp insertion will enable
  21. * sinks, dacs, etc
  22. * o Delayed powerdown of audio susbsystem to reduce pops between a quick
  23. * device reopen.
  24. *
  25. * Todo:
  26. * o DAPM power change sequencing - allow for configurable per
  27. * codec sequences.
  28. * o Support for analogue bias optimisation.
  29. * o Support for reduced codec oversampling rates.
  30. * o Support for reduced codec bias currents.
  31. */
  32. #include <linux/module.h>
  33. #include <linux/moduleparam.h>
  34. #include <linux/init.h>
  35. #include <linux/delay.h>
  36. #include <linux/pm.h>
  37. #include <linux/bitops.h>
  38. #include <linux/platform_device.h>
  39. #include <linux/jiffies.h>
  40. #include <sound/core.h>
  41. #include <sound/pcm.h>
  42. #include <sound/pcm_params.h>
  43. #include <sound/soc-dapm.h>
  44. #include <sound/initval.h>
  45. /* debug */
  46. #define DAPM_DEBUG 0
  47. #if DAPM_DEBUG
  48. #define dump_dapm(codec, action) dbg_dump_dapm(codec, action)
  49. #define dbg(format, arg...) printk(format, ## arg)
  50. #else
  51. #define dump_dapm(codec, action)
  52. #define dbg(format, arg...)
  53. #endif
  54. /* dapm power sequences - make this per codec in the future */
  55. static int dapm_up_seq[] = {
  56. snd_soc_dapm_pre, snd_soc_dapm_micbias, snd_soc_dapm_mic,
  57. snd_soc_dapm_mux, snd_soc_dapm_dac, snd_soc_dapm_mixer, snd_soc_dapm_pga,
  58. snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk, snd_soc_dapm_post
  59. };
  60. static int dapm_down_seq[] = {
  61. snd_soc_dapm_pre, snd_soc_dapm_adc, snd_soc_dapm_hp, snd_soc_dapm_spk,
  62. snd_soc_dapm_pga, snd_soc_dapm_mixer, snd_soc_dapm_dac, snd_soc_dapm_mic,
  63. snd_soc_dapm_micbias, snd_soc_dapm_mux, snd_soc_dapm_post
  64. };
  65. static int dapm_status = 1;
  66. module_param(dapm_status, int, 0);
  67. MODULE_PARM_DESC(dapm_status, "enable DPM sysfs entries");
  68. static unsigned int pop_time;
  69. static void pop_wait(void)
  70. {
  71. if (pop_time)
  72. schedule_timeout_uninterruptible(msecs_to_jiffies(pop_time));
  73. }
  74. static void pop_dbg(const char *fmt, ...)
  75. {
  76. va_list args;
  77. va_start(args, fmt);
  78. if (pop_time) {
  79. vprintk(fmt, args);
  80. pop_wait();
  81. }
  82. va_end(args);
  83. }
  84. /* create a new dapm widget */
  85. static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
  86. const struct snd_soc_dapm_widget *_widget)
  87. {
  88. return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
  89. }
  90. /* set up initial codec paths */
  91. static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
  92. struct snd_soc_dapm_path *p, int i)
  93. {
  94. switch (w->id) {
  95. case snd_soc_dapm_switch:
  96. case snd_soc_dapm_mixer: {
  97. int val;
  98. int reg = w->kcontrols[i].private_value & 0xff;
  99. int shift = (w->kcontrols[i].private_value >> 8) & 0x0f;
  100. int mask = (w->kcontrols[i].private_value >> 16) & 0xff;
  101. int invert = (w->kcontrols[i].private_value >> 24) & 0x01;
  102. val = snd_soc_read(w->codec, reg);
  103. val = (val >> shift) & mask;
  104. if ((invert && !val) || (!invert && val))
  105. p->connect = 1;
  106. else
  107. p->connect = 0;
  108. }
  109. break;
  110. case snd_soc_dapm_mux: {
  111. struct soc_enum *e = (struct soc_enum *)w->kcontrols[i].private_value;
  112. int val, item, bitmask;
  113. for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
  114. ;
  115. val = snd_soc_read(w->codec, e->reg);
  116. item = (val >> e->shift_l) & (bitmask - 1);
  117. p->connect = 0;
  118. for (i = 0; i < e->mask; i++) {
  119. if (!(strcmp(p->name, e->texts[i])) && item == i)
  120. p->connect = 1;
  121. }
  122. }
  123. break;
  124. /* does not effect routing - always connected */
  125. case snd_soc_dapm_pga:
  126. case snd_soc_dapm_output:
  127. case snd_soc_dapm_adc:
  128. case snd_soc_dapm_input:
  129. case snd_soc_dapm_dac:
  130. case snd_soc_dapm_micbias:
  131. case snd_soc_dapm_vmid:
  132. p->connect = 1;
  133. break;
  134. /* does effect routing - dynamically connected */
  135. case snd_soc_dapm_hp:
  136. case snd_soc_dapm_mic:
  137. case snd_soc_dapm_spk:
  138. case snd_soc_dapm_line:
  139. case snd_soc_dapm_pre:
  140. case snd_soc_dapm_post:
  141. p->connect = 0;
  142. break;
  143. }
  144. }
  145. /* connect mux widget to it's interconnecting audio paths */
  146. static int dapm_connect_mux(struct snd_soc_codec *codec,
  147. struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
  148. struct snd_soc_dapm_path *path, const char *control_name,
  149. const struct snd_kcontrol_new *kcontrol)
  150. {
  151. struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
  152. int i;
  153. for (i = 0; i < e->mask; i++) {
  154. if (!(strcmp(control_name, e->texts[i]))) {
  155. list_add(&path->list, &codec->dapm_paths);
  156. list_add(&path->list_sink, &dest->sources);
  157. list_add(&path->list_source, &src->sinks);
  158. path->name = (char*)e->texts[i];
  159. dapm_set_path_status(dest, path, 0);
  160. return 0;
  161. }
  162. }
  163. return -ENODEV;
  164. }
  165. /* connect mixer widget to it's interconnecting audio paths */
  166. static int dapm_connect_mixer(struct snd_soc_codec *codec,
  167. struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
  168. struct snd_soc_dapm_path *path, const char *control_name)
  169. {
  170. int i;
  171. /* search for mixer kcontrol */
  172. for (i = 0; i < dest->num_kcontrols; i++) {
  173. if (!strcmp(control_name, dest->kcontrols[i].name)) {
  174. list_add(&path->list, &codec->dapm_paths);
  175. list_add(&path->list_sink, &dest->sources);
  176. list_add(&path->list_source, &src->sinks);
  177. path->name = dest->kcontrols[i].name;
  178. dapm_set_path_status(dest, path, i);
  179. return 0;
  180. }
  181. }
  182. return -ENODEV;
  183. }
  184. /* update dapm codec register bits */
  185. static int dapm_update_bits(struct snd_soc_dapm_widget *widget)
  186. {
  187. int change, power;
  188. unsigned short old, new;
  189. struct snd_soc_codec *codec = widget->codec;
  190. /* check for valid widgets */
  191. if (widget->reg < 0 || widget->id == snd_soc_dapm_input ||
  192. widget->id == snd_soc_dapm_output ||
  193. widget->id == snd_soc_dapm_hp ||
  194. widget->id == snd_soc_dapm_mic ||
  195. widget->id == snd_soc_dapm_line ||
  196. widget->id == snd_soc_dapm_spk)
  197. return 0;
  198. power = widget->power;
  199. if (widget->invert)
  200. power = (power ? 0:1);
  201. old = snd_soc_read(codec, widget->reg);
  202. new = (old & ~(0x1 << widget->shift)) | (power << widget->shift);
  203. change = old != new;
  204. if (change) {
  205. pop_dbg("pop test %s : %s in %d ms\n", widget->name,
  206. widget->power ? "on" : "off", pop_time);
  207. snd_soc_write(codec, widget->reg, new);
  208. pop_wait();
  209. }
  210. dbg("reg %x old %x new %x change %d\n", widget->reg, old, new, change);
  211. return change;
  212. }
  213. /* ramps the volume up or down to minimise pops before or after a
  214. * DAPM power event */
  215. static int dapm_set_pga(struct snd_soc_dapm_widget *widget, int power)
  216. {
  217. const struct snd_kcontrol_new *k = widget->kcontrols;
  218. if (widget->muted && !power)
  219. return 0;
  220. if (!widget->muted && power)
  221. return 0;
  222. if (widget->num_kcontrols && k) {
  223. int reg = k->private_value & 0xff;
  224. int shift = (k->private_value >> 8) & 0x0f;
  225. int mask = (k->private_value >> 16) & 0xff;
  226. int invert = (k->private_value >> 24) & 0x01;
  227. if (power) {
  228. int i;
  229. /* power up has happended, increase volume to last level */
  230. if (invert) {
  231. for (i = mask; i > widget->saved_value; i--)
  232. snd_soc_update_bits(widget->codec, reg, mask, i);
  233. } else {
  234. for (i = 0; i < widget->saved_value; i++)
  235. snd_soc_update_bits(widget->codec, reg, mask, i);
  236. }
  237. widget->muted = 0;
  238. } else {
  239. /* power down is about to occur, decrease volume to mute */
  240. int val = snd_soc_read(widget->codec, reg);
  241. int i = widget->saved_value = (val >> shift) & mask;
  242. if (invert) {
  243. for (; i < mask; i++)
  244. snd_soc_update_bits(widget->codec, reg, mask, i);
  245. } else {
  246. for (; i > 0; i--)
  247. snd_soc_update_bits(widget->codec, reg, mask, i);
  248. }
  249. widget->muted = 1;
  250. }
  251. }
  252. return 0;
  253. }
  254. /* create new dapm mixer control */
  255. static int dapm_new_mixer(struct snd_soc_codec *codec,
  256. struct snd_soc_dapm_widget *w)
  257. {
  258. int i, ret = 0;
  259. char name[32];
  260. struct snd_soc_dapm_path *path;
  261. /* add kcontrol */
  262. for (i = 0; i < w->num_kcontrols; i++) {
  263. /* match name */
  264. list_for_each_entry(path, &w->sources, list_sink) {
  265. /* mixer/mux paths name must match control name */
  266. if (path->name != (char*)w->kcontrols[i].name)
  267. continue;
  268. /* add dapm control with long name */
  269. snprintf(name, 32, "%s %s", w->name, w->kcontrols[i].name);
  270. path->long_name = kstrdup (name, GFP_KERNEL);
  271. if (path->long_name == NULL)
  272. return -ENOMEM;
  273. path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w,
  274. path->long_name);
  275. ret = snd_ctl_add(codec->card, path->kcontrol);
  276. if (ret < 0) {
  277. printk(KERN_ERR "asoc: failed to add dapm kcontrol %s\n",
  278. path->long_name);
  279. kfree(path->long_name);
  280. path->long_name = NULL;
  281. return ret;
  282. }
  283. }
  284. }
  285. return ret;
  286. }
  287. /* create new dapm mux control */
  288. static int dapm_new_mux(struct snd_soc_codec *codec,
  289. struct snd_soc_dapm_widget *w)
  290. {
  291. struct snd_soc_dapm_path *path = NULL;
  292. struct snd_kcontrol *kcontrol;
  293. int ret = 0;
  294. if (!w->num_kcontrols) {
  295. printk(KERN_ERR "asoc: mux %s has no controls\n", w->name);
  296. return -EINVAL;
  297. }
  298. kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name);
  299. ret = snd_ctl_add(codec->card, kcontrol);
  300. if (ret < 0)
  301. goto err;
  302. list_for_each_entry(path, &w->sources, list_sink)
  303. path->kcontrol = kcontrol;
  304. return ret;
  305. err:
  306. printk(KERN_ERR "asoc: failed to add kcontrol %s\n", w->name);
  307. return ret;
  308. }
  309. /* create new dapm volume control */
  310. static int dapm_new_pga(struct snd_soc_codec *codec,
  311. struct snd_soc_dapm_widget *w)
  312. {
  313. struct snd_kcontrol *kcontrol;
  314. int ret = 0;
  315. if (!w->num_kcontrols)
  316. return -EINVAL;
  317. kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name);
  318. ret = snd_ctl_add(codec->card, kcontrol);
  319. if (ret < 0) {
  320. printk(KERN_ERR "asoc: failed to add kcontrol %s\n", w->name);
  321. return ret;
  322. }
  323. return ret;
  324. }
  325. /* reset 'walked' bit for each dapm path */
  326. static inline void dapm_clear_walk(struct snd_soc_codec *codec)
  327. {
  328. struct snd_soc_dapm_path *p;
  329. list_for_each_entry(p, &codec->dapm_paths, list)
  330. p->walked = 0;
  331. }
  332. /*
  333. * Recursively check for a completed path to an active or physically connected
  334. * output widget. Returns number of complete paths.
  335. */
  336. static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
  337. {
  338. struct snd_soc_dapm_path *path;
  339. int con = 0;
  340. if (widget->id == snd_soc_dapm_adc && widget->active)
  341. return 1;
  342. if (widget->connected) {
  343. /* connected pin ? */
  344. if (widget->id == snd_soc_dapm_output && !widget->ext)
  345. return 1;
  346. /* connected jack or spk ? */
  347. if (widget->id == snd_soc_dapm_hp || widget->id == snd_soc_dapm_spk ||
  348. widget->id == snd_soc_dapm_line)
  349. return 1;
  350. }
  351. list_for_each_entry(path, &widget->sinks, list_source) {
  352. if (path->walked)
  353. continue;
  354. if (path->sink && path->connect) {
  355. path->walked = 1;
  356. con += is_connected_output_ep(path->sink);
  357. }
  358. }
  359. return con;
  360. }
  361. /*
  362. * Recursively check for a completed path to an active or physically connected
  363. * input widget. Returns number of complete paths.
  364. */
  365. static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
  366. {
  367. struct snd_soc_dapm_path *path;
  368. int con = 0;
  369. /* active stream ? */
  370. if (widget->id == snd_soc_dapm_dac && widget->active)
  371. return 1;
  372. if (widget->connected) {
  373. /* connected pin ? */
  374. if (widget->id == snd_soc_dapm_input && !widget->ext)
  375. return 1;
  376. /* connected VMID/Bias for lower pops */
  377. if (widget->id == snd_soc_dapm_vmid)
  378. return 1;
  379. /* connected jack ? */
  380. if (widget->id == snd_soc_dapm_mic || widget->id == snd_soc_dapm_line)
  381. return 1;
  382. }
  383. list_for_each_entry(path, &widget->sources, list_sink) {
  384. if (path->walked)
  385. continue;
  386. if (path->source && path->connect) {
  387. path->walked = 1;
  388. con += is_connected_input_ep(path->source);
  389. }
  390. }
  391. return con;
  392. }
  393. /*
  394. * Handler for generic register modifier widget.
  395. */
  396. int dapm_reg_event(struct snd_soc_dapm_widget *w,
  397. struct snd_kcontrol *kcontrol, int event)
  398. {
  399. unsigned int val;
  400. if (SND_SOC_DAPM_EVENT_ON(event))
  401. val = w->on_val;
  402. else
  403. val = w->off_val;
  404. snd_soc_update_bits(w->codec, -(w->reg + 1),
  405. w->mask << w->shift, val << w->shift);
  406. return 0;
  407. }
  408. /*
  409. * Scan each dapm widget for complete audio path.
  410. * A complete path is a route that has valid endpoints i.e.:-
  411. *
  412. * o DAC to output pin.
  413. * o Input Pin to ADC.
  414. * o Input pin to Output pin (bypass, sidetone)
  415. * o DAC to ADC (loopback).
  416. */
  417. static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
  418. {
  419. struct snd_soc_dapm_widget *w;
  420. int in, out, i, c = 1, *seq = NULL, ret = 0, power_change, power;
  421. /* do we have a sequenced stream event */
  422. if (event == SND_SOC_DAPM_STREAM_START) {
  423. c = ARRAY_SIZE(dapm_up_seq);
  424. seq = dapm_up_seq;
  425. } else if (event == SND_SOC_DAPM_STREAM_STOP) {
  426. c = ARRAY_SIZE(dapm_down_seq);
  427. seq = dapm_down_seq;
  428. }
  429. for(i = 0; i < c; i++) {
  430. list_for_each_entry(w, &codec->dapm_widgets, list) {
  431. /* is widget in stream order */
  432. if (seq && seq[i] && w->id != seq[i])
  433. continue;
  434. /* vmid - no action */
  435. if (w->id == snd_soc_dapm_vmid)
  436. continue;
  437. /* active ADC */
  438. if (w->id == snd_soc_dapm_adc && w->active) {
  439. in = is_connected_input_ep(w);
  440. dapm_clear_walk(w->codec);
  441. w->power = (in != 0) ? 1 : 0;
  442. dapm_update_bits(w);
  443. continue;
  444. }
  445. /* active DAC */
  446. if (w->id == snd_soc_dapm_dac && w->active) {
  447. out = is_connected_output_ep(w);
  448. dapm_clear_walk(w->codec);
  449. w->power = (out != 0) ? 1 : 0;
  450. dapm_update_bits(w);
  451. continue;
  452. }
  453. /* programmable gain/attenuation */
  454. if (w->id == snd_soc_dapm_pga) {
  455. int on;
  456. in = is_connected_input_ep(w);
  457. dapm_clear_walk(w->codec);
  458. out = is_connected_output_ep(w);
  459. dapm_clear_walk(w->codec);
  460. w->power = on = (out != 0 && in != 0) ? 1 : 0;
  461. if (!on)
  462. dapm_set_pga(w, on); /* lower volume to reduce pops */
  463. dapm_update_bits(w);
  464. if (on)
  465. dapm_set_pga(w, on); /* restore volume from zero */
  466. continue;
  467. }
  468. /* pre and post event widgets */
  469. if (w->id == snd_soc_dapm_pre) {
  470. if (!w->event)
  471. continue;
  472. if (event == SND_SOC_DAPM_STREAM_START) {
  473. ret = w->event(w,
  474. NULL, SND_SOC_DAPM_PRE_PMU);
  475. if (ret < 0)
  476. return ret;
  477. } else if (event == SND_SOC_DAPM_STREAM_STOP) {
  478. ret = w->event(w,
  479. NULL, SND_SOC_DAPM_PRE_PMD);
  480. if (ret < 0)
  481. return ret;
  482. }
  483. continue;
  484. }
  485. if (w->id == snd_soc_dapm_post) {
  486. if (!w->event)
  487. continue;
  488. if (event == SND_SOC_DAPM_STREAM_START) {
  489. ret = w->event(w,
  490. NULL, SND_SOC_DAPM_POST_PMU);
  491. if (ret < 0)
  492. return ret;
  493. } else if (event == SND_SOC_DAPM_STREAM_STOP) {
  494. ret = w->event(w,
  495. NULL, SND_SOC_DAPM_POST_PMD);
  496. if (ret < 0)
  497. return ret;
  498. }
  499. continue;
  500. }
  501. /* all other widgets */
  502. in = is_connected_input_ep(w);
  503. dapm_clear_walk(w->codec);
  504. out = is_connected_output_ep(w);
  505. dapm_clear_walk(w->codec);
  506. power = (out != 0 && in != 0) ? 1 : 0;
  507. power_change = (w->power == power) ? 0: 1;
  508. w->power = power;
  509. /* call any power change event handlers */
  510. if (power_change) {
  511. if (w->event) {
  512. dbg("power %s event for %s flags %x\n",
  513. w->power ? "on" : "off", w->name, w->event_flags);
  514. if (power) {
  515. /* power up event */
  516. if (w->event_flags & SND_SOC_DAPM_PRE_PMU) {
  517. ret = w->event(w,
  518. NULL, SND_SOC_DAPM_PRE_PMU);
  519. if (ret < 0)
  520. return ret;
  521. }
  522. dapm_update_bits(w);
  523. if (w->event_flags & SND_SOC_DAPM_POST_PMU){
  524. ret = w->event(w,
  525. NULL, SND_SOC_DAPM_POST_PMU);
  526. if (ret < 0)
  527. return ret;
  528. }
  529. } else {
  530. /* power down event */
  531. if (w->event_flags & SND_SOC_DAPM_PRE_PMD) {
  532. ret = w->event(w,
  533. NULL, SND_SOC_DAPM_PRE_PMD);
  534. if (ret < 0)
  535. return ret;
  536. }
  537. dapm_update_bits(w);
  538. if (w->event_flags & SND_SOC_DAPM_POST_PMD) {
  539. ret = w->event(w,
  540. NULL, SND_SOC_DAPM_POST_PMD);
  541. if (ret < 0)
  542. return ret;
  543. }
  544. }
  545. } else
  546. /* no event handler */
  547. dapm_update_bits(w);
  548. }
  549. }
  550. }
  551. return ret;
  552. }
  553. #if DAPM_DEBUG
  554. static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action)
  555. {
  556. struct snd_soc_dapm_widget *w;
  557. struct snd_soc_dapm_path *p = NULL;
  558. int in, out;
  559. printk("DAPM %s %s\n", codec->name, action);
  560. list_for_each_entry(w, &codec->dapm_widgets, list) {
  561. /* only display widgets that effect routing */
  562. switch (w->id) {
  563. case snd_soc_dapm_pre:
  564. case snd_soc_dapm_post:
  565. case snd_soc_dapm_vmid:
  566. continue;
  567. case snd_soc_dapm_mux:
  568. case snd_soc_dapm_output:
  569. case snd_soc_dapm_input:
  570. case snd_soc_dapm_switch:
  571. case snd_soc_dapm_hp:
  572. case snd_soc_dapm_mic:
  573. case snd_soc_dapm_spk:
  574. case snd_soc_dapm_line:
  575. case snd_soc_dapm_micbias:
  576. case snd_soc_dapm_dac:
  577. case snd_soc_dapm_adc:
  578. case snd_soc_dapm_pga:
  579. case snd_soc_dapm_mixer:
  580. if (w->name) {
  581. in = is_connected_input_ep(w);
  582. dapm_clear_walk(w->codec);
  583. out = is_connected_output_ep(w);
  584. dapm_clear_walk(w->codec);
  585. printk("%s: %s in %d out %d\n", w->name,
  586. w->power ? "On":"Off",in, out);
  587. list_for_each_entry(p, &w->sources, list_sink) {
  588. if (p->connect)
  589. printk(" in %s %s\n", p->name ? p->name : "static",
  590. p->source->name);
  591. }
  592. list_for_each_entry(p, &w->sinks, list_source) {
  593. if (p->connect)
  594. printk(" out %s %s\n", p->name ? p->name : "static",
  595. p->sink->name);
  596. }
  597. }
  598. break;
  599. }
  600. }
  601. }
  602. #endif
  603. /* test and update the power status of a mux widget */
  604. static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
  605. struct snd_kcontrol *kcontrol, int mask,
  606. int val, struct soc_enum* e)
  607. {
  608. struct snd_soc_dapm_path *path;
  609. int found = 0;
  610. if (widget->id != snd_soc_dapm_mux)
  611. return -ENODEV;
  612. if (!snd_soc_test_bits(widget->codec, e->reg, mask, val))
  613. return 0;
  614. /* find dapm widget path assoc with kcontrol */
  615. list_for_each_entry(path, &widget->codec->dapm_paths, list) {
  616. if (path->kcontrol != kcontrol)
  617. continue;
  618. if (!path->name || ! e->texts[val])
  619. continue;
  620. found = 1;
  621. /* we now need to match the string in the enum to the path */
  622. if (!(strcmp(path->name, e->texts[val])))
  623. path->connect = 1; /* new connection */
  624. else
  625. path->connect = 0; /* old connection must be powered down */
  626. }
  627. if (found)
  628. dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
  629. return 0;
  630. }
  631. /* test and update the power status of a mixer or switch widget */
  632. static int dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
  633. struct snd_kcontrol *kcontrol, int reg,
  634. int val_mask, int val, int invert)
  635. {
  636. struct snd_soc_dapm_path *path;
  637. int found = 0;
  638. if (widget->id != snd_soc_dapm_mixer &&
  639. widget->id != snd_soc_dapm_switch)
  640. return -ENODEV;
  641. if (!snd_soc_test_bits(widget->codec, reg, val_mask, val))
  642. return 0;
  643. /* find dapm widget path assoc with kcontrol */
  644. list_for_each_entry(path, &widget->codec->dapm_paths, list) {
  645. if (path->kcontrol != kcontrol)
  646. continue;
  647. /* found, now check type */
  648. found = 1;
  649. if (val)
  650. /* new connection */
  651. path->connect = invert ? 0:1;
  652. else
  653. /* old connection must be powered down */
  654. path->connect = invert ? 1:0;
  655. break;
  656. }
  657. if (found)
  658. dapm_power_widgets(widget->codec, SND_SOC_DAPM_STREAM_NOP);
  659. return 0;
  660. }
  661. /* show dapm widget status in sys fs */
  662. static ssize_t dapm_widget_show(struct device *dev,
  663. struct device_attribute *attr, char *buf)
  664. {
  665. struct snd_soc_device *devdata = dev_get_drvdata(dev);
  666. struct snd_soc_codec *codec = devdata->codec;
  667. struct snd_soc_dapm_widget *w;
  668. int count = 0;
  669. char *state = "not set";
  670. list_for_each_entry(w, &codec->dapm_widgets, list) {
  671. /* only display widgets that burnm power */
  672. switch (w->id) {
  673. case snd_soc_dapm_hp:
  674. case snd_soc_dapm_mic:
  675. case snd_soc_dapm_spk:
  676. case snd_soc_dapm_line:
  677. case snd_soc_dapm_micbias:
  678. case snd_soc_dapm_dac:
  679. case snd_soc_dapm_adc:
  680. case snd_soc_dapm_pga:
  681. case snd_soc_dapm_mixer:
  682. if (w->name)
  683. count += sprintf(buf + count, "%s: %s\n",
  684. w->name, w->power ? "On":"Off");
  685. break;
  686. default:
  687. break;
  688. }
  689. }
  690. switch (codec->bias_level) {
  691. case SND_SOC_BIAS_ON:
  692. state = "On";
  693. break;
  694. case SND_SOC_BIAS_PREPARE:
  695. state = "Prepare";
  696. break;
  697. case SND_SOC_BIAS_STANDBY:
  698. state = "Standby";
  699. break;
  700. case SND_SOC_BIAS_OFF:
  701. state = "Off";
  702. break;
  703. }
  704. count += sprintf(buf + count, "PM State: %s\n", state);
  705. return count;
  706. }
  707. static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
  708. /* pop/click delay times */
  709. static ssize_t dapm_pop_time_show(struct device *dev,
  710. struct device_attribute *attr, char *buf)
  711. {
  712. return sprintf(buf, "%d\n", pop_time);
  713. }
  714. static ssize_t dapm_pop_time_store(struct device *dev,
  715. struct device_attribute *attr,
  716. const char *buf, size_t count)
  717. {
  718. unsigned long val;
  719. if (strict_strtoul(buf, 10, &val) >= 0)
  720. pop_time = val;
  721. else
  722. printk(KERN_ERR "Unable to parse pop_time setting\n");
  723. return count;
  724. }
  725. static DEVICE_ATTR(dapm_pop_time, 0744, dapm_pop_time_show,
  726. dapm_pop_time_store);
  727. int snd_soc_dapm_sys_add(struct device *dev)
  728. {
  729. int ret = 0;
  730. if (dapm_status) {
  731. ret = device_create_file(dev, &dev_attr_dapm_widget);
  732. if (ret == 0)
  733. ret = device_create_file(dev, &dev_attr_dapm_pop_time);
  734. }
  735. return ret;
  736. }
  737. static void snd_soc_dapm_sys_remove(struct device *dev)
  738. {
  739. if (dapm_status) {
  740. device_remove_file(dev, &dev_attr_dapm_pop_time);
  741. device_remove_file(dev, &dev_attr_dapm_widget);
  742. }
  743. }
  744. /* free all dapm widgets and resources */
  745. static void dapm_free_widgets(struct snd_soc_codec *codec)
  746. {
  747. struct snd_soc_dapm_widget *w, *next_w;
  748. struct snd_soc_dapm_path *p, *next_p;
  749. list_for_each_entry_safe(w, next_w, &codec->dapm_widgets, list) {
  750. list_del(&w->list);
  751. kfree(w);
  752. }
  753. list_for_each_entry_safe(p, next_p, &codec->dapm_paths, list) {
  754. list_del(&p->list);
  755. kfree(p->long_name);
  756. kfree(p);
  757. }
  758. }
  759. static int snd_soc_dapm_set_pin(struct snd_soc_codec *codec,
  760. char *pin, int status)
  761. {
  762. struct snd_soc_dapm_widget *w;
  763. list_for_each_entry(w, &codec->dapm_widgets, list) {
  764. if (!strcmp(w->name, pin)) {
  765. dbg("dapm: %s: pin %s\n", codec->name, pin);
  766. w->connected = status;
  767. return 0;
  768. }
  769. }
  770. dbg("dapm: %s: configuring unknown pin %s\n", codec->name, pin);
  771. return -EINVAL;
  772. }
  773. /**
  774. * snd_soc_dapm_sync - scan and power dapm paths
  775. * @codec: audio codec
  776. *
  777. * Walks all dapm audio paths and powers widgets according to their
  778. * stream or path usage.
  779. *
  780. * Returns 0 for success.
  781. */
  782. int snd_soc_dapm_sync(struct snd_soc_codec *codec)
  783. {
  784. return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
  785. }
  786. EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
  787. static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
  788. const char *sink, const char *control, const char *source)
  789. {
  790. struct snd_soc_dapm_path *path;
  791. struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
  792. int ret = 0;
  793. /* find src and dest widgets */
  794. list_for_each_entry(w, &codec->dapm_widgets, list) {
  795. if (!wsink && !(strcmp(w->name, sink))) {
  796. wsink = w;
  797. continue;
  798. }
  799. if (!wsource && !(strcmp(w->name, source))) {
  800. wsource = w;
  801. }
  802. }
  803. if (wsource == NULL || wsink == NULL)
  804. return -ENODEV;
  805. path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
  806. if (!path)
  807. return -ENOMEM;
  808. path->source = wsource;
  809. path->sink = wsink;
  810. INIT_LIST_HEAD(&path->list);
  811. INIT_LIST_HEAD(&path->list_source);
  812. INIT_LIST_HEAD(&path->list_sink);
  813. /* check for external widgets */
  814. if (wsink->id == snd_soc_dapm_input) {
  815. if (wsource->id == snd_soc_dapm_micbias ||
  816. wsource->id == snd_soc_dapm_mic ||
  817. wsink->id == snd_soc_dapm_line ||
  818. wsink->id == snd_soc_dapm_output)
  819. wsink->ext = 1;
  820. }
  821. if (wsource->id == snd_soc_dapm_output) {
  822. if (wsink->id == snd_soc_dapm_spk ||
  823. wsink->id == snd_soc_dapm_hp ||
  824. wsink->id == snd_soc_dapm_line ||
  825. wsink->id == snd_soc_dapm_input)
  826. wsource->ext = 1;
  827. }
  828. /* connect static paths */
  829. if (control == NULL) {
  830. list_add(&path->list, &codec->dapm_paths);
  831. list_add(&path->list_sink, &wsink->sources);
  832. list_add(&path->list_source, &wsource->sinks);
  833. path->connect = 1;
  834. return 0;
  835. }
  836. /* connect dynamic paths */
  837. switch(wsink->id) {
  838. case snd_soc_dapm_adc:
  839. case snd_soc_dapm_dac:
  840. case snd_soc_dapm_pga:
  841. case snd_soc_dapm_input:
  842. case snd_soc_dapm_output:
  843. case snd_soc_dapm_micbias:
  844. case snd_soc_dapm_vmid:
  845. case snd_soc_dapm_pre:
  846. case snd_soc_dapm_post:
  847. list_add(&path->list, &codec->dapm_paths);
  848. list_add(&path->list_sink, &wsink->sources);
  849. list_add(&path->list_source, &wsource->sinks);
  850. path->connect = 1;
  851. return 0;
  852. case snd_soc_dapm_mux:
  853. ret = dapm_connect_mux(codec, wsource, wsink, path, control,
  854. &wsink->kcontrols[0]);
  855. if (ret != 0)
  856. goto err;
  857. break;
  858. case snd_soc_dapm_switch:
  859. case snd_soc_dapm_mixer:
  860. ret = dapm_connect_mixer(codec, wsource, wsink, path, control);
  861. if (ret != 0)
  862. goto err;
  863. break;
  864. case snd_soc_dapm_hp:
  865. case snd_soc_dapm_mic:
  866. case snd_soc_dapm_line:
  867. case snd_soc_dapm_spk:
  868. list_add(&path->list, &codec->dapm_paths);
  869. list_add(&path->list_sink, &wsink->sources);
  870. list_add(&path->list_source, &wsource->sinks);
  871. path->connect = 0;
  872. return 0;
  873. }
  874. return 0;
  875. err:
  876. printk(KERN_WARNING "asoc: no dapm match for %s --> %s --> %s\n", source,
  877. control, sink);
  878. kfree(path);
  879. return ret;
  880. }
  881. /**
  882. * snd_soc_dapm_connect_input - connect dapm widgets
  883. * @codec: audio codec
  884. * @sink: name of target widget
  885. * @control: mixer control name
  886. * @source: name of source name
  887. *
  888. * Connects 2 dapm widgets together via a named audio path. The sink is
  889. * the widget receiving the audio signal, whilst the source is the sender
  890. * of the audio signal.
  891. *
  892. * This function has been deprecated in favour of snd_soc_dapm_add_routes().
  893. *
  894. * Returns 0 for success else error.
  895. */
  896. int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink,
  897. const char *control, const char *source)
  898. {
  899. return snd_soc_dapm_add_route(codec, sink, control, source);
  900. }
  901. EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input);
  902. /**
  903. * snd_soc_dapm_add_routes - Add routes between DAPM widgets
  904. * @codec: codec
  905. * @route: audio routes
  906. * @num: number of routes
  907. *
  908. * Connects 2 dapm widgets together via a named audio path. The sink is
  909. * the widget receiving the audio signal, whilst the source is the sender
  910. * of the audio signal.
  911. *
  912. * Returns 0 for success else error. On error all resources can be freed
  913. * with a call to snd_soc_card_free().
  914. */
  915. int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
  916. const struct snd_soc_dapm_route *route, int num)
  917. {
  918. int i, ret;
  919. for (i = 0; i < num; i++) {
  920. ret = snd_soc_dapm_add_route(codec, route->sink,
  921. route->control, route->source);
  922. if (ret < 0) {
  923. printk(KERN_ERR "Failed to add route %s->%s\n",
  924. route->source,
  925. route->sink);
  926. return ret;
  927. }
  928. route++;
  929. }
  930. return 0;
  931. }
  932. EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
  933. /**
  934. * snd_soc_dapm_new_widgets - add new dapm widgets
  935. * @codec: audio codec
  936. *
  937. * Checks the codec for any new dapm widgets and creates them if found.
  938. *
  939. * Returns 0 for success.
  940. */
  941. int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
  942. {
  943. struct snd_soc_dapm_widget *w;
  944. list_for_each_entry(w, &codec->dapm_widgets, list)
  945. {
  946. if (w->new)
  947. continue;
  948. switch(w->id) {
  949. case snd_soc_dapm_switch:
  950. case snd_soc_dapm_mixer:
  951. dapm_new_mixer(codec, w);
  952. break;
  953. case snd_soc_dapm_mux:
  954. dapm_new_mux(codec, w);
  955. break;
  956. case snd_soc_dapm_adc:
  957. case snd_soc_dapm_dac:
  958. case snd_soc_dapm_pga:
  959. dapm_new_pga(codec, w);
  960. break;
  961. case snd_soc_dapm_input:
  962. case snd_soc_dapm_output:
  963. case snd_soc_dapm_micbias:
  964. case snd_soc_dapm_spk:
  965. case snd_soc_dapm_hp:
  966. case snd_soc_dapm_mic:
  967. case snd_soc_dapm_line:
  968. case snd_soc_dapm_vmid:
  969. case snd_soc_dapm_pre:
  970. case snd_soc_dapm_post:
  971. break;
  972. }
  973. w->new = 1;
  974. }
  975. dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
  976. return 0;
  977. }
  978. EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
  979. /**
  980. * snd_soc_dapm_get_volsw - dapm mixer get callback
  981. * @kcontrol: mixer control
  982. * @uinfo: control element information
  983. *
  984. * Callback to get the value of a dapm mixer control.
  985. *
  986. * Returns 0 for success.
  987. */
  988. int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
  989. struct snd_ctl_elem_value *ucontrol)
  990. {
  991. struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
  992. int reg = kcontrol->private_value & 0xff;
  993. int shift = (kcontrol->private_value >> 8) & 0x0f;
  994. int rshift = (kcontrol->private_value >> 12) & 0x0f;
  995. int max = (kcontrol->private_value >> 16) & 0xff;
  996. int invert = (kcontrol->private_value >> 24) & 0x01;
  997. int mask = (1 << fls(max)) - 1;
  998. /* return the saved value if we are powered down */
  999. if (widget->id == snd_soc_dapm_pga && !widget->power) {
  1000. ucontrol->value.integer.value[0] = widget->saved_value;
  1001. return 0;
  1002. }
  1003. ucontrol->value.integer.value[0] =
  1004. (snd_soc_read(widget->codec, reg) >> shift) & mask;
  1005. if (shift != rshift)
  1006. ucontrol->value.integer.value[1] =
  1007. (snd_soc_read(widget->codec, reg) >> rshift) & mask;
  1008. if (invert) {
  1009. ucontrol->value.integer.value[0] =
  1010. max - ucontrol->value.integer.value[0];
  1011. if (shift != rshift)
  1012. ucontrol->value.integer.value[1] =
  1013. max - ucontrol->value.integer.value[1];
  1014. }
  1015. return 0;
  1016. }
  1017. EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
  1018. /**
  1019. * snd_soc_dapm_put_volsw - dapm mixer set callback
  1020. * @kcontrol: mixer control
  1021. * @uinfo: control element information
  1022. *
  1023. * Callback to set the value of a dapm mixer control.
  1024. *
  1025. * Returns 0 for success.
  1026. */
  1027. int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
  1028. struct snd_ctl_elem_value *ucontrol)
  1029. {
  1030. struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
  1031. int reg = kcontrol->private_value & 0xff;
  1032. int shift = (kcontrol->private_value >> 8) & 0x0f;
  1033. int rshift = (kcontrol->private_value >> 12) & 0x0f;
  1034. int max = (kcontrol->private_value >> 16) & 0xff;
  1035. int mask = (1 << fls(max)) - 1;
  1036. int invert = (kcontrol->private_value >> 24) & 0x01;
  1037. unsigned short val, val2, val_mask;
  1038. int ret;
  1039. val = (ucontrol->value.integer.value[0] & mask);
  1040. if (invert)
  1041. val = max - val;
  1042. val_mask = mask << shift;
  1043. val = val << shift;
  1044. if (shift != rshift) {
  1045. val2 = (ucontrol->value.integer.value[1] & mask);
  1046. if (invert)
  1047. val2 = max - val2;
  1048. val_mask |= mask << rshift;
  1049. val |= val2 << rshift;
  1050. }
  1051. mutex_lock(&widget->codec->mutex);
  1052. widget->value = val;
  1053. /* save volume value if the widget is powered down */
  1054. if (widget->id == snd_soc_dapm_pga && !widget->power) {
  1055. widget->saved_value = val;
  1056. mutex_unlock(&widget->codec->mutex);
  1057. return 1;
  1058. }
  1059. dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert);
  1060. if (widget->event) {
  1061. if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
  1062. ret = widget->event(widget, kcontrol,
  1063. SND_SOC_DAPM_PRE_REG);
  1064. if (ret < 0) {
  1065. ret = 1;
  1066. goto out;
  1067. }
  1068. }
  1069. ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
  1070. if (widget->event_flags & SND_SOC_DAPM_POST_REG)
  1071. ret = widget->event(widget, kcontrol,
  1072. SND_SOC_DAPM_POST_REG);
  1073. } else
  1074. ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
  1075. out:
  1076. mutex_unlock(&widget->codec->mutex);
  1077. return ret;
  1078. }
  1079. EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
  1080. /**
  1081. * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
  1082. * @kcontrol: mixer control
  1083. * @uinfo: control element information
  1084. *
  1085. * Callback to get the value of a dapm enumerated double mixer control.
  1086. *
  1087. * Returns 0 for success.
  1088. */
  1089. int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
  1090. struct snd_ctl_elem_value *ucontrol)
  1091. {
  1092. struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
  1093. struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
  1094. unsigned short val, bitmask;
  1095. for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
  1096. ;
  1097. val = snd_soc_read(widget->codec, e->reg);
  1098. ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
  1099. if (e->shift_l != e->shift_r)
  1100. ucontrol->value.enumerated.item[1] =
  1101. (val >> e->shift_r) & (bitmask - 1);
  1102. return 0;
  1103. }
  1104. EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
  1105. /**
  1106. * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
  1107. * @kcontrol: mixer control
  1108. * @uinfo: control element information
  1109. *
  1110. * Callback to set the value of a dapm enumerated double mixer control.
  1111. *
  1112. * Returns 0 for success.
  1113. */
  1114. int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
  1115. struct snd_ctl_elem_value *ucontrol)
  1116. {
  1117. struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
  1118. struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
  1119. unsigned short val, mux;
  1120. unsigned short mask, bitmask;
  1121. int ret = 0;
  1122. for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
  1123. ;
  1124. if (ucontrol->value.enumerated.item[0] > e->mask - 1)
  1125. return -EINVAL;
  1126. mux = ucontrol->value.enumerated.item[0];
  1127. val = mux << e->shift_l;
  1128. mask = (bitmask - 1) << e->shift_l;
  1129. if (e->shift_l != e->shift_r) {
  1130. if (ucontrol->value.enumerated.item[1] > e->mask - 1)
  1131. return -EINVAL;
  1132. val |= ucontrol->value.enumerated.item[1] << e->shift_r;
  1133. mask |= (bitmask - 1) << e->shift_r;
  1134. }
  1135. mutex_lock(&widget->codec->mutex);
  1136. widget->value = val;
  1137. dapm_mux_update_power(widget, kcontrol, mask, mux, e);
  1138. if (widget->event) {
  1139. if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
  1140. ret = widget->event(widget,
  1141. kcontrol, SND_SOC_DAPM_PRE_REG);
  1142. if (ret < 0)
  1143. goto out;
  1144. }
  1145. ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
  1146. if (widget->event_flags & SND_SOC_DAPM_POST_REG)
  1147. ret = widget->event(widget,
  1148. kcontrol, SND_SOC_DAPM_POST_REG);
  1149. } else
  1150. ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
  1151. out:
  1152. mutex_unlock(&widget->codec->mutex);
  1153. return ret;
  1154. }
  1155. EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
  1156. /**
  1157. * snd_soc_dapm_new_control - create new dapm control
  1158. * @codec: audio codec
  1159. * @widget: widget template
  1160. *
  1161. * Creates a new dapm control based upon the template.
  1162. *
  1163. * Returns 0 for success else error.
  1164. */
  1165. int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
  1166. const struct snd_soc_dapm_widget *widget)
  1167. {
  1168. struct snd_soc_dapm_widget *w;
  1169. if ((w = dapm_cnew_widget(widget)) == NULL)
  1170. return -ENOMEM;
  1171. w->codec = codec;
  1172. INIT_LIST_HEAD(&w->sources);
  1173. INIT_LIST_HEAD(&w->sinks);
  1174. INIT_LIST_HEAD(&w->list);
  1175. list_add(&w->list, &codec->dapm_widgets);
  1176. /* machine layer set ups unconnected pins and insertions */
  1177. w->connected = 1;
  1178. return 0;
  1179. }
  1180. EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
  1181. /**
  1182. * snd_soc_dapm_new_controls - create new dapm controls
  1183. * @codec: audio codec
  1184. * @widget: widget array
  1185. * @num: number of widgets
  1186. *
  1187. * Creates new DAPM controls based upon the templates.
  1188. *
  1189. * Returns 0 for success else error.
  1190. */
  1191. int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
  1192. const struct snd_soc_dapm_widget *widget,
  1193. int num)
  1194. {
  1195. int i, ret;
  1196. for (i = 0; i < num; i++) {
  1197. ret = snd_soc_dapm_new_control(codec, widget);
  1198. if (ret < 0)
  1199. return ret;
  1200. widget++;
  1201. }
  1202. return 0;
  1203. }
  1204. EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
  1205. /**
  1206. * snd_soc_dapm_stream_event - send a stream event to the dapm core
  1207. * @codec: audio codec
  1208. * @stream: stream name
  1209. * @event: stream event
  1210. *
  1211. * Sends a stream event to the dapm core. The core then makes any
  1212. * necessary widget power changes.
  1213. *
  1214. * Returns 0 for success else error.
  1215. */
  1216. int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
  1217. char *stream, int event)
  1218. {
  1219. struct snd_soc_dapm_widget *w;
  1220. if (stream == NULL)
  1221. return 0;
  1222. mutex_lock(&codec->mutex);
  1223. list_for_each_entry(w, &codec->dapm_widgets, list)
  1224. {
  1225. if (!w->sname)
  1226. continue;
  1227. dbg("widget %s\n %s stream %s event %d\n", w->name, w->sname,
  1228. stream, event);
  1229. if (strstr(w->sname, stream)) {
  1230. switch(event) {
  1231. case SND_SOC_DAPM_STREAM_START:
  1232. w->active = 1;
  1233. break;
  1234. case SND_SOC_DAPM_STREAM_STOP:
  1235. w->active = 0;
  1236. break;
  1237. case SND_SOC_DAPM_STREAM_SUSPEND:
  1238. if (w->active)
  1239. w->suspend = 1;
  1240. w->active = 0;
  1241. break;
  1242. case SND_SOC_DAPM_STREAM_RESUME:
  1243. if (w->suspend) {
  1244. w->active = 1;
  1245. w->suspend = 0;
  1246. }
  1247. break;
  1248. case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
  1249. break;
  1250. case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
  1251. break;
  1252. }
  1253. }
  1254. }
  1255. mutex_unlock(&codec->mutex);
  1256. dapm_power_widgets(codec, event);
  1257. dump_dapm(codec, __func__);
  1258. return 0;
  1259. }
  1260. EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
  1261. /**
  1262. * snd_soc_dapm_set_bias_level - set the bias level for the system
  1263. * @socdev: audio device
  1264. * @level: level to configure
  1265. *
  1266. * Configure the bias (power) levels for the SoC audio device.
  1267. *
  1268. * Returns 0 for success else error.
  1269. */
  1270. int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
  1271. enum snd_soc_bias_level level)
  1272. {
  1273. struct snd_soc_codec *codec = socdev->codec;
  1274. struct snd_soc_machine *machine = socdev->machine;
  1275. int ret = 0;
  1276. if (machine->set_bias_level)
  1277. ret = machine->set_bias_level(machine, level);
  1278. if (ret == 0 && codec->set_bias_level)
  1279. ret = codec->set_bias_level(codec, level);
  1280. return ret;
  1281. }
  1282. /**
  1283. * snd_soc_dapm_enable_pin - enable pin.
  1284. * @snd_soc_codec: SoC codec
  1285. * @pin: pin name
  1286. *
  1287. * Enables input/output pin and it's parents or children widgets iff there is
  1288. * a valid audio route and active audio stream.
  1289. * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
  1290. * do any widget power switching.
  1291. */
  1292. int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, char *pin)
  1293. {
  1294. return snd_soc_dapm_set_pin(codec, pin, 1);
  1295. }
  1296. EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin);
  1297. /**
  1298. * snd_soc_dapm_disable_pin - disable pin.
  1299. * @codec: SoC codec
  1300. * @pin: pin name
  1301. *
  1302. * Disables input/output pin and it's parents or children widgets.
  1303. * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to
  1304. * do any widget power switching.
  1305. */
  1306. int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, char *pin)
  1307. {
  1308. return snd_soc_dapm_set_pin(codec, pin, 0);
  1309. }
  1310. EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin);
  1311. /**
  1312. * snd_soc_dapm_get_pin_status - get audio pin status
  1313. * @codec: audio codec
  1314. * @pin: audio signal pin endpoint (or start point)
  1315. *
  1316. * Get audio pin status - connected or disconnected.
  1317. *
  1318. * Returns 1 for connected otherwise 0.
  1319. */
  1320. int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, char *pin)
  1321. {
  1322. struct snd_soc_dapm_widget *w;
  1323. list_for_each_entry(w, &codec->dapm_widgets, list) {
  1324. if (!strcmp(w->name, pin))
  1325. return w->connected;
  1326. }
  1327. return 0;
  1328. }
  1329. EXPORT_SYMBOL_GPL(snd_soc_dapm_get_pin_status);
  1330. /**
  1331. * snd_soc_dapm_free - free dapm resources
  1332. * @socdev: SoC device
  1333. *
  1334. * Free all dapm widgets and resources.
  1335. */
  1336. void snd_soc_dapm_free(struct snd_soc_device *socdev)
  1337. {
  1338. struct snd_soc_codec *codec = socdev->codec;
  1339. snd_soc_dapm_sys_remove(socdev->dev);
  1340. dapm_free_widgets(codec);
  1341. }
  1342. EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
  1343. /* Module information */
  1344. MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
  1345. MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
  1346. MODULE_LICENSE("GPL");