tegra: host: vi: Add ioctl to VI driver
[linux-3.10.git] / drivers / video / tegra / host / vi / vi.c
1 /*
2  * drivers/video/tegra/host/vi/vi.c
3  *
4  * Tegra Graphics Host VI
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 #include <linux/nvhost_vi_ioctl.h>
28
29 #include <mach/pm_domains.h>
30 #include <mach/clk.h>
31
32 #include "dev.h"
33 #include "bus_client.h"
34 #include "nvhost_acm.h"
35 #include "t20/t20.h"
36 #include "t30/t30.h"
37 #include "t114/t114.h"
38 #include "t148/t148.h"
39 #include "t124/t124.h"
40 #include "vi.h"
41
42 #define MAX_DEVID_LENGTH        16
43
44 static struct of_device_id tegra_vi_of_match[] = {
45 #ifdef TEGRA_2X_OR_HIGHER_CONFIG
46         { .compatible = "nvidia,tegra20-vi",
47                 .data = (struct nvhost_device_data *)&t20_vi_info },
48 #endif
49 #ifdef TEGRA_3X_OR_HIGHER_CONFIG
50         { .compatible = "nvidia,tegra30-vi",
51                 .data = (struct nvhost_device_data *)&t30_vi_info },
52 #endif
53 #ifdef TEGRA_11X_OR_HIGHER_CONFIG
54         { .compatible = "nvidia,tegra114-vi",
55                 .data = (struct nvhost_device_data *)&t11_vi_info },
56 #endif
57 #ifdef TEGRA_14X_OR_HIGHER_CONFIG
58         { .compatible = "nvidia,tegra148-vi",
59                 .data = (struct nvhost_device_data *)&t14_vi_info },
60 #endif
61 #ifdef TEGRA_12X_OR_HIGHER_CONFIG
62         { .compatible = "nvidia,tegra124-vi",
63                 .data = (struct nvhost_device_data *)&t124_vi_info },
64 #endif
65         { },
66 };
67
68 #ifdef CONFIG_PM_GENERIC_DOMAINS
69 static int vi_unpowergate(struct generic_pm_domain *domain)
70 {
71         struct nvhost_device_data *pdata;
72
73         pdata = container_of(domain, struct nvhost_device_data, pd);
74         return nvhost_module_power_on(pdata->pdev);
75 }
76
77 static int vi_powergate(struct generic_pm_domain *domain)
78 {
79         struct nvhost_device_data *pdata;
80
81         pdata = container_of(domain, struct nvhost_device_data, pd);
82         return nvhost_module_power_off(pdata->pdev);
83 }
84 #endif
85
86 static int vi_probe(struct platform_device *dev)
87 {
88         int err = 0;
89         struct vi *tegra_vi;
90         struct nvhost_device_data *pdata = NULL;
91
92         if (dev->dev.of_node) {
93                 const struct of_device_id *match;
94
95                 match = of_match_device(tegra_vi_of_match, &dev->dev);
96                 if (match)
97                         pdata = (struct nvhost_device_data *)match->data;
98         } else
99                 pdata = (struct nvhost_device_data *)dev->dev.platform_data;
100
101         WARN_ON(!pdata);
102         if (!pdata) {
103                 dev_info(&dev->dev, "no platform data\n");
104                 return -ENODATA;
105         }
106
107         dev_info(&dev->dev, "%s: ++\n", __func__);
108
109         tegra_vi = kzalloc(sizeof(struct vi), GFP_KERNEL);
110         if (!tegra_vi) {
111                 dev_err(&dev->dev, "can't allocate memory for vi\n");
112                 return -ENOMEM;
113         }
114
115         tegra_vi->ndev = dev;
116         pdata->private_data = tegra_vi;
117 #ifdef CONFIG_TEGRA_CAMERA
118         tegra_vi->camera = tegra_camera_register(dev);
119         if (!tegra_vi->camera) {
120                 dev_err(&dev->dev, "%s: can't register tegra_camera\n",
121                                 __func__);
122                 goto camera_register_fail;
123         }
124 #endif
125
126         pdata->pdev = dev;
127         mutex_init(&pdata->lock);
128         platform_set_drvdata(dev, pdata);
129         nvhost_module_init(dev);
130
131 #ifdef CONFIG_PM_GENERIC_DOMAINS
132         pdata->pd.name = "ve";
133         pdata->pd.power_off = vi_powergate;
134         pdata->pd.power_on = vi_unpowergate;
135         pdata->pd.dev_ops.start = nvhost_module_enable_clk;
136         pdata->pd.dev_ops.stop = nvhost_module_disable_clk;
137
138         /* add module power domain and also add its domain
139          * as sub-domain of MC domain */
140         err = nvhost_module_add_domain(&pdata->pd, dev);
141
142         /* overwrite save/restore fptrs set by pm_genpd_init */
143         pdata->pd.domain.ops.suspend = nvhost_client_device_suspend;
144         pdata->pd.domain.ops.resume = nvhost_client_device_resume;
145 #endif
146
147         err = nvhost_client_device_get_resources(dev);
148         if (err)
149                 goto camera_register_fail;
150
151         err = nvhost_client_device_init(dev);
152         if (err)
153                 goto camera_register_fail;
154
155 #ifdef CONFIG_PM_RUNTIME
156         if (pdata->clockgate_delay) {
157                 pm_runtime_set_autosuspend_delay(&dev->dev,
158                         pdata->clockgate_delay);
159                 pm_runtime_use_autosuspend(&dev->dev);
160         }
161         pm_runtime_enable(&dev->dev);
162 #else
163         nvhost_module_enable_clk(&dev->dev);
164 #endif
165
166         return 0;
167
168 camera_register_fail:
169         kfree(tegra_vi);
170         return err;
171 }
172
173 static int __exit vi_remove(struct platform_device *dev)
174 {
175 #ifdef CONFIG_TEGRA_CAMERA
176         int err = 0;
177         struct nvhost_device_data *pdata =
178                 (struct nvhost_device_data *)platform_get_drvdata(dev);
179         struct vi *tegra_vi = (struct vi *)pdata->private_data;
180 #endif
181
182         dev_info(&dev->dev, "%s: ++\n", __func__);
183
184 #ifdef CONFIG_TEGRA_CAMERA
185         err = tegra_camera_unregister(tegra_vi->camera);
186         if (err)
187                 return err;
188 #endif
189
190 #ifdef CONFIG_PM_RUNTIME
191         pm_runtime_put(&dev->dev);
192         pm_runtime_disable(&dev->dev);
193 #else
194         nvhost_module_disable_clk(&dev->dev);
195 #endif
196
197         return 0;
198 }
199
200 #ifdef CONFIG_PM
201 static int vi_suspend(struct device *dev)
202 {
203 #ifdef CONFIG_TEGRA_CAMERA
204         struct platform_device *pdev = to_platform_device(dev);
205         struct nvhost_device_data *pdata =
206                 (struct nvhost_device_data *)platform_get_drvdata(pdev);
207         struct vi *tegra_vi = (struct vi *)pdata->private_data;
208 #endif
209
210         dev_info(dev, "%s: ++\n", __func__);
211
212 #ifdef CONFIG_TEGRA_CAMERA
213         tegra_camera_suspend(tegra_vi->camera);
214 #endif
215
216         return nvhost_client_device_suspend(dev);
217 }
218
219 static int vi_resume(struct device *dev)
220 {
221 #ifdef CONFIG_TEGRA_CAMERA
222         struct platform_device *pdev = to_platform_device(dev);
223         struct nvhost_device_data *pdata =
224                 (struct nvhost_device_data *)platform_get_drvdata(pdev);
225         struct vi *tegra_vi = (struct vi *)pdata->private_data;
226 #endif
227
228         dev_info(dev, "%s: ++\n", __func__);
229
230 #ifdef CONFIG_TEGRA_CAMERA
231         tegra_camera_resume(tegra_vi->camera);
232 #endif
233
234         return 0;
235 }
236
237 static const struct dev_pm_ops vi_pm_ops = {
238         .suspend = vi_suspend,
239         .resume = vi_resume,
240 #if defined(CONFIG_PM_RUNTIME) && !defined(CONFIG_PM_GENERIC_DOMAINS)
241         .runtime_suspend = nvhost_module_disable_clk,
242         .runtime_resume = nvhost_module_enable_clk,
243 #endif
244 };
245 #endif
246
247 static struct platform_driver vi_driver = {
248         .probe = vi_probe,
249         .remove = __exit_p(vi_remove),
250         .driver = {
251                 .owner = THIS_MODULE,
252                 .name = "vi",
253 #ifdef CONFIG_PM
254                 .pm = &vi_pm_ops,
255 #endif
256 #ifdef CONFIG_OF
257                 .of_match_table = tegra_vi_of_match,
258 #endif
259         }
260 };
261
262 static int __init vi_init(void)
263 {
264         return platform_driver_register(&vi_driver);
265 }
266
267 static void __exit vi_exit(void)
268 {
269         platform_driver_unregister(&vi_driver);
270 }
271
272 #ifdef TEGRA_12X_OR_HIGHER_CONFIG
273 int nvhost_vi_init(struct platform_device *dev)
274 {
275         int ret = 0;
276         struct vi *tegra_vi;
277         tegra_vi = (struct vi *)nvhost_get_private_data(dev);
278
279         tegra_vi->reg = regulator_get(&dev->dev, "avdd_dsi_csi");
280         if (IS_ERR_OR_NULL(tegra_vi->reg)) {
281                 if (tegra_vi->reg == ERR_PTR(-ENODEV)) {
282                         ret = -ENODEV;
283                         dev_info(&dev->dev,
284                                 "%s: no regulator device\n",
285                                 __func__);
286                 } else {
287                         dev_err(&dev->dev,
288                                 "%s: couldn't get regulator\n",
289                                 __func__);
290                 }
291                 tegra_vi->reg = NULL;
292         }
293         return ret;
294 }
295
296 void nvhost_vi_deinit(struct platform_device *dev)
297 {
298         struct vi *tegra_vi;
299         tegra_vi = (struct vi *)nvhost_get_private_data(dev);
300
301         if (tegra_vi->reg)
302                 regulator_put(tegra_vi->reg);
303 }
304
305 int nvhost_vi_finalize_poweron(struct platform_device *dev)
306 {
307         int ret = 0;
308         struct vi *tegra_vi;
309         tegra_vi = (struct vi *)nvhost_get_private_data(dev);
310
311         if (tegra_vi->reg) {
312                 ret = regulator_enable(tegra_vi->reg);
313                 if (ret)
314                         dev_err(&dev->dev,
315                                 "%s: enable csi regulator failed.\n",
316                                 __func__);
317         }
318         return ret;
319 }
320
321 int nvhost_vi_prepare_poweroff(struct platform_device *dev)
322 {
323         int ret = 0;
324         struct vi *tegra_vi;
325         tegra_vi = (struct vi *)nvhost_get_private_data(dev);
326
327         if (tegra_vi->reg) {
328                 ret = regulator_disable(tegra_vi->reg);
329                 if (ret)
330                         dev_err(&dev->dev,
331                                 "%s: disable csi regulator failed.\n",
332                                 __func__);
333         }
334         return ret;
335 }
336
337 long tegra_vi_ioctl(struct file *file,
338                 unsigned int cmd, unsigned long arg)
339 {
340         struct vi *tegra_vi;
341
342         if (_IOC_TYPE(cmd) != NVHOST_VI_IOCTL_MAGIC)
343                 return -EFAULT;
344
345         tegra_vi = file->private_data;
346         switch (cmd) {
347         case NVHOST_VI_IOCTL_ENABLE_TPG: {
348                 uint enable;
349                 int ret;
350                 struct clk *clk;
351
352                 if (copy_from_user(&enable,
353                         (const void __user *)arg, sizeof(uint))) {
354                         dev_err(&tegra_vi->ndev->dev,
355                                 "%s: Failed to copy arg from user\n", __func__);
356                         return -EFAULT;
357                 }
358
359                 clk = clk_get(&tegra_vi->ndev->dev, "pll_d");
360                 if (enable)
361                         ret = tegra_clk_cfg_ex(clk,
362                                 TEGRA_CLK_PLLD_CSI_OUT_ENB, 1);
363                 else
364                         ret = tegra_clk_cfg_ex(clk,
365                                 TEGRA_CLK_MIPI_CSI_OUT_ENB, 1);
366                 clk_put(clk);
367
368                 return ret;
369         }
370         default:
371                 dev_err(&tegra_vi->ndev->dev,
372                         "%s: Unknown vi ioctl.\n", __func__);
373                 return -EINVAL;
374         }
375         return 0;
376 }
377
378 static int tegra_vi_open(struct inode *inode, struct file *file)
379 {
380         struct nvhost_device_data *pdata;
381         struct vi *vi;
382
383         pdata = container_of(inode->i_cdev,
384                 struct nvhost_device_data, ctrl_cdev);
385         BUG_ON(pdata == NULL);
386
387         vi = (struct vi *)pdata->private_data;
388         BUG_ON(vi == NULL);
389
390         file->private_data = vi;
391         return 0;
392 }
393
394 static int tegra_vi_release(struct inode *inode, struct file *file)
395 {
396         return 0;
397 }
398
399 const struct file_operations tegra_vi_ctrl_ops = {
400         .owner = THIS_MODULE,
401         .open = tegra_vi_open,
402         .unlocked_ioctl = tegra_vi_ioctl,
403         .release = tegra_vi_release,
404 };
405 #endif
406
407 late_initcall(vi_init);
408 module_exit(vi_exit);