1 /* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
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.
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.
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
18 #include <linux/module.h>
19 #include <linux/kernel.h>
20 #include <linux/slab.h>
21 #include <linux/delay.h>
24 #include <linux/init.h>
25 #include <linux/ioport.h>
26 #include <linux/device.h>
27 #include <linux/dma-mapping.h>
31 #include "mddihosti.h"
33 #include <linux/clk.h>
36 struct semaphore mddi_host_mutex
;
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
;
43 mddi_lcd_func_type mddi_lcd
;
45 extern mddi_client_capability_type mddi_client_capability_pkt
;
47 #ifdef FEATURE_MDDI_HITACHI
48 extern void mddi_hitachi_window_adjust(uint16 x1
,
49 uint16 x2
, uint16 y1
, uint16 y2
);
52 extern void mddi_toshiba_lcd_init(void);
54 #ifdef FEATURE_MDDI_S6D0142
55 extern void mddi_s6d0142_lcd_init(void);
56 extern void mddi_s6d0142_window_adjust(uint16 x1
,
60 mddi_llist_done_cb_type done_cb
);
65 if (mddi_host_initialized
)
68 mddi_host_initialized
= TRUE
;
70 sema_init(&mddi_host_mutex
, 1);
72 if (!mddi_host_powered
) {
73 down(&mddi_host_mutex
);
74 mddi_host_init(MDDI_HOST_PRIM
);
75 mddi_host_powered
= TRUE
;
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
;
89 MDDI_MSG_CRIT("Called from ISR context\n");
91 if (!mddi_host_powered
) {
92 MDDI_MSG_ERR("MDDI powered down!\n");
96 down(&mddi_host_mutex
);
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
);
103 /* need to change this to some sort of wait */
104 MDDI_MSG_ERR("Attempting to queue up more than 1 reg read\n");
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;
113 curr_llist_ptr
->next_packet_pointer
= NULL
;
114 curr_llist_ptr
->packet_data_pointer
= NULL
;
115 curr_llist_ptr
->reserved
= 0;
117 regacc_pkt_ptr
= &curr_llist_ptr
->packet_header
.register_pkt
;
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
;
125 /* now adjust pointers */
126 mddi_queue_forward_packets(curr_llist_idx
, curr_llist_idx
, wait
,
128 /* need to check if we can write the pointer or not */
130 up(&mddi_host_mutex
);
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
);
144 printk(KERN_ERR
"%s: failed to wait for completion!\n",
147 printk(KERN_ERR
"%s: Timed out waiting!\n", __func__
);
150 MDDI_MSG_DEBUG("Reg Read value=0x%x\n", *reg_value_ptr
);
153 } /* mddi_host_register_read */
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
;
165 MDDI_MSG_CRIT("Called from ISR context\n");
167 if (!mddi_host_powered
) {
168 MDDI_MSG_ERR("MDDI powered down!\n");
172 down(&mddi_host_mutex
);
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
];
178 curr_llist_ptr
->link_controller_flags
= 1;
179 curr_llist_ptr
->packet_header_count
= 14;
180 curr_llist_ptr
->packet_data_count
= 4;
182 curr_llist_ptr
->next_packet_pointer
= NULL
;
183 curr_llist_ptr
->reserved
= 0;
185 regacc_pkt_ptr
= &curr_llist_ptr
->packet_header
.register_pkt
;
187 regacc_pkt_ptr
->packet_length
= curr_llist_ptr
->packet_header_count
+
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
;
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
);
199 regacc_pkt_ptr
= &curr_llist_dma_ptr
->packet_header
.register_pkt
;
200 curr_llist_ptr
->packet_data_pointer
=
201 (void *)(®acc_pkt_ptr
->register_data_list
);
203 /* now adjust pointers */
204 mddi_queue_forward_packets(curr_llist_idx
, curr_llist_idx
, wait
,
207 up(&mddi_host_mutex
);
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
);
221 printk(KERN_ERR
"%s: failed to wait for completion!\n",
224 printk(KERN_ERR
"%s: Timed out waiting!\n", __func__
);
228 } /* mddi_host_register_write */
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
;
237 MDDI_MSG_CRIT("Called from TASK context\n");
239 if (!mddi_host_powered
) {
240 MDDI_MSG_ERR("MDDI powered down!\n");
244 if (down_trylock(&mddi_host_mutex
) != 0)
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
);
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;
259 curr_llist_ptr
->next_packet_pointer
= NULL
;
260 curr_llist_ptr
->packet_data_pointer
= NULL
;
261 curr_llist_ptr
->reserved
= 0;
263 regacc_pkt_ptr
= &curr_llist_ptr
->packet_header
.register_pkt
;
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
;
271 /* now adjust pointers */
272 mddi_queue_forward_packets(curr_llist_idx
, curr_llist_idx
, FALSE
,
274 /* need to check if we can write the pointer or not */
276 up(&mddi_host_mutex
);
280 } /* mddi_host_register_read */
282 boolean mddi_host_register_write_int
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
;
291 MDDI_MSG_CRIT("Called from TASK context\n");
293 if (!mddi_host_powered
) {
294 MDDI_MSG_ERR("MDDI powered down!\n");
298 if (down_trylock(&mddi_host_mutex
) != 0)
301 curr_llist_idx
= mddi_get_next_free_llist_item(host
, FALSE
);
302 if (curr_llist_idx
== UNASSIGNED_INDEX
) {
303 up(&mddi_host_mutex
);
307 curr_llist_ptr
= &llist_extern
[host
][curr_llist_idx
];
308 curr_llist_dma_ptr
= &llist_dma_extern
[host
][curr_llist_idx
];
310 curr_llist_ptr
->link_controller_flags
= 1;
311 curr_llist_ptr
->packet_header_count
= 14;
312 curr_llist_ptr
->packet_data_count
= 4;
314 curr_llist_ptr
->next_packet_pointer
= NULL
;
315 curr_llist_ptr
->reserved
= 0;
317 regacc_pkt_ptr
= &curr_llist_ptr
->packet_header
.register_pkt
;
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
;
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
));
330 /* now adjust pointers */
331 mddi_queue_forward_packets(curr_llist_idx
, curr_llist_idx
, FALSE
,
333 up(&mddi_host_mutex
);
337 } /* mddi_host_register_write */
339 void mddi_wait(uint16 time_ms
)
344 void mddi_client_lcd_vsync_detected(boolean detected
)
346 if (mddi_lcd
.vsync_detected
)
347 (*mddi_lcd
.vsync_detected
) (detected
);
350 /* extended version of function includes done callback */
351 void mddi_window_adjust_ext(struct msm_fb_data_type
*mfd
,
355 uint16 y2
, mddi_llist_done_cb_type done_cb
)
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
);
364 /* Do nothing then... except avoid lint/compiler warnings */
373 void mddi_window_adjust(struct msm_fb_data_type
*mfd
,
374 uint16 x1
, uint16 x2
, uint16 y1
, uint16 y2
)
376 mddi_window_adjust_ext(mfd
, x1
, x2
, y1
, y2
, NULL
);