wcd9xxx-common-v2.c 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
  4. */
  5. #include <linux/module.h>
  6. #include <linux/slab.h>
  7. #include <sound/soc.h>
  8. #include <linux/kernel.h>
  9. #include <linux/delay.h>
  10. #include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
  11. #include "core.h"
  12. #include "wcd9xxx-common-v2.h"
  13. #define WCD_USLEEP_RANGE 50
  14. #define MAX_IMPED_PARAMS 6
  15. enum {
  16. DAC_GAIN_0DB = 0,
  17. DAC_GAIN_0P2DB,
  18. DAC_GAIN_0P4DB,
  19. DAC_GAIN_0P6DB,
  20. DAC_GAIN_0P8DB,
  21. DAC_GAIN_M0P2DB,
  22. DAC_GAIN_M0P4DB,
  23. DAC_GAIN_M0P6DB,
  24. };
  25. enum {
  26. VREF_FILT_R_0OHM = 0,
  27. VREF_FILT_R_25KOHM,
  28. VREF_FILT_R_50KOHM,
  29. VREF_FILT_R_100KOHM,
  30. };
  31. enum {
  32. DELTA_I_0MA,
  33. DELTA_I_10MA,
  34. DELTA_I_20MA,
  35. DELTA_I_30MA,
  36. DELTA_I_40MA,
  37. DELTA_I_50MA,
  38. };
  39. struct wcd_imped_val {
  40. u32 imped_val;
  41. u8 index;
  42. };
  43. static const struct wcd_reg_mask_val imped_table[][MAX_IMPED_PARAMS] = {
  44. {
  45. {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf5},
  46. {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf5},
  47. {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
  48. {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf5},
  49. {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf5},
  50. {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
  51. },
  52. {
  53. {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf7},
  54. {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf7},
  55. {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
  56. {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf7},
  57. {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf7},
  58. {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
  59. },
  60. {
  61. {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf9},
  62. {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf9},
  63. {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x0},
  64. {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf9},
  65. {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf9},
  66. {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x0},
  67. },
  68. {
  69. {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfa},
  70. {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfa},
  71. {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
  72. {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfa},
  73. {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfa},
  74. {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
  75. },
  76. {
  77. {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfb},
  78. {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfb},
  79. {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
  80. {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfb},
  81. {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfb},
  82. {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
  83. },
  84. {
  85. {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfc},
  86. {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfc},
  87. {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
  88. {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfc},
  89. {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfc},
  90. {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
  91. },
  92. {
  93. {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfd},
  94. {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd},
  95. {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
  96. {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfd},
  97. {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfd},
  98. {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
  99. },
  100. {
  101. {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfe},
  102. {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfe},
  103. {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
  104. {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfe},
  105. {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfe},
  106. {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
  107. },
  108. {
  109. {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xff},
  110. {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xff},
  111. {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
  112. {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xff},
  113. {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xff},
  114. {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
  115. },
  116. };
  117. static const struct wcd_reg_mask_val imped_table_tavil[][MAX_IMPED_PARAMS] = {
  118. {
  119. {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf2},
  120. {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf2},
  121. {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
  122. {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf2},
  123. {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf2},
  124. {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
  125. },
  126. {
  127. {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf4},
  128. {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf4},
  129. {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
  130. {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf4},
  131. {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf4},
  132. {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
  133. },
  134. {
  135. {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf7},
  136. {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf7},
  137. {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
  138. {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf7},
  139. {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf7},
  140. {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
  141. },
  142. {
  143. {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf9},
  144. {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf9},
  145. {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
  146. {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf9},
  147. {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf9},
  148. {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
  149. },
  150. {
  151. {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfa},
  152. {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfa},
  153. {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
  154. {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfa},
  155. {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfa},
  156. {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
  157. },
  158. {
  159. {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfb},
  160. {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfb},
  161. {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
  162. {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfb},
  163. {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfb},
  164. {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
  165. },
  166. {
  167. {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfc},
  168. {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfc},
  169. {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
  170. {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfc},
  171. {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfc},
  172. {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
  173. },
  174. {
  175. {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfd},
  176. {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd},
  177. {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
  178. {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfd},
  179. {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfd},
  180. {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
  181. },
  182. {
  183. {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfd},
  184. {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd},
  185. {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
  186. {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfd},
  187. {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfd},
  188. {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
  189. },
  190. };
  191. static const struct wcd_imped_val imped_index[] = {
  192. {4, 0},
  193. {5, 1},
  194. {6, 2},
  195. {7, 3},
  196. {8, 4},
  197. {9, 5},
  198. {10, 6},
  199. {11, 7},
  200. {12, 8},
  201. {13, 9},
  202. };
  203. static void (*clsh_state_fp[NUM_CLSH_STATES_V2])(struct snd_soc_codec *,
  204. struct wcd_clsh_cdc_data *,
  205. u8 req_state, bool en, int mode);
  206. static int get_impedance_index(int imped)
  207. {
  208. int i = 0;
  209. if (imped < imped_index[i].imped_val) {
  210. pr_debug("%s, detected impedance is less than 4 Ohm\n",
  211. __func__);
  212. i = 0;
  213. goto ret;
  214. }
  215. if (imped >= imped_index[ARRAY_SIZE(imped_index) - 1].imped_val) {
  216. pr_debug("%s, detected impedance is greater than 12 Ohm\n",
  217. __func__);
  218. i = ARRAY_SIZE(imped_index) - 1;
  219. goto ret;
  220. }
  221. for (i = 0; i < ARRAY_SIZE(imped_index) - 1; i++) {
  222. if (imped >= imped_index[i].imped_val &&
  223. imped < imped_index[i + 1].imped_val)
  224. break;
  225. }
  226. ret:
  227. pr_debug("%s: selected impedance index = %d\n",
  228. __func__, imped_index[i].index);
  229. return imped_index[i].index;
  230. }
  231. /*
  232. * Function: wcd_clsh_imped_config
  233. * Params: codec, imped, reset
  234. * Description:
  235. * This function updates HPHL and HPHR gain settings
  236. * according to the impedance value.
  237. */
  238. void wcd_clsh_imped_config(struct snd_soc_codec *codec, int imped, bool reset)
  239. {
  240. int i;
  241. int index = 0;
  242. int table_size;
  243. static const struct wcd_reg_mask_val
  244. (*imped_table_ptr)[MAX_IMPED_PARAMS];
  245. struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
  246. if (IS_CODEC_TYPE(wcd9xxx, WCD934X)) {
  247. table_size = ARRAY_SIZE(imped_table_tavil);
  248. imped_table_ptr = imped_table_tavil;
  249. } else {
  250. table_size = ARRAY_SIZE(imped_table);
  251. imped_table_ptr = imped_table;
  252. }
  253. /* reset = 1, which means request is to reset the register values */
  254. if (reset) {
  255. for (i = 0; i < MAX_IMPED_PARAMS; i++)
  256. snd_soc_update_bits(codec,
  257. imped_table_ptr[index][i].reg,
  258. imped_table_ptr[index][i].mask, 0);
  259. return;
  260. }
  261. index = get_impedance_index(imped);
  262. if (index >= (ARRAY_SIZE(imped_index) - 1)) {
  263. pr_debug("%s, impedance not in range = %d\n", __func__, imped);
  264. return;
  265. }
  266. if (index >= table_size) {
  267. pr_debug("%s, impedance index not in range = %d\n", __func__,
  268. index);
  269. return;
  270. }
  271. for (i = 0; i < MAX_IMPED_PARAMS; i++)
  272. snd_soc_update_bits(codec,
  273. imped_table_ptr[index][i].reg,
  274. imped_table_ptr[index][i].mask,
  275. imped_table_ptr[index][i].val);
  276. }
  277. EXPORT_SYMBOL(wcd_clsh_imped_config);
  278. static bool is_native_44_1_active(struct snd_soc_codec *codec)
  279. {
  280. bool native_active = false;
  281. u8 native_clk, rx1_rate, rx2_rate;
  282. native_clk = snd_soc_read(codec,
  283. WCD9XXX_CDC_CLK_RST_CTRL_MCLK_CONTROL);
  284. rx1_rate = snd_soc_read(codec, WCD9XXX_CDC_RX1_RX_PATH_CTL);
  285. rx2_rate = snd_soc_read(codec, WCD9XXX_CDC_RX2_RX_PATH_CTL);
  286. dev_dbg(codec->dev, "%s: native_clk %x rx1_rate= %x rx2_rate= %x",
  287. __func__, native_clk, rx1_rate, rx2_rate);
  288. if ((native_clk & 0x2) &&
  289. ((rx1_rate & 0x0F) == 0x9 || (rx2_rate & 0x0F) == 0x9))
  290. native_active = true;
  291. return native_active;
  292. }
  293. static const char *mode_to_str(int mode)
  294. {
  295. switch (mode) {
  296. case CLS_H_NORMAL:
  297. return "CLS_H_NORMAL";
  298. case CLS_H_HIFI:
  299. return "CLS_H_HIFI";
  300. case CLS_H_LOHIFI:
  301. return "CLS_H_LOHIFI";
  302. case CLS_H_LP:
  303. return "CLS_H_LP";
  304. case CLS_H_ULP:
  305. return "CLS_H_ULP";
  306. case CLS_AB:
  307. return "CLS_AB";
  308. case CLS_AB_HIFI:
  309. return "CLS_AB_HIFI";
  310. default:
  311. return "CLS_H_INVALID";
  312. };
  313. }
  314. static const char *state_to_str(u8 state, char *buf, size_t buflen)
  315. {
  316. int i;
  317. int cnt = 0;
  318. /*
  319. * This array of strings should match with enum wcd_clsh_state_bit.
  320. */
  321. static const char *const states[] = {
  322. "STATE_EAR",
  323. "STATE_HPH_L",
  324. "STATE_HPH_R",
  325. "STATE_LO",
  326. };
  327. if (state == WCD_CLSH_STATE_IDLE) {
  328. snprintf(buf, buflen, "[STATE_IDLE]");
  329. goto done;
  330. }
  331. buf[0] = '\0';
  332. for (i = 0; i < ARRAY_SIZE(states); i++) {
  333. if (!(state & (1 << i)))
  334. continue;
  335. cnt = snprintf(buf, buflen - cnt - 1, "%s%s%s", buf,
  336. buf[0] == '\0' ? "[" : "|",
  337. states[i]);
  338. }
  339. if (cnt > 0)
  340. strlcat(buf + cnt, "]", buflen);
  341. done:
  342. if (buf[0] == '\0')
  343. snprintf(buf, buflen, "[STATE_UNKNOWN]");
  344. return buf;
  345. }
  346. static inline void
  347. wcd_enable_clsh_block(struct snd_soc_codec *codec,
  348. struct wcd_clsh_cdc_data *clsh_d, bool enable)
  349. {
  350. if ((enable && ++clsh_d->clsh_users == 1) ||
  351. (!enable && --clsh_d->clsh_users == 0))
  352. snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_CRC, 0x01,
  353. (u8) enable);
  354. if (clsh_d->clsh_users < 0)
  355. clsh_d->clsh_users = 0;
  356. dev_dbg(codec->dev, "%s: clsh_users %d, enable %d", __func__,
  357. clsh_d->clsh_users, enable);
  358. }
  359. static inline bool wcd_clsh_enable_status(struct snd_soc_codec *codec)
  360. {
  361. return snd_soc_read(codec, WCD9XXX_A_CDC_CLSH_CRC) & 0x01;
  362. }
  363. static inline int wcd_clsh_get_int_mode(struct wcd_clsh_cdc_data *clsh_d,
  364. int clsh_state)
  365. {
  366. int mode;
  367. if ((clsh_state != WCD_CLSH_STATE_EAR) &&
  368. (clsh_state != WCD_CLSH_STATE_HPHL) &&
  369. (clsh_state != WCD_CLSH_STATE_HPHR) &&
  370. (clsh_state != WCD_CLSH_STATE_LO))
  371. mode = CLS_NONE;
  372. else
  373. mode = clsh_d->interpolator_modes[ffs(clsh_state)];
  374. return mode;
  375. }
  376. static inline void wcd_clsh_set_int_mode(struct wcd_clsh_cdc_data *clsh_d,
  377. int clsh_state, int mode)
  378. {
  379. if ((clsh_state != WCD_CLSH_STATE_EAR) &&
  380. (clsh_state != WCD_CLSH_STATE_HPHL) &&
  381. (clsh_state != WCD_CLSH_STATE_HPHR) &&
  382. (clsh_state != WCD_CLSH_STATE_LO))
  383. return;
  384. clsh_d->interpolator_modes[ffs(clsh_state)] = mode;
  385. }
  386. static inline void wcd_clsh_set_buck_mode(struct snd_soc_codec *codec,
  387. int mode)
  388. {
  389. if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI ||
  390. mode == CLS_AB_HIFI || mode == CLS_AB)
  391. snd_soc_update_bits(codec, WCD9XXX_A_ANA_RX_SUPPLIES,
  392. 0x08, 0x08); /* set to HIFI */
  393. else
  394. snd_soc_update_bits(codec, WCD9XXX_A_ANA_RX_SUPPLIES,
  395. 0x08, 0x00); /* set to default */
  396. }
  397. static inline void wcd_clsh_set_flyback_mode(struct snd_soc_codec *codec,
  398. int mode)
  399. {
  400. if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI ||
  401. mode == CLS_AB_HIFI || mode == CLS_AB)
  402. snd_soc_update_bits(codec, WCD9XXX_A_ANA_RX_SUPPLIES,
  403. 0x04, 0x04); /* set to HIFI */
  404. else
  405. snd_soc_update_bits(codec, WCD9XXX_A_ANA_RX_SUPPLIES,
  406. 0x04, 0x00); /* set to Default */
  407. }
  408. static inline void wcd_clsh_gm3_boost_disable(struct snd_soc_codec *codec,
  409. int mode)
  410. {
  411. struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
  412. if (!IS_CODEC_TYPE(wcd9xxx, WCD934X))
  413. return;
  414. if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI ||
  415. mode == CLS_AB_HIFI || mode == CLS_AB) {
  416. if (TAVIL_IS_1_0(wcd9xxx))
  417. snd_soc_update_bits(codec, WCD9XXX_HPH_CNP_WG_CTL,
  418. 0x80, 0x0); /* disable GM3 Boost */
  419. snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEG_CTRL_4,
  420. 0xF0, 0x80);
  421. } else {
  422. snd_soc_update_bits(codec, WCD9XXX_HPH_CNP_WG_CTL,
  423. 0x80, 0x80); /* set to Default */
  424. snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEG_CTRL_4,
  425. 0xF0, 0x70);
  426. }
  427. }
  428. static inline void wcd_clsh_force_iq_ctl(struct snd_soc_codec *codec,
  429. int mode)
  430. {
  431. struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
  432. if (!IS_CODEC_TYPE(wcd9xxx, WCD934X))
  433. return;
  434. if (mode == CLS_H_LOHIFI || mode == CLS_AB) {
  435. snd_soc_update_bits(codec, WCD9XXX_HPH_NEW_INT_PA_MISC2,
  436. 0x20, 0x20);
  437. snd_soc_update_bits(codec, WCD9XXX_RX_BIAS_HPH_LOWPOWER,
  438. 0xF0, 0xC0);
  439. snd_soc_update_bits(codec, WCD9XXX_HPH_PA_CTL1,
  440. 0x0E, 0x02);
  441. } else {
  442. snd_soc_update_bits(codec, WCD9XXX_HPH_NEW_INT_PA_MISC2,
  443. 0x20, 0x0);
  444. snd_soc_update_bits(codec, WCD9XXX_RX_BIAS_HPH_LOWPOWER,
  445. 0xF0, 0x80);
  446. snd_soc_update_bits(codec, WCD9XXX_HPH_PA_CTL1,
  447. 0x0E, 0x06);
  448. }
  449. }
  450. static void wcd_clsh_buck_ctrl(struct snd_soc_codec *codec,
  451. struct wcd_clsh_cdc_data *clsh_d,
  452. int mode,
  453. bool enable)
  454. {
  455. /* enable/disable buck */
  456. if ((enable && (++clsh_d->buck_users == 1)) ||
  457. (!enable && (--clsh_d->buck_users == 0)))
  458. snd_soc_update_bits(codec, WCD9XXX_A_ANA_RX_SUPPLIES,
  459. (1 << 7), (enable << 7));
  460. dev_dbg(codec->dev, "%s: buck_users %d, enable %d, mode: %s",
  461. __func__, clsh_d->buck_users, enable, mode_to_str(mode));
  462. /*
  463. * 500us sleep is required after buck enable/disable
  464. * as per HW requirement
  465. */
  466. usleep_range(500, 500 + WCD_USLEEP_RANGE);
  467. }
  468. static void wcd_clsh_flyback_ctrl(struct snd_soc_codec *codec,
  469. struct wcd_clsh_cdc_data *clsh_d,
  470. int mode,
  471. bool enable)
  472. {
  473. struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
  474. struct wcd9xxx_reg_val bulk_reg[2];
  475. u8 vneg[] = {0x00, 0x40};
  476. /* enable/disable flyback */
  477. if ((enable && (++clsh_d->flyback_users == 1)) ||
  478. (!enable && (--clsh_d->flyback_users == 0))) {
  479. snd_soc_update_bits(codec, WCD9XXX_A_ANA_RX_SUPPLIES,
  480. (1 << 6), (enable << 6));
  481. /* 100usec delay is needed as per HW requirement */
  482. usleep_range(100, 110);
  483. if (enable && (TASHA_IS_1_1(wcd9xxx))) {
  484. wcd_clsh_set_flyback_mode(codec, CLS_H_HIFI);
  485. snd_soc_update_bits(codec, WCD9XXX_FLYBACK_EN,
  486. 0x60, 0x40);
  487. snd_soc_update_bits(codec, WCD9XXX_FLYBACK_EN,
  488. 0x10, 0x10);
  489. vneg[0] = snd_soc_read(codec,
  490. WCD9XXX_A_ANA_RX_SUPPLIES);
  491. vneg[0] &= ~(0x40);
  492. vneg[1] = vneg[0] | 0x40;
  493. bulk_reg[0].reg = WCD9XXX_A_ANA_RX_SUPPLIES;
  494. bulk_reg[0].buf = &vneg[0];
  495. bulk_reg[0].bytes = 1;
  496. bulk_reg[1].reg = WCD9XXX_A_ANA_RX_SUPPLIES;
  497. bulk_reg[1].buf = &vneg[1];
  498. bulk_reg[1].bytes = 1;
  499. /* 500usec delay is needed as per HW requirement */
  500. usleep_range(500, 510);
  501. wcd9xxx_slim_bulk_write(wcd9xxx, bulk_reg, 2,
  502. false);
  503. snd_soc_update_bits(codec, WCD9XXX_FLYBACK_EN,
  504. 0x10, 0x00);
  505. wcd_clsh_set_flyback_mode(codec, mode);
  506. }
  507. }
  508. dev_dbg(codec->dev, "%s: flyback_users %d, enable %d, mode: %s",
  509. __func__, clsh_d->flyback_users, enable, mode_to_str(mode));
  510. /*
  511. * 500us sleep is required after flyback enable/disable
  512. * as per HW requirement
  513. */
  514. usleep_range(500, 500 + WCD_USLEEP_RANGE);
  515. }
  516. static void wcd_clsh_set_gain_path(struct snd_soc_codec *codec,
  517. int mode)
  518. {
  519. u8 val = 0;
  520. struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
  521. if (!TASHA_IS_2_0(wcd9xxx))
  522. return;
  523. switch (mode) {
  524. case CLS_H_NORMAL:
  525. case CLS_AB:
  526. val = 0x00;
  527. break;
  528. case CLS_H_HIFI:
  529. val = 0x02;
  530. break;
  531. case CLS_H_LP:
  532. val = 0x01;
  533. break;
  534. default:
  535. return;
  536. };
  537. snd_soc_update_bits(codec, WCD9XXX_HPH_L_EN, 0xC0, (val << 6));
  538. snd_soc_update_bits(codec, WCD9XXX_HPH_R_EN, 0xC0, (val << 6));
  539. }
  540. static void wcd_clsh_set_hph_mode(struct snd_soc_codec *codec,
  541. int mode)
  542. {
  543. u8 val = 0;
  544. u8 gain = 0;
  545. u8 res_val = VREF_FILT_R_0OHM;
  546. u8 ipeak = DELTA_I_50MA;
  547. struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
  548. switch (mode) {
  549. case CLS_H_NORMAL:
  550. res_val = VREF_FILT_R_50KOHM;
  551. val = 0x00;
  552. gain = DAC_GAIN_0DB;
  553. ipeak = DELTA_I_50MA;
  554. break;
  555. case CLS_AB:
  556. val = 0x00;
  557. gain = DAC_GAIN_0DB;
  558. ipeak = DELTA_I_50MA;
  559. break;
  560. case CLS_AB_HIFI:
  561. val = 0x08;
  562. break;
  563. case CLS_H_HIFI:
  564. val = 0x08;
  565. gain = DAC_GAIN_M0P2DB;
  566. ipeak = DELTA_I_50MA;
  567. break;
  568. case CLS_H_LOHIFI:
  569. val = 0x00;
  570. if ((IS_CODEC_TYPE(wcd9xxx, WCD9335)) ||
  571. (IS_CODEC_TYPE(wcd9xxx, WCD9326))) {
  572. val = 0x08;
  573. gain = DAC_GAIN_M0P2DB;
  574. ipeak = DELTA_I_50MA;
  575. }
  576. break;
  577. case CLS_H_ULP:
  578. val = 0x0C;
  579. break;
  580. case CLS_H_LP:
  581. val = 0x04;
  582. ipeak = DELTA_I_30MA;
  583. break;
  584. default:
  585. return;
  586. };
  587. /*
  588. * For tavil set mode to Lower_power for
  589. * CLS_H_LOHIFI and CLS_AB
  590. */
  591. if ((IS_CODEC_TYPE(wcd9xxx, WCD934X)) &&
  592. (mode == CLS_H_LOHIFI || mode == CLS_AB))
  593. val = 0x04;
  594. snd_soc_update_bits(codec, WCD9XXX_A_ANA_HPH, 0x0C, val);
  595. if (TASHA_IS_2_0(wcd9xxx)) {
  596. snd_soc_update_bits(codec, WCD9XXX_CLASSH_CTRL_VCL_2,
  597. 0x30, (res_val << 4));
  598. if (mode != CLS_H_LP)
  599. snd_soc_update_bits(codec, WCD9XXX_HPH_REFBUFF_UHQA_CTL,
  600. 0x07, gain);
  601. snd_soc_update_bits(codec, WCD9XXX_CLASSH_CTRL_CCL_1,
  602. 0xF0, (ipeak << 4));
  603. }
  604. }
  605. static void wcd_clsh_set_flyback_vneg_ctl(struct snd_soc_codec *codec,
  606. bool enable)
  607. {
  608. struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
  609. if (!TASHA_IS_2_0(wcd9xxx))
  610. return;
  611. if (enable) {
  612. snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEG_CTRL_1, 0xE0,
  613. 0x00);
  614. snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEGDAC_CTRL_2,
  615. 0xE0, (0x07 << 5));
  616. } else {
  617. snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEG_CTRL_1, 0xE0,
  618. (0x07 << 5));
  619. snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEGDAC_CTRL_2,
  620. 0xE0, (0x02 << 5));
  621. }
  622. }
  623. static void wcd_clsh_set_flyback_current(struct snd_soc_codec *codec, int mode)
  624. {
  625. struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent);
  626. if (!TASHA_IS_2_0(wcd9xxx))
  627. return;
  628. snd_soc_update_bits(codec, WCD9XXX_RX_BIAS_FLYB_BUFF, 0x0F, 0x0A);
  629. snd_soc_update_bits(codec, WCD9XXX_RX_BIAS_FLYB_BUFF, 0xF0, 0xA0);
  630. /* Sleep needed to avoid click and pop as per HW requirement */
  631. usleep_range(100, 110);
  632. }
  633. static void wcd_clsh_set_buck_regulator_mode(struct snd_soc_codec *codec,
  634. int mode)
  635. {
  636. snd_soc_update_bits(codec, WCD9XXX_A_ANA_RX_SUPPLIES,
  637. 0x02, 0x00);
  638. }
  639. static void wcd_clsh_state_lo(struct snd_soc_codec *codec,
  640. struct wcd_clsh_cdc_data *clsh_d,
  641. u8 req_state, bool is_enable, int mode)
  642. {
  643. dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
  644. is_enable ? "enable" : "disable");
  645. if (mode != CLS_AB && mode != CLS_AB_HIFI) {
  646. dev_err(codec->dev, "%s: LO cannot be in this mode: %d\n",
  647. __func__, mode);
  648. return;
  649. }
  650. if (is_enable) {
  651. wcd_clsh_set_buck_regulator_mode(codec, mode);
  652. wcd_clsh_set_flyback_vneg_ctl(codec, true);
  653. wcd_clsh_set_buck_mode(codec, mode);
  654. wcd_clsh_set_flyback_mode(codec, mode);
  655. wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true);
  656. wcd_clsh_set_flyback_current(codec, mode);
  657. wcd_clsh_buck_ctrl(codec, clsh_d, mode, true);
  658. } else {
  659. wcd_clsh_buck_ctrl(codec, clsh_d, mode, false);
  660. wcd_clsh_flyback_ctrl(codec, clsh_d, mode, false);
  661. wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL);
  662. wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL);
  663. wcd_clsh_set_flyback_vneg_ctl(codec, false);
  664. wcd_clsh_set_buck_regulator_mode(codec, CLS_H_NORMAL);
  665. }
  666. }
  667. static void wcd_clsh_state_hph_ear(struct snd_soc_codec *codec,
  668. struct wcd_clsh_cdc_data *clsh_d,
  669. u8 req_state, bool is_enable, int mode)
  670. {
  671. int hph_mode = 0;
  672. dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
  673. is_enable ? "enable" : "disable");
  674. if (is_enable) {
  675. if (req_state == WCD_CLSH_STATE_EAR) {
  676. /* If HPH is running in CLS-AB when
  677. * EAR comes, let it continue to run
  678. * in Class-AB, no need to enable Class-H
  679. * for EAR.
  680. */
  681. if (clsh_d->state & WCD_CLSH_STATE_HPHL)
  682. hph_mode = wcd_clsh_get_int_mode(clsh_d,
  683. WCD_CLSH_STATE_HPHL);
  684. else if (clsh_d->state & WCD_CLSH_STATE_HPHR)
  685. hph_mode = wcd_clsh_get_int_mode(clsh_d,
  686. WCD_CLSH_STATE_HPHR);
  687. else
  688. return;
  689. if (hph_mode != CLS_AB && hph_mode != CLS_AB_HIFI
  690. && !is_native_44_1_active(codec))
  691. snd_soc_update_bits(codec,
  692. WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
  693. 0x40, 0x40);
  694. }
  695. if (is_native_44_1_active(codec)) {
  696. snd_soc_write(codec, WCD9XXX_CDC_CLSH_HPH_V_PA, 0x39);
  697. snd_soc_update_bits(codec,
  698. WCD9XXX_CDC_RX0_RX_PATH_SEC0,
  699. 0x03, 0x00);
  700. if ((req_state == WCD_CLSH_STATE_HPHL) ||
  701. (req_state == WCD_CLSH_STATE_HPHR))
  702. snd_soc_update_bits(codec,
  703. WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
  704. 0x40, 0x00);
  705. }
  706. if (req_state == WCD_CLSH_STATE_HPHL)
  707. snd_soc_update_bits(codec,
  708. WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
  709. 0x40, 0x40);
  710. if (req_state == WCD_CLSH_STATE_HPHR)
  711. snd_soc_update_bits(codec,
  712. WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
  713. 0x40, 0x40);
  714. if ((req_state == WCD_CLSH_STATE_HPHL) ||
  715. (req_state == WCD_CLSH_STATE_HPHR)) {
  716. wcd_clsh_set_gain_path(codec, mode);
  717. wcd_clsh_set_flyback_mode(codec, mode);
  718. wcd_clsh_set_buck_mode(codec, mode);
  719. }
  720. } else {
  721. if (req_state == WCD_CLSH_STATE_EAR) {
  722. /*
  723. * If EAR goes away, disable EAR Channel Enable
  724. * if HPH running in Class-H otherwise
  725. * and if HPH requested mode is CLS_AB then
  726. * no need to disable EAR channel enable bit.
  727. */
  728. if (wcd_clsh_enable_status(codec))
  729. snd_soc_update_bits(codec,
  730. WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
  731. 0x40, 0x00);
  732. }
  733. if (is_native_44_1_active(codec)) {
  734. snd_soc_write(codec, WCD9XXX_CDC_CLSH_HPH_V_PA, 0x1C);
  735. snd_soc_update_bits(codec,
  736. WCD9XXX_CDC_RX0_RX_PATH_SEC0,
  737. 0x03, 0x01);
  738. if (((clsh_d->state & WCD_CLSH_STATE_HPH_ST)
  739. != WCD_CLSH_STATE_HPH_ST) &&
  740. ((req_state == WCD_CLSH_STATE_HPHL) ||
  741. (req_state == WCD_CLSH_STATE_HPHR)))
  742. snd_soc_update_bits(codec,
  743. WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
  744. 0x40, 0x40);
  745. }
  746. if (req_state == WCD_CLSH_STATE_HPHL)
  747. snd_soc_update_bits(codec,
  748. WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
  749. 0x40, 0x00);
  750. if (req_state == WCD_CLSH_STATE_HPHR)
  751. snd_soc_update_bits(codec,
  752. WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
  753. 0x40, 0x00);
  754. if ((req_state & WCD_CLSH_STATE_HPH_ST) &&
  755. !wcd_clsh_enable_status(codec)) {
  756. /* If Class-H is not enabled when HPH is turned
  757. * off, enable it as EAR is in progress
  758. */
  759. wcd_enable_clsh_block(codec, clsh_d, true);
  760. snd_soc_update_bits(codec,
  761. WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
  762. 0x40, 0x40);
  763. wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL);
  764. wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL);
  765. }
  766. }
  767. }
  768. static void wcd_clsh_state_ear_lo(struct snd_soc_codec *codec,
  769. struct wcd_clsh_cdc_data *clsh_d,
  770. u8 req_state, bool is_enable, int mode)
  771. {
  772. dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
  773. is_enable ? "enable" : "disable");
  774. if (is_enable) {
  775. /* LO powerup is taken care in PA sequence.
  776. * No need to change to class AB here.
  777. */
  778. if (req_state == WCD_CLSH_STATE_EAR) {
  779. /* EAR powerup.*/
  780. if (!wcd_clsh_enable_status(codec)) {
  781. wcd_enable_clsh_block(codec, clsh_d, true);
  782. wcd_clsh_set_buck_mode(codec, mode);
  783. wcd_clsh_set_flyback_mode(codec, mode);
  784. }
  785. snd_soc_update_bits(codec,
  786. WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
  787. 0x40, 0x40);
  788. }
  789. } else {
  790. if (req_state == WCD_CLSH_STATE_EAR) {
  791. /* EAR powerdown.*/
  792. wcd_enable_clsh_block(codec, clsh_d, false);
  793. wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL);
  794. wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL);
  795. snd_soc_update_bits(codec,
  796. WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
  797. 0x40, 0x00);
  798. }
  799. /* LO powerdown is taken care in PA sequence.
  800. * No need to change to class H here.
  801. */
  802. }
  803. }
  804. static void wcd_clsh_state_hph_lo(struct snd_soc_codec *codec,
  805. struct wcd_clsh_cdc_data *clsh_d,
  806. u8 req_state, bool is_enable, int mode)
  807. {
  808. int hph_mode = 0;
  809. dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
  810. is_enable ? "enable" : "disable");
  811. if (is_enable) {
  812. /*
  813. * If requested state is LO, put regulator
  814. * in class-AB or if requested state is HPH,
  815. * which means LO is already enabled, keep
  816. * the regulator config the same at class-AB
  817. * and just set the power modes for flyback
  818. * and buck.
  819. */
  820. if (req_state == WCD_CLSH_STATE_LO)
  821. wcd_clsh_set_buck_regulator_mode(codec, CLS_AB);
  822. else {
  823. if (!wcd_clsh_enable_status(codec)) {
  824. wcd_enable_clsh_block(codec, clsh_d, true);
  825. snd_soc_update_bits(codec,
  826. WCD9XXX_A_CDC_CLSH_K1_MSB,
  827. 0x0F, 0x00);
  828. snd_soc_update_bits(codec,
  829. WCD9XXX_A_CDC_CLSH_K1_LSB,
  830. 0xFF, 0xC0);
  831. wcd_clsh_set_flyback_mode(codec, mode);
  832. wcd_clsh_set_flyback_vneg_ctl(codec, false);
  833. wcd_clsh_set_buck_mode(codec, mode);
  834. wcd_clsh_set_hph_mode(codec, mode);
  835. wcd_clsh_set_gain_path(codec, mode);
  836. } else {
  837. dev_dbg(codec->dev, "%s:clsh is already enabled\n",
  838. __func__);
  839. }
  840. if (req_state == WCD_CLSH_STATE_HPHL)
  841. snd_soc_update_bits(codec,
  842. WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
  843. 0x40, 0x40);
  844. if (req_state == WCD_CLSH_STATE_HPHR)
  845. snd_soc_update_bits(codec,
  846. WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
  847. 0x40, 0x40);
  848. }
  849. } else {
  850. if ((req_state == WCD_CLSH_STATE_HPHL) ||
  851. (req_state == WCD_CLSH_STATE_HPHR)) {
  852. if (req_state == WCD_CLSH_STATE_HPHL)
  853. snd_soc_update_bits(codec,
  854. WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
  855. 0x40, 0x00);
  856. if (req_state == WCD_CLSH_STATE_HPHR)
  857. snd_soc_update_bits(codec,
  858. WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
  859. 0x40, 0x00);
  860. /*
  861. * If HPH is powering down first, then disable clsh,
  862. * set the buck/flyback mode to default and keep the
  863. * regulator at Class-AB
  864. */
  865. if ((clsh_d->state & WCD_CLSH_STATE_HPH_ST)
  866. != WCD_CLSH_STATE_HPH_ST) {
  867. wcd_enable_clsh_block(codec, clsh_d, false);
  868. wcd_clsh_set_flyback_vneg_ctl(codec, true);
  869. wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL);
  870. wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL);
  871. }
  872. } else {
  873. /* LO powerdown.
  874. * If HPH mode also is CLS-AB, no need
  875. * to turn-on class-H, otherwise enable
  876. * Class-H configuration.
  877. */
  878. if (clsh_d->state & WCD_CLSH_STATE_HPHL)
  879. hph_mode = wcd_clsh_get_int_mode(clsh_d,
  880. WCD_CLSH_STATE_HPHL);
  881. else if (clsh_d->state & WCD_CLSH_STATE_HPHR)
  882. hph_mode = wcd_clsh_get_int_mode(clsh_d,
  883. WCD_CLSH_STATE_HPHR);
  884. else
  885. return;
  886. dev_dbg(codec->dev, "%s: hph_mode = %d\n", __func__,
  887. hph_mode);
  888. if ((hph_mode == CLS_AB) ||
  889. (hph_mode == CLS_AB_HIFI) ||
  890. (hph_mode == CLS_NONE))
  891. goto end;
  892. /*
  893. * If Class-H is already enabled (HPH ON and then
  894. * LO ON), no need to turn on again, just set the
  895. * regulator mode.
  896. */
  897. if (wcd_clsh_enable_status(codec)) {
  898. wcd_clsh_set_buck_regulator_mode(codec,
  899. hph_mode);
  900. goto end;
  901. } else {
  902. dev_dbg(codec->dev, "%s: clsh is not enabled\n",
  903. __func__);
  904. }
  905. wcd_enable_clsh_block(codec, clsh_d, true);
  906. snd_soc_update_bits(codec,
  907. WCD9XXX_A_CDC_CLSH_K1_MSB,
  908. 0x0F, 0x00);
  909. snd_soc_update_bits(codec,
  910. WCD9XXX_A_CDC_CLSH_K1_LSB,
  911. 0xFF, 0xC0);
  912. wcd_clsh_set_buck_regulator_mode(codec,
  913. hph_mode);
  914. if (clsh_d->state & WCD_CLSH_STATE_HPHL)
  915. snd_soc_update_bits(codec,
  916. WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
  917. 0x40, 0x40);
  918. if (clsh_d->state & WCD_CLSH_STATE_HPHR)
  919. snd_soc_update_bits(codec,
  920. WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
  921. 0x40, 0x40);
  922. wcd_clsh_set_hph_mode(codec, hph_mode);
  923. }
  924. }
  925. end:
  926. return;
  927. }
  928. static void wcd_clsh_state_hph_st(struct snd_soc_codec *codec,
  929. struct wcd_clsh_cdc_data *clsh_d,
  930. u8 req_state, bool is_enable, int mode)
  931. {
  932. dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
  933. is_enable ? "enable" : "disable");
  934. if (mode == CLS_AB || mode == CLS_AB_HIFI)
  935. return;
  936. if (is_enable) {
  937. if (req_state == WCD_CLSH_STATE_HPHL)
  938. snd_soc_update_bits(codec,
  939. WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
  940. 0x40, 0x40);
  941. if (req_state == WCD_CLSH_STATE_HPHR)
  942. snd_soc_update_bits(codec,
  943. WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
  944. 0x40, 0x40);
  945. } else {
  946. if (req_state == WCD_CLSH_STATE_HPHL)
  947. snd_soc_update_bits(codec,
  948. WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
  949. 0x40, 0x00);
  950. if (req_state == WCD_CLSH_STATE_HPHR)
  951. snd_soc_update_bits(codec,
  952. WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
  953. 0x40, 0x00);
  954. }
  955. }
  956. static void wcd_clsh_state_hph_r(struct snd_soc_codec *codec,
  957. struct wcd_clsh_cdc_data *clsh_d,
  958. u8 req_state, bool is_enable, int mode)
  959. {
  960. dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
  961. is_enable ? "enable" : "disable");
  962. if (mode == CLS_H_NORMAL) {
  963. dev_err(codec->dev, "%s: Normal mode not applicable for hph_r\n",
  964. __func__);
  965. return;
  966. }
  967. if (is_enable) {
  968. if (mode != CLS_AB && mode != CLS_AB_HIFI) {
  969. wcd_enable_clsh_block(codec, clsh_d, true);
  970. /*
  971. * These K1 values depend on the Headphone Impedance
  972. * For now it is assumed to be 16 ohm
  973. */
  974. snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_K1_MSB,
  975. 0x0F, 0x00);
  976. snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_K1_LSB,
  977. 0xFF, 0xC0);
  978. snd_soc_update_bits(codec,
  979. WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
  980. 0x40, 0x40);
  981. }
  982. wcd_clsh_set_buck_regulator_mode(codec, mode);
  983. wcd_clsh_set_flyback_mode(codec, mode);
  984. wcd_clsh_gm3_boost_disable(codec, mode);
  985. wcd_clsh_force_iq_ctl(codec, mode);
  986. wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true);
  987. wcd_clsh_set_flyback_current(codec, mode);
  988. wcd_clsh_set_buck_mode(codec, mode);
  989. wcd_clsh_buck_ctrl(codec, clsh_d, mode, true);
  990. wcd_clsh_set_hph_mode(codec, mode);
  991. wcd_clsh_set_gain_path(codec, mode);
  992. } else {
  993. wcd_clsh_set_hph_mode(codec, CLS_H_NORMAL);
  994. if (mode != CLS_AB && mode != CLS_AB_HIFI) {
  995. snd_soc_update_bits(codec,
  996. WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
  997. 0x40, 0x00);
  998. wcd_enable_clsh_block(codec, clsh_d, false);
  999. }
  1000. /* buck and flyback set to default mode and disable */
  1001. wcd_clsh_buck_ctrl(codec, clsh_d, CLS_H_NORMAL, false);
  1002. wcd_clsh_flyback_ctrl(codec, clsh_d, CLS_H_NORMAL, false);
  1003. wcd_clsh_force_iq_ctl(codec, CLS_H_NORMAL);
  1004. wcd_clsh_gm3_boost_disable(codec, CLS_H_NORMAL);
  1005. wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL);
  1006. wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL);
  1007. wcd_clsh_set_buck_regulator_mode(codec, CLS_H_NORMAL);
  1008. }
  1009. }
  1010. static void wcd_clsh_state_hph_l(struct snd_soc_codec *codec,
  1011. struct wcd_clsh_cdc_data *clsh_d,
  1012. u8 req_state, bool is_enable, int mode)
  1013. {
  1014. dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
  1015. is_enable ? "enable" : "disable");
  1016. if (mode == CLS_H_NORMAL) {
  1017. dev_err(codec->dev, "%s: Normal mode not applicable for hph_l\n",
  1018. __func__);
  1019. return;
  1020. }
  1021. if (is_enable) {
  1022. if (mode != CLS_AB && mode != CLS_AB_HIFI) {
  1023. wcd_enable_clsh_block(codec, clsh_d, true);
  1024. /*
  1025. * These K1 values depend on the Headphone Impedance
  1026. * For now it is assumed to be 16 ohm
  1027. */
  1028. snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_K1_MSB,
  1029. 0x0F, 0x00);
  1030. snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_K1_LSB,
  1031. 0xFF, 0xC0);
  1032. snd_soc_update_bits(codec,
  1033. WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
  1034. 0x40, 0x40);
  1035. }
  1036. wcd_clsh_set_buck_regulator_mode(codec, mode);
  1037. wcd_clsh_set_flyback_mode(codec, mode);
  1038. wcd_clsh_gm3_boost_disable(codec, mode);
  1039. wcd_clsh_force_iq_ctl(codec, mode);
  1040. wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true);
  1041. wcd_clsh_set_flyback_current(codec, mode);
  1042. wcd_clsh_set_buck_mode(codec, mode);
  1043. wcd_clsh_buck_ctrl(codec, clsh_d, mode, true);
  1044. wcd_clsh_set_hph_mode(codec, mode);
  1045. wcd_clsh_set_gain_path(codec, mode);
  1046. } else {
  1047. wcd_clsh_set_hph_mode(codec, CLS_H_NORMAL);
  1048. if (mode != CLS_AB && mode != CLS_AB_HIFI) {
  1049. snd_soc_update_bits(codec,
  1050. WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
  1051. 0x40, 0x00);
  1052. wcd_enable_clsh_block(codec, clsh_d, false);
  1053. }
  1054. /* set buck and flyback to Default Mode */
  1055. wcd_clsh_buck_ctrl(codec, clsh_d, CLS_H_NORMAL, false);
  1056. wcd_clsh_flyback_ctrl(codec, clsh_d, CLS_H_NORMAL, false);
  1057. wcd_clsh_force_iq_ctl(codec, CLS_H_NORMAL);
  1058. wcd_clsh_gm3_boost_disable(codec, CLS_H_NORMAL);
  1059. wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL);
  1060. wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL);
  1061. wcd_clsh_set_buck_regulator_mode(codec, CLS_H_NORMAL);
  1062. }
  1063. }
  1064. static void wcd_clsh_state_ear(struct snd_soc_codec *codec,
  1065. struct wcd_clsh_cdc_data *clsh_d,
  1066. u8 req_state, bool is_enable, int mode)
  1067. {
  1068. dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode),
  1069. is_enable ? "enable" : "disable");
  1070. if (mode != CLS_H_NORMAL) {
  1071. dev_err(codec->dev, "%s: mode: %s cannot be used for EAR\n",
  1072. __func__, mode_to_str(mode));
  1073. return;
  1074. }
  1075. if (is_enable) {
  1076. wcd_enable_clsh_block(codec, clsh_d, true);
  1077. snd_soc_update_bits(codec,
  1078. WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
  1079. 0x40, 0x40);
  1080. wcd_clsh_set_buck_mode(codec, mode);
  1081. wcd_clsh_set_flyback_mode(codec, mode);
  1082. wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true);
  1083. wcd_clsh_set_flyback_current(codec, mode);
  1084. wcd_clsh_buck_ctrl(codec, clsh_d, mode, true);
  1085. } else {
  1086. snd_soc_update_bits(codec,
  1087. WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
  1088. 0x40, 0x00);
  1089. wcd_enable_clsh_block(codec, clsh_d, false);
  1090. wcd_clsh_buck_ctrl(codec, clsh_d, mode, false);
  1091. wcd_clsh_flyback_ctrl(codec, clsh_d, mode, false);
  1092. wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL);
  1093. wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL);
  1094. }
  1095. }
  1096. static void wcd_clsh_state_err(struct snd_soc_codec *codec,
  1097. struct wcd_clsh_cdc_data *clsh_d,
  1098. u8 req_state, bool is_enable, int mode)
  1099. {
  1100. char msg[128];
  1101. dev_err(codec->dev,
  1102. "%s Wrong request for class H state machine requested to %s %s",
  1103. __func__, is_enable ? "enable" : "disable",
  1104. state_to_str(req_state, msg, sizeof(msg)));
  1105. WARN_ON(1);
  1106. }
  1107. /*
  1108. * Function: wcd_clsh_is_state_valid
  1109. * Params: state
  1110. * Description:
  1111. * Provides information on valid states of Class H configuration
  1112. */
  1113. static bool wcd_clsh_is_state_valid(u8 state)
  1114. {
  1115. switch (state) {
  1116. case WCD_CLSH_STATE_IDLE:
  1117. case WCD_CLSH_STATE_EAR:
  1118. case WCD_CLSH_STATE_HPHL:
  1119. case WCD_CLSH_STATE_HPHR:
  1120. case WCD_CLSH_STATE_HPH_ST:
  1121. case WCD_CLSH_STATE_LO:
  1122. case WCD_CLSH_STATE_HPHL_EAR:
  1123. case WCD_CLSH_STATE_HPHR_EAR:
  1124. case WCD_CLSH_STATE_HPH_ST_EAR:
  1125. case WCD_CLSH_STATE_HPHL_LO:
  1126. case WCD_CLSH_STATE_HPHR_LO:
  1127. case WCD_CLSH_STATE_HPH_ST_LO:
  1128. case WCD_CLSH_STATE_EAR_LO:
  1129. return true;
  1130. default:
  1131. return false;
  1132. };
  1133. }
  1134. /*
  1135. * Function: wcd_clsh_fsm
  1136. * Params: codec, cdc_clsh_d, req_state, req_type, clsh_event
  1137. * Description:
  1138. * This function handles PRE DAC and POST DAC conditions of different devices
  1139. * and updates class H configuration of different combination of devices
  1140. * based on validity of their states. cdc_clsh_d will contain current
  1141. * class h state information
  1142. */
  1143. void wcd_clsh_fsm(struct snd_soc_codec *codec,
  1144. struct wcd_clsh_cdc_data *cdc_clsh_d,
  1145. u8 clsh_event, u8 req_state,
  1146. int int_mode)
  1147. {
  1148. u8 old_state, new_state;
  1149. char msg0[128], msg1[128];
  1150. switch (clsh_event) {
  1151. case WCD_CLSH_EVENT_PRE_DAC:
  1152. old_state = cdc_clsh_d->state;
  1153. new_state = old_state | req_state;
  1154. if (!wcd_clsh_is_state_valid(new_state)) {
  1155. dev_err(codec->dev,
  1156. "%s: Class-H not a valid new state: %s\n",
  1157. __func__,
  1158. state_to_str(new_state, msg0, sizeof(msg0)));
  1159. return;
  1160. }
  1161. if (new_state == old_state) {
  1162. dev_err(codec->dev,
  1163. "%s: Class-H already in requested state: %s\n",
  1164. __func__,
  1165. state_to_str(new_state, msg0, sizeof(msg0)));
  1166. return;
  1167. }
  1168. cdc_clsh_d->state = new_state;
  1169. wcd_clsh_set_int_mode(cdc_clsh_d, req_state, int_mode);
  1170. (*clsh_state_fp[new_state]) (codec, cdc_clsh_d, req_state,
  1171. CLSH_REQ_ENABLE, int_mode);
  1172. dev_dbg(codec->dev,
  1173. "%s: ClassH state transition from %s to %s\n",
  1174. __func__, state_to_str(old_state, msg0, sizeof(msg0)),
  1175. state_to_str(cdc_clsh_d->state, msg1, sizeof(msg1)));
  1176. break;
  1177. case WCD_CLSH_EVENT_POST_PA:
  1178. old_state = cdc_clsh_d->state;
  1179. new_state = old_state & (~req_state);
  1180. if (new_state < NUM_CLSH_STATES_V2) {
  1181. if (!wcd_clsh_is_state_valid(old_state)) {
  1182. dev_err(codec->dev,
  1183. "%s:Invalid old state:%s\n",
  1184. __func__,
  1185. state_to_str(old_state, msg0,
  1186. sizeof(msg0)));
  1187. return;
  1188. }
  1189. if (new_state == old_state) {
  1190. dev_err(codec->dev,
  1191. "%s: Class-H already in requested state: %s\n",
  1192. __func__,
  1193. state_to_str(new_state, msg0,
  1194. sizeof(msg0)));
  1195. return;
  1196. }
  1197. (*clsh_state_fp[old_state]) (codec, cdc_clsh_d,
  1198. req_state, CLSH_REQ_DISABLE,
  1199. int_mode);
  1200. cdc_clsh_d->state = new_state;
  1201. wcd_clsh_set_int_mode(cdc_clsh_d, req_state, CLS_NONE);
  1202. dev_dbg(codec->dev, "%s: ClassH state transition from %s to %s\n",
  1203. __func__, state_to_str(old_state, msg0,
  1204. sizeof(msg0)),
  1205. state_to_str(cdc_clsh_d->state, msg1,
  1206. sizeof(msg1)));
  1207. }
  1208. break;
  1209. };
  1210. }
  1211. EXPORT_SYMBOL(wcd_clsh_fsm);
  1212. int wcd_clsh_get_clsh_state(struct wcd_clsh_cdc_data *clsh)
  1213. {
  1214. return clsh->state;
  1215. }
  1216. EXPORT_SYMBOL(wcd_clsh_get_clsh_state);
  1217. void wcd_clsh_init(struct wcd_clsh_cdc_data *clsh)
  1218. {
  1219. int i;
  1220. clsh->state = WCD_CLSH_STATE_IDLE;
  1221. for (i = 0; i < NUM_CLSH_STATES_V2; i++)
  1222. clsh_state_fp[i] = wcd_clsh_state_err;
  1223. clsh_state_fp[WCD_CLSH_STATE_EAR] = wcd_clsh_state_ear;
  1224. clsh_state_fp[WCD_CLSH_STATE_HPHL] =
  1225. wcd_clsh_state_hph_l;
  1226. clsh_state_fp[WCD_CLSH_STATE_HPHR] =
  1227. wcd_clsh_state_hph_r;
  1228. clsh_state_fp[WCD_CLSH_STATE_HPH_ST] =
  1229. wcd_clsh_state_hph_st;
  1230. clsh_state_fp[WCD_CLSH_STATE_LO] = wcd_clsh_state_lo;
  1231. clsh_state_fp[WCD_CLSH_STATE_HPHL_EAR] =
  1232. wcd_clsh_state_hph_ear;
  1233. clsh_state_fp[WCD_CLSH_STATE_HPHR_EAR] =
  1234. wcd_clsh_state_hph_ear;
  1235. clsh_state_fp[WCD_CLSH_STATE_HPH_ST_EAR] =
  1236. wcd_clsh_state_hph_ear;
  1237. clsh_state_fp[WCD_CLSH_STATE_HPHL_LO] = wcd_clsh_state_hph_lo;
  1238. clsh_state_fp[WCD_CLSH_STATE_HPHR_LO] = wcd_clsh_state_hph_lo;
  1239. clsh_state_fp[WCD_CLSH_STATE_HPH_ST_LO] =
  1240. wcd_clsh_state_hph_lo;
  1241. clsh_state_fp[WCD_CLSH_STATE_EAR_LO] = wcd_clsh_state_ear_lo;
  1242. /* Set interpolaotr modes to NONE */
  1243. wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_EAR, CLS_NONE);
  1244. wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_HPHL, CLS_NONE);
  1245. wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_HPHR, CLS_NONE);
  1246. wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_LO, CLS_NONE);
  1247. clsh->flyback_users = 0;
  1248. clsh->buck_users = 0;
  1249. clsh->clsh_users = 0;
  1250. }
  1251. EXPORT_SYMBOL(wcd_clsh_init);
  1252. MODULE_DESCRIPTION("WCD9XXX Common Driver");
  1253. MODULE_LICENSE("GPL v2");