]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/blob - drivers/video/tegra/host/vi/vi.c
drivers: video: tegra: vi: implement probe/remove
[sojka/nv-tegra/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-2014, 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/module.h>
23 #include <linux/resource.h>
24 #include <linux/pm_runtime.h>
25 #include <linux/of.h>
26 #include <linux/of_device.h>
27 #include <linux/of_platform.h>
28 #include <linux/clk/tegra.h>
29
30 #include <mach/pm_domains.h>
31 #include <media/tegra_v4l2_camera.h>
32
33 #include "dev.h"
34 #include "bus_client.h"
35 #include "nvhost_acm.h"
36 #include "t114/t114.h"
37 #include "t148/t148.h"
38 #include "t124/t124.h"
39 #include "vi.h"
40 #include "vi_irq.h"
41
42 #define MAX_DEVID_LENGTH        16
43 #define TEGRA_VI_NAME           "tegra_vi"
44
45 static struct of_device_id tegra_vi_of_match[] = {
46 #ifdef TEGRA_11X_OR_HIGHER_CONFIG
47         { .compatible = "nvidia,tegra114-vi",
48                 .data = (struct nvhost_device_data *)&t11_vi_info },
49 #endif
50 #ifdef TEGRA_14X_OR_HIGHER_CONFIG
51         { .compatible = "nvidia,tegra148-vi",
52                 .data = (struct nvhost_device_data *)&t14_vi_info },
53 #endif
54 #ifdef TEGRA_12X_OR_HIGHER_CONFIG
55         { .compatible = "nvidia,tegra124-vi",
56                 .data = (struct nvhost_device_data *)&t124_vi_info },
57 #endif
58         { },
59 };
60
61 static struct i2c_camera_ctrl *i2c_ctrl;
62
63 #if defined(CONFIG_TEGRA_ISOMGR)
64 static int vi_isomgr_unregister(struct vi *tegra_vi)
65 {
66         tegra_isomgr_unregister(tegra_vi->isomgr_handle);
67         tegra_vi->isomgr_handle = NULL;
68
69         return 0;
70 }
71 #endif
72
73 static int vi_out_show(struct seq_file *s, void *unused)
74 {
75         struct vi *vi = s->private;
76
77         seq_printf(s, "vi[%d] overflow: %u\n", vi->ndev->id,
78                 atomic_read(&(vi->vi_out.overflow)));
79
80         return 0;
81 }
82
83 static int vi_out_open(struct inode *inode, struct file *file)
84 {
85         return single_open(file, vi_out_show, inode->i_private);
86 }
87
88 static const struct file_operations vi_out_fops = {
89         .open           = vi_out_open,
90         .read           = seq_read,
91         .llseek         = seq_lseek,
92         .release        = single_release,
93 };
94
95 static void vi_remove_debugfs(struct vi *vi)
96 {
97         debugfs_remove_recursive(vi->debugdir);
98         vi->debugdir = NULL;
99 }
100
101 static void vi_create_debugfs(struct vi *vi)
102 {
103         struct dentry *ret;
104         char tegra_vi_name[20];
105         char debugfs_file_name[20];
106
107
108         snprintf(tegra_vi_name, sizeof(tegra_vi_name),
109                         "%s_%u", TEGRA_VI_NAME, vi->ndev->id);
110
111         vi->debugdir = debugfs_create_dir(tegra_vi_name, NULL);
112         if (!vi->debugdir) {
113                 dev_err(&vi->ndev->dev,
114                         "%s: failed to create %s directory",
115                         __func__, tegra_vi_name);
116                 goto create_debugfs_fail;
117         }
118
119         snprintf(debugfs_file_name, sizeof(debugfs_file_name),
120                         "%s_%u", "vi_out", vi->ndev->id);
121
122         ret = debugfs_create_file(debugfs_file_name, S_IRUGO,
123                         vi->debugdir, vi, &vi_out_fops);
124         if (!ret) {
125                 dev_err(&vi->ndev->dev,
126                 "%s: failed to create %s", __func__, debugfs_file_name);
127                 goto create_debugfs_fail;
128         }
129
130         return;
131
132 create_debugfs_fail:
133         dev_err(&vi->ndev->dev, "%s: could not create debugfs", __func__);
134         vi_remove_debugfs(vi);
135 }
136
137 static int vi_probe(struct platform_device *dev)
138 {
139         int err = 0;
140         struct vi *tegra_vi;
141         struct nvhost_device_data *pdata = NULL;
142         if (dev->dev.of_node) {
143                 const struct of_device_id *match;
144
145                 match = of_match_device(tegra_vi_of_match, &dev->dev);
146                 if (match) {
147                         pdata = (struct nvhost_device_data *)match->data;
148                         dev->dev.platform_data = pdata;
149                 }
150
151                 /* DT initializes it to -1, use below WAR to set correct value.
152                  * TODO: Once proper fix for dev-id goes in, remove it.
153                  */
154                 dev->id = dev->dev.id;
155         } else
156                 pdata = (struct nvhost_device_data *)dev->dev.platform_data;
157
158         WARN_ON(!pdata);
159         if (!pdata) {
160                 dev_info(&dev->dev, "no platform data\n");
161                 return -ENODATA;
162         }
163
164         pdata->pdev = dev;
165         mutex_init(&pdata->lock);
166         platform_set_drvdata(dev, pdata);
167
168         dev_info(&dev->dev, "%s: ++\n", __func__);
169
170         tegra_vi = devm_kzalloc(&dev->dev, sizeof(struct vi), GFP_KERNEL);
171         if (!tegra_vi) {
172                 dev_err(&dev->dev, "can't allocate memory for vi\n");
173                 return -ENOMEM;
174         }
175
176         err = nvhost_client_device_get_resources(dev);
177         if (err)
178                 goto vi_probe_fail;
179
180         tegra_vi->ndev = dev;
181
182         /* call vi_intr_init and stats_work */
183         INIT_WORK(&tegra_vi->stats_work, vi_stats_worker);
184
185         err = vi_intr_init(tegra_vi);
186         if (err)
187                 goto vi_probe_fail;
188
189         vi_create_debugfs(tegra_vi);
190
191         i2c_ctrl = pdata->private_data;
192         pdata->private_data = tegra_vi;
193
194         /* Create I2C Devices according to settings from board file */
195         if (i2c_ctrl && i2c_ctrl->new_devices)
196                 i2c_ctrl->new_devices(dev);
197
198         tegra_vi->reg = regulator_get(&tegra_vi->ndev->dev, "avdd_dsi_csi");
199         if (IS_ERR(tegra_vi->reg)) {
200                 err = PTR_ERR(tegra_vi->reg);
201                 if (err == -ENODEV)
202                         dev_info(&tegra_vi->ndev->dev,
203                                 "%s: no regulator device\n", __func__);
204                 else
205                         dev_err(&tegra_vi->ndev->dev,
206                                 "%s: couldn't get regulator\n", __func__);
207                 tegra_vi->reg = NULL;
208                 goto camera_i2c_unregister;
209         }
210
211 #ifdef CONFIG_TEGRA_CAMERA
212         tegra_vi->camera = tegra_camera_register(dev);
213         if (!tegra_vi->camera) {
214                 dev_err(&dev->dev, "%s: can't register tegra_camera\n",
215                                 __func__);
216                 goto vi_regulator_put;
217         }
218 #endif
219
220         nvhost_module_init(dev);
221
222 #ifdef CONFIG_PM_GENERIC_DOMAINS
223         pdata->pd.name = "ve";
224
225         /* add module power domain and also add its domain
226          * as sub-domain of MC domain */
227         err = nvhost_module_add_domain(&pdata->pd, dev);
228 #endif
229
230         err = nvhost_client_device_init(dev);
231         if (err)
232                 goto camera_unregister;
233
234         return 0;
235
236 camera_unregister:
237 #ifdef CONFIG_TEGRA_CAMERA
238         tegra_camera_unregister(tegra_vi->camera);
239 vi_regulator_put:
240 #endif
241         regulator_put(tegra_vi->reg);
242         tegra_vi->reg = NULL;
243
244 camera_i2c_unregister:
245         if (i2c_ctrl && i2c_ctrl->remove_devices)
246                 i2c_ctrl->remove_devices(dev);
247         pdata->private_data = i2c_ctrl;
248 vi_probe_fail:
249         dev_err(&dev->dev, "%s: failed\n", __func__);
250         return err;
251 }
252
253 static int __exit vi_remove(struct platform_device *dev)
254 {
255 #ifdef CONFIG_TEGRA_CAMERA
256         int err = 0;
257 #endif
258         struct nvhost_device_data *pdata = platform_get_drvdata(dev);
259         struct vi *tegra_vi = (struct vi *)pdata->private_data;
260
261         dev_info(&dev->dev, "%s: ++\n", __func__);
262
263 #if defined(CONFIG_TEGRA_ISOMGR)
264         if (tegra_vi->isomgr_handle)
265                 vi_isomgr_unregister(tegra_vi);
266 #endif
267
268         vi_remove_debugfs(tegra_vi);
269
270         vi_intr_free(tegra_vi);
271
272         nvhost_client_device_release(dev);
273         pdata->aperture[0] = NULL;
274
275 #ifdef CONFIG_TEGRA_CAMERA
276         err = tegra_camera_unregister(tegra_vi->camera);
277         if (err)
278                 return err;
279 #endif
280
281 #ifdef CONFIG_PM_GENERIC_DOMAINS
282         tegra_pd_remove_device(&dev->dev);
283 #endif
284
285         regulator_put(tegra_vi->reg);
286         tegra_vi->reg = NULL;
287
288         /* Remove I2C Devices according to settings from board file */
289         if (i2c_ctrl && i2c_ctrl->remove_devices)
290                 i2c_ctrl->remove_devices(dev);
291
292         pdata->private_data = i2c_ctrl;
293
294         return 0;
295 }
296
297 static struct platform_driver vi_driver = {
298         .probe = vi_probe,
299         .remove = __exit_p(vi_remove),
300         .driver = {
301                 .owner = THIS_MODULE,
302                 .name = "vi",
303 #ifdef CONFIG_PM
304                 .pm = &nvhost_module_pm_ops,
305 #endif
306 #ifdef CONFIG_OF
307                 .of_match_table = tegra_vi_of_match,
308 #endif
309         }
310 };
311
312 static int __init vi_init(void)
313 {
314         return platform_driver_register(&vi_driver);
315 }
316
317 static void __exit vi_exit(void)
318 {
319         platform_driver_unregister(&vi_driver);
320 }
321
322 late_initcall(vi_init);
323 module_exit(vi_exit);
324 MODULE_LICENSE("GPL v2");