intel_dp_i2c.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  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. /* Run a single AUX_CH I2C transaction, writing/reading data as necessary */
  32. #define MODE_I2C_START 1
  33. #define MODE_I2C_WRITE 2
  34. #define MODE_I2C_READ 4
  35. #define MODE_I2C_STOP 8
  36. static int
  37. i2c_algo_dp_aux_transaction(struct i2c_adapter *adapter, int mode,
  38. uint8_t write_byte, uint8_t *read_byte)
  39. {
  40. struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
  41. uint16_t address = algo_data->address;
  42. uint8_t msg[5];
  43. uint8_t reply[2];
  44. int msg_bytes;
  45. int reply_bytes;
  46. int ret;
  47. /* Set up the command byte */
  48. if (mode & MODE_I2C_READ)
  49. msg[0] = AUX_I2C_READ << 4;
  50. else
  51. msg[0] = AUX_I2C_WRITE << 4;
  52. if (!(mode & MODE_I2C_STOP))
  53. msg[0] |= AUX_I2C_MOT << 4;
  54. msg[1] = address >> 8;
  55. msg[2] = address;
  56. switch (mode) {
  57. case MODE_I2C_WRITE:
  58. msg[3] = 0;
  59. msg[4] = write_byte;
  60. msg_bytes = 5;
  61. reply_bytes = 1;
  62. break;
  63. case MODE_I2C_READ:
  64. msg[3] = 0;
  65. msg_bytes = 4;
  66. reply_bytes = 2;
  67. break;
  68. default:
  69. msg_bytes = 3;
  70. reply_bytes = 1;
  71. break;
  72. }
  73. for (;;) {
  74. ret = (*algo_data->aux_ch)(adapter,
  75. msg, msg_bytes,
  76. reply, reply_bytes);
  77. if (ret < 0) {
  78. printk(KERN_ERR "aux_ch failed %d\n", ret);
  79. return ret;
  80. }
  81. switch (reply[0] & AUX_I2C_REPLY_MASK) {
  82. case AUX_I2C_REPLY_ACK:
  83. if (mode == MODE_I2C_READ) {
  84. *read_byte = reply[1];
  85. }
  86. return reply_bytes - 1;
  87. case AUX_I2C_REPLY_NACK:
  88. printk(KERN_ERR "aux_ch nack\n");
  89. return -EREMOTEIO;
  90. case AUX_I2C_REPLY_DEFER:
  91. printk(KERN_ERR "aux_ch defer\n");
  92. udelay(100);
  93. break;
  94. default:
  95. printk(KERN_ERR "aux_ch invalid reply 0x%02x\n", reply[0]);
  96. return -EREMOTEIO;
  97. }
  98. }
  99. }
  100. /*
  101. * I2C over AUX CH
  102. */
  103. /*
  104. * Send the address. If the I2C link is running, this 'restarts'
  105. * the connection with the new address, this is used for doing
  106. * a write followed by a read (as needed for DDC)
  107. */
  108. static int
  109. i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool reading)
  110. {
  111. struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
  112. int mode = MODE_I2C_START;
  113. int ret;
  114. if (reading)
  115. mode |= MODE_I2C_READ;
  116. else
  117. mode |= MODE_I2C_WRITE;
  118. algo_data->address = address;
  119. algo_data->running = true;
  120. ret = i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL);
  121. return ret;
  122. }
  123. /*
  124. * Stop the I2C transaction. This closes out the link, sending
  125. * a bare address packet with the MOT bit turned off
  126. */
  127. static void
  128. i2c_algo_dp_aux_stop(struct i2c_adapter *adapter, bool reading)
  129. {
  130. struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
  131. int mode = MODE_I2C_STOP;
  132. if (reading)
  133. mode |= MODE_I2C_READ;
  134. else
  135. mode |= MODE_I2C_WRITE;
  136. if (algo_data->running) {
  137. (void) i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL);
  138. algo_data->running = false;
  139. }
  140. }
  141. /*
  142. * Write a single byte to the current I2C address, the
  143. * the I2C link must be running or this returns -EIO
  144. */
  145. static int
  146. i2c_algo_dp_aux_put_byte(struct i2c_adapter *adapter, u8 byte)
  147. {
  148. struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
  149. int ret;
  150. if (!algo_data->running)
  151. return -EIO;
  152. ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_WRITE, byte, NULL);
  153. return ret;
  154. }
  155. /*
  156. * Read a single byte from the current I2C address, the
  157. * I2C link must be running or this returns -EIO
  158. */
  159. static int
  160. i2c_algo_dp_aux_get_byte(struct i2c_adapter *adapter, u8 *byte_ret)
  161. {
  162. struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
  163. int ret;
  164. if (!algo_data->running)
  165. return -EIO;
  166. ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_READ, 0, byte_ret);
  167. return ret;
  168. }
  169. static int
  170. i2c_algo_dp_aux_xfer(struct i2c_adapter *adapter,
  171. struct i2c_msg *msgs,
  172. int num)
  173. {
  174. int ret = 0;
  175. bool reading = false;
  176. int m;
  177. int b;
  178. for (m = 0; m < num; m++) {
  179. u16 len = msgs[m].len;
  180. u8 *buf = msgs[m].buf;
  181. reading = (msgs[m].flags & I2C_M_RD) != 0;
  182. ret = i2c_algo_dp_aux_address(adapter, msgs[m].addr, reading);
  183. if (ret < 0)
  184. break;
  185. if (reading) {
  186. for (b = 0; b < len; b++) {
  187. ret = i2c_algo_dp_aux_get_byte(adapter, &buf[b]);
  188. if (ret < 0)
  189. break;
  190. }
  191. } else {
  192. for (b = 0; b < len; b++) {
  193. ret = i2c_algo_dp_aux_put_byte(adapter, buf[b]);
  194. if (ret < 0)
  195. break;
  196. }
  197. }
  198. if (ret < 0)
  199. break;
  200. }
  201. if (ret >= 0)
  202. ret = num;
  203. i2c_algo_dp_aux_stop(adapter, reading);
  204. printk(KERN_ERR "dp_aux_xfer return %d\n", ret);
  205. return ret;
  206. }
  207. static u32
  208. i2c_algo_dp_aux_functionality(struct i2c_adapter *adapter)
  209. {
  210. return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
  211. I2C_FUNC_SMBUS_READ_BLOCK_DATA |
  212. I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
  213. I2C_FUNC_10BIT_ADDR;
  214. }
  215. static const struct i2c_algorithm i2c_dp_aux_algo = {
  216. .master_xfer = i2c_algo_dp_aux_xfer,
  217. .functionality = i2c_algo_dp_aux_functionality,
  218. };
  219. static void
  220. i2c_dp_aux_reset_bus(struct i2c_adapter *adapter)
  221. {
  222. (void) i2c_algo_dp_aux_address(adapter, 0, false);
  223. (void) i2c_algo_dp_aux_stop(adapter, false);
  224. }
  225. static int
  226. i2c_dp_aux_prepare_bus(struct i2c_adapter *adapter)
  227. {
  228. adapter->algo = &i2c_dp_aux_algo;
  229. adapter->retries = 3;
  230. i2c_dp_aux_reset_bus(adapter);
  231. return 0;
  232. }
  233. int
  234. i2c_dp_aux_add_bus(struct i2c_adapter *adapter)
  235. {
  236. int error;
  237. error = i2c_dp_aux_prepare_bus(adapter);
  238. if (error)
  239. return error;
  240. error = i2c_add_adapter(adapter);
  241. return error;
  242. }
  243. EXPORT_SYMBOL(i2c_dp_aux_add_bus);