summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorDanny Nold <dannynold@freescale.com>2010-08-17 15:25:29 -0500
committerDanny Nold <dannynold@freescale.com>2010-08-18 10:04:00 -0500
commita9dd14fb1e3b626a46b9d4ee9b56b0fc05bc9ee4 (patch)
tree361cecb05ebc13cd5067de068a9846ed3cb037c5 /drivers
parent1de8462f38135934f4e3c1654fe7d38c773df012 (diff)
ENGR00126213 - EPDC fb: Add ioctl to control powerdown delay
Ability added to control the delay between all updates being complete and the EPDC powering down. This provides user space control over how frequently the EPDC is undertaking a time-consuming enable/disable process. Signed-off-by: Danny Nold <dannynold@freescale.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/video/mxc/mxc_epdc_fb.c137
1 files changed, 92 insertions, 45 deletions
diff --git a/drivers/video/mxc/mxc_epdc_fb.c b/drivers/video/mxc/mxc_epdc_fb.c
index 44842e9eda29..6ee45b490c24 100644
--- a/drivers/video/mxc/mxc_epdc_fb.c
+++ b/drivers/video/mxc/mxc_epdc_fb.c
@@ -21,8 +21,6 @@
* Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
*/
-/*#define NO_POWERDOWN*/
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
@@ -151,9 +149,10 @@ struct mxc_epdc_fb_data {
struct update_marker_data update_marker_array[EPDC_MAX_NUM_UPDATES];
u32 lut_update_type[EPDC_NUM_LUTS];
struct completion updates_done;
- struct work_struct epdc_done_work;
+ struct delayed_work epdc_done_work;
struct mutex power_mutex;
bool powering_down;
+ int pwrdown_delay;
/* FB elements related to PxP DMA */
struct completion pxp_tx_cmpl;
@@ -1676,52 +1675,98 @@ static int mxc_epdc_fb_wait_update_complete(u32 update_marker,
return 0;
}
+static int mxc_epdc_fb_set_pwrdown_delay(u32 pwrdown_delay,
+ struct fb_info *info)
+{
+ struct mxc_epdc_fb_data *fb_data = (struct mxc_epdc_fb_data *)info;
+ int ret;
+
+ fb_data->pwrdown_delay = pwrdown_delay;
+
+ return 0;
+}
+
static int mxc_epdc_fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
{
void __user *argp = (void __user *)arg;
- struct mxc_epdc_fb_data *fb_data = (struct mxc_epdc_fb_data *)info;
- struct mxcfb_waveform_modes modes;
- int temperature;
- u32 auto_mode = 0;
- struct mxcfb_update_data upd_data;
- u32 update_marker = 0;
int ret = -EINVAL;
switch (cmd) {
case MXCFB_SET_WAVEFORM_MODES:
- if (!copy_from_user(&modes, argp, sizeof(modes))) {
- memcpy(&fb_data->wv_modes, &modes, sizeof(modes));
- ret = 0;
+ {
+ struct mxcfb_waveform_modes modes;
+ struct mxc_epdc_fb_data *fb_data =
+ (struct mxc_epdc_fb_data *)info;
+ if (!copy_from_user(&modes, argp, sizeof(modes))) {
+ memcpy(&fb_data->wv_modes, &modes,
+ sizeof(modes));
+ ret = 0;
+ }
+ break;
}
- break;
case MXCFB_SET_TEMPERATURE:
- if (!get_user(temperature, (int32_t __user *) arg))
- ret =
- mxc_epdc_fb_set_temperature(temperature,
- info);
- break;
+ {
+ int temperature;
+ if (!get_user(temperature, (int32_t __user *) arg))
+ ret =
+ mxc_epdc_fb_set_temperature(temperature,
+ info);
+ break;
+ }
case MXCFB_SET_AUTO_UPDATE_MODE:
- if (!get_user(auto_mode, (__u32 __user *) arg))
- ret =
- mxc_epdc_fb_set_auto_update(auto_mode, info);
- break;
+ {
+ u32 auto_mode = 0;
+ if (!get_user(auto_mode, (__u32 __user *) arg))
+ ret =
+ mxc_epdc_fb_set_auto_update(auto_mode,
+ info);
+ break;
+ }
case MXCFB_SEND_UPDATE:
- if (!copy_from_user(&upd_data, argp, sizeof(upd_data))) {
- ret = mxc_epdc_fb_send_update(&upd_data, info);
- if (ret == 0 && copy_to_user(argp, &upd_data, sizeof(upd_data)))
+ {
+ struct mxcfb_update_data upd_data;
+ if (!copy_from_user(&upd_data, argp,
+ sizeof(upd_data))) {
+ ret = mxc_epdc_fb_send_update(&upd_data, info);
+ if (ret == 0 && copy_to_user(argp, &upd_data,
+ sizeof(upd_data)))
+ ret = -EFAULT;
+ } else {
ret = -EFAULT;
- } else {
- ret = -EFAULT;
- }
+ }
- break;
+ break;
+ }
case MXCFB_WAIT_FOR_UPDATE_COMPLETE:
- if (!get_user(update_marker, (__u32 __user *) arg))
- ret =
- mxc_epdc_fb_wait_update_complete(update_marker,
- info);
- break;
+ {
+ u32 update_marker = 0;
+ if (!get_user(update_marker, (__u32 __user *) arg))
+ ret =
+ mxc_epdc_fb_wait_update_complete(update_marker,
+ info);
+ break;
+ }
+
+ case MXCFB_SET_PWRDOWN_DELAY:
+ {
+ int delay = 0;
+ if (!get_user(delay, (__u32 __user *) arg))
+ ret =
+ mxc_epdc_fb_set_pwrdown_delay(delay, info);
+ break;
+ }
+
+ case MXCFB_GET_PWRDOWN_DELAY:
+ {
+ struct mxc_epdc_fb_data *fb_data =
+ (struct mxc_epdc_fb_data *)info;
+ if (put_user(fb_data->pwrdown_delay,
+ (int __user *)argp))
+ ret = -EFAULT;
+ ret = 0;
+ break;
+ }
default:
break;
}
@@ -2022,16 +2067,17 @@ static irqreturn_t mxc_epdc_irq_handler(int irq, void *dev_id)
(fb_data->cur_update == NULL) &&
!epdc_any_luts_active()) {
-#ifndef NO_POWERDOWN
- /*
- * Set variable to prevent overlapping
- * enable/disable requests
- */
- fb_data->powering_down = true;
-
- /* Schedule task to disable EPDC HW until next update */
- schedule_work(&fb_data->epdc_done_work);
-#endif
+ if (fb_data->pwrdown_delay != FB_POWERDOWN_DISABLE) {
+ /*
+ * Set variable to prevent overlapping
+ * enable/disable requests
+ */
+ fb_data->powering_down = true;
+
+ /* Schedule task to disable EPDC HW until next update */
+ schedule_delayed_work(&fb_data->epdc_done_work,
+ jiffies_to_msecs(fb_data->pwrdown_delay));
+ }
if (fb_data->waiting_for_idle)
complete(&fb_data->updates_done);
@@ -2614,7 +2660,7 @@ int __devinit mxc_epdc_fb_probe(struct platform_device *pdev)
goto out_dma_work_buf;
}
- INIT_WORK(&fb_data->epdc_done_work, epdc_done_work_func);
+ INIT_DELAYED_WORK(&fb_data->epdc_done_work, epdc_done_work_func);
info->fbdefio = &mxc_epdc_fb_defio;
#ifdef CONFIG_FB_MXC_EINK_AUTO_UPDATE_MODE
@@ -2735,6 +2781,7 @@ int __devinit mxc_epdc_fb_probe(struct platform_device *pdev)
fb_data->blank = FB_BLANK_UNBLANK;
fb_data->power_state = POWER_STATE_OFF;
fb_data->powering_down = false;
+ fb_data->pwrdown_delay = 0;
/* Register FB */
ret = register_framebuffer(info);