blob: 34676409ca085b29969905350f751c1004f5ca04 [file] [log] [blame]
Songjun Wu106267442016-08-17 03:05:27 -03001/*
2 * Atmel Image Sensor Controller (ISC) driver
3 *
4 * Copyright (C) 2016 Atmel
5 *
6 * Author: Songjun Wu <songjun.wu@microchip.com>
7 *
8 * This program is free software; you may redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * Sensor-->PFE-->WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB-->RLP-->DMA
13 *
14 * ISC video pipeline integrates the following submodules:
15 * PFE: Parallel Front End to sample the camera sensor input stream
16 * WB: Programmable white balance in the Bayer domain
17 * CFA: Color filter array interpolation module
18 * CC: Programmable color correction
19 * GAM: Gamma correction
20 * CSC: Programmable color space conversion
21 * CBC: Contrast and Brightness control
22 * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling
23 * RLP: This module performs rounding, range limiting
24 * and packing of the incoming data
25 */
26
27#include <linux/clk.h>
28#include <linux/clkdev.h>
29#include <linux/clk-provider.h>
30#include <linux/delay.h>
31#include <linux/interrupt.h>
Songjun Wu93d4a262017-01-24 06:05:57 -020032#include <linux/math64.h>
Songjun Wu106267442016-08-17 03:05:27 -030033#include <linux/module.h>
34#include <linux/of.h>
Sakari Ailus859969b2016-08-26 20:17:25 -030035#include <linux/of_graph.h>
Songjun Wu106267442016-08-17 03:05:27 -030036#include <linux/platform_device.h>
37#include <linux/pm_runtime.h>
38#include <linux/regmap.h>
39#include <linux/videodev2.h>
40
Songjun Wu93d4a262017-01-24 06:05:57 -020041#include <media/v4l2-ctrls.h>
Songjun Wu106267442016-08-17 03:05:27 -030042#include <media/v4l2-device.h>
Songjun Wu93d4a262017-01-24 06:05:57 -020043#include <media/v4l2-event.h>
Songjun Wu106267442016-08-17 03:05:27 -030044#include <media/v4l2-image-sizes.h>
45#include <media/v4l2-ioctl.h>
Sakari Ailus859969b2016-08-26 20:17:25 -030046#include <media/v4l2-fwnode.h>
Songjun Wu106267442016-08-17 03:05:27 -030047#include <media/v4l2-subdev.h>
48#include <media/videobuf2-dma-contig.h>
49
50#include "atmel-isc-regs.h"
51
52#define ATMEL_ISC_NAME "atmel_isc"
53
54#define ISC_MAX_SUPPORT_WIDTH 2592
55#define ISC_MAX_SUPPORT_HEIGHT 1944
56
57#define ISC_CLK_MAX_DIV 255
58
59enum isc_clk_id {
60 ISC_ISPCK = 0,
61 ISC_MCK = 1,
62};
63
64struct isc_clk {
65 struct clk_hw hw;
66 struct clk *clk;
67 struct regmap *regmap;
Wenyou Yangcab1dea2017-10-10 04:46:36 +020068 spinlock_t lock;
Songjun Wu106267442016-08-17 03:05:27 -030069 u8 id;
70 u8 parent_id;
71 u32 div;
72 struct device *dev;
73};
74
75#define to_isc_clk(hw) container_of(hw, struct isc_clk, hw)
76
77struct isc_buffer {
78 struct vb2_v4l2_buffer vb;
79 struct list_head list;
80};
81
82struct isc_subdev_entity {
83 struct v4l2_subdev *sd;
84 struct v4l2_async_subdev *asd;
85 struct v4l2_async_notifier notifier;
Songjun Wu106267442016-08-17 03:05:27 -030086
87 u32 pfe_cfg0;
88
89 struct list_head list;
90};
91
Wenyou Yangf103ea12017-10-10 04:46:40 +020092/* Indicate the format is generated by the sensor */
93#define FMT_FLAG_FROM_SENSOR BIT(0)
94/* Indicate the format is produced by ISC itself */
95#define FMT_FLAG_FROM_CONTROLLER BIT(1)
96/* Indicate a Raw Bayer format */
97#define FMT_FLAG_RAW_FORMAT BIT(2)
98
99#define FMT_FLAG_RAW_FROM_SENSOR (FMT_FLAG_FROM_SENSOR | \
100 FMT_FLAG_RAW_FORMAT)
101
Songjun Wu106267442016-08-17 03:05:27 -0300102/*
103 * struct isc_format - ISC media bus format information
104 * @fourcc: Fourcc code for this format
105 * @mbus_code: V4L2 media bus format code.
Wenyou Yangf103ea12017-10-10 04:46:40 +0200106 * flags: Indicate format from sensor or converted by controller
Songjun Wu93d4a262017-01-24 06:05:57 -0200107 * @bpp: Bits per pixel (when stored in memory)
Songjun Wu106267442016-08-17 03:05:27 -0300108 * (when transferred over a bus)
Songjun Wu93d4a262017-01-24 06:05:57 -0200109 * @sd_support: Subdev supports this format
110 * @isc_support: ISC can convert raw format to this format
Songjun Wu106267442016-08-17 03:05:27 -0300111 */
Wenyou Yangf103ea12017-10-10 04:46:40 +0200112
Songjun Wu106267442016-08-17 03:05:27 -0300113struct isc_format {
114 u32 fourcc;
115 u32 mbus_code;
Wenyou Yangf103ea12017-10-10 04:46:40 +0200116 u32 flags;
Songjun Wu106267442016-08-17 03:05:27 -0300117 u8 bpp;
118
Songjun Wu93d4a262017-01-24 06:05:57 -0200119 bool sd_support;
120 bool isc_support;
121};
122
Wenyou Yangf103ea12017-10-10 04:46:40 +0200123/* Pipeline bitmap */
124#define WB_ENABLE BIT(0)
125#define CFA_ENABLE BIT(1)
126#define CC_ENABLE BIT(2)
127#define GAM_ENABLE BIT(3)
128#define GAM_BENABLE BIT(4)
129#define GAM_GENABLE BIT(5)
130#define GAM_RENABLE BIT(6)
131#define CSC_ENABLE BIT(7)
132#define CBC_ENABLE BIT(8)
133#define SUB422_ENABLE BIT(9)
134#define SUB420_ENABLE BIT(10)
135
136#define GAM_ENABLES (GAM_RENABLE | GAM_GENABLE | GAM_BENABLE | GAM_ENABLE)
137
138struct fmt_config {
139 u32 fourcc;
140
141 u32 pfe_cfg0_bps;
142 u32 cfa_baycfg;
143 u32 rlp_cfg_mode;
144 u32 dcfg_imode;
145 u32 dctrl_dview;
146
147 u32 bits_pipeline;
148};
Songjun Wu93d4a262017-01-24 06:05:57 -0200149
150#define HIST_ENTRIES 512
151#define HIST_BAYER (ISC_HIS_CFG_MODE_B + 1)
152
153enum{
154 HIST_INIT = 0,
155 HIST_ENABLED,
156 HIST_DISABLED,
157};
158
159struct isc_ctrls {
160 struct v4l2_ctrl_handler handler;
161
162 u32 brightness;
163 u32 contrast;
164 u8 gamma_index;
165 u8 awb;
166
167 u32 r_gain;
168 u32 b_gain;
169
170 u32 hist_entry[HIST_ENTRIES];
171 u32 hist_count[HIST_BAYER];
172 u8 hist_id;
173 u8 hist_stat;
Songjun Wu106267442016-08-17 03:05:27 -0300174};
175
176#define ISC_PIPE_LINE_NODE_NUM 11
177
178struct isc_device {
179 struct regmap *regmap;
180 struct clk *hclock;
181 struct clk *ispck;
182 struct isc_clk isc_clks[2];
183
184 struct device *dev;
185 struct v4l2_device v4l2_dev;
186 struct video_device video_dev;
187
188 struct vb2_queue vb2_vidq;
189 spinlock_t dma_queue_lock;
190 struct list_head dma_queue;
191 struct isc_buffer *cur_frm;
192 unsigned int sequence;
193 bool stop;
194 struct completion comp;
195
196 struct v4l2_format fmt;
197 struct isc_format **user_formats;
198 unsigned int num_user_formats;
199 const struct isc_format *current_fmt;
Songjun Wu93d4a262017-01-24 06:05:57 -0200200 const struct isc_format *raw_fmt;
201
202 struct isc_ctrls ctrls;
203 struct work_struct awb_work;
Songjun Wu106267442016-08-17 03:05:27 -0300204
205 struct mutex lock;
206
207 struct regmap_field *pipeline[ISC_PIPE_LINE_NODE_NUM];
208
209 struct isc_subdev_entity *current_subdev;
210 struct list_head subdev_entities;
211};
212
Wenyou Yangf103ea12017-10-10 04:46:40 +0200213static struct isc_format formats_list[] = {
214 {
215 .fourcc = V4L2_PIX_FMT_SBGGR8,
216 .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
217 .flags = FMT_FLAG_RAW_FROM_SENSOR,
218 .bpp = 8,
219 },
220 {
221 .fourcc = V4L2_PIX_FMT_SGBRG8,
222 .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
223 .flags = FMT_FLAG_RAW_FROM_SENSOR,
224 .bpp = 8,
225 },
226 {
227 .fourcc = V4L2_PIX_FMT_SGRBG8,
228 .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
229 .flags = FMT_FLAG_RAW_FROM_SENSOR,
230 .bpp = 8,
231 },
232 {
233 .fourcc = V4L2_PIX_FMT_SRGGB8,
234 .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
235 .flags = FMT_FLAG_RAW_FROM_SENSOR,
236 .bpp = 8,
237 },
238 {
239 .fourcc = V4L2_PIX_FMT_SBGGR10,
240 .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
241 .flags = FMT_FLAG_RAW_FROM_SENSOR,
242 .bpp = 16,
243 },
244 {
245 .fourcc = V4L2_PIX_FMT_SGBRG10,
246 .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
247 .flags = FMT_FLAG_RAW_FROM_SENSOR,
248 .bpp = 16,
249 },
250 {
251 .fourcc = V4L2_PIX_FMT_SGRBG10,
252 .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
253 .flags = FMT_FLAG_RAW_FROM_SENSOR,
254 .bpp = 16,
255 },
256 {
257 .fourcc = V4L2_PIX_FMT_SRGGB10,
258 .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
259 .flags = FMT_FLAG_RAW_FROM_SENSOR,
260 .bpp = 16,
261 },
262 {
263 .fourcc = V4L2_PIX_FMT_SBGGR12,
264 .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
265 .flags = FMT_FLAG_RAW_FROM_SENSOR,
266 .bpp = 16,
267 },
268 {
269 .fourcc = V4L2_PIX_FMT_SGBRG12,
270 .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12,
271 .flags = FMT_FLAG_RAW_FROM_SENSOR,
272 .bpp = 16,
273 },
274 {
275 .fourcc = V4L2_PIX_FMT_SGRBG12,
276 .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
277 .flags = FMT_FLAG_RAW_FROM_SENSOR,
278 .bpp = 16,
279 },
280 {
281 .fourcc = V4L2_PIX_FMT_SRGGB12,
282 .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12,
283 .flags = FMT_FLAG_RAW_FROM_SENSOR,
284 .bpp = 16,
285 },
286 {
287 .fourcc = V4L2_PIX_FMT_YUV420,
288 .mbus_code = 0x0,
289 .flags = FMT_FLAG_FROM_CONTROLLER,
290 .bpp = 12,
291 },
292 {
293 .fourcc = V4L2_PIX_FMT_YUV422P,
294 .mbus_code = 0x0,
295 .flags = FMT_FLAG_FROM_CONTROLLER,
296 .bpp = 16,
297 },
298 {
299 .fourcc = V4L2_PIX_FMT_GREY,
300 .mbus_code = MEDIA_BUS_FMT_Y8_1X8,
301 .flags = FMT_FLAG_FROM_CONTROLLER |
302 FMT_FLAG_FROM_SENSOR,
303 .bpp = 8,
304 },
305 {
306 .fourcc = V4L2_PIX_FMT_ARGB444,
307 .mbus_code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE,
308 .flags = FMT_FLAG_FROM_CONTROLLER,
309 .bpp = 16,
310 },
311 {
312 .fourcc = V4L2_PIX_FMT_ARGB555,
313 .mbus_code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
314 .flags = FMT_FLAG_FROM_CONTROLLER,
315 .bpp = 16,
316 },
317 {
318 .fourcc = V4L2_PIX_FMT_RGB565,
319 .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
320 .flags = FMT_FLAG_FROM_CONTROLLER,
321 .bpp = 16,
322 },
323 {
324 .fourcc = V4L2_PIX_FMT_ARGB32,
325 .mbus_code = MEDIA_BUS_FMT_ARGB8888_1X32,
326 .flags = FMT_FLAG_FROM_CONTROLLER,
327 .bpp = 32,
328 },
329 {
330 .fourcc = V4L2_PIX_FMT_YUYV,
331 .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
332 .flags = FMT_FLAG_FROM_CONTROLLER |
333 FMT_FLAG_FROM_SENSOR,
334 .bpp = 16,
335 },
336};
Songjun Wu93d4a262017-01-24 06:05:57 -0200337
Wenyou Yangf103ea12017-10-10 04:46:40 +0200338struct fmt_config fmt_configs_list[] = {
339 {
340 .fourcc = V4L2_PIX_FMT_SBGGR8,
341 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
342 .cfa_baycfg = ISC_BAY_CFG_BGBG,
343 .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8,
344 .dcfg_imode = ISC_DCFG_IMODE_PACKED8,
345 .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
346 .bits_pipeline = 0x0,
347 },
348 {
349 .fourcc = V4L2_PIX_FMT_SGBRG8,
350 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
351 .cfa_baycfg = ISC_BAY_CFG_GBGB,
352 .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8,
353 .dcfg_imode = ISC_DCFG_IMODE_PACKED8,
354 .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
355 .bits_pipeline = 0x0,
356 },
357 {
358 .fourcc = V4L2_PIX_FMT_SGRBG8,
359 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
360 .cfa_baycfg = ISC_BAY_CFG_GRGR,
361 .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8,
362 .dcfg_imode = ISC_DCFG_IMODE_PACKED8,
363 .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
364 .bits_pipeline = 0x0,
365 },
366 {
367 .fourcc = V4L2_PIX_FMT_SRGGB8,
368 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
369 .cfa_baycfg = ISC_BAY_CFG_RGRG,
370 .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8,
371 .dcfg_imode = ISC_DCFG_IMODE_PACKED8,
372 .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
373 .bits_pipeline = 0x0,
374 },
375 {
376 .fourcc = V4L2_PIX_FMT_SBGGR10,
377 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
378 .cfa_baycfg = ISC_BAY_CFG_BGBG,
379 .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10,
380 .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
381 .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
382 .bits_pipeline = 0x0,
383 },
384 {
385 .fourcc = V4L2_PIX_FMT_SGBRG10,
386 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
387 .cfa_baycfg = ISC_BAY_CFG_GBGB,
388 .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10,
389 .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
390 .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
391 .bits_pipeline = 0x0,
392 },
393 {
394 .fourcc = V4L2_PIX_FMT_SGRBG10,
395 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
396 .cfa_baycfg = ISC_BAY_CFG_GRGR,
397 .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10,
398 .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
399 .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
400 .bits_pipeline = 0x0,
401 },
402 {
403 .fourcc = V4L2_PIX_FMT_SRGGB10,
404 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
405 .cfa_baycfg = ISC_BAY_CFG_RGRG,
406 .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10,
407 .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
408 .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
409 .bits_pipeline = 0x0,
410 },
411 {
412 .fourcc = V4L2_PIX_FMT_SBGGR12,
413 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
414 .cfa_baycfg = ISC_BAY_CFG_BGBG,
415 .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12,
416 .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
417 .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
418 .bits_pipeline = 0x0,
419 },
420 {
421 .fourcc = V4L2_PIX_FMT_SGBRG12,
422 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
423 .cfa_baycfg = ISC_BAY_CFG_GBGB,
424 .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12,
425 .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
426 .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
427 .bits_pipeline = 0x0
428 },
429 {
430 .fourcc = V4L2_PIX_FMT_SGRBG12,
431 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
432 .cfa_baycfg = ISC_BAY_CFG_GRGR,
433 .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12,
434 .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
435 .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
436 .bits_pipeline = 0x0,
437 },
438 {
439 .fourcc = V4L2_PIX_FMT_SRGGB12,
440 .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
441 .cfa_baycfg = ISC_BAY_CFG_RGRG,
442 .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12,
443 .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
444 .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
445 .bits_pipeline = 0x0,
446 },
447 {
448 .fourcc = V4L2_PIX_FMT_YUV420,
449 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
450 .cfa_baycfg = ISC_BAY_CFG_BGBG,
451 .rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC,
452 .dcfg_imode = ISC_DCFG_IMODE_YC420P,
453 .dctrl_dview = ISC_DCTRL_DVIEW_PLANAR,
454 .bits_pipeline = SUB420_ENABLE | SUB422_ENABLE |
455 CBC_ENABLE | CSC_ENABLE |
456 GAM_ENABLES |
457 CFA_ENABLE | WB_ENABLE,
458 },
459 {
460 .fourcc = V4L2_PIX_FMT_YUV422P,
461 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
462 .cfa_baycfg = ISC_BAY_CFG_BGBG,
463 .rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC,
464 .dcfg_imode = ISC_DCFG_IMODE_YC422P,
465 .dctrl_dview = ISC_DCTRL_DVIEW_PLANAR,
466 .bits_pipeline = SUB422_ENABLE |
467 CBC_ENABLE | CSC_ENABLE |
468 GAM_ENABLES |
469 CFA_ENABLE | WB_ENABLE,
470 },
471 {
472 .fourcc = V4L2_PIX_FMT_GREY,
473 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
474 .cfa_baycfg = ISC_BAY_CFG_BGBG,
475 .rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY8,
476 .dcfg_imode = ISC_DCFG_IMODE_PACKED8,
477 .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
478 .bits_pipeline = CBC_ENABLE | CSC_ENABLE |
479 GAM_ENABLES |
480 CFA_ENABLE | WB_ENABLE,
481 },
482 {
483 .fourcc = V4L2_PIX_FMT_ARGB444,
484 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
485 .cfa_baycfg = ISC_BAY_CFG_BGBG,
486 .rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB444,
487 .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
488 .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
489 .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE,
490 },
491 {
492 .fourcc = V4L2_PIX_FMT_ARGB555,
493 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
494 .cfa_baycfg = ISC_BAY_CFG_BGBG,
495 .rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB555,
496 .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
497 .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
498 .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE,
499 },
500 {
501 .fourcc = V4L2_PIX_FMT_RGB565,
502 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
503 .cfa_baycfg = ISC_BAY_CFG_BGBG,
504 .rlp_cfg_mode = ISC_RLP_CFG_MODE_RGB565,
505 .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
506 .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
507 .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE,
508 },
509 {
510 .fourcc = V4L2_PIX_FMT_ARGB32,
511 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
512 .cfa_baycfg = ISC_BAY_CFG_BGBG,
513 .rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB32,
514 .dcfg_imode = ISC_DCFG_IMODE_PACKED32,
515 .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
516 .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE,
517 },
518 {
519 .fourcc = V4L2_PIX_FMT_YUYV,
520 .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
521 .cfa_baycfg = ISC_BAY_CFG_BGBG,
522 .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8,
523 .dcfg_imode = ISC_DCFG_IMODE_PACKED8,
524 .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
525 .bits_pipeline = 0x0
526 },
Songjun Wu106267442016-08-17 03:05:27 -0300527};
528
Songjun Wu93d4a262017-01-24 06:05:57 -0200529#define GAMMA_MAX 2
530#define GAMMA_ENTRIES 64
531
532/* Gamma table with gamma 1/2.2 */
533static const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = {
534 /* 0 --> gamma 1/1.8 */
535 { 0x65, 0x66002F, 0x950025, 0xBB0020, 0xDB001D, 0xF8001A,
536 0x1130018, 0x12B0017, 0x1420016, 0x1580014, 0x16D0013, 0x1810012,
537 0x1940012, 0x1A60012, 0x1B80011, 0x1C90010, 0x1DA0010, 0x1EA000F,
538 0x1FA000F, 0x209000F, 0x218000F, 0x227000E, 0x235000E, 0x243000E,
539 0x251000E, 0x25F000D, 0x26C000D, 0x279000D, 0x286000D, 0x293000C,
540 0x2A0000C, 0x2AC000C, 0x2B8000C, 0x2C4000C, 0x2D0000B, 0x2DC000B,
541 0x2E7000B, 0x2F3000B, 0x2FE000B, 0x309000B, 0x314000B, 0x31F000A,
542 0x32A000A, 0x334000B, 0x33F000A, 0x349000A, 0x354000A, 0x35E000A,
543 0x368000A, 0x372000A, 0x37C000A, 0x386000A, 0x3900009, 0x399000A,
544 0x3A30009, 0x3AD0009, 0x3B60009, 0x3BF000A, 0x3C90009, 0x3D20009,
545 0x3DB0009, 0x3E40009, 0x3ED0009, 0x3F60009 },
546
547 /* 1 --> gamma 1/2 */
548 { 0x7F, 0x800034, 0xB50028, 0xDE0021, 0x100001E, 0x11E001B,
549 0x1390019, 0x1520017, 0x16A0015, 0x1800014, 0x1940014, 0x1A80013,
550 0x1BB0012, 0x1CD0011, 0x1DF0010, 0x1EF0010, 0x200000F, 0x20F000F,
551 0x21F000E, 0x22D000F, 0x23C000E, 0x24A000E, 0x258000D, 0x265000D,
552 0x273000C, 0x27F000D, 0x28C000C, 0x299000C, 0x2A5000C, 0x2B1000B,
553 0x2BC000C, 0x2C8000B, 0x2D3000C, 0x2DF000B, 0x2EA000A, 0x2F5000A,
554 0x2FF000B, 0x30A000A, 0x314000B, 0x31F000A, 0x329000A, 0x333000A,
555 0x33D0009, 0x3470009, 0x350000A, 0x35A0009, 0x363000A, 0x36D0009,
556 0x3760009, 0x37F0009, 0x3880009, 0x3910009, 0x39A0009, 0x3A30009,
557 0x3AC0008, 0x3B40009, 0x3BD0008, 0x3C60008, 0x3CE0008, 0x3D60009,
558 0x3DF0008, 0x3E70008, 0x3EF0008, 0x3F70008 },
559
560 /* 2 --> gamma 1/2.2 */
561 { 0x99, 0x9B0038, 0xD4002A, 0xFF0023, 0x122001F, 0x141001B,
562 0x15D0019, 0x1760017, 0x18E0015, 0x1A30015, 0x1B80013, 0x1CC0012,
563 0x1DE0011, 0x1F00010, 0x2010010, 0x2110010, 0x221000F, 0x230000F,
564 0x23F000E, 0x24D000E, 0x25B000D, 0x269000C, 0x276000C, 0x283000C,
565 0x28F000C, 0x29B000C, 0x2A7000C, 0x2B3000B, 0x2BF000B, 0x2CA000B,
566 0x2D5000B, 0x2E0000A, 0x2EB000A, 0x2F5000A, 0x2FF000A, 0x30A000A,
567 0x3140009, 0x31E0009, 0x327000A, 0x3310009, 0x33A0009, 0x3440009,
568 0x34D0009, 0x3560009, 0x35F0009, 0x3680008, 0x3710008, 0x3790009,
569 0x3820008, 0x38A0008, 0x3930008, 0x39B0008, 0x3A30008, 0x3AB0008,
570 0x3B30008, 0x3BB0008, 0x3C30008, 0x3CB0007, 0x3D20008, 0x3DA0007,
571 0x3E20007, 0x3E90007, 0x3F00008, 0x3F80007 },
572};
573
574static unsigned int sensor_preferred = 1;
575module_param(sensor_preferred, uint, 0644);
576MODULE_PARM_DESC(sensor_preferred,
577 "Sensor is preferred to output the specified format (1-on 0-off), default 1");
578
Wenyou Yang64f63062017-10-10 04:46:37 +0200579static int isc_wait_clk_stable(struct clk_hw *hw)
580{
581 struct isc_clk *isc_clk = to_isc_clk(hw);
582 struct regmap *regmap = isc_clk->regmap;
583 unsigned long timeout = jiffies + usecs_to_jiffies(1000);
584 unsigned int status;
585
586 while (time_before(jiffies, timeout)) {
587 regmap_read(regmap, ISC_CLKSR, &status);
588 if (!(status & ISC_CLKSR_SIP))
589 return 0;
590
591 usleep_range(10, 250);
592 }
593
594 return -ETIMEDOUT;
595}
596
597static int isc_clk_prepare(struct clk_hw *hw)
598{
599 struct isc_clk *isc_clk = to_isc_clk(hw);
600
Wenyou Yangd7ca1c92017-10-29 20:46:50 -0400601 if (isc_clk->id == ISC_ISPCK)
Wenyou Yang64f63062017-10-10 04:46:37 +0200602 pm_runtime_get_sync(isc_clk->dev);
603
604 return isc_wait_clk_stable(hw);
605}
606
607static void isc_clk_unprepare(struct clk_hw *hw)
608{
609 struct isc_clk *isc_clk = to_isc_clk(hw);
610
611 isc_wait_clk_stable(hw);
612
Wenyou Yangd7ca1c92017-10-29 20:46:50 -0400613 if (isc_clk->id == ISC_ISPCK)
Wenyou Yang64f63062017-10-10 04:46:37 +0200614 pm_runtime_put_sync(isc_clk->dev);
615}
616
Songjun Wu106267442016-08-17 03:05:27 -0300617static int isc_clk_enable(struct clk_hw *hw)
618{
619 struct isc_clk *isc_clk = to_isc_clk(hw);
620 u32 id = isc_clk->id;
621 struct regmap *regmap = isc_clk->regmap;
Wenyou Yangcab1dea2017-10-10 04:46:36 +0200622 unsigned long flags;
623 unsigned int status;
Songjun Wu106267442016-08-17 03:05:27 -0300624
625 dev_dbg(isc_clk->dev, "ISC CLK: %s, div = %d, parent id = %d\n",
626 __func__, isc_clk->div, isc_clk->parent_id);
627
Wenyou Yangcab1dea2017-10-10 04:46:36 +0200628 spin_lock_irqsave(&isc_clk->lock, flags);
Songjun Wu106267442016-08-17 03:05:27 -0300629 regmap_update_bits(regmap, ISC_CLKCFG,
630 ISC_CLKCFG_DIV_MASK(id) | ISC_CLKCFG_SEL_MASK(id),
631 (isc_clk->div << ISC_CLKCFG_DIV_SHIFT(id)) |
632 (isc_clk->parent_id << ISC_CLKCFG_SEL_SHIFT(id)));
633
634 regmap_write(regmap, ISC_CLKEN, ISC_CLK(id));
Wenyou Yangcab1dea2017-10-10 04:46:36 +0200635 spin_unlock_irqrestore(&isc_clk->lock, flags);
Songjun Wu106267442016-08-17 03:05:27 -0300636
Wenyou Yangcab1dea2017-10-10 04:46:36 +0200637 regmap_read(regmap, ISC_CLKSR, &status);
638 if (status & ISC_CLK(id))
639 return 0;
640 else
641 return -EINVAL;
Songjun Wu106267442016-08-17 03:05:27 -0300642}
643
644static void isc_clk_disable(struct clk_hw *hw)
645{
646 struct isc_clk *isc_clk = to_isc_clk(hw);
647 u32 id = isc_clk->id;
Wenyou Yangcab1dea2017-10-10 04:46:36 +0200648 unsigned long flags;
Songjun Wu106267442016-08-17 03:05:27 -0300649
Wenyou Yangcab1dea2017-10-10 04:46:36 +0200650 spin_lock_irqsave(&isc_clk->lock, flags);
Songjun Wu106267442016-08-17 03:05:27 -0300651 regmap_write(isc_clk->regmap, ISC_CLKDIS, ISC_CLK(id));
Wenyou Yangcab1dea2017-10-10 04:46:36 +0200652 spin_unlock_irqrestore(&isc_clk->lock, flags);
Songjun Wu106267442016-08-17 03:05:27 -0300653}
654
655static int isc_clk_is_enabled(struct clk_hw *hw)
656{
657 struct isc_clk *isc_clk = to_isc_clk(hw);
658 u32 status;
659
Wenyou Yangd7ca1c92017-10-29 20:46:50 -0400660 if (isc_clk->id == ISC_ISPCK)
Wenyou Yang01192aa2017-10-10 04:46:38 +0200661 pm_runtime_get_sync(isc_clk->dev);
662
Songjun Wu106267442016-08-17 03:05:27 -0300663 regmap_read(isc_clk->regmap, ISC_CLKSR, &status);
664
Wenyou Yangd7ca1c92017-10-29 20:46:50 -0400665 if (isc_clk->id == ISC_ISPCK)
Wenyou Yang01192aa2017-10-10 04:46:38 +0200666 pm_runtime_put_sync(isc_clk->dev);
667
Songjun Wu106267442016-08-17 03:05:27 -0300668 return status & ISC_CLK(isc_clk->id) ? 1 : 0;
669}
670
671static unsigned long
672isc_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
673{
674 struct isc_clk *isc_clk = to_isc_clk(hw);
675
676 return DIV_ROUND_CLOSEST(parent_rate, isc_clk->div + 1);
677}
678
679static int isc_clk_determine_rate(struct clk_hw *hw,
680 struct clk_rate_request *req)
681{
682 struct isc_clk *isc_clk = to_isc_clk(hw);
683 long best_rate = -EINVAL;
684 int best_diff = -1;
685 unsigned int i, div;
686
687 for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
688 struct clk_hw *parent;
689 unsigned long parent_rate;
690
691 parent = clk_hw_get_parent_by_index(hw, i);
692 if (!parent)
693 continue;
694
695 parent_rate = clk_hw_get_rate(parent);
696 if (!parent_rate)
697 continue;
698
699 for (div = 1; div < ISC_CLK_MAX_DIV + 2; div++) {
700 unsigned long rate;
701 int diff;
702
703 rate = DIV_ROUND_CLOSEST(parent_rate, div);
704 diff = abs(req->rate - rate);
705
706 if (best_diff < 0 || best_diff > diff) {
707 best_rate = rate;
708 best_diff = diff;
709 req->best_parent_rate = parent_rate;
710 req->best_parent_hw = parent;
711 }
712
713 if (!best_diff || rate < req->rate)
714 break;
715 }
716
717 if (!best_diff)
718 break;
719 }
720
721 dev_dbg(isc_clk->dev,
722 "ISC CLK: %s, best_rate = %ld, parent clk: %s @ %ld\n",
723 __func__, best_rate,
724 __clk_get_name((req->best_parent_hw)->clk),
725 req->best_parent_rate);
726
727 if (best_rate < 0)
728 return best_rate;
729
730 req->rate = best_rate;
731
732 return 0;
733}
734
735static int isc_clk_set_parent(struct clk_hw *hw, u8 index)
736{
737 struct isc_clk *isc_clk = to_isc_clk(hw);
738
739 if (index >= clk_hw_get_num_parents(hw))
740 return -EINVAL;
741
742 isc_clk->parent_id = index;
743
744 return 0;
745}
746
747static u8 isc_clk_get_parent(struct clk_hw *hw)
748{
749 struct isc_clk *isc_clk = to_isc_clk(hw);
750
751 return isc_clk->parent_id;
752}
753
754static int isc_clk_set_rate(struct clk_hw *hw,
755 unsigned long rate,
756 unsigned long parent_rate)
757{
758 struct isc_clk *isc_clk = to_isc_clk(hw);
759 u32 div;
760
761 if (!rate)
762 return -EINVAL;
763
764 div = DIV_ROUND_CLOSEST(parent_rate, rate);
765 if (div > (ISC_CLK_MAX_DIV + 1) || !div)
766 return -EINVAL;
767
768 isc_clk->div = div - 1;
769
770 return 0;
771}
772
773static const struct clk_ops isc_clk_ops = {
Wenyou Yang64f63062017-10-10 04:46:37 +0200774 .prepare = isc_clk_prepare,
775 .unprepare = isc_clk_unprepare,
Songjun Wu106267442016-08-17 03:05:27 -0300776 .enable = isc_clk_enable,
777 .disable = isc_clk_disable,
778 .is_enabled = isc_clk_is_enabled,
779 .recalc_rate = isc_clk_recalc_rate,
780 .determine_rate = isc_clk_determine_rate,
781 .set_parent = isc_clk_set_parent,
782 .get_parent = isc_clk_get_parent,
783 .set_rate = isc_clk_set_rate,
784};
785
786static int isc_clk_register(struct isc_device *isc, unsigned int id)
787{
788 struct regmap *regmap = isc->regmap;
789 struct device_node *np = isc->dev->of_node;
790 struct isc_clk *isc_clk;
791 struct clk_init_data init;
792 const char *clk_name = np->name;
793 const char *parent_names[3];
794 int num_parents;
795
796 num_parents = of_clk_get_parent_count(np);
797 if (num_parents < 1 || num_parents > 3)
798 return -EINVAL;
799
800 if (num_parents > 2 && id == ISC_ISPCK)
801 num_parents = 2;
802
803 of_clk_parent_fill(np, parent_names, num_parents);
804
805 if (id == ISC_MCK)
806 of_property_read_string(np, "clock-output-names", &clk_name);
807 else
808 clk_name = "isc-ispck";
809
810 init.parent_names = parent_names;
811 init.num_parents = num_parents;
812 init.name = clk_name;
813 init.ops = &isc_clk_ops;
814 init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
815
816 isc_clk = &isc->isc_clks[id];
817 isc_clk->hw.init = &init;
818 isc_clk->regmap = regmap;
819 isc_clk->id = id;
820 isc_clk->dev = isc->dev;
Wenyou Yangcab1dea2017-10-10 04:46:36 +0200821 spin_lock_init(&isc_clk->lock);
Songjun Wu106267442016-08-17 03:05:27 -0300822
823 isc_clk->clk = clk_register(isc->dev, &isc_clk->hw);
824 if (IS_ERR(isc_clk->clk)) {
825 dev_err(isc->dev, "%s: clock register fail\n", clk_name);
826 return PTR_ERR(isc_clk->clk);
827 } else if (id == ISC_MCK)
828 of_clk_add_provider(np, of_clk_src_simple_get, isc_clk->clk);
829
830 return 0;
831}
832
833static int isc_clk_init(struct isc_device *isc)
834{
835 unsigned int i;
836 int ret;
837
838 for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++)
839 isc->isc_clks[i].clk = ERR_PTR(-EINVAL);
840
841 for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) {
842 ret = isc_clk_register(isc, i);
843 if (ret)
844 return ret;
845 }
846
847 return 0;
848}
849
850static void isc_clk_cleanup(struct isc_device *isc)
851{
852 unsigned int i;
853
854 of_clk_del_provider(isc->dev->of_node);
855
856 for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) {
857 struct isc_clk *isc_clk = &isc->isc_clks[i];
858
859 if (!IS_ERR(isc_clk->clk))
860 clk_unregister(isc_clk->clk);
861 }
862}
863
864static int isc_queue_setup(struct vb2_queue *vq,
865 unsigned int *nbuffers, unsigned int *nplanes,
866 unsigned int sizes[], struct device *alloc_devs[])
867{
868 struct isc_device *isc = vb2_get_drv_priv(vq);
869 unsigned int size = isc->fmt.fmt.pix.sizeimage;
870
871 if (*nplanes)
872 return sizes[0] < size ? -EINVAL : 0;
873
874 *nplanes = 1;
875 sizes[0] = size;
876
877 return 0;
878}
879
880static int isc_buffer_prepare(struct vb2_buffer *vb)
881{
882 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
883 struct isc_device *isc = vb2_get_drv_priv(vb->vb2_queue);
884 unsigned long size = isc->fmt.fmt.pix.sizeimage;
885
886 if (vb2_plane_size(vb, 0) < size) {
887 v4l2_err(&isc->v4l2_dev, "buffer too small (%lu < %lu)\n",
888 vb2_plane_size(vb, 0), size);
889 return -EINVAL;
890 }
891
892 vb2_set_plane_payload(vb, 0, size);
893
894 vbuf->field = isc->fmt.fmt.pix.field;
895
896 return 0;
897}
898
Songjun Wu93d4a262017-01-24 06:05:57 -0200899static inline bool sensor_is_preferred(const struct isc_format *isc_fmt)
Songjun Wu106267442016-08-17 03:05:27 -0300900{
Songjun Wu93d4a262017-01-24 06:05:57 -0200901 return (sensor_preferred && isc_fmt->sd_support) ||
902 !isc_fmt->isc_support;
903}
Songjun Wu106267442016-08-17 03:05:27 -0300904
Wenyou Yangf103ea12017-10-10 04:46:40 +0200905static struct fmt_config *get_fmt_config(u32 fourcc)
906{
907 struct fmt_config *config;
908 int i;
909
910 config = &fmt_configs_list[0];
911 for (i = 0; i < ARRAY_SIZE(fmt_configs_list); i++) {
912 if (config->fourcc == fourcc)
913 return config;
914
915 config++;
916 }
917 return NULL;
918}
919
Songjun Wu93d4a262017-01-24 06:05:57 -0200920static void isc_start_dma(struct isc_device *isc)
921{
922 struct regmap *regmap = isc->regmap;
923 struct v4l2_pix_format *pixfmt = &isc->fmt.fmt.pix;
924 u32 sizeimage = pixfmt->sizeimage;
Wenyou Yangf103ea12017-10-10 04:46:40 +0200925 struct fmt_config *config = get_fmt_config(isc->current_fmt->fourcc);
Songjun Wu93d4a262017-01-24 06:05:57 -0200926 u32 dctrl_dview;
927 dma_addr_t addr0;
Songjun Wu106267442016-08-17 03:05:27 -0300928
Songjun Wu93d4a262017-01-24 06:05:57 -0200929 addr0 = vb2_dma_contig_plane_dma_addr(&isc->cur_frm->vb.vb2_buf, 0);
930 regmap_write(regmap, ISC_DAD0, addr0);
931
932 switch (pixfmt->pixelformat) {
933 case V4L2_PIX_FMT_YUV420:
934 regmap_write(regmap, ISC_DAD1, addr0 + (sizeimage * 2) / 3);
935 regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 5) / 6);
936 break;
937 case V4L2_PIX_FMT_YUV422P:
938 regmap_write(regmap, ISC_DAD1, addr0 + sizeimage / 2);
939 regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 3) / 4);
940 break;
941 default:
942 break;
943 }
944
945 if (sensor_is_preferred(isc->current_fmt))
946 dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
947 else
Wenyou Yangf103ea12017-10-10 04:46:40 +0200948 dctrl_dview = config->dctrl_dview;
Songjun Wu93d4a262017-01-24 06:05:57 -0200949
950 regmap_write(regmap, ISC_DCTRL, dctrl_dview | ISC_DCTRL_IE_IS);
Songjun Wu106267442016-08-17 03:05:27 -0300951 regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE);
952}
953
954static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
955{
Songjun Wu93d4a262017-01-24 06:05:57 -0200956 struct regmap *regmap = isc->regmap;
957 struct isc_ctrls *ctrls = &isc->ctrls;
Wenyou Yangf103ea12017-10-10 04:46:40 +0200958 struct fmt_config *config = get_fmt_config(isc->raw_fmt->fourcc);
Songjun Wu93d4a262017-01-24 06:05:57 -0200959 u32 val, bay_cfg;
960 const u32 *gamma;
Songjun Wu106267442016-08-17 03:05:27 -0300961 unsigned int i;
962
Songjun Wu93d4a262017-01-24 06:05:57 -0200963 /* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */
Songjun Wu106267442016-08-17 03:05:27 -0300964 for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) {
965 val = pipeline & BIT(i) ? 1 : 0;
966 regmap_field_write(isc->pipeline[i], val);
967 }
Songjun Wu93d4a262017-01-24 06:05:57 -0200968
969 if (!pipeline)
970 return;
971
Wenyou Yangf103ea12017-10-10 04:46:40 +0200972 bay_cfg = config->cfa_baycfg;
Songjun Wu93d4a262017-01-24 06:05:57 -0200973
974 regmap_write(regmap, ISC_WB_CFG, bay_cfg);
975 regmap_write(regmap, ISC_WB_O_RGR, 0x0);
976 regmap_write(regmap, ISC_WB_O_BGR, 0x0);
977 regmap_write(regmap, ISC_WB_G_RGR, ctrls->r_gain | (0x1 << 25));
978 regmap_write(regmap, ISC_WB_G_BGR, ctrls->b_gain | (0x1 << 25));
979
980 regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL);
981
982 gamma = &isc_gamma_table[ctrls->gamma_index][0];
983 regmap_bulk_write(regmap, ISC_GAM_BENTRY, gamma, GAMMA_ENTRIES);
984 regmap_bulk_write(regmap, ISC_GAM_GENTRY, gamma, GAMMA_ENTRIES);
985 regmap_bulk_write(regmap, ISC_GAM_RENTRY, gamma, GAMMA_ENTRIES);
986
987 /* Convert RGB to YUV */
988 regmap_write(regmap, ISC_CSC_YR_YG, 0x42 | (0x81 << 16));
989 regmap_write(regmap, ISC_CSC_YB_OY, 0x19 | (0x10 << 16));
990 regmap_write(regmap, ISC_CSC_CBR_CBG, 0xFDA | (0xFB6 << 16));
991 regmap_write(regmap, ISC_CSC_CBB_OCB, 0x70 | (0x80 << 16));
992 regmap_write(regmap, ISC_CSC_CRR_CRG, 0x70 | (0xFA2 << 16));
993 regmap_write(regmap, ISC_CSC_CRB_OCR, 0xFEE | (0x80 << 16));
994
995 regmap_write(regmap, ISC_CBC_BRIGHT, ctrls->brightness);
996 regmap_write(regmap, ISC_CBC_CONTRAST, ctrls->contrast);
997}
998
999static int isc_update_profile(struct isc_device *isc)
1000{
1001 struct regmap *regmap = isc->regmap;
1002 u32 sr;
1003 int counter = 100;
1004
1005 regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_UPPRO);
1006
1007 regmap_read(regmap, ISC_CTRLSR, &sr);
1008 while ((sr & ISC_CTRL_UPPRO) && counter--) {
1009 usleep_range(1000, 2000);
1010 regmap_read(regmap, ISC_CTRLSR, &sr);
1011 }
1012
1013 if (counter < 0) {
1014 v4l2_warn(&isc->v4l2_dev, "Time out to update profie\n");
1015 return -ETIMEDOUT;
1016 }
1017
1018 return 0;
1019}
1020
1021static void isc_set_histogram(struct isc_device *isc)
1022{
1023 struct regmap *regmap = isc->regmap;
1024 struct isc_ctrls *ctrls = &isc->ctrls;
Wenyou Yangf103ea12017-10-10 04:46:40 +02001025 struct fmt_config *config = get_fmt_config(isc->raw_fmt->fourcc);
Songjun Wu93d4a262017-01-24 06:05:57 -02001026
1027 if (ctrls->awb && (ctrls->hist_stat != HIST_ENABLED)) {
Wenyou Yangf103ea12017-10-10 04:46:40 +02001028 regmap_write(regmap, ISC_HIS_CFG,
1029 ISC_HIS_CFG_MODE_R |
1030 (config->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT) |
1031 ISC_HIS_CFG_RAR);
Songjun Wu93d4a262017-01-24 06:05:57 -02001032 regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_EN);
1033 regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE);
1034 ctrls->hist_id = ISC_HIS_CFG_MODE_R;
1035 isc_update_profile(isc);
1036 regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
1037
1038 ctrls->hist_stat = HIST_ENABLED;
1039 } else if (!ctrls->awb && (ctrls->hist_stat != HIST_DISABLED)) {
1040 regmap_write(regmap, ISC_INTDIS, ISC_INT_HISDONE);
1041 regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_DIS);
1042
1043 ctrls->hist_stat = HIST_DISABLED;
1044 }
1045}
1046
1047static inline void isc_get_param(const struct isc_format *fmt,
Wenyou Yangf103ea12017-10-10 04:46:40 +02001048 u32 *rlp_mode, u32 *dcfg)
Songjun Wu93d4a262017-01-24 06:05:57 -02001049{
Wenyou Yangf103ea12017-10-10 04:46:40 +02001050 struct fmt_config *config = get_fmt_config(fmt->fourcc);
1051
Songjun Wu682559d2017-04-20 05:51:30 -03001052 *dcfg = ISC_DCFG_YMBSIZE_BEATS8;
1053
Songjun Wu93d4a262017-01-24 06:05:57 -02001054 switch (fmt->fourcc) {
1055 case V4L2_PIX_FMT_SBGGR10:
1056 case V4L2_PIX_FMT_SGBRG10:
1057 case V4L2_PIX_FMT_SGRBG10:
1058 case V4L2_PIX_FMT_SRGGB10:
1059 case V4L2_PIX_FMT_SBGGR12:
1060 case V4L2_PIX_FMT_SGBRG12:
1061 case V4L2_PIX_FMT_SGRBG12:
1062 case V4L2_PIX_FMT_SRGGB12:
Wenyou Yangf103ea12017-10-10 04:46:40 +02001063 *rlp_mode = config->rlp_cfg_mode;
1064 *dcfg |= config->dcfg_imode;
Songjun Wu93d4a262017-01-24 06:05:57 -02001065 break;
1066 default:
1067 *rlp_mode = ISC_RLP_CFG_MODE_DAT8;
Songjun Wu682559d2017-04-20 05:51:30 -03001068 *dcfg |= ISC_DCFG_IMODE_PACKED8;
Songjun Wu93d4a262017-01-24 06:05:57 -02001069 break;
1070 }
Songjun Wu106267442016-08-17 03:05:27 -03001071}
1072
1073static int isc_configure(struct isc_device *isc)
1074{
1075 struct regmap *regmap = isc->regmap;
1076 const struct isc_format *current_fmt = isc->current_fmt;
Wenyou Yangf103ea12017-10-10 04:46:40 +02001077 struct fmt_config *curfmt_config = get_fmt_config(current_fmt->fourcc);
1078 struct fmt_config *rawfmt_config = get_fmt_config(isc->raw_fmt->fourcc);
Songjun Wu106267442016-08-17 03:05:27 -03001079 struct isc_subdev_entity *subdev = isc->current_subdev;
Songjun Wu682559d2017-04-20 05:51:30 -03001080 u32 pfe_cfg0, rlp_mode, dcfg, mask, pipeline;
Songjun Wu106267442016-08-17 03:05:27 -03001081
Songjun Wu93d4a262017-01-24 06:05:57 -02001082 if (sensor_is_preferred(current_fmt)) {
Wenyou Yangf103ea12017-10-10 04:46:40 +02001083 pfe_cfg0 = curfmt_config->pfe_cfg0_bps;
Songjun Wu93d4a262017-01-24 06:05:57 -02001084 pipeline = 0x0;
Songjun Wu682559d2017-04-20 05:51:30 -03001085 isc_get_param(current_fmt, &rlp_mode, &dcfg);
Songjun Wu93d4a262017-01-24 06:05:57 -02001086 isc->ctrls.hist_stat = HIST_INIT;
1087 } else {
Wenyou Yangf103ea12017-10-10 04:46:40 +02001088 pfe_cfg0 = rawfmt_config->pfe_cfg0_bps;
1089 pipeline = curfmt_config->bits_pipeline;
1090 rlp_mode = curfmt_config->rlp_cfg_mode;
1091 dcfg = curfmt_config->dcfg_imode |
1092 ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8;
Songjun Wu93d4a262017-01-24 06:05:57 -02001093 }
1094
1095 pfe_cfg0 |= subdev->pfe_cfg0 | ISC_PFE_CFG0_MODE_PROGRESSIVE;
Songjun Wu106267442016-08-17 03:05:27 -03001096 mask = ISC_PFE_CFG0_BPS_MASK | ISC_PFE_CFG0_HPOL_LOW |
1097 ISC_PFE_CFG0_VPOL_LOW | ISC_PFE_CFG0_PPOL_LOW |
1098 ISC_PFE_CFG0_MODE_MASK;
1099
Songjun Wu93d4a262017-01-24 06:05:57 -02001100 regmap_update_bits(regmap, ISC_PFE_CFG0, mask, pfe_cfg0);
Songjun Wu106267442016-08-17 03:05:27 -03001101
1102 regmap_update_bits(regmap, ISC_RLP_CFG, ISC_RLP_CFG_MODE_MASK,
Songjun Wu93d4a262017-01-24 06:05:57 -02001103 rlp_mode);
Songjun Wu106267442016-08-17 03:05:27 -03001104
Songjun Wu682559d2017-04-20 05:51:30 -03001105 regmap_write(regmap, ISC_DCFG, dcfg);
Songjun Wu106267442016-08-17 03:05:27 -03001106
Songjun Wu93d4a262017-01-24 06:05:57 -02001107 /* Set the pipeline */
1108 isc_set_pipeline(isc, pipeline);
1109
1110 if (pipeline)
1111 isc_set_histogram(isc);
Songjun Wu106267442016-08-17 03:05:27 -03001112
1113 /* Update profile */
Songjun Wu93d4a262017-01-24 06:05:57 -02001114 return isc_update_profile(isc);
Songjun Wu106267442016-08-17 03:05:27 -03001115}
1116
1117static int isc_start_streaming(struct vb2_queue *vq, unsigned int count)
1118{
1119 struct isc_device *isc = vb2_get_drv_priv(vq);
1120 struct regmap *regmap = isc->regmap;
1121 struct isc_buffer *buf;
1122 unsigned long flags;
1123 int ret;
Songjun Wu106267442016-08-17 03:05:27 -03001124
1125 /* Enable stream on the sub device */
1126 ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1);
1127 if (ret && ret != -ENOIOCTLCMD) {
1128 v4l2_err(&isc->v4l2_dev, "stream on failed in subdev\n");
1129 goto err_start_stream;
1130 }
1131
1132 pm_runtime_get_sync(isc->dev);
1133
Songjun Wu106267442016-08-17 03:05:27 -03001134 ret = isc_configure(isc);
1135 if (unlikely(ret))
1136 goto err_configure;
1137
1138 /* Enable DMA interrupt */
1139 regmap_write(regmap, ISC_INTEN, ISC_INT_DDONE);
1140
1141 spin_lock_irqsave(&isc->dma_queue_lock, flags);
1142
1143 isc->sequence = 0;
1144 isc->stop = false;
1145 reinit_completion(&isc->comp);
1146
1147 isc->cur_frm = list_first_entry(&isc->dma_queue,
1148 struct isc_buffer, list);
1149 list_del(&isc->cur_frm->list);
1150
Songjun Wu93d4a262017-01-24 06:05:57 -02001151 isc_start_dma(isc);
Songjun Wu106267442016-08-17 03:05:27 -03001152
1153 spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
1154
1155 return 0;
1156
1157err_configure:
1158 pm_runtime_put_sync(isc->dev);
1159
1160 v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0);
1161
1162err_start_stream:
1163 spin_lock_irqsave(&isc->dma_queue_lock, flags);
1164 list_for_each_entry(buf, &isc->dma_queue, list)
1165 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
1166 INIT_LIST_HEAD(&isc->dma_queue);
1167 spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
1168
1169 return ret;
1170}
1171
1172static void isc_stop_streaming(struct vb2_queue *vq)
1173{
1174 struct isc_device *isc = vb2_get_drv_priv(vq);
1175 unsigned long flags;
1176 struct isc_buffer *buf;
1177 int ret;
1178
1179 isc->stop = true;
1180
1181 /* Wait until the end of the current frame */
1182 if (isc->cur_frm && !wait_for_completion_timeout(&isc->comp, 5 * HZ))
1183 v4l2_err(&isc->v4l2_dev,
1184 "Timeout waiting for end of the capture\n");
1185
1186 /* Disable DMA interrupt */
1187 regmap_write(isc->regmap, ISC_INTDIS, ISC_INT_DDONE);
1188
1189 pm_runtime_put_sync(isc->dev);
1190
1191 /* Disable stream on the sub device */
1192 ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0);
1193 if (ret && ret != -ENOIOCTLCMD)
1194 v4l2_err(&isc->v4l2_dev, "stream off failed in subdev\n");
1195
1196 /* Release all active buffers */
1197 spin_lock_irqsave(&isc->dma_queue_lock, flags);
1198 if (unlikely(isc->cur_frm)) {
1199 vb2_buffer_done(&isc->cur_frm->vb.vb2_buf,
1200 VB2_BUF_STATE_ERROR);
1201 isc->cur_frm = NULL;
1202 }
1203 list_for_each_entry(buf, &isc->dma_queue, list)
1204 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
1205 INIT_LIST_HEAD(&isc->dma_queue);
1206 spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
1207}
1208
1209static void isc_buffer_queue(struct vb2_buffer *vb)
1210{
1211 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1212 struct isc_buffer *buf = container_of(vbuf, struct isc_buffer, vb);
1213 struct isc_device *isc = vb2_get_drv_priv(vb->vb2_queue);
1214 unsigned long flags;
1215
1216 spin_lock_irqsave(&isc->dma_queue_lock, flags);
Songjun Wufa8bbe02016-09-28 02:28:57 -03001217 if (!isc->cur_frm && list_empty(&isc->dma_queue) &&
1218 vb2_is_streaming(vb->vb2_queue)) {
1219 isc->cur_frm = buf;
Songjun Wu93d4a262017-01-24 06:05:57 -02001220 isc_start_dma(isc);
Songjun Wufa8bbe02016-09-28 02:28:57 -03001221 } else
1222 list_add_tail(&buf->list, &isc->dma_queue);
Songjun Wu106267442016-08-17 03:05:27 -03001223 spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
1224}
1225
Gustavo A. R. Silva62c11a52017-07-06 16:30:16 -04001226static const struct vb2_ops isc_vb2_ops = {
Songjun Wu106267442016-08-17 03:05:27 -03001227 .queue_setup = isc_queue_setup,
1228 .wait_prepare = vb2_ops_wait_prepare,
1229 .wait_finish = vb2_ops_wait_finish,
1230 .buf_prepare = isc_buffer_prepare,
1231 .start_streaming = isc_start_streaming,
1232 .stop_streaming = isc_stop_streaming,
1233 .buf_queue = isc_buffer_queue,
1234};
1235
1236static int isc_querycap(struct file *file, void *priv,
1237 struct v4l2_capability *cap)
1238{
1239 struct isc_device *isc = video_drvdata(file);
1240
1241 strcpy(cap->driver, ATMEL_ISC_NAME);
1242 strcpy(cap->card, "Atmel Image Sensor Controller");
1243 snprintf(cap->bus_info, sizeof(cap->bus_info),
1244 "platform:%s", isc->v4l2_dev.name);
1245
1246 return 0;
1247}
1248
1249static int isc_enum_fmt_vid_cap(struct file *file, void *priv,
1250 struct v4l2_fmtdesc *f)
1251{
1252 struct isc_device *isc = video_drvdata(file);
1253 u32 index = f->index;
1254
1255 if (index >= isc->num_user_formats)
1256 return -EINVAL;
1257
1258 f->pixelformat = isc->user_formats[index]->fourcc;
1259
1260 return 0;
1261}
1262
1263static int isc_g_fmt_vid_cap(struct file *file, void *priv,
1264 struct v4l2_format *fmt)
1265{
1266 struct isc_device *isc = video_drvdata(file);
1267
1268 *fmt = isc->fmt;
1269
1270 return 0;
1271}
1272
1273static struct isc_format *find_format_by_fourcc(struct isc_device *isc,
1274 unsigned int fourcc)
1275{
1276 unsigned int num_formats = isc->num_user_formats;
1277 struct isc_format *fmt;
1278 unsigned int i;
1279
1280 for (i = 0; i < num_formats; i++) {
1281 fmt = isc->user_formats[i];
1282 if (fmt->fourcc == fourcc)
1283 return fmt;
1284 }
1285
1286 return NULL;
1287}
1288
1289static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f,
Songjun Wu93d4a262017-01-24 06:05:57 -02001290 struct isc_format **current_fmt, u32 *code)
Songjun Wu106267442016-08-17 03:05:27 -03001291{
1292 struct isc_format *isc_fmt;
1293 struct v4l2_pix_format *pixfmt = &f->fmt.pix;
Wenyou Yangb0ea17c2017-10-10 04:46:39 +02001294 struct v4l2_subdev_pad_config pad_cfg;
Songjun Wu106267442016-08-17 03:05:27 -03001295 struct v4l2_subdev_format format = {
1296 .which = V4L2_SUBDEV_FORMAT_TRY,
1297 };
Songjun Wu93d4a262017-01-24 06:05:57 -02001298 u32 mbus_code;
Songjun Wu106267442016-08-17 03:05:27 -03001299 int ret;
1300
1301 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1302 return -EINVAL;
1303
1304 isc_fmt = find_format_by_fourcc(isc, pixfmt->pixelformat);
1305 if (!isc_fmt) {
1306 v4l2_warn(&isc->v4l2_dev, "Format 0x%x not found\n",
1307 pixfmt->pixelformat);
1308 isc_fmt = isc->user_formats[isc->num_user_formats - 1];
1309 pixfmt->pixelformat = isc_fmt->fourcc;
1310 }
1311
1312 /* Limit to Atmel ISC hardware capabilities */
1313 if (pixfmt->width > ISC_MAX_SUPPORT_WIDTH)
1314 pixfmt->width = ISC_MAX_SUPPORT_WIDTH;
1315 if (pixfmt->height > ISC_MAX_SUPPORT_HEIGHT)
1316 pixfmt->height = ISC_MAX_SUPPORT_HEIGHT;
1317
Songjun Wu93d4a262017-01-24 06:05:57 -02001318 if (sensor_is_preferred(isc_fmt))
1319 mbus_code = isc_fmt->mbus_code;
1320 else
1321 mbus_code = isc->raw_fmt->mbus_code;
1322
1323 v4l2_fill_mbus_format(&format.format, pixfmt, mbus_code);
Songjun Wu106267442016-08-17 03:05:27 -03001324 ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt,
Wenyou Yangb0ea17c2017-10-10 04:46:39 +02001325 &pad_cfg, &format);
Songjun Wu106267442016-08-17 03:05:27 -03001326 if (ret < 0)
1327 return ret;
1328
1329 v4l2_fill_pix_format(pixfmt, &format.format);
1330
1331 pixfmt->field = V4L2_FIELD_NONE;
Songjun Wu93d4a262017-01-24 06:05:57 -02001332 pixfmt->bytesperline = (pixfmt->width * isc_fmt->bpp) >> 3;
Songjun Wu106267442016-08-17 03:05:27 -03001333 pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
1334
1335 if (current_fmt)
1336 *current_fmt = isc_fmt;
1337
Songjun Wu93d4a262017-01-24 06:05:57 -02001338 if (code)
1339 *code = mbus_code;
1340
Songjun Wu106267442016-08-17 03:05:27 -03001341 return 0;
1342}
1343
1344static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f)
1345{
1346 struct v4l2_subdev_format format = {
1347 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
1348 };
1349 struct isc_format *current_fmt;
Songjun Wu93d4a262017-01-24 06:05:57 -02001350 u32 mbus_code;
Songjun Wu106267442016-08-17 03:05:27 -03001351 int ret;
1352
Songjun Wu93d4a262017-01-24 06:05:57 -02001353 ret = isc_try_fmt(isc, f, &current_fmt, &mbus_code);
Songjun Wu106267442016-08-17 03:05:27 -03001354 if (ret)
1355 return ret;
1356
Songjun Wu93d4a262017-01-24 06:05:57 -02001357 v4l2_fill_mbus_format(&format.format, &f->fmt.pix, mbus_code);
Songjun Wu106267442016-08-17 03:05:27 -03001358 ret = v4l2_subdev_call(isc->current_subdev->sd, pad,
1359 set_fmt, NULL, &format);
1360 if (ret < 0)
1361 return ret;
1362
1363 isc->fmt = *f;
1364 isc->current_fmt = current_fmt;
1365
1366 return 0;
1367}
1368
1369static int isc_s_fmt_vid_cap(struct file *file, void *priv,
1370 struct v4l2_format *f)
1371{
1372 struct isc_device *isc = video_drvdata(file);
1373
1374 if (vb2_is_streaming(&isc->vb2_vidq))
1375 return -EBUSY;
1376
1377 return isc_set_fmt(isc, f);
1378}
1379
1380static int isc_try_fmt_vid_cap(struct file *file, void *priv,
1381 struct v4l2_format *f)
1382{
1383 struct isc_device *isc = video_drvdata(file);
1384
Songjun Wu93d4a262017-01-24 06:05:57 -02001385 return isc_try_fmt(isc, f, NULL, NULL);
Songjun Wu106267442016-08-17 03:05:27 -03001386}
1387
1388static int isc_enum_input(struct file *file, void *priv,
1389 struct v4l2_input *inp)
1390{
1391 if (inp->index != 0)
1392 return -EINVAL;
1393
1394 inp->type = V4L2_INPUT_TYPE_CAMERA;
1395 inp->std = 0;
1396 strcpy(inp->name, "Camera");
1397
1398 return 0;
1399}
1400
1401static int isc_g_input(struct file *file, void *priv, unsigned int *i)
1402{
1403 *i = 0;
1404
1405 return 0;
1406}
1407
1408static int isc_s_input(struct file *file, void *priv, unsigned int i)
1409{
1410 if (i > 0)
1411 return -EINVAL;
1412
1413 return 0;
1414}
1415
1416static int isc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
1417{
1418 struct isc_device *isc = video_drvdata(file);
1419
1420 if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1421 return -EINVAL;
1422
1423 return v4l2_subdev_call(isc->current_subdev->sd, video, g_parm, a);
1424}
1425
1426static int isc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
1427{
1428 struct isc_device *isc = video_drvdata(file);
1429
1430 if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1431 return -EINVAL;
1432
1433 return v4l2_subdev_call(isc->current_subdev->sd, video, s_parm, a);
1434}
1435
1436static int isc_enum_framesizes(struct file *file, void *fh,
1437 struct v4l2_frmsizeenum *fsize)
1438{
1439 struct isc_device *isc = video_drvdata(file);
1440 const struct isc_format *isc_fmt;
1441 struct v4l2_subdev_frame_size_enum fse = {
1442 .index = fsize->index,
1443 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
1444 };
1445 int ret;
1446
1447 isc_fmt = find_format_by_fourcc(isc, fsize->pixel_format);
1448 if (!isc_fmt)
1449 return -EINVAL;
1450
Songjun Wu93d4a262017-01-24 06:05:57 -02001451 if (sensor_is_preferred(isc_fmt))
1452 fse.code = isc_fmt->mbus_code;
1453 else
1454 fse.code = isc->raw_fmt->mbus_code;
Songjun Wu106267442016-08-17 03:05:27 -03001455
1456 ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size,
1457 NULL, &fse);
1458 if (ret)
1459 return ret;
1460
1461 fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1462 fsize->discrete.width = fse.max_width;
1463 fsize->discrete.height = fse.max_height;
1464
1465 return 0;
1466}
1467
1468static int isc_enum_frameintervals(struct file *file, void *fh,
1469 struct v4l2_frmivalenum *fival)
1470{
1471 struct isc_device *isc = video_drvdata(file);
1472 const struct isc_format *isc_fmt;
1473 struct v4l2_subdev_frame_interval_enum fie = {
1474 .index = fival->index,
1475 .width = fival->width,
1476 .height = fival->height,
1477 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
1478 };
1479 int ret;
1480
1481 isc_fmt = find_format_by_fourcc(isc, fival->pixel_format);
1482 if (!isc_fmt)
1483 return -EINVAL;
1484
Songjun Wu93d4a262017-01-24 06:05:57 -02001485 if (sensor_is_preferred(isc_fmt))
1486 fie.code = isc_fmt->mbus_code;
1487 else
1488 fie.code = isc->raw_fmt->mbus_code;
Songjun Wu106267442016-08-17 03:05:27 -03001489
1490 ret = v4l2_subdev_call(isc->current_subdev->sd, pad,
1491 enum_frame_interval, NULL, &fie);
1492 if (ret)
1493 return ret;
1494
1495 fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
1496 fival->discrete = fie.interval;
1497
1498 return 0;
1499}
1500
1501static const struct v4l2_ioctl_ops isc_ioctl_ops = {
1502 .vidioc_querycap = isc_querycap,
1503 .vidioc_enum_fmt_vid_cap = isc_enum_fmt_vid_cap,
1504 .vidioc_g_fmt_vid_cap = isc_g_fmt_vid_cap,
1505 .vidioc_s_fmt_vid_cap = isc_s_fmt_vid_cap,
1506 .vidioc_try_fmt_vid_cap = isc_try_fmt_vid_cap,
1507
1508 .vidioc_enum_input = isc_enum_input,
1509 .vidioc_g_input = isc_g_input,
1510 .vidioc_s_input = isc_s_input,
1511
1512 .vidioc_reqbufs = vb2_ioctl_reqbufs,
1513 .vidioc_querybuf = vb2_ioctl_querybuf,
1514 .vidioc_qbuf = vb2_ioctl_qbuf,
1515 .vidioc_expbuf = vb2_ioctl_expbuf,
1516 .vidioc_dqbuf = vb2_ioctl_dqbuf,
1517 .vidioc_create_bufs = vb2_ioctl_create_bufs,
1518 .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
1519 .vidioc_streamon = vb2_ioctl_streamon,
1520 .vidioc_streamoff = vb2_ioctl_streamoff,
1521
1522 .vidioc_g_parm = isc_g_parm,
1523 .vidioc_s_parm = isc_s_parm,
1524 .vidioc_enum_framesizes = isc_enum_framesizes,
1525 .vidioc_enum_frameintervals = isc_enum_frameintervals,
Songjun Wu93d4a262017-01-24 06:05:57 -02001526
1527 .vidioc_log_status = v4l2_ctrl_log_status,
1528 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
1529 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
Songjun Wu106267442016-08-17 03:05:27 -03001530};
1531
1532static int isc_open(struct file *file)
1533{
1534 struct isc_device *isc = video_drvdata(file);
1535 struct v4l2_subdev *sd = isc->current_subdev->sd;
1536 int ret;
1537
1538 if (mutex_lock_interruptible(&isc->lock))
1539 return -ERESTARTSYS;
1540
1541 ret = v4l2_fh_open(file);
1542 if (ret < 0)
1543 goto unlock;
1544
1545 if (!v4l2_fh_is_singular_file(file))
1546 goto unlock;
1547
1548 ret = v4l2_subdev_call(sd, core, s_power, 1);
Songjun Wu4540e0a2016-09-12 04:47:24 -03001549 if (ret < 0 && ret != -ENOIOCTLCMD) {
Songjun Wu106267442016-08-17 03:05:27 -03001550 v4l2_fh_release(file);
Songjun Wu4540e0a2016-09-12 04:47:24 -03001551 goto unlock;
1552 }
1553
1554 ret = isc_set_fmt(isc, &isc->fmt);
1555 if (ret) {
1556 v4l2_subdev_call(sd, core, s_power, 0);
1557 v4l2_fh_release(file);
1558 }
Songjun Wu106267442016-08-17 03:05:27 -03001559
1560unlock:
1561 mutex_unlock(&isc->lock);
1562 return ret;
1563}
1564
1565static int isc_release(struct file *file)
1566{
1567 struct isc_device *isc = video_drvdata(file);
1568 struct v4l2_subdev *sd = isc->current_subdev->sd;
1569 bool fh_singular;
1570 int ret;
1571
1572 mutex_lock(&isc->lock);
1573
1574 fh_singular = v4l2_fh_is_singular_file(file);
1575
1576 ret = _vb2_fop_release(file, NULL);
1577
1578 if (fh_singular)
1579 v4l2_subdev_call(sd, core, s_power, 0);
1580
1581 mutex_unlock(&isc->lock);
1582
1583 return ret;
1584}
1585
1586static const struct v4l2_file_operations isc_fops = {
1587 .owner = THIS_MODULE,
1588 .open = isc_open,
1589 .release = isc_release,
1590 .unlocked_ioctl = video_ioctl2,
1591 .read = vb2_fop_read,
1592 .mmap = vb2_fop_mmap,
1593 .poll = vb2_fop_poll,
1594};
1595
1596static irqreturn_t isc_interrupt(int irq, void *dev_id)
1597{
1598 struct isc_device *isc = (struct isc_device *)dev_id;
1599 struct regmap *regmap = isc->regmap;
1600 u32 isc_intsr, isc_intmask, pending;
1601 irqreturn_t ret = IRQ_NONE;
1602
Songjun Wu106267442016-08-17 03:05:27 -03001603 regmap_read(regmap, ISC_INTSR, &isc_intsr);
1604 regmap_read(regmap, ISC_INTMASK, &isc_intmask);
1605
1606 pending = isc_intsr & isc_intmask;
1607
1608 if (likely(pending & ISC_INT_DDONE)) {
Songjun Wu93d4a262017-01-24 06:05:57 -02001609 spin_lock(&isc->dma_queue_lock);
Songjun Wu106267442016-08-17 03:05:27 -03001610 if (isc->cur_frm) {
1611 struct vb2_v4l2_buffer *vbuf = &isc->cur_frm->vb;
1612 struct vb2_buffer *vb = &vbuf->vb2_buf;
1613
1614 vb->timestamp = ktime_get_ns();
1615 vbuf->sequence = isc->sequence++;
1616 vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
1617 isc->cur_frm = NULL;
1618 }
1619
1620 if (!list_empty(&isc->dma_queue) && !isc->stop) {
1621 isc->cur_frm = list_first_entry(&isc->dma_queue,
1622 struct isc_buffer, list);
1623 list_del(&isc->cur_frm->list);
1624
Songjun Wu93d4a262017-01-24 06:05:57 -02001625 isc_start_dma(isc);
Songjun Wu106267442016-08-17 03:05:27 -03001626 }
1627
1628 if (isc->stop)
1629 complete(&isc->comp);
1630
1631 ret = IRQ_HANDLED;
Songjun Wu93d4a262017-01-24 06:05:57 -02001632 spin_unlock(&isc->dma_queue_lock);
Songjun Wu106267442016-08-17 03:05:27 -03001633 }
1634
Songjun Wu93d4a262017-01-24 06:05:57 -02001635 if (pending & ISC_INT_HISDONE) {
1636 schedule_work(&isc->awb_work);
1637 ret = IRQ_HANDLED;
1638 }
Songjun Wu106267442016-08-17 03:05:27 -03001639
1640 return ret;
1641}
1642
Songjun Wu93d4a262017-01-24 06:05:57 -02001643static void isc_hist_count(struct isc_device *isc)
1644{
1645 struct regmap *regmap = isc->regmap;
1646 struct isc_ctrls *ctrls = &isc->ctrls;
1647 u32 *hist_count = &ctrls->hist_count[ctrls->hist_id];
1648 u32 *hist_entry = &ctrls->hist_entry[0];
1649 u32 i;
1650
1651 regmap_bulk_read(regmap, ISC_HIS_ENTRY, hist_entry, HIST_ENTRIES);
1652
1653 *hist_count = 0;
Colin Ian King6ea87862017-03-07 11:30:47 -03001654 for (i = 0; i < HIST_ENTRIES; i++)
Songjun Wu93d4a262017-01-24 06:05:57 -02001655 *hist_count += i * (*hist_entry++);
1656}
1657
1658static void isc_wb_update(struct isc_ctrls *ctrls)
1659{
1660 u32 *hist_count = &ctrls->hist_count[0];
1661 u64 g_count = (u64)hist_count[ISC_HIS_CFG_MODE_GB] << 9;
1662 u32 hist_r = hist_count[ISC_HIS_CFG_MODE_R];
1663 u32 hist_b = hist_count[ISC_HIS_CFG_MODE_B];
1664
1665 if (hist_r)
1666 ctrls->r_gain = div_u64(g_count, hist_r);
1667
1668 if (hist_b)
1669 ctrls->b_gain = div_u64(g_count, hist_b);
1670}
1671
1672static void isc_awb_work(struct work_struct *w)
1673{
1674 struct isc_device *isc =
1675 container_of(w, struct isc_device, awb_work);
1676 struct regmap *regmap = isc->regmap;
Wenyou Yangf103ea12017-10-10 04:46:40 +02001677 struct fmt_config *config = get_fmt_config(isc->raw_fmt->fourcc);
Songjun Wu93d4a262017-01-24 06:05:57 -02001678 struct isc_ctrls *ctrls = &isc->ctrls;
1679 u32 hist_id = ctrls->hist_id;
1680 u32 baysel;
1681
1682 if (ctrls->hist_stat != HIST_ENABLED)
1683 return;
1684
1685 isc_hist_count(isc);
1686
1687 if (hist_id != ISC_HIS_CFG_MODE_B) {
1688 hist_id++;
1689 } else {
1690 isc_wb_update(ctrls);
1691 hist_id = ISC_HIS_CFG_MODE_R;
1692 }
1693
1694 ctrls->hist_id = hist_id;
Wenyou Yangf103ea12017-10-10 04:46:40 +02001695 baysel = config->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT;
Songjun Wu93d4a262017-01-24 06:05:57 -02001696
1697 pm_runtime_get_sync(isc->dev);
1698
1699 regmap_write(regmap, ISC_HIS_CFG, hist_id | baysel | ISC_HIS_CFG_RAR);
1700 isc_update_profile(isc);
1701 regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
1702
1703 pm_runtime_put_sync(isc->dev);
1704}
1705
1706static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
1707{
1708 struct isc_device *isc = container_of(ctrl->handler,
1709 struct isc_device, ctrls.handler);
1710 struct isc_ctrls *ctrls = &isc->ctrls;
1711
1712 switch (ctrl->id) {
1713 case V4L2_CID_BRIGHTNESS:
1714 ctrls->brightness = ctrl->val & ISC_CBC_BRIGHT_MASK;
1715 break;
1716 case V4L2_CID_CONTRAST:
1717 ctrls->contrast = ctrl->val & ISC_CBC_CONTRAST_MASK;
1718 break;
1719 case V4L2_CID_GAMMA:
1720 ctrls->gamma_index = ctrl->val;
1721 break;
1722 case V4L2_CID_AUTO_WHITE_BALANCE:
1723 ctrls->awb = ctrl->val;
1724 if (ctrls->hist_stat != HIST_ENABLED) {
1725 ctrls->r_gain = 0x1 << 9;
1726 ctrls->b_gain = 0x1 << 9;
1727 }
1728 break;
1729 default:
1730 return -EINVAL;
1731 }
1732
1733 return 0;
1734}
1735
1736static const struct v4l2_ctrl_ops isc_ctrl_ops = {
1737 .s_ctrl = isc_s_ctrl,
1738};
1739
1740static int isc_ctrl_init(struct isc_device *isc)
1741{
1742 const struct v4l2_ctrl_ops *ops = &isc_ctrl_ops;
1743 struct isc_ctrls *ctrls = &isc->ctrls;
1744 struct v4l2_ctrl_handler *hdl = &ctrls->handler;
1745 int ret;
1746
1747 ctrls->hist_stat = HIST_INIT;
1748
1749 ret = v4l2_ctrl_handler_init(hdl, 4);
1750 if (ret < 0)
1751 return ret;
1752
1753 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0);
1754 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256);
1755 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 2);
1756 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
1757
1758 v4l2_ctrl_handler_setup(hdl);
1759
1760 return 0;
1761}
1762
1763
Songjun Wu106267442016-08-17 03:05:27 -03001764static int isc_async_bound(struct v4l2_async_notifier *notifier,
1765 struct v4l2_subdev *subdev,
1766 struct v4l2_async_subdev *asd)
1767{
1768 struct isc_device *isc = container_of(notifier->v4l2_dev,
1769 struct isc_device, v4l2_dev);
1770 struct isc_subdev_entity *subdev_entity =
1771 container_of(notifier, struct isc_subdev_entity, notifier);
1772
1773 if (video_is_registered(&isc->video_dev)) {
1774 v4l2_err(&isc->v4l2_dev, "only supports one sub-device.\n");
1775 return -EBUSY;
1776 }
1777
1778 subdev_entity->sd = subdev;
1779
1780 return 0;
1781}
1782
1783static void isc_async_unbind(struct v4l2_async_notifier *notifier,
1784 struct v4l2_subdev *subdev,
1785 struct v4l2_async_subdev *asd)
1786{
1787 struct isc_device *isc = container_of(notifier->v4l2_dev,
1788 struct isc_device, v4l2_dev);
Songjun Wu93d4a262017-01-24 06:05:57 -02001789 cancel_work_sync(&isc->awb_work);
Songjun Wu106267442016-08-17 03:05:27 -03001790 video_unregister_device(&isc->video_dev);
Songjun Wu93d4a262017-01-24 06:05:57 -02001791 v4l2_ctrl_handler_free(&isc->ctrls.handler);
Songjun Wu106267442016-08-17 03:05:27 -03001792}
1793
1794static struct isc_format *find_format_by_code(unsigned int code, int *index)
1795{
Wenyou Yangf103ea12017-10-10 04:46:40 +02001796 struct isc_format *fmt = &formats_list[0];
Songjun Wu106267442016-08-17 03:05:27 -03001797 unsigned int i;
1798
Wenyou Yangf103ea12017-10-10 04:46:40 +02001799 for (i = 0; i < ARRAY_SIZE(formats_list); i++) {
Songjun Wu106267442016-08-17 03:05:27 -03001800 if (fmt->mbus_code == code) {
1801 *index = i;
1802 return fmt;
1803 }
1804
1805 fmt++;
1806 }
1807
1808 return NULL;
1809}
1810
1811static int isc_formats_init(struct isc_device *isc)
1812{
1813 struct isc_format *fmt;
1814 struct v4l2_subdev *subdev = isc->current_subdev->sd;
Songjun Wu93d4a262017-01-24 06:05:57 -02001815 unsigned int num_fmts, i, j;
Wenyou Yangf103ea12017-10-10 04:46:40 +02001816 u32 list_size = ARRAY_SIZE(formats_list);
Songjun Wu106267442016-08-17 03:05:27 -03001817 struct v4l2_subdev_mbus_code_enum mbus_code = {
1818 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
1819 };
1820
Songjun Wu106267442016-08-17 03:05:27 -03001821 while (!v4l2_subdev_call(subdev, pad, enum_mbus_code,
1822 NULL, &mbus_code)) {
1823 mbus_code.index++;
Wenyou Yangf103ea12017-10-10 04:46:40 +02001824
Songjun Wu106267442016-08-17 03:05:27 -03001825 fmt = find_format_by_code(mbus_code.code, &i);
Wenyou Yangf103ea12017-10-10 04:46:40 +02001826 if ((!fmt) || (!(fmt->flags & FMT_FLAG_FROM_SENSOR)))
Songjun Wu106267442016-08-17 03:05:27 -03001827 continue;
1828
Songjun Wu93d4a262017-01-24 06:05:57 -02001829 fmt->sd_support = true;
1830
Wenyou Yangf103ea12017-10-10 04:46:40 +02001831 if (fmt->flags & FMT_FLAG_RAW_FORMAT)
Songjun Wu93d4a262017-01-24 06:05:57 -02001832 isc->raw_fmt = fmt;
Songjun Wu93d4a262017-01-24 06:05:57 -02001833 }
1834
Wenyou Yangf103ea12017-10-10 04:46:40 +02001835 fmt = &formats_list[0];
1836 for (i = 0; i < list_size; i++) {
1837 if (fmt->flags & FMT_FLAG_FROM_CONTROLLER)
1838 fmt->isc_support = true;
1839
1840 fmt++;
1841 }
1842
1843 fmt = &formats_list[0];
1844 num_fmts = 0;
1845 for (i = 0; i < list_size; i++) {
Songjun Wu93d4a262017-01-24 06:05:57 -02001846 if (fmt->isc_support || fmt->sd_support)
1847 num_fmts++;
1848
1849 fmt++;
Songjun Wu106267442016-08-17 03:05:27 -03001850 }
1851
1852 if (!num_fmts)
1853 return -ENXIO;
1854
1855 isc->num_user_formats = num_fmts;
1856 isc->user_formats = devm_kcalloc(isc->dev,
Markus Elfring2d3da592017-08-28 05:55:16 -04001857 num_fmts, sizeof(*isc->user_formats),
Songjun Wu106267442016-08-17 03:05:27 -03001858 GFP_KERNEL);
Markus Elfringc38e8652017-08-28 05:46:57 -04001859 if (!isc->user_formats)
Songjun Wu106267442016-08-17 03:05:27 -03001860 return -ENOMEM;
Songjun Wu106267442016-08-17 03:05:27 -03001861
Wenyou Yangf103ea12017-10-10 04:46:40 +02001862 fmt = &formats_list[0];
1863 for (i = 0, j = 0; i < list_size; i++) {
Songjun Wu93d4a262017-01-24 06:05:57 -02001864 if (fmt->isc_support || fmt->sd_support)
Songjun Wu106267442016-08-17 03:05:27 -03001865 isc->user_formats[j++] = fmt;
1866
1867 fmt++;
1868 }
1869
1870 return 0;
1871}
1872
1873static int isc_set_default_fmt(struct isc_device *isc)
1874{
1875 struct v4l2_format f = {
1876 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
1877 .fmt.pix = {
1878 .width = VGA_WIDTH,
1879 .height = VGA_HEIGHT,
1880 .field = V4L2_FIELD_NONE,
1881 .pixelformat = isc->user_formats[0]->fourcc,
1882 },
1883 };
Songjun Wu4540e0a2016-09-12 04:47:24 -03001884 int ret;
Songjun Wu106267442016-08-17 03:05:27 -03001885
Songjun Wu93d4a262017-01-24 06:05:57 -02001886 ret = isc_try_fmt(isc, &f, NULL, NULL);
Songjun Wu4540e0a2016-09-12 04:47:24 -03001887 if (ret)
1888 return ret;
1889
1890 isc->current_fmt = isc->user_formats[0];
1891 isc->fmt = f;
1892
1893 return 0;
Songjun Wu106267442016-08-17 03:05:27 -03001894}
1895
1896static int isc_async_complete(struct v4l2_async_notifier *notifier)
1897{
1898 struct isc_device *isc = container_of(notifier->v4l2_dev,
1899 struct isc_device, v4l2_dev);
Songjun Wu106267442016-08-17 03:05:27 -03001900 struct video_device *vdev = &isc->video_dev;
1901 struct vb2_queue *q = &isc->vb2_vidq;
1902 int ret;
1903
Songjun Wu93d4a262017-01-24 06:05:57 -02001904 ret = v4l2_device_register_subdev_nodes(&isc->v4l2_dev);
1905 if (ret < 0) {
1906 v4l2_err(&isc->v4l2_dev, "Failed to register subdev nodes\n");
1907 return ret;
1908 }
1909
Songjun Wu106267442016-08-17 03:05:27 -03001910 isc->current_subdev = container_of(notifier,
1911 struct isc_subdev_entity, notifier);
Songjun Wu106267442016-08-17 03:05:27 -03001912 mutex_init(&isc->lock);
1913 init_completion(&isc->comp);
1914
1915 /* Initialize videobuf2 queue */
1916 q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1917 q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
1918 q->drv_priv = isc;
1919 q->buf_struct_size = sizeof(struct isc_buffer);
1920 q->ops = &isc_vb2_ops;
1921 q->mem_ops = &vb2_dma_contig_memops;
1922 q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
1923 q->lock = &isc->lock;
1924 q->min_buffers_needed = 1;
1925 q->dev = isc->dev;
1926
1927 ret = vb2_queue_init(q);
1928 if (ret < 0) {
1929 v4l2_err(&isc->v4l2_dev,
1930 "vb2_queue_init() failed: %d\n", ret);
1931 return ret;
1932 }
1933
1934 /* Init video dma queues */
1935 INIT_LIST_HEAD(&isc->dma_queue);
1936 spin_lock_init(&isc->dma_queue_lock);
1937
Songjun Wu106267442016-08-17 03:05:27 -03001938 ret = isc_formats_init(isc);
1939 if (ret < 0) {
1940 v4l2_err(&isc->v4l2_dev,
1941 "Init format failed: %d\n", ret);
1942 return ret;
1943 }
1944
Songjun Wu106267442016-08-17 03:05:27 -03001945 ret = isc_set_default_fmt(isc);
1946 if (ret) {
1947 v4l2_err(&isc->v4l2_dev, "Could not set default format\n");
1948 return ret;
1949 }
1950
Songjun Wu93d4a262017-01-24 06:05:57 -02001951 ret = isc_ctrl_init(isc);
1952 if (ret) {
1953 v4l2_err(&isc->v4l2_dev, "Init isc ctrols failed: %d\n", ret);
1954 return ret;
1955 }
1956
1957 INIT_WORK(&isc->awb_work, isc_awb_work);
1958
Songjun Wu106267442016-08-17 03:05:27 -03001959 /* Register video device */
1960 strlcpy(vdev->name, ATMEL_ISC_NAME, sizeof(vdev->name));
1961 vdev->release = video_device_release_empty;
1962 vdev->fops = &isc_fops;
1963 vdev->ioctl_ops = &isc_ioctl_ops;
1964 vdev->v4l2_dev = &isc->v4l2_dev;
1965 vdev->vfl_dir = VFL_DIR_RX;
1966 vdev->queue = q;
1967 vdev->lock = &isc->lock;
Songjun Wu93d4a262017-01-24 06:05:57 -02001968 vdev->ctrl_handler = &isc->ctrls.handler;
Songjun Wu106267442016-08-17 03:05:27 -03001969 vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
1970 video_set_drvdata(vdev, isc);
1971
1972 ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
1973 if (ret < 0) {
1974 v4l2_err(&isc->v4l2_dev,
1975 "video_register_device failed: %d\n", ret);
1976 return ret;
1977 }
1978
1979 return 0;
1980}
1981
Laurent Pinchartb6ee3f02017-08-30 13:18:04 -04001982static const struct v4l2_async_notifier_operations isc_async_ops = {
1983 .bound = isc_async_bound,
1984 .unbind = isc_async_unbind,
1985 .complete = isc_async_complete,
1986};
1987
Songjun Wu106267442016-08-17 03:05:27 -03001988static void isc_subdev_cleanup(struct isc_device *isc)
1989{
1990 struct isc_subdev_entity *subdev_entity;
1991
1992 list_for_each_entry(subdev_entity, &isc->subdev_entities, list)
1993 v4l2_async_notifier_unregister(&subdev_entity->notifier);
1994
1995 INIT_LIST_HEAD(&isc->subdev_entities);
1996}
1997
1998static int isc_pipeline_init(struct isc_device *isc)
1999{
2000 struct device *dev = isc->dev;
2001 struct regmap *regmap = isc->regmap;
2002 struct regmap_field *regs;
2003 unsigned int i;
2004
2005 /* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */
2006 const struct reg_field regfields[ISC_PIPE_LINE_NODE_NUM] = {
2007 REG_FIELD(ISC_WB_CTRL, 0, 0),
2008 REG_FIELD(ISC_CFA_CTRL, 0, 0),
2009 REG_FIELD(ISC_CC_CTRL, 0, 0),
2010 REG_FIELD(ISC_GAM_CTRL, 0, 0),
2011 REG_FIELD(ISC_GAM_CTRL, 1, 1),
2012 REG_FIELD(ISC_GAM_CTRL, 2, 2),
2013 REG_FIELD(ISC_GAM_CTRL, 3, 3),
2014 REG_FIELD(ISC_CSC_CTRL, 0, 0),
2015 REG_FIELD(ISC_CBC_CTRL, 0, 0),
2016 REG_FIELD(ISC_SUB422_CTRL, 0, 0),
2017 REG_FIELD(ISC_SUB420_CTRL, 0, 0),
2018 };
2019
2020 for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) {
2021 regs = devm_regmap_field_alloc(dev, regmap, regfields[i]);
2022 if (IS_ERR(regs))
2023 return PTR_ERR(regs);
2024
2025 isc->pipeline[i] = regs;
2026 }
2027
2028 return 0;
2029}
2030
2031static int isc_parse_dt(struct device *dev, struct isc_device *isc)
2032{
2033 struct device_node *np = dev->of_node;
2034 struct device_node *epn = NULL, *rem;
Sakari Ailus859969b2016-08-26 20:17:25 -03002035 struct v4l2_fwnode_endpoint v4l2_epn;
Songjun Wu106267442016-08-17 03:05:27 -03002036 struct isc_subdev_entity *subdev_entity;
2037 unsigned int flags;
2038 int ret;
2039
2040 INIT_LIST_HEAD(&isc->subdev_entities);
2041
Mauro Carvalho Chehab79c54532017-11-01 08:54:58 -04002042 while (1) {
Songjun Wu106267442016-08-17 03:05:27 -03002043 epn = of_graph_get_next_endpoint(np, epn);
2044 if (!epn)
Mauro Carvalho Chehab79c54532017-11-01 08:54:58 -04002045 return 0;
Songjun Wu106267442016-08-17 03:05:27 -03002046
2047 rem = of_graph_get_remote_port_parent(epn);
2048 if (!rem) {
Rob Herring68d9c472017-07-21 15:28:33 -04002049 dev_notice(dev, "Remote device at %pOF not found\n",
2050 epn);
Songjun Wu106267442016-08-17 03:05:27 -03002051 continue;
2052 }
2053
Sakari Ailus859969b2016-08-26 20:17:25 -03002054 ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
2055 &v4l2_epn);
Songjun Wu106267442016-08-17 03:05:27 -03002056 if (ret) {
2057 of_node_put(rem);
2058 ret = -EINVAL;
2059 dev_err(dev, "Could not parse the endpoint\n");
2060 break;
2061 }
2062
2063 subdev_entity = devm_kzalloc(dev,
2064 sizeof(*subdev_entity), GFP_KERNEL);
Markus Elfringaf28c992017-08-28 06:50:28 -04002065 if (!subdev_entity) {
Songjun Wu106267442016-08-17 03:05:27 -03002066 of_node_put(rem);
2067 ret = -ENOMEM;
2068 break;
2069 }
2070
2071 subdev_entity->asd = devm_kzalloc(dev,
2072 sizeof(*subdev_entity->asd), GFP_KERNEL);
Markus Elfringaf28c992017-08-28 06:50:28 -04002073 if (!subdev_entity->asd) {
Songjun Wu106267442016-08-17 03:05:27 -03002074 of_node_put(rem);
2075 ret = -ENOMEM;
2076 break;
2077 }
2078
2079 flags = v4l2_epn.bus.parallel.flags;
2080
2081 if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
2082 subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
2083
2084 if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
2085 subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
2086
2087 if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
2088 subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
2089
Sakari Ailus859969b2016-08-26 20:17:25 -03002090 subdev_entity->asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
Mauro Carvalho Chehab4e48afe2017-09-27 10:12:00 -04002091 subdev_entity->asd->match.fwnode =
Sakari Ailus859969b2016-08-26 20:17:25 -03002092 of_fwnode_handle(rem);
Songjun Wu106267442016-08-17 03:05:27 -03002093 list_add_tail(&subdev_entity->list, &isc->subdev_entities);
2094 }
2095
2096 of_node_put(epn);
2097 return ret;
2098}
2099
2100/* regmap configuration */
2101#define ATMEL_ISC_REG_MAX 0xbfc
2102static const struct regmap_config isc_regmap_config = {
2103 .reg_bits = 32,
2104 .reg_stride = 4,
2105 .val_bits = 32,
2106 .max_register = ATMEL_ISC_REG_MAX,
2107};
2108
2109static int atmel_isc_probe(struct platform_device *pdev)
2110{
2111 struct device *dev = &pdev->dev;
2112 struct isc_device *isc;
2113 struct resource *res;
2114 void __iomem *io_base;
2115 struct isc_subdev_entity *subdev_entity;
2116 int irq;
2117 int ret;
2118
2119 isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
2120 if (!isc)
2121 return -ENOMEM;
2122
2123 platform_set_drvdata(pdev, isc);
2124 isc->dev = dev;
2125
2126 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2127 io_base = devm_ioremap_resource(dev, res);
2128 if (IS_ERR(io_base))
2129 return PTR_ERR(io_base);
2130
2131 isc->regmap = devm_regmap_init_mmio(dev, io_base, &isc_regmap_config);
2132 if (IS_ERR(isc->regmap)) {
2133 ret = PTR_ERR(isc->regmap);
2134 dev_err(dev, "failed to init register map: %d\n", ret);
2135 return ret;
2136 }
2137
2138 irq = platform_get_irq(pdev, 0);
Songjun Wu846c4a72016-08-24 05:49:28 -03002139 if (irq < 0) {
Songjun Wu106267442016-08-17 03:05:27 -03002140 ret = irq;
2141 dev_err(dev, "failed to get irq: %d\n", ret);
2142 return ret;
2143 }
2144
2145 ret = devm_request_irq(dev, irq, isc_interrupt, 0,
2146 ATMEL_ISC_NAME, isc);
2147 if (ret < 0) {
2148 dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
2149 irq, ret);
2150 return ret;
2151 }
2152
2153 ret = isc_pipeline_init(isc);
2154 if (ret)
2155 return ret;
2156
2157 isc->hclock = devm_clk_get(dev, "hclock");
2158 if (IS_ERR(isc->hclock)) {
2159 ret = PTR_ERR(isc->hclock);
2160 dev_err(dev, "failed to get hclock: %d\n", ret);
2161 return ret;
2162 }
2163
Wenyou Yang01192aa2017-10-10 04:46:38 +02002164 ret = clk_prepare_enable(isc->hclock);
2165 if (ret) {
2166 dev_err(dev, "failed to enable hclock: %d\n", ret);
2167 return ret;
2168 }
2169
Songjun Wu106267442016-08-17 03:05:27 -03002170 ret = isc_clk_init(isc);
2171 if (ret) {
2172 dev_err(dev, "failed to init isc clock: %d\n", ret);
Wenyou Yang01192aa2017-10-10 04:46:38 +02002173 goto unprepare_hclk;
Songjun Wu106267442016-08-17 03:05:27 -03002174 }
2175
2176 isc->ispck = isc->isc_clks[ISC_ISPCK].clk;
2177
Wenyou Yang01192aa2017-10-10 04:46:38 +02002178 ret = clk_prepare_enable(isc->ispck);
2179 if (ret) {
2180 dev_err(dev, "failed to enable ispck: %d\n", ret);
2181 goto unprepare_hclk;
2182 }
2183
Songjun Wu106267442016-08-17 03:05:27 -03002184 /* ispck should be greater or equal to hclock */
2185 ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock));
2186 if (ret) {
2187 dev_err(dev, "failed to set ispck rate: %d\n", ret);
Wenyou Yang01192aa2017-10-10 04:46:38 +02002188 goto unprepare_clk;
Songjun Wu106267442016-08-17 03:05:27 -03002189 }
2190
2191 ret = v4l2_device_register(dev, &isc->v4l2_dev);
2192 if (ret) {
2193 dev_err(dev, "unable to register v4l2 device.\n");
Wenyou Yang01192aa2017-10-10 04:46:38 +02002194 goto unprepare_clk;
Songjun Wu106267442016-08-17 03:05:27 -03002195 }
2196
2197 ret = isc_parse_dt(dev, isc);
2198 if (ret) {
2199 dev_err(dev, "fail to parse device tree\n");
2200 goto unregister_v4l2_device;
2201 }
2202
2203 if (list_empty(&isc->subdev_entities)) {
2204 dev_err(dev, "no subdev found\n");
Wei Yongjune04e5812016-11-11 11:40:20 -02002205 ret = -ENODEV;
Songjun Wu106267442016-08-17 03:05:27 -03002206 goto unregister_v4l2_device;
2207 }
2208
2209 list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
2210 subdev_entity->notifier.subdevs = &subdev_entity->asd;
2211 subdev_entity->notifier.num_subdevs = 1;
Laurent Pinchartb6ee3f02017-08-30 13:18:04 -04002212 subdev_entity->notifier.ops = &isc_async_ops;
Songjun Wu106267442016-08-17 03:05:27 -03002213
2214 ret = v4l2_async_notifier_register(&isc->v4l2_dev,
2215 &subdev_entity->notifier);
2216 if (ret) {
2217 dev_err(dev, "fail to register async notifier\n");
2218 goto cleanup_subdev;
2219 }
2220
2221 if (video_is_registered(&isc->video_dev))
2222 break;
2223 }
2224
Wenyou Yang01192aa2017-10-10 04:46:38 +02002225 pm_runtime_set_active(dev);
Songjun Wu106267442016-08-17 03:05:27 -03002226 pm_runtime_enable(dev);
Wenyou Yang01192aa2017-10-10 04:46:38 +02002227 pm_request_idle(dev);
Songjun Wu106267442016-08-17 03:05:27 -03002228
2229 return 0;
2230
2231cleanup_subdev:
2232 isc_subdev_cleanup(isc);
2233
2234unregister_v4l2_device:
2235 v4l2_device_unregister(&isc->v4l2_dev);
2236
Wenyou Yang01192aa2017-10-10 04:46:38 +02002237unprepare_clk:
2238 clk_disable_unprepare(isc->ispck);
2239unprepare_hclk:
2240 clk_disable_unprepare(isc->hclock);
2241
Songjun Wu106267442016-08-17 03:05:27 -03002242 isc_clk_cleanup(isc);
2243
2244 return ret;
2245}
2246
2247static int atmel_isc_remove(struct platform_device *pdev)
2248{
2249 struct isc_device *isc = platform_get_drvdata(pdev);
2250
2251 pm_runtime_disable(&pdev->dev);
Wenyou Yang01192aa2017-10-10 04:46:38 +02002252 clk_disable_unprepare(isc->ispck);
2253 clk_disable_unprepare(isc->hclock);
Songjun Wu106267442016-08-17 03:05:27 -03002254
2255 isc_subdev_cleanup(isc);
2256
2257 v4l2_device_unregister(&isc->v4l2_dev);
2258
2259 isc_clk_cleanup(isc);
2260
2261 return 0;
2262}
2263
Arnd Bergmannb7e50632016-09-12 12:32:58 -03002264static int __maybe_unused isc_runtime_suspend(struct device *dev)
Songjun Wu106267442016-08-17 03:05:27 -03002265{
2266 struct isc_device *isc = dev_get_drvdata(dev);
2267
2268 clk_disable_unprepare(isc->ispck);
2269 clk_disable_unprepare(isc->hclock);
2270
2271 return 0;
2272}
2273
Arnd Bergmannb7e50632016-09-12 12:32:58 -03002274static int __maybe_unused isc_runtime_resume(struct device *dev)
Songjun Wu106267442016-08-17 03:05:27 -03002275{
2276 struct isc_device *isc = dev_get_drvdata(dev);
2277 int ret;
2278
2279 ret = clk_prepare_enable(isc->hclock);
2280 if (ret)
2281 return ret;
2282
2283 return clk_prepare_enable(isc->ispck);
2284}
2285
2286static const struct dev_pm_ops atmel_isc_dev_pm_ops = {
2287 SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL)
2288};
2289
2290static const struct of_device_id atmel_isc_of_match[] = {
2291 { .compatible = "atmel,sama5d2-isc" },
2292 { }
2293};
2294MODULE_DEVICE_TABLE(of, atmel_isc_of_match);
2295
2296static struct platform_driver atmel_isc_driver = {
2297 .probe = atmel_isc_probe,
2298 .remove = atmel_isc_remove,
2299 .driver = {
2300 .name = ATMEL_ISC_NAME,
2301 .pm = &atmel_isc_dev_pm_ops,
2302 .of_match_table = of_match_ptr(atmel_isc_of_match),
2303 },
2304};
2305
2306module_platform_driver(atmel_isc_driver);
2307
2308MODULE_AUTHOR("Songjun Wu <songjun.wu@microchip.com>");
2309MODULE_DESCRIPTION("The V4L2 driver for Atmel-ISC");
2310MODULE_LICENSE("GPL v2");
2311MODULE_SUPPORTED_DEVICE("video");