#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/device.h>
+#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/interrupt.h>
static int rk3188_lcdc_ioctl(struct rk_lcdc_device_driver *dev_drv, unsigned int cmd,unsigned long arg,int layer_id)
{
+ struct rk3188_lcdc_device *lcdc_dev =
+ container_of(dev_drv,struct rk3188_lcdc_device,driver);
+ u32 panel_size[2];
+ void __user *argp = (void __user *)arg;
+ int enable;
+ switch(cmd)
+ {
+ case FBIOGET_PANEL_SIZE: //get panel size
+ panel_size[0] = lcdc_dev->screen->x_res;
+ panel_size[1] = lcdc_dev->screen->y_res;
+ if(copy_to_user(argp, panel_size, 8))
+ return -EFAULT;
+ break;
+ case RK_FBIOSET_CONFIG_DONE:
+ lcdc_cfg_done(lcdc_dev);
+ break;
+ case RK_FBIOSET_VSYNC_ENABLE:
+ if (copy_from_user(&enable, argp, sizeof(enable)))
+ return -EFAULT;
+ lcdc_dev->vsync_info.active = enable;
+ break;
+ default:
+ break;
+ }
return 0;
}
return ret;
}
+
+static int lcdc_wait_for_vsync_thread(void *data)
+{
+ struct rk3188_lcdc_device *lcdc_dev = data;
+
+ while (!kthread_should_stop()) {
+ ktime_t timestamp = lcdc_dev->vsync_info.timestamp;
+ int ret = wait_event_interruptible(lcdc_dev->vsync_info.wait,
+ !ktime_equal(timestamp, lcdc_dev->vsync_info.timestamp) &&
+ lcdc_dev->vsync_info.active);
+
+ if (!ret) {
+ sysfs_notify(&lcdc_dev->driver.dev->kobj, NULL, "vsync");
+ }
+ }
+
+ return 0;
+}
+
+static ssize_t rk3188_lcdc_vsync_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rk3188_lcdc_device *lcdc_dev = dev_get_drvdata(dev);
+ return scnprintf(buf, PAGE_SIZE, "%llu\n",
+ ktime_to_ns(lcdc_dev->vsync_info.timestamp));
+}
+
+static DEVICE_ATTR(vsync, S_IRUGO, rk3188_lcdc_vsync_show, NULL);
+
static struct layer_par lcdc_layer[] = {
[0] = {
.name = "win0",
{
struct rk3188_lcdc_device *lcdc_dev =
(struct rk3188_lcdc_device *)dev_id;
+ ktime_t timestamp = ktime_get();
lcdc_msk_reg(lcdc_dev, INT_STATUS, m_FS_INT_CLEAR, v_FS_INT_CLEAR(1));
spin_unlock(&(lcdc_dev->driver.cpl_lock));
}
#endif
+ lcdc_dev->vsync_info.timestamp = timestamp;
+ wake_up_interruptible_all(&lcdc_dev->vsync_info.wait);
+
return IRQ_HANDLED;
}
ret = -ENODEV;
goto err4;
}
+
+ init_waitqueue_head(&lcdc_dev->vsync_info.wait);
+ ret = device_create_file(&pdev->dev, &dev_attr_vsync);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to create vsync file\n");
+ }
+ lcdc_dev->vsync_info.thread = kthread_run(lcdc_wait_for_vsync_thread,
+ lcdc_dev, "lcdc-vsync");
+
+
+ if (lcdc_dev->vsync_info.thread == ERR_PTR(-ENOMEM)) {
+ dev_err(&pdev->dev, "failed to run vsync thread\n");
+ lcdc_dev->vsync_info.thread = NULL;
+ }
+ lcdc_dev->vsync_info.active = 1;
ret = rk_fb_register(&(lcdc_dev->driver),&lcdc_driver,lcdc_dev->id);
if(ret < 0)