]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/blob - drivers/media/platform/tegra/vi/vi.c
media: tegra_camera: add SoC fops for VI
[sojka/nv-tegra/linux-3.10.git] / drivers / media / platform / tegra / vi / vi.c
1 /*
2  * drivers/video/tegra/host/vi/vi.c
3  *
4  * Tegra Graphics Host VI
5  *
6  * Copyright (c) 2012-2016, 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/init.h>
22 #include <linux/export.h>
23 #include <linux/module.h>
24 #include <linux/resource.h>
25 #include <linux/pm_runtime.h>
26 #include <linux/of.h>
27 #include <linux/of_device.h>
28 #include <linux/of_platform.h>
29 #include <linux/clk/tegra.h>
30 #include <linux/tegra-soc.h>
31 #include <linux/tegra_pm_domains.h>
32 #include <linux/debugfs.h>
33
34 #include <media/tegra_v4l2_camera.h>
35
36 #include "dev.h"
37 #include "bus_client.h"
38 #include "nvhost_acm.h"
39 #include "t124/t124.h"
40 #include "t210/t210.h"
41 #include "vi/vi.h"
42 #include "vi/vi_irq.h"
43 #include "camera/vi2_fops.h"
44
45 #ifdef CONFIG_ARCH_TEGRA_18x_SOC
46 #include "t186/t186.h"
47 #endif
48
49 #define MAX_DEVID_LENGTH        16
50 #define TEGRA_VI_NAME           "tegra_vi"
51
52 struct vi *tegra_vi;
53
54 struct vi *tegra_vi_get(void)
55 {
56         return tegra_vi;
57 }
58 EXPORT_SYMBOL(tegra_vi_get);
59
60 struct tegra_vi_data t124_vi_data = {
61         .info = (struct nvhost_device_data *)&t124_vi_info,
62         .vi_fops = &vi2_fops,
63         .channel_fops = &vi2_channel_fops,
64 };
65
66 struct tegra_vi_data t210_vi_data = {
67         .info = (struct nvhost_device_data *)&t21_vi_info,
68         .vi_fops = &vi2_fops,
69         .channel_fops = &vi2_channel_fops,
70 };
71
72 #ifdef CONFIG_ARCH_TEGRA_18x_SOC
73 struct tegra_vi_data t186_vi_data = {
74         .info = (struct nvhost_device_data *)&t18_vi_info,
75 };
76 #endif
77
78 static struct of_device_id tegra_vi_of_match[] = {
79         {
80                 .compatible = "nvidia,tegra124-vi",
81                 .data = &t124_vi_data
82         },
83         {
84                 .compatible = "nvidia,tegra210-vi",
85                 .data = &t210_vi_data
86         },
87 #ifdef CONFIG_ARCH_TEGRA_18x_SOC
88         {
89                 .compatible = "nvidia,tegra186-vi",
90                 .data = &t186_vi_data
91         },
92 #endif
93         { },
94 };
95
96 static struct i2c_camera_ctrl *i2c_ctrl;
97
98 static void (*mfi_callback)(void *);
99 static void *mfi_callback_arg;
100 static DEFINE_MUTEX(vi_isr_lock);
101
102 #ifdef CONFIG_VIDEO_TEGRA_VI
103 int tegra_vi_register_mfi_cb(callback cb, void *cb_arg)
104 {
105         if (mfi_callback || mfi_callback_arg) {
106                 pr_err("cb already registered\n");
107                 return -1;
108         }
109
110         mutex_lock(&vi_isr_lock);
111         mfi_callback = cb;
112         mfi_callback_arg = cb_arg;
113         mutex_unlock(&vi_isr_lock);
114
115         return 0;
116 }
117 EXPORT_SYMBOL(tegra_vi_register_mfi_cb);
118
119 int tegra_vi_unregister_mfi_cb(void)
120 {
121         mutex_lock(&vi_isr_lock);
122         mfi_callback = NULL;
123         mfi_callback_arg = NULL;
124         mutex_unlock(&vi_isr_lock);
125
126         return 0;
127 }
128 EXPORT_SYMBOL(tegra_vi_unregister_mfi_cb);
129 #endif
130
131 static void vi_mfi_worker(struct work_struct *vi_work)
132 {
133         struct vi *pdev = container_of(vi_work, struct vi, mfi_cb_work);
134
135         if (mfi_callback == NULL) {
136                 dev_dbg(&pdev->ndev->dev, "NULL callback\n");
137                 return;
138         }
139         mutex_lock(&vi_isr_lock);
140         mfi_callback(mfi_callback_arg);
141         mutex_unlock(&vi_isr_lock);
142         return;
143 }
144
145 #if defined(CONFIG_TEGRA_ISOMGR)
146 static int vi_isomgr_unregister(struct vi *tegra_vi)
147 {
148         tegra_isomgr_unregister(tegra_vi->isomgr_handle);
149         tegra_vi->isomgr_handle = NULL;
150
151         return 0;
152 }
153 #endif
154
155 static int vi_out_show(struct seq_file *s, void *unused)
156 {
157         struct vi *vi = s->private;
158
159         seq_printf(s, "vi overflow: %u\n",
160                 atomic_read(&(vi->vi_out.overflow)));
161
162         return 0;
163 }
164
165 static int vi_out_open(struct inode *inode, struct file *file)
166 {
167         return single_open(file, vi_out_show, inode->i_private);
168 }
169
170 static const struct file_operations vi_out_fops = {
171         .open           = vi_out_open,
172         .read           = seq_read,
173         .llseek         = seq_lseek,
174         .release        = single_release,
175 };
176
177 static void vi_remove_debugfs(struct vi *vi)
178 {
179         debugfs_remove_recursive(vi->debugdir);
180         vi->debugdir = NULL;
181 }
182
183 static void vi_create_debugfs(struct vi *vi)
184 {
185         struct dentry *ret;
186         char tegra_vi_name[20];
187         char debugfs_file_name[20];
188
189
190         snprintf(tegra_vi_name, sizeof(tegra_vi_name), "%s", TEGRA_VI_NAME);
191
192         vi->debugdir = debugfs_create_dir(tegra_vi_name, NULL);
193         if (!vi->debugdir) {
194                 dev_err(&vi->ndev->dev,
195                         "%s: failed to create %s directory",
196                         __func__, tegra_vi_name);
197                 goto create_debugfs_fail;
198         }
199
200         snprintf(debugfs_file_name, sizeof(debugfs_file_name), "%s", "vi_out");
201
202         ret = debugfs_create_file(debugfs_file_name, S_IRUGO,
203                         vi->debugdir, vi, &vi_out_fops);
204         if (!ret) {
205                 dev_err(&vi->ndev->dev,
206                 "%s: failed to create %s", __func__, debugfs_file_name);
207                 goto create_debugfs_fail;
208         }
209
210         return;
211
212 create_debugfs_fail:
213         dev_err(&vi->ndev->dev, "%s: could not create debugfs", __func__);
214         vi_remove_debugfs(vi);
215 }
216
217 static int nvhost_vi_slcg_handler(struct notifier_block *nb,
218                 unsigned long action, void *data)
219 {
220         struct clk *clk;
221         int ret = 0;
222
223         struct nvhost_device_data *pdata =
224                 container_of(nb, struct nvhost_device_data,
225                         toggle_slcg_notifier);
226         struct vi *tegra_vi = (struct vi *)pdata->private_data;
227
228         if (tegra_vi->mc_vi.pg_mode)
229                 return NOTIFY_OK;
230
231         clk = clk_get(&pdata->pdev->dev, "pll_d");
232         if (IS_ERR(clk))
233                 return -EINVAL;
234
235         /* Make CSI sourced from PLL_D */
236         ret = tegra_clk_cfg_ex(clk, TEGRA_CLK_PLLD_CSI_OUT_ENB, 1);
237         if (ret) {
238                 dev_err(&pdata->pdev->dev,
239                 "%s: failed to select CSI source pll_d: %d\n",
240                 __func__, ret);
241                 return ret;
242         }
243
244         /* Enable PLL_D */
245         ret = clk_prepare_enable(clk);
246         if (ret) {
247                 dev_err(&pdata->pdev->dev, "Can't enable pll_d: %d\n", ret);
248                 return ret;
249         }
250
251         udelay(1);
252
253         /* Disable PLL_D */
254         clk_disable_unprepare(clk);
255
256         /* Restore CSI source */
257         ret = tegra_clk_cfg_ex(clk, TEGRA_CLK_MIPI_CSI_OUT_ENB, 1);
258         if (ret) {
259                 dev_err(&pdata->pdev->dev,
260                 "%s: failed to restore csi source: %d\n",
261                 __func__, ret);
262                 return ret;
263         }
264
265         clk_put(clk);
266
267         return NOTIFY_OK;
268 }
269
270 static int vi_probe(struct platform_device *dev)
271 {
272         int err = 0;
273         struct tegra_vi_data *data = NULL;
274         struct nvhost_device_data *pdata = NULL;
275
276         if (dev->dev.of_node) {
277                 const struct of_device_id *match;
278
279                 match = of_match_device(tegra_vi_of_match, &dev->dev);
280                 if (match)
281                         data = (struct tegra_vi_data *) match->data;
282
283                 /* DT initializes it to -1, use below WAR to set correct value.
284                  * TODO: Once proper fix for dev-id goes in, remove it.
285                  */
286                 dev->id = dev->dev.id;
287         }
288
289         BUG_ON(!data || !data->info);
290         dev->dev.platform_data = data->info;
291         pdata = data->info;
292
293         err = nvhost_check_bondout(pdata->bond_out_id);
294         if (err) {
295                 dev_warn(&dev->dev, "No VI unit present. err:%d", err);
296                 return err;
297         }
298
299         pdata->pdev = dev;
300         mutex_init(&pdata->lock);
301         platform_set_drvdata(dev, pdata);
302
303         dev_info(&dev->dev, "%s: ++\n", __func__);
304
305         tegra_vi = devm_kzalloc(&dev->dev, sizeof(struct vi), GFP_KERNEL);
306         if (!tegra_vi) {
307                 dev_err(&dev->dev, "can't allocate memory for vi\n");
308                 return -ENOMEM;
309         }
310         tegra_vi->ndev = dev;
311         tegra_vi->data = data;
312         tegra_vi->dev = &dev->dev;
313
314         /* If missing SoC fops, whole VI/CSI has be in bypass mode */
315         if (!data->vi_fops || !data->channel_fops)
316                 tegra_vi->bypass = true;
317
318         err = nvhost_client_device_get_resources(dev);
319         if (err)
320                 goto vi_probe_fail;
321
322         if (!pdata->aperture[0]) {
323                 dev_err(&dev->dev, "%s: failed to map register base\n",
324                                 __func__);
325                 return -ENXIO;
326         }
327
328         /* create workqueue for mfi callback */
329         tegra_vi->vi_workqueue = alloc_workqueue("vi_workqueue",
330                                         WQ_HIGHPRI | WQ_UNBOUND, 1);
331         if (!tegra_vi->vi_workqueue) {
332                 dev_err(&dev->dev, "Failed to allocated vi_workqueue");
333                 goto vi_probe_fail;
334         }
335         /* Init mfi callback work */
336         INIT_WORK(&tegra_vi->mfi_cb_work, vi_mfi_worker);
337
338         /* call vi_intr_init and stats_work */
339         INIT_WORK(&tegra_vi->stats_work, vi_stats_worker);
340
341         err = vi_intr_init(tegra_vi);
342         if (err)
343                 goto vi_probe_fail;
344
345         vi_create_debugfs(tegra_vi);
346
347         i2c_ctrl = pdata->private_data;
348         pdata->private_data = tegra_vi;
349         mutex_init(&tegra_vi->update_la_lock);
350
351         /* Create I2C Devices according to settings from board file */
352         if (i2c_ctrl && i2c_ctrl->new_devices)
353                 i2c_ctrl->new_devices(dev);
354
355         tegra_vi->reg = regulator_get(&tegra_vi->ndev->dev, "avdd_dsi_csi");
356         if (IS_ERR(tegra_vi->reg)) {
357                 err = PTR_ERR(tegra_vi->reg);
358                 if (err == -ENODEV)
359                         dev_info(&tegra_vi->ndev->dev,
360                                 "%s: no regulator device\n", __func__);
361                 else
362                         dev_err(&tegra_vi->ndev->dev,
363                                 "%s: couldn't get regulator\n", __func__);
364                 tegra_vi->reg = NULL;
365                 if (tegra_platform_is_silicon())
366                         goto camera_i2c_unregister;
367         }
368
369 #ifdef CONFIG_TEGRA_CAMERA
370         tegra_vi->camera = tegra_camera_register(dev);
371         if (!tegra_vi->camera) {
372                 dev_err(&dev->dev, "%s: can't register tegra_camera\n",
373                                 __func__);
374                 goto vi_regulator_put;
375         }
376 #endif
377
378         if (pdata->slcg_notifier_enable &&
379                         (pdata->powergate_id != -1)) {
380                 pdata->toggle_slcg_notifier.notifier_call =
381                 &nvhost_vi_slcg_handler;
382
383                 slcg_register_notifier(pdata->powergate_id,
384                         &pdata->toggle_slcg_notifier);
385         }
386
387         nvhost_module_init(dev);
388
389 #ifdef CONFIG_PM_GENERIC_DOMAINS
390 #ifndef CONFIG_PM_GENERIC_DOMAINS_OF
391         pdata->pd.name = "ve";
392 #endif
393
394         /* add module power domain and also add its domain
395          * as sub-domain of MC domain */
396         err = nvhost_module_add_domain(&pdata->pd, dev);
397 #endif
398         err = nvhost_client_device_init(dev);
399         if (err)
400                 goto camera_unregister;
401
402         tegra_vi->csi.vi = tegra_vi;
403         err = tegra_csi_init(&tegra_vi->csi, dev);
404         if (err)
405                 goto vi_mc_init_error;
406
407         tegra_vi->mc_vi.vi = tegra_vi;
408         tegra_vi->mc_vi.csi = &tegra_vi->csi;
409         tegra_vi->mc_vi.reg = tegra_vi->reg;
410         tegra_vi->mc_vi.fops = tegra_vi->data->vi_fops;
411         err = tegra_vi_media_controller_init(&tegra_vi->mc_vi, dev);
412         if (err)
413                 goto vi_mc_init_error;
414
415         return 0;
416
417 vi_mc_init_error:
418         nvhost_client_device_release(dev);
419 camera_unregister:
420 #ifdef CONFIG_TEGRA_CAMERA
421         tegra_camera_unregister(tegra_vi->camera);
422 vi_regulator_put:
423 #endif
424         regulator_put(tegra_vi->reg);
425         tegra_vi->reg = NULL;
426
427 camera_i2c_unregister:
428         if (i2c_ctrl && i2c_ctrl->remove_devices)
429                 i2c_ctrl->remove_devices(dev);
430         pdata->private_data = i2c_ctrl;
431 vi_probe_fail:
432         dev_err(&dev->dev, "%s: failed\n", __func__);
433         return err;
434 }
435
436 static int __exit vi_remove(struct platform_device *dev)
437 {
438 #ifdef CONFIG_TEGRA_CAMERA
439         int err = 0;
440 #endif
441         struct nvhost_device_data *pdata = platform_get_drvdata(dev);
442         struct vi *tegra_vi = (struct vi *)pdata->private_data;
443
444 #ifdef CONFIG_PM_RUNTIME
445         if (atomic_read(&dev->dev.power.usage_count) > 0)
446                 return -EBUSY;
447 #endif
448
449         dev_info(&dev->dev, "%s: ++\n", __func__);
450
451 #if defined(CONFIG_TEGRA_ISOMGR)
452         if (tegra_vi->isomgr_handle)
453                 vi_isomgr_unregister(tegra_vi);
454 #endif
455
456         vi_remove_debugfs(tegra_vi);
457
458         tegra_vi_media_controller_cleanup(&tegra_vi->mc_vi);
459
460         nvhost_client_device_release(dev);
461
462         if (pdata->slcg_notifier_enable &&
463             (pdata->powergate_id != -1))
464                 slcg_unregister_notifier(pdata->powergate_id,
465                                          &pdata->toggle_slcg_notifier);
466
467         vi_intr_free(tegra_vi);
468
469         pdata->aperture[0] = NULL;
470         flush_workqueue(tegra_vi->vi_workqueue);
471         destroy_workqueue(tegra_vi->vi_workqueue);
472 #ifdef CONFIG_TEGRA_CAMERA
473         err = tegra_camera_unregister(tegra_vi->camera);
474         if (err)
475                 return err;
476 #endif
477
478 #ifdef CONFIG_PM_GENERIC_DOMAINS
479         tegra_pd_remove_device(&dev->dev);
480 #endif
481
482         regulator_put(tegra_vi->reg);
483         tegra_vi->reg = NULL;
484
485         /* Remove I2C Devices according to settings from board file */
486         if (i2c_ctrl && i2c_ctrl->remove_devices)
487                 i2c_ctrl->remove_devices(dev);
488
489         pdata->private_data = i2c_ctrl;
490
491         return 0;
492 }
493
494 static struct platform_driver vi_driver = {
495         .probe = vi_probe,
496         .remove = __exit_p(vi_remove),
497         .driver = {
498                 .owner = THIS_MODULE,
499                 .name = "vi",
500 #ifdef CONFIG_PM
501                 .pm = &nvhost_module_pm_ops,
502 #endif
503 #ifdef CONFIG_OF
504                 .of_match_table = tegra_vi_of_match,
505 #endif
506         }
507 };
508
509 static struct of_device_id tegra_vi_domain_match[] = {
510         {.compatible = "nvidia,tegra210-ve-pd",
511         .data = (struct nvhost_device_data *)&t21_vi_info},
512         {.compatible = "nvidia,tegra132-ve-pd",
513         .data = (struct nvhost_device_data *)&t124_vi_info},
514         {.compatible = "nvidia,tegra124-ve-pd",
515          .data = (struct nvhost_device_data *)&t124_vi_info},
516         {},
517 };
518
519 static int __init vi_init(void)
520 {
521         int ret;
522
523         ret = nvhost_domain_init(tegra_vi_domain_match);
524         if (ret)
525                 return ret;
526
527         return platform_driver_register(&vi_driver);
528 }
529
530 static void __exit vi_exit(void)
531 {
532         platform_driver_unregister(&vi_driver);
533 }
534
535 late_initcall(vi_init);
536 module_exit(vi_exit);
537 MODULE_LICENSE("GPL v2");