1
0

pmic.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All rights reserved.
  3. Module Name:
  4. pmic.c
  5. Abstract:
  6. This module implements support for the TWL4030 PMIC that usually
  7. accompanies the TI OMAP4.
  8. Author:
  9. Evan Green 13-Mar-2014
  10. Environment:
  11. Kernel
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <uefifw.h>
  17. #include "../twl6030.h"
  18. #include "../pandafw.h"
  19. //
  20. // ---------------------------------------------------------------- Definitions
  21. //
  22. #define OMAP4_SYSCTRL_PADCONF_CORE_BASE 0x4A100000
  23. #define OMAP4_SYSTEM_CONTROL_PBIASLITE 0x600
  24. #define OMAP4_MMC1_VMODE (1 << 21)
  25. #define OMAP4_MMC1_PBIASLITE_PWRDNZ (1 << 22)
  26. #define OMAP4_MMC1_PWRDNZ (1 << 26)
  27. //
  28. // ------------------------------------------------------ Data Type Definitions
  29. //
  30. //
  31. // ----------------------------------------------- Internal Function Prototypes
  32. //
  33. EFI_STATUS
  34. Omap4Twl6030I2cWrite8 (
  35. UINT8 ChipNumber,
  36. UINT8 Register,
  37. UINT8 Value
  38. );
  39. EFI_STATUS
  40. Omap4Twl6030I2cRead8 (
  41. UINT8 ChipNumber,
  42. UINT8 Register,
  43. UINT8 *Value
  44. );
  45. //
  46. // -------------------------------------------------------------------- Globals
  47. //
  48. //
  49. // ------------------------------------------------------------------ Functions
  50. //
  51. EFI_STATUS
  52. Omap4Twl6030InitializeMmcPower (
  53. VOID
  54. )
  55. /*++
  56. Routine Description:
  57. This routine enables the MMC power rails controlled by the TWL4030.
  58. Arguments:
  59. None.
  60. Return Value:
  61. Status code.
  62. --*/
  63. {
  64. volatile UINT32 *PbiasLite;
  65. EFI_STATUS Status;
  66. VOID *SystemControlBase;
  67. UINT32 Value;
  68. SystemControlBase = (VOID *)OMAP4_SYSCTRL_PADCONF_CORE_BASE;
  69. PbiasLite = SystemControlBase + OMAP4_SYSTEM_CONTROL_PBIASLITE;
  70. Value = *PbiasLite;
  71. Value &= ~(OMAP4_MMC1_PBIASLITE_PWRDNZ | OMAP4_MMC1_PWRDNZ);
  72. *PbiasLite = Value;
  73. //
  74. // Set VMMC1 to 3.00 Volts.
  75. //
  76. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM,
  77. VMMC_CFG_VOLTAGE,
  78. VMMC_VOLTAGE_3V0);
  79. if (EFI_ERROR(Status)) {
  80. return Status;
  81. }
  82. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM, VMMC_CFG_STATE, 0x21);
  83. if (!EFI_ERROR(Status)) {
  84. Value = *PbiasLite;
  85. Value |= OMAP4_MMC1_PBIASLITE_PWRDNZ | OMAP4_MMC1_PWRDNZ |
  86. OMAP4_MMC1_VMODE;
  87. *PbiasLite = Value;
  88. }
  89. return Status;
  90. }
  91. EFI_STATUS
  92. Omap4Twl6030InitializeRtc (
  93. VOID
  94. )
  95. /*++
  96. Routine Description:
  97. This routine enables the RTC controlled by the TWL4030.
  98. Arguments:
  99. None.
  100. Return Value:
  101. Status code.
  102. --*/
  103. {
  104. EFI_STATUS Status;
  105. UINT8 Value;
  106. //
  107. // Write to the RTC control register to start the counter ticking if it
  108. // isn't already.
  109. //
  110. Value = TWL6030_RTC_CONTROL_RUN;
  111. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM, TWL6030_RTC_CONTROL, Value);
  112. return Status;
  113. }
  114. EFI_STATUS
  115. Omap4Twl6030ReadRtc (
  116. EFI_TIME *Time
  117. )
  118. /*++
  119. Routine Description:
  120. This routine reads the current time from the TWL6030.
  121. Arguments:
  122. Time - Supplies a pointer where the time is returned on success.
  123. Return Value:
  124. Status code.
  125. --*/
  126. {
  127. EFI_STATUS Status;
  128. UINT8 Value;
  129. //
  130. // Read and clear the power up status and alarm bits.
  131. //
  132. Status = Omap4Twl6030I2cRead8(TWL6030_CHIP_PM,
  133. TWL6030_RTC_STATUS,
  134. &Value);
  135. if (EFI_ERROR(Status)) {
  136. return Status;
  137. }
  138. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM, TWL6030_RTC_STATUS, Value);
  139. if (EFI_ERROR(Status)) {
  140. return Status;
  141. }
  142. //
  143. // Write a zero and then a one to snap the current time into the shadow
  144. // registers.
  145. //
  146. Value = TWL6030_RTC_CONTROL_READ_SHADOWED | TWL6030_RTC_CONTROL_RUN;
  147. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM,
  148. TWL6030_RTC_CONTROL,
  149. Value);
  150. if (EFI_ERROR(Status)) {
  151. return Status;
  152. }
  153. Value |= TWL6030_RTC_CONTROL_GET_TIME;
  154. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM,
  155. TWL6030_RTC_CONTROL,
  156. Value);
  157. if (EFI_ERROR(Status)) {
  158. return Status;
  159. }
  160. Status = Omap4Twl6030I2cRead8(TWL6030_CHIP_PM, TWL6030_RTC_SECONDS, &Value);
  161. if (EFI_ERROR(Status)) {
  162. return Status;
  163. }
  164. Time->Second = EFI_BCD_TO_BINARY(Value);
  165. Status = Omap4Twl6030I2cRead8(TWL6030_CHIP_PM, TWL6030_RTC_MINUTES, &Value);
  166. if (EFI_ERROR(Status)) {
  167. return Status;
  168. }
  169. Time->Minute = EFI_BCD_TO_BINARY(Value);
  170. Status = Omap4Twl6030I2cRead8(TWL6030_CHIP_PM, TWL6030_RTC_HOURS, &Value);
  171. if (EFI_ERROR(Status)) {
  172. return Status;
  173. }
  174. Time->Hour = EFI_BCD_TO_BINARY(Value);
  175. Status = Omap4Twl6030I2cRead8(TWL6030_CHIP_PM, TWL6030_RTC_DAYS, &Value);
  176. if (EFI_ERROR(Status)) {
  177. return Status;
  178. }
  179. Time->Day = EFI_BCD_TO_BINARY(Value);
  180. Status = Omap4Twl6030I2cRead8(TWL6030_CHIP_PM, TWL6030_RTC_MONTHS, &Value);
  181. if (EFI_ERROR(Status)) {
  182. return Status;
  183. }
  184. Time->Month = EFI_BCD_TO_BINARY(Value);
  185. Status = Omap4Twl6030I2cRead8(TWL6030_CHIP_PM, TWL6030_RTC_YEARS, &Value);
  186. if (EFI_ERROR(Status)) {
  187. return Status;
  188. }
  189. Time->Year = EFI_BCD_TO_BINARY(Value) + 2000;
  190. Time->Nanosecond = 0;
  191. Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;
  192. Time->Daylight = 0;
  193. return EFI_SUCCESS;
  194. }
  195. EFI_STATUS
  196. Omap4Twl6030ReadRtcWakeupTime (
  197. BOOLEAN *Enabled,
  198. BOOLEAN *Pending,
  199. EFI_TIME *Time
  200. )
  201. /*++
  202. Routine Description:
  203. This routine reads the wake alarm time from the TWL6030.
  204. Arguments:
  205. Enabled - Supplies a pointer where a boolean will be returned indicating if
  206. the wake time interrupt is enabled.
  207. Pending - Supplies a pointer where a boolean will be returned indicating if
  208. the wake alarm interrupt is pending and requires service.
  209. Time - Supplies a pointer where the time is returned on success.
  210. Return Value:
  211. Status code.
  212. --*/
  213. {
  214. EFI_STATUS Status;
  215. UINT8 Value;
  216. *Enabled = FALSE;
  217. *Pending = FALSE;
  218. Status = Omap4Twl6030I2cRead8(TWL6030_CHIP_PM,
  219. TWL6030_RTC_INTERRUPTS,
  220. &Value);
  221. if (EFI_ERROR(Status)) {
  222. return Status;
  223. }
  224. if ((Value & TWL6030_RTC_INTERRUPT_ALARM) != 0) {
  225. *Enabled = TRUE;
  226. }
  227. Status = Omap4Twl6030I2cRead8(TWL6030_CHIP_PM, TWL6030_RTC_STATUS, &Value);
  228. if (EFI_ERROR(Status)) {
  229. return Status;
  230. }
  231. if ((Value & TWL6030_RTC_STATUS_ALARM) != 0) {
  232. *Pending = TRUE;
  233. }
  234. Status = Omap4Twl6030I2cRead8(TWL6030_CHIP_PM,
  235. TWL6030_RTC_ALARM_SECONDS,
  236. &Value);
  237. if (EFI_ERROR(Status)) {
  238. return Status;
  239. }
  240. Time->Second = EFI_BCD_TO_BINARY(Value);
  241. Status = Omap4Twl6030I2cRead8(TWL6030_CHIP_PM,
  242. TWL6030_RTC_ALARM_MINUTES,
  243. &Value);
  244. if (EFI_ERROR(Status)) {
  245. return Status;
  246. }
  247. Time->Minute = EFI_BCD_TO_BINARY(Value);
  248. Status = Omap4Twl6030I2cRead8(TWL6030_CHIP_PM,
  249. TWL6030_RTC_ALARM_HOURS,
  250. &Value);
  251. if (EFI_ERROR(Status)) {
  252. return Status;
  253. }
  254. Time->Hour = EFI_BCD_TO_BINARY(Value);
  255. Status = Omap4Twl6030I2cRead8(TWL6030_CHIP_PM,
  256. TWL6030_RTC_ALARM_DAYS,
  257. &Value);
  258. if (EFI_ERROR(Status)) {
  259. return Status;
  260. }
  261. Time->Day = EFI_BCD_TO_BINARY(Value);
  262. Status = Omap4Twl6030I2cRead8(TWL6030_CHIP_PM,
  263. TWL6030_RTC_ALARM_MONTHS,
  264. &Value);
  265. if (EFI_ERROR(Status)) {
  266. return Status;
  267. }
  268. Time->Month = EFI_BCD_TO_BINARY(Value);
  269. Status = Omap4Twl6030I2cRead8(TWL6030_CHIP_PM,
  270. TWL6030_RTC_ALARM_YEARS,
  271. &Value);
  272. if (EFI_ERROR(Status)) {
  273. return Status;
  274. }
  275. Time->Year = EFI_BCD_TO_BINARY(Value) + 2000;
  276. Time->Nanosecond = 0;
  277. Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;
  278. Time->Daylight = 0;
  279. return EFI_SUCCESS;
  280. }
  281. EFI_STATUS
  282. Omap4Twl6030WriteRtc (
  283. EFI_TIME *Time
  284. )
  285. /*++
  286. Routine Description:
  287. This routine writes the current time to the TWL6030.
  288. Arguments:
  289. Time - Supplies a pointer to the new time to set.
  290. Return Value:
  291. Status code.
  292. --*/
  293. {
  294. EFI_STATUS Status;
  295. UINT8 Value;
  296. //
  297. // Stop the clock while programming.
  298. //
  299. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM, TWL6030_RTC_CONTROL, 0);
  300. if (EFI_ERROR(Status)) {
  301. return Status;
  302. }
  303. Value = EFI_BINARY_TO_BCD(Time->Second);
  304. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM, TWL6030_RTC_SECONDS, Value);
  305. if (EFI_ERROR(Status)) {
  306. return Status;
  307. }
  308. Value = EFI_BINARY_TO_BCD(Time->Minute);
  309. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM, TWL6030_RTC_MINUTES, Value);
  310. if (EFI_ERROR(Status)) {
  311. return Status;
  312. }
  313. Value = EFI_BINARY_TO_BCD(Time->Hour);
  314. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM, TWL6030_RTC_HOURS, Value);
  315. if (EFI_ERROR(Status)) {
  316. return Status;
  317. }
  318. Value = EFI_BINARY_TO_BCD(Time->Day);
  319. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM, TWL6030_RTC_DAYS, Value);
  320. if (EFI_ERROR(Status)) {
  321. return Status;
  322. }
  323. Value = EFI_BINARY_TO_BCD(Time->Month);
  324. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM, TWL6030_RTC_MONTHS, Value);
  325. if (EFI_ERROR(Status)) {
  326. return Status;
  327. }
  328. if (Time->Year < 2000) {
  329. Value = EFI_BINARY_TO_BCD(Time->Year - 1900);
  330. } else {
  331. Value = EFI_BINARY_TO_BCD(Time->Year - 2000);
  332. }
  333. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM, TWL6030_RTC_YEARS, Value);
  334. if (EFI_ERROR(Status)) {
  335. return Status;
  336. }
  337. //
  338. // Fire the clock back up.
  339. //
  340. Value = TWL6030_RTC_CONTROL_RUN;
  341. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM, TWL6030_RTC_CONTROL, Value);
  342. if (EFI_ERROR(Status)) {
  343. return Status;
  344. }
  345. return Status;
  346. }
  347. EFI_STATUS
  348. Omap4Twl6030WriteRtcWakeupTime (
  349. BOOLEAN Enable,
  350. EFI_TIME *Time
  351. )
  352. /*++
  353. Routine Description:
  354. This routine writes the alarm time to the TWL6030.
  355. Arguments:
  356. Enable - Supplies a boolean enabling or disabling the wakeup timer.
  357. Time - Supplies an optional pointer to the time to set. This parameter is
  358. only optional if the enable parameter is FALSE.
  359. Return Value:
  360. Status code.
  361. --*/
  362. {
  363. UINT8 Interrupts;
  364. EFI_STATUS Status;
  365. UINT8 Value;
  366. //
  367. // Clear the interrupt first.
  368. //
  369. Status = Omap4Twl6030I2cRead8(TWL6030_CHIP_PM,
  370. TWL6030_RTC_INTERRUPTS,
  371. &Interrupts);
  372. if (EFI_ERROR(Status)) {
  373. return Status;
  374. }
  375. Interrupts &= ~TWL6030_RTC_INTERRUPT_ALARM;
  376. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM,
  377. TWL6030_RTC_INTERRUPTS,
  378. Interrupts);
  379. if (EFI_ERROR(Status)) {
  380. return Status;
  381. }
  382. if (Enable == FALSE) {
  383. return Status;
  384. }
  385. if (Time == NULL) {
  386. return EFI_INVALID_PARAMETER;
  387. }
  388. //
  389. // Program the new time.
  390. //
  391. Value = EFI_BINARY_TO_BCD(Time->Second);
  392. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM,
  393. TWL6030_RTC_ALARM_SECONDS,
  394. Value);
  395. if (EFI_ERROR(Status)) {
  396. return Status;
  397. }
  398. Value = EFI_BINARY_TO_BCD(Time->Minute);
  399. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM,
  400. TWL6030_RTC_ALARM_MINUTES,
  401. Value);
  402. if (EFI_ERROR(Status)) {
  403. return Status;
  404. }
  405. Value = EFI_BINARY_TO_BCD(Time->Hour);
  406. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM,
  407. TWL6030_RTC_ALARM_HOURS,
  408. Value);
  409. if (EFI_ERROR(Status)) {
  410. return Status;
  411. }
  412. Value = EFI_BINARY_TO_BCD(Time->Day);
  413. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM,
  414. TWL6030_RTC_ALARM_DAYS,
  415. Value);
  416. if (EFI_ERROR(Status)) {
  417. return Status;
  418. }
  419. Value = EFI_BINARY_TO_BCD(Time->Month);
  420. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM,
  421. TWL6030_RTC_ALARM_MONTHS,
  422. Value);
  423. if (EFI_ERROR(Status)) {
  424. return Status;
  425. }
  426. if (Time->Year < 2000) {
  427. Value = EFI_BINARY_TO_BCD(Time->Year - 1900);
  428. } else {
  429. Value = EFI_BINARY_TO_BCD(Time->Year - 2000);
  430. }
  431. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM,
  432. TWL6030_RTC_ALARM_YEARS,
  433. Value);
  434. if (EFI_ERROR(Status)) {
  435. return Status;
  436. }
  437. //
  438. // Enable the interrupt.
  439. //
  440. Interrupts |= TWL6030_RTC_INTERRUPT_ALARM;
  441. Status = Omap4Twl6030I2cWrite8(TWL6030_CHIP_PM,
  442. TWL6030_RTC_INTERRUPTS,
  443. Interrupts);
  444. if (EFI_ERROR(Status)) {
  445. return Status;
  446. }
  447. return Status;
  448. }
  449. //
  450. // --------------------------------------------------------- Internal Functions
  451. //
  452. EFI_STATUS
  453. Omap4Twl6030I2cWrite8 (
  454. UINT8 ChipNumber,
  455. UINT8 Register,
  456. UINT8 Value
  457. )
  458. /*++
  459. Routine Description:
  460. This routine writes a register on the TWL6030.
  461. Arguments:
  462. ChipNumber - Supplies the device address of the TWL4030 on the I2C bus.
  463. Register - Supplies the register number to write.
  464. Value - Supplies the register value.
  465. Return Value:
  466. Status code.
  467. --*/
  468. {
  469. return EfipOmapI2cWrite(ChipNumber, Register, 1, &Value, 1);
  470. }
  471. EFI_STATUS
  472. Omap4Twl6030I2cRead8 (
  473. UINT8 ChipNumber,
  474. UINT8 Register,
  475. UINT8 *Value
  476. )
  477. /*++
  478. Routine Description:
  479. This routine reads a register on the TWL6030.
  480. Arguments:
  481. ChipNumber - Supplies the device address of the TWL4030 on the I2C bus.
  482. Register - Supplies the register number to write.
  483. Value - Supplies a pointer where the read value will be returned.
  484. Return Value:
  485. Status code.
  486. --*/
  487. {
  488. return EfipOmapI2cRead(ChipNumber, Register, 1, Value, 1);
  489. }