Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging-2.6
[pandora-kernel.git] / drivers / staging / msm / mddihost.c
1 /* Copyright (c) 2008-2009, Code Aurora Forum. 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  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17
18 #include <linux/module.h>
19 #include <linux/kernel.h>
20 #include <linux/slab.h>
21 #include <linux/delay.h>
22 #include <linux/mm.h>
23 #include <linux/fb.h>
24 #include <linux/init.h>
25 #include <linux/ioport.h>
26 #include <linux/device.h>
27 #include <linux/dma-mapping.h>
28
29 #include "msm_fb.h"
30 #include "mddihost.h"
31 #include "mddihosti.h"
32
33 #include <linux/clk.h>
34 #include <mach/clk.h>
35
36 struct semaphore mddi_host_mutex;
37
38 struct clk *mddi_io_clk;
39 static boolean mddi_host_powered = FALSE;
40 static boolean mddi_host_initialized = FALSE;
41 extern uint32 *mddi_reg_read_value_ptr;
42
43 mddi_lcd_func_type mddi_lcd;
44
45 extern mddi_client_capability_type mddi_client_capability_pkt;
46
47 #ifdef FEATURE_MDDI_HITACHI
48 extern void mddi_hitachi_window_adjust(uint16 x1,
49                                        uint16 x2, uint16 y1, uint16 y2);
50 #endif
51
52 extern void mddi_toshiba_lcd_init(void);
53
54 #ifdef FEATURE_MDDI_S6D0142
55 extern void mddi_s6d0142_lcd_init(void);
56 extern void mddi_s6d0142_window_adjust(uint16 x1,
57                                        uint16 x2,
58                                        uint16 y1,
59                                        uint16 y2,
60                                        mddi_llist_done_cb_type done_cb);
61 #endif
62
63 void mddi_init(void)
64 {
65         if (mddi_host_initialized)
66                 return;
67
68         mddi_host_initialized = TRUE;
69
70         sema_init(&mddi_host_mutex, 1);
71
72         if (!mddi_host_powered) {
73                 down(&mddi_host_mutex);
74                 mddi_host_init(MDDI_HOST_PRIM);
75                 mddi_host_powered = TRUE;
76                 up(&mddi_host_mutex);
77                 mdelay(10);
78         }
79 }
80
81 int mddi_host_register_read(uint32 reg_addr,
82      uint32 *reg_value_ptr, boolean wait, mddi_host_type host) {
83         mddi_linked_list_type *curr_llist_ptr;
84         mddi_register_access_packet_type *regacc_pkt_ptr;
85         uint16 curr_llist_idx;
86         int ret = 0;
87
88         if (in_interrupt())
89                 MDDI_MSG_CRIT("Called from ISR context\n");
90
91         if (!mddi_host_powered) {
92                 MDDI_MSG_ERR("MDDI powered down!\n");
93                 mddi_init();
94         }
95
96         down(&mddi_host_mutex);
97
98         mddi_reg_read_value_ptr = reg_value_ptr;
99         curr_llist_idx = mddi_get_reg_read_llist_item(host, TRUE);
100         if (curr_llist_idx == UNASSIGNED_INDEX) {
101                 up(&mddi_host_mutex);
102
103                 /* need to change this to some sort of wait */
104                 MDDI_MSG_ERR("Attempting to queue up more than 1 reg read\n");
105                 return -EINVAL;
106         }
107
108         curr_llist_ptr = &llist_extern[host][curr_llist_idx];
109         curr_llist_ptr->link_controller_flags = 0x11;
110         curr_llist_ptr->packet_header_count = 14;
111         curr_llist_ptr->packet_data_count = 0;
112
113         curr_llist_ptr->next_packet_pointer = NULL;
114         curr_llist_ptr->packet_data_pointer = NULL;
115         curr_llist_ptr->reserved = 0;
116
117         regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
118
119         regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count;
120         regacc_pkt_ptr->packet_type = 146;      /* register access packet */
121         regacc_pkt_ptr->bClient_ID = 0;
122         regacc_pkt_ptr->read_write_info = 0x8001;
123         regacc_pkt_ptr->register_address = reg_addr;
124
125         /* now adjust pointers */
126         mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, wait,
127                                    NULL, host);
128         /* need to check if we can write the pointer or not */
129
130         up(&mddi_host_mutex);
131
132         if (wait) {
133                 int wait_ret;
134
135                 mddi_linked_list_notify_type *llist_notify_ptr;
136                 llist_notify_ptr = &llist_extern_notify[host][curr_llist_idx];
137                 wait_ret = wait_for_completion_timeout(
138                                         &(llist_notify_ptr->done_comp), 5 * HZ);
139
140                 if (wait_ret <= 0)
141                         ret = -EBUSY;
142
143                 if (wait_ret < 0)
144                         printk(KERN_ERR "%s: failed to wait for completion!\n",
145                                 __func__);
146                 else if (!wait_ret)
147                         printk(KERN_ERR "%s: Timed out waiting!\n", __func__);
148         }
149
150         MDDI_MSG_DEBUG("Reg Read value=0x%x\n", *reg_value_ptr);
151
152         return ret;
153 }                               /* mddi_host_register_read */
154
155 int mddi_host_register_write(uint32 reg_addr,
156      uint32 reg_val, enum mddi_data_packet_size_type packet_size,
157      boolean wait, mddi_llist_done_cb_type done_cb, mddi_host_type host) {
158         mddi_linked_list_type *curr_llist_ptr;
159         mddi_linked_list_type *curr_llist_dma_ptr;
160         mddi_register_access_packet_type *regacc_pkt_ptr;
161         uint16 curr_llist_idx;
162         int ret = 0;
163
164         if (in_interrupt())
165                 MDDI_MSG_CRIT("Called from ISR context\n");
166
167         if (!mddi_host_powered) {
168                 MDDI_MSG_ERR("MDDI powered down!\n");
169                 mddi_init();
170         }
171
172         down(&mddi_host_mutex);
173
174         curr_llist_idx = mddi_get_next_free_llist_item(host, TRUE);
175         curr_llist_ptr = &llist_extern[host][curr_llist_idx];
176         curr_llist_dma_ptr = &llist_dma_extern[host][curr_llist_idx];
177
178         curr_llist_ptr->link_controller_flags = 1;
179         curr_llist_ptr->packet_header_count = 14;
180         curr_llist_ptr->packet_data_count = 4;
181
182         curr_llist_ptr->next_packet_pointer = NULL;
183         curr_llist_ptr->reserved = 0;
184
185         regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
186
187         regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count +
188                                         (uint16)packet_size;
189         regacc_pkt_ptr->packet_type = 146;      /* register access packet */
190         regacc_pkt_ptr->bClient_ID = 0;
191         regacc_pkt_ptr->read_write_info = 0x0001;
192         regacc_pkt_ptr->register_address = reg_addr;
193         regacc_pkt_ptr->register_data_list = reg_val;
194
195         MDDI_MSG_DEBUG("Reg Access write reg=0x%x, value=0x%x\n",
196                        regacc_pkt_ptr->register_address,
197                        regacc_pkt_ptr->register_data_list);
198
199         regacc_pkt_ptr = &curr_llist_dma_ptr->packet_header.register_pkt;
200         curr_llist_ptr->packet_data_pointer =
201             (void *)(&regacc_pkt_ptr->register_data_list);
202
203         /* now adjust pointers */
204         mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, wait,
205                                    done_cb, host);
206
207         up(&mddi_host_mutex);
208
209         if (wait) {
210                 int wait_ret;
211
212                 mddi_linked_list_notify_type *llist_notify_ptr;
213                 llist_notify_ptr = &llist_extern_notify[host][curr_llist_idx];
214                 wait_ret = wait_for_completion_timeout(
215                                         &(llist_notify_ptr->done_comp), 5 * HZ);
216
217                 if (wait_ret <= 0)
218                         ret = -EBUSY;
219
220                 if (wait_ret < 0)
221                         printk(KERN_ERR "%s: failed to wait for completion!\n",
222                                 __func__);
223                 else if (!wait_ret)
224                         printk(KERN_ERR "%s: Timed out waiting!\n", __func__);
225         }
226
227         return ret;
228 }                               /* mddi_host_register_write */
229
230 boolean mddi_host_register_read_int
231     (uint32 reg_addr, uint32 *reg_value_ptr, mddi_host_type host) {
232         mddi_linked_list_type *curr_llist_ptr;
233         mddi_register_access_packet_type *regacc_pkt_ptr;
234         uint16 curr_llist_idx;
235
236         if (!in_interrupt())
237                 MDDI_MSG_CRIT("Called from TASK context\n");
238
239         if (!mddi_host_powered) {
240                 MDDI_MSG_ERR("MDDI powered down!\n");
241                 return FALSE;
242         }
243
244         if (down_trylock(&mddi_host_mutex) != 0)
245                 return FALSE;
246
247         mddi_reg_read_value_ptr = reg_value_ptr;
248         curr_llist_idx = mddi_get_reg_read_llist_item(host, FALSE);
249         if (curr_llist_idx == UNASSIGNED_INDEX) {
250                 up(&mddi_host_mutex);
251                 return FALSE;
252         }
253
254         curr_llist_ptr = &llist_extern[host][curr_llist_idx];
255         curr_llist_ptr->link_controller_flags = 0x11;
256         curr_llist_ptr->packet_header_count = 14;
257         curr_llist_ptr->packet_data_count = 0;
258
259         curr_llist_ptr->next_packet_pointer = NULL;
260         curr_llist_ptr->packet_data_pointer = NULL;
261         curr_llist_ptr->reserved = 0;
262
263         regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
264
265         regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count;
266         regacc_pkt_ptr->packet_type = 146;      /* register access packet */
267         regacc_pkt_ptr->bClient_ID = 0;
268         regacc_pkt_ptr->read_write_info = 0x8001;
269         regacc_pkt_ptr->register_address = reg_addr;
270
271         /* now adjust pointers */
272         mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, FALSE,
273                                    NULL, host);
274         /* need to check if we can write the pointer or not */
275
276         up(&mddi_host_mutex);
277
278         return TRUE;
279
280 }                               /* mddi_host_register_read */
281
282 boolean mddi_host_register_write_int
283     (uint32 reg_addr,
284      uint32 reg_val, mddi_llist_done_cb_type done_cb, mddi_host_type host) {
285         mddi_linked_list_type *curr_llist_ptr;
286         mddi_linked_list_type *curr_llist_dma_ptr;
287         mddi_register_access_packet_type *regacc_pkt_ptr;
288         uint16 curr_llist_idx;
289
290         if (!in_interrupt())
291                 MDDI_MSG_CRIT("Called from TASK context\n");
292
293         if (!mddi_host_powered) {
294                 MDDI_MSG_ERR("MDDI powered down!\n");
295                 return FALSE;
296         }
297
298         if (down_trylock(&mddi_host_mutex) != 0)
299                 return FALSE;
300
301         curr_llist_idx = mddi_get_next_free_llist_item(host, FALSE);
302         if (curr_llist_idx == UNASSIGNED_INDEX) {
303                 up(&mddi_host_mutex);
304                 return FALSE;
305         }
306
307         curr_llist_ptr = &llist_extern[host][curr_llist_idx];
308         curr_llist_dma_ptr = &llist_dma_extern[host][curr_llist_idx];
309
310         curr_llist_ptr->link_controller_flags = 1;
311         curr_llist_ptr->packet_header_count = 14;
312         curr_llist_ptr->packet_data_count = 4;
313
314         curr_llist_ptr->next_packet_pointer = NULL;
315         curr_llist_ptr->reserved = 0;
316
317         regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
318
319         regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count + 4;
320         regacc_pkt_ptr->packet_type = 146;      /* register access packet */
321         regacc_pkt_ptr->bClient_ID = 0;
322         regacc_pkt_ptr->read_write_info = 0x0001;
323         regacc_pkt_ptr->register_address = reg_addr;
324         regacc_pkt_ptr->register_data_list = reg_val;
325
326         regacc_pkt_ptr = &curr_llist_dma_ptr->packet_header.register_pkt;
327         curr_llist_ptr->packet_data_pointer =
328             (void *)(&(regacc_pkt_ptr->register_data_list));
329
330         /* now adjust pointers */
331         mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, FALSE,
332                                    done_cb, host);
333         up(&mddi_host_mutex);
334
335         return TRUE;
336
337 }                               /* mddi_host_register_write */
338
339 void mddi_wait(uint16 time_ms)
340 {
341         mdelay(time_ms);
342 }
343
344 void mddi_client_lcd_vsync_detected(boolean detected)
345 {
346         if (mddi_lcd.vsync_detected)
347                 (*mddi_lcd.vsync_detected) (detected);
348 }
349
350 /* extended version of function includes done callback */
351 void mddi_window_adjust_ext(struct msm_fb_data_type *mfd,
352                             uint16 x1,
353                             uint16 x2,
354                             uint16 y1,
355                             uint16 y2, mddi_llist_done_cb_type done_cb)
356 {
357 #ifdef FEATURE_MDDI_HITACHI
358         if (mfd->panel.id == HITACHI)
359                 mddi_hitachi_window_adjust(x1, x2, y1, y2);
360 #elif defined(FEATURE_MDDI_S6D0142)
361         if (mfd->panel.id == MDDI_LCD_S6D0142)
362                 mddi_s6d0142_window_adjust(x1, x2, y1, y2, done_cb);
363 #else
364         /* Do nothing then... except avoid lint/compiler warnings */
365         (void)x1;
366         (void)x2;
367         (void)y1;
368         (void)y2;
369         (void)done_cb;
370 #endif
371 }
372
373 void mddi_window_adjust(struct msm_fb_data_type *mfd,
374                         uint16 x1, uint16 x2, uint16 y1, uint16 y2)
375 {
376         mddi_window_adjust_ext(mfd, x1, x2, y1, y2, NULL);
377 }