blob: b380a7d40d858f7caa59d839ee3b27da8a26f3ac [file] [log] [blame]
Songjun Wu10626742016-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 Wu10626742016-08-17 03:05:27 -030033#include <linux/module.h>
34#include <linux/of.h>
35#include <linux/platform_device.h>
36#include <linux/pm_runtime.h>
37#include <linux/regmap.h>
38#include <linux/videodev2.h>
39
Songjun Wu93d4a262017-01-24 06:05:57 -020040#include <media/v4l2-ctrls.h>
Songjun Wu10626742016-08-17 03:05:27 -030041#include <media/v4l2-device.h>
Songjun Wu93d4a262017-01-24 06:05:57 -020042#include <media/v4l2-event.h>
Songjun Wu10626742016-08-17 03:05:27 -030043#include <media/v4l2-image-sizes.h>
44#include <media/v4l2-ioctl.h>
45#include <media/v4l2-of.h>
46#include <media/v4l2-subdev.h>
47#include <media/videobuf2-dma-contig.h>
48
49#include "atmel-isc-regs.h"
50
51#define ATMEL_ISC_NAME "atmel_isc"
52
53#define ISC_MAX_SUPPORT_WIDTH 2592
54#define ISC_MAX_SUPPORT_HEIGHT 1944
55
56#define ISC_CLK_MAX_DIV 255
57
58enum isc_clk_id {
59 ISC_ISPCK = 0,
60 ISC_MCK = 1,
61};
62
63struct isc_clk {
64 struct clk_hw hw;
65 struct clk *clk;
66 struct regmap *regmap;
67 u8 id;
68 u8 parent_id;
69 u32 div;
70 struct device *dev;
71};
72
73#define to_isc_clk(hw) container_of(hw, struct isc_clk, hw)
74
75struct isc_buffer {
76 struct vb2_v4l2_buffer vb;
77 struct list_head list;
78};
79
80struct isc_subdev_entity {
81 struct v4l2_subdev *sd;
82 struct v4l2_async_subdev *asd;
83 struct v4l2_async_notifier notifier;
84 struct v4l2_subdev_pad_config *config;
85
86 u32 pfe_cfg0;
87
88 struct list_head list;
89};
90
91/*
92 * struct isc_format - ISC media bus format information
93 * @fourcc: Fourcc code for this format
94 * @mbus_code: V4L2 media bus format code.
Songjun Wu93d4a262017-01-24 06:05:57 -020095 * @bpp: Bits per pixel (when stored in memory)
Songjun Wu10626742016-08-17 03:05:27 -030096 * @reg_bps: reg value for bits per sample
97 * (when transferred over a bus)
Songjun Wu93d4a262017-01-24 06:05:57 -020098 * @pipeline: pipeline switch
99 * @sd_support: Subdev supports this format
100 * @isc_support: ISC can convert raw format to this format
Songjun Wu10626742016-08-17 03:05:27 -0300101 */
102struct isc_format {
103 u32 fourcc;
104 u32 mbus_code;
105 u8 bpp;
106
107 u32 reg_bps;
Songjun Wu93d4a262017-01-24 06:05:57 -0200108 u32 reg_bay_cfg;
Songjun Wu10626742016-08-17 03:05:27 -0300109 u32 reg_rlp_mode;
110 u32 reg_dcfg_imode;
111 u32 reg_dctrl_dview;
112
Songjun Wu93d4a262017-01-24 06:05:57 -0200113 u32 pipeline;
114
115 bool sd_support;
116 bool isc_support;
117};
118
119
120#define HIST_ENTRIES 512
121#define HIST_BAYER (ISC_HIS_CFG_MODE_B + 1)
122
123enum{
124 HIST_INIT = 0,
125 HIST_ENABLED,
126 HIST_DISABLED,
127};
128
129struct isc_ctrls {
130 struct v4l2_ctrl_handler handler;
131
132 u32 brightness;
133 u32 contrast;
134 u8 gamma_index;
135 u8 awb;
136
137 u32 r_gain;
138 u32 b_gain;
139
140 u32 hist_entry[HIST_ENTRIES];
141 u32 hist_count[HIST_BAYER];
142 u8 hist_id;
143 u8 hist_stat;
Songjun Wu10626742016-08-17 03:05:27 -0300144};
145
146#define ISC_PIPE_LINE_NODE_NUM 11
147
148struct isc_device {
149 struct regmap *regmap;
150 struct clk *hclock;
151 struct clk *ispck;
152 struct isc_clk isc_clks[2];
153
154 struct device *dev;
155 struct v4l2_device v4l2_dev;
156 struct video_device video_dev;
157
158 struct vb2_queue vb2_vidq;
159 spinlock_t dma_queue_lock;
160 struct list_head dma_queue;
161 struct isc_buffer *cur_frm;
162 unsigned int sequence;
163 bool stop;
164 struct completion comp;
165
166 struct v4l2_format fmt;
167 struct isc_format **user_formats;
168 unsigned int num_user_formats;
169 const struct isc_format *current_fmt;
Songjun Wu93d4a262017-01-24 06:05:57 -0200170 const struct isc_format *raw_fmt;
171
172 struct isc_ctrls ctrls;
173 struct work_struct awb_work;
Songjun Wu10626742016-08-17 03:05:27 -0300174
175 struct mutex lock;
176
177 struct regmap_field *pipeline[ISC_PIPE_LINE_NODE_NUM];
178
179 struct isc_subdev_entity *current_subdev;
180 struct list_head subdev_entities;
181};
182
Songjun Wu93d4a262017-01-24 06:05:57 -0200183#define RAW_FMT_IND_START 0
184#define RAW_FMT_IND_END 11
185#define ISC_FMT_IND_START 12
186#define ISC_FMT_IND_END 14
187
Songjun Wu10626742016-08-17 03:05:27 -0300188static struct isc_format isc_formats[] = {
Songjun Wu93d4a262017-01-24 06:05:57 -0200189 { V4L2_PIX_FMT_SBGGR8, MEDIA_BUS_FMT_SBGGR8_1X8, 8,
190 ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT8,
191 ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0,
192 false, false },
193 { V4L2_PIX_FMT_SGBRG8, MEDIA_BUS_FMT_SGBRG8_1X8, 8,
194 ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_GBGB, ISC_RLP_CFG_MODE_DAT8,
195 ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0,
196 false, false },
197 { V4L2_PIX_FMT_SGRBG8, MEDIA_BUS_FMT_SGRBG8_1X8, 8,
198 ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_GRGR, ISC_RLP_CFG_MODE_DAT8,
199 ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0,
200 false, false },
201 { V4L2_PIX_FMT_SRGGB8, MEDIA_BUS_FMT_SRGGB8_1X8, 8,
202 ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_RGRG, ISC_RLP_CFG_MODE_DAT8,
203 ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0,
204 false, false },
Songjun Wu10626742016-08-17 03:05:27 -0300205
Songjun Wu93d4a262017-01-24 06:05:57 -0200206 { V4L2_PIX_FMT_SBGGR10, MEDIA_BUS_FMT_SBGGR10_1X10, 16,
207 ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT10,
208 ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0,
209 false, false },
210 { V4L2_PIX_FMT_SGBRG10, MEDIA_BUS_FMT_SGBRG10_1X10, 16,
211 ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_GBGB, ISC_RLP_CFG_MODE_DAT10,
212 ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0,
213 false, false },
214 { V4L2_PIX_FMT_SGRBG10, MEDIA_BUS_FMT_SGRBG10_1X10, 16,
215 ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_GRGR, ISC_RLP_CFG_MODE_DAT10,
216 ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0,
217 false, false },
218 { V4L2_PIX_FMT_SRGGB10, MEDIA_BUS_FMT_SRGGB10_1X10, 16,
219 ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_RGRG, ISC_RLP_CFG_MODE_DAT10,
220 ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0,
221 false, false },
Songjun Wu10626742016-08-17 03:05:27 -0300222
Songjun Wu93d4a262017-01-24 06:05:57 -0200223 { V4L2_PIX_FMT_SBGGR12, MEDIA_BUS_FMT_SBGGR12_1X12, 16,
224 ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT12,
225 ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0,
226 false, false },
227 { V4L2_PIX_FMT_SGBRG12, MEDIA_BUS_FMT_SGBRG12_1X12, 16,
228 ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_GBGB, ISC_RLP_CFG_MODE_DAT12,
229 ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0,
230 false, false },
231 { V4L2_PIX_FMT_SGRBG12, MEDIA_BUS_FMT_SGRBG12_1X12, 16,
232 ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_GRGR, ISC_RLP_CFG_MODE_DAT12,
233 ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0,
234 false, false },
235 { V4L2_PIX_FMT_SRGGB12, MEDIA_BUS_FMT_SRGGB12_1X12, 16,
236 ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_RGRG, ISC_RLP_CFG_MODE_DAT12,
237 ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0,
238 false, false },
Songjun Wu10626742016-08-17 03:05:27 -0300239
Songjun Wu93d4a262017-01-24 06:05:57 -0200240 { V4L2_PIX_FMT_YUV420, 0x0, 12,
241 ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_YYCC,
242 ISC_DCFG_IMODE_YC420P | ISC_DCFG_YMBSIZE_BEATS8 |
243 ISC_DCFG_CMBSIZE_BEATS8, ISC_DCTRL_DVIEW_PLANAR, 0x7fb,
244 false, false },
245 { V4L2_PIX_FMT_YUV422P, 0x0, 16,
246 ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_YYCC,
247 ISC_DCFG_IMODE_YC422P | ISC_DCFG_YMBSIZE_BEATS8 |
248 ISC_DCFG_CMBSIZE_BEATS8, ISC_DCTRL_DVIEW_PLANAR, 0x3fb,
249 false, false },
250 { V4L2_PIX_FMT_RGB565, MEDIA_BUS_FMT_RGB565_2X8_LE, 16,
251 ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_RGB565,
252 ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x7b,
253 false, false },
254
255 { V4L2_PIX_FMT_YUYV, MEDIA_BUS_FMT_YUYV8_2X8, 16,
256 ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT8,
257 ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0,
258 false, false },
Songjun Wu10626742016-08-17 03:05:27 -0300259};
260
Songjun Wu93d4a262017-01-24 06:05:57 -0200261#define GAMMA_MAX 2
262#define GAMMA_ENTRIES 64
263
264/* Gamma table with gamma 1/2.2 */
265static const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = {
266 /* 0 --> gamma 1/1.8 */
267 { 0x65, 0x66002F, 0x950025, 0xBB0020, 0xDB001D, 0xF8001A,
268 0x1130018, 0x12B0017, 0x1420016, 0x1580014, 0x16D0013, 0x1810012,
269 0x1940012, 0x1A60012, 0x1B80011, 0x1C90010, 0x1DA0010, 0x1EA000F,
270 0x1FA000F, 0x209000F, 0x218000F, 0x227000E, 0x235000E, 0x243000E,
271 0x251000E, 0x25F000D, 0x26C000D, 0x279000D, 0x286000D, 0x293000C,
272 0x2A0000C, 0x2AC000C, 0x2B8000C, 0x2C4000C, 0x2D0000B, 0x2DC000B,
273 0x2E7000B, 0x2F3000B, 0x2FE000B, 0x309000B, 0x314000B, 0x31F000A,
274 0x32A000A, 0x334000B, 0x33F000A, 0x349000A, 0x354000A, 0x35E000A,
275 0x368000A, 0x372000A, 0x37C000A, 0x386000A, 0x3900009, 0x399000A,
276 0x3A30009, 0x3AD0009, 0x3B60009, 0x3BF000A, 0x3C90009, 0x3D20009,
277 0x3DB0009, 0x3E40009, 0x3ED0009, 0x3F60009 },
278
279 /* 1 --> gamma 1/2 */
280 { 0x7F, 0x800034, 0xB50028, 0xDE0021, 0x100001E, 0x11E001B,
281 0x1390019, 0x1520017, 0x16A0015, 0x1800014, 0x1940014, 0x1A80013,
282 0x1BB0012, 0x1CD0011, 0x1DF0010, 0x1EF0010, 0x200000F, 0x20F000F,
283 0x21F000E, 0x22D000F, 0x23C000E, 0x24A000E, 0x258000D, 0x265000D,
284 0x273000C, 0x27F000D, 0x28C000C, 0x299000C, 0x2A5000C, 0x2B1000B,
285 0x2BC000C, 0x2C8000B, 0x2D3000C, 0x2DF000B, 0x2EA000A, 0x2F5000A,
286 0x2FF000B, 0x30A000A, 0x314000B, 0x31F000A, 0x329000A, 0x333000A,
287 0x33D0009, 0x3470009, 0x350000A, 0x35A0009, 0x363000A, 0x36D0009,
288 0x3760009, 0x37F0009, 0x3880009, 0x3910009, 0x39A0009, 0x3A30009,
289 0x3AC0008, 0x3B40009, 0x3BD0008, 0x3C60008, 0x3CE0008, 0x3D60009,
290 0x3DF0008, 0x3E70008, 0x3EF0008, 0x3F70008 },
291
292 /* 2 --> gamma 1/2.2 */
293 { 0x99, 0x9B0038, 0xD4002A, 0xFF0023, 0x122001F, 0x141001B,
294 0x15D0019, 0x1760017, 0x18E0015, 0x1A30015, 0x1B80013, 0x1CC0012,
295 0x1DE0011, 0x1F00010, 0x2010010, 0x2110010, 0x221000F, 0x230000F,
296 0x23F000E, 0x24D000E, 0x25B000D, 0x269000C, 0x276000C, 0x283000C,
297 0x28F000C, 0x29B000C, 0x2A7000C, 0x2B3000B, 0x2BF000B, 0x2CA000B,
298 0x2D5000B, 0x2E0000A, 0x2EB000A, 0x2F5000A, 0x2FF000A, 0x30A000A,
299 0x3140009, 0x31E0009, 0x327000A, 0x3310009, 0x33A0009, 0x3440009,
300 0x34D0009, 0x3560009, 0x35F0009, 0x3680008, 0x3710008, 0x3790009,
301 0x3820008, 0x38A0008, 0x3930008, 0x39B0008, 0x3A30008, 0x3AB0008,
302 0x3B30008, 0x3BB0008, 0x3C30008, 0x3CB0007, 0x3D20008, 0x3DA0007,
303 0x3E20007, 0x3E90007, 0x3F00008, 0x3F80007 },
304};
305
306static unsigned int sensor_preferred = 1;
307module_param(sensor_preferred, uint, 0644);
308MODULE_PARM_DESC(sensor_preferred,
309 "Sensor is preferred to output the specified format (1-on 0-off), default 1");
310
Songjun Wu10626742016-08-17 03:05:27 -0300311static int isc_clk_enable(struct clk_hw *hw)
312{
313 struct isc_clk *isc_clk = to_isc_clk(hw);
314 u32 id = isc_clk->id;
315 struct regmap *regmap = isc_clk->regmap;
316
317 dev_dbg(isc_clk->dev, "ISC CLK: %s, div = %d, parent id = %d\n",
318 __func__, isc_clk->div, isc_clk->parent_id);
319
320 regmap_update_bits(regmap, ISC_CLKCFG,
321 ISC_CLKCFG_DIV_MASK(id) | ISC_CLKCFG_SEL_MASK(id),
322 (isc_clk->div << ISC_CLKCFG_DIV_SHIFT(id)) |
323 (isc_clk->parent_id << ISC_CLKCFG_SEL_SHIFT(id)));
324
325 regmap_write(regmap, ISC_CLKEN, ISC_CLK(id));
326
327 return 0;
328}
329
330static void isc_clk_disable(struct clk_hw *hw)
331{
332 struct isc_clk *isc_clk = to_isc_clk(hw);
333 u32 id = isc_clk->id;
334
335 regmap_write(isc_clk->regmap, ISC_CLKDIS, ISC_CLK(id));
336}
337
338static int isc_clk_is_enabled(struct clk_hw *hw)
339{
340 struct isc_clk *isc_clk = to_isc_clk(hw);
341 u32 status;
342
343 regmap_read(isc_clk->regmap, ISC_CLKSR, &status);
344
345 return status & ISC_CLK(isc_clk->id) ? 1 : 0;
346}
347
348static unsigned long
349isc_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
350{
351 struct isc_clk *isc_clk = to_isc_clk(hw);
352
353 return DIV_ROUND_CLOSEST(parent_rate, isc_clk->div + 1);
354}
355
356static int isc_clk_determine_rate(struct clk_hw *hw,
357 struct clk_rate_request *req)
358{
359 struct isc_clk *isc_clk = to_isc_clk(hw);
360 long best_rate = -EINVAL;
361 int best_diff = -1;
362 unsigned int i, div;
363
364 for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
365 struct clk_hw *parent;
366 unsigned long parent_rate;
367
368 parent = clk_hw_get_parent_by_index(hw, i);
369 if (!parent)
370 continue;
371
372 parent_rate = clk_hw_get_rate(parent);
373 if (!parent_rate)
374 continue;
375
376 for (div = 1; div < ISC_CLK_MAX_DIV + 2; div++) {
377 unsigned long rate;
378 int diff;
379
380 rate = DIV_ROUND_CLOSEST(parent_rate, div);
381 diff = abs(req->rate - rate);
382
383 if (best_diff < 0 || best_diff > diff) {
384 best_rate = rate;
385 best_diff = diff;
386 req->best_parent_rate = parent_rate;
387 req->best_parent_hw = parent;
388 }
389
390 if (!best_diff || rate < req->rate)
391 break;
392 }
393
394 if (!best_diff)
395 break;
396 }
397
398 dev_dbg(isc_clk->dev,
399 "ISC CLK: %s, best_rate = %ld, parent clk: %s @ %ld\n",
400 __func__, best_rate,
401 __clk_get_name((req->best_parent_hw)->clk),
402 req->best_parent_rate);
403
404 if (best_rate < 0)
405 return best_rate;
406
407 req->rate = best_rate;
408
409 return 0;
410}
411
412static int isc_clk_set_parent(struct clk_hw *hw, u8 index)
413{
414 struct isc_clk *isc_clk = to_isc_clk(hw);
415
416 if (index >= clk_hw_get_num_parents(hw))
417 return -EINVAL;
418
419 isc_clk->parent_id = index;
420
421 return 0;
422}
423
424static u8 isc_clk_get_parent(struct clk_hw *hw)
425{
426 struct isc_clk *isc_clk = to_isc_clk(hw);
427
428 return isc_clk->parent_id;
429}
430
431static int isc_clk_set_rate(struct clk_hw *hw,
432 unsigned long rate,
433 unsigned long parent_rate)
434{
435 struct isc_clk *isc_clk = to_isc_clk(hw);
436 u32 div;
437
438 if (!rate)
439 return -EINVAL;
440
441 div = DIV_ROUND_CLOSEST(parent_rate, rate);
442 if (div > (ISC_CLK_MAX_DIV + 1) || !div)
443 return -EINVAL;
444
445 isc_clk->div = div - 1;
446
447 return 0;
448}
449
450static const struct clk_ops isc_clk_ops = {
451 .enable = isc_clk_enable,
452 .disable = isc_clk_disable,
453 .is_enabled = isc_clk_is_enabled,
454 .recalc_rate = isc_clk_recalc_rate,
455 .determine_rate = isc_clk_determine_rate,
456 .set_parent = isc_clk_set_parent,
457 .get_parent = isc_clk_get_parent,
458 .set_rate = isc_clk_set_rate,
459};
460
461static int isc_clk_register(struct isc_device *isc, unsigned int id)
462{
463 struct regmap *regmap = isc->regmap;
464 struct device_node *np = isc->dev->of_node;
465 struct isc_clk *isc_clk;
466 struct clk_init_data init;
467 const char *clk_name = np->name;
468 const char *parent_names[3];
469 int num_parents;
470
471 num_parents = of_clk_get_parent_count(np);
472 if (num_parents < 1 || num_parents > 3)
473 return -EINVAL;
474
475 if (num_parents > 2 && id == ISC_ISPCK)
476 num_parents = 2;
477
478 of_clk_parent_fill(np, parent_names, num_parents);
479
480 if (id == ISC_MCK)
481 of_property_read_string(np, "clock-output-names", &clk_name);
482 else
483 clk_name = "isc-ispck";
484
485 init.parent_names = parent_names;
486 init.num_parents = num_parents;
487 init.name = clk_name;
488 init.ops = &isc_clk_ops;
489 init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
490
491 isc_clk = &isc->isc_clks[id];
492 isc_clk->hw.init = &init;
493 isc_clk->regmap = regmap;
494 isc_clk->id = id;
495 isc_clk->dev = isc->dev;
496
497 isc_clk->clk = clk_register(isc->dev, &isc_clk->hw);
498 if (IS_ERR(isc_clk->clk)) {
499 dev_err(isc->dev, "%s: clock register fail\n", clk_name);
500 return PTR_ERR(isc_clk->clk);
501 } else if (id == ISC_MCK)
502 of_clk_add_provider(np, of_clk_src_simple_get, isc_clk->clk);
503
504 return 0;
505}
506
507static int isc_clk_init(struct isc_device *isc)
508{
509 unsigned int i;
510 int ret;
511
512 for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++)
513 isc->isc_clks[i].clk = ERR_PTR(-EINVAL);
514
515 for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) {
516 ret = isc_clk_register(isc, i);
517 if (ret)
518 return ret;
519 }
520
521 return 0;
522}
523
524static void isc_clk_cleanup(struct isc_device *isc)
525{
526 unsigned int i;
527
528 of_clk_del_provider(isc->dev->of_node);
529
530 for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) {
531 struct isc_clk *isc_clk = &isc->isc_clks[i];
532
533 if (!IS_ERR(isc_clk->clk))
534 clk_unregister(isc_clk->clk);
535 }
536}
537
538static int isc_queue_setup(struct vb2_queue *vq,
539 unsigned int *nbuffers, unsigned int *nplanes,
540 unsigned int sizes[], struct device *alloc_devs[])
541{
542 struct isc_device *isc = vb2_get_drv_priv(vq);
543 unsigned int size = isc->fmt.fmt.pix.sizeimage;
544
545 if (*nplanes)
546 return sizes[0] < size ? -EINVAL : 0;
547
548 *nplanes = 1;
549 sizes[0] = size;
550
551 return 0;
552}
553
554static int isc_buffer_prepare(struct vb2_buffer *vb)
555{
556 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
557 struct isc_device *isc = vb2_get_drv_priv(vb->vb2_queue);
558 unsigned long size = isc->fmt.fmt.pix.sizeimage;
559
560 if (vb2_plane_size(vb, 0) < size) {
561 v4l2_err(&isc->v4l2_dev, "buffer too small (%lu < %lu)\n",
562 vb2_plane_size(vb, 0), size);
563 return -EINVAL;
564 }
565
566 vb2_set_plane_payload(vb, 0, size);
567
568 vbuf->field = isc->fmt.fmt.pix.field;
569
570 return 0;
571}
572
Songjun Wu93d4a262017-01-24 06:05:57 -0200573static inline bool sensor_is_preferred(const struct isc_format *isc_fmt)
Songjun Wu10626742016-08-17 03:05:27 -0300574{
Songjun Wu93d4a262017-01-24 06:05:57 -0200575 return (sensor_preferred && isc_fmt->sd_support) ||
576 !isc_fmt->isc_support;
577}
Songjun Wu10626742016-08-17 03:05:27 -0300578
Songjun Wu93d4a262017-01-24 06:05:57 -0200579static void isc_start_dma(struct isc_device *isc)
580{
581 struct regmap *regmap = isc->regmap;
582 struct v4l2_pix_format *pixfmt = &isc->fmt.fmt.pix;
583 u32 sizeimage = pixfmt->sizeimage;
584 u32 dctrl_dview;
585 dma_addr_t addr0;
Songjun Wu10626742016-08-17 03:05:27 -0300586
Songjun Wu93d4a262017-01-24 06:05:57 -0200587 addr0 = vb2_dma_contig_plane_dma_addr(&isc->cur_frm->vb.vb2_buf, 0);
588 regmap_write(regmap, ISC_DAD0, addr0);
589
590 switch (pixfmt->pixelformat) {
591 case V4L2_PIX_FMT_YUV420:
592 regmap_write(regmap, ISC_DAD1, addr0 + (sizeimage * 2) / 3);
593 regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 5) / 6);
594 break;
595 case V4L2_PIX_FMT_YUV422P:
596 regmap_write(regmap, ISC_DAD1, addr0 + sizeimage / 2);
597 regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 3) / 4);
598 break;
599 default:
600 break;
601 }
602
603 if (sensor_is_preferred(isc->current_fmt))
604 dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
605 else
606 dctrl_dview = isc->current_fmt->reg_dctrl_dview;
607
608 regmap_write(regmap, ISC_DCTRL, dctrl_dview | ISC_DCTRL_IE_IS);
Songjun Wu10626742016-08-17 03:05:27 -0300609 regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE);
610}
611
612static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
613{
Songjun Wu93d4a262017-01-24 06:05:57 -0200614 struct regmap *regmap = isc->regmap;
615 struct isc_ctrls *ctrls = &isc->ctrls;
616 u32 val, bay_cfg;
617 const u32 *gamma;
Songjun Wu10626742016-08-17 03:05:27 -0300618 unsigned int i;
619
Songjun Wu93d4a262017-01-24 06:05:57 -0200620 /* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */
Songjun Wu10626742016-08-17 03:05:27 -0300621 for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) {
622 val = pipeline & BIT(i) ? 1 : 0;
623 regmap_field_write(isc->pipeline[i], val);
624 }
Songjun Wu93d4a262017-01-24 06:05:57 -0200625
626 if (!pipeline)
627 return;
628
629 bay_cfg = isc->raw_fmt->reg_bay_cfg;
630
631 regmap_write(regmap, ISC_WB_CFG, bay_cfg);
632 regmap_write(regmap, ISC_WB_O_RGR, 0x0);
633 regmap_write(regmap, ISC_WB_O_BGR, 0x0);
634 regmap_write(regmap, ISC_WB_G_RGR, ctrls->r_gain | (0x1 << 25));
635 regmap_write(regmap, ISC_WB_G_BGR, ctrls->b_gain | (0x1 << 25));
636
637 regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL);
638
639 gamma = &isc_gamma_table[ctrls->gamma_index][0];
640 regmap_bulk_write(regmap, ISC_GAM_BENTRY, gamma, GAMMA_ENTRIES);
641 regmap_bulk_write(regmap, ISC_GAM_GENTRY, gamma, GAMMA_ENTRIES);
642 regmap_bulk_write(regmap, ISC_GAM_RENTRY, gamma, GAMMA_ENTRIES);
643
644 /* Convert RGB to YUV */
645 regmap_write(regmap, ISC_CSC_YR_YG, 0x42 | (0x81 << 16));
646 regmap_write(regmap, ISC_CSC_YB_OY, 0x19 | (0x10 << 16));
647 regmap_write(regmap, ISC_CSC_CBR_CBG, 0xFDA | (0xFB6 << 16));
648 regmap_write(regmap, ISC_CSC_CBB_OCB, 0x70 | (0x80 << 16));
649 regmap_write(regmap, ISC_CSC_CRR_CRG, 0x70 | (0xFA2 << 16));
650 regmap_write(regmap, ISC_CSC_CRB_OCR, 0xFEE | (0x80 << 16));
651
652 regmap_write(regmap, ISC_CBC_BRIGHT, ctrls->brightness);
653 regmap_write(regmap, ISC_CBC_CONTRAST, ctrls->contrast);
654}
655
656static int isc_update_profile(struct isc_device *isc)
657{
658 struct regmap *regmap = isc->regmap;
659 u32 sr;
660 int counter = 100;
661
662 regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_UPPRO);
663
664 regmap_read(regmap, ISC_CTRLSR, &sr);
665 while ((sr & ISC_CTRL_UPPRO) && counter--) {
666 usleep_range(1000, 2000);
667 regmap_read(regmap, ISC_CTRLSR, &sr);
668 }
669
670 if (counter < 0) {
671 v4l2_warn(&isc->v4l2_dev, "Time out to update profie\n");
672 return -ETIMEDOUT;
673 }
674
675 return 0;
676}
677
678static void isc_set_histogram(struct isc_device *isc)
679{
680 struct regmap *regmap = isc->regmap;
681 struct isc_ctrls *ctrls = &isc->ctrls;
682
683 if (ctrls->awb && (ctrls->hist_stat != HIST_ENABLED)) {
684 regmap_write(regmap, ISC_HIS_CFG, ISC_HIS_CFG_MODE_R |
685 (isc->raw_fmt->reg_bay_cfg << ISC_HIS_CFG_BAYSEL_SHIFT) |
686 ISC_HIS_CFG_RAR);
687 regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_EN);
688 regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE);
689 ctrls->hist_id = ISC_HIS_CFG_MODE_R;
690 isc_update_profile(isc);
691 regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
692
693 ctrls->hist_stat = HIST_ENABLED;
694 } else if (!ctrls->awb && (ctrls->hist_stat != HIST_DISABLED)) {
695 regmap_write(regmap, ISC_INTDIS, ISC_INT_HISDONE);
696 regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_DIS);
697
698 ctrls->hist_stat = HIST_DISABLED;
699 }
700}
701
702static inline void isc_get_param(const struct isc_format *fmt,
703 u32 *rlp_mode, u32 *dcfg_imode)
704{
705 switch (fmt->fourcc) {
706 case V4L2_PIX_FMT_SBGGR10:
707 case V4L2_PIX_FMT_SGBRG10:
708 case V4L2_PIX_FMT_SGRBG10:
709 case V4L2_PIX_FMT_SRGGB10:
710 case V4L2_PIX_FMT_SBGGR12:
711 case V4L2_PIX_FMT_SGBRG12:
712 case V4L2_PIX_FMT_SGRBG12:
713 case V4L2_PIX_FMT_SRGGB12:
714 *rlp_mode = fmt->reg_rlp_mode;
715 *dcfg_imode = fmt->reg_dcfg_imode;
716 break;
717 default:
718 *rlp_mode = ISC_RLP_CFG_MODE_DAT8;
719 *dcfg_imode = ISC_DCFG_IMODE_PACKED8;
720 break;
721 }
Songjun Wu10626742016-08-17 03:05:27 -0300722}
723
724static int isc_configure(struct isc_device *isc)
725{
726 struct regmap *regmap = isc->regmap;
727 const struct isc_format *current_fmt = isc->current_fmt;
728 struct isc_subdev_entity *subdev = isc->current_subdev;
Songjun Wu93d4a262017-01-24 06:05:57 -0200729 u32 pfe_cfg0, rlp_mode, dcfg_imode, mask, pipeline;
Songjun Wu10626742016-08-17 03:05:27 -0300730
Songjun Wu93d4a262017-01-24 06:05:57 -0200731 if (sensor_is_preferred(current_fmt)) {
732 pfe_cfg0 = current_fmt->reg_bps;
733 pipeline = 0x0;
734 isc_get_param(current_fmt, &rlp_mode, &dcfg_imode);
735 isc->ctrls.hist_stat = HIST_INIT;
736 } else {
737 pfe_cfg0 = isc->raw_fmt->reg_bps;
738 pipeline = current_fmt->pipeline;
739 rlp_mode = current_fmt->reg_rlp_mode;
740 dcfg_imode = current_fmt->reg_dcfg_imode;
741 }
742
743 pfe_cfg0 |= subdev->pfe_cfg0 | ISC_PFE_CFG0_MODE_PROGRESSIVE;
Songjun Wu10626742016-08-17 03:05:27 -0300744 mask = ISC_PFE_CFG0_BPS_MASK | ISC_PFE_CFG0_HPOL_LOW |
745 ISC_PFE_CFG0_VPOL_LOW | ISC_PFE_CFG0_PPOL_LOW |
746 ISC_PFE_CFG0_MODE_MASK;
747
Songjun Wu93d4a262017-01-24 06:05:57 -0200748 regmap_update_bits(regmap, ISC_PFE_CFG0, mask, pfe_cfg0);
Songjun Wu10626742016-08-17 03:05:27 -0300749
750 regmap_update_bits(regmap, ISC_RLP_CFG, ISC_RLP_CFG_MODE_MASK,
Songjun Wu93d4a262017-01-24 06:05:57 -0200751 rlp_mode);
Songjun Wu10626742016-08-17 03:05:27 -0300752
Songjun Wu93d4a262017-01-24 06:05:57 -0200753 regmap_update_bits(regmap, ISC_DCFG, ISC_DCFG_IMODE_MASK, dcfg_imode);
Songjun Wu10626742016-08-17 03:05:27 -0300754
Songjun Wu93d4a262017-01-24 06:05:57 -0200755 /* Set the pipeline */
756 isc_set_pipeline(isc, pipeline);
757
758 if (pipeline)
759 isc_set_histogram(isc);
Songjun Wu10626742016-08-17 03:05:27 -0300760
761 /* Update profile */
Songjun Wu93d4a262017-01-24 06:05:57 -0200762 return isc_update_profile(isc);
Songjun Wu10626742016-08-17 03:05:27 -0300763}
764
765static int isc_start_streaming(struct vb2_queue *vq, unsigned int count)
766{
767 struct isc_device *isc = vb2_get_drv_priv(vq);
768 struct regmap *regmap = isc->regmap;
769 struct isc_buffer *buf;
770 unsigned long flags;
771 int ret;
Songjun Wu10626742016-08-17 03:05:27 -0300772
773 /* Enable stream on the sub device */
774 ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1);
775 if (ret && ret != -ENOIOCTLCMD) {
776 v4l2_err(&isc->v4l2_dev, "stream on failed in subdev\n");
777 goto err_start_stream;
778 }
779
780 pm_runtime_get_sync(isc->dev);
781
Songjun Wu10626742016-08-17 03:05:27 -0300782 ret = isc_configure(isc);
783 if (unlikely(ret))
784 goto err_configure;
785
786 /* Enable DMA interrupt */
787 regmap_write(regmap, ISC_INTEN, ISC_INT_DDONE);
788
789 spin_lock_irqsave(&isc->dma_queue_lock, flags);
790
791 isc->sequence = 0;
792 isc->stop = false;
793 reinit_completion(&isc->comp);
794
795 isc->cur_frm = list_first_entry(&isc->dma_queue,
796 struct isc_buffer, list);
797 list_del(&isc->cur_frm->list);
798
Songjun Wu93d4a262017-01-24 06:05:57 -0200799 isc_start_dma(isc);
Songjun Wu10626742016-08-17 03:05:27 -0300800
801 spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
802
803 return 0;
804
805err_configure:
806 pm_runtime_put_sync(isc->dev);
807
808 v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0);
809
810err_start_stream:
811 spin_lock_irqsave(&isc->dma_queue_lock, flags);
812 list_for_each_entry(buf, &isc->dma_queue, list)
813 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
814 INIT_LIST_HEAD(&isc->dma_queue);
815 spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
816
817 return ret;
818}
819
820static void isc_stop_streaming(struct vb2_queue *vq)
821{
822 struct isc_device *isc = vb2_get_drv_priv(vq);
823 unsigned long flags;
824 struct isc_buffer *buf;
825 int ret;
826
827 isc->stop = true;
828
829 /* Wait until the end of the current frame */
830 if (isc->cur_frm && !wait_for_completion_timeout(&isc->comp, 5 * HZ))
831 v4l2_err(&isc->v4l2_dev,
832 "Timeout waiting for end of the capture\n");
833
834 /* Disable DMA interrupt */
835 regmap_write(isc->regmap, ISC_INTDIS, ISC_INT_DDONE);
836
837 pm_runtime_put_sync(isc->dev);
838
839 /* Disable stream on the sub device */
840 ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0);
841 if (ret && ret != -ENOIOCTLCMD)
842 v4l2_err(&isc->v4l2_dev, "stream off failed in subdev\n");
843
844 /* Release all active buffers */
845 spin_lock_irqsave(&isc->dma_queue_lock, flags);
846 if (unlikely(isc->cur_frm)) {
847 vb2_buffer_done(&isc->cur_frm->vb.vb2_buf,
848 VB2_BUF_STATE_ERROR);
849 isc->cur_frm = NULL;
850 }
851 list_for_each_entry(buf, &isc->dma_queue, list)
852 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
853 INIT_LIST_HEAD(&isc->dma_queue);
854 spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
855}
856
857static void isc_buffer_queue(struct vb2_buffer *vb)
858{
859 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
860 struct isc_buffer *buf = container_of(vbuf, struct isc_buffer, vb);
861 struct isc_device *isc = vb2_get_drv_priv(vb->vb2_queue);
862 unsigned long flags;
863
864 spin_lock_irqsave(&isc->dma_queue_lock, flags);
Songjun Wufa8bbe02016-09-28 02:28:57 -0300865 if (!isc->cur_frm && list_empty(&isc->dma_queue) &&
866 vb2_is_streaming(vb->vb2_queue)) {
867 isc->cur_frm = buf;
Songjun Wu93d4a262017-01-24 06:05:57 -0200868 isc_start_dma(isc);
Songjun Wufa8bbe02016-09-28 02:28:57 -0300869 } else
870 list_add_tail(&buf->list, &isc->dma_queue);
Songjun Wu10626742016-08-17 03:05:27 -0300871 spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
872}
873
874static struct vb2_ops isc_vb2_ops = {
875 .queue_setup = isc_queue_setup,
876 .wait_prepare = vb2_ops_wait_prepare,
877 .wait_finish = vb2_ops_wait_finish,
878 .buf_prepare = isc_buffer_prepare,
879 .start_streaming = isc_start_streaming,
880 .stop_streaming = isc_stop_streaming,
881 .buf_queue = isc_buffer_queue,
882};
883
884static int isc_querycap(struct file *file, void *priv,
885 struct v4l2_capability *cap)
886{
887 struct isc_device *isc = video_drvdata(file);
888
889 strcpy(cap->driver, ATMEL_ISC_NAME);
890 strcpy(cap->card, "Atmel Image Sensor Controller");
891 snprintf(cap->bus_info, sizeof(cap->bus_info),
892 "platform:%s", isc->v4l2_dev.name);
893
894 return 0;
895}
896
897static int isc_enum_fmt_vid_cap(struct file *file, void *priv,
898 struct v4l2_fmtdesc *f)
899{
900 struct isc_device *isc = video_drvdata(file);
901 u32 index = f->index;
902
903 if (index >= isc->num_user_formats)
904 return -EINVAL;
905
906 f->pixelformat = isc->user_formats[index]->fourcc;
907
908 return 0;
909}
910
911static int isc_g_fmt_vid_cap(struct file *file, void *priv,
912 struct v4l2_format *fmt)
913{
914 struct isc_device *isc = video_drvdata(file);
915
916 *fmt = isc->fmt;
917
918 return 0;
919}
920
921static struct isc_format *find_format_by_fourcc(struct isc_device *isc,
922 unsigned int fourcc)
923{
924 unsigned int num_formats = isc->num_user_formats;
925 struct isc_format *fmt;
926 unsigned int i;
927
928 for (i = 0; i < num_formats; i++) {
929 fmt = isc->user_formats[i];
930 if (fmt->fourcc == fourcc)
931 return fmt;
932 }
933
934 return NULL;
935}
936
937static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f,
Songjun Wu93d4a262017-01-24 06:05:57 -0200938 struct isc_format **current_fmt, u32 *code)
Songjun Wu10626742016-08-17 03:05:27 -0300939{
940 struct isc_format *isc_fmt;
941 struct v4l2_pix_format *pixfmt = &f->fmt.pix;
942 struct v4l2_subdev_format format = {
943 .which = V4L2_SUBDEV_FORMAT_TRY,
944 };
Songjun Wu93d4a262017-01-24 06:05:57 -0200945 u32 mbus_code;
Songjun Wu10626742016-08-17 03:05:27 -0300946 int ret;
947
948 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
949 return -EINVAL;
950
951 isc_fmt = find_format_by_fourcc(isc, pixfmt->pixelformat);
952 if (!isc_fmt) {
953 v4l2_warn(&isc->v4l2_dev, "Format 0x%x not found\n",
954 pixfmt->pixelformat);
955 isc_fmt = isc->user_formats[isc->num_user_formats - 1];
956 pixfmt->pixelformat = isc_fmt->fourcc;
957 }
958
959 /* Limit to Atmel ISC hardware capabilities */
960 if (pixfmt->width > ISC_MAX_SUPPORT_WIDTH)
961 pixfmt->width = ISC_MAX_SUPPORT_WIDTH;
962 if (pixfmt->height > ISC_MAX_SUPPORT_HEIGHT)
963 pixfmt->height = ISC_MAX_SUPPORT_HEIGHT;
964
Songjun Wu93d4a262017-01-24 06:05:57 -0200965 if (sensor_is_preferred(isc_fmt))
966 mbus_code = isc_fmt->mbus_code;
967 else
968 mbus_code = isc->raw_fmt->mbus_code;
969
970 v4l2_fill_mbus_format(&format.format, pixfmt, mbus_code);
Songjun Wu10626742016-08-17 03:05:27 -0300971 ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt,
972 isc->current_subdev->config, &format);
973 if (ret < 0)
974 return ret;
975
976 v4l2_fill_pix_format(pixfmt, &format.format);
977
978 pixfmt->field = V4L2_FIELD_NONE;
Songjun Wu93d4a262017-01-24 06:05:57 -0200979 pixfmt->bytesperline = (pixfmt->width * isc_fmt->bpp) >> 3;
Songjun Wu10626742016-08-17 03:05:27 -0300980 pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
981
982 if (current_fmt)
983 *current_fmt = isc_fmt;
984
Songjun Wu93d4a262017-01-24 06:05:57 -0200985 if (code)
986 *code = mbus_code;
987
Songjun Wu10626742016-08-17 03:05:27 -0300988 return 0;
989}
990
991static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f)
992{
993 struct v4l2_subdev_format format = {
994 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
995 };
996 struct isc_format *current_fmt;
Songjun Wu93d4a262017-01-24 06:05:57 -0200997 u32 mbus_code;
Songjun Wu10626742016-08-17 03:05:27 -0300998 int ret;
999
Songjun Wu93d4a262017-01-24 06:05:57 -02001000 ret = isc_try_fmt(isc, f, &current_fmt, &mbus_code);
Songjun Wu10626742016-08-17 03:05:27 -03001001 if (ret)
1002 return ret;
1003
Songjun Wu93d4a262017-01-24 06:05:57 -02001004 v4l2_fill_mbus_format(&format.format, &f->fmt.pix, mbus_code);
Songjun Wu10626742016-08-17 03:05:27 -03001005 ret = v4l2_subdev_call(isc->current_subdev->sd, pad,
1006 set_fmt, NULL, &format);
1007 if (ret < 0)
1008 return ret;
1009
1010 isc->fmt = *f;
1011 isc->current_fmt = current_fmt;
1012
1013 return 0;
1014}
1015
1016static int isc_s_fmt_vid_cap(struct file *file, void *priv,
1017 struct v4l2_format *f)
1018{
1019 struct isc_device *isc = video_drvdata(file);
1020
1021 if (vb2_is_streaming(&isc->vb2_vidq))
1022 return -EBUSY;
1023
1024 return isc_set_fmt(isc, f);
1025}
1026
1027static int isc_try_fmt_vid_cap(struct file *file, void *priv,
1028 struct v4l2_format *f)
1029{
1030 struct isc_device *isc = video_drvdata(file);
1031
Songjun Wu93d4a262017-01-24 06:05:57 -02001032 return isc_try_fmt(isc, f, NULL, NULL);
Songjun Wu10626742016-08-17 03:05:27 -03001033}
1034
1035static int isc_enum_input(struct file *file, void *priv,
1036 struct v4l2_input *inp)
1037{
1038 if (inp->index != 0)
1039 return -EINVAL;
1040
1041 inp->type = V4L2_INPUT_TYPE_CAMERA;
1042 inp->std = 0;
1043 strcpy(inp->name, "Camera");
1044
1045 return 0;
1046}
1047
1048static int isc_g_input(struct file *file, void *priv, unsigned int *i)
1049{
1050 *i = 0;
1051
1052 return 0;
1053}
1054
1055static int isc_s_input(struct file *file, void *priv, unsigned int i)
1056{
1057 if (i > 0)
1058 return -EINVAL;
1059
1060 return 0;
1061}
1062
1063static int isc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
1064{
1065 struct isc_device *isc = video_drvdata(file);
1066
1067 if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1068 return -EINVAL;
1069
1070 return v4l2_subdev_call(isc->current_subdev->sd, video, g_parm, a);
1071}
1072
1073static int isc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
1074{
1075 struct isc_device *isc = video_drvdata(file);
1076
1077 if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1078 return -EINVAL;
1079
1080 return v4l2_subdev_call(isc->current_subdev->sd, video, s_parm, a);
1081}
1082
1083static int isc_enum_framesizes(struct file *file, void *fh,
1084 struct v4l2_frmsizeenum *fsize)
1085{
1086 struct isc_device *isc = video_drvdata(file);
1087 const struct isc_format *isc_fmt;
1088 struct v4l2_subdev_frame_size_enum fse = {
1089 .index = fsize->index,
1090 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
1091 };
1092 int ret;
1093
1094 isc_fmt = find_format_by_fourcc(isc, fsize->pixel_format);
1095 if (!isc_fmt)
1096 return -EINVAL;
1097
Songjun Wu93d4a262017-01-24 06:05:57 -02001098 if (sensor_is_preferred(isc_fmt))
1099 fse.code = isc_fmt->mbus_code;
1100 else
1101 fse.code = isc->raw_fmt->mbus_code;
Songjun Wu10626742016-08-17 03:05:27 -03001102
1103 ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size,
1104 NULL, &fse);
1105 if (ret)
1106 return ret;
1107
1108 fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1109 fsize->discrete.width = fse.max_width;
1110 fsize->discrete.height = fse.max_height;
1111
1112 return 0;
1113}
1114
1115static int isc_enum_frameintervals(struct file *file, void *fh,
1116 struct v4l2_frmivalenum *fival)
1117{
1118 struct isc_device *isc = video_drvdata(file);
1119 const struct isc_format *isc_fmt;
1120 struct v4l2_subdev_frame_interval_enum fie = {
1121 .index = fival->index,
1122 .width = fival->width,
1123 .height = fival->height,
1124 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
1125 };
1126 int ret;
1127
1128 isc_fmt = find_format_by_fourcc(isc, fival->pixel_format);
1129 if (!isc_fmt)
1130 return -EINVAL;
1131
Songjun Wu93d4a262017-01-24 06:05:57 -02001132 if (sensor_is_preferred(isc_fmt))
1133 fie.code = isc_fmt->mbus_code;
1134 else
1135 fie.code = isc->raw_fmt->mbus_code;
Songjun Wu10626742016-08-17 03:05:27 -03001136
1137 ret = v4l2_subdev_call(isc->current_subdev->sd, pad,
1138 enum_frame_interval, NULL, &fie);
1139 if (ret)
1140 return ret;
1141
1142 fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
1143 fival->discrete = fie.interval;
1144
1145 return 0;
1146}
1147
1148static const struct v4l2_ioctl_ops isc_ioctl_ops = {
1149 .vidioc_querycap = isc_querycap,
1150 .vidioc_enum_fmt_vid_cap = isc_enum_fmt_vid_cap,
1151 .vidioc_g_fmt_vid_cap = isc_g_fmt_vid_cap,
1152 .vidioc_s_fmt_vid_cap = isc_s_fmt_vid_cap,
1153 .vidioc_try_fmt_vid_cap = isc_try_fmt_vid_cap,
1154
1155 .vidioc_enum_input = isc_enum_input,
1156 .vidioc_g_input = isc_g_input,
1157 .vidioc_s_input = isc_s_input,
1158
1159 .vidioc_reqbufs = vb2_ioctl_reqbufs,
1160 .vidioc_querybuf = vb2_ioctl_querybuf,
1161 .vidioc_qbuf = vb2_ioctl_qbuf,
1162 .vidioc_expbuf = vb2_ioctl_expbuf,
1163 .vidioc_dqbuf = vb2_ioctl_dqbuf,
1164 .vidioc_create_bufs = vb2_ioctl_create_bufs,
1165 .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
1166 .vidioc_streamon = vb2_ioctl_streamon,
1167 .vidioc_streamoff = vb2_ioctl_streamoff,
1168
1169 .vidioc_g_parm = isc_g_parm,
1170 .vidioc_s_parm = isc_s_parm,
1171 .vidioc_enum_framesizes = isc_enum_framesizes,
1172 .vidioc_enum_frameintervals = isc_enum_frameintervals,
Songjun Wu93d4a262017-01-24 06:05:57 -02001173
1174 .vidioc_log_status = v4l2_ctrl_log_status,
1175 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
1176 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
Songjun Wu10626742016-08-17 03:05:27 -03001177};
1178
1179static int isc_open(struct file *file)
1180{
1181 struct isc_device *isc = video_drvdata(file);
1182 struct v4l2_subdev *sd = isc->current_subdev->sd;
1183 int ret;
1184
1185 if (mutex_lock_interruptible(&isc->lock))
1186 return -ERESTARTSYS;
1187
1188 ret = v4l2_fh_open(file);
1189 if (ret < 0)
1190 goto unlock;
1191
1192 if (!v4l2_fh_is_singular_file(file))
1193 goto unlock;
1194
1195 ret = v4l2_subdev_call(sd, core, s_power, 1);
Songjun Wu4540e0a2016-09-12 04:47:24 -03001196 if (ret < 0 && ret != -ENOIOCTLCMD) {
Songjun Wu10626742016-08-17 03:05:27 -03001197 v4l2_fh_release(file);
Songjun Wu4540e0a2016-09-12 04:47:24 -03001198 goto unlock;
1199 }
1200
1201 ret = isc_set_fmt(isc, &isc->fmt);
1202 if (ret) {
1203 v4l2_subdev_call(sd, core, s_power, 0);
1204 v4l2_fh_release(file);
1205 }
Songjun Wu10626742016-08-17 03:05:27 -03001206
1207unlock:
1208 mutex_unlock(&isc->lock);
1209 return ret;
1210}
1211
1212static int isc_release(struct file *file)
1213{
1214 struct isc_device *isc = video_drvdata(file);
1215 struct v4l2_subdev *sd = isc->current_subdev->sd;
1216 bool fh_singular;
1217 int ret;
1218
1219 mutex_lock(&isc->lock);
1220
1221 fh_singular = v4l2_fh_is_singular_file(file);
1222
1223 ret = _vb2_fop_release(file, NULL);
1224
1225 if (fh_singular)
1226 v4l2_subdev_call(sd, core, s_power, 0);
1227
1228 mutex_unlock(&isc->lock);
1229
1230 return ret;
1231}
1232
1233static const struct v4l2_file_operations isc_fops = {
1234 .owner = THIS_MODULE,
1235 .open = isc_open,
1236 .release = isc_release,
1237 .unlocked_ioctl = video_ioctl2,
1238 .read = vb2_fop_read,
1239 .mmap = vb2_fop_mmap,
1240 .poll = vb2_fop_poll,
1241};
1242
1243static irqreturn_t isc_interrupt(int irq, void *dev_id)
1244{
1245 struct isc_device *isc = (struct isc_device *)dev_id;
1246 struct regmap *regmap = isc->regmap;
1247 u32 isc_intsr, isc_intmask, pending;
1248 irqreturn_t ret = IRQ_NONE;
1249
Songjun Wu10626742016-08-17 03:05:27 -03001250 regmap_read(regmap, ISC_INTSR, &isc_intsr);
1251 regmap_read(regmap, ISC_INTMASK, &isc_intmask);
1252
1253 pending = isc_intsr & isc_intmask;
1254
1255 if (likely(pending & ISC_INT_DDONE)) {
Songjun Wu93d4a262017-01-24 06:05:57 -02001256 spin_lock(&isc->dma_queue_lock);
Songjun Wu10626742016-08-17 03:05:27 -03001257 if (isc->cur_frm) {
1258 struct vb2_v4l2_buffer *vbuf = &isc->cur_frm->vb;
1259 struct vb2_buffer *vb = &vbuf->vb2_buf;
1260
1261 vb->timestamp = ktime_get_ns();
1262 vbuf->sequence = isc->sequence++;
1263 vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
1264 isc->cur_frm = NULL;
1265 }
1266
1267 if (!list_empty(&isc->dma_queue) && !isc->stop) {
1268 isc->cur_frm = list_first_entry(&isc->dma_queue,
1269 struct isc_buffer, list);
1270 list_del(&isc->cur_frm->list);
1271
Songjun Wu93d4a262017-01-24 06:05:57 -02001272 isc_start_dma(isc);
Songjun Wu10626742016-08-17 03:05:27 -03001273 }
1274
1275 if (isc->stop)
1276 complete(&isc->comp);
1277
1278 ret = IRQ_HANDLED;
Songjun Wu93d4a262017-01-24 06:05:57 -02001279 spin_unlock(&isc->dma_queue_lock);
Songjun Wu10626742016-08-17 03:05:27 -03001280 }
1281
Songjun Wu93d4a262017-01-24 06:05:57 -02001282 if (pending & ISC_INT_HISDONE) {
1283 schedule_work(&isc->awb_work);
1284 ret = IRQ_HANDLED;
1285 }
Songjun Wu10626742016-08-17 03:05:27 -03001286
1287 return ret;
1288}
1289
Songjun Wu93d4a262017-01-24 06:05:57 -02001290static void isc_hist_count(struct isc_device *isc)
1291{
1292 struct regmap *regmap = isc->regmap;
1293 struct isc_ctrls *ctrls = &isc->ctrls;
1294 u32 *hist_count = &ctrls->hist_count[ctrls->hist_id];
1295 u32 *hist_entry = &ctrls->hist_entry[0];
1296 u32 i;
1297
1298 regmap_bulk_read(regmap, ISC_HIS_ENTRY, hist_entry, HIST_ENTRIES);
1299
1300 *hist_count = 0;
1301 for (i = 0; i <= HIST_ENTRIES; i++)
1302 *hist_count += i * (*hist_entry++);
1303}
1304
1305static void isc_wb_update(struct isc_ctrls *ctrls)
1306{
1307 u32 *hist_count = &ctrls->hist_count[0];
1308 u64 g_count = (u64)hist_count[ISC_HIS_CFG_MODE_GB] << 9;
1309 u32 hist_r = hist_count[ISC_HIS_CFG_MODE_R];
1310 u32 hist_b = hist_count[ISC_HIS_CFG_MODE_B];
1311
1312 if (hist_r)
1313 ctrls->r_gain = div_u64(g_count, hist_r);
1314
1315 if (hist_b)
1316 ctrls->b_gain = div_u64(g_count, hist_b);
1317}
1318
1319static void isc_awb_work(struct work_struct *w)
1320{
1321 struct isc_device *isc =
1322 container_of(w, struct isc_device, awb_work);
1323 struct regmap *regmap = isc->regmap;
1324 struct isc_ctrls *ctrls = &isc->ctrls;
1325 u32 hist_id = ctrls->hist_id;
1326 u32 baysel;
1327
1328 if (ctrls->hist_stat != HIST_ENABLED)
1329 return;
1330
1331 isc_hist_count(isc);
1332
1333 if (hist_id != ISC_HIS_CFG_MODE_B) {
1334 hist_id++;
1335 } else {
1336 isc_wb_update(ctrls);
1337 hist_id = ISC_HIS_CFG_MODE_R;
1338 }
1339
1340 ctrls->hist_id = hist_id;
1341 baysel = isc->raw_fmt->reg_bay_cfg << ISC_HIS_CFG_BAYSEL_SHIFT;
1342
1343 pm_runtime_get_sync(isc->dev);
1344
1345 regmap_write(regmap, ISC_HIS_CFG, hist_id | baysel | ISC_HIS_CFG_RAR);
1346 isc_update_profile(isc);
1347 regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
1348
1349 pm_runtime_put_sync(isc->dev);
1350}
1351
1352static int isc_s_ctrl(struct v4l2_ctrl *ctrl)
1353{
1354 struct isc_device *isc = container_of(ctrl->handler,
1355 struct isc_device, ctrls.handler);
1356 struct isc_ctrls *ctrls = &isc->ctrls;
1357
1358 switch (ctrl->id) {
1359 case V4L2_CID_BRIGHTNESS:
1360 ctrls->brightness = ctrl->val & ISC_CBC_BRIGHT_MASK;
1361 break;
1362 case V4L2_CID_CONTRAST:
1363 ctrls->contrast = ctrl->val & ISC_CBC_CONTRAST_MASK;
1364 break;
1365 case V4L2_CID_GAMMA:
1366 ctrls->gamma_index = ctrl->val;
1367 break;
1368 case V4L2_CID_AUTO_WHITE_BALANCE:
1369 ctrls->awb = ctrl->val;
1370 if (ctrls->hist_stat != HIST_ENABLED) {
1371 ctrls->r_gain = 0x1 << 9;
1372 ctrls->b_gain = 0x1 << 9;
1373 }
1374 break;
1375 default:
1376 return -EINVAL;
1377 }
1378
1379 return 0;
1380}
1381
1382static const struct v4l2_ctrl_ops isc_ctrl_ops = {
1383 .s_ctrl = isc_s_ctrl,
1384};
1385
1386static int isc_ctrl_init(struct isc_device *isc)
1387{
1388 const struct v4l2_ctrl_ops *ops = &isc_ctrl_ops;
1389 struct isc_ctrls *ctrls = &isc->ctrls;
1390 struct v4l2_ctrl_handler *hdl = &ctrls->handler;
1391 int ret;
1392
1393 ctrls->hist_stat = HIST_INIT;
1394
1395 ret = v4l2_ctrl_handler_init(hdl, 4);
1396 if (ret < 0)
1397 return ret;
1398
1399 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0);
1400 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256);
1401 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 2);
1402 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
1403
1404 v4l2_ctrl_handler_setup(hdl);
1405
1406 return 0;
1407}
1408
1409
Songjun Wu10626742016-08-17 03:05:27 -03001410static int isc_async_bound(struct v4l2_async_notifier *notifier,
1411 struct v4l2_subdev *subdev,
1412 struct v4l2_async_subdev *asd)
1413{
1414 struct isc_device *isc = container_of(notifier->v4l2_dev,
1415 struct isc_device, v4l2_dev);
1416 struct isc_subdev_entity *subdev_entity =
1417 container_of(notifier, struct isc_subdev_entity, notifier);
1418
1419 if (video_is_registered(&isc->video_dev)) {
1420 v4l2_err(&isc->v4l2_dev, "only supports one sub-device.\n");
1421 return -EBUSY;
1422 }
1423
1424 subdev_entity->sd = subdev;
1425
1426 return 0;
1427}
1428
1429static void isc_async_unbind(struct v4l2_async_notifier *notifier,
1430 struct v4l2_subdev *subdev,
1431 struct v4l2_async_subdev *asd)
1432{
1433 struct isc_device *isc = container_of(notifier->v4l2_dev,
1434 struct isc_device, v4l2_dev);
Songjun Wu93d4a262017-01-24 06:05:57 -02001435 cancel_work_sync(&isc->awb_work);
Songjun Wu10626742016-08-17 03:05:27 -03001436 video_unregister_device(&isc->video_dev);
1437 if (isc->current_subdev->config)
1438 v4l2_subdev_free_pad_config(isc->current_subdev->config);
Songjun Wu93d4a262017-01-24 06:05:57 -02001439 v4l2_ctrl_handler_free(&isc->ctrls.handler);
Songjun Wu10626742016-08-17 03:05:27 -03001440}
1441
1442static struct isc_format *find_format_by_code(unsigned int code, int *index)
1443{
1444 struct isc_format *fmt = &isc_formats[0];
1445 unsigned int i;
1446
1447 for (i = 0; i < ARRAY_SIZE(isc_formats); i++) {
1448 if (fmt->mbus_code == code) {
1449 *index = i;
1450 return fmt;
1451 }
1452
1453 fmt++;
1454 }
1455
1456 return NULL;
1457}
1458
1459static int isc_formats_init(struct isc_device *isc)
1460{
1461 struct isc_format *fmt;
1462 struct v4l2_subdev *subdev = isc->current_subdev->sd;
Songjun Wu93d4a262017-01-24 06:05:57 -02001463 unsigned int num_fmts, i, j;
Songjun Wu10626742016-08-17 03:05:27 -03001464 struct v4l2_subdev_mbus_code_enum mbus_code = {
1465 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
1466 };
1467
1468 fmt = &isc_formats[0];
1469 for (i = 0; i < ARRAY_SIZE(isc_formats); i++) {
Songjun Wu93d4a262017-01-24 06:05:57 -02001470 fmt->isc_support = false;
1471 fmt->sd_support = false;
1472
Songjun Wu10626742016-08-17 03:05:27 -03001473 fmt++;
1474 }
1475
1476 while (!v4l2_subdev_call(subdev, pad, enum_mbus_code,
1477 NULL, &mbus_code)) {
1478 mbus_code.index++;
1479 fmt = find_format_by_code(mbus_code.code, &i);
1480 if (!fmt)
1481 continue;
1482
Songjun Wu93d4a262017-01-24 06:05:57 -02001483 fmt->sd_support = true;
1484
1485 if (i <= RAW_FMT_IND_END) {
1486 for (j = ISC_FMT_IND_START; j <= ISC_FMT_IND_END; j++)
1487 isc_formats[j].isc_support = true;
1488
1489 isc->raw_fmt = fmt;
1490 }
1491 }
1492
1493 for (i = 0, num_fmts = 0; i < ARRAY_SIZE(isc_formats); i++) {
1494 if (fmt->isc_support || fmt->sd_support)
1495 num_fmts++;
1496
1497 fmt++;
Songjun Wu10626742016-08-17 03:05:27 -03001498 }
1499
1500 if (!num_fmts)
1501 return -ENXIO;
1502
1503 isc->num_user_formats = num_fmts;
1504 isc->user_formats = devm_kcalloc(isc->dev,
1505 num_fmts, sizeof(struct isc_format *),
1506 GFP_KERNEL);
1507 if (!isc->user_formats) {
1508 v4l2_err(&isc->v4l2_dev, "could not allocate memory\n");
1509 return -ENOMEM;
1510 }
1511
1512 fmt = &isc_formats[0];
1513 for (i = 0, j = 0; i < ARRAY_SIZE(isc_formats); i++) {
Songjun Wu93d4a262017-01-24 06:05:57 -02001514 if (fmt->isc_support || fmt->sd_support)
Songjun Wu10626742016-08-17 03:05:27 -03001515 isc->user_formats[j++] = fmt;
1516
1517 fmt++;
1518 }
1519
1520 return 0;
1521}
1522
1523static int isc_set_default_fmt(struct isc_device *isc)
1524{
1525 struct v4l2_format f = {
1526 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
1527 .fmt.pix = {
1528 .width = VGA_WIDTH,
1529 .height = VGA_HEIGHT,
1530 .field = V4L2_FIELD_NONE,
1531 .pixelformat = isc->user_formats[0]->fourcc,
1532 },
1533 };
Songjun Wu4540e0a2016-09-12 04:47:24 -03001534 int ret;
Songjun Wu10626742016-08-17 03:05:27 -03001535
Songjun Wu93d4a262017-01-24 06:05:57 -02001536 ret = isc_try_fmt(isc, &f, NULL, NULL);
Songjun Wu4540e0a2016-09-12 04:47:24 -03001537 if (ret)
1538 return ret;
1539
1540 isc->current_fmt = isc->user_formats[0];
1541 isc->fmt = f;
1542
1543 return 0;
Songjun Wu10626742016-08-17 03:05:27 -03001544}
1545
1546static int isc_async_complete(struct v4l2_async_notifier *notifier)
1547{
1548 struct isc_device *isc = container_of(notifier->v4l2_dev,
1549 struct isc_device, v4l2_dev);
1550 struct isc_subdev_entity *sd_entity;
1551 struct video_device *vdev = &isc->video_dev;
1552 struct vb2_queue *q = &isc->vb2_vidq;
1553 int ret;
1554
Songjun Wu93d4a262017-01-24 06:05:57 -02001555 ret = v4l2_device_register_subdev_nodes(&isc->v4l2_dev);
1556 if (ret < 0) {
1557 v4l2_err(&isc->v4l2_dev, "Failed to register subdev nodes\n");
1558 return ret;
1559 }
1560
Songjun Wu10626742016-08-17 03:05:27 -03001561 isc->current_subdev = container_of(notifier,
1562 struct isc_subdev_entity, notifier);
1563 sd_entity = isc->current_subdev;
1564
1565 mutex_init(&isc->lock);
1566 init_completion(&isc->comp);
1567
1568 /* Initialize videobuf2 queue */
1569 q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1570 q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
1571 q->drv_priv = isc;
1572 q->buf_struct_size = sizeof(struct isc_buffer);
1573 q->ops = &isc_vb2_ops;
1574 q->mem_ops = &vb2_dma_contig_memops;
1575 q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
1576 q->lock = &isc->lock;
1577 q->min_buffers_needed = 1;
1578 q->dev = isc->dev;
1579
1580 ret = vb2_queue_init(q);
1581 if (ret < 0) {
1582 v4l2_err(&isc->v4l2_dev,
1583 "vb2_queue_init() failed: %d\n", ret);
1584 return ret;
1585 }
1586
1587 /* Init video dma queues */
1588 INIT_LIST_HEAD(&isc->dma_queue);
1589 spin_lock_init(&isc->dma_queue_lock);
1590
1591 sd_entity->config = v4l2_subdev_alloc_pad_config(sd_entity->sd);
1592 if (sd_entity->config == NULL)
1593 return -ENOMEM;
1594
1595 ret = isc_formats_init(isc);
1596 if (ret < 0) {
1597 v4l2_err(&isc->v4l2_dev,
1598 "Init format failed: %d\n", ret);
1599 return ret;
1600 }
1601
Songjun Wu10626742016-08-17 03:05:27 -03001602 ret = isc_set_default_fmt(isc);
1603 if (ret) {
1604 v4l2_err(&isc->v4l2_dev, "Could not set default format\n");
1605 return ret;
1606 }
1607
Songjun Wu93d4a262017-01-24 06:05:57 -02001608 ret = isc_ctrl_init(isc);
1609 if (ret) {
1610 v4l2_err(&isc->v4l2_dev, "Init isc ctrols failed: %d\n", ret);
1611 return ret;
1612 }
1613
1614 INIT_WORK(&isc->awb_work, isc_awb_work);
1615
Songjun Wu10626742016-08-17 03:05:27 -03001616 /* Register video device */
1617 strlcpy(vdev->name, ATMEL_ISC_NAME, sizeof(vdev->name));
1618 vdev->release = video_device_release_empty;
1619 vdev->fops = &isc_fops;
1620 vdev->ioctl_ops = &isc_ioctl_ops;
1621 vdev->v4l2_dev = &isc->v4l2_dev;
1622 vdev->vfl_dir = VFL_DIR_RX;
1623 vdev->queue = q;
1624 vdev->lock = &isc->lock;
Songjun Wu93d4a262017-01-24 06:05:57 -02001625 vdev->ctrl_handler = &isc->ctrls.handler;
Songjun Wu10626742016-08-17 03:05:27 -03001626 vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
1627 video_set_drvdata(vdev, isc);
1628
1629 ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
1630 if (ret < 0) {
1631 v4l2_err(&isc->v4l2_dev,
1632 "video_register_device failed: %d\n", ret);
1633 return ret;
1634 }
1635
1636 return 0;
1637}
1638
1639static void isc_subdev_cleanup(struct isc_device *isc)
1640{
1641 struct isc_subdev_entity *subdev_entity;
1642
1643 list_for_each_entry(subdev_entity, &isc->subdev_entities, list)
1644 v4l2_async_notifier_unregister(&subdev_entity->notifier);
1645
1646 INIT_LIST_HEAD(&isc->subdev_entities);
1647}
1648
1649static int isc_pipeline_init(struct isc_device *isc)
1650{
1651 struct device *dev = isc->dev;
1652 struct regmap *regmap = isc->regmap;
1653 struct regmap_field *regs;
1654 unsigned int i;
1655
1656 /* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */
1657 const struct reg_field regfields[ISC_PIPE_LINE_NODE_NUM] = {
1658 REG_FIELD(ISC_WB_CTRL, 0, 0),
1659 REG_FIELD(ISC_CFA_CTRL, 0, 0),
1660 REG_FIELD(ISC_CC_CTRL, 0, 0),
1661 REG_FIELD(ISC_GAM_CTRL, 0, 0),
1662 REG_FIELD(ISC_GAM_CTRL, 1, 1),
1663 REG_FIELD(ISC_GAM_CTRL, 2, 2),
1664 REG_FIELD(ISC_GAM_CTRL, 3, 3),
1665 REG_FIELD(ISC_CSC_CTRL, 0, 0),
1666 REG_FIELD(ISC_CBC_CTRL, 0, 0),
1667 REG_FIELD(ISC_SUB422_CTRL, 0, 0),
1668 REG_FIELD(ISC_SUB420_CTRL, 0, 0),
1669 };
1670
1671 for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) {
1672 regs = devm_regmap_field_alloc(dev, regmap, regfields[i]);
1673 if (IS_ERR(regs))
1674 return PTR_ERR(regs);
1675
1676 isc->pipeline[i] = regs;
1677 }
1678
1679 return 0;
1680}
1681
1682static int isc_parse_dt(struct device *dev, struct isc_device *isc)
1683{
1684 struct device_node *np = dev->of_node;
1685 struct device_node *epn = NULL, *rem;
1686 struct v4l2_of_endpoint v4l2_epn;
1687 struct isc_subdev_entity *subdev_entity;
1688 unsigned int flags;
1689 int ret;
1690
1691 INIT_LIST_HEAD(&isc->subdev_entities);
1692
1693 for (; ;) {
1694 epn = of_graph_get_next_endpoint(np, epn);
1695 if (!epn)
1696 break;
1697
1698 rem = of_graph_get_remote_port_parent(epn);
1699 if (!rem) {
1700 dev_notice(dev, "Remote device at %s not found\n",
1701 of_node_full_name(epn));
1702 continue;
1703 }
1704
1705 ret = v4l2_of_parse_endpoint(epn, &v4l2_epn);
1706 if (ret) {
1707 of_node_put(rem);
1708 ret = -EINVAL;
1709 dev_err(dev, "Could not parse the endpoint\n");
1710 break;
1711 }
1712
1713 subdev_entity = devm_kzalloc(dev,
1714 sizeof(*subdev_entity), GFP_KERNEL);
1715 if (subdev_entity == NULL) {
1716 of_node_put(rem);
1717 ret = -ENOMEM;
1718 break;
1719 }
1720
1721 subdev_entity->asd = devm_kzalloc(dev,
1722 sizeof(*subdev_entity->asd), GFP_KERNEL);
1723 if (subdev_entity->asd == NULL) {
1724 of_node_put(rem);
1725 ret = -ENOMEM;
1726 break;
1727 }
1728
1729 flags = v4l2_epn.bus.parallel.flags;
1730
1731 if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
1732 subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
1733
1734 if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
1735 subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
1736
1737 if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
1738 subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
1739
1740 subdev_entity->asd->match_type = V4L2_ASYNC_MATCH_OF;
1741 subdev_entity->asd->match.of.node = rem;
1742 list_add_tail(&subdev_entity->list, &isc->subdev_entities);
1743 }
1744
1745 of_node_put(epn);
1746 return ret;
1747}
1748
1749/* regmap configuration */
1750#define ATMEL_ISC_REG_MAX 0xbfc
1751static const struct regmap_config isc_regmap_config = {
1752 .reg_bits = 32,
1753 .reg_stride = 4,
1754 .val_bits = 32,
1755 .max_register = ATMEL_ISC_REG_MAX,
1756};
1757
1758static int atmel_isc_probe(struct platform_device *pdev)
1759{
1760 struct device *dev = &pdev->dev;
1761 struct isc_device *isc;
1762 struct resource *res;
1763 void __iomem *io_base;
1764 struct isc_subdev_entity *subdev_entity;
1765 int irq;
1766 int ret;
1767
1768 isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
1769 if (!isc)
1770 return -ENOMEM;
1771
1772 platform_set_drvdata(pdev, isc);
1773 isc->dev = dev;
1774
1775 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1776 io_base = devm_ioremap_resource(dev, res);
1777 if (IS_ERR(io_base))
1778 return PTR_ERR(io_base);
1779
1780 isc->regmap = devm_regmap_init_mmio(dev, io_base, &isc_regmap_config);
1781 if (IS_ERR(isc->regmap)) {
1782 ret = PTR_ERR(isc->regmap);
1783 dev_err(dev, "failed to init register map: %d\n", ret);
1784 return ret;
1785 }
1786
1787 irq = platform_get_irq(pdev, 0);
Songjun Wu846c4a72016-08-24 05:49:28 -03001788 if (irq < 0) {
Songjun Wu10626742016-08-17 03:05:27 -03001789 ret = irq;
1790 dev_err(dev, "failed to get irq: %d\n", ret);
1791 return ret;
1792 }
1793
1794 ret = devm_request_irq(dev, irq, isc_interrupt, 0,
1795 ATMEL_ISC_NAME, isc);
1796 if (ret < 0) {
1797 dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
1798 irq, ret);
1799 return ret;
1800 }
1801
1802 ret = isc_pipeline_init(isc);
1803 if (ret)
1804 return ret;
1805
1806 isc->hclock = devm_clk_get(dev, "hclock");
1807 if (IS_ERR(isc->hclock)) {
1808 ret = PTR_ERR(isc->hclock);
1809 dev_err(dev, "failed to get hclock: %d\n", ret);
1810 return ret;
1811 }
1812
1813 ret = isc_clk_init(isc);
1814 if (ret) {
1815 dev_err(dev, "failed to init isc clock: %d\n", ret);
1816 goto clean_isc_clk;
1817 }
1818
1819 isc->ispck = isc->isc_clks[ISC_ISPCK].clk;
1820
1821 /* ispck should be greater or equal to hclock */
1822 ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock));
1823 if (ret) {
1824 dev_err(dev, "failed to set ispck rate: %d\n", ret);
1825 goto clean_isc_clk;
1826 }
1827
1828 ret = v4l2_device_register(dev, &isc->v4l2_dev);
1829 if (ret) {
1830 dev_err(dev, "unable to register v4l2 device.\n");
1831 goto clean_isc_clk;
1832 }
1833
1834 ret = isc_parse_dt(dev, isc);
1835 if (ret) {
1836 dev_err(dev, "fail to parse device tree\n");
1837 goto unregister_v4l2_device;
1838 }
1839
1840 if (list_empty(&isc->subdev_entities)) {
1841 dev_err(dev, "no subdev found\n");
Wei Yongjune04e5812016-11-11 11:40:20 -02001842 ret = -ENODEV;
Songjun Wu10626742016-08-17 03:05:27 -03001843 goto unregister_v4l2_device;
1844 }
1845
1846 list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
1847 subdev_entity->notifier.subdevs = &subdev_entity->asd;
1848 subdev_entity->notifier.num_subdevs = 1;
1849 subdev_entity->notifier.bound = isc_async_bound;
1850 subdev_entity->notifier.unbind = isc_async_unbind;
1851 subdev_entity->notifier.complete = isc_async_complete;
1852
1853 ret = v4l2_async_notifier_register(&isc->v4l2_dev,
1854 &subdev_entity->notifier);
1855 if (ret) {
1856 dev_err(dev, "fail to register async notifier\n");
1857 goto cleanup_subdev;
1858 }
1859
1860 if (video_is_registered(&isc->video_dev))
1861 break;
1862 }
1863
1864 pm_runtime_enable(dev);
1865
1866 return 0;
1867
1868cleanup_subdev:
1869 isc_subdev_cleanup(isc);
1870
1871unregister_v4l2_device:
1872 v4l2_device_unregister(&isc->v4l2_dev);
1873
1874clean_isc_clk:
1875 isc_clk_cleanup(isc);
1876
1877 return ret;
1878}
1879
1880static int atmel_isc_remove(struct platform_device *pdev)
1881{
1882 struct isc_device *isc = platform_get_drvdata(pdev);
1883
1884 pm_runtime_disable(&pdev->dev);
1885
1886 isc_subdev_cleanup(isc);
1887
1888 v4l2_device_unregister(&isc->v4l2_dev);
1889
1890 isc_clk_cleanup(isc);
1891
1892 return 0;
1893}
1894
Arnd Bergmannb7e50632016-09-12 12:32:58 -03001895static int __maybe_unused isc_runtime_suspend(struct device *dev)
Songjun Wu10626742016-08-17 03:05:27 -03001896{
1897 struct isc_device *isc = dev_get_drvdata(dev);
1898
1899 clk_disable_unprepare(isc->ispck);
1900 clk_disable_unprepare(isc->hclock);
1901
1902 return 0;
1903}
1904
Arnd Bergmannb7e50632016-09-12 12:32:58 -03001905static int __maybe_unused isc_runtime_resume(struct device *dev)
Songjun Wu10626742016-08-17 03:05:27 -03001906{
1907 struct isc_device *isc = dev_get_drvdata(dev);
1908 int ret;
1909
1910 ret = clk_prepare_enable(isc->hclock);
1911 if (ret)
1912 return ret;
1913
1914 return clk_prepare_enable(isc->ispck);
1915}
1916
1917static const struct dev_pm_ops atmel_isc_dev_pm_ops = {
1918 SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL)
1919};
1920
1921static const struct of_device_id atmel_isc_of_match[] = {
1922 { .compatible = "atmel,sama5d2-isc" },
1923 { }
1924};
1925MODULE_DEVICE_TABLE(of, atmel_isc_of_match);
1926
1927static struct platform_driver atmel_isc_driver = {
1928 .probe = atmel_isc_probe,
1929 .remove = atmel_isc_remove,
1930 .driver = {
1931 .name = ATMEL_ISC_NAME,
1932 .pm = &atmel_isc_dev_pm_ops,
1933 .of_match_table = of_match_ptr(atmel_isc_of_match),
1934 },
1935};
1936
1937module_platform_driver(atmel_isc_driver);
1938
1939MODULE_AUTHOR("Songjun Wu <songjun.wu@microchip.com>");
1940MODULE_DESCRIPTION("The V4L2 driver for Atmel-ISC");
1941MODULE_LICENSE("GPL v2");
1942MODULE_SUPPORTED_DEVICE("video");