GNU Linux-libre 4.14.262-gnu1
[releases.git] / drivers / staging / media / atomisp / pci / atomisp2 / atomisp_file.c
1 /*
2  * Support for Medifield PNW Camera Imaging ISP subsystem.
3  *
4  * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
5  *
6  * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License version
10  * 2 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  * 02110-1301, USA.
21  *
22  */
23
24 #include <media/v4l2-event.h>
25 #include <media/v4l2-mediabus.h>
26
27 #include <media/videobuf-vmalloc.h>
28 #include <linux/delay.h>
29
30 #include "ia_css.h"
31
32 #include "atomisp_cmd.h"
33 #include "atomisp_common.h"
34 #include "atomisp_file.h"
35 #include "atomisp_internal.h"
36 #include "atomisp_ioctl.h"
37
38 static void file_work(struct work_struct *work)
39 {
40         struct atomisp_file_device *file_dev =
41                         container_of(work, struct atomisp_file_device, work);
42         struct atomisp_device *isp = file_dev->isp;
43         /* only support file injection on subdev0 */
44         struct atomisp_sub_device *asd = &isp->asd[0];
45         struct atomisp_video_pipe *out_pipe = &asd->video_in;
46         unsigned short *buf = videobuf_to_vmalloc(out_pipe->outq.bufs[0]);
47         struct v4l2_mbus_framefmt isp_sink_fmt;
48
49         if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED)
50                 return;
51
52         dev_dbg(isp->dev, ">%s: ready to start streaming\n", __func__);
53         isp_sink_fmt = *atomisp_subdev_get_ffmt(&asd->subdev, NULL,
54                                                 V4L2_SUBDEV_FORMAT_ACTIVE,
55                                                 ATOMISP_SUBDEV_PAD_SINK);
56
57         while (!atomisp_css_isp_has_started())
58                 usleep_range(1000, 1500);
59
60         atomisp_css_send_input_frame(asd, buf, isp_sink_fmt.width,
61                                      isp_sink_fmt.height);
62         dev_dbg(isp->dev, "<%s: streaming done\n", __func__);
63 }
64
65 static int file_input_s_stream(struct v4l2_subdev *sd, int enable)
66 {
67         struct atomisp_file_device *file_dev = v4l2_get_subdevdata(sd);
68         struct atomisp_device *isp = file_dev->isp;
69         /* only support file injection on subdev0 */
70         struct atomisp_sub_device *asd = &isp->asd[0];
71
72         dev_dbg(isp->dev, "%s: enable %d\n", __func__, enable);
73         if (enable) {
74                 if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED)
75                         return 0;
76
77                 queue_work(file_dev->work_queue, &file_dev->work);
78                 return 0;
79         }
80         cancel_work_sync(&file_dev->work);
81         return 0;
82 }
83
84 static int file_input_g_parm(struct v4l2_subdev *sd,
85                 struct v4l2_streamparm *param)
86 {
87         /*to fake*/
88         return 0;
89 }
90
91 static int file_input_s_parm(struct v4l2_subdev *sd,
92                 struct v4l2_streamparm *param)
93 {
94         /*to fake*/
95         return 0;
96 }
97
98 static int file_input_get_fmt(struct v4l2_subdev *sd,
99                               struct v4l2_subdev_pad_config *cfg,
100                               struct v4l2_subdev_format *format)
101 {
102         struct v4l2_mbus_framefmt *fmt = &format->format;
103         struct atomisp_file_device *file_dev = v4l2_get_subdevdata(sd);
104         struct atomisp_device *isp = file_dev->isp;
105         /* only support file injection on subdev0 */
106         struct atomisp_sub_device *asd = &isp->asd[0];
107         struct v4l2_mbus_framefmt *isp_sink_fmt;
108         if (format->pad)
109                 return -EINVAL;
110         isp_sink_fmt = atomisp_subdev_get_ffmt(&asd->subdev, NULL,
111                                                V4L2_SUBDEV_FORMAT_ACTIVE,
112                                                ATOMISP_SUBDEV_PAD_SINK);
113
114         fmt->width = isp_sink_fmt->width;
115         fmt->height = isp_sink_fmt->height;
116         fmt->code = isp_sink_fmt->code;
117
118         return 0;
119 }
120
121 static int file_input_set_fmt(struct v4l2_subdev *sd,
122                               struct v4l2_subdev_pad_config *cfg,
123                               struct v4l2_subdev_format *format)
124 {
125         struct v4l2_mbus_framefmt *fmt = &format->format;
126         if (format->pad)
127                 return -EINVAL;
128         file_input_get_fmt(sd, cfg, format);
129         if (format->which == V4L2_SUBDEV_FORMAT_TRY)
130                 cfg->try_fmt = *fmt;
131         return 0;
132 }
133
134 static int file_input_log_status(struct v4l2_subdev *sd)
135 {
136         /*to fake*/
137         return 0;
138 }
139
140 static int file_input_s_power(struct v4l2_subdev *sd, int on)
141 {
142         /* to fake */
143         return 0;
144 }
145
146 static int file_input_enum_mbus_code(struct v4l2_subdev *sd,
147                                      struct v4l2_subdev_pad_config *cfg,
148                                      struct v4l2_subdev_mbus_code_enum *code)
149 {
150         /*to fake*/
151         return 0;
152 }
153
154 static int file_input_enum_frame_size(struct v4l2_subdev *sd,
155                                       struct v4l2_subdev_pad_config *cfg,
156                                       struct v4l2_subdev_frame_size_enum *fse)
157 {
158         /*to fake*/
159         return 0;
160 }
161
162 static int file_input_enum_frame_ival(struct v4l2_subdev *sd,
163                                       struct v4l2_subdev_pad_config *cfg,
164                                       struct v4l2_subdev_frame_interval_enum
165                                       *fie)
166 {
167         /*to fake*/
168         return 0;
169 }
170
171 static const struct v4l2_subdev_video_ops file_input_video_ops = {
172         .s_stream = file_input_s_stream,
173         .g_parm = file_input_g_parm,
174         .s_parm = file_input_s_parm,
175 };
176
177 static const struct v4l2_subdev_core_ops file_input_core_ops = {
178         .log_status = file_input_log_status,
179         .s_power = file_input_s_power,
180 };
181
182 static const struct v4l2_subdev_pad_ops file_input_pad_ops = {
183         .enum_mbus_code = file_input_enum_mbus_code,
184         .enum_frame_size = file_input_enum_frame_size,
185         .enum_frame_interval = file_input_enum_frame_ival,
186         .get_fmt = file_input_get_fmt,
187         .set_fmt = file_input_set_fmt,
188 };
189
190 static const struct v4l2_subdev_ops file_input_ops = {
191         .core = &file_input_core_ops,
192         .video = &file_input_video_ops,
193         .pad = &file_input_pad_ops,
194 };
195
196 void
197 atomisp_file_input_unregister_entities(struct atomisp_file_device *file_dev)
198 {
199         media_entity_cleanup(&file_dev->sd.entity);
200         v4l2_device_unregister_subdev(&file_dev->sd);
201 }
202
203 int atomisp_file_input_register_entities(struct atomisp_file_device *file_dev,
204                         struct v4l2_device *vdev)
205 {
206         /* Register the subdev and video nodes. */
207         return  v4l2_device_register_subdev(vdev, &file_dev->sd);
208 }
209
210 void atomisp_file_input_cleanup(struct atomisp_device *isp)
211 {
212         struct atomisp_file_device *file_dev = &isp->file_dev;
213
214         if (file_dev->work_queue) {
215                 destroy_workqueue(file_dev->work_queue);
216                 file_dev->work_queue = NULL;
217         }
218 }
219
220 int atomisp_file_input_init(struct atomisp_device *isp)
221 {
222         struct atomisp_file_device *file_dev = &isp->file_dev;
223         struct v4l2_subdev *sd = &file_dev->sd;
224         struct media_pad *pads = file_dev->pads;
225         struct media_entity *me = &sd->entity;
226
227         file_dev->isp = isp;
228         file_dev->work_queue = alloc_workqueue(isp->v4l2_dev.name, 0, 1);
229         if (file_dev->work_queue == NULL) {
230                 dev_err(isp->dev, "Failed to initialize file inject workq\n");
231                 return -ENOMEM;
232         }
233
234         INIT_WORK(&file_dev->work, file_work);
235
236         v4l2_subdev_init(sd, &file_input_ops);
237         sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
238         strcpy(sd->name, "file_input_subdev");
239         v4l2_set_subdevdata(sd, file_dev);
240
241         pads[0].flags = MEDIA_PAD_FL_SINK;
242         me->function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
243
244         return media_entity_pads_init(me, 1, pads);
245 }