ARM: tegra12: set CPU rate to 2.2GHz for sku 0x87
[linux-3.10.git] / arch / arm / mach-tegra / mipi-cal.c
1 /*
2  * arch/arch/mach-tegra/mipi-cal.c
3  *
4  * Copyright (C) 2013 NVIDIA Corporation. All rights reserved.
5  *
6  * Author:
7  *      Charlie Huang <chahuang@nvidia.com>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms and conditions of the GNU General Public License,
11  * version 2, as published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16  * more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <linux/fs.h>
23 #include <linux/mm.h>
24 #include <linux/miscdevice.h>
25 #include <linux/module.h>
26 #include <linux/clk.h>
27
28 #include "iomap.h"
29
30 struct mipi_cal_info {
31         struct clk *clk;
32         struct clk *clk72mhz;
33 };
34
35 static struct mipi_cal_info     pm;
36 static atomic_t                 mipi_cal_in_use;
37
38 static int mipi_cal_open(struct inode *inode, struct file *filp);
39 static int mipi_cal_release(struct inode *inode, struct file *filp);
40 static int mipi_cal_dev_mmap(struct file *file, struct vm_area_struct *vma);
41
42 static const struct file_operations mipi_cal_dev_fops = {
43         .owner = THIS_MODULE,
44         .open = mipi_cal_open,
45         .release = mipi_cal_release,
46         .mmap = mipi_cal_dev_mmap,
47         .llseek = noop_llseek,
48 };
49
50 static struct miscdevice mipi_cal_dev = {
51         .minor = MISC_DYNAMIC_MINOR,
52         .name = "mipi-cal",
53         .fops = &mipi_cal_dev_fops,
54 };
55
56 static int mipi_cal_open(struct inode *inode, struct file *filp)
57 {
58         if (atomic_xchg(&mipi_cal_in_use, 1))
59                 return -EBUSY;
60
61         if (pm.clk72mhz)
62                 clk_prepare_enable(pm.clk72mhz);
63         if (pm.clk)
64                 clk_prepare_enable(pm.clk);
65
66         return nonseekable_open(inode, filp);
67 }
68
69 static int mipi_cal_release(struct inode *inode, struct file *filp)
70 {
71         if (pm.clk)
72                 clk_disable_unprepare(pm.clk);
73         if (pm.clk72mhz)
74                 clk_disable_unprepare(pm.clk72mhz);
75
76         WARN_ON(!atomic_xchg(&mipi_cal_in_use, 0));
77         return 0;
78 }
79
80 static int mipi_cal_dev_mmap(struct file *file, struct vm_area_struct *vma)
81 {
82         phys_addr_t addr = TEGRA_MIPI_CAL_BASE;
83
84         if (vma->vm_end  - vma->vm_start != PAGE_SIZE)
85                 return -EINVAL;
86
87         vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
88
89         if (remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT, PAGE_SIZE,
90                 vma->vm_page_prot)) {
91                 pr_err("%s:remap_pfn_range for mipi_cal failed\n",
92                         mipi_cal_dev.name);
93                 return -EAGAIN;
94         }
95
96         return 0;
97 }
98
99 static int __init mipi_cal_dev_init(void)
100 {
101         pm.clk = clk_get_sys("mipi-cal", NULL);
102         if (IS_ERR_OR_NULL(pm.clk)) {
103                 pr_warn("%s: cannot get mipi-cal clk.\n", __func__);
104                 pm.clk = NULL;
105         }
106 #ifdef CONFIG_ARCH_TEGRA_14x_SOC
107         pm.clk72mhz = clk_get_sys("clk72mhz", NULL);
108         if (IS_ERR_OR_NULL(pm.clk72mhz)) {
109                 pr_warn("%s: cannot get mipi-cal clk.\n", __func__);
110                 pm.clk72mhz = NULL;
111         }
112 #endif
113         return misc_register(&mipi_cal_dev);
114 }
115
116 module_init(mipi_cal_dev_init);
117 MODULE_LICENSE("GPL v2");