59d83a9f4a83b516cfdf8dc8c071efebaff534eb
[linux-3.10.git] / drivers / video / tegra / host / isp / isp.c
1 /*
2  * drivers/video/tegra/host/isp/isp.c
3  *
4  * Tegra Graphics ISP
5  *
6  * Copyright (c) 2012-2013, NVIDIA Corporation.  All rights reserved.
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms and conditions of the GNU General Public License,
10  * version 2, as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <linux/export.h>
22 #include <linux/resource.h>
23 #include <linux/pm_runtime.h>
24 #include <linux/of.h>
25 #include <linux/of_device.h>
26 #include <linux/of_platform.h>
27
28 #include <mach/pm_domains.h>
29
30 #include "dev.h"
31 #include "bus_client.h"
32 #include "nvhost_acm.h"
33 #include "t114/t114.h"
34 #include "t148/t148.h"
35 #include "t124/t124.h"
36
37 #include <linux/uaccess.h>
38 #include <linux/fs.h>
39 #include <linux/nvhost_isp_ioctl.h>
40 #include <mach/latency_allowance.h>
41 #include "isp.h"
42
43 #define T12_ISP_CG_CTRL         0x1d
44 #define T12_CG_2ND_LEVEL_EN     1
45 #define T12_ISPB_DEV_ID         1
46
47 static struct of_device_id tegra_isp_of_match[] = {
48 #ifdef TEGRA_11X_OR_HIGHER_CONFIG
49         { .compatible = "nvidia,tegra114-isp",
50                 .data = (struct nvhost_device_data *)&t11_isp_info },
51 #endif
52 #ifdef TEGRA_14X_OR_HIGHER_CONFIG
53         { .compatible = "nvidia,tegra148-isp",
54                 .data = (struct nvhost_device_data *)&t14_isp_info },
55 #endif
56 #ifdef TEGRA_12X_OR_HIGHER_CONFIG
57         { .compatible = "nvidia,tegra124-isp",
58                 .data = (struct nvhost_device_data *)&t124_isp_info },
59 #endif
60         { },
61 };
62
63 int nvhost_isp_t124_finalize_poweron(struct platform_device *pdev)
64 {
65         nvhost_client_writel(pdev, T12_CG_2ND_LEVEL_EN, T12_ISP_CG_CTRL);
66         return 0;
67 }
68
69 static int isp_probe(struct platform_device *dev)
70 {
71         int err = 0;
72 #ifdef TEGRA_12X_OR_HIGHER_CONFIG
73         int dev_id = 0;
74 #endif
75         struct nvhost_device_data *pdata = NULL;
76
77         if (dev->dev.of_node) {
78                 const struct of_device_id *match;
79
80                 match = of_match_device(tegra_isp_of_match, &dev->dev);
81                 if (match)
82                         pdata = (struct nvhost_device_data *)match->data;
83 #ifdef TEGRA_12X_OR_HIGHER_CONFIG
84                 sscanf(dev->name, "isp.%1d", &dev_id);
85                 if (dev_id == T12_ISPB_DEV_ID)
86                         pdata = &t124_ispb_info;
87 #endif
88         } else
89                 pdata = (struct nvhost_device_data *)dev->dev.platform_data;
90
91         WARN_ON(!pdata);
92         if (!pdata) {
93                 dev_info(&dev->dev, "no platform data\n");
94                 return -ENODATA;
95         }
96
97         pdata->pdev = dev;
98         mutex_init(&pdata->lock);
99         platform_set_drvdata(dev, pdata);
100
101         err = nvhost_client_device_get_resources(dev);
102         if (err)
103                 return err;
104
105         nvhost_module_init(dev);
106
107 #ifdef CONFIG_PM_GENERIC_DOMAINS
108         pdata->pd.name = "ve";
109
110         /* add module power domain and also add its domain
111          * as sub-domain of MC domain */
112         err = nvhost_module_add_domain(&pdata->pd, dev);
113 #endif
114
115         err = nvhost_client_device_init(dev);
116         if (err)
117                 return err;
118
119         return 0;
120 }
121
122 static int __exit isp_remove(struct platform_device *dev)
123 {
124 #ifdef CONFIG_PM_RUNTIME
125         pm_runtime_put(&dev->dev);
126         pm_runtime_disable(&dev->dev);
127 #else
128         nvhost_module_disable_clk(&dev->dev);
129 #endif
130         return 0;
131 }
132
133 static struct platform_driver isp_driver = {
134         .probe = isp_probe,
135         .remove = __exit_p(isp_remove),
136         .driver = {
137                 .owner = THIS_MODULE,
138                 .name = "isp",
139 #ifdef CONFIG_PM
140                 .pm = &nvhost_module_pm_ops,
141 #endif
142 #ifdef CONFIG_OF
143                 .of_match_table = tegra_isp_of_match,
144 #endif
145         }
146 };
147
148 static int set_isp_la(struct platform_device *isp_ndev,
149                          struct isp_emc emc_info)
150 {
151         int ret;
152         uint la_bw;
153         uint la_client;
154
155         la_bw = (((emc_info.isp_clk/1000)*emc_info.bpp_output)/8);
156
157         if (emc_info.bpp_output && emc_info.bpp_input)
158                 la_client = ISP_SOFT_ISO_CLIENT;
159         else
160                 la_client = ISP_HARD_ISO_CLIENT;
161
162         if (isp_ndev->id)
163                 ret = tegra_set_camera_ptsa(TEGRA_LA_ISP_WAB,
164                                 la_bw, la_client);
165         else
166                 ret = tegra_set_camera_ptsa(TEGRA_LA_ISP_WA,
167                                 la_bw, la_client);
168         return ret;
169 }
170
171 long isp_ioctl(struct file *file,
172                 unsigned int cmd, unsigned long arg)
173 {
174         struct platform_device *isp_ndev;
175         struct nvhost_device_data *pdata;
176
177         if (_IOC_TYPE(cmd) != NVHOST_ISP_IOCTL_MAGIC)
178                 return -EFAULT;
179
180         isp_ndev = file->private_data;
181         pdata  = (struct nvhost_device_data *)isp_ndev->dev.platform_data;
182         switch (cmd) {
183         case NVHOST_ISP_IOCTL_SET_EMC: {
184                 int ret;
185                 struct isp_emc emc_info;
186                 if (copy_from_user(&emc_info,
187                         (const void __user *)arg, sizeof(struct isp_emc))) {
188                         dev_err(&isp_ndev->dev,
189                                 "%s: Failed to copy arg from user\n", __func__);
190                         return -EFAULT;
191                         }
192
193                 ret = set_isp_la(isp_ndev, emc_info);
194
195                 return ret;
196         }
197         default:
198                 dev_err(&isp_ndev->dev,
199                         "%s: Unknown ISP ioctl.\n", __func__);
200                 return -EINVAL;
201         }
202         return 0;
203 }
204
205 static int isp_open(struct inode *inode, struct file *file)
206 {
207         struct nvhost_device_data *pdata;
208
209         pdata = container_of(inode->i_cdev,
210                 struct nvhost_device_data, ctrl_cdev);
211         BUG_ON(pdata == NULL);
212
213         file->private_data = pdata->pdev;
214         return 0;
215 }
216
217 static int isp_release(struct inode *inode, struct file *file)
218 {
219         return 0;
220 }
221
222 const struct file_operations tegra_isp_ctrl_ops = {
223         .owner = THIS_MODULE,
224         .open = isp_open,
225         .unlocked_ioctl = isp_ioctl,
226         .release = isp_release,
227 };
228
229
230 static int __init isp_init(void)
231 {
232         return platform_driver_register(&isp_driver);
233 }
234
235 static void __exit isp_exit(void)
236 {
237         platform_driver_unregister(&isp_driver);
238 }
239
240 module_init(isp_init);
241 module_exit(isp_exit);