diff options
author | Tomi Valkeinen <tomi.valkeinen@nokia.com> | 2010-01-12 07:16:41 -0500 |
---|---|---|
committer | Tomi Valkeinen <tomi.valkeinen@nokia.com> | 2010-02-24 07:31:28 -0500 |
commit | 18946f62c6cc8cf051bafca8b7fa72309e8a1067 (patch) | |
tree | f1e33d76a571ebc4580b15c1b7ba1bec8e441cf6 /drivers/video/omap2/dss/dsi.c | |
parent | 446f7bff703f5f82560afde90fb22b7a1d366bbc (diff) |
OMAP: DSS2: move update() and sync()
Move update() and sync() from omap_dss_device to omap_dss_driver.
Also, update was hardcoded to use virtual channel 0. This patch adds a
parameter that specifies the VC.
This is part of a larger patch-set, which moves the control from omapdss
driver to the display driver.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>
Diffstat (limited to 'drivers/video/omap2/dss/dsi.c')
-rw-r--r-- | drivers/video/omap2/dss/dsi.c | 322 |
1 files changed, 115 insertions, 207 deletions
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index b9fa62027f67..203b18bbddae 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c | |||
@@ -31,8 +31,8 @@ | |||
31 | #include <linux/seq_file.h> | 31 | #include <linux/seq_file.h> |
32 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
33 | #include <linux/regulator/consumer.h> | 33 | #include <linux/regulator/consumer.h> |
34 | #include <linux/kthread.h> | ||
35 | #include <linux/wait.h> | 34 | #include <linux/wait.h> |
35 | #include <linux/workqueue.h> | ||
36 | 36 | ||
37 | #include <plat/display.h> | 37 | #include <plat/display.h> |
38 | #include <plat/clock.h> | 38 | #include <plat/clock.h> |
@@ -200,7 +200,6 @@ enum dsi_vc_mode { | |||
200 | }; | 200 | }; |
201 | 201 | ||
202 | struct dsi_update_region { | 202 | struct dsi_update_region { |
203 | bool dirty; | ||
204 | u16 x, y, w, h; | 203 | u16 x, y, w, h; |
205 | struct omap_dss_device *device; | 204 | struct omap_dss_device *device; |
206 | }; | 205 | }; |
@@ -234,18 +233,18 @@ static struct | |||
234 | 233 | ||
235 | struct completion bta_completion; | 234 | struct completion bta_completion; |
236 | 235 | ||
237 | struct task_struct *thread; | 236 | int update_channel; |
238 | wait_queue_head_t waitqueue; | ||
239 | |||
240 | spinlock_t update_lock; | ||
241 | bool framedone_received; | ||
242 | struct dsi_update_region update_region; | 237 | struct dsi_update_region update_region; |
243 | struct dsi_update_region active_update_region; | ||
244 | struct completion update_completion; | ||
245 | 238 | ||
246 | bool te_enabled; | 239 | bool te_enabled; |
247 | bool use_ext_te; | 240 | bool use_ext_te; |
248 | 241 | ||
242 | struct work_struct framedone_work; | ||
243 | void (*framedone_callback)(int, void *); | ||
244 | void *framedone_data; | ||
245 | |||
246 | struct delayed_work framedone_timeout_work; | ||
247 | |||
249 | #ifdef DSI_CATCH_MISSING_TE | 248 | #ifdef DSI_CATCH_MISSING_TE |
250 | struct timer_list te_timer; | 249 | struct timer_list te_timer; |
251 | #endif | 250 | #endif |
@@ -357,9 +356,9 @@ static void dsi_perf_show(const char *name) | |||
357 | 356 | ||
358 | total_us = setup_us + trans_us; | 357 | total_us = setup_us + trans_us; |
359 | 358 | ||
360 | total_bytes = dsi.active_update_region.w * | 359 | total_bytes = dsi.update_region.w * |
361 | dsi.active_update_region.h * | 360 | dsi.update_region.h * |
362 | dsi.active_update_region.device->ctrl.pixel_size / 8; | 361 | dsi.update_region.device->ctrl.pixel_size / 8; |
363 | 362 | ||
364 | printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), " | 363 | printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), " |
365 | "%u bytes, %u kbytes/sec\n", | 364 | "%u bytes, %u kbytes/sec\n", |
@@ -2725,7 +2724,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, | |||
2725 | unsigned packet_len; | 2724 | unsigned packet_len; |
2726 | u32 l; | 2725 | u32 l; |
2727 | bool use_te_trigger; | 2726 | bool use_te_trigger; |
2728 | const unsigned channel = 0; | 2727 | const unsigned channel = dsi.update_channel; |
2729 | /* line buffer is 1024 x 24bits */ | 2728 | /* line buffer is 1024 x 24bits */ |
2730 | /* XXX: for some reason using full buffer size causes considerable TX | 2729 | /* XXX: for some reason using full buffer size causes considerable TX |
2731 | * slowdown with update sizes that fill the whole buffer */ | 2730 | * slowdown with update sizes that fill the whole buffer */ |
@@ -2736,6 +2735,8 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, | |||
2736 | DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n", | 2735 | DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n", |
2737 | x, y, w, h); | 2736 | x, y, w, h); |
2738 | 2737 | ||
2738 | dsi_vc_config_vp(channel); | ||
2739 | |||
2739 | bytespp = dssdev->ctrl.pixel_size / 8; | 2740 | bytespp = dssdev->ctrl.pixel_size / 8; |
2740 | bytespl = w * bytespp; | 2741 | bytespl = w * bytespp; |
2741 | bytespf = bytespl * h; | 2742 | bytespf = bytespl * h; |
@@ -2773,6 +2774,11 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, | |||
2773 | */ | 2774 | */ |
2774 | dispc_disable_sidle(); | 2775 | dispc_disable_sidle(); |
2775 | 2776 | ||
2777 | dsi_perf_mark_start(); | ||
2778 | |||
2779 | schedule_delayed_work(&dsi.framedone_timeout_work, | ||
2780 | msecs_to_jiffies(250)); | ||
2781 | |||
2776 | dss_start_update(dssdev); | 2782 | dss_start_update(dssdev); |
2777 | 2783 | ||
2778 | if (use_te_trigger) { | 2784 | if (use_te_trigger) { |
@@ -2795,47 +2801,63 @@ static void dsi_te_timeout(unsigned long arg) | |||
2795 | } | 2801 | } |
2796 | #endif | 2802 | #endif |
2797 | 2803 | ||
2798 | static void dsi_framedone_irq_callback(void *data, u32 mask) | 2804 | static void dsi_framedone_timeout_work_callback(struct work_struct *work) |
2799 | { | 2805 | { |
2800 | /* Note: We get FRAMEDONE when DISPC has finished sending pixels and | 2806 | int r; |
2801 | * turns itself off. However, DSI still has the pixels in its buffers, | 2807 | const int channel = dsi.update_channel; |
2802 | * and is sending the data. | 2808 | bool use_te_trigger; |
2803 | */ | 2809 | |
2810 | DSSERR("Framedone not received for 250ms!\n"); | ||
2804 | 2811 | ||
2805 | /* SIDLEMODE back to smart-idle */ | 2812 | /* SIDLEMODE back to smart-idle */ |
2806 | dispc_enable_sidle(); | 2813 | dispc_enable_sidle(); |
2807 | 2814 | ||
2808 | dsi.framedone_received = true; | 2815 | use_te_trigger = dsi.te_enabled && !dsi.use_ext_te; |
2809 | wake_up(&dsi.waitqueue); | ||
2810 | } | ||
2811 | 2816 | ||
2812 | static void dsi_set_update_region(struct omap_dss_device *dssdev, | 2817 | if (use_te_trigger) { |
2813 | u16 x, u16 y, u16 w, u16 h) | 2818 | /* enable LP_RX_TO again after the TE */ |
2814 | { | 2819 | REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */ |
2815 | spin_lock(&dsi.update_lock); | ||
2816 | if (dsi.update_region.dirty) { | ||
2817 | dsi.update_region.x = min(x, dsi.update_region.x); | ||
2818 | dsi.update_region.y = min(y, dsi.update_region.y); | ||
2819 | dsi.update_region.w = max(w, dsi.update_region.w); | ||
2820 | dsi.update_region.h = max(h, dsi.update_region.h); | ||
2821 | } else { | ||
2822 | dsi.update_region.x = x; | ||
2823 | dsi.update_region.y = y; | ||
2824 | dsi.update_region.w = w; | ||
2825 | dsi.update_region.h = h; | ||
2826 | } | 2820 | } |
2827 | 2821 | ||
2828 | dsi.update_region.device = dssdev; | 2822 | /* Send BTA after the frame. We need this for the TE to work, as TE |
2829 | dsi.update_region.dirty = true; | 2823 | * trigger is only sent for BTAs without preceding packet. Thus we need |
2824 | * to BTA after the pixel packets so that next BTA will cause TE | ||
2825 | * trigger. | ||
2826 | * | ||
2827 | * This is not needed when TE is not in use, but we do it anyway to | ||
2828 | * make sure that the transfer has been completed. It would be more | ||
2829 | * optimal, but more complex, to wait only just before starting next | ||
2830 | * transfer. */ | ||
2831 | r = dsi_vc_send_bta_sync(channel); | ||
2832 | if (r) | ||
2833 | DSSERR("BTA after framedone failed\n"); | ||
2834 | |||
2835 | /* RX_FIFO_NOT_EMPTY */ | ||
2836 | if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { | ||
2837 | DSSERR("Received error during frame transfer:\n"); | ||
2838 | dsi_vc_flush_receive_data(channel); | ||
2839 | } | ||
2840 | |||
2841 | dsi.framedone_callback(-ETIMEDOUT, dsi.framedone_data); | ||
2842 | } | ||
2830 | 2843 | ||
2831 | spin_unlock(&dsi.update_lock); | 2844 | static void dsi_framedone_irq_callback(void *data, u32 mask) |
2845 | { | ||
2846 | /* Note: We get FRAMEDONE when DISPC has finished sending pixels and | ||
2847 | * turns itself off. However, DSI still has the pixels in its buffers, | ||
2848 | * and is sending the data. | ||
2849 | */ | ||
2850 | |||
2851 | /* SIDLEMODE back to smart-idle */ | ||
2852 | dispc_enable_sidle(); | ||
2832 | 2853 | ||
2854 | schedule_work(&dsi.framedone_work); | ||
2833 | } | 2855 | } |
2834 | 2856 | ||
2835 | static void dsi_handle_framedone(void) | 2857 | static void dsi_handle_framedone(void) |
2836 | { | 2858 | { |
2837 | int r; | 2859 | int r; |
2838 | const int channel = 0; | 2860 | const int channel = dsi.update_channel; |
2839 | bool use_te_trigger; | 2861 | bool use_te_trigger; |
2840 | 2862 | ||
2841 | use_te_trigger = dsi.te_enabled && !dsi.use_ext_te; | 2863 | use_te_trigger = dsi.te_enabled && !dsi.use_ext_te; |
@@ -2871,105 +2893,79 @@ static void dsi_handle_framedone(void) | |||
2871 | #endif | 2893 | #endif |
2872 | } | 2894 | } |
2873 | 2895 | ||
2874 | static int dsi_update_thread(void *data) | 2896 | static void dsi_framedone_work_callback(struct work_struct *work) |
2875 | { | 2897 | { |
2876 | unsigned long timeout; | 2898 | DSSDBGF(); |
2877 | struct omap_dss_device *device; | ||
2878 | u16 x, y, w, h; | ||
2879 | |||
2880 | while (1) { | ||
2881 | wait_event_interruptible(dsi.waitqueue, | ||
2882 | dsi.update_region.dirty == true || | ||
2883 | kthread_should_stop()); | ||
2884 | |||
2885 | if (kthread_should_stop()) | ||
2886 | break; | ||
2887 | |||
2888 | dsi_bus_lock(); | ||
2889 | |||
2890 | if (kthread_should_stop()) { | ||
2891 | dsi_bus_unlock(); | ||
2892 | break; | ||
2893 | } | ||
2894 | 2899 | ||
2895 | dsi_perf_mark_setup(); | 2900 | cancel_delayed_work_sync(&dsi.framedone_timeout_work); |
2896 | 2901 | ||
2897 | if (dsi.update_region.dirty) { | 2902 | dsi_handle_framedone(); |
2898 | spin_lock(&dsi.update_lock); | ||
2899 | dsi.active_update_region = dsi.update_region; | ||
2900 | dsi.update_region.dirty = false; | ||
2901 | spin_unlock(&dsi.update_lock); | ||
2902 | } | ||
2903 | 2903 | ||
2904 | device = dsi.active_update_region.device; | 2904 | dsi_perf_show("DISPC"); |
2905 | x = dsi.active_update_region.x; | ||
2906 | y = dsi.active_update_region.y; | ||
2907 | w = dsi.active_update_region.w; | ||
2908 | h = dsi.active_update_region.h; | ||
2909 | 2905 | ||
2910 | if (device->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { | 2906 | dsi.framedone_callback(0, dsi.framedone_data); |
2907 | } | ||
2911 | 2908 | ||
2912 | dss_setup_partial_planes(device, | 2909 | int omap_dsi_prepare_update(struct omap_dss_device *dssdev, |
2913 | &x, &y, &w, &h); | 2910 | u16 *x, u16 *y, u16 *w, u16 *h) |
2911 | { | ||
2912 | u16 dw, dh; | ||
2914 | 2913 | ||
2915 | dispc_set_lcd_size(w, h); | 2914 | dssdev->driver->get_resolution(dssdev, &dw, &dh); |
2916 | } | ||
2917 | 2915 | ||
2918 | if (dsi.active_update_region.dirty) { | 2916 | if (*x > dw || *y > dh) |
2919 | dsi.active_update_region.dirty = false; | 2917 | return -EINVAL; |
2920 | /* XXX TODO we don't need to send the coords, if they | ||
2921 | * are the same that are already programmed to the | ||
2922 | * panel. That should speed up manual update a bit */ | ||
2923 | device->driver->setup_update(device, x, y, w, h); | ||
2924 | } | ||
2925 | 2918 | ||
2926 | dsi_perf_mark_start(); | 2919 | if (*x + *w > dw) |
2920 | return -EINVAL; | ||
2927 | 2921 | ||
2928 | if (device->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { | 2922 | if (*y + *h > dh) |
2929 | dsi_vc_config_vp(0); | 2923 | return -EINVAL; |
2930 | 2924 | ||
2931 | if (dsi.te_enabled && dsi.use_ext_te) | 2925 | if (*w == 1) |
2932 | device->driver->wait_for_te(device); | 2926 | return -EINVAL; |
2933 | 2927 | ||
2934 | dsi.framedone_received = false; | 2928 | if (*w == 0 || *h == 0) |
2929 | return -EINVAL; | ||
2935 | 2930 | ||
2936 | dsi_update_screen_dispc(device, x, y, w, h); | 2931 | dsi_perf_mark_setup(); |
2937 | 2932 | ||
2938 | /* wait for framedone */ | 2933 | if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { |
2939 | timeout = msecs_to_jiffies(1000); | 2934 | dss_setup_partial_planes(dssdev, x, y, w, h); |
2940 | wait_event_timeout(dsi.waitqueue, | 2935 | dispc_set_lcd_size(*w, *h); |
2941 | dsi.framedone_received == true, | 2936 | } |
2942 | timeout); | ||
2943 | 2937 | ||
2944 | if (!dsi.framedone_received) { | 2938 | return 0; |
2945 | DSSERR("framedone timeout\n"); | 2939 | } |
2946 | DSSERR("failed update %d,%d %dx%d\n", | 2940 | EXPORT_SYMBOL(omap_dsi_prepare_update); |
2947 | x, y, w, h); | ||
2948 | 2941 | ||
2949 | dispc_enable_sidle(); | 2942 | int omap_dsi_update(struct omap_dss_device *dssdev, |
2950 | device->manager->disable(device->manager); | 2943 | int channel, |
2944 | u16 x, u16 y, u16 w, u16 h, | ||
2945 | void (*callback)(int, void *), void *data) | ||
2946 | { | ||
2947 | dsi.update_channel = channel; | ||
2951 | 2948 | ||
2952 | dsi_reset_tx_fifo(0); | 2949 | if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { |
2953 | } else { | 2950 | dsi.framedone_callback = callback; |
2954 | dsi_handle_framedone(); | 2951 | dsi.framedone_data = data; |
2955 | dsi_perf_show("DISPC"); | ||
2956 | } | ||
2957 | } else { | ||
2958 | dsi_update_screen_l4(device, x, y, w, h); | ||
2959 | dsi_perf_show("L4"); | ||
2960 | } | ||
2961 | 2952 | ||
2962 | complete_all(&dsi.update_completion); | 2953 | dsi.update_region.x = x; |
2954 | dsi.update_region.y = y; | ||
2955 | dsi.update_region.w = w; | ||
2956 | dsi.update_region.h = h; | ||
2957 | dsi.update_region.device = dssdev; | ||
2963 | 2958 | ||
2964 | dsi_bus_unlock(); | 2959 | dsi_update_screen_dispc(dssdev, x, y, w, h); |
2960 | } else { | ||
2961 | dsi_update_screen_l4(dssdev, x, y, w, h); | ||
2962 | dsi_perf_show("L4"); | ||
2963 | callback(0, data); | ||
2965 | } | 2964 | } |
2966 | 2965 | ||
2967 | DSSDBG("update thread exiting\n"); | ||
2968 | |||
2969 | return 0; | 2966 | return 0; |
2970 | } | 2967 | } |
2971 | 2968 | EXPORT_SYMBOL(omap_dsi_update); | |
2972 | |||
2973 | 2969 | ||
2974 | /* Display funcs */ | 2970 | /* Display funcs */ |
2975 | 2971 | ||
@@ -3324,74 +3320,6 @@ err0: | |||
3324 | return r; | 3320 | return r; |
3325 | } | 3321 | } |
3326 | 3322 | ||
3327 | static int dsi_display_update(struct omap_dss_device *dssdev, | ||
3328 | u16 x, u16 y, u16 w, u16 h) | ||
3329 | { | ||
3330 | int r = 0; | ||
3331 | u16 dw, dh; | ||
3332 | |||
3333 | DSSDBG("dsi_display_update(%d,%d %dx%d)\n", x, y, w, h); | ||
3334 | |||
3335 | mutex_lock(&dsi.lock); | ||
3336 | |||
3337 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
3338 | goto end; | ||
3339 | |||
3340 | dssdev->driver->get_resolution(dssdev, &dw, &dh); | ||
3341 | |||
3342 | if (x > dw || y > dh) | ||
3343 | goto end; | ||
3344 | |||
3345 | if (x + w > dw) | ||
3346 | w = dw - x; | ||
3347 | |||
3348 | if (y + h > dh) | ||
3349 | h = dh - y; | ||
3350 | |||
3351 | if (w == 0 || h == 0) | ||
3352 | goto end; | ||
3353 | |||
3354 | if (w == 1) { | ||
3355 | r = -EINVAL; | ||
3356 | goto end; | ||
3357 | } | ||
3358 | |||
3359 | dsi_set_update_region(dssdev, x, y, w, h); | ||
3360 | |||
3361 | wake_up(&dsi.waitqueue); | ||
3362 | |||
3363 | end: | ||
3364 | mutex_unlock(&dsi.lock); | ||
3365 | |||
3366 | return r; | ||
3367 | } | ||
3368 | |||
3369 | static int dsi_display_sync(struct omap_dss_device *dssdev) | ||
3370 | { | ||
3371 | bool wait; | ||
3372 | |||
3373 | DSSDBG("dsi_display_sync()\n"); | ||
3374 | |||
3375 | mutex_lock(&dsi.lock); | ||
3376 | dsi_bus_lock(); | ||
3377 | |||
3378 | if (dsi.update_region.dirty) { | ||
3379 | INIT_COMPLETION(dsi.update_completion); | ||
3380 | wait = true; | ||
3381 | } else { | ||
3382 | wait = false; | ||
3383 | } | ||
3384 | |||
3385 | dsi_bus_unlock(); | ||
3386 | mutex_unlock(&dsi.lock); | ||
3387 | |||
3388 | if (wait) | ||
3389 | wait_for_completion_interruptible(&dsi.update_completion); | ||
3390 | |||
3391 | DSSDBG("dsi_display_sync() done\n"); | ||
3392 | return 0; | ||
3393 | } | ||
3394 | |||
3395 | int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable) | 3323 | int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable) |
3396 | { | 3324 | { |
3397 | dsi.te_enabled = enable; | 3325 | dsi.te_enabled = enable; |
@@ -3420,8 +3348,6 @@ int dsi_init_display(struct omap_dss_device *dssdev) | |||
3420 | dssdev->disable = dsi_display_disable; | 3348 | dssdev->disable = dsi_display_disable; |
3421 | dssdev->suspend = dsi_display_suspend; | 3349 | dssdev->suspend = dsi_display_suspend; |
3422 | dssdev->resume = dsi_display_resume; | 3350 | dssdev->resume = dsi_display_resume; |
3423 | dssdev->update = dsi_display_update; | ||
3424 | dssdev->sync = dsi_display_sync; | ||
3425 | 3351 | ||
3426 | /* XXX these should be figured out dynamically */ | 3352 | /* XXX these should be figured out dynamically */ |
3427 | dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | | 3353 | dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | |
@@ -3437,9 +3363,6 @@ int dsi_init(struct platform_device *pdev) | |||
3437 | { | 3363 | { |
3438 | u32 rev; | 3364 | u32 rev; |
3439 | int r; | 3365 | int r; |
3440 | struct sched_param param = { | ||
3441 | .sched_priority = MAX_USER_RT_PRIO-1 | ||
3442 | }; | ||
3443 | 3366 | ||
3444 | spin_lock_init(&dsi.errors_lock); | 3367 | spin_lock_init(&dsi.errors_lock); |
3445 | dsi.errors = 0; | 3368 | dsi.errors = 0; |
@@ -3450,28 +3373,19 @@ int dsi_init(struct platform_device *pdev) | |||
3450 | #endif | 3373 | #endif |
3451 | 3374 | ||
3452 | init_completion(&dsi.bta_completion); | 3375 | init_completion(&dsi.bta_completion); |
3453 | init_completion(&dsi.update_completion); | ||
3454 | |||
3455 | dsi.thread = kthread_create(dsi_update_thread, NULL, "dsi"); | ||
3456 | if (IS_ERR(dsi.thread)) { | ||
3457 | DSSERR("cannot create kthread\n"); | ||
3458 | r = PTR_ERR(dsi.thread); | ||
3459 | goto err0; | ||
3460 | } | ||
3461 | sched_setscheduler(dsi.thread, SCHED_FIFO, ¶m); | ||
3462 | |||
3463 | init_waitqueue_head(&dsi.waitqueue); | ||
3464 | spin_lock_init(&dsi.update_lock); | ||
3465 | 3376 | ||
3466 | mutex_init(&dsi.lock); | 3377 | mutex_init(&dsi.lock); |
3467 | sema_init(&dsi.bus_lock, 1); | 3378 | sema_init(&dsi.bus_lock, 1); |
3468 | 3379 | ||
3380 | INIT_WORK(&dsi.framedone_work, dsi_framedone_work_callback); | ||
3381 | INIT_DELAYED_WORK_DEFERRABLE(&dsi.framedone_timeout_work, | ||
3382 | dsi_framedone_timeout_work_callback); | ||
3383 | |||
3469 | #ifdef DSI_CATCH_MISSING_TE | 3384 | #ifdef DSI_CATCH_MISSING_TE |
3470 | init_timer(&dsi.te_timer); | 3385 | init_timer(&dsi.te_timer); |
3471 | dsi.te_timer.function = dsi_te_timeout; | 3386 | dsi.te_timer.function = dsi_te_timeout; |
3472 | dsi.te_timer.data = 0; | 3387 | dsi.te_timer.data = 0; |
3473 | #endif | 3388 | #endif |
3474 | |||
3475 | dsi.base = ioremap(DSI_BASE, DSI_SZ_REGS); | 3389 | dsi.base = ioremap(DSI_BASE, DSI_SZ_REGS); |
3476 | if (!dsi.base) { | 3390 | if (!dsi.base) { |
3477 | DSSERR("can't ioremap DSI\n"); | 3391 | DSSERR("can't ioremap DSI\n"); |
@@ -3495,21 +3409,15 @@ int dsi_init(struct platform_device *pdev) | |||
3495 | 3409 | ||
3496 | enable_clocks(0); | 3410 | enable_clocks(0); |
3497 | 3411 | ||
3498 | wake_up_process(dsi.thread); | ||
3499 | |||
3500 | return 0; | 3412 | return 0; |
3501 | err2: | 3413 | err2: |
3502 | iounmap(dsi.base); | 3414 | iounmap(dsi.base); |
3503 | err1: | 3415 | err1: |
3504 | kthread_stop(dsi.thread); | ||
3505 | err0: | ||
3506 | return r; | 3416 | return r; |
3507 | } | 3417 | } |
3508 | 3418 | ||
3509 | void dsi_exit(void) | 3419 | void dsi_exit(void) |
3510 | { | 3420 | { |
3511 | kthread_stop(dsi.thread); | ||
3512 | |||
3513 | iounmap(dsi.base); | 3421 | iounmap(dsi.base); |
3514 | 3422 | ||
3515 | DSSDBG("omap_dsi_exit\n"); | 3423 | DSSDBG("omap_dsi_exit\n"); |