mddihost.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. /* Copyright (c) 2008-2009, The Linux Foundation. All rights reserved.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 and
  5. * only version 2 as published by the Free Software Foundation.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. */
  13. #include <linux/module.h>
  14. #include <linux/kernel.h>
  15. #include <linux/slab.h>
  16. #include <linux/delay.h>
  17. #include <linux/mm.h>
  18. #include <linux/fb.h>
  19. #include <linux/init.h>
  20. #include <linux/ioport.h>
  21. #include <linux/device.h>
  22. #include <linux/dma-mapping.h>
  23. #include "msm_fb.h"
  24. #include "mddihost.h"
  25. #include "mddihosti.h"
  26. #include <linux/clk.h>
  27. #include <mach/clk.h>
  28. struct semaphore mddi_host_mutex;
  29. struct clk *mddi_io_clk;
  30. static boolean mddi_host_powered = FALSE;
  31. static boolean mddi_host_initialized = FALSE;
  32. extern uint32 *mddi_reg_read_value_ptr;
  33. mddi_lcd_func_type mddi_lcd;
  34. extern mddi_client_capability_type mddi_client_capability_pkt;
  35. #ifdef MDDI_HOST_WINDOW_WORKAROUND
  36. /* Tables showing number of rows that would cause a packet length
  37. * ending in 0x02, for each number of columns. These tables have
  38. * been generated for MDDI packets that have 16 and 16 bits-per-pixel.
  39. * This is a work-around for MDDI clients that declare a CRC error
  40. * on MDDI packets where ((length & 0x00ff) == 0x02).
  41. */
  42. static uint16 error_vals_16bpp[] = {
  43. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  44. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 0,
  45. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  46. 0, 10, 0, 0, 0, 14, 0, 0, 0, 2, 0, 0, 4, 6, 12, 0,
  47. 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0,
  48. 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 11, 4, 0, 12, 0,
  49. 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0,
  50. 0, 10, 0, 1, 0, 14, 0, 0, 0, 2, 0, 3, 4, 6, 12, 0,
  51. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  52. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 0,
  53. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  54. 0, 10, 0, 0, 0, 14, 0, 0, 0, 2, 0, 0, 4, 6, 12, 0,
  55. 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0,
  56. 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 11, 4, 0, 12, 0,
  57. 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0,
  58. };
  59. static uint16 error_vals_18bpp[] = {
  60. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  61. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  62. 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 14,
  63. 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 9, 0, 0,
  64. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  65. 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 7,
  66. 0, 0, 0, 0, 0, 0, 1, 0, 0, 16, 0, 0, 0, 0, 0, 6,
  67. 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  68. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  69. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  70. 7, 0, 0, 0, 0, 0, 0, 4, 0, 16, 0, 0, 0, 0, 0, 0,
  71. 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,
  72. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  73. 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3,
  74. 0, 7, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 9, 0
  75. };
  76. #endif
  77. #ifdef FEATURE_MDDI_HITACHI
  78. extern void mddi_hitachi_window_adjust(uint16 x1,
  79. uint16 x2, uint16 y1, uint16 y2);
  80. #endif
  81. extern void mddi_toshiba_lcd_init(void);
  82. #ifdef FEATURE_MDDI_S6D0142
  83. extern void mddi_s6d0142_lcd_init(void);
  84. extern void mddi_s6d0142_window_adjust(uint16 x1,
  85. uint16 x2,
  86. uint16 y1,
  87. uint16 y2,
  88. mddi_llist_done_cb_type done_cb);
  89. #endif
  90. void mddi_init(void)
  91. {
  92. if (mddi_host_initialized)
  93. return;
  94. mddi_host_initialized = TRUE;
  95. sema_init(&mddi_host_mutex, 1);
  96. if (!mddi_host_powered) {
  97. down(&mddi_host_mutex);
  98. mddi_host_init(MDDI_HOST_PRIM);
  99. mddi_host_powered = TRUE;
  100. up(&mddi_host_mutex);
  101. mdelay(10);
  102. }
  103. }
  104. int mddi_host_register_read(uint32 reg_addr,
  105. uint32 *reg_value_ptr, boolean wait, mddi_host_type host) {
  106. mddi_linked_list_type *curr_llist_ptr;
  107. mddi_register_access_packet_type *regacc_pkt_ptr;
  108. uint16 curr_llist_idx;
  109. int ret = 0;
  110. if (in_interrupt())
  111. MDDI_MSG_CRIT("Called from ISR context\n");
  112. if (!mddi_host_powered) {
  113. MDDI_MSG_ERR("MDDI powered down!\n");
  114. mddi_init();
  115. }
  116. down(&mddi_host_mutex);
  117. mddi_reg_read_value_ptr = reg_value_ptr;
  118. curr_llist_idx = mddi_get_reg_read_llist_item(host, TRUE);
  119. if (curr_llist_idx == UNASSIGNED_INDEX) {
  120. up(&mddi_host_mutex);
  121. /* need to change this to some sort of wait */
  122. MDDI_MSG_ERR("Attempting to queue up more than 1 reg read\n");
  123. return -EINVAL;
  124. }
  125. curr_llist_ptr = &llist_extern[host][curr_llist_idx];
  126. curr_llist_ptr->link_controller_flags = 0x11;
  127. curr_llist_ptr->packet_header_count = 14;
  128. curr_llist_ptr->packet_data_count = 0;
  129. curr_llist_ptr->next_packet_pointer = NULL;
  130. curr_llist_ptr->packet_data_pointer = NULL;
  131. curr_llist_ptr->reserved = 0;
  132. regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
  133. regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count;
  134. regacc_pkt_ptr->packet_type = 146; /* register access packet */
  135. regacc_pkt_ptr->bClient_ID = 0;
  136. regacc_pkt_ptr->read_write_info = 0x8001;
  137. regacc_pkt_ptr->register_address = reg_addr;
  138. /* now adjust pointers */
  139. mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, wait,
  140. NULL, host);
  141. /* need to check if we can write the pointer or not */
  142. up(&mddi_host_mutex);
  143. if (wait) {
  144. int wait_ret;
  145. mddi_linked_list_notify_type *llist_notify_ptr;
  146. llist_notify_ptr = &llist_extern_notify[host][curr_llist_idx];
  147. wait_ret = wait_for_completion_timeout(
  148. &(llist_notify_ptr->done_comp), 5 * HZ);
  149. if (wait_ret <= 0)
  150. ret = -EBUSY;
  151. if (wait_ret < 0)
  152. printk(KERN_ERR "%s: failed to wait for completion!\n",
  153. __func__);
  154. else if (!wait_ret)
  155. printk(KERN_ERR "%s: Timed out waiting!\n", __func__);
  156. if (!ret && (mddi_reg_read_value_ptr == reg_value_ptr) &&
  157. (*reg_value_ptr == -EBUSY)) {
  158. printk(KERN_ERR "%s - failed to get data from client",
  159. __func__);
  160. mddi_reg_read_value_ptr = NULL;
  161. ret = -EBUSY;
  162. }
  163. }
  164. MDDI_MSG_DEBUG("Reg Read value=0x%x\n", *reg_value_ptr);
  165. return ret;
  166. } /* mddi_host_register_read */
  167. int mddi_host_register_write(uint32 reg_addr,
  168. uint32 reg_val, enum mddi_data_packet_size_type packet_size,
  169. boolean wait, mddi_llist_done_cb_type done_cb, mddi_host_type host) {
  170. mddi_linked_list_type *curr_llist_ptr;
  171. mddi_linked_list_type *curr_llist_dma_ptr;
  172. mddi_register_access_packet_type *regacc_pkt_ptr;
  173. uint16 curr_llist_idx;
  174. int ret = 0;
  175. if (in_interrupt())
  176. MDDI_MSG_CRIT("Called from ISR context\n");
  177. if (!mddi_host_powered) {
  178. MDDI_MSG_ERR("MDDI powered down!\n");
  179. mddi_init();
  180. }
  181. down(&mddi_host_mutex);
  182. curr_llist_idx = mddi_get_next_free_llist_item(host, TRUE);
  183. curr_llist_ptr = &llist_extern[host][curr_llist_idx];
  184. curr_llist_dma_ptr = &llist_dma_extern[host][curr_llist_idx];
  185. curr_llist_ptr->link_controller_flags = 1;
  186. curr_llist_ptr->packet_header_count = 14;
  187. curr_llist_ptr->packet_data_count = 4;
  188. curr_llist_ptr->next_packet_pointer = NULL;
  189. curr_llist_ptr->reserved = 0;
  190. regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
  191. regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count +
  192. (uint16)packet_size;
  193. regacc_pkt_ptr->packet_type = 146; /* register access packet */
  194. regacc_pkt_ptr->bClient_ID = 0;
  195. regacc_pkt_ptr->read_write_info = 0x0001;
  196. regacc_pkt_ptr->register_address = reg_addr;
  197. regacc_pkt_ptr->register_data_list[0] = reg_val;
  198. MDDI_MSG_DEBUG("Reg Access write reg=0x%x, value=0x%x\n",
  199. regacc_pkt_ptr->register_address,
  200. regacc_pkt_ptr->register_data_list[0]);
  201. regacc_pkt_ptr = &curr_llist_dma_ptr->packet_header.register_pkt;
  202. curr_llist_ptr->packet_data_pointer =
  203. (void *)(&regacc_pkt_ptr->register_data_list[0]);
  204. /* now adjust pointers */
  205. mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, wait,
  206. done_cb, host);
  207. up(&mddi_host_mutex);
  208. if (wait) {
  209. int wait_ret;
  210. mddi_linked_list_notify_type *llist_notify_ptr;
  211. llist_notify_ptr = &llist_extern_notify[host][curr_llist_idx];
  212. wait_ret = wait_for_completion_timeout(
  213. &(llist_notify_ptr->done_comp), 5 * HZ);
  214. if (wait_ret <= 0)
  215. ret = -EBUSY;
  216. if (wait_ret < 0)
  217. printk(KERN_ERR "%s: failed to wait for completion!\n",
  218. __func__);
  219. else if (!wait_ret)
  220. printk(KERN_ERR "%s: Timed out waiting!\n", __func__);
  221. }
  222. return ret;
  223. } /* mddi_host_register_write */
  224. boolean mddi_host_register_read_int
  225. (uint32 reg_addr, uint32 *reg_value_ptr, mddi_host_type host) {
  226. mddi_linked_list_type *curr_llist_ptr;
  227. mddi_register_access_packet_type *regacc_pkt_ptr;
  228. uint16 curr_llist_idx;
  229. if (!in_interrupt())
  230. MDDI_MSG_CRIT("Called from TASK context\n");
  231. if (!mddi_host_powered) {
  232. MDDI_MSG_ERR("MDDI powered down!\n");
  233. return FALSE;
  234. }
  235. if (down_trylock(&mddi_host_mutex) != 0)
  236. return FALSE;
  237. mddi_reg_read_value_ptr = reg_value_ptr;
  238. curr_llist_idx = mddi_get_reg_read_llist_item(host, FALSE);
  239. if (curr_llist_idx == UNASSIGNED_INDEX) {
  240. up(&mddi_host_mutex);
  241. return FALSE;
  242. }
  243. curr_llist_ptr = &llist_extern[host][curr_llist_idx];
  244. curr_llist_ptr->link_controller_flags = 0x11;
  245. curr_llist_ptr->packet_header_count = 14;
  246. curr_llist_ptr->packet_data_count = 0;
  247. curr_llist_ptr->next_packet_pointer = NULL;
  248. curr_llist_ptr->packet_data_pointer = NULL;
  249. curr_llist_ptr->reserved = 0;
  250. regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
  251. regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count;
  252. regacc_pkt_ptr->packet_type = 146; /* register access packet */
  253. regacc_pkt_ptr->bClient_ID = 0;
  254. regacc_pkt_ptr->read_write_info = 0x8001;
  255. regacc_pkt_ptr->register_address = reg_addr;
  256. /* now adjust pointers */
  257. mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, FALSE,
  258. NULL, host);
  259. /* need to check if we can write the pointer or not */
  260. up(&mddi_host_mutex);
  261. return TRUE;
  262. } /* mddi_host_register_read */
  263. boolean mddi_host_register_write_int
  264. (uint32 reg_addr,
  265. uint32 reg_val, mddi_llist_done_cb_type done_cb, mddi_host_type host) {
  266. mddi_linked_list_type *curr_llist_ptr;
  267. mddi_linked_list_type *curr_llist_dma_ptr;
  268. mddi_register_access_packet_type *regacc_pkt_ptr;
  269. uint16 curr_llist_idx;
  270. if (!in_interrupt())
  271. MDDI_MSG_CRIT("Called from TASK context\n");
  272. if (!mddi_host_powered) {
  273. MDDI_MSG_ERR("MDDI powered down!\n");
  274. return FALSE;
  275. }
  276. if (down_trylock(&mddi_host_mutex) != 0)
  277. return FALSE;
  278. curr_llist_idx = mddi_get_next_free_llist_item(host, FALSE);
  279. if (curr_llist_idx == UNASSIGNED_INDEX) {
  280. up(&mddi_host_mutex);
  281. return FALSE;
  282. }
  283. curr_llist_ptr = &llist_extern[host][curr_llist_idx];
  284. curr_llist_dma_ptr = &llist_dma_extern[host][curr_llist_idx];
  285. curr_llist_ptr->link_controller_flags = 1;
  286. curr_llist_ptr->packet_header_count = 14;
  287. curr_llist_ptr->packet_data_count = 4;
  288. curr_llist_ptr->next_packet_pointer = NULL;
  289. curr_llist_ptr->reserved = 0;
  290. regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
  291. regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count + 4;
  292. regacc_pkt_ptr->packet_type = 146; /* register access packet */
  293. regacc_pkt_ptr->bClient_ID = 0;
  294. regacc_pkt_ptr->read_write_info = 0x0001;
  295. regacc_pkt_ptr->register_address = reg_addr;
  296. regacc_pkt_ptr->register_data_list[0] = reg_val;
  297. regacc_pkt_ptr = &curr_llist_dma_ptr->packet_header.register_pkt;
  298. curr_llist_ptr->packet_data_pointer =
  299. (void *)(&(regacc_pkt_ptr->register_data_list[0]));
  300. /* now adjust pointers */
  301. mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, FALSE,
  302. done_cb, host);
  303. up(&mddi_host_mutex);
  304. return TRUE;
  305. } /* mddi_host_register_write */
  306. void mddi_wait(uint16 time_ms)
  307. {
  308. mdelay(time_ms);
  309. }
  310. void mddi_client_lcd_vsync_detected(boolean detected)
  311. {
  312. if (mddi_lcd.vsync_detected)
  313. (*mddi_lcd.vsync_detected) (detected);
  314. }
  315. /* extended version of function includes done callback */
  316. void mddi_window_adjust_ext(struct msm_fb_data_type *mfd,
  317. uint16 x1,
  318. uint16 x2,
  319. uint16 y1,
  320. uint16 y2, mddi_llist_done_cb_type done_cb)
  321. {
  322. #ifdef FEATURE_MDDI_HITACHI
  323. if (mfd->panel.id == HITACHI)
  324. mddi_hitachi_window_adjust(x1, x2, y1, y2);
  325. #elif defined(FEATURE_MDDI_S6D0142)
  326. if (mfd->panel.id == MDDI_LCD_S6D0142)
  327. mddi_s6d0142_window_adjust(x1, x2, y1, y2, done_cb);
  328. #else
  329. /* Do nothing then... except avoid lint/compiler warnings */
  330. (void)x1;
  331. (void)x2;
  332. (void)y1;
  333. (void)y2;
  334. (void)done_cb;
  335. #endif
  336. }
  337. void mddi_window_adjust(struct msm_fb_data_type *mfd,
  338. uint16 x1, uint16 x2, uint16 y1, uint16 y2)
  339. {
  340. mddi_window_adjust_ext(mfd, x1, x2, y1, y2, NULL);
  341. }
  342. #ifdef MDDI_HOST_WINDOW_WORKAROUND
  343. uint16 mddi_assign_pkt_height(uint16 pkt_width,
  344. uint16 pkt_height, uint16 bpp)
  345. {
  346. uint16 new_pkt_height;
  347. uint16 problem_height = 0;
  348. if (pkt_width <= 240) {
  349. if (bpp == 16)
  350. problem_height = error_vals_16bpp[pkt_width-1];
  351. else if (bpp == 18)
  352. problem_height = error_vals_18bpp[pkt_width-1];
  353. else {
  354. printk(KERN_ERR"Invalid bpp value");
  355. return -EINVAL;
  356. }
  357. }
  358. if (problem_height == pkt_height)
  359. new_pkt_height = problem_height - 1;
  360. else
  361. new_pkt_height = pkt_height;
  362. return new_pkt_height;
  363. }
  364. #endif
  365. #ifdef ENABLE_MDDI_MULTI_READ_WRITE
  366. int mddi_host_register_multiwrite(uint32 reg_addr,
  367. uint32 *value_list_ptr,
  368. uint32 value_count, boolean wait, mddi_llist_done_cb_type done_cb,
  369. mddi_host_type host)
  370. {
  371. mddi_linked_list_type *curr_llist_ptr;
  372. mddi_linked_list_type *curr_llist_dma_ptr;
  373. mddi_register_access_packet_type *regacc_pkt_ptr;
  374. uint16 curr_llist_idx;
  375. int ret = 0;
  376. if (!value_list_ptr || !value_count ||
  377. value_count > MDDI_HOST_MAX_CLIENT_REG_IN_SAME_ADDR) {
  378. MDDI_MSG_ERR("\n Invalid value_list or value_count");
  379. return -EINVAL;
  380. }
  381. if (in_interrupt())
  382. MDDI_MSG_CRIT("Called from ISR context\n");
  383. if (!mddi_host_powered) {
  384. MDDI_MSG_ERR("MDDI powered down!\n");
  385. mddi_init();
  386. }
  387. down(&mddi_host_mutex);
  388. curr_llist_idx = mddi_get_next_free_llist_item(host, TRUE);
  389. curr_llist_ptr = &llist_extern[host][curr_llist_idx];
  390. curr_llist_dma_ptr = &llist_dma_extern[host][curr_llist_idx];
  391. curr_llist_ptr->link_controller_flags = 1;
  392. curr_llist_ptr->packet_header_count = 14;
  393. curr_llist_ptr->packet_data_count =
  394. (uint16)(value_count * 4);
  395. curr_llist_ptr->next_packet_pointer = NULL;
  396. curr_llist_ptr->reserved = 0;
  397. regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
  398. regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count
  399. + curr_llist_ptr->packet_data_count;
  400. regacc_pkt_ptr->packet_type = 146; /* register access packet */
  401. regacc_pkt_ptr->bClient_ID = 0;
  402. regacc_pkt_ptr->read_write_info = value_count;
  403. regacc_pkt_ptr->register_address = reg_addr;
  404. memcpy((void *)&regacc_pkt_ptr->register_data_list[0], value_list_ptr,
  405. curr_llist_ptr->packet_data_count);
  406. regacc_pkt_ptr = &curr_llist_dma_ptr->packet_header.register_pkt;
  407. curr_llist_ptr->packet_data_pointer =
  408. (void *)(&regacc_pkt_ptr->register_data_list[0]);
  409. MDDI_MSG_DEBUG("MultiReg Access write reg=0x%x, value[0]=0x%x\n",
  410. regacc_pkt_ptr->register_address,
  411. regacc_pkt_ptr->register_data_list[0]);
  412. /* now adjust pointers */
  413. mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, wait,
  414. done_cb, host);
  415. up(&mddi_host_mutex);
  416. if (wait) {
  417. int wait_ret;
  418. mddi_linked_list_notify_type *llist_notify_ptr;
  419. llist_notify_ptr = &llist_extern_notify[host][curr_llist_idx];
  420. wait_ret = wait_for_completion_timeout(
  421. &(llist_notify_ptr->done_comp), 5 * HZ);
  422. if (wait_ret <= 0)
  423. ret = -EBUSY;
  424. if (wait_ret < 0)
  425. printk(KERN_ERR "%s: failed to wait for completion!\n",
  426. __func__);
  427. else if (!wait_ret)
  428. printk(KERN_ERR "%s: Timed out waiting!\n", __func__);
  429. }
  430. return ret;
  431. }
  432. int mddi_host_register_multiread(uint32 reg_addr,
  433. uint32 *value_list_ptr, uint32 value_count,
  434. boolean wait, mddi_host_type host) {
  435. mddi_linked_list_type *curr_llist_ptr;
  436. mddi_register_access_packet_type *regacc_pkt_ptr;
  437. uint16 curr_llist_idx;
  438. int ret = 0;
  439. if (!value_list_ptr || !value_count ||
  440. value_count >= MDDI_HOST_MAX_CLIENT_REG_IN_SAME_ADDR) {
  441. MDDI_MSG_ERR("\n Invalid value_list or value_count");
  442. return -EINVAL;
  443. }
  444. if (in_interrupt())
  445. MDDI_MSG_CRIT("Called from ISR context\n");
  446. if (!mddi_host_powered) {
  447. MDDI_MSG_ERR("MDDI powered down!\n");
  448. mddi_init();
  449. }
  450. down(&mddi_host_mutex);
  451. mddi_reg_read_value_ptr = value_list_ptr;
  452. curr_llist_idx = mddi_get_reg_read_llist_item(host, TRUE);
  453. if (curr_llist_idx == UNASSIGNED_INDEX) {
  454. up(&mddi_host_mutex);
  455. /* need to change this to some sort of wait */
  456. MDDI_MSG_ERR("Attempting to queue up more than 1 reg read\n");
  457. return -EINVAL;
  458. }
  459. curr_llist_ptr = &llist_extern[host][curr_llist_idx];
  460. curr_llist_ptr->link_controller_flags = 0x11;
  461. curr_llist_ptr->packet_header_count = 14;
  462. curr_llist_ptr->packet_data_count = 0;
  463. curr_llist_ptr->next_packet_pointer = NULL;
  464. curr_llist_ptr->packet_data_pointer = NULL;
  465. curr_llist_ptr->reserved = 0;
  466. regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
  467. regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count;
  468. regacc_pkt_ptr->packet_type = 146; /* register access packet */
  469. regacc_pkt_ptr->bClient_ID = 0;
  470. regacc_pkt_ptr->read_write_info = 0x8000 | value_count;
  471. regacc_pkt_ptr->register_address = reg_addr;
  472. /* now adjust pointers */
  473. mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, wait,
  474. NULL, host);
  475. /* need to check if we can write the pointer or not */
  476. up(&mddi_host_mutex);
  477. if (wait) {
  478. int wait_ret;
  479. mddi_linked_list_notify_type *llist_notify_ptr;
  480. llist_notify_ptr = &llist_extern_notify[host][curr_llist_idx];
  481. wait_ret = wait_for_completion_timeout(
  482. &(llist_notify_ptr->done_comp), 5 * HZ);
  483. if (wait_ret <= 0)
  484. ret = -EBUSY;
  485. if (wait_ret < 0)
  486. printk(KERN_ERR "%s: failed to wait for completion!\n",
  487. __func__);
  488. else if (!wait_ret)
  489. printk(KERN_ERR "%s: Timed out waiting!\n", __func__);
  490. if (!ret && (mddi_reg_read_value_ptr == value_list_ptr) &&
  491. (*value_list_ptr == -EBUSY)) {
  492. printk(KERN_ERR "%s - failed to get data from client",
  493. __func__);
  494. mddi_reg_read_value_ptr = NULL;
  495. ret = -EBUSY;
  496. }
  497. }
  498. MDDI_MSG_DEBUG("MultiReg Read value[0]=0x%x\n", *value_list_ptr);
  499. return ret;
  500. }
  501. #endif