diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 08d4964..815487f 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -58,8 +58,9 @@ struct evdev_client {
 	struct list_head node;
 	int clk_type;
 	bool revoked;
+	bool is_input_event64;
 	unsigned int bufsize;
-	struct input_event buffer[];
+	struct input_event64 *buffer;
 };
 
 /* flush queued events of type @type, caller must hold client->buffer_lock */
@@ -68,7 +69,7 @@ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type)
 	unsigned int i, head, num;
 	unsigned int mask = client->bufsize - 1;
 	bool is_report;
-	struct input_event *ev;
+	struct input_event64 *ev;
 
 	BUG_ON(type == EV_SYN);
 
@@ -110,7 +111,7 @@ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type)
 
 static void __evdev_queue_syn_dropped(struct evdev_client *client)
 {
-	struct input_event ev;
+	struct input_event64 ev;
 	ktime_t time;
 
 	time = client->clk_type == EV_CLK_REAL ?
@@ -119,7 +120,7 @@ static void __evdev_queue_syn_dropped(struct evdev_client *client)
 				ktime_get() :
 				ktime_get_boottime();
 
-	ev.time = ktime_to_timeval(time);
+	ev.time = ktime_to_timespec64(time);
 	ev.type = EV_SYN;
 	ev.code = SYN_DROPPED;
 	ev.value = 0;
@@ -182,7 +183,7 @@ static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid)
 }
 
 static void __pass_event(struct evdev_client *client,
-			 const struct input_event *event)
+			 const struct input_event64 *event)
 {
 	client->buffer[client->head++] = *event;
 	client->head &= client->bufsize - 1;
@@ -214,13 +215,13 @@ static void evdev_pass_values(struct evdev_client *client,
 {
 	struct evdev *evdev = client->evdev;
 	const struct input_value *v;
-	struct input_event event;
+	struct input_event64 event;
 	bool wakeup = false;
 
 	if (client->revoked)
 		return;
 
-	event.time = ktime_to_timeval(ev_time[client->clk_type]);
+	event.time = ktime_to_timespec64(ev_time[client->clk_type]);
 
 	/* Interrupts are disabled, just acquire the lock. */
 	spin_lock(&client->buffer_lock);
@@ -438,7 +439,7 @@ static int evdev_open(struct inode *inode, struct file *file)
 	struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev);
 	unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev);
 	unsigned int size = sizeof(struct evdev_client) +
-					bufsize * sizeof(struct input_event);
+					bufsize * sizeof(struct input_event64);
 	struct evdev_client *client;
 	int error;
 
@@ -473,7 +474,7 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,
 {
 	struct evdev_client *client = file->private_data;
 	struct evdev *evdev = client->evdev;
-	struct input_event event;
+	struct input_event64 event;
 	int retval = 0;
 
 	if (count != 0 && count < input_event_size())
@@ -490,7 +491,8 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,
 
 	while (retval + input_event_size() <= count) {
 
-		if (input_event_from_user(buffer + retval, &event)) {
+		if (input_event_from_user(buffer + retval, &event,
+					client->is_input_event64)) {
 			retval = -EFAULT;
 			goto out;
 		}
@@ -506,7 +508,7 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,
 }
 
 static int evdev_fetch_next_event(struct evdev_client *client,
-				  struct input_event *event)
+				  struct input_event64 *event)
 {
 	int have_event;
 
@@ -528,7 +530,7 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,
 {
 	struct evdev_client *client = file->private_data;
 	struct evdev *evdev = client->evdev;
-	struct input_event event;
+	struct input_event64 event;
 	size_t read = 0;
 	int error;
 
@@ -553,7 +555,8 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,
 		while (read + input_event_size() <= count &&
 		       evdev_fetch_next_event(client, &event)) {
 
-			if (input_event_to_user(buffer + read, &event))
+			if (input_event_to_user(buffer + read, &event,
+						client->is_input_event64))
 				return -EFAULT;
 
 			read += input_event_size();
diff --git a/drivers/input/input-compat.c b/drivers/input/input-compat.c
index 64ca711..9bad69a 100644
--- a/drivers/input/input-compat.c
+++ b/drivers/input/input-compat.c
@@ -12,10 +12,30 @@
 #include <asm/uaccess.h>
 #include "input-compat.h"
 
+void input_event_to_event64(const struct input_event *event,
+		struct input_event64 *event64)
+{
+	event64->time.tv_sec = event->time.tv_sec;
+	event64->time.tv_nsec = event->time.tv_usec * NSEC_PER_USEC;
+	event64->type = event->type;
+	event64->code = event->code;
+	event64->value = event->value;
+}
+
+void input_event64_to_event(const struct input_event64 *event64,
+		struct input_event *event)
+{
+	event->time.tv_sec = event64->time.tv_sec;
+	event->time.tv_usec = event64->time.tv_nsec / NSEC_PER_USEC;
+	event->type = event64->type;
+	event->code = event64->code;
+	event->value = event64->value;
+}
+
 #ifdef CONFIG_COMPAT
 
 int input_event_from_user(const char __user *buffer,
-			  struct input_event *event)
+		struct input_event64 *event, bool is_input_event64)
 {
 	if (INPUT_COMPAT_TEST && !COMPAT_USE_64BIT_TIME) {
 		struct input_event_compat compat_event;
@@ -25,27 +45,37 @@ int input_event_from_user(const char __user *buffer,
 			return -EFAULT;
 
 		event->time.tv_sec = compat_event.time.tv_sec;
-		event->time.tv_usec = compat_event.time.tv_usec;
+		event->time.tv_nsec = compat_event.time.tv_usec * NSEC_PER_USEC;
 		event->type = compat_event.type;
 		event->code = compat_event.code;
 		event->value = compat_event.value;
 
 	} else {
-		if (copy_from_user(event, buffer, sizeof(struct input_event)))
-			return -EFAULT;
+		if (is_input_event64) {
+			if (copy_from_user(event, buffer,
+					sizeof(struct input_event64)))
+				return -EFAULT;
+		} else { /* userland use struct input_event */
+			struct input_event ev;
+
+			if (copy_from_user(&ev, buffer,
+					sizeof(struct input_event)))
+				return -EFAULT;
+			input_event_to_event64(&ev, event);
+		}
 	}
 
 	return 0;
 }
 
 int input_event_to_user(char __user *buffer,
-			const struct input_event *event)
+		const struct input_event64 *event, bool is_input_event64)
 {
 	if (INPUT_COMPAT_TEST && !COMPAT_USE_64BIT_TIME) {
 		struct input_event_compat compat_event;
 
 		compat_event.time.tv_sec = event->time.tv_sec;
-		compat_event.time.tv_usec = event->time.tv_usec;
+		compat_event.time.tv_usec = event->time.tv_nsec / NSEC_PER_USEC;
 		compat_event.type = event->type;
 		compat_event.code = event->code;
 		compat_event.value = event->value;
@@ -55,8 +85,18 @@ int input_event_to_user(char __user *buffer,
 			return -EFAULT;
 
 	} else {
-		if (copy_to_user(buffer, event, sizeof(struct input_event)))
-			return -EFAULT;
+		if (is_input_event64) {
+			if (copy_to_user(buffer, event,
+					sizeof(struct input_event64)))
+				return -EFAULT;
+		} else { /* userland use struct input_event */
+			struct input_event ev;
+
+			input_event64_to_event(event, &ev);
+			if (copy_to_user(buffer, &ev,
+					sizeof(struct input_event)))
+				return -EFAULT;
+		}
 	}
 
 	return 0;
@@ -100,19 +140,39 @@ int input_ff_effect_from_user(const char __user *buffer, size_t size,
 #else
 
 int input_event_from_user(const char __user *buffer,
-			 struct input_event *event)
+		struct input_event64 *event, bool is_input_event64)
 {
-	if (copy_from_user(event, buffer, sizeof(struct input_event)))
-		return -EFAULT;
+	if (is_input_event64) {
+		if (copy_from_user(event, buffer,
+				sizeof(struct input_event64)))
+			return -EFAULT;
+	} else { /* userland use struct input_event */
+		struct input_event ev;
+
+		if (copy_from_user(&ev, buffer,
+				sizeof(struct input_event)))
+			return -EFAULT;
+		input_event_to_event64(&ev, event);
+	}
 
 	return 0;
 }
 
 int input_event_to_user(char __user *buffer,
-			const struct input_event *event)
+		const struct input_event64 *event, bool is_input_event64)
 {
-	if (copy_to_user(buffer, event, sizeof(struct input_event)))
-		return -EFAULT;
+	if (is_input_event64) {
+		if (copy_to_user(buffer, event,
+				sizeof(struct input_event64)))
+			return -EFAULT;
+	} else { /* userland use struct input_event */
+		struct input_event ev;
+
+		input_event64_to_event(event, &ev);
+		if (copy_to_user(buffer, &ev,
+				sizeof(struct input_event)))
+			return -EFAULT;
+	}
 
 	return 0;
 }
diff --git a/drivers/input/input-compat.h b/drivers/input/input-compat.h
index 148f66f..f770b5d 100644
--- a/drivers/input/input-compat.h
+++ b/drivers/input/input-compat.h
@@ -68,23 +68,24 @@ struct ff_effect_compat {
 static inline size_t input_event_size(void)
 {
 	return (INPUT_COMPAT_TEST && !COMPAT_USE_64BIT_TIME) ?
-		sizeof(struct input_event_compat) : sizeof(struct input_event);
+		sizeof(struct input_event_compat) :
+		sizeof(struct input_event64);
 }
 
 #else
 
 static inline size_t input_event_size(void)
 {
-	return sizeof(struct input_event);
+	return sizeof(struct input_event64);
 }
 
 #endif /* CONFIG_COMPAT */
 
 int input_event_from_user(const char __user *buffer,
-			 struct input_event *event);
+		struct input_event64 *event, bool is_input_event64);
 
 int input_event_to_user(char __user *buffer,
-			const struct input_event *event);
+		const struct input_event64 *event, bool is_input_event64);
 
 int input_ff_effect_from_user(const char __user *buffer, size_t size,
 			      struct ff_effect *effect);
diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
index 731417c..1e252ff 100644
--- a/include/uapi/linux/input.h
+++ b/include/uapi/linux/input.h
@@ -21,6 +21,14 @@
  * The event structure itself
  */
 
+/*
+ * This structure should not use anymore, please
+ * use input_event64 instead. Placing it here is
+ * only for compatibility purpose.
+ *
+ * FIXME: move to input-compat.h if there are no
+ * compatibility issues.
+ */
 struct input_event {
 	struct timeval time;
 	__u16 type;
@@ -28,6 +36,13 @@ struct input_event {
 	__s32 value;
 };
 
+struct input_event64 {
+	struct timespec64 time;
+	__u16 type;
+	__u16 code;
+	__s32 value;
+};
+
 /*
  * Protocol version.
  */
