intel_dp_i2c.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /*
  2. * Copyright © 2009 Keith Packard
  3. *
  4. * Permission to use, copy, modify, distribute, and sell this software and its
  5. * documentation for any purpose is hereby granted without fee, provided that
  6. * the above copyright notice appear in all copies and that both that copyright
  7. * notice and this permission notice appear in supporting documentation, and
  8. * that the name of the copyright holders not be used in advertising or
  9. * publicity pertaining to distribution of the software without specific,
  10. * written prior permission. The copyright holders make no representations
  11. * about the suitability of this software for any purpose. It is provided "as
  12. * is" without express or implied warranty.
  13. *
  14. * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15. * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  16. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17. * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18. * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  19. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  20. * OF THIS SOFTWARE.
  21. */
  22. #include <linux/kernel.h>
  23. #include <linux/module.h>
  24. #include <linux/delay.h>
  25. #include <linux/slab.h>
  26. #include <linux/init.h>
  27. #include <linux/errno.h>
  28. #include <linux/sched.h>
  29. #include <linux/i2c.h>
  30. #include "intel_dp.h"
  31. #include "drmP.h"
  32. /* Run a single AUX_CH I2C transaction, writing/reading data as necessary */
  33. #define MODE_I2C_START 1
  34. #define MODE_I2C_WRITE 2
  35. #define MODE_I2C_READ 4
  36. #define MODE_I2C_STOP 8
  37. static int
  38. i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode,
  39. uint8_t write_byte, uint8_t *read_byte)
  40. {
  41. struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
  42. uint16_t address = algo_data->address;
  43. uint8_t msg[5];
  44. uint8_t reply[2];
  45. int msg_bytes;
  46. int reply_bytes;
  47. int ret;
  48. /* Set up the command byte */
  49. if (mode & MODE_I2C_READ)
  50. msg[0] = AUX_I2C_READ << 4;
  51. else
  52. msg[0] = AUX_I2C_WRITE << 4;
  53. if (!(mode & MODE_I2C_STOP))
  54. msg[0] |= AUX_I2C_MOT << 4;
  55. msg[1] = address >> 8;
  56. msg[2] = address;
  57. switch (mode) {
  58. case MODE_I2C_WRITE:
  59. msg[3] = 0;
  60. msg[4] = write_byte;
  61. msg_bytes = 5;
  62. reply_bytes = 1;
  63. break;
  64. case MODE_I2C_READ:
  65. msg[3] = 0;
  66. msg_bytes = 4;
  67. reply_bytes = 2;
  68. break;
  69. default:
  70. msg_bytes = 3;
  71. reply_bytes = 1;
  72. break;
  73. }
  74. for (;;) {
  75. ret = (*algo_data->aux_ch)(adapter,
  76. msg, msg_bytes,
  77. reply, reply_bytes);
  78. if (ret < 0) {
  79. DRM_DEBUG("aux_ch failed %d\n", ret);
  80. return ret;
  81. }
  82. switch (reply[0] & AUX_I2C_REPLY_MASK) {
  83. case AUX_I2C_REPLY_ACK:
  84. if (mode == MODE_I2C_READ) {
  85. *read_byte = reply[1];
  86. }
  87. return reply_bytes - 1;
  88. case AUX_I2C_REPLY_NACK:
  89. DRM_DEBUG("aux_ch nack\n");
  90. return -EREMOTEIO;
  91. case AUX_I2C_REPLY_DEFER:
  92. DRM_DEBUG("aux_ch defer\n");
  93. udelay(100);
  94. break;
  95. default:
  96. DRM_ERROR("aux_ch invalid reply 0x%02x\n", reply[0]);
  97. return -EREMOTEIO;
  98. }
  99. }
  100. }
  101. /*
  102. * I2C over AUX CH
  103. */
  104. /*
  105. * Send the address. If the I2C link is running, this 'restarts'
  106. * the connection with the new address, this is used for doing
  107. * a write followed by a read (as needed for DDC)
  108. */
  109. static int
  110. i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool reading)
  111. {
  112. struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
  113. int mode = MODE_I2C_START;
  114. int ret;
  115. if (reading)
  116. mode |= MODE_I2C_READ;
  117. else
  118. mode |= MODE_I2C_WRITE;
  119. algo_data->address = address;
  120. algo_data->running = true;
  121. ret = i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL);
  122. return ret;
  123. }
  124. /*
  125. * Stop the I2C transaction. This closes out the link, sending
  126. * a bare address packet with the MOT bit turned off
  127. */
  128. static void
  129. i2c_algo_dp_aux_stop(struct i2c_adapter *adapter, bool reading)
  130. {
  131. struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
  132. int mode = MODE_I2C_STOP;
  133. if (reading)
  134. mode |= MODE_I2C_READ;
  135. else
  136. mode |= MODE_I2C_WRITE;
  137. if (algo_data->running) {
  138. (void) i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL);
  139. algo_data->running = false;
  140. }
  141. }
  142. /*
  143. * Write a single byte to the current I2C address, the
  144. * the I2C link must be running or this returns -EIO
  145. */
  146. static int
  147. i2c_algo_dp_aux_put_byte(struct i2c_adapter *adapter, u8 byte)
  148. {
  149. struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
  150. int ret;
  151. if (!algo_data->running)
  152. return -EIO;
  153. ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_WRITE, byte, NULL);
  154. return ret;
  155. }
  156. /*
  157. * Read a single byte from the current I2C address, the
  158. * I2C link must be running or this returns -EIO
  159. */
  160. static int
  161. i2c_algo_dp_aux_get_byte(struct i2c_adapter *adapter, u8 *byte_ret)
  162. {
  163. struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
  164. int ret;
  165. if (!algo_data->running)
  166. return -EIO;
  167. ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_READ, 0, byte_ret);
  168. return ret;
  169. }
  170. static int
  171. i2c_algo_dp_aux_xfer(struct i2c_adapter *adapter,
  172. struct i2c_msg *msgs,
  173. int num)
  174. {
  175. int ret = 0;
  176. bool reading = false;
  177. int m;
  178. int b;
  179. for (m = 0; m < num; m++) {
  180. u16 len = msgs[m].len;
  181. u8 *buf = msgs[m].buf;
  182. reading = (msgs[m].flags & I2C_M_RD) != 0;
  183. ret = i2c_algo_dp_aux_address(adapter, msgs[m].addr, reading);
  184. if (ret < 0)
  185. break;
  186. if (reading) {
  187. for (b = 0; b < len; b++) {
  188. ret = i2c_algo_dp_aux_get_byte(adapter, &buf[b]);
  189. if (ret < 0)
  190. break;
  191. }
  192. } else {
  193. for (b = 0; b < len; b++) {
  194. ret = i2c_algo_dp_aux_put_byte(adapter, buf[b]);
  195. if (ret < 0)
  196. break;
  197. }
  198. }
  199. if (ret < 0)
  200. break;
  201. }
  202. if (ret >= 0)
  203. ret = num;
  204. i2c_algo_dp_aux_stop(adapter, reading);
  205. DRM_DEBUG("dp_aux_xfer return %d\n", ret);
  206. return ret;
  207. }
  208. static u32
  209. i2c_algo_dp_aux_functionality(struct i2c_adapter *adapter)
  210. {
  211. return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
  212. I2C_FUNC_SMBUS_READ_BLOCK_DATA |
  213. I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
  214. I2C_FUNC_10BIT_ADDR;
  215. }
  216. static const struct i2c_algorithm i2c_dp_aux_algo = {
  217. .master_xfer = i2c_algo_dp_aux_xfer,
  218. .functionality = i2c_algo_dp_aux_functionality,
  219. };
  220. static void
  221. i2c_dp_aux_reset_bus(struct i2c_adapter *adapter)
  222. {
  223. (void) i2c_algo_dp_aux_address(adapter, 0, false);
  224. (void) i2c_algo_dp_aux_stop(adapter, false);
  225. }
  226. static int
  227. i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter)
  228. {
  229. adapter->algo = &i2c_dp_aux_algo;
  230. adapter->retries = 3;
  231. i2c_dp_aux_reset_bus(adapter);
  232. return 0;
  233. }
  234. int
  235. i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
  236. {
  237. int error;
  238. error = i2c_dp_aux_prepare_bus(adapter);
  239. if (error)
  240. return error;
  241. error = i2c_add_adapter(adapter);
  242. return error;
  243. }
  244. EXPORT_SYMBOL(i2c_dp_aux_add_bus);