]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/blob - drivers/media/platform/tegra/camera/mc_common.c
media: tegra_camera: add SoC fops for VI
[sojka/nv-tegra/linux-3.10.git] / drivers / media / platform / tegra / camera / mc_common.c
1 /*
2  * Tegra Video Input device common APIs
3  *
4  * Copyright (c) 2015-2016, NVIDIA CORPORATION.  All rights reserved.
5  *
6  * Author: Bryan Wu <pengw@nvidia.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <linux/init.h>
14 #include <linux/export.h>
15 #include <linux/module.h>
16 #include <linux/of.h>
17 #include <linux/of_device.h>
18 #include <linux/of_platform.h>
19
20 #include <media/tegra_v4l2_camera.h>
21 #include <media/camera_common.h>
22 #include <media/v4l2-event.h>
23 #include <media/tegra_camera_platform.h>
24
25 #include "dev.h"
26 #include "camera/mc_common.h"
27 #include "vi/vi.h"
28 #include "camera/registers.h"
29
30 /* In TPG mode, VI only support 2 formats */
31 static void vi_tpg_fmts_bitmap_init(struct tegra_mc_vi *vi)
32 {
33         int index;
34
35         bitmap_zero(vi->tpg_fmts_bitmap, MAX_FORMAT_NUM);
36
37         index = tegra_core_get_idx_by_code(MEDIA_BUS_FMT_SRGGB10_1X10);
38         bitmap_set(vi->tpg_fmts_bitmap, index, 1);
39
40         index = tegra_core_get_idx_by_code(MEDIA_BUS_FMT_RGB888_1X32_PADHI);
41         bitmap_set(vi->tpg_fmts_bitmap, index, 1);
42 }
43
44 int tegra_vi_power_on(struct tegra_mc_vi *vi)
45 {
46         int ret;
47
48         if (atomic_add_return(1, &vi->power_on_refcnt) > 1)
49                 return 0;
50
51         ret = nvhost_module_busy_ext(vi->ndev);
52         if (ret) {
53                 dev_err(vi->dev, "%s:nvhost module is busy\n", __func__);
54                 return ret;
55         }
56
57         if (vi->reg) {
58                 ret = regulator_enable(vi->reg);
59                 if (ret) {
60                         dev_err(vi->dev, "%s: enable csi regulator failed.\n",
61                                         __func__);
62                         goto error_regulator_fail;
63                 }
64         }
65
66         ret = vi->fops->soc_power_on(vi);
67         if (ret)
68                 goto error_soc_power_on;
69
70         /* clock settings */
71         clk_prepare_enable(vi->clk);
72         ret = clk_set_rate(vi->clk, 0);
73         if (ret) {
74                 dev_err(vi->dev, "failed to set vi clock\n");
75                 goto error_clk_set_rate;
76         }
77
78         ret = tegra_camera_emc_clk_enable();
79         if (ret)
80                 goto err_emc_enable;
81
82         return 0;
83 err_emc_enable:
84         clk_disable_unprepare(vi->clk);
85 error_clk_set_rate:
86         vi->fops->soc_power_off(vi);
87 error_soc_power_on:
88         regulator_disable(vi->reg);
89 error_regulator_fail:
90         nvhost_module_idle_ext(vi->ndev);
91
92         return ret;
93 }
94
95 void tegra_vi_power_off(struct tegra_mc_vi *vi)
96 {
97         if (!atomic_dec_and_test(&vi->power_on_refcnt))
98                 return;
99
100         tegra_channel_ec_close(vi);
101         tegra_camera_emc_clk_disable();
102         clk_disable_unprepare(vi->clk);
103         vi->fops->soc_power_off(vi);
104         regulator_disable(vi->reg);
105         nvhost_module_idle_ext(vi->ndev);
106 }
107
108 /* -----------------------------------------------------------------------------
109  * Media Controller and V4L2
110  */
111
112 static const char *const vi_pattern_strings[] = {
113         "Disabled",
114         "Black/White Direct Mode",
115         "Color Patch Mode",
116 };
117
118 static int vi_s_ctrl(struct v4l2_ctrl *ctrl)
119 {
120         struct tegra_mc_vi *vi = container_of(ctrl->handler, struct tegra_mc_vi,
121                                            ctrl_handler);
122
123         switch (ctrl->id) {
124         case V4L2_CID_TEST_PATTERN:
125                 /*
126                  * TPG control is only avaiable to TPG driver,
127                  * it can't be changed to 0 to disable TPG mode.
128                  */
129                 if (!vi->pg_mode)
130                         break;
131
132                 if (ctrl->val) {
133                         dev_info(&vi->ndev->dev, "Set TPG mode to %d\n",
134                                  ctrl->val);
135                         vi->pg_mode = ctrl->val;
136                         vi->csi->pg_mode = vi->pg_mode;
137                 } else
138                         dev_warn(&vi->ndev->dev,
139                                  "TPG mode can't be disabled for TPG driver\n");
140                 break;
141         default:
142                 dev_err(vi->dev, "%s:Not valid ctrl\n", __func__);
143                 return -EINVAL;
144         }
145
146         return 0;
147 }
148
149 static const struct v4l2_ctrl_ops vi_ctrl_ops = {
150         .s_ctrl = vi_s_ctrl,
151 };
152
153 void tegra_vi_v4l2_cleanup(struct tegra_mc_vi *vi)
154 {
155         v4l2_ctrl_handler_free(&vi->ctrl_handler);
156         v4l2_device_unregister(&vi->v4l2_dev);
157         if (!vi->pg_mode)
158                 media_device_unregister(&vi->media_dev);
159 }
160 EXPORT_SYMBOL(tegra_vi_v4l2_cleanup);
161
162 static void tegra_vi_notify(struct v4l2_subdev *sd,
163                                           unsigned int notification, void *arg)
164 {
165         struct tegra_mc_vi *vi = container_of(sd->v4l2_dev,
166                         struct tegra_mc_vi, v4l2_dev);
167         unsigned ch, i;
168
169         if (notification != V4L2_DEVICE_NOTIFY_EVENT)
170                 return;
171
172         for (ch = 0; ch < vi->num_channels; ch++) {
173                 struct tegra_channel *chan = &vi->chans[ch];
174
175                 for (i = 0; i < chan->num_subdevs; i++)
176                         if (sd == chan->subdev[i])
177                                 v4l2_event_queue(&chan->video, arg);
178         }
179 }
180
181 int tegra_vi_v4l2_init(struct tegra_mc_vi *vi)
182 {
183         int ret;
184
185         vi_tpg_fmts_bitmap_init(vi);
186
187         /*
188          * TPG mode need to reuse the real media_device struct of tegra_vi,
189          * so bypass the media_device_register() here.
190          */
191         if (vi->pg_mode) {
192                 struct vi *tegra_vi = tegra_vi_get();
193                 if (tegra_vi)
194                         memcpy(&vi->media_dev, &tegra_vi->mc_vi.media_dev,
195                                         sizeof(struct media_device));
196         } else {
197                 vi->media_dev.dev = vi->dev;
198                 strlcpy(vi->media_dev.model, "NVIDIA Tegra Video Input Device",
199                                 sizeof(vi->media_dev.model));
200                 vi->media_dev.hw_revision = 3;
201
202                 ret = media_device_register(&vi->media_dev);
203                 if (ret < 0) {
204                         dev_err(vi->dev, "media device registration failed (%d)\n",
205                                         ret);
206                         return ret;
207                 }
208         }
209         mutex_init(&vi->bw_update_lock);
210         mutex_init(&vi->mipical_lock);
211         vi->v4l2_dev.mdev = &vi->media_dev;
212         vi->v4l2_dev.notify = tegra_vi_notify;
213         ret = v4l2_device_register(vi->dev, &vi->v4l2_dev);
214         if (ret < 0) {
215                 dev_err(vi->dev, "V4L2 device registration failed (%d)\n",
216                         ret);
217                 goto register_error;
218         }
219
220         v4l2_ctrl_handler_init(&vi->ctrl_handler, 1);
221         vi->pattern = v4l2_ctrl_new_std_menu_items(&vi->ctrl_handler,
222                                 &vi_ctrl_ops, V4L2_CID_TEST_PATTERN,
223                                 ARRAY_SIZE(vi_pattern_strings) - 1,
224                                 0, vi->pg_mode, vi_pattern_strings);
225
226         if (vi->ctrl_handler.error) {
227                 dev_err(vi->dev, "failed to add controls\n");
228                 ret = vi->ctrl_handler.error;
229                 goto ctrl_error;
230         }
231         vi->v4l2_dev.ctrl_handler = &vi->ctrl_handler;
232
233         ret = v4l2_ctrl_handler_setup(&vi->ctrl_handler);
234         if (ret < 0) {
235                 dev_err(vi->dev, "failed to set controls\n");
236                 goto ctrl_error;
237         }
238         return 0;
239
240
241 ctrl_error:
242         v4l2_ctrl_handler_free(&vi->ctrl_handler);
243         v4l2_device_unregister(&vi->v4l2_dev);
244 register_error:
245         if (!vi->pg_mode)
246                 media_device_unregister(&vi->media_dev);
247         return ret;
248 }
249
250 static int vi_get_clks(struct tegra_mc_vi *vi, struct platform_device *pdev)
251 {
252         int ret = 0;
253
254         vi->clk = devm_clk_get(&pdev->dev, "vi_v4l2");
255         if (IS_ERR(vi->clk)) {
256                 dev_err(&pdev->dev, "Failed to get vi clock\n");
257                 return PTR_ERR(vi->clk);
258         }
259
260         return ret;
261 }
262
263 static int vi_parse_dt(struct tegra_mc_vi *vi, struct platform_device *dev)
264 {
265         int err = 0;
266         int num_channels = 0;
267         struct device_node *node = dev->dev.of_node;
268
269         err = of_property_read_u32(node, "num-channels", &num_channels);
270         if (err) {
271                 dev_err(&dev->dev,
272                         "Failed to find num of channels, set TPG mode\n");
273                 vi->pg_mode = TEGRA_VI_PG_PATCH;
274         }
275
276         vi->num_channels = num_channels;
277         vi->chans = devm_kzalloc(&dev->dev,
278                         (sizeof(struct tegra_channel) * num_channels),
279                         GFP_KERNEL);
280         if (!vi->chans)
281                 return -ENOMEM;
282
283         return 0;
284 }
285
286 static void set_vi_register_base(struct tegra_mc_vi *mc_vi,
287                         void __iomem *regbase)
288 {
289         mc_vi->iomem = regbase;
290 }
291
292 int tegra_vi_media_controller_init(struct tegra_mc_vi *mc_vi,
293                                    struct platform_device *pdev)
294 {
295         int err = 0;
296         struct nvhost_device_data *pdata = pdev->dev.platform_data;
297
298         set_vi_register_base(mc_vi, pdata->aperture[0]);
299
300         err = vi_get_clks(mc_vi, pdev);
301         if (err)
302                 return err;
303
304         if (mc_vi->pg_mode) {
305                 mc_vi->chans = devm_kzalloc(&pdev->dev,
306                                             sizeof(struct tegra_channel) *
307                                             mc_vi->num_channels,
308                                             GFP_KERNEL);
309                 if (!mc_vi->chans)
310                         return -ENOMEM;
311         } else {
312                 err = vi_parse_dt(mc_vi, pdev);
313                 if (err)
314                         goto mc_init_fail;
315         }
316
317         mc_vi->ndev = pdev;
318         mc_vi->dev = &pdev->dev;
319         INIT_LIST_HEAD(&mc_vi->entities);
320
321         err = tegra_vi_v4l2_init(mc_vi);
322         if (err < 0)
323                 goto mc_init_fail;
324
325         /* Init Tegra VI channels */
326         err = tegra_vi_channels_init(mc_vi);
327         if (err < 0)
328                 goto channels_error;
329
330         /* Setup media links between VI and external sensor subdev. */
331         if (mc_vi->pg_mode)
332                 err = tegra_vi_tpg_graph_init(mc_vi);
333         else
334                 err = tegra_vi_graph_init(mc_vi);
335         if (err < 0)
336                 goto graph_error;
337
338         return 0;
339
340 graph_error:
341         tegra_vi_channels_cleanup(mc_vi);
342 channels_error:
343         tegra_vi_v4l2_cleanup(mc_vi);
344 mc_init_fail:
345         dev_err(&pdev->dev, "%s: failed\n", __func__);
346         return err;
347 }
348 EXPORT_SYMBOL(tegra_vi_media_controller_init);
349
350 void tegra_vi_media_controller_cleanup(struct tegra_mc_vi *mc_vi)
351 {
352         tegra_vi_graph_cleanup(mc_vi);
353         tegra_vi_channels_cleanup(mc_vi);
354         tegra_vi_v4l2_cleanup(mc_vi);
355 }
356 EXPORT_SYMBOL(tegra_vi_media_controller_cleanup);