wcd9xxx-rst.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
  3. */
  4. #include <linux/kernel.h>
  5. #include <linux/device.h>
  6. #include <linux/regmap.h>
  7. #include <linux/delay.h>
  8. #include <asoc/core.h>
  9. #include <asoc/pdata.h>
  10. #include "wcd9xxx-utils.h"
  11. #include "wcd9335_registers.h"
  12. #include "wcd9335_irq.h"
  13. #include <asoc/wcd934x_registers.h>
  14. #include "wcd934x/wcd934x_irq.h"
  15. /* wcd9335 interrupt table */
  16. static const struct intr_data wcd9335_intr_table[] = {
  17. {WCD9XXX_IRQ_SLIMBUS, false},
  18. {WCD9335_IRQ_MBHC_SW_DET, true},
  19. {WCD9335_IRQ_MBHC_BUTTON_PRESS_DET, true},
  20. {WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET, true},
  21. {WCD9335_IRQ_MBHC_ELECT_INS_REM_DET, true},
  22. {WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET, true},
  23. {WCD9335_IRQ_FLL_LOCK_LOSS, false},
  24. {WCD9335_IRQ_HPH_PA_CNPL_COMPLETE, false},
  25. {WCD9335_IRQ_HPH_PA_CNPR_COMPLETE, false},
  26. {WCD9335_IRQ_EAR_PA_CNP_COMPLETE, false},
  27. {WCD9335_IRQ_LINE_PA1_CNP_COMPLETE, false},
  28. {WCD9335_IRQ_LINE_PA2_CNP_COMPLETE, false},
  29. {WCD9335_IRQ_LINE_PA3_CNP_COMPLETE, false},
  30. {WCD9335_IRQ_LINE_PA4_CNP_COMPLETE, false},
  31. {WCD9335_IRQ_HPH_PA_OCPL_FAULT, false},
  32. {WCD9335_IRQ_HPH_PA_OCPR_FAULT, false},
  33. {WCD9335_IRQ_EAR_PA_OCP_FAULT, false},
  34. {WCD9335_IRQ_SOUNDWIRE, false},
  35. {WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE, false},
  36. {WCD9335_IRQ_RCO_ERROR, false},
  37. {WCD9335_IRQ_SVA_ERROR, false},
  38. {WCD9335_IRQ_MAD_AUDIO, false},
  39. {WCD9335_IRQ_MAD_BEACON, false},
  40. {WCD9335_IRQ_SVA_OUTBOX1, true},
  41. {WCD9335_IRQ_SVA_OUTBOX2, true},
  42. {WCD9335_IRQ_MAD_ULTRASOUND, false},
  43. {WCD9335_IRQ_VBAT_ATTACK, false},
  44. {WCD9335_IRQ_VBAT_RESTORE, false},
  45. };
  46. static const struct intr_data wcd934x_intr_table[] = {
  47. {WCD9XXX_IRQ_SLIMBUS, false},
  48. {WCD934X_IRQ_MBHC_SW_DET, true},
  49. {WCD934X_IRQ_MBHC_BUTTON_PRESS_DET, true},
  50. {WCD934X_IRQ_MBHC_BUTTON_RELEASE_DET, true},
  51. {WCD934X_IRQ_MBHC_ELECT_INS_REM_DET, true},
  52. {WCD934X_IRQ_MBHC_ELECT_INS_REM_LEG_DET, true},
  53. {WCD934X_IRQ_MISC, false},
  54. {WCD934X_IRQ_HPH_PA_CNPL_COMPLETE, false},
  55. {WCD934X_IRQ_HPH_PA_CNPR_COMPLETE, false},
  56. {WCD934X_IRQ_EAR_PA_CNP_COMPLETE, false},
  57. {WCD934X_IRQ_LINE_PA1_CNP_COMPLETE, false},
  58. {WCD934X_IRQ_LINE_PA2_CNP_COMPLETE, false},
  59. {WCD934X_IRQ_SLNQ_ANALOG_ERROR, false},
  60. {WCD934X_IRQ_RESERVED_3, false},
  61. {WCD934X_IRQ_HPH_PA_OCPL_FAULT, false},
  62. {WCD934X_IRQ_HPH_PA_OCPR_FAULT, false},
  63. {WCD934X_IRQ_EAR_PA_OCP_FAULT, false},
  64. {WCD934X_IRQ_SOUNDWIRE, false},
  65. {WCD934X_IRQ_VDD_DIG_RAMP_COMPLETE, false},
  66. {WCD934X_IRQ_RCO_ERROR, false},
  67. {WCD934X_IRQ_CPE_ERROR, false},
  68. {WCD934X_IRQ_MAD_AUDIO, false},
  69. {WCD934X_IRQ_MAD_BEACON, false},
  70. {WCD934X_IRQ_CPE1_INTR, true},
  71. {WCD934X_IRQ_RESERVED_4, false},
  72. {WCD934X_IRQ_MAD_ULTRASOUND, false},
  73. {WCD934X_IRQ_VBAT_ATTACK, false},
  74. {WCD934X_IRQ_VBAT_RESTORE, false},
  75. };
  76. /*
  77. * wcd9335_bring_down: Bringdown WCD Codec
  78. *
  79. * @wcd9xxx: Pointer to wcd9xxx structure
  80. *
  81. * Returns 0 for success or negative error code for failure
  82. */
  83. static int wcd9335_bring_down(struct wcd9xxx *wcd9xxx)
  84. {
  85. if (!wcd9xxx || !wcd9xxx->regmap)
  86. return -EINVAL;
  87. regmap_write(wcd9xxx->regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
  88. 0x04);
  89. return 0;
  90. }
  91. /*
  92. * wcd9335_bring_up: Bringup WCD Codec
  93. *
  94. * @wcd9xxx: Pointer to the wcd9xxx structure
  95. *
  96. * Returns 0 for success or negative error code for failure
  97. */
  98. static int wcd9335_bring_up(struct wcd9xxx *wcd9xxx)
  99. {
  100. int ret = 0;
  101. int val, byte0;
  102. struct regmap *wcd_regmap;
  103. if (!wcd9xxx)
  104. return -EINVAL;
  105. if (!wcd9xxx->regmap) {
  106. dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n",
  107. __func__);
  108. return -EINVAL;
  109. }
  110. wcd_regmap = wcd9xxx->regmap;
  111. regmap_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0, &val);
  112. regmap_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0, &byte0);
  113. if ((val < 0) || (byte0 < 0)) {
  114. dev_err(wcd9xxx->dev, "%s: tasha codec version detection fail!\n",
  115. __func__);
  116. return -EINVAL;
  117. }
  118. if ((val & 0x80) && (byte0 == 0x0)) {
  119. dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v1.1\n",
  120. __func__);
  121. regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
  122. regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_2, 0xFC);
  123. regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_4, 0x21);
  124. regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
  125. 0x5);
  126. regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
  127. 0x7);
  128. regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
  129. 0x3);
  130. regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
  131. } else if (byte0 == 0x1) {
  132. dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v2.0\n",
  133. __func__);
  134. regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
  135. regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_TEST_2, 0x00);
  136. regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_8, 0x6F);
  137. regmap_write(wcd_regmap, WCD9335_BIAS_VBG_FINE_ADJ, 0x65);
  138. regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
  139. 0x5);
  140. regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
  141. 0x7);
  142. regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
  143. 0x3);
  144. regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
  145. } else if ((byte0 == 0) && (!(val & 0x80))) {
  146. dev_info(wcd9xxx->dev, "%s: wcd9335 codec version is v1.0\n",
  147. __func__);
  148. regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
  149. regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_2, 0xFC);
  150. regmap_write(wcd_regmap, WCD9335_SIDO_SIDO_CCL_4, 0x21);
  151. regmap_write(wcd_regmap, WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
  152. 0x3);
  153. regmap_write(wcd_regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
  154. } else {
  155. dev_err(wcd9xxx->dev, "%s: tasha codec version unknown\n",
  156. __func__);
  157. ret = -EINVAL;
  158. }
  159. return ret;
  160. }
  161. /*
  162. * wcd9335_get_cdc_info: Get codec specific information
  163. *
  164. * @wcd9xxx: pointer to wcd9xxx structure
  165. * @wcd_type: pointer to wcd9xxx_codec_type structure
  166. *
  167. * Returns 0 for success or negative error code for failure
  168. */
  169. static int wcd9335_get_cdc_info(struct wcd9xxx *wcd9xxx,
  170. struct wcd9xxx_codec_type *wcd_type)
  171. {
  172. u16 id_minor, id_major;
  173. struct regmap *wcd_regmap;
  174. int rc, val, version = 0;
  175. if (!wcd9xxx || !wcd_type)
  176. return -EINVAL;
  177. if (!wcd9xxx->regmap) {
  178. dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n",
  179. __func__);
  180. return -EINVAL;
  181. }
  182. wcd_regmap = wcd9xxx->regmap;
  183. rc = regmap_bulk_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0,
  184. (u8 *)&id_minor, sizeof(u16));
  185. if (rc)
  186. return -EINVAL;
  187. rc = regmap_bulk_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE2,
  188. (u8 *)&id_major, sizeof(u16));
  189. if (rc)
  190. return -EINVAL;
  191. dev_info(wcd9xxx->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n",
  192. __func__, id_major, id_minor);
  193. /* Version detection */
  194. if (id_major == TASHA_MAJOR) {
  195. regmap_read(wcd_regmap, WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0,
  196. &val);
  197. version = ((u8)val & 0x80) >> 7;
  198. } else if (id_major == TASHA2P0_MAJOR)
  199. version = 2;
  200. else
  201. dev_err(wcd9xxx->dev, "%s: wcd9335 version unknown (major 0x%x, minor 0x%x)\n",
  202. __func__, id_major, id_minor);
  203. /* Fill codec type info */
  204. wcd_type->id_major = id_major;
  205. wcd_type->id_minor = id_minor;
  206. wcd_type->num_irqs = WCD9335_NUM_IRQS;
  207. wcd_type->version = version;
  208. wcd_type->slim_slave_type = WCD9XXX_SLIM_SLAVE_ADDR_TYPE_1;
  209. wcd_type->i2c_chip_status = 0x01;
  210. wcd_type->intr_tbl = wcd9335_intr_table;
  211. wcd_type->intr_tbl_size = ARRAY_SIZE(wcd9335_intr_table);
  212. wcd_type->intr_reg[WCD9XXX_INTR_STATUS_BASE] =
  213. WCD9335_INTR_PIN1_STATUS0;
  214. wcd_type->intr_reg[WCD9XXX_INTR_CLEAR_BASE] =
  215. WCD9335_INTR_PIN1_CLEAR0;
  216. wcd_type->intr_reg[WCD9XXX_INTR_MASK_BASE] =
  217. WCD9335_INTR_PIN1_MASK0;
  218. wcd_type->intr_reg[WCD9XXX_INTR_LEVEL_BASE] =
  219. WCD9335_INTR_LEVEL0;
  220. wcd_type->intr_reg[WCD9XXX_INTR_CLR_COMMIT] =
  221. WCD9335_INTR_CLR_COMMIT;
  222. return rc;
  223. }
  224. /*
  225. * wcd934x_bring_down: Bringdown WCD Codec
  226. *
  227. * @wcd9xxx: Pointer to wcd9xxx structure
  228. *
  229. * Returns 0 for success or negative error code for failure
  230. */
  231. static int wcd934x_bring_down(struct wcd9xxx *wcd9xxx)
  232. {
  233. if (!wcd9xxx || !wcd9xxx->regmap)
  234. return -EINVAL;
  235. regmap_write(wcd9xxx->regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
  236. 0x04);
  237. return 0;
  238. }
  239. /*
  240. * wcd934x_bring_up: Bringup WCD Codec
  241. *
  242. * @wcd9xxx: Pointer to the wcd9xxx structure
  243. *
  244. * Returns 0 for success or negative error code for failure
  245. */
  246. static int wcd934x_bring_up(struct wcd9xxx *wcd9xxx)
  247. {
  248. struct regmap *wcd_regmap;
  249. if (!wcd9xxx)
  250. return -EINVAL;
  251. if (!wcd9xxx->regmap) {
  252. dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null!\n",
  253. __func__);
  254. return -EINVAL;
  255. }
  256. wcd_regmap = wcd9xxx->regmap;
  257. regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x01);
  258. regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_A_STARTUP, 0x19);
  259. regmap_write(wcd_regmap, WCD934X_SIDO_NEW_VOUT_D_STARTUP, 0x15);
  260. /* Add 1msec delay for VOUT to settle */
  261. usleep_range(1000, 1100);
  262. regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5);
  263. regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7);
  264. regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x3);
  265. regmap_write(wcd_regmap, WCD934X_CODEC_RPM_RST_CTL, 0x7);
  266. regmap_write(wcd_regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
  267. return 0;
  268. }
  269. /*
  270. * wcd934x_get_cdc_info: Get codec specific information
  271. *
  272. * @wcd9xxx: pointer to wcd9xxx structure
  273. * @wcd_type: pointer to wcd9xxx_codec_type structure
  274. *
  275. * Returns 0 for success or negative error code for failure
  276. */
  277. static int wcd934x_get_cdc_info(struct wcd9xxx *wcd9xxx,
  278. struct wcd9xxx_codec_type *wcd_type)
  279. {
  280. u16 id_minor, id_major;
  281. struct regmap *wcd_regmap;
  282. int rc, version = -1;
  283. if (!wcd9xxx || !wcd_type)
  284. return -EINVAL;
  285. if (!wcd9xxx->regmap) {
  286. dev_err(wcd9xxx->dev, "%s: wcd9xxx regmap is null\n", __func__);
  287. return -EINVAL;
  288. }
  289. wcd_regmap = wcd9xxx->regmap;
  290. rc = regmap_bulk_read(wcd_regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0,
  291. (u8 *)&id_minor, sizeof(u16));
  292. if (rc)
  293. return -EINVAL;
  294. rc = regmap_bulk_read(wcd_regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE2,
  295. (u8 *)&id_major, sizeof(u16));
  296. if (rc)
  297. return -EINVAL;
  298. dev_info(wcd9xxx->dev, "%s: wcd9xxx chip id major 0x%x, minor 0x%x\n",
  299. __func__, id_major, id_minor);
  300. if (id_major != TAVIL_MAJOR)
  301. goto version_unknown;
  302. /*
  303. * As fine version info cannot be retrieved before tavil probe.
  304. * Assign coarse versions for possible future use before tavil probe.
  305. */
  306. if (id_minor == cpu_to_le16(0))
  307. version = TAVIL_VERSION_1_0;
  308. else if (id_minor == cpu_to_le16(0x01))
  309. version = TAVIL_VERSION_1_1;
  310. version_unknown:
  311. if (version < 0)
  312. dev_err(wcd9xxx->dev, "%s: wcd934x version unknown\n",
  313. __func__);
  314. /* Fill codec type info */
  315. wcd_type->id_major = id_major;
  316. wcd_type->id_minor = id_minor;
  317. wcd_type->num_irqs = WCD934X_NUM_IRQS;
  318. wcd_type->version = version;
  319. wcd_type->slim_slave_type = WCD9XXX_SLIM_SLAVE_ADDR_TYPE_1;
  320. wcd_type->i2c_chip_status = 0x01;
  321. wcd_type->intr_tbl = wcd934x_intr_table;
  322. wcd_type->intr_tbl_size = ARRAY_SIZE(wcd934x_intr_table);
  323. wcd_type->intr_reg[WCD9XXX_INTR_STATUS_BASE] =
  324. WCD934X_INTR_PIN1_STATUS0;
  325. wcd_type->intr_reg[WCD9XXX_INTR_CLEAR_BASE] =
  326. WCD934X_INTR_PIN1_CLEAR0;
  327. wcd_type->intr_reg[WCD9XXX_INTR_MASK_BASE] =
  328. WCD934X_INTR_PIN1_MASK0;
  329. wcd_type->intr_reg[WCD9XXX_INTR_LEVEL_BASE] =
  330. WCD934X_INTR_LEVEL0;
  331. wcd_type->intr_reg[WCD9XXX_INTR_CLR_COMMIT] =
  332. WCD934X_INTR_CLR_COMMIT;
  333. return rc;
  334. }
  335. codec_bringdown_fn wcd9xxx_bringdown_fn(int type)
  336. {
  337. codec_bringdown_fn cdc_bdown_fn;
  338. switch (type) {
  339. case WCD934X:
  340. cdc_bdown_fn = wcd934x_bring_down;
  341. break;
  342. case WCD9335:
  343. cdc_bdown_fn = wcd9335_bring_down;
  344. break;
  345. default:
  346. cdc_bdown_fn = NULL;
  347. break;
  348. }
  349. return cdc_bdown_fn;
  350. }
  351. codec_bringup_fn wcd9xxx_bringup_fn(int type)
  352. {
  353. codec_bringup_fn cdc_bup_fn;
  354. switch (type) {
  355. case WCD934X:
  356. cdc_bup_fn = wcd934x_bring_up;
  357. break;
  358. case WCD9335:
  359. cdc_bup_fn = wcd9335_bring_up;
  360. break;
  361. default:
  362. cdc_bup_fn = NULL;
  363. break;
  364. }
  365. return cdc_bup_fn;
  366. }
  367. codec_type_fn wcd9xxx_get_codec_info_fn(int type)
  368. {
  369. codec_type_fn cdc_type_fn;
  370. switch (type) {
  371. case WCD934X:
  372. cdc_type_fn = wcd934x_get_cdc_info;
  373. break;
  374. case WCD9335:
  375. cdc_type_fn = wcd9335_get_cdc_info;
  376. break;
  377. default:
  378. cdc_type_fn = NULL;
  379. break;
  380. }
  381. return cdc_type_fn;
  382. }