BaseGpioExpanderLib.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. /** @file
  2. Support for IO expander TCA6424.
  3. Copyright (c) 2020, 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. UINT8 WriBuf[1];
  60. UINT8 ReBuf[1] = {0};
  61. WriBuf[0] = Register;
  62. I2cWriteRead (Bar0, TCA6424_I2C_ADDRESS + Address, 1, WriBuf, 1, ReBuf, WAIT_1_SECOND);
  63. return ReBuf[0];
  64. }
  65. /**
  66. Set the input register to a give value mentioned in the function.
  67. This function is to Programm the data value to the Expander
  68. Register by following the I2C Protocol communication.
  69. @param[in] Bar0 Bar address of the SerialIo Controller
  70. @param[in] Address Expander Value with in the Contoller
  71. @param[in] Register Address of Input/Output/Configure/Polarity
  72. registers with in the Expander
  73. @param[in] Value Value to set in the mentioned the register
  74. **/
  75. VOID
  76. GpioExpSetRegister (
  77. IN UINTN Bar0,
  78. IN UINT8 Address,
  79. IN UINT8 Register,
  80. IN UINT8 Value
  81. )
  82. {
  83. UINT8 WriBuf[2];
  84. WriBuf[0] = Register;
  85. WriBuf[1] = Value;
  86. I2cWriteRead (Bar0, TCA6424_I2C_ADDRESS + Address, 2, WriBuf, 0, NULL, WAIT_1_SECOND);
  87. }
  88. /**
  89. Set the input register to a give value mentioned in the function.
  90. This function is to update the status of the Gpio Expander
  91. pin based on the input Operation value of the caller.This
  92. function calculates the exact address of the register with
  93. the help of the Register Bank
  94. @param[in] Controller SerialIo Controller value
  95. @param[in] Expander Expander Value with in the Contoller
  96. @param[in] Pin Pin with in the Expnader Value
  97. @param[in] Value none
  98. @param[in] Operation Type of operation (Setoutput/Setdirection
  99. /Getinput/Setpolarity)
  100. @retval UINT8 Final Value returned from the register
  101. **/
  102. UINT8
  103. GpioExpDecodeRegAccess (
  104. IN UINT8 Controller,
  105. IN UINT8 Expander,
  106. IN UINT8 Pin,
  107. IN UINT8 Value,
  108. IN UINT8 Operation
  109. )
  110. {
  111. UINT8* RegisterBank;
  112. UINT8 OldValue;
  113. UINT8 NewValue;
  114. UINT8 RegisterAddress;
  115. UINT8 PinNumber;
  116. UINT8 ReturnValue = 0;
  117. DEBUG ((DEBUG_INFO, "GpioExpDecodeRegAccess() %x:%x:%x:%x:%x\n", Controller, Expander, Pin, Value, Operation));
  118. ASSERT(Controller<6);
  119. ASSERT(Expander<2);
  120. ASSERT(Pin<24);
  121. ASSERT(Value<2);
  122. ASSERT(Operation<4);
  123. //
  124. // Find the register Address value based on the OPeration
  125. //
  126. switch(Operation) {
  127. case GPIO_EXP_SET_OUTPUT:
  128. RegisterBank = mOutputRegister;
  129. break;
  130. case GPIO_EXP_SET_DIR:
  131. RegisterBank = mConfigRegister;
  132. break;
  133. case GPIO_EXP_GET_INPUT:
  134. RegisterBank = mInputRegister;
  135. break;
  136. case GPIO_EXP_SET_POLARITY:
  137. RegisterBank = mPolarityRegister;
  138. break;
  139. default:
  140. ASSERT(FALSE);
  141. return 0;
  142. }
  143. //
  144. // Each bit of register represents each Pin
  145. // calaulate the register address and Pinnumber(offset with in register)
  146. //
  147. if (Pin >= 24) {
  148. //
  149. // Avoid out-of-bound usage of RegisterBank
  150. //
  151. return 0;
  152. }
  153. RegisterAddress = RegisterBank[(Pin/PINS_PER_REGISTER)];
  154. PinNumber = Pin%PINS_PER_REGISTER;
  155. OldValue = GpioExpGetRegister(FindSerialIoBar(Controller, 0), Expander, RegisterAddress);
  156. //
  157. // If it to get the data ,just returned otherwise mark the input value and write the register
  158. //
  159. if (Operation == GPIO_EXP_GET_INPUT) {
  160. ReturnValue = 0x1 & (OldValue>>PinNumber);
  161. } else {
  162. NewValue = OldValue;
  163. NewValue &= ~(BIT0<<PinNumber);
  164. NewValue |= (Value<<PinNumber);
  165. if(NewValue!=OldValue) {
  166. GpioExpSetRegister(FindSerialIoBar(Controller, 0), Expander, RegisterAddress, NewValue);
  167. }
  168. }
  169. return ReturnValue;
  170. }
  171. /**
  172. Set the Output value for the given Expander Gpio pin.
  173. This function is to Set the Output value for the GPIO
  174. Pin within the giving Expander.
  175. @param[in] Expander Expander Value with in the Contoller
  176. @param[in] Pin Pin with in the Expnader Value
  177. @param[in] Value none
  178. **/
  179. VOID
  180. GpioExpSetOutput (
  181. IN UINT8 Expander,
  182. IN UINT8 Pin,
  183. IN UINT8 Value
  184. )
  185. {
  186. UINT8 Controller;
  187. if(!EFI_ERROR(GpioExpGetController(&Controller))) {
  188. GpioExpDecodeRegAccess(Controller,Expander,Pin,Value,GPIO_EXP_SET_OUTPUT);
  189. }
  190. }
  191. /**
  192. Set the Direction value for the given Expander Gpio pin.
  193. This function is to Set the direction value for the GPIO
  194. Pin within the giving Expander.
  195. @param[in] Expander Expander Value with in the Contoller
  196. @param[in] Pin Pin with in the Expnader Value
  197. @param[in] Value none
  198. **/
  199. VOID
  200. GpioExpSetDirection (
  201. IN UINT8 Expander,
  202. IN UINT8 Pin,
  203. IN UINT8 Value
  204. )
  205. {
  206. UINT8 Controller;
  207. if(!EFI_ERROR(GpioExpGetController(&Controller))) {
  208. GpioExpDecodeRegAccess(Controller,Expander,Pin,Value,GPIO_EXP_SET_DIR);
  209. }
  210. }
  211. /**
  212. Get the input value for the given Expander Gpio pin.
  213. This function is to get the input value for the GPIO
  214. Pin within the giving Expander.
  215. @param[in] Expander Expander Value with in the Contoller
  216. @param[in] Pin Pin with in the Expnader Value
  217. @retval UINT8 Final Value returned from the register
  218. **/
  219. UINT8
  220. GpioExpGetInput (
  221. IN UINT8 Expander,
  222. IN UINT8 Pin
  223. )
  224. {
  225. UINT8 Controller;
  226. if(!EFI_ERROR(GpioExpGetController(&Controller))) {
  227. return GpioExpDecodeRegAccess(Controller,Expander,Pin,0,GPIO_EXP_GET_INPUT);
  228. }
  229. return 0;
  230. }
  231. /**
  232. Configures all registers of a single IO Expander in one go.
  233. @param[in] Expander Expander number (0/1)
  234. @param[in] Direction Bit-encoded direction values. BIT0 is for pin0, etc. 0=output, 1=input
  235. @param[in] Polarity Bit-encoded input inversion values. BIT0 is for pin0, etc. 0=normal, 1=inversion
  236. @param[in] Output Bit-encoded output state, ignores polarity, only applicable if direction=INPUT. BIT0 is for pin0, etc. 0=low, 1=high
  237. **/
  238. VOID
  239. GpioExpBulkConfig (
  240. IN UINT8 Expander,
  241. IN UINT32 Direction,
  242. IN UINT32 Polarity,
  243. IN UINT32 Output
  244. )
  245. {
  246. UINT8 WriteBuf[4];
  247. UINT8 Controller;
  248. GpioExpGetController(&Controller);
  249. WriteBuf[0] = mOutputRegister[0] + AUTO_INCREMENT;
  250. WriteBuf[1] = Output & 0xFF;
  251. WriteBuf[2] = (Output>>8) & 0xFF;
  252. WriteBuf[3] = (Output>>16) & 0xFF;
  253. I2cWriteRead( FindSerialIoBar(Controller,0), TCA6424_I2C_ADDRESS+Expander, 4, WriteBuf, 0, NULL, WAIT_1_SECOND);
  254. WriteBuf[0] = mPolarityRegister[0] + AUTO_INCREMENT;
  255. WriteBuf[1] = Polarity & 0xFF;
  256. WriteBuf[2] = (Polarity>>8) & 0xFF;
  257. WriteBuf[3] = (Polarity>>16) & 0xFF;
  258. I2cWriteRead( FindSerialIoBar(Controller,0), TCA6424_I2C_ADDRESS+Expander, 4, WriteBuf, 0, NULL, WAIT_1_SECOND);
  259. WriteBuf[0] = mConfigRegister[0] + AUTO_INCREMENT;
  260. WriteBuf[1] = Direction & 0xFF;
  261. WriteBuf[2] = (Direction>>8) & 0xFF;
  262. WriteBuf[3] = (Direction>>16) & 0xFF;
  263. I2cWriteRead( FindSerialIoBar(Controller,0), TCA6424_I2C_ADDRESS+Expander, 4, WriteBuf, 0, NULL, WAIT_1_SECOND);
  264. }