anx9805.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /*
  2. * Copyright 2013 Red Hat Inc.
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17. * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. * OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. * Authors: Ben Skeggs <bskeggs@redhat.com>
  23. */
  24. #define anx9805_pad(p) container_of((p), struct anx9805_pad, base)
  25. #define anx9805_bus(p) container_of((p), struct anx9805_bus, base)
  26. #define anx9805_aux(p) container_of((p), struct anx9805_aux, base)
  27. #include "aux.h"
  28. #include "bus.h"
  29. struct anx9805_pad {
  30. struct nvkm_i2c_pad base;
  31. struct nvkm_i2c_bus *bus;
  32. u8 addr;
  33. };
  34. struct anx9805_bus {
  35. struct nvkm_i2c_bus base;
  36. struct anx9805_pad *pad;
  37. u8 addr;
  38. };
  39. static int
  40. anx9805_bus_xfer(struct nvkm_i2c_bus *base, struct i2c_msg *msgs, int num)
  41. {
  42. struct anx9805_bus *bus = anx9805_bus(base);
  43. struct anx9805_pad *pad = bus->pad;
  44. struct i2c_adapter *adap = &pad->bus->i2c;
  45. struct i2c_msg *msg = msgs;
  46. int ret = -ETIMEDOUT;
  47. int i, j, cnt = num;
  48. u8 seg = 0x00, off = 0x00, tmp;
  49. tmp = nvkm_rdi2cr(adap, pad->addr, 0x07) & ~0x10;
  50. nvkm_wri2cr(adap, pad->addr, 0x07, tmp | 0x10);
  51. nvkm_wri2cr(adap, pad->addr, 0x07, tmp);
  52. nvkm_wri2cr(adap, bus->addr, 0x43, 0x05);
  53. mdelay(5);
  54. while (cnt--) {
  55. if ( (msg->flags & I2C_M_RD) && msg->addr == 0x50) {
  56. nvkm_wri2cr(adap, bus->addr, 0x40, msg->addr << 1);
  57. nvkm_wri2cr(adap, bus->addr, 0x41, seg);
  58. nvkm_wri2cr(adap, bus->addr, 0x42, off);
  59. nvkm_wri2cr(adap, bus->addr, 0x44, msg->len);
  60. nvkm_wri2cr(adap, bus->addr, 0x45, 0x00);
  61. nvkm_wri2cr(adap, bus->addr, 0x43, 0x01);
  62. for (i = 0; i < msg->len; i++) {
  63. j = 0;
  64. while (nvkm_rdi2cr(adap, bus->addr, 0x46) & 0x10) {
  65. mdelay(5);
  66. if (j++ == 32)
  67. goto done;
  68. }
  69. msg->buf[i] = nvkm_rdi2cr(adap, bus->addr, 0x47);
  70. }
  71. } else
  72. if (!(msg->flags & I2C_M_RD)) {
  73. if (msg->addr == 0x50 && msg->len == 0x01) {
  74. off = msg->buf[0];
  75. } else
  76. if (msg->addr == 0x30 && msg->len == 0x01) {
  77. seg = msg->buf[0];
  78. } else
  79. goto done;
  80. } else {
  81. goto done;
  82. }
  83. msg++;
  84. }
  85. ret = num;
  86. done:
  87. nvkm_wri2cr(adap, bus->addr, 0x43, 0x00);
  88. return ret;
  89. }
  90. static const struct nvkm_i2c_bus_func
  91. anx9805_bus_func = {
  92. .xfer = anx9805_bus_xfer,
  93. };
  94. static int
  95. anx9805_bus_new(struct nvkm_i2c_pad *base, int id, u8 drive,
  96. struct nvkm_i2c_bus **pbus)
  97. {
  98. struct anx9805_pad *pad = anx9805_pad(base);
  99. struct anx9805_bus *bus;
  100. int ret;
  101. if (!(bus = kzalloc(sizeof(*bus), GFP_KERNEL)))
  102. return -ENOMEM;
  103. *pbus = &bus->base;
  104. bus->pad = pad;
  105. ret = nvkm_i2c_bus_ctor(&anx9805_bus_func, &pad->base, id, &bus->base);
  106. if (ret)
  107. return ret;
  108. switch (pad->addr) {
  109. case 0x39: bus->addr = 0x3d; break;
  110. case 0x3b: bus->addr = 0x3f; break;
  111. default:
  112. return -ENOSYS;
  113. }
  114. return 0;
  115. }
  116. struct anx9805_aux {
  117. struct nvkm_i2c_aux base;
  118. struct anx9805_pad *pad;
  119. u8 addr;
  120. };
  121. static int
  122. anx9805_aux_xfer(struct nvkm_i2c_aux *base, bool retry,
  123. u8 type, u32 addr, u8 *data, u8 size)
  124. {
  125. struct anx9805_aux *aux = anx9805_aux(base);
  126. struct anx9805_pad *pad = aux->pad;
  127. struct i2c_adapter *adap = &pad->bus->i2c;
  128. int i, ret = -ETIMEDOUT;
  129. u8 buf[16] = {};
  130. u8 tmp;
  131. AUX_DBG(&aux->base, "%02x %05x %d", type, addr, size);
  132. tmp = nvkm_rdi2cr(adap, pad->addr, 0x07) & ~0x04;
  133. nvkm_wri2cr(adap, pad->addr, 0x07, tmp | 0x04);
  134. nvkm_wri2cr(adap, pad->addr, 0x07, tmp);
  135. nvkm_wri2cr(adap, pad->addr, 0xf7, 0x01);
  136. nvkm_wri2cr(adap, aux->addr, 0xe4, 0x80);
  137. if (!(type & 1)) {
  138. memcpy(buf, data, size);
  139. AUX_DBG(&aux->base, "%16ph", buf);
  140. for (i = 0; i < size; i++)
  141. nvkm_wri2cr(adap, aux->addr, 0xf0 + i, buf[i]);
  142. }
  143. nvkm_wri2cr(adap, aux->addr, 0xe5, ((size - 1) << 4) | type);
  144. nvkm_wri2cr(adap, aux->addr, 0xe6, (addr & 0x000ff) >> 0);
  145. nvkm_wri2cr(adap, aux->addr, 0xe7, (addr & 0x0ff00) >> 8);
  146. nvkm_wri2cr(adap, aux->addr, 0xe8, (addr & 0xf0000) >> 16);
  147. nvkm_wri2cr(adap, aux->addr, 0xe9, 0x01);
  148. i = 0;
  149. while ((tmp = nvkm_rdi2cr(adap, aux->addr, 0xe9)) & 0x01) {
  150. mdelay(5);
  151. if (i++ == 32)
  152. goto done;
  153. }
  154. if ((tmp = nvkm_rdi2cr(adap, pad->addr, 0xf7)) & 0x01) {
  155. ret = -EIO;
  156. goto done;
  157. }
  158. if (type & 1) {
  159. for (i = 0; i < size; i++)
  160. buf[i] = nvkm_rdi2cr(adap, aux->addr, 0xf0 + i);
  161. AUX_DBG(&aux->base, "%16ph", buf);
  162. memcpy(data, buf, size);
  163. }
  164. ret = 0;
  165. done:
  166. nvkm_wri2cr(adap, pad->addr, 0xf7, 0x01);
  167. return ret;
  168. }
  169. static int
  170. anx9805_aux_lnk_ctl(struct nvkm_i2c_aux *base,
  171. int link_nr, int link_bw, bool enh)
  172. {
  173. struct anx9805_aux *aux = anx9805_aux(base);
  174. struct anx9805_pad *pad = aux->pad;
  175. struct i2c_adapter *adap = &pad->bus->i2c;
  176. u8 tmp, i;
  177. AUX_DBG(&aux->base, "ANX9805 train %d %02x %d",
  178. link_nr, link_bw, enh);
  179. nvkm_wri2cr(adap, aux->addr, 0xa0, link_bw);
  180. nvkm_wri2cr(adap, aux->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00));
  181. nvkm_wri2cr(adap, aux->addr, 0xa2, 0x01);
  182. nvkm_wri2cr(adap, aux->addr, 0xa8, 0x01);
  183. i = 0;
  184. while ((tmp = nvkm_rdi2cr(adap, aux->addr, 0xa8)) & 0x01) {
  185. mdelay(5);
  186. if (i++ == 100) {
  187. AUX_ERR(&aux->base, "link training timeout");
  188. return -ETIMEDOUT;
  189. }
  190. }
  191. if (tmp & 0x70) {
  192. AUX_ERR(&aux->base, "link training failed");
  193. return -EIO;
  194. }
  195. return 0;
  196. }
  197. static const struct nvkm_i2c_aux_func
  198. anx9805_aux_func = {
  199. .xfer = anx9805_aux_xfer,
  200. .lnk_ctl = anx9805_aux_lnk_ctl,
  201. };
  202. static int
  203. anx9805_aux_new(struct nvkm_i2c_pad *base, int id, u8 drive,
  204. struct nvkm_i2c_aux **pbus)
  205. {
  206. struct anx9805_pad *pad = anx9805_pad(base);
  207. struct anx9805_aux *aux;
  208. int ret;
  209. if (!(aux = kzalloc(sizeof(*aux), GFP_KERNEL)))
  210. return -ENOMEM;
  211. *pbus = &aux->base;
  212. aux->pad = pad;
  213. ret = nvkm_i2c_aux_ctor(&anx9805_aux_func, &pad->base, id, &aux->base);
  214. if (ret)
  215. return ret;
  216. switch (pad->addr) {
  217. case 0x39: aux->addr = 0x38; break;
  218. case 0x3b: aux->addr = 0x3c; break;
  219. default:
  220. return -ENOSYS;
  221. }
  222. return 0;
  223. }
  224. static const struct nvkm_i2c_pad_func
  225. anx9805_pad_func = {
  226. .bus_new_4 = anx9805_bus_new,
  227. .aux_new_6 = anx9805_aux_new,
  228. };
  229. int
  230. anx9805_pad_new(struct nvkm_i2c_bus *bus, int id, u8 addr,
  231. struct nvkm_i2c_pad **ppad)
  232. {
  233. struct anx9805_pad *pad;
  234. if (!(pad = kzalloc(sizeof(*pad), GFP_KERNEL)))
  235. return -ENOMEM;
  236. *ppad = &pad->base;
  237. nvkm_i2c_pad_ctor(&anx9805_pad_func, bus->pad->i2c, id, &pad->base);
  238. pad->bus = bus;
  239. pad->addr = addr;
  240. return 0;
  241. }