BaseGpioExpanderLib.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. /** @file
  2. Support for IO expander TCA6424.
  3. Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include <Library/GpioExpanderLib.h>
  7. #include <Library/I2cAccessLib.h>
  8. //
  9. // Addresses of registers inside expander
  10. //
  11. GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mInputRegister[3] = {0x0,0x1,0x2};
  12. GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mOutputRegister[3] = {0x4,0x5,0x6};
  13. GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mConfigRegister[3] = {0xC,0xD,0xE};
  14. GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mPolarityRegister[3] = {0x8,0x9,0xA};
  15. #define PCH_SERIAL_IO_I2C4 4
  16. #define TCA6424_I2C_ADDRESS 0x22
  17. #define PINS_PER_REGISTER 8
  18. #define GPIO_EXP_PIN_DIRECTION_OUT 1
  19. #define GPIO_EXP_PIN_DIRECTION_IN 0
  20. #define GPIO_EXP_PIN_POLARITY_NORMAL 0
  21. #define GPIO_EXP_PIN_POLARITY_INVERTED 1
  22. #define GPIO_EXP_SET_OUTPUT 0
  23. #define GPIO_EXP_SET_DIR 1
  24. #define GPIO_EXP_GET_INPUT 2
  25. #define GPIO_EXP_SET_POLARITY 3
  26. #define AUTO_INCREMENT 0x80
  27. /**
  28. Returns the Controller on which GPIO expander is present.
  29. This function returns the Controller value
  30. @param[out] Controller Pointer to a Controller value on
  31. which I2C expander is configured.
  32. @retval EFI_SUCCESS non.
  33. **/
  34. EFI_STATUS
  35. GpioExpGetController (
  36. OUT UINT8 *Controller
  37. )
  38. {
  39. *Controller = PCH_SERIAL_IO_I2C4;
  40. return EFI_SUCCESS;
  41. }
  42. /**
  43. Returns the data from register value giving in the input.
  44. This function is to get the data from the Expander
  45. Registers by following the I2C Protocol communication
  46. @param[in] Bar0 Bar address of the SerialIo Controller
  47. @param[in] Address Expander Value with in the Contoller
  48. @param[in] Register Address of Input/Output/Configure/Polarity
  49. registers with in the Expander
  50. @retval UINT8 Value returned from the register
  51. **/
  52. UINT8
  53. GpioExpGetRegister (
  54. IN UINTN Bar0,
  55. IN UINT8 Address,
  56. IN UINT8 Register
  57. )
  58. {
  59. EFI_STATUS Status;
  60. UINT8 WriBuf[1];
  61. UINT8 ReBuf[1] = {0};
  62. WriBuf[0] = Register;
  63. Status = I2cWriteRead( Bar0, TCA6424_I2C_ADDRESS+Address, 1, WriBuf, 1, ReBuf, WAIT_1_SECOND);
  64. return ReBuf[0];
  65. }
  66. /**
  67. Set the input register to a give value mentioned in the function.
  68. This function is to Programm the data value to the Expander
  69. Register by following the I2C Protocol communication.
  70. @param[in] Bar0 Bar address of the SerialIo Controller
  71. @param[in] Address Expander Value with in the Contoller
  72. @param[in] Register Address of Input/Output/Configure/Polarity
  73. registers with in the Expander
  74. @param[in] Value Value to set in the mentioned the register
  75. **/
  76. VOID
  77. GpioExpSetRegister (
  78. IN UINTN Bar0,
  79. IN UINT8 Address,
  80. IN UINT8 Register,
  81. IN UINT8 Value
  82. )
  83. {
  84. EFI_STATUS Status;
  85. UINT8 WriBuf[2];
  86. WriBuf[0] = Register;
  87. WriBuf[1] = Value;
  88. Status = I2cWriteRead( Bar0, TCA6424_I2C_ADDRESS+Address, 2, WriBuf, 0, NULL, WAIT_1_SECOND);
  89. }
  90. /**
  91. Set the input register to a give value mentioned in the function.
  92. This function is to update the status of the Gpio Expander
  93. pin based on the input Operation value of the caller.This
  94. function calculates the exact address of the register with
  95. the help of the Register Bank
  96. @param[in] Controller SerialIo Controller value
  97. @param[in] Expander Expander Value with in the Contoller
  98. @param[in] Pin Pin with in the Expnader Value
  99. @param[in] Value none
  100. @param[in] Operation Type of operation (Setoutput/Setdirection
  101. /Getinput/Setpolarity)
  102. @retval UINT8 Final Value returned from the register
  103. **/
  104. UINT8
  105. GpioExpDecodeRegAccess (
  106. IN UINT8 Controller,
  107. IN UINT8 Expander,
  108. IN UINT8 Pin,
  109. IN UINT8 Value,
  110. IN UINT8 Operation
  111. )
  112. {
  113. UINT8* RegisterBank;
  114. UINT8 OldValue;
  115. UINT8 NewValue;
  116. UINT8 RegisterAddress;
  117. UINT8 PinNumber;
  118. UINT8 ReturnValue = 0;
  119. DEBUG ((DEBUG_INFO, "GpioExpDecodeRegAccess() %x:%x:%x:%x:%x\n", Controller, Expander, Pin, Value, Operation));
  120. ASSERT(Controller<6);
  121. ASSERT(Expander<2);
  122. ASSERT(Pin<24);
  123. ASSERT(Value<2);
  124. ASSERT(Operation<4);
  125. //
  126. // Find the register Address value based on the OPeration
  127. //
  128. switch(Operation) {
  129. case GPIO_EXP_SET_OUTPUT:
  130. RegisterBank = mOutputRegister;
  131. break;
  132. case GPIO_EXP_SET_DIR:
  133. RegisterBank = mConfigRegister;
  134. break;
  135. case GPIO_EXP_GET_INPUT:
  136. RegisterBank = mInputRegister;
  137. break;
  138. case GPIO_EXP_SET_POLARITY:
  139. RegisterBank = mPolarityRegister;
  140. break;
  141. default:
  142. ASSERT(FALSE);
  143. return 0;
  144. }
  145. //
  146. // Each bit of register represents each Pin
  147. // calaulate the register address and Pinnumber(offset with in register)
  148. //
  149. if (Pin >= 24) {
  150. //
  151. // Avoid out-of-bound usage of RegisterBank
  152. //
  153. return 0;
  154. }
  155. RegisterAddress = RegisterBank[(Pin/PINS_PER_REGISTER)];
  156. PinNumber = Pin%PINS_PER_REGISTER;
  157. OldValue = GpioExpGetRegister(FindSerialIoBar(Controller, 0), Expander, RegisterAddress);
  158. //
  159. // If it to get the data ,just returned otherwise mark the input value and write the register
  160. //
  161. if (Operation == GPIO_EXP_GET_INPUT) {
  162. ReturnValue = 0x1 & (OldValue>>PinNumber);
  163. } else {
  164. NewValue = OldValue;
  165. NewValue &= ~(BIT0<<PinNumber);
  166. NewValue |= (Value<<PinNumber);
  167. if(NewValue!=OldValue) {
  168. GpioExpSetRegister(FindSerialIoBar(Controller, 0), Expander, RegisterAddress, NewValue);
  169. }
  170. }
  171. return ReturnValue;
  172. }
  173. /**
  174. Set the Output value for the given Expander Gpio pin.
  175. This function is to Set the Output value for the GPIO
  176. Pin within the giving Expander.
  177. @param[in] Expander Expander Value with in the Contoller
  178. @param[in] Pin Pin with in the Expnader Value
  179. @param[in] Value none
  180. **/
  181. VOID
  182. GpioExpSetOutput (
  183. IN UINT8 Expander,
  184. IN UINT8 Pin,
  185. IN UINT8 Value
  186. )
  187. {
  188. UINT8 Controller;
  189. if(!EFI_ERROR(GpioExpGetController(&Controller))) {
  190. GpioExpDecodeRegAccess(Controller,Expander,Pin,Value,GPIO_EXP_SET_OUTPUT);
  191. }
  192. }
  193. /**
  194. Set the Direction value for the given Expander Gpio pin.
  195. This function is to Set the direction value for the GPIO
  196. Pin within the giving Expander.
  197. @param[in] Expander Expander Value with in the Contoller
  198. @param[in] Pin Pin with in the Expnader Value
  199. @param[in] Value none
  200. **/
  201. VOID
  202. GpioExpSetDirection (
  203. IN UINT8 Expander,
  204. IN UINT8 Pin,
  205. IN UINT8 Value
  206. )
  207. {
  208. UINT8 Controller;
  209. if(!EFI_ERROR(GpioExpGetController(&Controller))) {
  210. GpioExpDecodeRegAccess(Controller,Expander,Pin,Value,GPIO_EXP_SET_DIR);
  211. }
  212. }
  213. /**
  214. Get the input value for the given Expander Gpio pin.
  215. This function is to get the input value for the GPIO
  216. Pin within the giving Expander.
  217. @param[in] Expander Expander Value with in the Contoller
  218. @param[in] Pin Pin with in the Expnader Value
  219. @retval UINT8 Final Value returned from the register
  220. **/
  221. UINT8
  222. GpioExpGetInput (
  223. IN UINT8 Expander,
  224. IN UINT8 Pin
  225. )
  226. {
  227. UINT8 Controller;
  228. if(!EFI_ERROR(GpioExpGetController(&Controller))) {
  229. return GpioExpDecodeRegAccess(Controller,Expander,Pin,0,GPIO_EXP_GET_INPUT);
  230. }
  231. return 0;
  232. }
  233. /**
  234. Configures all registers of a single IO Expander in one go.
  235. @param[in] Expander Expander number (0/1)
  236. @param[in] Direction Bit-encoded direction values. BIT0 is for pin0, etc. 0=output, 1=input
  237. @param[in] Polarity Bit-encoded input inversion values. BIT0 is for pin0, etc. 0=normal, 1=inversion
  238. @param[in] Output Bit-encoded output state, ignores polarity, only applicable if direction=INPUT. BIT0 is for pin0, etc. 0=low, 1=high
  239. **/
  240. VOID
  241. GpioExpBulkConfig (
  242. IN UINT8 Expander,
  243. IN UINT32 Direction,
  244. IN UINT32 Polarity,
  245. IN UINT32 Output
  246. )
  247. {
  248. UINT8 WriteBuf[4];
  249. UINT8 Controller;
  250. GpioExpGetController(&Controller);
  251. WriteBuf[0] = mOutputRegister[0] + AUTO_INCREMENT;
  252. WriteBuf[1] = Output & 0xFF;
  253. WriteBuf[2] = (Output>>8) & 0xFF;
  254. WriteBuf[3] = (Output>>16) & 0xFF;
  255. I2cWriteRead( FindSerialIoBar(Controller,0), TCA6424_I2C_ADDRESS+Expander, 4, WriteBuf, 0, NULL, WAIT_1_SECOND);
  256. WriteBuf[0] = mPolarityRegister[0] + AUTO_INCREMENT;
  257. WriteBuf[1] = Polarity & 0xFF;
  258. WriteBuf[2] = (Polarity>>8) & 0xFF;
  259. WriteBuf[3] = (Polarity>>16) & 0xFF;
  260. I2cWriteRead( FindSerialIoBar(Controller,0), TCA6424_I2C_ADDRESS+Expander, 4, WriteBuf, 0, NULL, WAIT_1_SECOND);
  261. WriteBuf[0] = mConfigRegister[0] + AUTO_INCREMENT;
  262. WriteBuf[1] = Direction & 0xFF;
  263. WriteBuf[2] = (Direction>>8) & 0xFF;
  264. WriteBuf[3] = (Direction>>16) & 0xFF;
  265. I2cWriteRead( FindSerialIoBar(Controller,0), TCA6424_I2C_ADDRESS+Expander, 4, WriteBuf, 0, NULL, WAIT_1_SECOND);
  266. }