#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
 
 static DEFINE_MUTEX(pp_do_mutex);
+
+/* define fixed sized ioctl cmd for y2038 migration */
+#define PPGETTIME32    _IOR(PP_IOCTL, 0x95, s32[2])
+#define PPSETTIME32    _IOW(PP_IOCTL, 0x96, s32[2])
+#define PPGETTIME64    _IOR(PP_IOCTL, 0x95, s64[2])
+#define PPSETTIME64    _IOW(PP_IOCTL, 0x96, s64[2])
+
 static inline void pp_enable_irq (struct pp_struct *pp)
 {
        struct parport *port = pp->pdev->port;
        return IEEE1284_PH_FWD_IDLE;
 }
 
+static int pp_set_timeout(struct pardevice *pdev, long tv_sec, int tv_usec)
+{
+       long to_jiffies;
+
+       if ((tv_sec < 0) || (tv_usec < 0))
+               return -EINVAL;
+
+       to_jiffies = usecs_to_jiffies(tv_usec);
+       to_jiffies += tv_sec * HZ;
+       if (to_jiffies <= 0)
+               return -EINVAL;
+
+       pdev->timeout = to_jiffies;
+       return 0;
+}
+
 static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        unsigned int minor = iminor(file_inode(file));
                unsigned char reg;
                unsigned char mask;
                int mode;
+               s32 time32[2];
+               s64 time64[2];
+               struct timespec64 ts;
                int ret;
-               struct timeval par_timeout;
-               long to_jiffies;
 
        case PPRSTATUS:
                reg = parport_read_status (port);
                atomic_sub (ret, &pp->irqc);
                return 0;
 
-       case PPSETTIME:
-               if (copy_from_user (&par_timeout, argp, sizeof(struct timeval))) {
+       case PPSETTIME32:
+               if (copy_from_user(time32, argp, sizeof(time32)))
                        return -EFAULT;
-               }
-               /* Convert to jiffies, place in pp->pdev->timeout */
-               if ((par_timeout.tv_sec < 0) || (par_timeout.tv_usec < 0)) {
-                       return -EINVAL;
-               }
-               to_jiffies = ROUND_UP(par_timeout.tv_usec, 1000000/HZ);
-               to_jiffies += par_timeout.tv_sec * (long)HZ;
-               if (to_jiffies <= 0) {
+
+               return pp_set_timeout(pp->pdev, time32[0], time32[1]);
+
+       case PPSETTIME64:
+               if (copy_from_user(time64, argp, sizeof(time64)))
+                       return -EFAULT;
+
+               return pp_set_timeout(pp->pdev, time64[0], time64[1]);
+
+       case PPGETTIME32:
+               jiffies_to_timespec64(pp->pdev->timeout, &ts);
+               time32[0] = ts.tv_sec;
+               time32[1] = ts.tv_nsec / NSEC_PER_USEC;
+               if ((time32[0] < 0) || (time32[1] < 0))
                        return -EINVAL;
-               }
-               pp->pdev->timeout = to_jiffies;
+
+               if (copy_to_user(argp, time32, sizeof(time32)))
+                       return -EFAULT;
+
                return 0;
 
-       case PPGETTIME:
-               to_jiffies = pp->pdev->timeout;
-               memset(&par_timeout, 0, sizeof(par_timeout));
-               par_timeout.tv_sec = to_jiffies / HZ;
-               par_timeout.tv_usec = (to_jiffies % (long)HZ) * (1000000/HZ);
-               if (copy_to_user (argp, &par_timeout, sizeof(struct timeval)))
+       case PPGETTIME64:
+               jiffies_to_timespec64(pp->pdev->timeout, &ts);
+               time64[0] = ts.tv_sec;
+               time64[1] = ts.tv_nsec / NSEC_PER_USEC;
+               if ((time64[0] < 0) || (time64[1] < 0))
+                       return -EINVAL;
+
+               if (copy_to_user(argp, time64, sizeof(time64)))
                        return -EFAULT;
+
                return 0;
 
        default: