wm_hubs.c 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311
  1. /*
  2. * wm_hubs.c -- WM8993/4 common code
  3. *
  4. * Copyright 2009-12 Wolfson Microelectronics plc
  5. *
  6. * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
  7. *
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2 as
  11. * published by the Free Software Foundation.
  12. */
  13. #include <linux/module.h>
  14. #include <linux/moduleparam.h>
  15. #include <linux/init.h>
  16. #include <linux/delay.h>
  17. #include <linux/pm.h>
  18. #include <linux/i2c.h>
  19. #include <linux/mfd/wm8994/registers.h>
  20. #include <sound/core.h>
  21. #include <sound/pcm.h>
  22. #include <sound/pcm_params.h>
  23. #include <sound/soc.h>
  24. #include <sound/initval.h>
  25. #include <sound/tlv.h>
  26. #include "wm8993.h"
  27. #include "wm_hubs.h"
  28. const DECLARE_TLV_DB_SCALE(wm_hubs_spkmix_tlv, -300, 300, 0);
  29. EXPORT_SYMBOL_GPL(wm_hubs_spkmix_tlv);
  30. static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1650, 150, 0);
  31. static const DECLARE_TLV_DB_SCALE(inmix_sw_tlv, 0, 3000, 0);
  32. static const DECLARE_TLV_DB_SCALE(inmix_tlv, -1500, 300, 1);
  33. static const DECLARE_TLV_DB_SCALE(earpiece_tlv, -600, 600, 0);
  34. static const DECLARE_TLV_DB_SCALE(outmix_tlv, -2100, 300, 0);
  35. static const DECLARE_TLV_DB_SCALE(spkmixout_tlv, -1800, 600, 1);
  36. static const DECLARE_TLV_DB_SCALE(outpga_tlv, -5700, 100, 0);
  37. static const DECLARE_TLV_DB_RANGE(spkboost_tlv,
  38. 0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
  39. 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0)
  40. );
  41. static const DECLARE_TLV_DB_SCALE(line_tlv, -600, 600, 0);
  42. static const char *speaker_ref_text[] = {
  43. "SPKVDD/2",
  44. "VMID",
  45. };
  46. static SOC_ENUM_SINGLE_DECL(speaker_ref,
  47. WM8993_SPEAKER_MIXER, 8, speaker_ref_text);
  48. static const char *speaker_mode_text[] = {
  49. "Class D",
  50. "Class AB",
  51. };
  52. static SOC_ENUM_SINGLE_DECL(speaker_mode,
  53. WM8993_SPKMIXR_ATTENUATION, 8, speaker_mode_text);
  54. static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op)
  55. {
  56. struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
  57. unsigned int reg;
  58. int count = 0;
  59. int timeout;
  60. unsigned int val;
  61. val = op | WM8993_DCS_ENA_CHAN_0 | WM8993_DCS_ENA_CHAN_1;
  62. /* Trigger the command */
  63. snd_soc_write(codec, WM8993_DC_SERVO_0, val);
  64. dev_dbg(codec->dev, "Waiting for DC servo...\n");
  65. if (hubs->dcs_done_irq)
  66. timeout = 4;
  67. else
  68. timeout = 400;
  69. do {
  70. count++;
  71. if (hubs->dcs_done_irq)
  72. wait_for_completion_timeout(&hubs->dcs_done,
  73. msecs_to_jiffies(250));
  74. else
  75. msleep(1);
  76. reg = snd_soc_read(codec, WM8993_DC_SERVO_0);
  77. dev_dbg(codec->dev, "DC servo: %x\n", reg);
  78. } while (reg & op && count < timeout);
  79. if (reg & op)
  80. dev_err(codec->dev, "Timed out waiting for DC Servo %x\n",
  81. op);
  82. }
  83. irqreturn_t wm_hubs_dcs_done(int irq, void *data)
  84. {
  85. struct wm_hubs_data *hubs = data;
  86. complete(&hubs->dcs_done);
  87. return IRQ_HANDLED;
  88. }
  89. EXPORT_SYMBOL_GPL(wm_hubs_dcs_done);
  90. static bool wm_hubs_dac_hp_direct(struct snd_soc_codec *codec)
  91. {
  92. int reg;
  93. /* If we're going via the mixer we'll need to do additional checks */
  94. reg = snd_soc_read(codec, WM8993_OUTPUT_MIXER1);
  95. if (!(reg & WM8993_DACL_TO_HPOUT1L)) {
  96. if (reg & ~WM8993_DACL_TO_MIXOUTL) {
  97. dev_vdbg(codec->dev, "Analogue paths connected: %x\n",
  98. reg & ~WM8993_DACL_TO_HPOUT1L);
  99. return false;
  100. } else {
  101. dev_vdbg(codec->dev, "HPL connected to mixer\n");
  102. }
  103. } else {
  104. dev_vdbg(codec->dev, "HPL connected to DAC\n");
  105. }
  106. reg = snd_soc_read(codec, WM8993_OUTPUT_MIXER2);
  107. if (!(reg & WM8993_DACR_TO_HPOUT1R)) {
  108. if (reg & ~WM8993_DACR_TO_MIXOUTR) {
  109. dev_vdbg(codec->dev, "Analogue paths connected: %x\n",
  110. reg & ~WM8993_DACR_TO_HPOUT1R);
  111. return false;
  112. } else {
  113. dev_vdbg(codec->dev, "HPR connected to mixer\n");
  114. }
  115. } else {
  116. dev_vdbg(codec->dev, "HPR connected to DAC\n");
  117. }
  118. return true;
  119. }
  120. struct wm_hubs_dcs_cache {
  121. struct list_head list;
  122. unsigned int left;
  123. unsigned int right;
  124. u16 dcs_cfg;
  125. };
  126. static bool wm_hubs_dcs_cache_get(struct snd_soc_codec *codec,
  127. struct wm_hubs_dcs_cache **entry)
  128. {
  129. struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
  130. struct wm_hubs_dcs_cache *cache;
  131. unsigned int left, right;
  132. left = snd_soc_read(codec, WM8993_LEFT_OUTPUT_VOLUME);
  133. left &= WM8993_HPOUT1L_VOL_MASK;
  134. right = snd_soc_read(codec, WM8993_RIGHT_OUTPUT_VOLUME);
  135. right &= WM8993_HPOUT1R_VOL_MASK;
  136. list_for_each_entry(cache, &hubs->dcs_cache, list) {
  137. if (cache->left != left || cache->right != right)
  138. continue;
  139. *entry = cache;
  140. return true;
  141. }
  142. return false;
  143. }
  144. static void wm_hubs_dcs_cache_set(struct snd_soc_codec *codec, u16 dcs_cfg)
  145. {
  146. struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
  147. struct wm_hubs_dcs_cache *cache;
  148. if (hubs->no_cache_dac_hp_direct)
  149. return;
  150. cache = devm_kzalloc(codec->dev, sizeof(*cache), GFP_KERNEL);
  151. if (!cache)
  152. return;
  153. cache->left = snd_soc_read(codec, WM8993_LEFT_OUTPUT_VOLUME);
  154. cache->left &= WM8993_HPOUT1L_VOL_MASK;
  155. cache->right = snd_soc_read(codec, WM8993_RIGHT_OUTPUT_VOLUME);
  156. cache->right &= WM8993_HPOUT1R_VOL_MASK;
  157. cache->dcs_cfg = dcs_cfg;
  158. list_add_tail(&cache->list, &hubs->dcs_cache);
  159. }
  160. static int wm_hubs_read_dc_servo(struct snd_soc_codec *codec,
  161. u16 *reg_l, u16 *reg_r)
  162. {
  163. struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
  164. u16 dcs_reg, reg;
  165. int ret = 0;
  166. switch (hubs->dcs_readback_mode) {
  167. case 2:
  168. dcs_reg = WM8994_DC_SERVO_4E;
  169. break;
  170. case 1:
  171. dcs_reg = WM8994_DC_SERVO_READBACK;
  172. break;
  173. default:
  174. dcs_reg = WM8993_DC_SERVO_3;
  175. break;
  176. }
  177. /* Different chips in the family support different readback
  178. * methods.
  179. */
  180. switch (hubs->dcs_readback_mode) {
  181. case 0:
  182. *reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1)
  183. & WM8993_DCS_INTEG_CHAN_0_MASK;
  184. *reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
  185. & WM8993_DCS_INTEG_CHAN_1_MASK;
  186. break;
  187. case 2:
  188. case 1:
  189. reg = snd_soc_read(codec, dcs_reg);
  190. *reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
  191. >> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
  192. *reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
  193. break;
  194. default:
  195. WARN(1, "Unknown DCS readback method\n");
  196. ret = -1;
  197. }
  198. return ret;
  199. }
  200. /*
  201. * Startup calibration of the DC servo
  202. */
  203. static void enable_dc_servo(struct snd_soc_codec *codec)
  204. {
  205. struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
  206. struct wm_hubs_dcs_cache *cache;
  207. s8 offset;
  208. u16 reg_l, reg_r, dcs_cfg, dcs_reg;
  209. switch (hubs->dcs_readback_mode) {
  210. case 2:
  211. dcs_reg = WM8994_DC_SERVO_4E;
  212. break;
  213. default:
  214. dcs_reg = WM8993_DC_SERVO_3;
  215. break;
  216. }
  217. /* If we're using a digital only path and have a previously
  218. * callibrated DC servo offset stored then use that. */
  219. if (wm_hubs_dac_hp_direct(codec) &&
  220. wm_hubs_dcs_cache_get(codec, &cache)) {
  221. dev_dbg(codec->dev, "Using cached DCS offset %x for %d,%d\n",
  222. cache->dcs_cfg, cache->left, cache->right);
  223. snd_soc_write(codec, dcs_reg, cache->dcs_cfg);
  224. wait_for_dc_servo(codec,
  225. WM8993_DCS_TRIG_DAC_WR_0 |
  226. WM8993_DCS_TRIG_DAC_WR_1);
  227. return;
  228. }
  229. if (hubs->series_startup) {
  230. /* Set for 32 series updates */
  231. snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
  232. WM8993_DCS_SERIES_NO_01_MASK,
  233. 32 << WM8993_DCS_SERIES_NO_01_SHIFT);
  234. wait_for_dc_servo(codec,
  235. WM8993_DCS_TRIG_SERIES_0 |
  236. WM8993_DCS_TRIG_SERIES_1);
  237. } else {
  238. wait_for_dc_servo(codec,
  239. WM8993_DCS_TRIG_STARTUP_0 |
  240. WM8993_DCS_TRIG_STARTUP_1);
  241. }
  242. if (wm_hubs_read_dc_servo(codec, &reg_l, &reg_r) < 0)
  243. return;
  244. dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
  245. /* Apply correction to DC servo result */
  246. if (hubs->dcs_codes_l || hubs->dcs_codes_r) {
  247. dev_dbg(codec->dev,
  248. "Applying %d/%d code DC servo correction\n",
  249. hubs->dcs_codes_l, hubs->dcs_codes_r);
  250. /* HPOUT1R */
  251. offset = (s8)reg_r;
  252. dev_dbg(codec->dev, "DCS right %d->%d\n", offset,
  253. offset + hubs->dcs_codes_r);
  254. offset += hubs->dcs_codes_r;
  255. dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
  256. /* HPOUT1L */
  257. offset = (s8)reg_l;
  258. dev_dbg(codec->dev, "DCS left %d->%d\n", offset,
  259. offset + hubs->dcs_codes_l);
  260. offset += hubs->dcs_codes_l;
  261. dcs_cfg |= (u8)offset;
  262. dev_dbg(codec->dev, "DCS result: %x\n", dcs_cfg);
  263. /* Do it */
  264. snd_soc_write(codec, dcs_reg, dcs_cfg);
  265. wait_for_dc_servo(codec,
  266. WM8993_DCS_TRIG_DAC_WR_0 |
  267. WM8993_DCS_TRIG_DAC_WR_1);
  268. } else {
  269. dcs_cfg = reg_r << WM8993_DCS_DAC_WR_VAL_1_SHIFT;
  270. dcs_cfg |= reg_l;
  271. }
  272. /* Save the callibrated offset if we're in class W mode and
  273. * therefore don't have any analogue signal mixed in. */
  274. if (wm_hubs_dac_hp_direct(codec))
  275. wm_hubs_dcs_cache_set(codec, dcs_cfg);
  276. }
  277. /*
  278. * Update the DC servo calibration on gain changes
  279. */
  280. static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
  281. struct snd_ctl_elem_value *ucontrol)
  282. {
  283. struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
  284. struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
  285. int ret;
  286. ret = snd_soc_put_volsw(kcontrol, ucontrol);
  287. /* If we're applying an offset correction then updating the
  288. * callibration would be likely to introduce further offsets. */
  289. if (hubs->dcs_codes_l || hubs->dcs_codes_r || hubs->no_series_update)
  290. return ret;
  291. /* Only need to do this if the outputs are active */
  292. if (snd_soc_read(codec, WM8993_POWER_MANAGEMENT_1)
  293. & (WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA))
  294. snd_soc_update_bits(codec,
  295. WM8993_DC_SERVO_0,
  296. WM8993_DCS_TRIG_SINGLE_0 |
  297. WM8993_DCS_TRIG_SINGLE_1,
  298. WM8993_DCS_TRIG_SINGLE_0 |
  299. WM8993_DCS_TRIG_SINGLE_1);
  300. return ret;
  301. }
  302. static const struct snd_kcontrol_new analogue_snd_controls[] = {
  303. SOC_SINGLE_TLV("IN1L Volume", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 0, 31, 0,
  304. inpga_tlv),
  305. SOC_SINGLE("IN1L Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 7, 1, 1),
  306. SOC_SINGLE("IN1L ZC Switch", WM8993_LEFT_LINE_INPUT_1_2_VOLUME, 6, 1, 0),
  307. SOC_SINGLE_TLV("IN1R Volume", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 0, 31, 0,
  308. inpga_tlv),
  309. SOC_SINGLE("IN1R Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 7, 1, 1),
  310. SOC_SINGLE("IN1R ZC Switch", WM8993_RIGHT_LINE_INPUT_1_2_VOLUME, 6, 1, 0),
  311. SOC_SINGLE_TLV("IN2L Volume", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 0, 31, 0,
  312. inpga_tlv),
  313. SOC_SINGLE("IN2L Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 7, 1, 1),
  314. SOC_SINGLE("IN2L ZC Switch", WM8993_LEFT_LINE_INPUT_3_4_VOLUME, 6, 1, 0),
  315. SOC_SINGLE_TLV("IN2R Volume", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 0, 31, 0,
  316. inpga_tlv),
  317. SOC_SINGLE("IN2R Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 7, 1, 1),
  318. SOC_SINGLE("IN2R ZC Switch", WM8993_RIGHT_LINE_INPUT_3_4_VOLUME, 6, 1, 0),
  319. SOC_SINGLE_TLV("MIXINL IN2L Volume", WM8993_INPUT_MIXER3, 7, 1, 0,
  320. inmix_sw_tlv),
  321. SOC_SINGLE_TLV("MIXINL IN1L Volume", WM8993_INPUT_MIXER3, 4, 1, 0,
  322. inmix_sw_tlv),
  323. SOC_SINGLE_TLV("MIXINL Output Record Volume", WM8993_INPUT_MIXER3, 0, 7, 0,
  324. inmix_tlv),
  325. SOC_SINGLE_TLV("MIXINL IN1LP Volume", WM8993_INPUT_MIXER5, 6, 7, 0, inmix_tlv),
  326. SOC_SINGLE_TLV("MIXINL Direct Voice Volume", WM8993_INPUT_MIXER5, 0, 6, 0,
  327. inmix_tlv),
  328. SOC_SINGLE_TLV("MIXINR IN2R Volume", WM8993_INPUT_MIXER4, 7, 1, 0,
  329. inmix_sw_tlv),
  330. SOC_SINGLE_TLV("MIXINR IN1R Volume", WM8993_INPUT_MIXER4, 4, 1, 0,
  331. inmix_sw_tlv),
  332. SOC_SINGLE_TLV("MIXINR Output Record Volume", WM8993_INPUT_MIXER4, 0, 7, 0,
  333. inmix_tlv),
  334. SOC_SINGLE_TLV("MIXINR IN1RP Volume", WM8993_INPUT_MIXER6, 6, 7, 0, inmix_tlv),
  335. SOC_SINGLE_TLV("MIXINR Direct Voice Volume", WM8993_INPUT_MIXER6, 0, 6, 0,
  336. inmix_tlv),
  337. SOC_SINGLE_TLV("Left Output Mixer IN2RN Volume", WM8993_OUTPUT_MIXER5, 6, 7, 1,
  338. outmix_tlv),
  339. SOC_SINGLE_TLV("Left Output Mixer IN2LN Volume", WM8993_OUTPUT_MIXER3, 6, 7, 1,
  340. outmix_tlv),
  341. SOC_SINGLE_TLV("Left Output Mixer IN2LP Volume", WM8993_OUTPUT_MIXER3, 9, 7, 1,
  342. outmix_tlv),
  343. SOC_SINGLE_TLV("Left Output Mixer IN1L Volume", WM8993_OUTPUT_MIXER3, 0, 7, 1,
  344. outmix_tlv),
  345. SOC_SINGLE_TLV("Left Output Mixer IN1R Volume", WM8993_OUTPUT_MIXER3, 3, 7, 1,
  346. outmix_tlv),
  347. SOC_SINGLE_TLV("Left Output Mixer Right Input Volume",
  348. WM8993_OUTPUT_MIXER5, 3, 7, 1, outmix_tlv),
  349. SOC_SINGLE_TLV("Left Output Mixer Left Input Volume",
  350. WM8993_OUTPUT_MIXER5, 0, 7, 1, outmix_tlv),
  351. SOC_SINGLE_TLV("Left Output Mixer DAC Volume", WM8993_OUTPUT_MIXER5, 9, 7, 1,
  352. outmix_tlv),
  353. SOC_SINGLE_TLV("Right Output Mixer IN2LN Volume",
  354. WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv),
  355. SOC_SINGLE_TLV("Right Output Mixer IN2RN Volume",
  356. WM8993_OUTPUT_MIXER4, 6, 7, 1, outmix_tlv),
  357. SOC_SINGLE_TLV("Right Output Mixer IN1L Volume",
  358. WM8993_OUTPUT_MIXER4, 3, 7, 1, outmix_tlv),
  359. SOC_SINGLE_TLV("Right Output Mixer IN1R Volume",
  360. WM8993_OUTPUT_MIXER4, 0, 7, 1, outmix_tlv),
  361. SOC_SINGLE_TLV("Right Output Mixer IN2RP Volume",
  362. WM8993_OUTPUT_MIXER4, 9, 7, 1, outmix_tlv),
  363. SOC_SINGLE_TLV("Right Output Mixer Left Input Volume",
  364. WM8993_OUTPUT_MIXER6, 3, 7, 1, outmix_tlv),
  365. SOC_SINGLE_TLV("Right Output Mixer Right Input Volume",
  366. WM8993_OUTPUT_MIXER6, 6, 7, 1, outmix_tlv),
  367. SOC_SINGLE_TLV("Right Output Mixer DAC Volume",
  368. WM8993_OUTPUT_MIXER6, 9, 7, 1, outmix_tlv),
  369. SOC_DOUBLE_R_TLV("Output Volume", WM8993_LEFT_OPGA_VOLUME,
  370. WM8993_RIGHT_OPGA_VOLUME, 0, 63, 0, outpga_tlv),
  371. SOC_DOUBLE_R("Output Switch", WM8993_LEFT_OPGA_VOLUME,
  372. WM8993_RIGHT_OPGA_VOLUME, 6, 1, 0),
  373. SOC_DOUBLE_R("Output ZC Switch", WM8993_LEFT_OPGA_VOLUME,
  374. WM8993_RIGHT_OPGA_VOLUME, 7, 1, 0),
  375. SOC_SINGLE("Earpiece Switch", WM8993_HPOUT2_VOLUME, 5, 1, 1),
  376. SOC_SINGLE_TLV("Earpiece Volume", WM8993_HPOUT2_VOLUME, 4, 1, 1, earpiece_tlv),
  377. SOC_SINGLE_TLV("SPKL Input Volume", WM8993_SPKMIXL_ATTENUATION,
  378. 5, 1, 1, wm_hubs_spkmix_tlv),
  379. SOC_SINGLE_TLV("SPKL IN1LP Volume", WM8993_SPKMIXL_ATTENUATION,
  380. 4, 1, 1, wm_hubs_spkmix_tlv),
  381. SOC_SINGLE_TLV("SPKL Output Volume", WM8993_SPKMIXL_ATTENUATION,
  382. 3, 1, 1, wm_hubs_spkmix_tlv),
  383. SOC_SINGLE_TLV("SPKR Input Volume", WM8993_SPKMIXR_ATTENUATION,
  384. 5, 1, 1, wm_hubs_spkmix_tlv),
  385. SOC_SINGLE_TLV("SPKR IN1RP Volume", WM8993_SPKMIXR_ATTENUATION,
  386. 4, 1, 1, wm_hubs_spkmix_tlv),
  387. SOC_SINGLE_TLV("SPKR Output Volume", WM8993_SPKMIXR_ATTENUATION,
  388. 3, 1, 1, wm_hubs_spkmix_tlv),
  389. SOC_DOUBLE_R_TLV("Speaker Mixer Volume",
  390. WM8993_SPKMIXL_ATTENUATION, WM8993_SPKMIXR_ATTENUATION,
  391. 0, 3, 1, spkmixout_tlv),
  392. SOC_DOUBLE_R_TLV("Speaker Volume",
  393. WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
  394. 0, 63, 0, outpga_tlv),
  395. SOC_DOUBLE_R("Speaker Switch",
  396. WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
  397. 6, 1, 0),
  398. SOC_DOUBLE_R("Speaker ZC Switch",
  399. WM8993_SPEAKER_VOLUME_LEFT, WM8993_SPEAKER_VOLUME_RIGHT,
  400. 7, 1, 0),
  401. SOC_DOUBLE_TLV("Speaker Boost Volume", WM8993_SPKOUT_BOOST, 3, 0, 7, 0,
  402. spkboost_tlv),
  403. SOC_ENUM("Speaker Reference", speaker_ref),
  404. SOC_ENUM("Speaker Mode", speaker_mode),
  405. SOC_DOUBLE_R_EXT_TLV("Headphone Volume",
  406. WM8993_LEFT_OUTPUT_VOLUME, WM8993_RIGHT_OUTPUT_VOLUME,
  407. 0, 63, 0, snd_soc_get_volsw, wm8993_put_dc_servo,
  408. outpga_tlv),
  409. SOC_DOUBLE_R("Headphone Switch", WM8993_LEFT_OUTPUT_VOLUME,
  410. WM8993_RIGHT_OUTPUT_VOLUME, 6, 1, 0),
  411. SOC_DOUBLE_R("Headphone ZC Switch", WM8993_LEFT_OUTPUT_VOLUME,
  412. WM8993_RIGHT_OUTPUT_VOLUME, 7, 1, 0),
  413. SOC_SINGLE("LINEOUT1N Switch", WM8993_LINE_OUTPUTS_VOLUME, 6, 1, 1),
  414. SOC_SINGLE("LINEOUT1P Switch", WM8993_LINE_OUTPUTS_VOLUME, 5, 1, 1),
  415. SOC_SINGLE_TLV("LINEOUT1 Volume", WM8993_LINE_OUTPUTS_VOLUME, 4, 1, 1,
  416. line_tlv),
  417. SOC_SINGLE("LINEOUT2N Switch", WM8993_LINE_OUTPUTS_VOLUME, 2, 1, 1),
  418. SOC_SINGLE("LINEOUT2P Switch", WM8993_LINE_OUTPUTS_VOLUME, 1, 1, 1),
  419. SOC_SINGLE_TLV("LINEOUT2 Volume", WM8993_LINE_OUTPUTS_VOLUME, 0, 1, 1,
  420. line_tlv),
  421. };
  422. static int hp_supply_event(struct snd_soc_dapm_widget *w,
  423. struct snd_kcontrol *kcontrol, int event)
  424. {
  425. struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
  426. struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
  427. switch (event) {
  428. case SND_SOC_DAPM_PRE_PMU:
  429. switch (hubs->hp_startup_mode) {
  430. case 0:
  431. break;
  432. case 1:
  433. /* Enable the headphone amp */
  434. snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
  435. WM8993_HPOUT1L_ENA |
  436. WM8993_HPOUT1R_ENA,
  437. WM8993_HPOUT1L_ENA |
  438. WM8993_HPOUT1R_ENA);
  439. /* Enable the second stage */
  440. snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
  441. WM8993_HPOUT1L_DLY |
  442. WM8993_HPOUT1R_DLY,
  443. WM8993_HPOUT1L_DLY |
  444. WM8993_HPOUT1R_DLY);
  445. break;
  446. default:
  447. dev_err(codec->dev, "Unknown HP startup mode %d\n",
  448. hubs->hp_startup_mode);
  449. break;
  450. }
  451. break;
  452. case SND_SOC_DAPM_PRE_PMD:
  453. snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1,
  454. WM8993_CP_ENA, 0);
  455. break;
  456. }
  457. return 0;
  458. }
  459. static int hp_event(struct snd_soc_dapm_widget *w,
  460. struct snd_kcontrol *kcontrol, int event)
  461. {
  462. struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
  463. unsigned int reg = snd_soc_read(codec, WM8993_ANALOGUE_HP_0);
  464. switch (event) {
  465. case SND_SOC_DAPM_POST_PMU:
  466. snd_soc_update_bits(codec, WM8993_CHARGE_PUMP_1,
  467. WM8993_CP_ENA, WM8993_CP_ENA);
  468. msleep(5);
  469. snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
  470. WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
  471. WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA);
  472. reg |= WM8993_HPOUT1L_DLY | WM8993_HPOUT1R_DLY;
  473. snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg);
  474. snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
  475. WM8993_DCS_TIMER_PERIOD_01_MASK, 0);
  476. enable_dc_servo(codec);
  477. reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT |
  478. WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT;
  479. snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg);
  480. break;
  481. case SND_SOC_DAPM_PRE_PMD:
  482. snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
  483. WM8993_HPOUT1L_OUTP |
  484. WM8993_HPOUT1R_OUTP |
  485. WM8993_HPOUT1L_RMV_SHORT |
  486. WM8993_HPOUT1R_RMV_SHORT, 0);
  487. snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
  488. WM8993_HPOUT1L_DLY |
  489. WM8993_HPOUT1R_DLY, 0);
  490. snd_soc_write(codec, WM8993_DC_SERVO_0, 0);
  491. snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
  492. WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
  493. 0);
  494. break;
  495. }
  496. return 0;
  497. }
  498. static int earpiece_event(struct snd_soc_dapm_widget *w,
  499. struct snd_kcontrol *control, int event)
  500. {
  501. struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
  502. u16 reg = snd_soc_read(codec, WM8993_ANTIPOP1) & ~WM8993_HPOUT2_IN_ENA;
  503. switch (event) {
  504. case SND_SOC_DAPM_PRE_PMU:
  505. reg |= WM8993_HPOUT2_IN_ENA;
  506. snd_soc_write(codec, WM8993_ANTIPOP1, reg);
  507. udelay(50);
  508. break;
  509. case SND_SOC_DAPM_POST_PMD:
  510. snd_soc_write(codec, WM8993_ANTIPOP1, reg);
  511. break;
  512. default:
  513. WARN(1, "Invalid event %d\n", event);
  514. break;
  515. }
  516. return 0;
  517. }
  518. static int lineout_event(struct snd_soc_dapm_widget *w,
  519. struct snd_kcontrol *control, int event)
  520. {
  521. struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
  522. struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
  523. bool *flag;
  524. switch (w->shift) {
  525. case WM8993_LINEOUT1N_ENA_SHIFT:
  526. flag = &hubs->lineout1n_ena;
  527. break;
  528. case WM8993_LINEOUT1P_ENA_SHIFT:
  529. flag = &hubs->lineout1p_ena;
  530. break;
  531. case WM8993_LINEOUT2N_ENA_SHIFT:
  532. flag = &hubs->lineout2n_ena;
  533. break;
  534. case WM8993_LINEOUT2P_ENA_SHIFT:
  535. flag = &hubs->lineout2p_ena;
  536. break;
  537. default:
  538. WARN(1, "Unknown line output");
  539. return -EINVAL;
  540. }
  541. *flag = SND_SOC_DAPM_EVENT_ON(event);
  542. return 0;
  543. }
  544. static int micbias_event(struct snd_soc_dapm_widget *w,
  545. struct snd_kcontrol *kcontrol, int event)
  546. {
  547. struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
  548. struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
  549. switch (w->shift) {
  550. case WM8993_MICB1_ENA_SHIFT:
  551. if (hubs->micb1_delay)
  552. msleep(hubs->micb1_delay);
  553. break;
  554. case WM8993_MICB2_ENA_SHIFT:
  555. if (hubs->micb2_delay)
  556. msleep(hubs->micb2_delay);
  557. break;
  558. default:
  559. return -EINVAL;
  560. }
  561. return 0;
  562. }
  563. void wm_hubs_update_class_w(struct snd_soc_codec *codec)
  564. {
  565. struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
  566. int enable = WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ;
  567. if (!wm_hubs_dac_hp_direct(codec))
  568. enable = false;
  569. if (hubs->check_class_w_digital && !hubs->check_class_w_digital(codec))
  570. enable = false;
  571. dev_vdbg(codec->dev, "Class W %s\n", enable ? "enabled" : "disabled");
  572. snd_soc_update_bits(codec, WM8993_CLASS_W_0,
  573. WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ, enable);
  574. snd_soc_write(codec, WM8993_LEFT_OUTPUT_VOLUME,
  575. snd_soc_read(codec, WM8993_LEFT_OUTPUT_VOLUME));
  576. snd_soc_write(codec, WM8993_RIGHT_OUTPUT_VOLUME,
  577. snd_soc_read(codec, WM8993_RIGHT_OUTPUT_VOLUME));
  578. }
  579. EXPORT_SYMBOL_GPL(wm_hubs_update_class_w);
  580. #define WM_HUBS_SINGLE_W(xname, reg, shift, max, invert) \
  581. SOC_SINGLE_EXT(xname, reg, shift, max, invert, \
  582. snd_soc_dapm_get_volsw, class_w_put_volsw)
  583. static int class_w_put_volsw(struct snd_kcontrol *kcontrol,
  584. struct snd_ctl_elem_value *ucontrol)
  585. {
  586. struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
  587. int ret;
  588. ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
  589. wm_hubs_update_class_w(codec);
  590. return ret;
  591. }
  592. #define WM_HUBS_ENUM_W(xname, xenum) \
  593. { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
  594. .info = snd_soc_info_enum_double, \
  595. .get = snd_soc_dapm_get_enum_double, \
  596. .put = class_w_put_double, \
  597. .private_value = (unsigned long)&xenum }
  598. static int class_w_put_double(struct snd_kcontrol *kcontrol,
  599. struct snd_ctl_elem_value *ucontrol)
  600. {
  601. struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
  602. int ret;
  603. ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
  604. wm_hubs_update_class_w(codec);
  605. return ret;
  606. }
  607. static const char *hp_mux_text[] = {
  608. "Mixer",
  609. "DAC",
  610. };
  611. static SOC_ENUM_SINGLE_DECL(hpl_enum,
  612. WM8993_OUTPUT_MIXER1, 8, hp_mux_text);
  613. const struct snd_kcontrol_new wm_hubs_hpl_mux =
  614. WM_HUBS_ENUM_W("Left Headphone Mux", hpl_enum);
  615. EXPORT_SYMBOL_GPL(wm_hubs_hpl_mux);
  616. static SOC_ENUM_SINGLE_DECL(hpr_enum,
  617. WM8993_OUTPUT_MIXER2, 8, hp_mux_text);
  618. const struct snd_kcontrol_new wm_hubs_hpr_mux =
  619. WM_HUBS_ENUM_W("Right Headphone Mux", hpr_enum);
  620. EXPORT_SYMBOL_GPL(wm_hubs_hpr_mux);
  621. static const struct snd_kcontrol_new in1l_pga[] = {
  622. SOC_DAPM_SINGLE("IN1LP Switch", WM8993_INPUT_MIXER2, 5, 1, 0),
  623. SOC_DAPM_SINGLE("IN1LN Switch", WM8993_INPUT_MIXER2, 4, 1, 0),
  624. };
  625. static const struct snd_kcontrol_new in1r_pga[] = {
  626. SOC_DAPM_SINGLE("IN1RP Switch", WM8993_INPUT_MIXER2, 1, 1, 0),
  627. SOC_DAPM_SINGLE("IN1RN Switch", WM8993_INPUT_MIXER2, 0, 1, 0),
  628. };
  629. static const struct snd_kcontrol_new in2l_pga[] = {
  630. SOC_DAPM_SINGLE("IN2LP Switch", WM8993_INPUT_MIXER2, 7, 1, 0),
  631. SOC_DAPM_SINGLE("IN2LN Switch", WM8993_INPUT_MIXER2, 6, 1, 0),
  632. };
  633. static const struct snd_kcontrol_new in2r_pga[] = {
  634. SOC_DAPM_SINGLE("IN2RP Switch", WM8993_INPUT_MIXER2, 3, 1, 0),
  635. SOC_DAPM_SINGLE("IN2RN Switch", WM8993_INPUT_MIXER2, 2, 1, 0),
  636. };
  637. static const struct snd_kcontrol_new mixinl[] = {
  638. SOC_DAPM_SINGLE("IN2L Switch", WM8993_INPUT_MIXER3, 8, 1, 0),
  639. SOC_DAPM_SINGLE("IN1L Switch", WM8993_INPUT_MIXER3, 5, 1, 0),
  640. };
  641. static const struct snd_kcontrol_new mixinr[] = {
  642. SOC_DAPM_SINGLE("IN2R Switch", WM8993_INPUT_MIXER4, 8, 1, 0),
  643. SOC_DAPM_SINGLE("IN1R Switch", WM8993_INPUT_MIXER4, 5, 1, 0),
  644. };
  645. static const struct snd_kcontrol_new left_output_mixer[] = {
  646. WM_HUBS_SINGLE_W("Right Input Switch", WM8993_OUTPUT_MIXER1, 7, 1, 0),
  647. WM_HUBS_SINGLE_W("Left Input Switch", WM8993_OUTPUT_MIXER1, 6, 1, 0),
  648. WM_HUBS_SINGLE_W("IN2RN Switch", WM8993_OUTPUT_MIXER1, 5, 1, 0),
  649. WM_HUBS_SINGLE_W("IN2LN Switch", WM8993_OUTPUT_MIXER1, 4, 1, 0),
  650. WM_HUBS_SINGLE_W("IN2LP Switch", WM8993_OUTPUT_MIXER1, 1, 1, 0),
  651. WM_HUBS_SINGLE_W("IN1R Switch", WM8993_OUTPUT_MIXER1, 3, 1, 0),
  652. WM_HUBS_SINGLE_W("IN1L Switch", WM8993_OUTPUT_MIXER1, 2, 1, 0),
  653. WM_HUBS_SINGLE_W("DAC Switch", WM8993_OUTPUT_MIXER1, 0, 1, 0),
  654. };
  655. static const struct snd_kcontrol_new right_output_mixer[] = {
  656. WM_HUBS_SINGLE_W("Left Input Switch", WM8993_OUTPUT_MIXER2, 7, 1, 0),
  657. WM_HUBS_SINGLE_W("Right Input Switch", WM8993_OUTPUT_MIXER2, 6, 1, 0),
  658. WM_HUBS_SINGLE_W("IN2LN Switch", WM8993_OUTPUT_MIXER2, 5, 1, 0),
  659. WM_HUBS_SINGLE_W("IN2RN Switch", WM8993_OUTPUT_MIXER2, 4, 1, 0),
  660. WM_HUBS_SINGLE_W("IN1L Switch", WM8993_OUTPUT_MIXER2, 3, 1, 0),
  661. WM_HUBS_SINGLE_W("IN1R Switch", WM8993_OUTPUT_MIXER2, 2, 1, 0),
  662. WM_HUBS_SINGLE_W("IN2RP Switch", WM8993_OUTPUT_MIXER2, 1, 1, 0),
  663. WM_HUBS_SINGLE_W("DAC Switch", WM8993_OUTPUT_MIXER2, 0, 1, 0),
  664. };
  665. static const struct snd_kcontrol_new earpiece_mixer[] = {
  666. SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_HPOUT2_MIXER, 5, 1, 0),
  667. SOC_DAPM_SINGLE("Left Output Switch", WM8993_HPOUT2_MIXER, 4, 1, 0),
  668. SOC_DAPM_SINGLE("Right Output Switch", WM8993_HPOUT2_MIXER, 3, 1, 0),
  669. };
  670. static const struct snd_kcontrol_new left_speaker_boost[] = {
  671. SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 5, 1, 0),
  672. SOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 4, 1, 0),
  673. SOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 3, 1, 0),
  674. };
  675. static const struct snd_kcontrol_new right_speaker_boost[] = {
  676. SOC_DAPM_SINGLE("Direct Voice Switch", WM8993_SPKOUT_MIXERS, 2, 1, 0),
  677. SOC_DAPM_SINGLE("SPKL Switch", WM8993_SPKOUT_MIXERS, 1, 1, 0),
  678. SOC_DAPM_SINGLE("SPKR Switch", WM8993_SPKOUT_MIXERS, 0, 1, 0),
  679. };
  680. static const struct snd_kcontrol_new line1_mix[] = {
  681. SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER1, 2, 1, 0),
  682. SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER1, 1, 1, 0),
  683. SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER1, 0, 1, 0),
  684. };
  685. static const struct snd_kcontrol_new line1n_mix[] = {
  686. SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 6, 1, 0),
  687. SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER1, 5, 1, 0),
  688. };
  689. static const struct snd_kcontrol_new line1p_mix[] = {
  690. SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 0, 1, 0),
  691. };
  692. static const struct snd_kcontrol_new line2_mix[] = {
  693. SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER2, 2, 1, 0),
  694. SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER2, 1, 1, 0),
  695. SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER2, 0, 1, 0),
  696. };
  697. static const struct snd_kcontrol_new line2n_mix[] = {
  698. SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 5, 1, 0),
  699. SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 6, 1, 0),
  700. };
  701. static const struct snd_kcontrol_new line2p_mix[] = {
  702. SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 0, 1, 0),
  703. };
  704. static const struct snd_soc_dapm_widget analogue_dapm_widgets[] = {
  705. SND_SOC_DAPM_INPUT("IN1LN"),
  706. SND_SOC_DAPM_INPUT("IN1LP"),
  707. SND_SOC_DAPM_INPUT("IN2LN"),
  708. SND_SOC_DAPM_INPUT("IN2LP:VXRN"),
  709. SND_SOC_DAPM_INPUT("IN1RN"),
  710. SND_SOC_DAPM_INPUT("IN1RP"),
  711. SND_SOC_DAPM_INPUT("IN2RN"),
  712. SND_SOC_DAPM_INPUT("IN2RP:VXRP"),
  713. SND_SOC_DAPM_SUPPLY("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0,
  714. micbias_event, SND_SOC_DAPM_POST_PMU),
  715. SND_SOC_DAPM_SUPPLY("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0,
  716. micbias_event, SND_SOC_DAPM_POST_PMU),
  717. SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0,
  718. in1l_pga, ARRAY_SIZE(in1l_pga)),
  719. SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0,
  720. in1r_pga, ARRAY_SIZE(in1r_pga)),
  721. SND_SOC_DAPM_MIXER("IN2L PGA", WM8993_POWER_MANAGEMENT_2, 7, 0,
  722. in2l_pga, ARRAY_SIZE(in2l_pga)),
  723. SND_SOC_DAPM_MIXER("IN2R PGA", WM8993_POWER_MANAGEMENT_2, 5, 0,
  724. in2r_pga, ARRAY_SIZE(in2r_pga)),
  725. SND_SOC_DAPM_MIXER("MIXINL", WM8993_POWER_MANAGEMENT_2, 9, 0,
  726. mixinl, ARRAY_SIZE(mixinl)),
  727. SND_SOC_DAPM_MIXER("MIXINR", WM8993_POWER_MANAGEMENT_2, 8, 0,
  728. mixinr, ARRAY_SIZE(mixinr)),
  729. SND_SOC_DAPM_MIXER("Left Output Mixer", WM8993_POWER_MANAGEMENT_3, 5, 0,
  730. left_output_mixer, ARRAY_SIZE(left_output_mixer)),
  731. SND_SOC_DAPM_MIXER("Right Output Mixer", WM8993_POWER_MANAGEMENT_3, 4, 0,
  732. right_output_mixer, ARRAY_SIZE(right_output_mixer)),
  733. SND_SOC_DAPM_PGA("Left Output PGA", WM8993_POWER_MANAGEMENT_3, 7, 0, NULL, 0),
  734. SND_SOC_DAPM_PGA("Right Output PGA", WM8993_POWER_MANAGEMENT_3, 6, 0, NULL, 0),
  735. SND_SOC_DAPM_SUPPLY("Headphone Supply", SND_SOC_NOPM, 0, 0, hp_supply_event,
  736. SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
  737. SND_SOC_DAPM_OUT_DRV_E("Headphone PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
  738. hp_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
  739. SND_SOC_DAPM_MIXER("Earpiece Mixer", SND_SOC_NOPM, 0, 0,
  740. earpiece_mixer, ARRAY_SIZE(earpiece_mixer)),
  741. SND_SOC_DAPM_PGA_E("Earpiece Driver", WM8993_POWER_MANAGEMENT_1, 11, 0,
  742. NULL, 0, earpiece_event,
  743. SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
  744. SND_SOC_DAPM_MIXER("SPKL Boost", SND_SOC_NOPM, 0, 0,
  745. left_speaker_boost, ARRAY_SIZE(left_speaker_boost)),
  746. SND_SOC_DAPM_MIXER("SPKR Boost", SND_SOC_NOPM, 0, 0,
  747. right_speaker_boost, ARRAY_SIZE(right_speaker_boost)),
  748. SND_SOC_DAPM_SUPPLY("TSHUT", WM8993_POWER_MANAGEMENT_2, 14, 0, NULL, 0),
  749. SND_SOC_DAPM_OUT_DRV("SPKL Driver", WM8993_POWER_MANAGEMENT_1, 12, 0,
  750. NULL, 0),
  751. SND_SOC_DAPM_OUT_DRV("SPKR Driver", WM8993_POWER_MANAGEMENT_1, 13, 0,
  752. NULL, 0),
  753. SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0,
  754. line1_mix, ARRAY_SIZE(line1_mix)),
  755. SND_SOC_DAPM_MIXER("LINEOUT2 Mixer", SND_SOC_NOPM, 0, 0,
  756. line2_mix, ARRAY_SIZE(line2_mix)),
  757. SND_SOC_DAPM_MIXER("LINEOUT1N Mixer", SND_SOC_NOPM, 0, 0,
  758. line1n_mix, ARRAY_SIZE(line1n_mix)),
  759. SND_SOC_DAPM_MIXER("LINEOUT1P Mixer", SND_SOC_NOPM, 0, 0,
  760. line1p_mix, ARRAY_SIZE(line1p_mix)),
  761. SND_SOC_DAPM_MIXER("LINEOUT2N Mixer", SND_SOC_NOPM, 0, 0,
  762. line2n_mix, ARRAY_SIZE(line2n_mix)),
  763. SND_SOC_DAPM_MIXER("LINEOUT2P Mixer", SND_SOC_NOPM, 0, 0,
  764. line2p_mix, ARRAY_SIZE(line2p_mix)),
  765. SND_SOC_DAPM_OUT_DRV_E("LINEOUT1N Driver", WM8993_POWER_MANAGEMENT_3, 13, 0,
  766. NULL, 0, lineout_event,
  767. SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
  768. SND_SOC_DAPM_OUT_DRV_E("LINEOUT1P Driver", WM8993_POWER_MANAGEMENT_3, 12, 0,
  769. NULL, 0, lineout_event,
  770. SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
  771. SND_SOC_DAPM_OUT_DRV_E("LINEOUT2N Driver", WM8993_POWER_MANAGEMENT_3, 11, 0,
  772. NULL, 0, lineout_event,
  773. SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
  774. SND_SOC_DAPM_OUT_DRV_E("LINEOUT2P Driver", WM8993_POWER_MANAGEMENT_3, 10, 0,
  775. NULL, 0, lineout_event,
  776. SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
  777. SND_SOC_DAPM_OUTPUT("SPKOUTLP"),
  778. SND_SOC_DAPM_OUTPUT("SPKOUTLN"),
  779. SND_SOC_DAPM_OUTPUT("SPKOUTRP"),
  780. SND_SOC_DAPM_OUTPUT("SPKOUTRN"),
  781. SND_SOC_DAPM_OUTPUT("HPOUT1L"),
  782. SND_SOC_DAPM_OUTPUT("HPOUT1R"),
  783. SND_SOC_DAPM_OUTPUT("HPOUT2P"),
  784. SND_SOC_DAPM_OUTPUT("HPOUT2N"),
  785. SND_SOC_DAPM_OUTPUT("LINEOUT1P"),
  786. SND_SOC_DAPM_OUTPUT("LINEOUT1N"),
  787. SND_SOC_DAPM_OUTPUT("LINEOUT2P"),
  788. SND_SOC_DAPM_OUTPUT("LINEOUT2N"),
  789. };
  790. static const struct snd_soc_dapm_route analogue_routes[] = {
  791. { "MICBIAS1", NULL, "CLK_SYS" },
  792. { "MICBIAS2", NULL, "CLK_SYS" },
  793. { "IN1L PGA", "IN1LP Switch", "IN1LP" },
  794. { "IN1L PGA", "IN1LN Switch", "IN1LN" },
  795. { "IN1L PGA", NULL, "VMID" },
  796. { "IN1R PGA", NULL, "VMID" },
  797. { "IN2L PGA", NULL, "VMID" },
  798. { "IN2R PGA", NULL, "VMID" },
  799. { "IN1R PGA", "IN1RP Switch", "IN1RP" },
  800. { "IN1R PGA", "IN1RN Switch", "IN1RN" },
  801. { "IN2L PGA", "IN2LP Switch", "IN2LP:VXRN" },
  802. { "IN2L PGA", "IN2LN Switch", "IN2LN" },
  803. { "IN2R PGA", "IN2RP Switch", "IN2RP:VXRP" },
  804. { "IN2R PGA", "IN2RN Switch", "IN2RN" },
  805. { "Direct Voice", NULL, "IN2LP:VXRN" },
  806. { "Direct Voice", NULL, "IN2RP:VXRP" },
  807. { "MIXINL", "IN1L Switch", "IN1L PGA" },
  808. { "MIXINL", "IN2L Switch", "IN2L PGA" },
  809. { "MIXINL", NULL, "Direct Voice" },
  810. { "MIXINL", NULL, "IN1LP" },
  811. { "MIXINL", NULL, "Left Output Mixer" },
  812. { "MIXINL", NULL, "VMID" },
  813. { "MIXINR", "IN1R Switch", "IN1R PGA" },
  814. { "MIXINR", "IN2R Switch", "IN2R PGA" },
  815. { "MIXINR", NULL, "Direct Voice" },
  816. { "MIXINR", NULL, "IN1RP" },
  817. { "MIXINR", NULL, "Right Output Mixer" },
  818. { "MIXINR", NULL, "VMID" },
  819. { "ADCL", NULL, "MIXINL" },
  820. { "ADCR", NULL, "MIXINR" },
  821. { "Left Output Mixer", "Left Input Switch", "MIXINL" },
  822. { "Left Output Mixer", "Right Input Switch", "MIXINR" },
  823. { "Left Output Mixer", "IN2RN Switch", "IN2RN" },
  824. { "Left Output Mixer", "IN2LN Switch", "IN2LN" },
  825. { "Left Output Mixer", "IN2LP Switch", "IN2LP:VXRN" },
  826. { "Left Output Mixer", "IN1L Switch", "IN1L PGA" },
  827. { "Left Output Mixer", "IN1R Switch", "IN1R PGA" },
  828. { "Right Output Mixer", "Left Input Switch", "MIXINL" },
  829. { "Right Output Mixer", "Right Input Switch", "MIXINR" },
  830. { "Right Output Mixer", "IN2LN Switch", "IN2LN" },
  831. { "Right Output Mixer", "IN2RN Switch", "IN2RN" },
  832. { "Right Output Mixer", "IN2RP Switch", "IN2RP:VXRP" },
  833. { "Right Output Mixer", "IN1L Switch", "IN1L PGA" },
  834. { "Right Output Mixer", "IN1R Switch", "IN1R PGA" },
  835. { "Left Output PGA", NULL, "Left Output Mixer" },
  836. { "Left Output PGA", NULL, "TOCLK" },
  837. { "Right Output PGA", NULL, "Right Output Mixer" },
  838. { "Right Output PGA", NULL, "TOCLK" },
  839. { "Earpiece Mixer", "Direct Voice Switch", "Direct Voice" },
  840. { "Earpiece Mixer", "Left Output Switch", "Left Output PGA" },
  841. { "Earpiece Mixer", "Right Output Switch", "Right Output PGA" },
  842. { "Earpiece Driver", NULL, "VMID" },
  843. { "Earpiece Driver", NULL, "Earpiece Mixer" },
  844. { "HPOUT2N", NULL, "Earpiece Driver" },
  845. { "HPOUT2P", NULL, "Earpiece Driver" },
  846. { "SPKL", "Input Switch", "MIXINL" },
  847. { "SPKL", "IN1LP Switch", "IN1LP" },
  848. { "SPKL", "Output Switch", "Left Output PGA" },
  849. { "SPKL", NULL, "TOCLK" },
  850. { "SPKR", "Input Switch", "MIXINR" },
  851. { "SPKR", "IN1RP Switch", "IN1RP" },
  852. { "SPKR", "Output Switch", "Right Output PGA" },
  853. { "SPKR", NULL, "TOCLK" },
  854. { "SPKL Boost", "Direct Voice Switch", "Direct Voice" },
  855. { "SPKL Boost", "SPKL Switch", "SPKL" },
  856. { "SPKL Boost", "SPKR Switch", "SPKR" },
  857. { "SPKR Boost", "Direct Voice Switch", "Direct Voice" },
  858. { "SPKR Boost", "SPKR Switch", "SPKR" },
  859. { "SPKR Boost", "SPKL Switch", "SPKL" },
  860. { "SPKL Driver", NULL, "VMID" },
  861. { "SPKL Driver", NULL, "SPKL Boost" },
  862. { "SPKL Driver", NULL, "CLK_SYS" },
  863. { "SPKL Driver", NULL, "TSHUT" },
  864. { "SPKR Driver", NULL, "VMID" },
  865. { "SPKR Driver", NULL, "SPKR Boost" },
  866. { "SPKR Driver", NULL, "CLK_SYS" },
  867. { "SPKR Driver", NULL, "TSHUT" },
  868. { "SPKOUTLP", NULL, "SPKL Driver" },
  869. { "SPKOUTLN", NULL, "SPKL Driver" },
  870. { "SPKOUTRP", NULL, "SPKR Driver" },
  871. { "SPKOUTRN", NULL, "SPKR Driver" },
  872. { "Left Headphone Mux", "Mixer", "Left Output PGA" },
  873. { "Right Headphone Mux", "Mixer", "Right Output PGA" },
  874. { "Headphone PGA", NULL, "Left Headphone Mux" },
  875. { "Headphone PGA", NULL, "Right Headphone Mux" },
  876. { "Headphone PGA", NULL, "VMID" },
  877. { "Headphone PGA", NULL, "CLK_SYS" },
  878. { "Headphone PGA", NULL, "Headphone Supply" },
  879. { "HPOUT1L", NULL, "Headphone PGA" },
  880. { "HPOUT1R", NULL, "Headphone PGA" },
  881. { "LINEOUT1N Driver", NULL, "VMID" },
  882. { "LINEOUT1P Driver", NULL, "VMID" },
  883. { "LINEOUT2N Driver", NULL, "VMID" },
  884. { "LINEOUT2P Driver", NULL, "VMID" },
  885. { "LINEOUT1N", NULL, "LINEOUT1N Driver" },
  886. { "LINEOUT1P", NULL, "LINEOUT1P Driver" },
  887. { "LINEOUT2N", NULL, "LINEOUT2N Driver" },
  888. { "LINEOUT2P", NULL, "LINEOUT2P Driver" },
  889. };
  890. static const struct snd_soc_dapm_route lineout1_diff_routes[] = {
  891. { "LINEOUT1 Mixer", "IN1L Switch", "IN1L PGA" },
  892. { "LINEOUT1 Mixer", "IN1R Switch", "IN1R PGA" },
  893. { "LINEOUT1 Mixer", "Output Switch", "Left Output PGA" },
  894. { "LINEOUT1N Driver", NULL, "LINEOUT1 Mixer" },
  895. { "LINEOUT1P Driver", NULL, "LINEOUT1 Mixer" },
  896. };
  897. static const struct snd_soc_dapm_route lineout1_se_routes[] = {
  898. { "LINEOUT1N Mixer", "Left Output Switch", "Left Output PGA" },
  899. { "LINEOUT1N Mixer", "Right Output Switch", "Right Output PGA" },
  900. { "LINEOUT1P Mixer", "Left Output Switch", "Left Output PGA" },
  901. { "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" },
  902. { "LINEOUT1P Driver", NULL, "LINEOUT1P Mixer" },
  903. };
  904. static const struct snd_soc_dapm_route lineout2_diff_routes[] = {
  905. { "LINEOUT2 Mixer", "IN1L Switch", "IN1L PGA" },
  906. { "LINEOUT2 Mixer", "IN1R Switch", "IN1R PGA" },
  907. { "LINEOUT2 Mixer", "Output Switch", "Right Output PGA" },
  908. { "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" },
  909. { "LINEOUT2P Driver", NULL, "LINEOUT2 Mixer" },
  910. };
  911. static const struct snd_soc_dapm_route lineout2_se_routes[] = {
  912. { "LINEOUT2N Mixer", "Left Output Switch", "Left Output PGA" },
  913. { "LINEOUT2N Mixer", "Right Output Switch", "Right Output PGA" },
  914. { "LINEOUT2P Mixer", "Right Output Switch", "Right Output PGA" },
  915. { "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" },
  916. { "LINEOUT2P Driver", NULL, "LINEOUT2P Mixer" },
  917. };
  918. int wm_hubs_add_analogue_controls(struct snd_soc_codec *codec)
  919. {
  920. struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
  921. /* Latch volume update bits & default ZC on */
  922. snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_1_2_VOLUME,
  923. WM8993_IN1_VU, WM8993_IN1_VU);
  924. snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_1_2_VOLUME,
  925. WM8993_IN1_VU, WM8993_IN1_VU);
  926. snd_soc_update_bits(codec, WM8993_LEFT_LINE_INPUT_3_4_VOLUME,
  927. WM8993_IN2_VU, WM8993_IN2_VU);
  928. snd_soc_update_bits(codec, WM8993_RIGHT_LINE_INPUT_3_4_VOLUME,
  929. WM8993_IN2_VU, WM8993_IN2_VU);
  930. snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_LEFT,
  931. WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);
  932. snd_soc_update_bits(codec, WM8993_SPEAKER_VOLUME_RIGHT,
  933. WM8993_SPKOUT_VU, WM8993_SPKOUT_VU);
  934. snd_soc_update_bits(codec, WM8993_LEFT_OUTPUT_VOLUME,
  935. WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC,
  936. WM8993_HPOUT1_VU | WM8993_HPOUT1L_ZC);
  937. snd_soc_update_bits(codec, WM8993_RIGHT_OUTPUT_VOLUME,
  938. WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC,
  939. WM8993_HPOUT1_VU | WM8993_HPOUT1R_ZC);
  940. snd_soc_update_bits(codec, WM8993_LEFT_OPGA_VOLUME,
  941. WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU,
  942. WM8993_MIXOUTL_ZC | WM8993_MIXOUT_VU);
  943. snd_soc_update_bits(codec, WM8993_RIGHT_OPGA_VOLUME,
  944. WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU,
  945. WM8993_MIXOUTR_ZC | WM8993_MIXOUT_VU);
  946. snd_soc_add_codec_controls(codec, analogue_snd_controls,
  947. ARRAY_SIZE(analogue_snd_controls));
  948. snd_soc_dapm_new_controls(dapm, analogue_dapm_widgets,
  949. ARRAY_SIZE(analogue_dapm_widgets));
  950. return 0;
  951. }
  952. EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_controls);
  953. int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec,
  954. int lineout1_diff, int lineout2_diff)
  955. {
  956. struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
  957. struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
  958. hubs->codec = codec;
  959. INIT_LIST_HEAD(&hubs->dcs_cache);
  960. init_completion(&hubs->dcs_done);
  961. snd_soc_dapm_add_routes(dapm, analogue_routes,
  962. ARRAY_SIZE(analogue_routes));
  963. if (lineout1_diff)
  964. snd_soc_dapm_add_routes(dapm,
  965. lineout1_diff_routes,
  966. ARRAY_SIZE(lineout1_diff_routes));
  967. else
  968. snd_soc_dapm_add_routes(dapm,
  969. lineout1_se_routes,
  970. ARRAY_SIZE(lineout1_se_routes));
  971. if (lineout2_diff)
  972. snd_soc_dapm_add_routes(dapm,
  973. lineout2_diff_routes,
  974. ARRAY_SIZE(lineout2_diff_routes));
  975. else
  976. snd_soc_dapm_add_routes(dapm,
  977. lineout2_se_routes,
  978. ARRAY_SIZE(lineout2_se_routes));
  979. return 0;
  980. }
  981. EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_routes);
  982. int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *codec,
  983. int lineout1_diff, int lineout2_diff,
  984. int lineout1fb, int lineout2fb,
  985. int jd_scthr, int jd_thr,
  986. int micbias1_delay, int micbias2_delay,
  987. int micbias1_lvl, int micbias2_lvl)
  988. {
  989. struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
  990. hubs->lineout1_se = !lineout1_diff;
  991. hubs->lineout2_se = !lineout2_diff;
  992. hubs->micb1_delay = micbias1_delay;
  993. hubs->micb2_delay = micbias2_delay;
  994. if (!lineout1_diff)
  995. snd_soc_update_bits(codec, WM8993_LINE_MIXER1,
  996. WM8993_LINEOUT1_MODE,
  997. WM8993_LINEOUT1_MODE);
  998. if (!lineout2_diff)
  999. snd_soc_update_bits(codec, WM8993_LINE_MIXER2,
  1000. WM8993_LINEOUT2_MODE,
  1001. WM8993_LINEOUT2_MODE);
  1002. if (!lineout1_diff && !lineout2_diff)
  1003. snd_soc_update_bits(codec, WM8993_ANTIPOP1,
  1004. WM8993_LINEOUT_VMID_BUF_ENA,
  1005. WM8993_LINEOUT_VMID_BUF_ENA);
  1006. if (lineout1fb)
  1007. snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
  1008. WM8993_LINEOUT1_FB, WM8993_LINEOUT1_FB);
  1009. if (lineout2fb)
  1010. snd_soc_update_bits(codec, WM8993_ADDITIONAL_CONTROL,
  1011. WM8993_LINEOUT2_FB, WM8993_LINEOUT2_FB);
  1012. snd_soc_update_bits(codec, WM8993_MICBIAS,
  1013. WM8993_JD_SCTHR_MASK | WM8993_JD_THR_MASK |
  1014. WM8993_MICB1_LVL | WM8993_MICB2_LVL,
  1015. jd_scthr << WM8993_JD_SCTHR_SHIFT |
  1016. jd_thr << WM8993_JD_THR_SHIFT |
  1017. micbias1_lvl |
  1018. micbias2_lvl << WM8993_MICB2_LVL_SHIFT);
  1019. return 0;
  1020. }
  1021. EXPORT_SYMBOL_GPL(wm_hubs_handle_analogue_pdata);
  1022. void wm_hubs_vmid_ena(struct snd_soc_codec *codec)
  1023. {
  1024. struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
  1025. int val = 0;
  1026. if (hubs->lineout1_se)
  1027. val |= WM8993_LINEOUT1N_ENA | WM8993_LINEOUT1P_ENA;
  1028. if (hubs->lineout2_se)
  1029. val |= WM8993_LINEOUT2N_ENA | WM8993_LINEOUT2P_ENA;
  1030. /* Enable the line outputs while we power up */
  1031. snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_3, val, val);
  1032. }
  1033. EXPORT_SYMBOL_GPL(wm_hubs_vmid_ena);
  1034. void wm_hubs_set_bias_level(struct snd_soc_codec *codec,
  1035. enum snd_soc_bias_level level)
  1036. {
  1037. struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
  1038. int mask, val;
  1039. switch (level) {
  1040. case SND_SOC_BIAS_STANDBY:
  1041. /* Clamp the inputs to VMID while we ramp to charge caps */
  1042. snd_soc_update_bits(codec, WM8993_INPUTS_CLAMP_REG,
  1043. WM8993_INPUTS_CLAMP, WM8993_INPUTS_CLAMP);
  1044. break;
  1045. case SND_SOC_BIAS_ON:
  1046. /* Turn off any unneded single ended outputs */
  1047. val = 0;
  1048. mask = 0;
  1049. if (hubs->lineout1_se)
  1050. mask |= WM8993_LINEOUT1N_ENA | WM8993_LINEOUT1P_ENA;
  1051. if (hubs->lineout2_se)
  1052. mask |= WM8993_LINEOUT2N_ENA | WM8993_LINEOUT2P_ENA;
  1053. if (hubs->lineout1_se && hubs->lineout1n_ena)
  1054. val |= WM8993_LINEOUT1N_ENA;
  1055. if (hubs->lineout1_se && hubs->lineout1p_ena)
  1056. val |= WM8993_LINEOUT1P_ENA;
  1057. if (hubs->lineout2_se && hubs->lineout2n_ena)
  1058. val |= WM8993_LINEOUT2N_ENA;
  1059. if (hubs->lineout2_se && hubs->lineout2p_ena)
  1060. val |= WM8993_LINEOUT2P_ENA;
  1061. snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_3,
  1062. mask, val);
  1063. /* Remove the input clamps */
  1064. snd_soc_update_bits(codec, WM8993_INPUTS_CLAMP_REG,
  1065. WM8993_INPUTS_CLAMP, 0);
  1066. break;
  1067. default:
  1068. break;
  1069. }
  1070. }
  1071. EXPORT_SYMBOL_GPL(wm_hubs_set_bias_level);
  1072. MODULE_DESCRIPTION("Shared support for Wolfson hubs products");
  1073. MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
  1074. MODULE_LICENSE("GPL");