wcd9xxx-common-v2.c 40 KB

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