ARM: tegra: timer: add /dev/timerinfo
Jon Mayo [Wed, 29 Feb 2012 04:55:19 +0000 (20:55 -0800)]
Add a device that allows read-only mmap() of timer registers.

Reviewed-on: http://git-master/r/87511
(cherry picked from commit 95a6a6dafd97cbc72ea305f17b600be67a03093b)

Change-Id: I8782107dc3a32ff1c5a3a3c68d2ff0e8fb123dc3
Signed-off-by: Jon Mayo <jmayo@nvidia.com>
Reviewed-on: http://git-master/r/91984
Reviewed-by: Simone Willett <swillett@nvidia.com>
Tested-by: Simone Willett <swillett@nvidia.com>

arch/arm/mach-tegra/Makefile
arch/arm/mach-tegra/timerinfo.c [new file with mode: 0644]

index 290ac33..96d4667 100644 (file)
@@ -12,6 +12,7 @@ obj-$(CONFIG_TEGRA_GRHOST)              += syncpt.o
 obj-y                                   += clock.o
 obj-y                                   += clock-common.o
 obj-y                                   += timer.o
+obj-y                                   += timerinfo.o
 ifeq ($(CONFIG_ARCH_TEGRA_2x_SOC),y)
 obj-y                                   += tegra2_clocks.o
 obj-y                                   += timer-t2.o
diff --git a/arch/arm/mach-tegra/timerinfo.c b/arch/arm/mach-tegra/timerinfo.c
new file mode 100644 (file)
index 0000000..b64ea82
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * arch/arch/mach-tegra/timerinfo.c
+ *
+ * Copyright (C) 2012 NVIDIA Corporation.
+ *
+ * Author:
+ *     Jon Mayo <jmayo@nvidia.com>
+ *
+ * Copyright (C) 2012 NVIDIA Corporation.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+#include <linux/miscdevice.h>
+#include <mach/iomap.h>
+
+#include "timer.h"
+
+static int timerinfo_dev_mmap(struct file *file, struct vm_area_struct *vma);
+
+static const struct file_operations timerinfo_dev_fops = {
+       .owner = THIS_MODULE,
+       .open = nonseekable_open,
+       .mmap = timerinfo_dev_mmap,
+       .llseek = noop_llseek,
+};
+
+static struct miscdevice timerinfo_dev = {
+       .minor = MISC_DYNAMIC_MINOR,
+       .name = "timerinfo",
+       .fops = &timerinfo_dev_fops,
+};
+
+static int timerinfo_dev_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       /* start at first page containing TIMERUS_CNTR_1US */
+       phys_addr_t addr = TEGRA_TMR1_BASE;
+
+       if (vma->vm_end  - vma->vm_start != PAGE_SIZE)
+               return -EINVAL;
+
+       if (vma->vm_flags & VM_WRITE)
+               return -EPERM;
+
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+       if (remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT, PAGE_SIZE,
+               vma->vm_page_prot)) {
+               pr_err("%s:remap_pfn_range failed\n", timerinfo_dev.name);
+               return -EAGAIN;
+       }
+
+       return 0;
+}
+
+static int __init timerinfo_dev_init(void)
+{
+       return misc_register(&timerinfo_dev);
+}
+
+module_init(timerinfo_dev_init);
+MODULE_LICENSE("GPL");