soc-dapm.c 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506
  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. if (strict_strtoul(buf, 10, &pop_time) < 0)
  719. printk(KERN_ERR "Unable to parse pop_time setting\n");
  720. return count;
  721. }
  722. static DEVICE_ATTR(dapm_pop_time, 0744, dapm_pop_time_show,
  723. dapm_pop_time_store);
  724. int snd_soc_dapm_sys_add(struct device *dev)
  725. {
  726. int ret = 0;
  727. if (dapm_status) {
  728. ret = device_create_file(dev, &dev_attr_dapm_widget);
  729. if (ret == 0)
  730. ret = device_create_file(dev, &dev_attr_dapm_pop_time);
  731. }
  732. return ret;
  733. }
  734. static void snd_soc_dapm_sys_remove(struct device *dev)
  735. {
  736. if (dapm_status) {
  737. device_remove_file(dev, &dev_attr_dapm_pop_time);
  738. device_remove_file(dev, &dev_attr_dapm_widget);
  739. }
  740. }
  741. /* free all dapm widgets and resources */
  742. static void dapm_free_widgets(struct snd_soc_codec *codec)
  743. {
  744. struct snd_soc_dapm_widget *w, *next_w;
  745. struct snd_soc_dapm_path *p, *next_p;
  746. list_for_each_entry_safe(w, next_w, &codec->dapm_widgets, list) {
  747. list_del(&w->list);
  748. kfree(w);
  749. }
  750. list_for_each_entry_safe(p, next_p, &codec->dapm_paths, list) {
  751. list_del(&p->list);
  752. kfree(p->long_name);
  753. kfree(p);
  754. }
  755. }
  756. /**
  757. * snd_soc_dapm_sync_endpoints - scan and power dapm paths
  758. * @codec: audio codec
  759. *
  760. * Walks all dapm audio paths and powers widgets according to their
  761. * stream or path usage.
  762. *
  763. * Returns 0 for success.
  764. */
  765. int snd_soc_dapm_sync_endpoints(struct snd_soc_codec *codec)
  766. {
  767. return dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
  768. }
  769. EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_endpoints);
  770. static int snd_soc_dapm_add_route(struct snd_soc_codec *codec,
  771. const char *sink, const char *control, const char *source)
  772. {
  773. struct snd_soc_dapm_path *path;
  774. struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
  775. int ret = 0;
  776. /* find src and dest widgets */
  777. list_for_each_entry(w, &codec->dapm_widgets, list) {
  778. if (!wsink && !(strcmp(w->name, sink))) {
  779. wsink = w;
  780. continue;
  781. }
  782. if (!wsource && !(strcmp(w->name, source))) {
  783. wsource = w;
  784. }
  785. }
  786. if (wsource == NULL || wsink == NULL)
  787. return -ENODEV;
  788. path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
  789. if (!path)
  790. return -ENOMEM;
  791. path->source = wsource;
  792. path->sink = wsink;
  793. INIT_LIST_HEAD(&path->list);
  794. INIT_LIST_HEAD(&path->list_source);
  795. INIT_LIST_HEAD(&path->list_sink);
  796. /* check for external widgets */
  797. if (wsink->id == snd_soc_dapm_input) {
  798. if (wsource->id == snd_soc_dapm_micbias ||
  799. wsource->id == snd_soc_dapm_mic ||
  800. wsink->id == snd_soc_dapm_line ||
  801. wsink->id == snd_soc_dapm_output)
  802. wsink->ext = 1;
  803. }
  804. if (wsource->id == snd_soc_dapm_output) {
  805. if (wsink->id == snd_soc_dapm_spk ||
  806. wsink->id == snd_soc_dapm_hp ||
  807. wsink->id == snd_soc_dapm_line ||
  808. wsink->id == snd_soc_dapm_input)
  809. wsource->ext = 1;
  810. }
  811. /* connect static paths */
  812. if (control == NULL) {
  813. list_add(&path->list, &codec->dapm_paths);
  814. list_add(&path->list_sink, &wsink->sources);
  815. list_add(&path->list_source, &wsource->sinks);
  816. path->connect = 1;
  817. return 0;
  818. }
  819. /* connect dynamic paths */
  820. switch(wsink->id) {
  821. case snd_soc_dapm_adc:
  822. case snd_soc_dapm_dac:
  823. case snd_soc_dapm_pga:
  824. case snd_soc_dapm_input:
  825. case snd_soc_dapm_output:
  826. case snd_soc_dapm_micbias:
  827. case snd_soc_dapm_vmid:
  828. case snd_soc_dapm_pre:
  829. case snd_soc_dapm_post:
  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. case snd_soc_dapm_mux:
  836. ret = dapm_connect_mux(codec, wsource, wsink, path, control,
  837. &wsink->kcontrols[0]);
  838. if (ret != 0)
  839. goto err;
  840. break;
  841. case snd_soc_dapm_switch:
  842. case snd_soc_dapm_mixer:
  843. ret = dapm_connect_mixer(codec, wsource, wsink, path, control);
  844. if (ret != 0)
  845. goto err;
  846. break;
  847. case snd_soc_dapm_hp:
  848. case snd_soc_dapm_mic:
  849. case snd_soc_dapm_line:
  850. case snd_soc_dapm_spk:
  851. list_add(&path->list, &codec->dapm_paths);
  852. list_add(&path->list_sink, &wsink->sources);
  853. list_add(&path->list_source, &wsource->sinks);
  854. path->connect = 0;
  855. return 0;
  856. }
  857. return 0;
  858. err:
  859. printk(KERN_WARNING "asoc: no dapm match for %s --> %s --> %s\n", source,
  860. control, sink);
  861. kfree(path);
  862. return ret;
  863. }
  864. /**
  865. * snd_soc_dapm_connect_input - connect dapm widgets
  866. * @codec: audio codec
  867. * @sink: name of target widget
  868. * @control: mixer control name
  869. * @source: name of source name
  870. *
  871. * Connects 2 dapm widgets together via a named audio path. The sink is
  872. * the widget receiving the audio signal, whilst the source is the sender
  873. * of the audio signal.
  874. *
  875. * This function has been deprecated in favour of snd_soc_dapm_add_routes().
  876. *
  877. * Returns 0 for success else error.
  878. */
  879. int snd_soc_dapm_connect_input(struct snd_soc_codec *codec, const char *sink,
  880. const char *control, const char *source)
  881. {
  882. return snd_soc_dapm_add_route(codec, sink, control, source);
  883. }
  884. EXPORT_SYMBOL_GPL(snd_soc_dapm_connect_input);
  885. /**
  886. * snd_soc_dapm_add_routes - Add routes between DAPM widgets
  887. * @codec: codec
  888. * @route: audio routes
  889. * @num: number of routes
  890. *
  891. * Connects 2 dapm widgets together via a named audio path. The sink is
  892. * the widget receiving the audio signal, whilst the source is the sender
  893. * of the audio signal.
  894. *
  895. * Returns 0 for success else error. On error all resources can be freed
  896. * with a call to snd_soc_card_free().
  897. */
  898. int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
  899. const struct snd_soc_dapm_route *route, int num)
  900. {
  901. int i, ret;
  902. for (i = 0; i < num; i++) {
  903. ret = snd_soc_dapm_add_route(codec, route->sink,
  904. route->control, route->source);
  905. if (ret < 0) {
  906. printk(KERN_ERR "Failed to add route %s->%s\n",
  907. route->source,
  908. route->sink);
  909. return ret;
  910. }
  911. route++;
  912. }
  913. return 0;
  914. }
  915. EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes);
  916. /**
  917. * snd_soc_dapm_new_widgets - add new dapm widgets
  918. * @codec: audio codec
  919. *
  920. * Checks the codec for any new dapm widgets and creates them if found.
  921. *
  922. * Returns 0 for success.
  923. */
  924. int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
  925. {
  926. struct snd_soc_dapm_widget *w;
  927. list_for_each_entry(w, &codec->dapm_widgets, list)
  928. {
  929. if (w->new)
  930. continue;
  931. switch(w->id) {
  932. case snd_soc_dapm_switch:
  933. case snd_soc_dapm_mixer:
  934. dapm_new_mixer(codec, w);
  935. break;
  936. case snd_soc_dapm_mux:
  937. dapm_new_mux(codec, w);
  938. break;
  939. case snd_soc_dapm_adc:
  940. case snd_soc_dapm_dac:
  941. case snd_soc_dapm_pga:
  942. dapm_new_pga(codec, w);
  943. break;
  944. case snd_soc_dapm_input:
  945. case snd_soc_dapm_output:
  946. case snd_soc_dapm_micbias:
  947. case snd_soc_dapm_spk:
  948. case snd_soc_dapm_hp:
  949. case snd_soc_dapm_mic:
  950. case snd_soc_dapm_line:
  951. case snd_soc_dapm_vmid:
  952. case snd_soc_dapm_pre:
  953. case snd_soc_dapm_post:
  954. break;
  955. }
  956. w->new = 1;
  957. }
  958. dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
  959. return 0;
  960. }
  961. EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
  962. /**
  963. * snd_soc_dapm_get_volsw - dapm mixer get callback
  964. * @kcontrol: mixer control
  965. * @uinfo: control element information
  966. *
  967. * Callback to get the value of a dapm mixer control.
  968. *
  969. * Returns 0 for success.
  970. */
  971. int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
  972. struct snd_ctl_elem_value *ucontrol)
  973. {
  974. struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
  975. int reg = kcontrol->private_value & 0xff;
  976. int shift = (kcontrol->private_value >> 8) & 0x0f;
  977. int rshift = (kcontrol->private_value >> 12) & 0x0f;
  978. int max = (kcontrol->private_value >> 16) & 0xff;
  979. int invert = (kcontrol->private_value >> 24) & 0x01;
  980. int mask = (1 << fls(max)) - 1;
  981. /* return the saved value if we are powered down */
  982. if (widget->id == snd_soc_dapm_pga && !widget->power) {
  983. ucontrol->value.integer.value[0] = widget->saved_value;
  984. return 0;
  985. }
  986. ucontrol->value.integer.value[0] =
  987. (snd_soc_read(widget->codec, reg) >> shift) & mask;
  988. if (shift != rshift)
  989. ucontrol->value.integer.value[1] =
  990. (snd_soc_read(widget->codec, reg) >> rshift) & mask;
  991. if (invert) {
  992. ucontrol->value.integer.value[0] =
  993. max - ucontrol->value.integer.value[0];
  994. if (shift != rshift)
  995. ucontrol->value.integer.value[1] =
  996. max - ucontrol->value.integer.value[1];
  997. }
  998. return 0;
  999. }
  1000. EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
  1001. /**
  1002. * snd_soc_dapm_put_volsw - dapm mixer set callback
  1003. * @kcontrol: mixer control
  1004. * @uinfo: control element information
  1005. *
  1006. * Callback to set the value of a dapm mixer control.
  1007. *
  1008. * Returns 0 for success.
  1009. */
  1010. int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
  1011. struct snd_ctl_elem_value *ucontrol)
  1012. {
  1013. struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
  1014. int reg = kcontrol->private_value & 0xff;
  1015. int shift = (kcontrol->private_value >> 8) & 0x0f;
  1016. int rshift = (kcontrol->private_value >> 12) & 0x0f;
  1017. int max = (kcontrol->private_value >> 16) & 0xff;
  1018. int mask = (1 << fls(max)) - 1;
  1019. int invert = (kcontrol->private_value >> 24) & 0x01;
  1020. unsigned short val, val2, val_mask;
  1021. int ret;
  1022. val = (ucontrol->value.integer.value[0] & mask);
  1023. if (invert)
  1024. val = max - val;
  1025. val_mask = mask << shift;
  1026. val = val << shift;
  1027. if (shift != rshift) {
  1028. val2 = (ucontrol->value.integer.value[1] & mask);
  1029. if (invert)
  1030. val2 = max - val2;
  1031. val_mask |= mask << rshift;
  1032. val |= val2 << rshift;
  1033. }
  1034. mutex_lock(&widget->codec->mutex);
  1035. widget->value = val;
  1036. /* save volume value if the widget is powered down */
  1037. if (widget->id == snd_soc_dapm_pga && !widget->power) {
  1038. widget->saved_value = val;
  1039. mutex_unlock(&widget->codec->mutex);
  1040. return 1;
  1041. }
  1042. dapm_mixer_update_power(widget, kcontrol, reg, val_mask, val, invert);
  1043. if (widget->event) {
  1044. if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
  1045. ret = widget->event(widget, kcontrol,
  1046. SND_SOC_DAPM_PRE_REG);
  1047. if (ret < 0) {
  1048. ret = 1;
  1049. goto out;
  1050. }
  1051. }
  1052. ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
  1053. if (widget->event_flags & SND_SOC_DAPM_POST_REG)
  1054. ret = widget->event(widget, kcontrol,
  1055. SND_SOC_DAPM_POST_REG);
  1056. } else
  1057. ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
  1058. out:
  1059. mutex_unlock(&widget->codec->mutex);
  1060. return ret;
  1061. }
  1062. EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
  1063. /**
  1064. * snd_soc_dapm_get_enum_double - dapm enumerated double mixer get callback
  1065. * @kcontrol: mixer control
  1066. * @uinfo: control element information
  1067. *
  1068. * Callback to get the value of a dapm enumerated double mixer control.
  1069. *
  1070. * Returns 0 for success.
  1071. */
  1072. int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
  1073. struct snd_ctl_elem_value *ucontrol)
  1074. {
  1075. struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
  1076. struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
  1077. unsigned short val, bitmask;
  1078. for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
  1079. ;
  1080. val = snd_soc_read(widget->codec, e->reg);
  1081. ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & (bitmask - 1);
  1082. if (e->shift_l != e->shift_r)
  1083. ucontrol->value.enumerated.item[1] =
  1084. (val >> e->shift_r) & (bitmask - 1);
  1085. return 0;
  1086. }
  1087. EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
  1088. /**
  1089. * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback
  1090. * @kcontrol: mixer control
  1091. * @uinfo: control element information
  1092. *
  1093. * Callback to set the value of a dapm enumerated double mixer control.
  1094. *
  1095. * Returns 0 for success.
  1096. */
  1097. int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
  1098. struct snd_ctl_elem_value *ucontrol)
  1099. {
  1100. struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
  1101. struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
  1102. unsigned short val, mux;
  1103. unsigned short mask, bitmask;
  1104. int ret = 0;
  1105. for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
  1106. ;
  1107. if (ucontrol->value.enumerated.item[0] > e->mask - 1)
  1108. return -EINVAL;
  1109. mux = ucontrol->value.enumerated.item[0];
  1110. val = mux << e->shift_l;
  1111. mask = (bitmask - 1) << e->shift_l;
  1112. if (e->shift_l != e->shift_r) {
  1113. if (ucontrol->value.enumerated.item[1] > e->mask - 1)
  1114. return -EINVAL;
  1115. val |= ucontrol->value.enumerated.item[1] << e->shift_r;
  1116. mask |= (bitmask - 1) << e->shift_r;
  1117. }
  1118. mutex_lock(&widget->codec->mutex);
  1119. widget->value = val;
  1120. dapm_mux_update_power(widget, kcontrol, mask, mux, e);
  1121. if (widget->event) {
  1122. if (widget->event_flags & SND_SOC_DAPM_PRE_REG) {
  1123. ret = widget->event(widget,
  1124. kcontrol, SND_SOC_DAPM_PRE_REG);
  1125. if (ret < 0)
  1126. goto out;
  1127. }
  1128. ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
  1129. if (widget->event_flags & SND_SOC_DAPM_POST_REG)
  1130. ret = widget->event(widget,
  1131. kcontrol, SND_SOC_DAPM_POST_REG);
  1132. } else
  1133. ret = snd_soc_update_bits(widget->codec, e->reg, mask, val);
  1134. out:
  1135. mutex_unlock(&widget->codec->mutex);
  1136. return ret;
  1137. }
  1138. EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
  1139. /**
  1140. * snd_soc_dapm_new_control - create new dapm control
  1141. * @codec: audio codec
  1142. * @widget: widget template
  1143. *
  1144. * Creates a new dapm control based upon the template.
  1145. *
  1146. * Returns 0 for success else error.
  1147. */
  1148. int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
  1149. const struct snd_soc_dapm_widget *widget)
  1150. {
  1151. struct snd_soc_dapm_widget *w;
  1152. if ((w = dapm_cnew_widget(widget)) == NULL)
  1153. return -ENOMEM;
  1154. w->codec = codec;
  1155. INIT_LIST_HEAD(&w->sources);
  1156. INIT_LIST_HEAD(&w->sinks);
  1157. INIT_LIST_HEAD(&w->list);
  1158. list_add(&w->list, &codec->dapm_widgets);
  1159. /* machine layer set ups unconnected pins and insertions */
  1160. w->connected = 1;
  1161. return 0;
  1162. }
  1163. EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control);
  1164. /**
  1165. * snd_soc_dapm_new_controls - create new dapm controls
  1166. * @codec: audio codec
  1167. * @widget: widget array
  1168. * @num: number of widgets
  1169. *
  1170. * Creates new DAPM controls based upon the templates.
  1171. *
  1172. * Returns 0 for success else error.
  1173. */
  1174. int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
  1175. const struct snd_soc_dapm_widget *widget,
  1176. int num)
  1177. {
  1178. int i, ret;
  1179. for (i = 0; i < num; i++) {
  1180. ret = snd_soc_dapm_new_control(codec, widget);
  1181. if (ret < 0)
  1182. return ret;
  1183. widget++;
  1184. }
  1185. return 0;
  1186. }
  1187. EXPORT_SYMBOL_GPL(snd_soc_dapm_new_controls);
  1188. /**
  1189. * snd_soc_dapm_stream_event - send a stream event to the dapm core
  1190. * @codec: audio codec
  1191. * @stream: stream name
  1192. * @event: stream event
  1193. *
  1194. * Sends a stream event to the dapm core. The core then makes any
  1195. * necessary widget power changes.
  1196. *
  1197. * Returns 0 for success else error.
  1198. */
  1199. int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
  1200. char *stream, int event)
  1201. {
  1202. struct snd_soc_dapm_widget *w;
  1203. if (stream == NULL)
  1204. return 0;
  1205. mutex_lock(&codec->mutex);
  1206. list_for_each_entry(w, &codec->dapm_widgets, list)
  1207. {
  1208. if (!w->sname)
  1209. continue;
  1210. dbg("widget %s\n %s stream %s event %d\n", w->name, w->sname,
  1211. stream, event);
  1212. if (strstr(w->sname, stream)) {
  1213. switch(event) {
  1214. case SND_SOC_DAPM_STREAM_START:
  1215. w->active = 1;
  1216. break;
  1217. case SND_SOC_DAPM_STREAM_STOP:
  1218. w->active = 0;
  1219. break;
  1220. case SND_SOC_DAPM_STREAM_SUSPEND:
  1221. if (w->active)
  1222. w->suspend = 1;
  1223. w->active = 0;
  1224. break;
  1225. case SND_SOC_DAPM_STREAM_RESUME:
  1226. if (w->suspend) {
  1227. w->active = 1;
  1228. w->suspend = 0;
  1229. }
  1230. break;
  1231. case SND_SOC_DAPM_STREAM_PAUSE_PUSH:
  1232. break;
  1233. case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
  1234. break;
  1235. }
  1236. }
  1237. }
  1238. mutex_unlock(&codec->mutex);
  1239. dapm_power_widgets(codec, event);
  1240. dump_dapm(codec, __func__);
  1241. return 0;
  1242. }
  1243. EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event);
  1244. /**
  1245. * snd_soc_dapm_set_bias_level - set the bias level for the system
  1246. * @socdev: audio device
  1247. * @level: level to configure
  1248. *
  1249. * Configure the bias (power) levels for the SoC audio device.
  1250. *
  1251. * Returns 0 for success else error.
  1252. */
  1253. int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
  1254. enum snd_soc_bias_level level)
  1255. {
  1256. struct snd_soc_codec *codec = socdev->codec;
  1257. struct snd_soc_machine *machine = socdev->machine;
  1258. int ret = 0;
  1259. if (machine->set_bias_level)
  1260. ret = machine->set_bias_level(machine, level);
  1261. if (ret == 0 && codec->set_bias_level)
  1262. ret = codec->set_bias_level(codec, level);
  1263. return ret;
  1264. }
  1265. /**
  1266. * snd_soc_dapm_set_endpoint - set audio endpoint status
  1267. * @codec: audio codec
  1268. * @endpoint: audio signal endpoint (or start point)
  1269. * @status: point status
  1270. *
  1271. * Set audio endpoint status - connected or disconnected.
  1272. *
  1273. * Returns 0 for success else error.
  1274. */
  1275. int snd_soc_dapm_set_endpoint(struct snd_soc_codec *codec,
  1276. char *endpoint, int status)
  1277. {
  1278. struct snd_soc_dapm_widget *w;
  1279. list_for_each_entry(w, &codec->dapm_widgets, list) {
  1280. if (!strcmp(w->name, endpoint)) {
  1281. w->connected = status;
  1282. return 0;
  1283. }
  1284. }
  1285. return -ENODEV;
  1286. }
  1287. EXPORT_SYMBOL_GPL(snd_soc_dapm_set_endpoint);
  1288. /**
  1289. * snd_soc_dapm_get_endpoint_status - get audio endpoint status
  1290. * @codec: audio codec
  1291. * @endpoint: audio signal endpoint (or start point)
  1292. *
  1293. * Get audio endpoint status - connected or disconnected.
  1294. *
  1295. * Returns status
  1296. */
  1297. int snd_soc_dapm_get_endpoint_status(struct snd_soc_codec *codec,
  1298. char *endpoint)
  1299. {
  1300. struct snd_soc_dapm_widget *w;
  1301. list_for_each_entry(w, &codec->dapm_widgets, list) {
  1302. if (!strcmp(w->name, endpoint))
  1303. return w->connected;
  1304. }
  1305. return 0;
  1306. }
  1307. EXPORT_SYMBOL_GPL(snd_soc_dapm_get_endpoint_status);
  1308. /**
  1309. * snd_soc_dapm_free - free dapm resources
  1310. * @socdev: SoC device
  1311. *
  1312. * Free all dapm widgets and resources.
  1313. */
  1314. void snd_soc_dapm_free(struct snd_soc_device *socdev)
  1315. {
  1316. struct snd_soc_codec *codec = socdev->codec;
  1317. snd_soc_dapm_sys_remove(socdev->dev);
  1318. dapm_free_widgets(codec);
  1319. }
  1320. EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
  1321. /* Module information */
  1322. MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
  1323. MODULE_DESCRIPTION("Dynamic Audio Power Management core for ALSA SoC");
  1324. MODULE_LICENSE("GPL");