diff options
Diffstat (limited to 'drivers')
73 files changed, 41536 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-tegra-vi.c b/drivers/i2c/busses/i2c-tegra-vi.c new file mode 100644 index 000000000..4c2645504 --- /dev/null +++ b/drivers/i2c/busses/i2c-tegra-vi.c | |||
@@ -0,0 +1,2238 @@ | |||
1 | /* | ||
2 | * drivers/i2c/busses/i2c-tegra-vi.c | ||
3 | * | ||
4 | * Copyright (C) 2010 Google, Inc. | ||
5 | * Author: Colin Cross <ccross@android.com> | ||
6 | * | ||
7 | * Copyright (C) 2015 Google, Inc. | ||
8 | * Author: Tomasz Figa <tfiga@chromium.org> | ||
9 | * | ||
10 | * Copyright (C) 2010-2016 NVIDIA Corporation. All rights reserved. | ||
11 | * | ||
12 | * This software is licensed under the terms of the GNU General Public | ||
13 | * License version 2, as published by the Free Software Foundation, and | ||
14 | * may be copied, distributed, and modified under those terms. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/clk.h> | ||
27 | #include <linux/err.h> | ||
28 | #include <linux/i2c.h> | ||
29 | #include <linux/io.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/delay.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/of_device.h> | ||
34 | #include <linux/module.h> | ||
35 | #include <linux/regulator/consumer.h> | ||
36 | #include <linux/reset.h> | ||
37 | #include <linux/iopoll.h> | ||
38 | #include <linux/of_gpio.h> | ||
39 | #include <linux/i2c-algo-bit.h> | ||
40 | #include <linux/i2c-gpio.h> | ||
41 | #include <linux/tegra_prod.h> | ||
42 | #include <linux/dmaengine.h> | ||
43 | #include <linux/dma-mapping.h> | ||
44 | #include <linux/dmapool.h> | ||
45 | #include <linux/pm_runtime.h> | ||
46 | #include <soc/tegra/tegra_powergate.h> | ||
47 | #include <asm/unaligned.h> | ||
48 | |||
49 | #define TEGRA_I2C_TIMEOUT (msecs_to_jiffies(1000)) | ||
50 | #define BYTES_PER_FIFO_WORD 4 | ||
51 | |||
52 | #define VI_I2C_REG_SHIFT 2 | ||
53 | #define VI_I2C_REG_OFFSET 0xc00 | ||
54 | |||
55 | #define I2C_CNFG 0x000 | ||
56 | #define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12 | ||
57 | #define I2C_CNFG_PACKET_MODE_EN (1<<10) | ||
58 | #define I2C_CNFG_NEW_MASTER_FSM (1<<11) | ||
59 | #define I2C_CNFG_MULTI_MASTER_MODE (1<<17) | ||
60 | #define I2C_STATUS 0x01C | ||
61 | #define I2C_SL_CNFG 0x020 | ||
62 | #define I2C_SL_CNFG_NACK (1<<1) | ||
63 | #define I2C_SL_CNFG_NEWSL (1<<2) | ||
64 | #define I2C_SL_ADDR1 0x02c | ||
65 | #define I2C_SL_ADDR2 0x030 | ||
66 | #define I2C_TLOW_SEXT 0x034 | ||
67 | #define I2C_TX_FIFO 0x050 | ||
68 | #define I2C_RX_FIFO 0x054 | ||
69 | #define I2C_PACKET_TRANSFER_STATUS 0x058 | ||
70 | #define I2C_FIFO_CONTROL 0x05c | ||
71 | #define I2C_FIFO_CONTROL_TX_FLUSH (1<<1) | ||
72 | #define I2C_FIFO_CONTROL_RX_FLUSH (1<<0) | ||
73 | #define I2C_FIFO_CONTROL_RX_TRIG_1 (0<<2) | ||
74 | #define I2C_FIFO_CONTROL_RX_TRIG_4 (3<<2) | ||
75 | #define I2C_FIFO_CONTROL_RX_TRIG_8 (7<<2) | ||
76 | #define I2C_FIFO_CONTROL_TX_TRIG_1 (0<<5) | ||
77 | #define I2C_FIFO_CONTROL_TX_TRIG_4 (3<<5) | ||
78 | #define I2C_FIFO_CONTROL_TX_TRIG_8 (7<<5) | ||
79 | #define I2C_FIFO_CONTROL_TX_TRIG_SHIFT 5 | ||
80 | #define I2C_FIFO_CONTROL_RX_TRIG_SHIFT 2 | ||
81 | #define I2C_FIFO_STATUS 0x060 | ||
82 | #define I2C_FIFO_STATUS_TX_MASK 0xF0 | ||
83 | #define I2C_FIFO_STATUS_TX_SHIFT 4 | ||
84 | #define I2C_FIFO_STATUS_RX_MASK 0x0F | ||
85 | #define I2C_FIFO_STATUS_RX_SHIFT 0 | ||
86 | #define I2C_INT_MASK 0x064 | ||
87 | #define I2C_INT_STATUS 0x068 | ||
88 | #define I2C_INT_BUS_CLEAR_DONE (1<<11) | ||
89 | #define I2C_INT_PACKET_XFER_COMPLETE (1<<7) | ||
90 | #define I2C_INT_ALL_PACKETS_XFER_COMPLETE (1<<6) | ||
91 | #define I2C_INT_TX_FIFO_OVERFLOW (1<<5) | ||
92 | #define I2C_INT_RX_FIFO_UNDERFLOW (1<<4) | ||
93 | #define I2C_INT_NO_ACK (1<<3) | ||
94 | #define I2C_INT_ARBITRATION_LOST (1<<2) | ||
95 | #define I2C_INT_TX_FIFO_DATA_REQ (1<<1) | ||
96 | #define I2C_INT_RX_FIFO_DATA_REQ (1<<0) | ||
97 | #define I2C_CLK_DIVISOR 0x06c | ||
98 | #define I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT 16 | ||
99 | #define I2C_CLK_MULTIPLIER_STD_FAST_MODE 8 | ||
100 | #define I2C_CLK_DIVISOR_HS_MODE_MASK 0xFFFF | ||
101 | |||
102 | #define I2C_BUS_CLEAR_CNFG 0x084 | ||
103 | #define I2C_TLOW 2 | ||
104 | #define I2C_TLOW_SHIFT 0 | ||
105 | #define I2C_THIGH 4 | ||
106 | #define I2C_THIGH_SHIFT 8 | ||
107 | #define I2C_INTERFACE_TIMING_1 0x098 | ||
108 | #define I2C_HS_INTERFACE_TIMING_0 0x09C | ||
109 | #define I2C_HS_INTERFACE_TIMING_1 0x0A0 | ||
110 | |||
111 | #define DVC_CTRL_REG1 0x000 | ||
112 | #define DVC_CTRL_REG1_INTR_EN (1<<10) | ||
113 | #define DVC_CTRL_REG2 0x004 | ||
114 | #define DVC_CTRL_REG3 0x008 | ||
115 | #define DVC_CTRL_REG3_SW_PROG (1<<26) | ||
116 | #define DVC_CTRL_REG3_I2C_DONE_INTR_EN (1<<30) | ||
117 | #define DVC_STATUS 0x00c | ||
118 | #define DVC_STATUS_I2C_DONE_INTR (1<<30) | ||
119 | |||
120 | #define I2C_ERR_NONE 0x00 | ||
121 | #define I2C_ERR_NO_ACK 0x01 | ||
122 | #define I2C_ERR_ARBITRATION_LOST 0x02 | ||
123 | #define I2C_ERR_UNKNOWN_INTERRUPT 0x04 | ||
124 | |||
125 | #define PACKET_HEADER0_HEADER_SIZE_SHIFT 28 | ||
126 | #define PACKET_HEADER0_PACKET_ID_SHIFT 16 | ||
127 | #define PACKET_HEADER0_CONT_ID_SHIFT 12 | ||
128 | #define PACKET_HEADER0_CONT_ID_MASK 0xF | ||
129 | #define PACKET_HEADER0_PROTOCOL_I2C (1<<4) | ||
130 | |||
131 | #define I2C_HEADER_HIGHSPEED_MODE (1<<22) | ||
132 | #define I2C_HEADER_CONT_ON_NAK (1<<21) | ||
133 | #define I2C_HEADER_SEND_START_BYTE (1<<20) | ||
134 | #define I2C_HEADER_READ (1<<19) | ||
135 | #define I2C_HEADER_10BIT_ADDR (1<<18) | ||
136 | #define I2C_HEADER_IE_ENABLE (1<<17) | ||
137 | #define I2C_HEADER_REPEAT_START (1<<16) | ||
138 | #define I2C_HEADER_CONTINUE_XFER (1<<15) | ||
139 | #define I2C_HEADER_MASTER_ADDR_SHIFT 12 | ||
140 | #define I2C_HEADER_SLAVE_ADDR_SHIFT 1 | ||
141 | |||
142 | #define I2C_BUS_CLEAR_CNFG 0x084 | ||
143 | #define I2C_BC_SCLK_THRESHOLD (9<<16) | ||
144 | #define I2C_BC_STOP_COND (1<<2) | ||
145 | #define I2C_BC_TERMINATE (1<<1) | ||
146 | #define I2C_BC_ENABLE (1<<0) | ||
147 | |||
148 | #define I2C_BUS_CLEAR_STATUS 0x088 | ||
149 | #define I2C_BC_STATUS (1<<0) | ||
150 | |||
151 | #define I2C_CONFIG_LOAD 0x08C | ||
152 | #define I2C_MSTR_CONFIG_LOAD (1 << 0) | ||
153 | #define I2C_SLV_CONFIG_LOAD (1 << 1) | ||
154 | #define I2C_TIMEOUT_CONFIG_LOAD (1 << 2) | ||
155 | |||
156 | #define I2C_CLKEN_OVERRIDE 0x090 | ||
157 | #define I2C_MST_CORE_CLKEN_OVR (1 << 0) | ||
158 | |||
159 | #define I2C_INTERFACE_TIMING_0 0x94 | ||
160 | #define I2C_TLOW_MASK 0x3F | ||
161 | #define I2C_THIGH_SHIFT 8 | ||
162 | #define I2C_THIGH_MASK (0x3F << I2C_THIGH_SHIFT) | ||
163 | |||
164 | #define I2C_MASTER_RESET_CONTROL 0x0A8 | ||
165 | #define I2C_CMD_ADDR0 0x004 | ||
166 | #define I2C_CMD_ADDR1 0x008 | ||
167 | #define I2C_CMD_DATA1 0x00C | ||
168 | #define I2C_CMD_DATA2 0x010 | ||
169 | #define I2C_DEBUG_CONTROL 0x0A4 | ||
170 | #define I2C_TLOW_SEXT 0x034 | ||
171 | #define I2C_INTERRUPT_SET_REGISTER 0x074 | ||
172 | |||
173 | #define I2C_MAX_TRANSFER_LEN 4096 | ||
174 | #define I2C_CONFIG_LOAD_TIMEOUT 1000000 | ||
175 | |||
176 | /* Define speed modes */ | ||
177 | #define I2C_STANDARD_MODE 100000 | ||
178 | #define I2C_FAST_MODE 400000 | ||
179 | #define I2C_FAST_MODE_PLUS 1000000 | ||
180 | #define I2C_HS_MODE 3500000 | ||
181 | |||
182 | /* Max DMA buffer size = max packet transfer length + size of pkt header */ | ||
183 | #define I2C_DMA_MAX_BUF_LEN (I2C_MAX_TRANSFER_LEN + 12) | ||
184 | #define DATA_DMA_DIR_TX (1 << 0) | ||
185 | #define DATA_DMA_DIR_RX (1 << 1) | ||
186 | |||
187 | /* Upto I2C_PIO_MODE_MAX_LEN bytes, controller will use PIO mode, | ||
188 | * above this, controller will use DMA to fill FIFO. | ||
189 | * Here MAX PIO len is 20 bytes excluding packet header | ||
190 | */ | ||
191 | #define I2C_PIO_MODE_MAX_LEN (20) | ||
192 | |||
193 | /* Packet header size in words */ | ||
194 | #define I2C_PACKET_HEADER_SIZE (3) | ||
195 | |||
196 | /* | ||
197 | * msg_end_type: The bus control which need to be send at end of transfer. | ||
198 | * @MSG_END_STOP: Send stop pulse at end of transfer. | ||
199 | * @MSG_END_REPEAT_START: Send repeat start at end of transfer. | ||
200 | * @MSG_END_CONTINUE: The following on message is coming and so do not send | ||
201 | * stop or repeat start. | ||
202 | */ | ||
203 | enum msg_end_type { | ||
204 | MSG_END_STOP, | ||
205 | MSG_END_REPEAT_START, | ||
206 | MSG_END_CONTINUE, | ||
207 | }; | ||
208 | |||
209 | /** | ||
210 | * struct tegra_i2c_hw_feature : Different HW support on Tegra | ||
211 | * @has_continue_xfer_support: Continue transfer supports. | ||
212 | * @has_per_pkt_xfer_complete_irq: Has enable/disable capability for transfer | ||
213 | * complete interrupt per packet basis. | ||
214 | * @has_single_clk_source: The i2c controller has single clock source. Tegra30 | ||
215 | * and earlier Socs has two clock sources i.e. div-clk and | ||
216 | * fast-clk. | ||
217 | * @has_config_load_reg: Has the config load register to load the new | ||
218 | * configuration. | ||
219 | * @has_regulator: Controller requires extrnal regulator to be powered on | ||
220 | * during transfers. | ||
221 | * @has_powergate: Controller is located inside a powergate partition. | ||
222 | * @is_vi: Identifies the VI i2c controller, has a different register layout, | ||
223 | * and needs more clocks. | ||
224 | * @powergate: Powergate partition ID, if applicable. | ||
225 | * @clk_divisor_hs_mode: Clock divisor in HS mode. | ||
226 | * @clk_divisor_std_fast_mode: Clock divisor in standard/fast mode. It is | ||
227 | * applicable if there is no fast clock source i.e. single clock | ||
228 | * source. | ||
229 | */ | ||
230 | |||
231 | struct tegra_i2c_hw_feature { | ||
232 | bool has_continue_xfer_support; | ||
233 | bool has_per_pkt_xfer_complete_irq; | ||
234 | bool has_single_clk_source; | ||
235 | bool has_config_load_reg; | ||
236 | int clk_divisor_hs_mode; | ||
237 | int clk_multiplier_hs_mode; | ||
238 | int clk_divisor_std_fast_mode; | ||
239 | u16 clk_divisor_fast_plus_mode; | ||
240 | bool has_multi_master_mode; | ||
241 | bool has_slcg_override_reg; | ||
242 | bool has_sw_reset_reg; | ||
243 | bool has_hw_arb_support; | ||
244 | bool has_reg_write_buffering; | ||
245 | bool has_slcg_support; | ||
246 | bool has_regulator; | ||
247 | bool has_powergate; | ||
248 | bool is_vi; | ||
249 | int powergate_id; | ||
250 | }; | ||
251 | |||
252 | /** | ||
253 | * struct tegra_i2c_dev - per device i2c context | ||
254 | * @dev: device reference for power management | ||
255 | * @hw: Tegra i2c hw feature. | ||
256 | * @adapter: core i2c layer adapter information | ||
257 | * @div_clk: clock reference for div clock of i2c controller. | ||
258 | * @fast_clk: clock reference for fast clock of i2c controller. | ||
259 | * @base: ioremapped registers cookie | ||
260 | * @cont_id: i2c controller id, used for for packet header | ||
261 | * @irq: irq number of transfer complete interrupt | ||
262 | * @is_dvc: identifies the DVC i2c controller, has a different register layout | ||
263 | * @msg_complete: transfer completion notifier | ||
264 | * @msg_err: error code for completed message | ||
265 | * @msg_buf: pointer to current message data | ||
266 | * @msg_buf_remaining: size of unsent data in the message buffer | ||
267 | * @msg_read: identifies read transfers | ||
268 | * @bus_clk_rate: current i2c bus clock rate | ||
269 | * @is_suspended: prevents i2c controller accesses after suspend is called | ||
270 | */ | ||
271 | struct tegra_i2c_dev { | ||
272 | struct device *dev; | ||
273 | const struct tegra_i2c_hw_feature *hw; | ||
274 | struct i2c_adapter adapter; | ||
275 | struct clk *div_clk; | ||
276 | struct clk *fast_clk; | ||
277 | struct reset_control *rst; | ||
278 | void __iomem *base; | ||
279 | phys_addr_t phys_addr; | ||
280 | int cont_id; | ||
281 | int irq; | ||
282 | bool irq_disabled; | ||
283 | int is_dvc; | ||
284 | struct completion msg_complete; | ||
285 | int msg_add; | ||
286 | int msg_err; | ||
287 | u8 *msg_buf; | ||
288 | size_t msg_buf_remaining; | ||
289 | int msg_read; | ||
290 | u32 bus_clk_rate; | ||
291 | u16 clk_divisor_non_hs_mode; | ||
292 | bool is_suspended; | ||
293 | bool is_multimaster_mode; | ||
294 | bool is_periph_reset_done; | ||
295 | spinlock_t xfer_lock; | ||
296 | struct i2c_bus_recovery_info bri; | ||
297 | int scl_gpio; | ||
298 | int sda_gpio; | ||
299 | struct i2c_algo_bit_data bit_data; | ||
300 | const struct i2c_algorithm *bit_algo; | ||
301 | bool bit_banging_xfer_after_shutdown; | ||
302 | bool is_shutdown; | ||
303 | u32 low_clock_count; | ||
304 | u32 high_clock_count; | ||
305 | struct tegra_prod *prod_list; | ||
306 | int clk_divisor_hs_mode; | ||
307 | u16 hs_master_code; | ||
308 | struct dma_async_tx_descriptor *rx_dma_desc; | ||
309 | struct dma_chan *rx_dma_chan; | ||
310 | u32 *rx_dma_buf; | ||
311 | dma_addr_t rx_dma_phys; | ||
312 | struct dma_async_tx_descriptor *tx_dma_desc; | ||
313 | struct dma_chan *tx_dma_chan; | ||
314 | u32 *tx_dma_buf; | ||
315 | dma_addr_t tx_dma_phys; | ||
316 | unsigned dma_buf_size; | ||
317 | bool is_curr_dma_xfer; | ||
318 | struct completion rx_dma_complete; | ||
319 | struct completion tx_dma_complete; | ||
320 | int curr_direction; | ||
321 | int rx_dma_len; | ||
322 | dma_cookie_t rx_cookie; | ||
323 | bool disable_dma_mode; | ||
324 | bool is_clkon_always; | ||
325 | struct clk *slow_clk; | ||
326 | struct clk *host1x_clk; | ||
327 | struct regulator *reg; | ||
328 | }; | ||
329 | |||
330 | static void dvc_writel(struct tegra_i2c_dev *i2c_dev, | ||
331 | u32 val, unsigned long reg) | ||
332 | { | ||
333 | writel(val, i2c_dev->base + reg); | ||
334 | } | ||
335 | |||
336 | static u32 dvc_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg) | ||
337 | { | ||
338 | return readl(i2c_dev->base + reg); | ||
339 | } | ||
340 | |||
341 | /* | ||
342 | * i2c_writel and i2c_readl will offset the register if necessary to talk | ||
343 | * to the I2C block inside the DVC block | ||
344 | */ | ||
345 | static unsigned long tegra_i2c_reg_addr(struct tegra_i2c_dev *i2c_dev, | ||
346 | unsigned long reg) | ||
347 | { | ||
348 | if (i2c_dev->is_dvc) | ||
349 | reg += (reg >= I2C_TX_FIFO) ? 0x10 : 0x40; | ||
350 | else if (i2c_dev->hw->is_vi) | ||
351 | reg = VI_I2C_REG_OFFSET + (reg << VI_I2C_REG_SHIFT); | ||
352 | return reg; | ||
353 | } | ||
354 | |||
355 | static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val, | ||
356 | unsigned long reg) | ||
357 | { | ||
358 | writel(val, i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg)); | ||
359 | |||
360 | /* Read back register to make sure that register writes completed */ | ||
361 | if (i2c_dev->hw->has_reg_write_buffering) { | ||
362 | if (reg != I2C_TX_FIFO) | ||
363 | readl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg)); | ||
364 | } | ||
365 | } | ||
366 | |||
367 | static u32 i2c_readl(struct tegra_i2c_dev *i2c_dev, unsigned long reg) | ||
368 | { | ||
369 | return readl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg)); | ||
370 | } | ||
371 | |||
372 | static void i2c_writesl(struct tegra_i2c_dev *i2c_dev, void *data, | ||
373 | unsigned long reg, int len) | ||
374 | { | ||
375 | writesl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len); | ||
376 | } | ||
377 | |||
378 | static void i2c_readsl(struct tegra_i2c_dev *i2c_dev, void *data, | ||
379 | unsigned long reg, int len) | ||
380 | { | ||
381 | readsl(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg), data, len); | ||
382 | } | ||
383 | |||
384 | static inline void tegra_i2c_gpio_setscl(void *data, int state) | ||
385 | { | ||
386 | struct tegra_i2c_dev *i2c_dev = data; | ||
387 | |||
388 | gpio_set_value(i2c_dev->scl_gpio, state); | ||
389 | } | ||
390 | |||
391 | static inline int tegra_i2c_gpio_getscl(void *data) | ||
392 | { | ||
393 | struct tegra_i2c_dev *i2c_dev = data; | ||
394 | |||
395 | return gpio_get_value(i2c_dev->scl_gpio); | ||
396 | } | ||
397 | |||
398 | static inline void tegra_i2c_gpio_setsda(void *data, int state) | ||
399 | { | ||
400 | struct tegra_i2c_dev *i2c_dev = data; | ||
401 | |||
402 | gpio_set_value(i2c_dev->sda_gpio, state); | ||
403 | } | ||
404 | |||
405 | static inline int tegra_i2c_gpio_getsda(void *data) | ||
406 | { | ||
407 | struct tegra_i2c_dev *i2c_dev = data; | ||
408 | |||
409 | return gpio_get_value(i2c_dev->sda_gpio); | ||
410 | } | ||
411 | |||
412 | static int tegra_i2c_gpio_request(struct tegra_i2c_dev *i2c_dev) | ||
413 | { | ||
414 | int ret; | ||
415 | |||
416 | ret = gpio_request_one(i2c_dev->scl_gpio, | ||
417 | GPIOF_OUT_INIT_HIGH | GPIOF_OPEN_DRAIN, | ||
418 | "i2c-gpio-scl"); | ||
419 | if (ret < 0) { | ||
420 | dev_err(i2c_dev->dev, "GPIO request for gpio %d failed %d\n", | ||
421 | i2c_dev->scl_gpio, ret); | ||
422 | return ret; | ||
423 | } | ||
424 | |||
425 | ret = gpio_request_one(i2c_dev->sda_gpio, | ||
426 | GPIOF_OUT_INIT_HIGH | GPIOF_OPEN_DRAIN, | ||
427 | "i2c-gpio-sda"); | ||
428 | if (ret < 0) { | ||
429 | dev_err(i2c_dev->dev, "GPIO request for gpio %d failed %d\n", | ||
430 | i2c_dev->sda_gpio, ret); | ||
431 | gpio_free(i2c_dev->scl_gpio); | ||
432 | return ret; | ||
433 | } | ||
434 | return ret; | ||
435 | } | ||
436 | |||
437 | static void tegra_i2c_gpio_free(struct tegra_i2c_dev *i2c_dev) | ||
438 | { | ||
439 | gpio_free(i2c_dev->scl_gpio); | ||
440 | gpio_free(i2c_dev->sda_gpio); | ||
441 | } | ||
442 | |||
443 | static int tegra_i2c_gpio_xfer(struct i2c_adapter *adap, | ||
444 | struct i2c_msg msgs[], int num) | ||
445 | { | ||
446 | struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap); | ||
447 | int ret; | ||
448 | |||
449 | ret = tegra_i2c_gpio_request(i2c_dev); | ||
450 | if (ret < 0) | ||
451 | return ret; | ||
452 | |||
453 | ret = i2c_dev->bit_algo->master_xfer(adap, msgs, num); | ||
454 | if (ret < 0) | ||
455 | dev_err(i2c_dev->dev, "i2c-bit-algo xfer failed %d\n", ret); | ||
456 | |||
457 | tegra_i2c_gpio_free(i2c_dev); | ||
458 | return ret; | ||
459 | } | ||
460 | |||
461 | static int tegra_i2c_gpio_init(struct tegra_i2c_dev *i2c_dev) | ||
462 | { | ||
463 | struct i2c_algo_bit_data *bit_data = &i2c_dev->bit_data; | ||
464 | |||
465 | bit_data->setsda = tegra_i2c_gpio_setsda; | ||
466 | bit_data->getsda = tegra_i2c_gpio_getsda; | ||
467 | bit_data->setscl = tegra_i2c_gpio_setscl; | ||
468 | bit_data->getscl = tegra_i2c_gpio_getscl; | ||
469 | bit_data->data = i2c_dev; | ||
470 | bit_data->udelay = 5; /* 100KHz */ | ||
471 | bit_data->timeout = HZ; /* 10 ms*/ | ||
472 | i2c_dev->bit_algo = &i2c_bit_algo; | ||
473 | i2c_dev->adapter.algo_data = bit_data; | ||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | static void tegra_i2c_rx_dma_complete(void *args) | ||
478 | { | ||
479 | struct tegra_i2c_dev *i2c_dev = args; | ||
480 | struct dma_tx_state state; | ||
481 | |||
482 | dma_sync_single_for_cpu(i2c_dev->dev, i2c_dev->rx_dma_phys, | ||
483 | i2c_dev->dma_buf_size, DMA_FROM_DEVICE); | ||
484 | dmaengine_tx_status(i2c_dev->rx_dma_chan, i2c_dev->rx_cookie, &state); | ||
485 | memcpy(i2c_dev->msg_buf, i2c_dev->rx_dma_buf, i2c_dev->rx_dma_len); | ||
486 | dma_sync_single_for_device(i2c_dev->dev, i2c_dev->rx_dma_phys, | ||
487 | i2c_dev->dma_buf_size, DMA_FROM_DEVICE); | ||
488 | complete(&i2c_dev->rx_dma_complete); | ||
489 | } | ||
490 | |||
491 | static void tegra_i2c_tx_dma_complete(void *args) | ||
492 | { | ||
493 | struct tegra_i2c_dev *i2c_dev = args; | ||
494 | |||
495 | complete(&i2c_dev->tx_dma_complete); | ||
496 | } | ||
497 | |||
498 | static int tegra_i2c_start_tx_dma(struct tegra_i2c_dev *i2c_dev, int len) | ||
499 | { | ||
500 | reinit_completion(&i2c_dev->tx_dma_complete); | ||
501 | dev_dbg(i2c_dev->dev, "Starting tx dma for len:%d\n", len); | ||
502 | i2c_dev->tx_dma_desc = dmaengine_prep_slave_single(i2c_dev->tx_dma_chan, | ||
503 | i2c_dev->tx_dma_phys, len, DMA_MEM_TO_DEV, | ||
504 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
505 | if (!i2c_dev->tx_dma_desc) { | ||
506 | dev_err(i2c_dev->dev, "Not able to get desc for Tx\n"); | ||
507 | return -EIO; | ||
508 | } | ||
509 | |||
510 | i2c_dev->tx_dma_desc->callback = tegra_i2c_tx_dma_complete; | ||
511 | i2c_dev->tx_dma_desc->callback_param = i2c_dev; | ||
512 | |||
513 | dmaengine_submit(i2c_dev->tx_dma_desc); | ||
514 | dma_async_issue_pending(i2c_dev->tx_dma_chan); | ||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | static int tegra_i2c_start_rx_dma(struct tegra_i2c_dev *i2c_dev, int len) | ||
519 | { | ||
520 | reinit_completion(&i2c_dev->rx_dma_complete); | ||
521 | i2c_dev->rx_dma_len = len; | ||
522 | |||
523 | dev_dbg(i2c_dev->dev, "Starting rx dma for len:%d\n", len); | ||
524 | i2c_dev->rx_dma_desc = dmaengine_prep_slave_single(i2c_dev->rx_dma_chan, | ||
525 | i2c_dev->rx_dma_phys, len, DMA_DEV_TO_MEM, | ||
526 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
527 | if (!i2c_dev->rx_dma_desc) { | ||
528 | dev_err(i2c_dev->dev, "Not able to get desc for Rx\n"); | ||
529 | return -EIO; | ||
530 | } | ||
531 | |||
532 | i2c_dev->rx_dma_desc->callback = tegra_i2c_rx_dma_complete; | ||
533 | i2c_dev->rx_dma_desc->callback_param = i2c_dev; | ||
534 | |||
535 | dmaengine_submit(i2c_dev->rx_dma_desc); | ||
536 | dma_async_issue_pending(i2c_dev->rx_dma_chan); | ||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | |||
541 | static int tegra_i2c_init_dma_param(struct tegra_i2c_dev *i2c_dev, | ||
542 | bool dma_to_memory) | ||
543 | { | ||
544 | struct dma_chan *dma_chan; | ||
545 | u32 *dma_buf; | ||
546 | dma_addr_t dma_phys; | ||
547 | int ret; | ||
548 | struct dma_slave_config dma_sconfig; | ||
549 | |||
550 | dma_chan = dma_request_slave_channel_reason(i2c_dev->dev, | ||
551 | dma_to_memory ? "rx" : "tx"); | ||
552 | if (IS_ERR(dma_chan)) { | ||
553 | ret = PTR_ERR(dma_chan); | ||
554 | if (ret != -EPROBE_DEFER) | ||
555 | dev_err(i2c_dev->dev, | ||
556 | "Dma channel is not available: %d\n", ret); | ||
557 | return ret; | ||
558 | } | ||
559 | |||
560 | dma_buf = dma_alloc_coherent(i2c_dev->dev, i2c_dev->dma_buf_size, | ||
561 | &dma_phys, GFP_KERNEL); | ||
562 | if (!dma_buf) { | ||
563 | dev_err(i2c_dev->dev, "Not able to allocate the dma buffer\n"); | ||
564 | dma_release_channel(dma_chan); | ||
565 | return -ENOMEM; | ||
566 | } | ||
567 | |||
568 | if (dma_to_memory) { | ||
569 | dma_sconfig.src_addr = i2c_dev->phys_addr + I2C_RX_FIFO; | ||
570 | dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
571 | dma_sconfig.src_maxburst = 0; | ||
572 | } else { | ||
573 | dma_sconfig.dst_addr = i2c_dev->phys_addr + I2C_TX_FIFO; | ||
574 | dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
575 | dma_sconfig.dst_maxburst = 0; | ||
576 | } | ||
577 | |||
578 | ret = dmaengine_slave_config(dma_chan, &dma_sconfig); | ||
579 | if (ret) | ||
580 | goto scrub; | ||
581 | if (dma_to_memory) { | ||
582 | i2c_dev->rx_dma_chan = dma_chan; | ||
583 | i2c_dev->rx_dma_buf = dma_buf; | ||
584 | i2c_dev->rx_dma_phys = dma_phys; | ||
585 | } else { | ||
586 | i2c_dev->tx_dma_chan = dma_chan; | ||
587 | i2c_dev->tx_dma_buf = dma_buf; | ||
588 | i2c_dev->tx_dma_phys = dma_phys; | ||
589 | } | ||
590 | return 0; | ||
591 | |||
592 | scrub: | ||
593 | dma_free_coherent(i2c_dev->dev, i2c_dev->dma_buf_size, | ||
594 | dma_buf, dma_phys); | ||
595 | dma_release_channel(dma_chan); | ||
596 | return ret; | ||
597 | } | ||
598 | |||
599 | static void tegra_i2c_deinit_dma_param(struct tegra_i2c_dev *i2c_dev, | ||
600 | bool dma_to_memory) | ||
601 | { | ||
602 | u32 *dma_buf; | ||
603 | dma_addr_t dma_phys; | ||
604 | struct dma_chan *dma_chan; | ||
605 | |||
606 | if (dma_to_memory) { | ||
607 | dma_buf = i2c_dev->rx_dma_buf; | ||
608 | dma_chan = i2c_dev->rx_dma_chan; | ||
609 | dma_phys = i2c_dev->rx_dma_phys; | ||
610 | i2c_dev->rx_dma_chan = NULL; | ||
611 | i2c_dev->rx_dma_buf = NULL; | ||
612 | } else { | ||
613 | dma_buf = i2c_dev->tx_dma_buf; | ||
614 | dma_chan = i2c_dev->tx_dma_chan; | ||
615 | dma_phys = i2c_dev->tx_dma_phys; | ||
616 | i2c_dev->tx_dma_buf = NULL; | ||
617 | i2c_dev->tx_dma_chan = NULL; | ||
618 | } | ||
619 | if (!dma_chan) | ||
620 | return; | ||
621 | |||
622 | dma_free_coherent(i2c_dev->dev, i2c_dev->dma_buf_size, | ||
623 | dma_buf, dma_phys); | ||
624 | dma_release_channel(dma_chan); | ||
625 | } | ||
626 | |||
627 | static void tegra_i2c_mask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask) | ||
628 | { | ||
629 | u32 int_mask = i2c_readl(i2c_dev, I2C_INT_MASK); | ||
630 | |||
631 | int_mask &= ~mask; | ||
632 | i2c_writel(i2c_dev, int_mask, I2C_INT_MASK); | ||
633 | } | ||
634 | |||
635 | static void tegra_i2c_unmask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask) | ||
636 | { | ||
637 | u32 int_mask = i2c_readl(i2c_dev, I2C_INT_MASK); | ||
638 | |||
639 | int_mask |= mask; | ||
640 | i2c_writel(i2c_dev, int_mask, I2C_INT_MASK); | ||
641 | } | ||
642 | |||
643 | static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev) | ||
644 | { | ||
645 | unsigned long timeout = jiffies + HZ; | ||
646 | u32 val = i2c_readl(i2c_dev, I2C_FIFO_CONTROL); | ||
647 | |||
648 | val |= I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH; | ||
649 | i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); | ||
650 | |||
651 | while (i2c_readl(i2c_dev, I2C_FIFO_CONTROL) & | ||
652 | (I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH)) { | ||
653 | if (time_after(jiffies, timeout)) { | ||
654 | dev_warn(i2c_dev->dev, "timeout waiting for fifo flush\n"); | ||
655 | return -ETIMEDOUT; | ||
656 | } | ||
657 | msleep(1); | ||
658 | } | ||
659 | return 0; | ||
660 | } | ||
661 | |||
662 | static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev) | ||
663 | { | ||
664 | u32 val; | ||
665 | int rx_fifo_avail; | ||
666 | u8 *buf = i2c_dev->msg_buf; | ||
667 | size_t buf_remaining = i2c_dev->msg_buf_remaining; | ||
668 | int words_to_transfer; | ||
669 | |||
670 | val = i2c_readl(i2c_dev, I2C_FIFO_STATUS); | ||
671 | rx_fifo_avail = (val & I2C_FIFO_STATUS_RX_MASK) >> | ||
672 | I2C_FIFO_STATUS_RX_SHIFT; | ||
673 | |||
674 | /* Rounds down to not include partial word at the end of buf */ | ||
675 | words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD; | ||
676 | if (words_to_transfer > rx_fifo_avail) | ||
677 | words_to_transfer = rx_fifo_avail; | ||
678 | |||
679 | i2c_readsl(i2c_dev, buf, I2C_RX_FIFO, words_to_transfer); | ||
680 | |||
681 | buf += words_to_transfer * BYTES_PER_FIFO_WORD; | ||
682 | buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD; | ||
683 | rx_fifo_avail -= words_to_transfer; | ||
684 | |||
685 | /* | ||
686 | * If there is a partial word at the end of buf, handle it manually to | ||
687 | * prevent overwriting past the end of buf | ||
688 | */ | ||
689 | if (rx_fifo_avail > 0 && buf_remaining > 0) { | ||
690 | BUG_ON(buf_remaining > 3); | ||
691 | val = i2c_readl(i2c_dev, I2C_RX_FIFO); | ||
692 | val = cpu_to_le32(val); | ||
693 | memcpy(buf, &val, buf_remaining); | ||
694 | buf_remaining = 0; | ||
695 | rx_fifo_avail--; | ||
696 | } | ||
697 | |||
698 | BUG_ON(rx_fifo_avail > 0 && buf_remaining > 0); | ||
699 | i2c_dev->msg_buf_remaining = buf_remaining; | ||
700 | i2c_dev->msg_buf = buf; | ||
701 | return 0; | ||
702 | } | ||
703 | |||
704 | static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev) | ||
705 | { | ||
706 | u32 val; | ||
707 | int tx_fifo_avail; | ||
708 | u8 *buf = i2c_dev->msg_buf; | ||
709 | size_t buf_remaining = i2c_dev->msg_buf_remaining; | ||
710 | int words_to_transfer; | ||
711 | |||
712 | val = i2c_readl(i2c_dev, I2C_FIFO_STATUS); | ||
713 | tx_fifo_avail = (val & I2C_FIFO_STATUS_TX_MASK) >> | ||
714 | I2C_FIFO_STATUS_TX_SHIFT; | ||
715 | |||
716 | /* Rounds down to not include partial word at the end of buf */ | ||
717 | words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD; | ||
718 | |||
719 | /* It's very common to have < 4 bytes, so optimize that case. */ | ||
720 | if (words_to_transfer) { | ||
721 | if (words_to_transfer > tx_fifo_avail) | ||
722 | words_to_transfer = tx_fifo_avail; | ||
723 | |||
724 | /* | ||
725 | * Update state before writing to FIFO. If this casues us | ||
726 | * to finish writing all bytes (AKA buf_remaining goes to 0) we | ||
727 | * have a potential for an interrupt (PACKET_XFER_COMPLETE is | ||
728 | * not maskable). We need to make sure that the isr sees | ||
729 | * buf_remaining as 0 and doesn't call us back re-entrantly. | ||
730 | */ | ||
731 | buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD; | ||
732 | tx_fifo_avail -= words_to_transfer; | ||
733 | i2c_dev->msg_buf_remaining = buf_remaining; | ||
734 | i2c_dev->msg_buf = buf + | ||
735 | words_to_transfer * BYTES_PER_FIFO_WORD; | ||
736 | barrier(); | ||
737 | |||
738 | i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer); | ||
739 | |||
740 | buf += words_to_transfer * BYTES_PER_FIFO_WORD; | ||
741 | } | ||
742 | |||
743 | /* | ||
744 | * If there is a partial word at the end of buf, handle it manually to | ||
745 | * prevent reading past the end of buf, which could cross a page | ||
746 | * boundary and fault. | ||
747 | */ | ||
748 | if (tx_fifo_avail > 0 && buf_remaining > 0) { | ||
749 | BUG_ON(buf_remaining > 3); | ||
750 | memcpy(&val, buf, buf_remaining); | ||
751 | val = le32_to_cpu(val); | ||
752 | |||
753 | /* Again update before writing to FIFO to make sure isr sees. */ | ||
754 | i2c_dev->msg_buf_remaining = 0; | ||
755 | i2c_dev->msg_buf = NULL; | ||
756 | barrier(); | ||
757 | |||
758 | i2c_writel(i2c_dev, val, I2C_TX_FIFO); | ||
759 | } | ||
760 | |||
761 | return 0; | ||
762 | } | ||
763 | |||
764 | /* | ||
765 | * One of the Tegra I2C blocks is inside the DVC (Digital Voltage Controller) | ||
766 | * block. This block is identical to the rest of the I2C blocks, except that | ||
767 | * it only supports master mode, it has registers moved around, and it needs | ||
768 | * some extra init to get it into I2C mode. The register moves are handled | ||
769 | * by i2c_readl and i2c_writel | ||
770 | */ | ||
771 | static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev) | ||
772 | { | ||
773 | u32 val = 0; | ||
774 | |||
775 | val = dvc_readl(i2c_dev, DVC_CTRL_REG3); | ||
776 | val |= DVC_CTRL_REG3_SW_PROG; | ||
777 | val |= DVC_CTRL_REG3_I2C_DONE_INTR_EN; | ||
778 | dvc_writel(i2c_dev, val, DVC_CTRL_REG3); | ||
779 | |||
780 | val = dvc_readl(i2c_dev, DVC_CTRL_REG1); | ||
781 | val |= DVC_CTRL_REG1_INTR_EN; | ||
782 | dvc_writel(i2c_dev, val, DVC_CTRL_REG1); | ||
783 | } | ||
784 | |||
785 | /* | ||
786 | * One of the Tegra I2C blocks is inside the VI (Video Interface?) | ||
787 | * block. This block is identical to the rest of the I2C blocks, except that | ||
788 | * it only supports master mode, it has registers moved around, and it needs | ||
789 | * some extra init to get it into I2C mode. The register moves are handled | ||
790 | * by i2c_readl and i2c_writel. | ||
791 | */ | ||
792 | static void tegra_vi_init(struct tegra_i2c_dev *i2c_dev) | ||
793 | { | ||
794 | i2c_writel(i2c_dev, (I2C_TLOW << I2C_TLOW_SHIFT) | | ||
795 | (I2C_THIGH << I2C_THIGH_SHIFT), I2C_INTERFACE_TIMING_0); | ||
796 | i2c_writel(i2c_dev, 0x04070404, I2C_INTERFACE_TIMING_1); | ||
797 | i2c_writel(i2c_dev, 0x308, I2C_HS_INTERFACE_TIMING_0); | ||
798 | i2c_writel(i2c_dev, 0x0B0B0B, I2C_HS_INTERFACE_TIMING_1); | ||
799 | i2c_writel(i2c_dev, 0x90004, I2C_BUS_CLEAR_CNFG); | ||
800 | i2c_writel(i2c_dev, 0x0, I2C_TLOW_SEXT); | ||
801 | } | ||
802 | |||
803 | static inline int tegra_i2c_clock_enable(struct tegra_i2c_dev *i2c_dev) | ||
804 | { | ||
805 | int ret; | ||
806 | |||
807 | if (!i2c_dev->hw->has_single_clk_source) { | ||
808 | ret = clk_enable(i2c_dev->fast_clk); | ||
809 | if (ret < 0) { | ||
810 | dev_err(i2c_dev->dev, | ||
811 | "Enabling fast clk failed, err %d\n", ret); | ||
812 | return ret; | ||
813 | } | ||
814 | } | ||
815 | ret = clk_enable(i2c_dev->div_clk); | ||
816 | if (ret < 0) { | ||
817 | dev_err(i2c_dev->dev, | ||
818 | "Enabling div clk failed, err %d\n", ret); | ||
819 | goto err_fast_disable; | ||
820 | } | ||
821 | if (i2c_dev->hw->is_vi) { | ||
822 | ret = clk_prepare_enable(i2c_dev->slow_clk); | ||
823 | if (ret < 0) { | ||
824 | dev_err(i2c_dev->dev, | ||
825 | "Enabling slow clk failed, err %d\n", ret); | ||
826 | goto err_div_disable; | ||
827 | } | ||
828 | |||
829 | ret = clk_prepare_enable(i2c_dev->host1x_clk); | ||
830 | if (ret < 0) { | ||
831 | dev_err(i2c_dev->dev, | ||
832 | "Enabling host1x clk failed, err %d\n", ret); | ||
833 | goto err_slow_disable; | ||
834 | } | ||
835 | } | ||
836 | |||
837 | return 0; | ||
838 | |||
839 | err_slow_disable: | ||
840 | if (i2c_dev->hw->is_vi) | ||
841 | clk_disable_unprepare(i2c_dev->slow_clk); | ||
842 | err_div_disable: | ||
843 | clk_disable(i2c_dev->div_clk); | ||
844 | err_fast_disable: | ||
845 | if (!i2c_dev->hw->has_single_clk_source) | ||
846 | clk_disable(i2c_dev->fast_clk); | ||
847 | |||
848 | return ret; | ||
849 | } | ||
850 | |||
851 | static inline void tegra_i2c_clock_disable(struct tegra_i2c_dev *i2c_dev) | ||
852 | { | ||
853 | if (i2c_dev->hw->is_vi) { | ||
854 | clk_disable_unprepare(i2c_dev->host1x_clk); | ||
855 | clk_disable_unprepare(i2c_dev->slow_clk); | ||
856 | } | ||
857 | clk_disable(i2c_dev->div_clk); | ||
858 | if (!i2c_dev->hw->has_single_clk_source) | ||
859 | clk_disable(i2c_dev->fast_clk); | ||
860 | } | ||
861 | |||
862 | static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev) | ||
863 | { | ||
864 | if (i2c_dev->hw->has_config_load_reg) { | ||
865 | u32 val; | ||
866 | int err; | ||
867 | |||
868 | i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD); | ||
869 | if (!in_atomic()) | ||
870 | err = readx_poll_timeout(readl, i2c_dev->base + | ||
871 | tegra_i2c_reg_addr(i2c_dev, | ||
872 | I2C_CONFIG_LOAD), val, val == 0, | ||
873 | 1000, I2C_CONFIG_LOAD_TIMEOUT); | ||
874 | else | ||
875 | err = readx_poll_timeout_atomic(readl, i2c_dev->base + | ||
876 | tegra_i2c_reg_addr(i2c_dev, | ||
877 | I2C_CONFIG_LOAD), val, val == 0, | ||
878 | 1000, I2C_CONFIG_LOAD_TIMEOUT); | ||
879 | |||
880 | if (err) { | ||
881 | dev_warn(i2c_dev->dev, | ||
882 | "timeout waiting for config load\n"); | ||
883 | return err; | ||
884 | } | ||
885 | } | ||
886 | |||
887 | return 0; | ||
888 | } | ||
889 | |||
890 | static int tegra_i2c_set_clk_rate(struct tegra_i2c_dev *i2c_dev) | ||
891 | { | ||
892 | u32 clk_multiplier = I2C_CLK_MULTIPLIER_STD_FAST_MODE; | ||
893 | int ret = 0; | ||
894 | |||
895 | |||
896 | switch (i2c_dev->bus_clk_rate) { | ||
897 | case I2C_HS_MODE: | ||
898 | clk_multiplier = i2c_dev->hw->clk_multiplier_hs_mode; | ||
899 | clk_multiplier *= (i2c_dev->clk_divisor_hs_mode + 1); | ||
900 | break; | ||
901 | case I2C_FAST_MODE_PLUS: | ||
902 | case I2C_STANDARD_MODE: | ||
903 | case I2C_FAST_MODE: | ||
904 | default: | ||
905 | clk_multiplier = (i2c_dev->low_clock_count + | ||
906 | i2c_dev->high_clock_count + 2); | ||
907 | clk_multiplier *= (i2c_dev->clk_divisor_non_hs_mode + 1); | ||
908 | break; | ||
909 | } | ||
910 | |||
911 | ret = clk_set_rate(i2c_dev->div_clk, | ||
912 | i2c_dev->bus_clk_rate * clk_multiplier); | ||
913 | if (ret) { | ||
914 | dev_err(i2c_dev->dev, "Clock rate change failed %d\n", ret); | ||
915 | return ret; | ||
916 | } | ||
917 | |||
918 | return ret; | ||
919 | } | ||
920 | |||
921 | static void tegra_i2c_config_prod_settings(struct tegra_i2c_dev *i2c_dev) | ||
922 | { | ||
923 | char *prod_name; | ||
924 | int ret; | ||
925 | |||
926 | switch (i2c_dev->bus_clk_rate) { | ||
927 | case I2C_FAST_MODE: | ||
928 | prod_name = "prod_c_fm"; | ||
929 | break; | ||
930 | case I2C_FAST_MODE_PLUS: | ||
931 | prod_name = "prod_c_fmplus"; | ||
932 | break; | ||
933 | case I2C_HS_MODE: | ||
934 | prod_name = "prod_c_hs"; | ||
935 | break; | ||
936 | case I2C_STANDARD_MODE: | ||
937 | default: | ||
938 | prod_name = "prod_c_sm"; | ||
939 | break; | ||
940 | } | ||
941 | |||
942 | ret = tegra_prod_set_by_name(&i2c_dev->base, prod_name, | ||
943 | i2c_dev->prod_list); | ||
944 | if (ret == 0) | ||
945 | dev_dbg(i2c_dev->dev, "setting prod: %s\n", prod_name); | ||
946 | } | ||
947 | |||
948 | static void tegra_i2c_get_clk_parameters(struct tegra_i2c_dev *i2c_dev) | ||
949 | { | ||
950 | u32 val; | ||
951 | |||
952 | val = i2c_readl(i2c_dev, I2C_INTERFACE_TIMING_0); | ||
953 | i2c_dev->low_clock_count = val & I2C_TLOW_MASK; | ||
954 | i2c_dev->high_clock_count = (val & I2C_THIGH_MASK) >> I2C_THIGH_SHIFT; | ||
955 | |||
956 | val = i2c_readl(i2c_dev, I2C_CLK_DIVISOR); | ||
957 | i2c_dev->clk_divisor_hs_mode = val & I2C_CLK_DIVISOR_HS_MODE_MASK; | ||
958 | i2c_dev->clk_divisor_non_hs_mode = (val >> | ||
959 | I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT); | ||
960 | } | ||
961 | |||
962 | static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) | ||
963 | { | ||
964 | u32 val; | ||
965 | int err = 0; | ||
966 | u32 clk_divisor; | ||
967 | |||
968 | err = tegra_i2c_clock_enable(i2c_dev); | ||
969 | if (err < 0) { | ||
970 | dev_err(i2c_dev->dev, "Clock enable failed %d\n", err); | ||
971 | return err; | ||
972 | } | ||
973 | |||
974 | if (i2c_dev->hw->has_sw_reset_reg) { | ||
975 | if (i2c_dev->is_periph_reset_done) { | ||
976 | /* If already controller reset is done through */ | ||
977 | /* clock reset control register, then use SW reset */ | ||
978 | i2c_writel(i2c_dev, 1, I2C_MASTER_RESET_CONTROL); | ||
979 | udelay(2); | ||
980 | i2c_writel(i2c_dev, 0, I2C_MASTER_RESET_CONTROL); | ||
981 | goto skip_periph_reset; | ||
982 | } | ||
983 | } | ||
984 | reset_control_assert(i2c_dev->rst); | ||
985 | udelay(2); | ||
986 | reset_control_deassert(i2c_dev->rst); | ||
987 | |||
988 | skip_periph_reset: | ||
989 | if (i2c_dev->is_dvc) | ||
990 | tegra_dvc_init(i2c_dev); | ||
991 | |||
992 | /* configuring below register to default as per TRM*/ | ||
993 | i2c_writel(i2c_dev, 0, I2C_TLOW_SEXT); | ||
994 | i2c_writel(i2c_dev, 0, I2C_CMD_ADDR0); | ||
995 | i2c_writel(i2c_dev, 0, I2C_CMD_ADDR1); | ||
996 | i2c_writel(i2c_dev, 0, I2C_CMD_DATA1); | ||
997 | i2c_writel(i2c_dev, 0, I2C_CMD_DATA2); | ||
998 | i2c_writel(i2c_dev, 0, I2C_DEBUG_CONTROL); | ||
999 | i2c_writel(i2c_dev, 0, I2C_INTERRUPT_SET_REGISTER); | ||
1000 | i2c_writel(i2c_dev, 0, I2C_FIFO_CONTROL); | ||
1001 | |||
1002 | val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN; | ||
1003 | if (i2c_dev->bus_clk_rate != I2C_HS_MODE) | ||
1004 | val |= (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT); | ||
1005 | |||
1006 | if (i2c_dev->hw->has_multi_master_mode) | ||
1007 | val |= I2C_CNFG_MULTI_MASTER_MODE; | ||
1008 | |||
1009 | i2c_writel(i2c_dev, val, I2C_CNFG); | ||
1010 | i2c_writel(i2c_dev, 0, I2C_INT_MASK); | ||
1011 | |||
1012 | if (i2c_dev->hw->is_vi) | ||
1013 | tegra_vi_init(i2c_dev); | ||
1014 | |||
1015 | /* Make sure clock divisor programmed correctly */ | ||
1016 | if (i2c_dev->bus_clk_rate == I2C_HS_MODE) { | ||
1017 | i2c_dev->clk_divisor_hs_mode = i2c_dev->hw->clk_divisor_hs_mode; | ||
1018 | } else { | ||
1019 | val = i2c_readl(i2c_dev, I2C_CLK_DIVISOR); | ||
1020 | i2c_dev->clk_divisor_hs_mode = | ||
1021 | val & I2C_CLK_DIVISOR_HS_MODE_MASK; | ||
1022 | } | ||
1023 | |||
1024 | clk_divisor = i2c_dev->clk_divisor_hs_mode; | ||
1025 | clk_divisor |= i2c_dev->clk_divisor_non_hs_mode << | ||
1026 | I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT; | ||
1027 | i2c_writel(i2c_dev, clk_divisor, I2C_CLK_DIVISOR); | ||
1028 | |||
1029 | if (i2c_dev->prod_list) | ||
1030 | tegra_i2c_config_prod_settings(i2c_dev); | ||
1031 | |||
1032 | tegra_i2c_get_clk_parameters(i2c_dev); | ||
1033 | |||
1034 | err = tegra_i2c_set_clk_rate(i2c_dev); | ||
1035 | if (err < 0) | ||
1036 | return err; | ||
1037 | |||
1038 | if (!i2c_dev->is_dvc && !i2c_dev->hw->is_vi) { | ||
1039 | u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG); | ||
1040 | |||
1041 | sl_cfg |= I2C_SL_CNFG_NACK | I2C_SL_CNFG_NEWSL; | ||
1042 | i2c_writel(i2c_dev, sl_cfg, I2C_SL_CNFG); | ||
1043 | i2c_writel(i2c_dev, 0xfc, I2C_SL_ADDR1); | ||
1044 | i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2); | ||
1045 | |||
1046 | } | ||
1047 | |||
1048 | val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT | | ||
1049 | 0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT; | ||
1050 | i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); | ||
1051 | |||
1052 | err = tegra_i2c_flush_fifos(i2c_dev); | ||
1053 | if (err) | ||
1054 | goto err; | ||
1055 | |||
1056 | if (i2c_dev->is_multimaster_mode && i2c_dev->hw->has_slcg_override_reg) | ||
1057 | i2c_writel(i2c_dev, I2C_MST_CORE_CLKEN_OVR, I2C_CLKEN_OVERRIDE); | ||
1058 | |||
1059 | err = tegra_i2c_wait_for_config_load(i2c_dev); | ||
1060 | if (err) | ||
1061 | goto err; | ||
1062 | |||
1063 | if (i2c_dev->irq_disabled) { | ||
1064 | i2c_dev->irq_disabled = 0; | ||
1065 | enable_irq(i2c_dev->irq); | ||
1066 | } | ||
1067 | |||
1068 | err: | ||
1069 | tegra_i2c_clock_disable(i2c_dev); | ||
1070 | return err; | ||
1071 | } | ||
1072 | |||
1073 | static int tegra_i2c_power_enable(struct tegra_i2c_dev *i2c_dev) | ||
1074 | { | ||
1075 | int ret; | ||
1076 | |||
1077 | if (i2c_dev->hw->has_regulator) { | ||
1078 | ret = regulator_enable(i2c_dev->reg); | ||
1079 | if (ret) | ||
1080 | return ret; | ||
1081 | } | ||
1082 | |||
1083 | if (i2c_dev->hw->has_powergate) { | ||
1084 | ret = tegra_unpowergate_partition(i2c_dev->hw->powergate_id); | ||
1085 | if (ret) | ||
1086 | goto err_regulator; | ||
1087 | |||
1088 | ret = tegra_i2c_init(i2c_dev); | ||
1089 | if (ret) | ||
1090 | goto err_powergate; | ||
1091 | } | ||
1092 | |||
1093 | return 0; | ||
1094 | |||
1095 | err_regulator: | ||
1096 | if (i2c_dev->hw->has_regulator) | ||
1097 | regulator_disable(i2c_dev->reg); | ||
1098 | err_powergate: | ||
1099 | if (i2c_dev->hw->has_powergate) | ||
1100 | tegra_powergate_partition(i2c_dev->hw->powergate_id); | ||
1101 | |||
1102 | return ret; | ||
1103 | } | ||
1104 | |||
1105 | static void tegra_i2c_power_disable(struct tegra_i2c_dev *i2c_dev) | ||
1106 | { | ||
1107 | if (i2c_dev->hw->has_regulator) | ||
1108 | regulator_disable(i2c_dev->reg); | ||
1109 | |||
1110 | if (i2c_dev->hw->has_powergate) | ||
1111 | tegra_powergate_partition(i2c_dev->hw->powergate_id); | ||
1112 | } | ||
1113 | |||
1114 | static int tegra_i2c_disable_packet_mode(struct tegra_i2c_dev *i2c_dev) | ||
1115 | { | ||
1116 | u32 cnfg; | ||
1117 | |||
1118 | cnfg = i2c_readl(i2c_dev, I2C_CNFG); | ||
1119 | if (cnfg & I2C_CNFG_PACKET_MODE_EN) | ||
1120 | i2c_writel(i2c_dev, cnfg & ~I2C_CNFG_PACKET_MODE_EN, I2C_CNFG); | ||
1121 | |||
1122 | return tegra_i2c_wait_for_config_load(i2c_dev); | ||
1123 | } | ||
1124 | |||
1125 | static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) | ||
1126 | { | ||
1127 | u32 status; | ||
1128 | const u32 status_err = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST; | ||
1129 | struct tegra_i2c_dev *i2c_dev = dev_id; | ||
1130 | unsigned long flags; | ||
1131 | u32 mask; | ||
1132 | |||
1133 | spin_lock_irqsave(&i2c_dev->xfer_lock, flags); | ||
1134 | |||
1135 | status = i2c_readl(i2c_dev, I2C_INT_STATUS); | ||
1136 | |||
1137 | if (status == 0) { | ||
1138 | dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n", | ||
1139 | i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS), | ||
1140 | i2c_readl(i2c_dev, I2C_STATUS), | ||
1141 | i2c_readl(i2c_dev, I2C_CNFG)); | ||
1142 | i2c_dev->msg_err |= I2C_ERR_UNKNOWN_INTERRUPT; | ||
1143 | |||
1144 | if (!i2c_dev->irq_disabled) { | ||
1145 | disable_irq_nosync(i2c_dev->irq); | ||
1146 | i2c_dev->irq_disabled = 1; | ||
1147 | } | ||
1148 | goto err; | ||
1149 | } | ||
1150 | |||
1151 | if (unlikely(status & status_err)) { | ||
1152 | tegra_i2c_disable_packet_mode(i2c_dev); | ||
1153 | if (status & I2C_INT_NO_ACK) | ||
1154 | i2c_dev->msg_err |= I2C_ERR_NO_ACK; | ||
1155 | if (status & I2C_INT_ARBITRATION_LOST) | ||
1156 | i2c_dev->msg_err |= I2C_ERR_ARBITRATION_LOST; | ||
1157 | goto err; | ||
1158 | } | ||
1159 | |||
1160 | if (i2c_dev->hw->has_hw_arb_support && | ||
1161 | (status & I2C_INT_BUS_CLEAR_DONE)) | ||
1162 | goto err; | ||
1163 | |||
1164 | if (i2c_dev->msg_read && (status & I2C_INT_RX_FIFO_DATA_REQ)) { | ||
1165 | if (i2c_dev->msg_buf_remaining) | ||
1166 | tegra_i2c_empty_rx_fifo(i2c_dev); | ||
1167 | else | ||
1168 | BUG(); | ||
1169 | } | ||
1170 | |||
1171 | if (!i2c_dev->msg_read && (status & I2C_INT_TX_FIFO_DATA_REQ)) { | ||
1172 | if (i2c_dev->msg_buf_remaining) | ||
1173 | tegra_i2c_fill_tx_fifo(i2c_dev); | ||
1174 | else | ||
1175 | tegra_i2c_mask_irq(i2c_dev, I2C_INT_TX_FIFO_DATA_REQ); | ||
1176 | } | ||
1177 | |||
1178 | i2c_writel(i2c_dev, status, I2C_INT_STATUS); | ||
1179 | if (i2c_dev->is_dvc) | ||
1180 | dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS); | ||
1181 | |||
1182 | if (status & I2C_INT_PACKET_XFER_COMPLETE) { | ||
1183 | BUG_ON(i2c_dev->msg_buf_remaining); | ||
1184 | complete(&i2c_dev->msg_complete); | ||
1185 | } | ||
1186 | goto done; | ||
1187 | err: | ||
1188 | /* An error occurred, mask all interrupts */ | ||
1189 | mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST | | ||
1190 | I2C_INT_PACKET_XFER_COMPLETE | I2C_INT_TX_FIFO_DATA_REQ | | ||
1191 | I2C_INT_RX_FIFO_DATA_REQ; | ||
1192 | |||
1193 | if (i2c_dev->hw->has_hw_arb_support) | ||
1194 | mask |= I2C_INT_BUS_CLEAR_DONE; | ||
1195 | |||
1196 | /* An error occurred, mask all interrupts */ | ||
1197 | tegra_i2c_mask_irq(i2c_dev, mask); | ||
1198 | |||
1199 | i2c_writel(i2c_dev, status, I2C_INT_STATUS); | ||
1200 | if (i2c_dev->is_dvc) | ||
1201 | dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS); | ||
1202 | |||
1203 | if (i2c_dev->is_curr_dma_xfer) { | ||
1204 | if (i2c_dev->curr_direction == DATA_DMA_DIR_TX) { | ||
1205 | dmaengine_terminate_all(i2c_dev->tx_dma_chan); | ||
1206 | complete(&i2c_dev->tx_dma_complete); | ||
1207 | } else { | ||
1208 | dmaengine_terminate_all(i2c_dev->rx_dma_chan); | ||
1209 | complete(&i2c_dev->rx_dma_complete); | ||
1210 | } | ||
1211 | } | ||
1212 | |||
1213 | complete(&i2c_dev->msg_complete); | ||
1214 | done: | ||
1215 | spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags); | ||
1216 | return IRQ_HANDLED; | ||
1217 | } | ||
1218 | |||
1219 | static int tegra_i2c_issue_bus_clear(struct tegra_i2c_dev *i2c_dev) | ||
1220 | { | ||
1221 | int ret; | ||
1222 | |||
1223 | if (i2c_dev->hw->has_hw_arb_support) { | ||
1224 | reinit_completion(&i2c_dev->msg_complete); | ||
1225 | i2c_writel(i2c_dev, I2C_BC_ENABLE | ||
1226 | | I2C_BC_SCLK_THRESHOLD | ||
1227 | | I2C_BC_STOP_COND | ||
1228 | | I2C_BC_TERMINATE | ||
1229 | , I2C_BUS_CLEAR_CNFG); | ||
1230 | if (i2c_dev->hw->has_config_load_reg) { | ||
1231 | ret = tegra_i2c_wait_for_config_load(i2c_dev); | ||
1232 | if (ret) | ||
1233 | return ret; | ||
1234 | } | ||
1235 | tegra_i2c_unmask_irq(i2c_dev, I2C_INT_BUS_CLEAR_DONE); | ||
1236 | |||
1237 | ret = wait_for_completion_timeout(&i2c_dev->msg_complete, | ||
1238 | TEGRA_I2C_TIMEOUT); | ||
1239 | if (ret == 0) | ||
1240 | dev_err(i2c_dev->dev, "timed out for bus clear\n"); | ||
1241 | |||
1242 | if (!(i2c_readl(i2c_dev, I2C_BUS_CLEAR_STATUS) & I2C_BC_STATUS)) | ||
1243 | dev_warn(i2c_dev->dev, "Un-recovered Arb lost\n"); | ||
1244 | } else { | ||
1245 | ret = i2c_recover_bus(&i2c_dev->adapter); | ||
1246 | if (ret) { | ||
1247 | dev_warn(i2c_dev->dev, "Un-recovered Arb lost\n"); | ||
1248 | return ret; | ||
1249 | } | ||
1250 | } | ||
1251 | |||
1252 | return 0; | ||
1253 | } | ||
1254 | |||
1255 | static void tegra_i2c_fill_packet_header(struct tegra_i2c_dev *i2c_dev, | ||
1256 | struct i2c_msg *msg, enum msg_end_type end_state, | ||
1257 | u32 *packet_header) | ||
1258 | { | ||
1259 | u32 io_header = 0; | ||
1260 | |||
1261 | /* Generic header packet */ | ||
1262 | packet_header[0] = (0 << PACKET_HEADER0_HEADER_SIZE_SHIFT) | ||
1263 | | PACKET_HEADER0_PROTOCOL_I2C | | ||
1264 | (i2c_dev->cont_id << PACKET_HEADER0_CONT_ID_SHIFT) | | ||
1265 | (1 << PACKET_HEADER0_PACKET_ID_SHIFT); | ||
1266 | |||
1267 | /* Payload size */ | ||
1268 | packet_header[1] = msg->len - 1; | ||
1269 | |||
1270 | /* IO header */ | ||
1271 | io_header = I2C_HEADER_IE_ENABLE; | ||
1272 | |||
1273 | if (end_state == MSG_END_CONTINUE) | ||
1274 | io_header |= I2C_HEADER_CONTINUE_XFER; | ||
1275 | else if (end_state == MSG_END_REPEAT_START) | ||
1276 | io_header |= I2C_HEADER_REPEAT_START; | ||
1277 | |||
1278 | if (msg->flags & I2C_M_TEN) { | ||
1279 | io_header |= msg->addr; | ||
1280 | io_header |= I2C_HEADER_10BIT_ADDR; | ||
1281 | } else { | ||
1282 | io_header |= | ||
1283 | msg->addr << I2C_HEADER_SLAVE_ADDR_SHIFT; | ||
1284 | } | ||
1285 | |||
1286 | if (msg->flags & I2C_M_IGNORE_NAK) | ||
1287 | io_header |= I2C_HEADER_CONT_ON_NAK; | ||
1288 | if (msg->flags & I2C_M_RD) | ||
1289 | io_header |= I2C_HEADER_READ; | ||
1290 | |||
1291 | if (i2c_dev->bus_clk_rate == I2C_HS_MODE) { | ||
1292 | io_header |= I2C_HEADER_HIGHSPEED_MODE; | ||
1293 | io_header |= (i2c_dev->hs_master_code & 0x7) | ||
1294 | << I2C_HEADER_MASTER_ADDR_SHIFT; | ||
1295 | } | ||
1296 | packet_header[2] = io_header; | ||
1297 | } | ||
1298 | |||
1299 | static void tegra_i2c_config_fifo_trig(struct tegra_i2c_dev *i2c_dev, | ||
1300 | int len) | ||
1301 | { | ||
1302 | u32 val; | ||
1303 | u8 maxburst = 0; | ||
1304 | struct dma_slave_config dma_sconfig; | ||
1305 | |||
1306 | val = i2c_readl(i2c_dev, I2C_FIFO_CONTROL); | ||
1307 | if (len & 0xF) { | ||
1308 | val |= I2C_FIFO_CONTROL_TX_TRIG_1 | ||
1309 | | I2C_FIFO_CONTROL_RX_TRIG_1; | ||
1310 | maxburst = 1; | ||
1311 | } else if (((len) >> 4) & 0x1) { | ||
1312 | val |= I2C_FIFO_CONTROL_TX_TRIG_4 | ||
1313 | | I2C_FIFO_CONTROL_RX_TRIG_4; | ||
1314 | maxburst = 4; | ||
1315 | } else { | ||
1316 | val |= I2C_FIFO_CONTROL_TX_TRIG_8 | ||
1317 | | I2C_FIFO_CONTROL_RX_TRIG_8; | ||
1318 | maxburst = 8; | ||
1319 | } | ||
1320 | i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); | ||
1321 | |||
1322 | if (i2c_dev->curr_direction == DATA_DMA_DIR_TX) { | ||
1323 | dma_sconfig.dst_addr = i2c_dev->phys_addr + I2C_TX_FIFO; | ||
1324 | dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
1325 | dma_sconfig.dst_maxburst = maxburst; | ||
1326 | dmaengine_slave_config(i2c_dev->tx_dma_chan, &dma_sconfig); | ||
1327 | } else { | ||
1328 | dma_sconfig.src_addr = i2c_dev->phys_addr + I2C_RX_FIFO; | ||
1329 | dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
1330 | dma_sconfig.src_maxburst = maxburst; | ||
1331 | dmaengine_slave_config(i2c_dev->rx_dma_chan, &dma_sconfig); | ||
1332 | } | ||
1333 | } | ||
1334 | |||
1335 | static int tegra_i2c_start_dma_based_xfer(struct tegra_i2c_dev *i2c_dev, | ||
1336 | struct i2c_msg *msg, enum msg_end_type end_state) | ||
1337 | { | ||
1338 | int ret = 0; | ||
1339 | u32 packet_header[3]; | ||
1340 | u32 dma_xfer_len; | ||
1341 | u32 int_mask; | ||
1342 | unsigned long flags = 0; | ||
1343 | |||
1344 | i2c_dev->is_curr_dma_xfer = true; | ||
1345 | |||
1346 | /* set msg_buf_remaining to zero as complete xfer is done thru DMA*/ | ||
1347 | i2c_dev->msg_buf_remaining = 0; | ||
1348 | |||
1349 | /* Enable error interrupts */ | ||
1350 | int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST | ||
1351 | | I2C_INT_TX_FIFO_OVERFLOW; | ||
1352 | tegra_i2c_unmask_irq(i2c_dev, int_mask); | ||
1353 | |||
1354 | if (!(msg->flags & I2C_M_RD)) { | ||
1355 | i2c_dev->curr_direction = DATA_DMA_DIR_TX; | ||
1356 | dma_sync_single_for_cpu(i2c_dev->dev, i2c_dev->tx_dma_phys, | ||
1357 | i2c_dev->dma_buf_size, DMA_TO_DEVICE); | ||
1358 | /* Fill packet header */ | ||
1359 | tegra_i2c_fill_packet_header(i2c_dev, msg, end_state, | ||
1360 | packet_header); | ||
1361 | |||
1362 | dma_xfer_len = I2C_PACKET_HEADER_SIZE; | ||
1363 | memcpy(i2c_dev->tx_dma_buf, packet_header, (dma_xfer_len * 4)); | ||
1364 | |||
1365 | /* Copy data payload to dma buffer*/ | ||
1366 | memcpy(i2c_dev->tx_dma_buf + dma_xfer_len, i2c_dev->msg_buf, | ||
1367 | msg->len); | ||
1368 | /* make the dma buffer to read by dma */ | ||
1369 | dma_sync_single_for_device(i2c_dev->dev, i2c_dev->tx_dma_phys, | ||
1370 | i2c_dev->dma_buf_size, DMA_TO_DEVICE); | ||
1371 | dma_xfer_len += DIV_ROUND_UP(msg->len, 4); | ||
1372 | |||
1373 | /* Round up final length for DMA xfer in bytes*/ | ||
1374 | dma_xfer_len = DIV_ROUND_UP(dma_xfer_len * 4, 4) * 4; | ||
1375 | |||
1376 | tegra_i2c_config_fifo_trig(i2c_dev, dma_xfer_len); | ||
1377 | |||
1378 | /* Acquire the lock before posting the data to FIFO */ | ||
1379 | spin_lock_irqsave(&i2c_dev->xfer_lock, flags); | ||
1380 | |||
1381 | ret = tegra_i2c_start_tx_dma(i2c_dev, dma_xfer_len); | ||
1382 | if (ret < 0) { | ||
1383 | dev_err(i2c_dev->dev, | ||
1384 | "Starting tx dma failed, err %d\n", ret); | ||
1385 | goto exit; | ||
1386 | } | ||
1387 | } else { | ||
1388 | i2c_dev->curr_direction = DATA_DMA_DIR_RX; | ||
1389 | /* Round up final length for DMA xfer */ | ||
1390 | dma_xfer_len = DIV_ROUND_UP(msg->len, 4) * 4; | ||
1391 | tegra_i2c_config_fifo_trig(i2c_dev, dma_xfer_len); | ||
1392 | |||
1393 | ret = tegra_i2c_start_rx_dma(i2c_dev, dma_xfer_len); | ||
1394 | if (ret < 0) { | ||
1395 | dev_err(i2c_dev->dev, | ||
1396 | "Starting rx dma failed, err %d\n", ret); | ||
1397 | return ret; | ||
1398 | } | ||
1399 | /* Fill packet header */ | ||
1400 | tegra_i2c_fill_packet_header(i2c_dev, msg, end_state, | ||
1401 | packet_header); | ||
1402 | |||
1403 | /* Acquire the lock before posting the data to FIFO */ | ||
1404 | spin_lock_irqsave(&i2c_dev->xfer_lock, flags); | ||
1405 | |||
1406 | /* Transfer packet header through PIO */ | ||
1407 | i2c_writel(i2c_dev, packet_header[0], I2C_TX_FIFO); | ||
1408 | i2c_writel(i2c_dev, packet_header[1], I2C_TX_FIFO); | ||
1409 | i2c_writel(i2c_dev, packet_header[2], I2C_TX_FIFO); | ||
1410 | } | ||
1411 | |||
1412 | if (i2c_dev->hw->has_per_pkt_xfer_complete_irq) | ||
1413 | int_mask |= I2C_INT_PACKET_XFER_COMPLETE; | ||
1414 | |||
1415 | tegra_i2c_unmask_irq(i2c_dev, int_mask); | ||
1416 | |||
1417 | exit: | ||
1418 | spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags); | ||
1419 | return ret; | ||
1420 | } | ||
1421 | |||
1422 | static int tegra_i2c_start_pio_based_xfer(struct tegra_i2c_dev *i2c_dev, | ||
1423 | struct i2c_msg *msg, enum msg_end_type end_state) | ||
1424 | { | ||
1425 | |||
1426 | u32 val; | ||
1427 | u32 int_mask; | ||
1428 | u32 packet_header[3]; | ||
1429 | unsigned long flags = 0; | ||
1430 | |||
1431 | i2c_dev->is_curr_dma_xfer = false; | ||
1432 | val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT | | ||
1433 | 0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT; | ||
1434 | i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); | ||
1435 | |||
1436 | i2c_dev->msg_add = msg->addr; | ||
1437 | |||
1438 | /* Enable error interrupts */ | ||
1439 | int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST | ||
1440 | | I2C_INT_TX_FIFO_OVERFLOW; | ||
1441 | tegra_i2c_unmask_irq(i2c_dev, int_mask); | ||
1442 | |||
1443 | /* Fill packet header */ | ||
1444 | tegra_i2c_fill_packet_header(i2c_dev, msg, end_state, packet_header); | ||
1445 | |||
1446 | /* Acquire the lock before posting the data to FIFO */ | ||
1447 | spin_lock_irqsave(&i2c_dev->xfer_lock, flags); | ||
1448 | |||
1449 | i2c_writel(i2c_dev, packet_header[0], I2C_TX_FIFO); | ||
1450 | i2c_writel(i2c_dev, packet_header[1], I2C_TX_FIFO); | ||
1451 | i2c_writel(i2c_dev, packet_header[2], I2C_TX_FIFO); | ||
1452 | |||
1453 | if (!(msg->flags & I2C_M_RD)) | ||
1454 | tegra_i2c_fill_tx_fifo(i2c_dev); | ||
1455 | |||
1456 | if (i2c_dev->hw->has_per_pkt_xfer_complete_irq) | ||
1457 | int_mask |= I2C_INT_PACKET_XFER_COMPLETE; | ||
1458 | |||
1459 | if (msg->flags & I2C_M_RD) | ||
1460 | int_mask |= I2C_INT_RX_FIFO_DATA_REQ; | ||
1461 | else if (i2c_dev->msg_buf_remaining) | ||
1462 | int_mask |= I2C_INT_TX_FIFO_DATA_REQ; | ||
1463 | |||
1464 | tegra_i2c_unmask_irq(i2c_dev, int_mask); | ||
1465 | spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags); | ||
1466 | |||
1467 | return 0; | ||
1468 | } | ||
1469 | |||
1470 | static void tegra_i2c_pre_xfer_config(struct tegra_i2c_dev *i2c_dev, | ||
1471 | struct i2c_msg *msg) | ||
1472 | { | ||
1473 | tegra_i2c_flush_fifos(i2c_dev); | ||
1474 | |||
1475 | i2c_dev->is_curr_dma_xfer = false; | ||
1476 | i2c_dev->msg_buf = msg->buf; | ||
1477 | i2c_dev->msg_buf_remaining = msg->len; | ||
1478 | i2c_dev->msg_err = I2C_ERR_NONE; | ||
1479 | i2c_dev->msg_read = (msg->flags & I2C_M_RD); | ||
1480 | reinit_completion(&i2c_dev->msg_complete); | ||
1481 | |||
1482 | i2c_writel(i2c_dev, 0, I2C_INT_MASK); | ||
1483 | } | ||
1484 | |||
1485 | static int tegra_i2c_handle_xfer_error(struct tegra_i2c_dev *i2c_dev) | ||
1486 | { | ||
1487 | int ret; | ||
1488 | |||
1489 | /* Prints errors */ | ||
1490 | if (i2c_dev->msg_err & I2C_ERR_UNKNOWN_INTERRUPT) | ||
1491 | dev_warn(i2c_dev->dev, "unknown interrupt Add 0x%02x\n", | ||
1492 | i2c_dev->msg_add); | ||
1493 | if (i2c_dev->msg_err & I2C_ERR_NO_ACK) | ||
1494 | dev_warn(i2c_dev->dev, "no acknowledge from address 0x%x\n", | ||
1495 | i2c_dev->msg_add); | ||
1496 | if (i2c_dev->msg_err & I2C_ERR_ARBITRATION_LOST) | ||
1497 | dev_warn(i2c_dev->dev, "arb lost in communicate to add 0x%x\n", | ||
1498 | i2c_dev->msg_add); | ||
1499 | if (i2c_dev->msg_err & I2C_INT_TX_FIFO_OVERFLOW) | ||
1500 | dev_warn(i2c_dev->dev, "Tx fifo overflow to add 0x%x\n", | ||
1501 | i2c_dev->msg_add); | ||
1502 | /* | ||
1503 | * NACK interrupt is generated before the I2C controller generates the | ||
1504 | * STOP condition on the bus. | ||
1505 | * So wait for 2 clock periods before resetting | ||
1506 | * the controller so that STOP condition has been delivered properly. | ||
1507 | */ | ||
1508 | if (i2c_dev->msg_err == I2C_ERR_NO_ACK) | ||
1509 | udelay(DIV_ROUND_UP(2 * 1000000, i2c_dev->bus_clk_rate)); | ||
1510 | |||
1511 | ret = tegra_i2c_init(i2c_dev); | ||
1512 | if (ret) { | ||
1513 | WARN_ON(1); | ||
1514 | return ret; | ||
1515 | } | ||
1516 | |||
1517 | /* Arbitration Lost occurs, Start recovery */ | ||
1518 | if (i2c_dev->msg_err == I2C_ERR_ARBITRATION_LOST) { | ||
1519 | if (!i2c_dev->is_multimaster_mode) { | ||
1520 | ret = tegra_i2c_issue_bus_clear(i2c_dev); | ||
1521 | if (ret) | ||
1522 | return ret; | ||
1523 | } | ||
1524 | return -EAGAIN; | ||
1525 | } | ||
1526 | |||
1527 | if (i2c_dev->msg_err == I2C_ERR_NO_ACK) | ||
1528 | return -EREMOTEIO; | ||
1529 | |||
1530 | return -EIO; | ||
1531 | } | ||
1532 | |||
1533 | static void tegra_i2c_reg_dump(struct tegra_i2c_dev *i2c_dev, | ||
1534 | struct i2c_msg *msg) | ||
1535 | { | ||
1536 | dev_err(i2c_dev->dev, "--- register dump for debugging ----\n"); | ||
1537 | dev_err(i2c_dev->dev, "I2C_CNFG - 0x%x\n", | ||
1538 | i2c_readl(i2c_dev, I2C_CNFG)); | ||
1539 | dev_err(i2c_dev->dev, "I2C_PACKET_TRANSFER_STATUS - 0x%x\n", | ||
1540 | i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS)); | ||
1541 | dev_err(i2c_dev->dev, "I2C_FIFO_CONTROL - 0x%x\n", | ||
1542 | i2c_readl(i2c_dev, I2C_FIFO_CONTROL)); | ||
1543 | dev_err(i2c_dev->dev, "I2C_FIFO_STATUS - 0x%x\n", | ||
1544 | i2c_readl(i2c_dev, I2C_FIFO_STATUS)); | ||
1545 | dev_err(i2c_dev->dev, "I2C_INT_MASK - 0x%x\n", | ||
1546 | i2c_readl(i2c_dev, I2C_INT_MASK)); | ||
1547 | dev_err(i2c_dev->dev, "I2C_INT_STATUS - 0x%x\n", | ||
1548 | i2c_readl(i2c_dev, I2C_INT_STATUS)); | ||
1549 | dev_err(i2c_dev->dev, "msg->len - %d\n", msg->len); | ||
1550 | dev_err(i2c_dev->dev, "is_msg_write - %d\n", | ||
1551 | !(msg->flags & I2C_M_RD)); | ||
1552 | dev_err(i2c_dev->dev, "buf_remaining - %zd\n", | ||
1553 | i2c_dev->msg_buf_remaining); | ||
1554 | } | ||
1555 | |||
1556 | static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, | ||
1557 | struct i2c_msg *msg, enum msg_end_type end_state) | ||
1558 | { | ||
1559 | u32 int_mask = 0; | ||
1560 | unsigned long time_left; | ||
1561 | int ret; | ||
1562 | |||
1563 | if (msg->len == 0) | ||
1564 | return -EINVAL; | ||
1565 | |||
1566 | if (!i2c_dev->disable_dma_mode && (msg->len > I2C_PIO_MODE_MAX_LEN) | ||
1567 | && !(i2c_dev->tx_dma_chan && i2c_dev->rx_dma_chan)) { | ||
1568 | ret = tegra_i2c_init_dma_param(i2c_dev, true); | ||
1569 | if (ret && (ret != -EPROBE_DEFER) && (ret != -ENODEV)) | ||
1570 | return ret; | ||
1571 | ret = tegra_i2c_init_dma_param(i2c_dev, false); | ||
1572 | if (ret && (ret != -EPROBE_DEFER) && (ret != -ENODEV)) | ||
1573 | return ret; | ||
1574 | } | ||
1575 | |||
1576 | tegra_i2c_pre_xfer_config(i2c_dev, msg); | ||
1577 | |||
1578 | if ((msg->len > I2C_PIO_MODE_MAX_LEN) && i2c_dev->tx_dma_chan | ||
1579 | && i2c_dev->rx_dma_chan) | ||
1580 | ret = tegra_i2c_start_dma_based_xfer(i2c_dev, msg, end_state); | ||
1581 | else | ||
1582 | ret = tegra_i2c_start_pio_based_xfer(i2c_dev, msg, end_state); | ||
1583 | |||
1584 | if (ret) | ||
1585 | return ret; | ||
1586 | |||
1587 | dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n", | ||
1588 | i2c_readl(i2c_dev, I2C_INT_MASK)); | ||
1589 | |||
1590 | if (i2c_dev->is_curr_dma_xfer) { | ||
1591 | if (i2c_dev->curr_direction == DATA_DMA_DIR_TX) { | ||
1592 | time_left = wait_for_completion_timeout( | ||
1593 | &i2c_dev->tx_dma_complete, | ||
1594 | TEGRA_I2C_TIMEOUT); | ||
1595 | if (time_left == 0) { | ||
1596 | dev_err(i2c_dev->dev, "tx dma timeout\n"); | ||
1597 | dmaengine_terminate_all(i2c_dev->tx_dma_chan); | ||
1598 | goto end_xfer; | ||
1599 | } | ||
1600 | } else if (i2c_dev->curr_direction == DATA_DMA_DIR_RX) { | ||
1601 | time_left = wait_for_completion_timeout( | ||
1602 | &i2c_dev->rx_dma_complete, | ||
1603 | TEGRA_I2C_TIMEOUT); | ||
1604 | if (time_left == 0) { | ||
1605 | dev_err(i2c_dev->dev, "rx dma timeout\n"); | ||
1606 | dmaengine_terminate_all(i2c_dev->rx_dma_chan); | ||
1607 | goto end_xfer; | ||
1608 | } | ||
1609 | } | ||
1610 | } | ||
1611 | |||
1612 | time_left = wait_for_completion_timeout(&i2c_dev->msg_complete, | ||
1613 | TEGRA_I2C_TIMEOUT); | ||
1614 | if (time_left == 0) { | ||
1615 | tegra_i2c_reg_dump(i2c_dev, msg); | ||
1616 | if (i2c_dev->is_curr_dma_xfer) { | ||
1617 | if (i2c_dev->curr_direction == DATA_DMA_DIR_TX) | ||
1618 | dmaengine_terminate_all(i2c_dev->tx_dma_chan); | ||
1619 | else if (i2c_dev->curr_direction == DATA_DMA_DIR_RX) | ||
1620 | dmaengine_terminate_all(i2c_dev->rx_dma_chan); | ||
1621 | } | ||
1622 | } | ||
1623 | |||
1624 | end_xfer: | ||
1625 | int_mask = i2c_readl(i2c_dev, I2C_INT_MASK); | ||
1626 | tegra_i2c_mask_irq(i2c_dev, int_mask); | ||
1627 | |||
1628 | if (time_left == 0) { | ||
1629 | dev_err(i2c_dev->dev, | ||
1630 | "i2c transfer timed out, addr 0x%04x, data 0x%02x\n", | ||
1631 | msg->addr, msg->buf[0]); | ||
1632 | |||
1633 | ret = tegra_i2c_init(i2c_dev); | ||
1634 | if (!ret) | ||
1635 | ret = -ETIMEDOUT; | ||
1636 | else | ||
1637 | WARN_ON(1); | ||
1638 | return ret; | ||
1639 | } | ||
1640 | |||
1641 | dev_dbg(i2c_dev->dev, "transfer complete: %d %d %d\n", | ||
1642 | ret, completion_done(&i2c_dev->msg_complete), i2c_dev->msg_err); | ||
1643 | |||
1644 | if (likely(i2c_dev->msg_err == I2C_ERR_NONE)) | ||
1645 | return 0; | ||
1646 | |||
1647 | return tegra_i2c_handle_xfer_error(i2c_dev); | ||
1648 | } | ||
1649 | |||
1650 | static int tegra_i2c_split_i2c_msg_xfer(struct tegra_i2c_dev *i2c_dev, | ||
1651 | struct i2c_msg *msg, enum msg_end_type end_type) | ||
1652 | { | ||
1653 | int size, len, ret; | ||
1654 | struct i2c_msg temp_msg; | ||
1655 | u8 *buf = msg->buf; | ||
1656 | enum msg_end_type temp_end_type; | ||
1657 | |||
1658 | size = msg->len; | ||
1659 | temp_msg.flags = msg->flags; | ||
1660 | temp_msg.addr = msg->addr; | ||
1661 | temp_end_type = end_type; | ||
1662 | do { | ||
1663 | temp_msg.buf = buf; | ||
1664 | len = min(size, I2C_MAX_TRANSFER_LEN); | ||
1665 | temp_msg.len = len; | ||
1666 | size -= len; | ||
1667 | if ((len == I2C_MAX_TRANSFER_LEN) && size) | ||
1668 | end_type = MSG_END_CONTINUE; | ||
1669 | else | ||
1670 | end_type = temp_end_type; | ||
1671 | ret = tegra_i2c_xfer_msg(i2c_dev, &temp_msg, end_type); | ||
1672 | if (ret) | ||
1673 | return ret; | ||
1674 | buf += len; | ||
1675 | } while (size != 0); | ||
1676 | |||
1677 | return ret; | ||
1678 | } | ||
1679 | |||
1680 | static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], | ||
1681 | int num) | ||
1682 | { | ||
1683 | struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap); | ||
1684 | int i; | ||
1685 | int ret = 0; | ||
1686 | |||
1687 | if (i2c_dev->is_suspended) | ||
1688 | return -EBUSY; | ||
1689 | |||
1690 | ret = tegra_i2c_power_enable(i2c_dev); | ||
1691 | if (ret < 0) { | ||
1692 | dev_err(i2c_dev->dev, "Regulator enable failed %d\n", ret); | ||
1693 | return ret; | ||
1694 | } | ||
1695 | |||
1696 | if (i2c_dev->is_shutdown && i2c_dev->bit_banging_xfer_after_shutdown) | ||
1697 | return tegra_i2c_gpio_xfer(adap, msgs, num); | ||
1698 | |||
1699 | pm_runtime_get_sync(&adap->dev); | ||
1700 | ret = tegra_i2c_clock_enable(i2c_dev); | ||
1701 | if (ret < 0) { | ||
1702 | tegra_i2c_power_disable(i2c_dev); | ||
1703 | dev_err(i2c_dev->dev, "Clock enable failed %d\n", ret); | ||
1704 | pm_runtime_put(&adap->dev); | ||
1705 | return ret; | ||
1706 | } | ||
1707 | |||
1708 | if (adap->bus_clk_rate != i2c_dev->bus_clk_rate) { | ||
1709 | i2c_dev->bus_clk_rate = adap->bus_clk_rate; | ||
1710 | ret = tegra_i2c_set_clk_rate(i2c_dev); | ||
1711 | if (ret < 0) | ||
1712 | return ret; | ||
1713 | } | ||
1714 | |||
1715 | for (i = 0; i < num; i++) { | ||
1716 | enum msg_end_type end_type = MSG_END_STOP; | ||
1717 | |||
1718 | if (i < (num - 1)) { | ||
1719 | if (msgs[i + 1].flags & I2C_M_NOSTART) | ||
1720 | end_type = MSG_END_CONTINUE; | ||
1721 | else | ||
1722 | end_type = MSG_END_REPEAT_START; | ||
1723 | } | ||
1724 | if (msgs[i].len > I2C_MAX_TRANSFER_LEN) | ||
1725 | ret = tegra_i2c_split_i2c_msg_xfer(i2c_dev, &msgs[i], | ||
1726 | end_type); | ||
1727 | else | ||
1728 | ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], end_type); | ||
1729 | if (ret) | ||
1730 | break; | ||
1731 | } | ||
1732 | tegra_i2c_clock_disable(i2c_dev); | ||
1733 | tegra_i2c_power_disable(i2c_dev); | ||
1734 | pm_runtime_put(&adap->dev); | ||
1735 | return ret ?: i; | ||
1736 | } | ||
1737 | |||
1738 | static u32 tegra_i2c_func(struct i2c_adapter *adap) | ||
1739 | { | ||
1740 | struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap); | ||
1741 | u32 ret = I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | | ||
1742 | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; | ||
1743 | |||
1744 | if (i2c_dev->hw->has_continue_xfer_support) | ||
1745 | ret |= I2C_FUNC_NOSTART; | ||
1746 | return ret; | ||
1747 | } | ||
1748 | |||
1749 | static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev) | ||
1750 | { | ||
1751 | struct device_node *np = i2c_dev->dev->of_node; | ||
1752 | int ret; | ||
1753 | u32 prop; | ||
1754 | |||
1755 | ret = of_property_read_u32(np, | ||
1756 | "clock-frequency", &i2c_dev->bus_clk_rate); | ||
1757 | if (ret) | ||
1758 | i2c_dev->bus_clk_rate = 100000; /* default clock rate */ | ||
1759 | |||
1760 | i2c_dev->is_multimaster_mode = | ||
1761 | of_property_read_bool(np, "multi-master"); | ||
1762 | |||
1763 | i2c_dev->scl_gpio = of_get_named_gpio(np, "scl-gpio", 0); | ||
1764 | i2c_dev->sda_gpio = of_get_named_gpio(np, "sda-gpio", 0); | ||
1765 | |||
1766 | i2c_dev->bit_banging_xfer_after_shutdown = of_property_read_bool(np, | ||
1767 | "nvidia,bit-banging-xfer-after-shutdown"); | ||
1768 | |||
1769 | ret = of_property_read_u32(np, "nvidia,hs-master-code", &prop); | ||
1770 | if (!ret) | ||
1771 | i2c_dev->hs_master_code = prop; | ||
1772 | |||
1773 | i2c_dev->disable_dma_mode = of_property_read_bool(np, | ||
1774 | "nvidia,disable-dma-mode"); | ||
1775 | |||
1776 | i2c_dev->is_clkon_always = of_property_read_bool(np, | ||
1777 | "nvidia,clock-always-on"); | ||
1778 | } | ||
1779 | |||
1780 | static const struct i2c_algorithm tegra_i2c_algo = { | ||
1781 | .master_xfer = tegra_i2c_xfer, | ||
1782 | .functionality = tegra_i2c_func, | ||
1783 | }; | ||
1784 | |||
1785 | /* payload size is only 12 bit */ | ||
1786 | static struct i2c_adapter_quirks tegra_i2c_quirks = { | ||
1787 | .max_read_len = 4096, | ||
1788 | .max_write_len = 4096, | ||
1789 | }; | ||
1790 | |||
1791 | static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { | ||
1792 | .has_continue_xfer_support = false, | ||
1793 | .has_per_pkt_xfer_complete_irq = false, | ||
1794 | .has_single_clk_source = false, | ||
1795 | .clk_divisor_hs_mode = 3, | ||
1796 | .clk_multiplier_hs_mode = 12, | ||
1797 | .clk_divisor_std_fast_mode = 0, | ||
1798 | .clk_divisor_fast_plus_mode = 0, | ||
1799 | .has_config_load_reg = false, | ||
1800 | .has_multi_master_mode = false, | ||
1801 | .has_slcg_override_reg = false, | ||
1802 | .has_sw_reset_reg = false, | ||
1803 | .has_hw_arb_support = false, | ||
1804 | .has_reg_write_buffering = true, | ||
1805 | .has_slcg_support = false, | ||
1806 | }; | ||
1807 | |||
1808 | static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { | ||
1809 | .has_continue_xfer_support = true, | ||
1810 | .has_per_pkt_xfer_complete_irq = false, | ||
1811 | .has_single_clk_source = false, | ||
1812 | .clk_divisor_hs_mode = 3, | ||
1813 | .clk_multiplier_hs_mode = 12, | ||
1814 | .clk_divisor_std_fast_mode = 0, | ||
1815 | .clk_divisor_fast_plus_mode = 0, | ||
1816 | .has_config_load_reg = false, | ||
1817 | .has_multi_master_mode = false, | ||
1818 | .has_slcg_override_reg = false, | ||
1819 | .has_sw_reset_reg = false, | ||
1820 | .has_hw_arb_support = false, | ||
1821 | .has_reg_write_buffering = true, | ||
1822 | .has_slcg_support = false, | ||
1823 | }; | ||
1824 | |||
1825 | static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { | ||
1826 | .has_continue_xfer_support = true, | ||
1827 | .has_per_pkt_xfer_complete_irq = true, | ||
1828 | .has_single_clk_source = true, | ||
1829 | .clk_divisor_hs_mode = 1, | ||
1830 | .clk_multiplier_hs_mode = 3, | ||
1831 | .clk_divisor_std_fast_mode = 0x19, | ||
1832 | .clk_divisor_fast_plus_mode = 0x10, | ||
1833 | .has_config_load_reg = false, | ||
1834 | .has_multi_master_mode = false, | ||
1835 | .has_slcg_override_reg = false, | ||
1836 | .has_sw_reset_reg = false, | ||
1837 | .has_hw_arb_support = true, | ||
1838 | .has_reg_write_buffering = true, | ||
1839 | .has_slcg_support = false, | ||
1840 | }; | ||
1841 | |||
1842 | static const struct tegra_i2c_hw_feature tegra124_i2c_hw = { | ||
1843 | .has_continue_xfer_support = true, | ||
1844 | .has_per_pkt_xfer_complete_irq = true, | ||
1845 | .has_single_clk_source = true, | ||
1846 | .clk_divisor_hs_mode = 2, | ||
1847 | .clk_multiplier_hs_mode = 13, | ||
1848 | .clk_divisor_std_fast_mode = 0x19, | ||
1849 | .clk_divisor_fast_plus_mode = 0x10, | ||
1850 | .has_config_load_reg = true, | ||
1851 | .has_multi_master_mode = false, | ||
1852 | .has_slcg_override_reg = true, | ||
1853 | .has_sw_reset_reg = false, | ||
1854 | .has_hw_arb_support = true, | ||
1855 | .has_reg_write_buffering = true, | ||
1856 | .has_slcg_support = false, | ||
1857 | }; | ||
1858 | |||
1859 | static const struct tegra_i2c_hw_feature tegra210_i2c_hw = { | ||
1860 | .has_continue_xfer_support = true, | ||
1861 | .has_per_pkt_xfer_complete_irq = true, | ||
1862 | .has_single_clk_source = true, | ||
1863 | .clk_divisor_hs_mode = 2, | ||
1864 | .clk_multiplier_hs_mode = 13, | ||
1865 | .clk_divisor_std_fast_mode = 0x19, | ||
1866 | .clk_divisor_fast_plus_mode = 0x10, | ||
1867 | .has_config_load_reg = true, | ||
1868 | .has_multi_master_mode = true, | ||
1869 | .has_slcg_override_reg = true, | ||
1870 | .has_sw_reset_reg = false, | ||
1871 | .has_hw_arb_support = true, | ||
1872 | .has_reg_write_buffering = true, | ||
1873 | .has_slcg_support = false, | ||
1874 | }; | ||
1875 | |||
1876 | static const struct tegra_i2c_hw_feature tegra210_vii2c_hw = { | ||
1877 | .has_continue_xfer_support = true, | ||
1878 | .has_per_pkt_xfer_complete_irq = true, | ||
1879 | .has_single_clk_source = true, | ||
1880 | .clk_divisor_hs_mode = 2, | ||
1881 | .clk_multiplier_hs_mode = 13, | ||
1882 | .clk_divisor_std_fast_mode = 0x19, | ||
1883 | .clk_divisor_fast_plus_mode = 0x10, | ||
1884 | .has_config_load_reg = true, | ||
1885 | .has_multi_master_mode = true, | ||
1886 | .has_slcg_override_reg = true, | ||
1887 | .has_sw_reset_reg = false, | ||
1888 | .has_hw_arb_support = true, | ||
1889 | .has_reg_write_buffering = true, | ||
1890 | .has_slcg_support = false, | ||
1891 | .has_regulator = true, | ||
1892 | .has_powergate = true, | ||
1893 | .powergate_id = TEGRA210_POWER_DOMAIN_VENC, | ||
1894 | .is_vi = true, | ||
1895 | }; | ||
1896 | |||
1897 | static const struct tegra_i2c_hw_feature tegra186_i2c_hw = { | ||
1898 | .has_continue_xfer_support = true, | ||
1899 | .has_per_pkt_xfer_complete_irq = true, | ||
1900 | .has_single_clk_source = true, | ||
1901 | .clk_divisor_hs_mode = 2, | ||
1902 | .clk_multiplier_hs_mode = 13, | ||
1903 | .clk_divisor_std_fast_mode = 0x19, | ||
1904 | .clk_divisor_fast_plus_mode = 0x10, | ||
1905 | .has_config_load_reg = true, | ||
1906 | .has_multi_master_mode = true, | ||
1907 | .has_slcg_override_reg = true, | ||
1908 | .has_sw_reset_reg = true, | ||
1909 | .has_hw_arb_support = true, | ||
1910 | .has_reg_write_buffering = false, | ||
1911 | .has_slcg_support = true, | ||
1912 | }; | ||
1913 | |||
1914 | /* Match table for of_platform binding */ | ||
1915 | static const struct of_device_id tegra_i2c_of_match[] = { | ||
1916 | { .compatible = "nvidia,tegra210-vii2c", | ||
1917 | .data = &tegra210_vii2c_hw, }, | ||
1918 | {}, | ||
1919 | }; | ||
1920 | MODULE_DEVICE_TABLE(of, tegra_i2c_of_match); | ||
1921 | |||
1922 | static int tegra_i2c_probe(struct platform_device *pdev) | ||
1923 | { | ||
1924 | struct tegra_i2c_dev *i2c_dev; | ||
1925 | struct resource *res; | ||
1926 | struct clk *div_clk; | ||
1927 | struct clk *fast_clk; | ||
1928 | void __iomem *base; | ||
1929 | phys_addr_t phys_addr; | ||
1930 | int irq; | ||
1931 | int ret = 0; | ||
1932 | |||
1933 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1934 | phys_addr = res->start; | ||
1935 | base = devm_ioremap_resource(&pdev->dev, res); | ||
1936 | if (IS_ERR(base)) | ||
1937 | return PTR_ERR(base); | ||
1938 | |||
1939 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
1940 | if (!res) { | ||
1941 | dev_err(&pdev->dev, "no irq resource\n"); | ||
1942 | return -EINVAL; | ||
1943 | } | ||
1944 | irq = res->start; | ||
1945 | |||
1946 | div_clk = devm_clk_get(&pdev->dev, "vii2c"); | ||
1947 | if (IS_ERR(div_clk)) { | ||
1948 | dev_err(&pdev->dev, "missing controller clock"); | ||
1949 | return PTR_ERR(div_clk); | ||
1950 | } | ||
1951 | |||
1952 | i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); | ||
1953 | if (!i2c_dev) | ||
1954 | return -ENOMEM; | ||
1955 | |||
1956 | i2c_dev->base = base; | ||
1957 | i2c_dev->phys_addr = phys_addr; | ||
1958 | i2c_dev->div_clk = div_clk; | ||
1959 | i2c_dev->adapter.algo = &tegra_i2c_algo; | ||
1960 | i2c_dev->adapter.quirks = &tegra_i2c_quirks; | ||
1961 | i2c_dev->irq = irq; | ||
1962 | i2c_dev->dev = &pdev->dev; | ||
1963 | i2c_dev->dma_buf_size = I2C_DMA_MAX_BUF_LEN; | ||
1964 | |||
1965 | i2c_dev->rst = devm_reset_control_get(&pdev->dev, "vii2c"); | ||
1966 | if (IS_ERR(i2c_dev->rst)) { | ||
1967 | dev_err(&pdev->dev, "missing controller reset"); | ||
1968 | return PTR_ERR(i2c_dev->rst); | ||
1969 | } | ||
1970 | |||
1971 | tegra_i2c_parse_dt(i2c_dev); | ||
1972 | |||
1973 | i2c_dev->hw = &tegra20_i2c_hw; | ||
1974 | |||
1975 | if (pdev->dev.of_node) { | ||
1976 | const struct of_device_id *match; | ||
1977 | |||
1978 | match = of_match_device(tegra_i2c_of_match, &pdev->dev); | ||
1979 | i2c_dev->hw = match->data; | ||
1980 | i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node, | ||
1981 | "nvidia,tegra20-i2c-dvc"); | ||
1982 | } else if (pdev->id == 3) { | ||
1983 | i2c_dev->is_dvc = 1; | ||
1984 | } | ||
1985 | init_completion(&i2c_dev->msg_complete); | ||
1986 | init_completion(&i2c_dev->tx_dma_complete); | ||
1987 | init_completion(&i2c_dev->rx_dma_complete); | ||
1988 | |||
1989 | if (!i2c_dev->hw->has_single_clk_source) { | ||
1990 | fast_clk = devm_clk_get(&pdev->dev, "fast-clk"); | ||
1991 | if (IS_ERR(fast_clk)) { | ||
1992 | dev_err(&pdev->dev, "missing fast clock"); | ||
1993 | return PTR_ERR(fast_clk); | ||
1994 | } | ||
1995 | i2c_dev->fast_clk = fast_clk; | ||
1996 | } | ||
1997 | |||
1998 | if (i2c_dev->hw->is_vi) { | ||
1999 | i2c_dev->slow_clk = devm_clk_get(&pdev->dev, "i2cslow"); | ||
2000 | if (IS_ERR(i2c_dev->slow_clk)) { | ||
2001 | dev_err(&pdev->dev, "missing slow clock"); | ||
2002 | return PTR_ERR(i2c_dev->slow_clk); | ||
2003 | } | ||
2004 | i2c_dev->host1x_clk = devm_clk_get(&pdev->dev, "host1x"); | ||
2005 | if (IS_ERR(i2c_dev->host1x_clk)) { | ||
2006 | dev_err(&pdev->dev, "missing host1x clock"); | ||
2007 | return PTR_ERR(i2c_dev->host1x_clk); | ||
2008 | } | ||
2009 | } | ||
2010 | |||
2011 | if (i2c_dev->hw->has_regulator) { | ||
2012 | i2c_dev->reg = devm_regulator_get(&pdev->dev, "avdd_dsi_csi"); | ||
2013 | if (IS_ERR(i2c_dev->reg)) { | ||
2014 | dev_err(&pdev->dev, "could not get regulator"); | ||
2015 | return PTR_ERR(i2c_dev->reg); | ||
2016 | } | ||
2017 | } | ||
2018 | |||
2019 | spin_lock_init(&i2c_dev->xfer_lock); | ||
2020 | |||
2021 | i2c_dev->prod_list = devm_tegra_prod_get(&pdev->dev); | ||
2022 | if (IS_ERR_OR_NULL(i2c_dev->prod_list)) { | ||
2023 | dev_dbg(&pdev->dev, "Prod-setting not available\n"); | ||
2024 | i2c_dev->prod_list = NULL; | ||
2025 | } | ||
2026 | |||
2027 | platform_set_drvdata(pdev, i2c_dev); | ||
2028 | |||
2029 | if (!i2c_dev->hw->has_single_clk_source) { | ||
2030 | ret = clk_prepare(i2c_dev->fast_clk); | ||
2031 | if (ret < 0) { | ||
2032 | dev_err(i2c_dev->dev, "Clock prepare failed %d\n", ret); | ||
2033 | return ret; | ||
2034 | } | ||
2035 | } | ||
2036 | |||
2037 | i2c_dev->clk_divisor_non_hs_mode = | ||
2038 | i2c_dev->hw->clk_divisor_std_fast_mode; | ||
2039 | if (i2c_dev->hw->clk_divisor_fast_plus_mode && | ||
2040 | (i2c_dev->bus_clk_rate == I2C_FAST_MODE_PLUS)) | ||
2041 | i2c_dev->clk_divisor_non_hs_mode = | ||
2042 | i2c_dev->hw->clk_divisor_fast_plus_mode; | ||
2043 | |||
2044 | ret = tegra_i2c_set_clk_rate(i2c_dev); | ||
2045 | if (ret < 0) | ||
2046 | return ret; | ||
2047 | |||
2048 | ret = clk_prepare(i2c_dev->div_clk); | ||
2049 | if (ret < 0) { | ||
2050 | dev_err(i2c_dev->dev, "Clock prepare failed %d\n", ret); | ||
2051 | goto unprepare_fast_clk; | ||
2052 | } | ||
2053 | |||
2054 | if (!i2c_dev->hw->has_powergate) { | ||
2055 | ret = tegra_i2c_init(i2c_dev); | ||
2056 | if (ret) { | ||
2057 | dev_err(&pdev->dev, "Failed to initialize i2c controller"); | ||
2058 | goto unprepare_div_clk; | ||
2059 | } | ||
2060 | } | ||
2061 | |||
2062 | if (i2c_dev->is_multimaster_mode || i2c_dev->hw->has_slcg_support) | ||
2063 | i2c_dev->is_clkon_always = true; | ||
2064 | |||
2065 | if (i2c_dev->is_clkon_always) { | ||
2066 | ret = tegra_i2c_clock_enable(i2c_dev); | ||
2067 | if (ret < 0) { | ||
2068 | dev_err(i2c_dev->dev, "div_clk enable failed %d\n", | ||
2069 | ret); | ||
2070 | goto unprepare_div_clk; | ||
2071 | } | ||
2072 | } | ||
2073 | |||
2074 | if (!i2c_dev->disable_dma_mode) { | ||
2075 | ret = tegra_i2c_init_dma_param(i2c_dev, true); | ||
2076 | if (ret && (ret != -EPROBE_DEFER) && (ret != -ENODEV)) | ||
2077 | goto disable_clk; | ||
2078 | ret = tegra_i2c_init_dma_param(i2c_dev, false); | ||
2079 | if (ret && (ret != -EPROBE_DEFER) && (ret != -ENODEV)) | ||
2080 | goto disable_clk; | ||
2081 | } | ||
2082 | |||
2083 | ret = devm_request_irq(&pdev->dev, i2c_dev->irq, | ||
2084 | tegra_i2c_isr, 0, dev_name(&pdev->dev), i2c_dev); | ||
2085 | if (ret) { | ||
2086 | dev_err(&pdev->dev, "Failed to request irq %i\n", i2c_dev->irq); | ||
2087 | goto disable_clk; | ||
2088 | } | ||
2089 | |||
2090 | pm_runtime_enable(&pdev->dev); | ||
2091 | i2c_set_adapdata(&i2c_dev->adapter, i2c_dev); | ||
2092 | i2c_dev->adapter.owner = THIS_MODULE; | ||
2093 | i2c_dev->adapter.class = I2C_CLASS_DEPRECATED; | ||
2094 | strlcpy(i2c_dev->adapter.name, "Tegra I2C adapter", | ||
2095 | sizeof(i2c_dev->adapter.name)); | ||
2096 | i2c_dev->adapter.bus_clk_rate = i2c_dev->bus_clk_rate; | ||
2097 | i2c_dev->adapter.dev.parent = &pdev->dev; | ||
2098 | i2c_dev->adapter.nr = pdev->id; | ||
2099 | i2c_dev->adapter.dev.of_node = pdev->dev.of_node; | ||
2100 | i2c_dev->bri.scl_gpio = i2c_dev->scl_gpio; | ||
2101 | i2c_dev->bri.sda_gpio = i2c_dev->sda_gpio; | ||
2102 | i2c_dev->bri.recover_bus = i2c_generic_gpio_recovery; | ||
2103 | i2c_dev->adapter.bus_recovery_info = &i2c_dev->bri; | ||
2104 | |||
2105 | ret = i2c_add_numbered_adapter(&i2c_dev->adapter); | ||
2106 | if (ret) { | ||
2107 | dev_err(&pdev->dev, "Failed to add I2C adapter\n"); | ||
2108 | goto disable_clk; | ||
2109 | } | ||
2110 | i2c_dev->cont_id = i2c_dev->adapter.nr & PACKET_HEADER0_CONT_ID_MASK; | ||
2111 | pm_runtime_enable(&i2c_dev->adapter.dev); | ||
2112 | tegra_i2c_gpio_init(i2c_dev); | ||
2113 | |||
2114 | return 0; | ||
2115 | |||
2116 | disable_clk: | ||
2117 | tegra_i2c_clock_disable(i2c_dev); | ||
2118 | |||
2119 | unprepare_div_clk: | ||
2120 | clk_unprepare(i2c_dev->div_clk); | ||
2121 | |||
2122 | unprepare_fast_clk: | ||
2123 | if (!i2c_dev->hw->has_single_clk_source) | ||
2124 | clk_unprepare(i2c_dev->fast_clk); | ||
2125 | |||
2126 | return ret; | ||
2127 | } | ||
2128 | |||
2129 | static int tegra_i2c_remove(struct platform_device *pdev) | ||
2130 | { | ||
2131 | struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev); | ||
2132 | |||
2133 | i2c_del_adapter(&i2c_dev->adapter); | ||
2134 | pm_runtime_disable(&i2c_dev->adapter.dev); | ||
2135 | |||
2136 | if (i2c_dev->tx_dma_chan) | ||
2137 | tegra_i2c_deinit_dma_param(i2c_dev, false); | ||
2138 | if (i2c_dev->rx_dma_chan) | ||
2139 | tegra_i2c_deinit_dma_param(i2c_dev, true); | ||
2140 | |||
2141 | if (i2c_dev->is_clkon_always) | ||
2142 | tegra_i2c_clock_disable(i2c_dev); | ||
2143 | pm_runtime_disable(&pdev->dev); | ||
2144 | |||
2145 | clk_unprepare(i2c_dev->div_clk); | ||
2146 | if (!i2c_dev->hw->has_single_clk_source) | ||
2147 | clk_unprepare(i2c_dev->fast_clk); | ||
2148 | |||
2149 | return 0; | ||
2150 | } | ||
2151 | |||
2152 | static void tegra_i2c_shutdown(struct platform_device *pdev) | ||
2153 | { | ||
2154 | struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev); | ||
2155 | |||
2156 | dev_info(i2c_dev->dev, "Bus is shutdown down..\n"); | ||
2157 | i2c_shutdown_adapter(&i2c_dev->adapter); | ||
2158 | i2c_dev->is_shutdown = true; | ||
2159 | } | ||
2160 | |||
2161 | #ifdef CONFIG_PM_SLEEP | ||
2162 | static int tegra_i2c_suspend(struct device *dev) | ||
2163 | { | ||
2164 | struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); | ||
2165 | |||
2166 | i2c_lock_adapter(&i2c_dev->adapter); | ||
2167 | i2c_dev->is_suspended = true; | ||
2168 | |||
2169 | if (i2c_dev->is_clkon_always) | ||
2170 | tegra_i2c_clock_disable(i2c_dev); | ||
2171 | |||
2172 | i2c_unlock_adapter(&i2c_dev->adapter); | ||
2173 | |||
2174 | return 0; | ||
2175 | } | ||
2176 | |||
2177 | static int tegra_i2c_resume(struct device *dev) | ||
2178 | { | ||
2179 | struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); | ||
2180 | int ret; | ||
2181 | |||
2182 | i2c_lock_adapter(&i2c_dev->adapter); | ||
2183 | |||
2184 | if (!i2c_dev->hw->has_powergate) { | ||
2185 | ret = tegra_i2c_init(i2c_dev); | ||
2186 | if (ret) { | ||
2187 | i2c_unlock_adapter(&i2c_dev->adapter); | ||
2188 | return ret; | ||
2189 | } | ||
2190 | } | ||
2191 | |||
2192 | if (i2c_dev->is_clkon_always) { | ||
2193 | ret = tegra_i2c_clock_enable(i2c_dev); | ||
2194 | if (ret < 0) { | ||
2195 | dev_err(i2c_dev->dev, "clock enable failed %d\n", | ||
2196 | ret); | ||
2197 | return ret; | ||
2198 | } | ||
2199 | } | ||
2200 | i2c_dev->is_suspended = false; | ||
2201 | i2c_unlock_adapter(&i2c_dev->adapter); | ||
2202 | |||
2203 | return 0; | ||
2204 | } | ||
2205 | |||
2206 | static SIMPLE_DEV_PM_OPS(tegra_i2c_pm, tegra_i2c_suspend, tegra_i2c_resume); | ||
2207 | #define TEGRA_I2C_PM (&tegra_i2c_pm) | ||
2208 | #else | ||
2209 | #define TEGRA_I2C_PM NULL | ||
2210 | #endif | ||
2211 | |||
2212 | static struct platform_driver tegra_i2c_driver = { | ||
2213 | .probe = tegra_i2c_probe, | ||
2214 | .remove = tegra_i2c_remove, | ||
2215 | .late_shutdown = tegra_i2c_shutdown, | ||
2216 | .driver = { | ||
2217 | .name = "tegra-vii2c", | ||
2218 | .of_match_table = tegra_i2c_of_match, | ||
2219 | .pm = TEGRA_I2C_PM, | ||
2220 | }, | ||
2221 | }; | ||
2222 | |||
2223 | static int __init tegra_i2c_init_driver(void) | ||
2224 | { | ||
2225 | return platform_driver_register(&tegra_i2c_driver); | ||
2226 | } | ||
2227 | |||
2228 | static void __exit tegra_i2c_exit_driver(void) | ||
2229 | { | ||
2230 | platform_driver_unregister(&tegra_i2c_driver); | ||
2231 | } | ||
2232 | |||
2233 | subsys_initcall(tegra_i2c_init_driver); | ||
2234 | module_exit(tegra_i2c_exit_driver); | ||
2235 | |||
2236 | MODULE_DESCRIPTION("nVidia Tegra2 I2C Bus Controller driver"); | ||
2237 | MODULE_AUTHOR("Colin Cross"); | ||
2238 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/i2c/imx185.c b/drivers/media/i2c/imx185.c new file mode 100644 index 000000000..2dbd79d41 --- /dev/null +++ b/drivers/media/i2c/imx185.c | |||
@@ -0,0 +1,1125 @@ | |||
1 | /* | ||
2 | * imx185.c - imx185 sensor driver | ||
3 | * | ||
4 | * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <linux/slab.h> | ||
20 | #include <linux/uaccess.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/module.h> | ||
23 | |||
24 | #include <linux/seq_file.h> | ||
25 | #include <linux/of.h> | ||
26 | #include <linux/of_device.h> | ||
27 | #include <linux/of_gpio.h> | ||
28 | |||
29 | #include <media/tegra_v4l2_camera.h> | ||
30 | #include <media/camera_common.h> | ||
31 | #include "imx185_mode_tbls.h" | ||
32 | |||
33 | #define IMX185_DEFAULT_MODE IMX185_MODE_1920X1080_CROP_30FPS | ||
34 | #define IMX185_DEFAULT_DATAFMT MEDIA_BUS_FMT_SRGGB12_1X12 | ||
35 | |||
36 | #define IMX185_MIN_FRAME_LENGTH (1125) | ||
37 | #define IMX185_MAX_FRAME_LENGTH (0x1FFFF) | ||
38 | #define IMX185_MIN_SHS1_1080P_HDR (5) | ||
39 | #define IMX185_MIN_SHS2_1080P_HDR (82) | ||
40 | #define IMX185_MAX_SHS2_1080P_HDR (IMX185_MAX_FRAME_LENGTH - 5) | ||
41 | #define IMX185_MAX_SHS1_1080P_HDR (IMX185_MAX_SHS2_1080P_HDR / 16) | ||
42 | |||
43 | #define IMX185_FRAME_LENGTH_ADDR_MSB 0x301A | ||
44 | #define IMX185_FRAME_LENGTH_ADDR_MID 0x3019 | ||
45 | #define IMX185_FRAME_LENGTH_ADDR_LSB 0x3018 | ||
46 | #define IMX185_COARSE_TIME_SHS1_ADDR_MSB 0x3022 | ||
47 | #define IMX185_COARSE_TIME_SHS1_ADDR_MID 0x3021 | ||
48 | #define IMX185_COARSE_TIME_SHS1_ADDR_LSB 0x3020 | ||
49 | #define IMX185_COARSE_TIME_SHS2_ADDR_MSB 0x3025 | ||
50 | #define IMX185_COARSE_TIME_SHS2_ADDR_MID 0x3024 | ||
51 | #define IMX185_COARSE_TIME_SHS2_ADDR_LSB 0x3023 | ||
52 | #define IMX185_GAIN_ADDR 0x3014 | ||
53 | #define IMX185_GROUP_HOLD_ADDR 0x3001 | ||
54 | #define IMX185_SW_RESET_ADDR 0x3003 | ||
55 | |||
56 | #define IMX185_FUSE_ID_ADDR 0x3382 | ||
57 | #define IMX185_FUSE_ID_SIZE 6 | ||
58 | #define IMX185_FUSE_ID_STR_SIZE (IMX185_FUSE_ID_SIZE * 2) | ||
59 | #define IMX185_DEFAULT_WIDTH 1920 | ||
60 | #define IMX185_DEFAULT_HEIGHT 1080 | ||
61 | #define IMX185_DEFAULT_CLK_FREQ 37125000 | ||
62 | |||
63 | struct imx185 { | ||
64 | struct camera_common_power_rail power; | ||
65 | int numctrls; | ||
66 | struct v4l2_ctrl_handler ctrl_handler; | ||
67 | struct i2c_client *i2c_client; | ||
68 | struct v4l2_subdev *subdev; | ||
69 | struct media_pad pad; | ||
70 | u32 frame_length; | ||
71 | s32 group_hold_prev; | ||
72 | bool group_hold_en; | ||
73 | s64 last_wdr_et_val; | ||
74 | struct regmap *regmap; | ||
75 | struct camera_common_data *s_data; | ||
76 | struct camera_common_pdata *pdata; | ||
77 | struct v4l2_ctrl *ctrls[]; | ||
78 | }; | ||
79 | |||
80 | static const struct regmap_config sensor_regmap_config = { | ||
81 | .reg_bits = 16, | ||
82 | .val_bits = 8, | ||
83 | .cache_type = REGCACHE_RBTREE, | ||
84 | .use_single_rw = true, | ||
85 | }; | ||
86 | |||
87 | static int imx185_g_volatile_ctrl(struct v4l2_ctrl *ctrl); | ||
88 | static int imx185_s_ctrl(struct v4l2_ctrl *ctrl); | ||
89 | |||
90 | static const struct v4l2_ctrl_ops imx185_ctrl_ops = { | ||
91 | .g_volatile_ctrl = imx185_g_volatile_ctrl, | ||
92 | .s_ctrl = imx185_s_ctrl, | ||
93 | }; | ||
94 | |||
95 | static struct v4l2_ctrl_config ctrl_config_list[] = { | ||
96 | /* Do not change the name field for the controls! */ | ||
97 | { | ||
98 | .ops = &imx185_ctrl_ops, | ||
99 | .id = V4L2_CID_GAIN, | ||
100 | .name = "Gain", | ||
101 | .type = V4L2_CTRL_TYPE_INTEGER64, | ||
102 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
103 | .min = 0 * FIXED_POINT_SCALING_FACTOR, | ||
104 | .max = 48 * FIXED_POINT_SCALING_FACTOR, | ||
105 | .def = 0 * FIXED_POINT_SCALING_FACTOR, | ||
106 | .step = 1, | ||
107 | }, | ||
108 | { | ||
109 | .ops = &imx185_ctrl_ops, | ||
110 | .id = V4L2_CID_EXPOSURE, | ||
111 | .name = "Exposure", | ||
112 | .type = V4L2_CTRL_TYPE_INTEGER64, | ||
113 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
114 | .min = 30 * FIXED_POINT_SCALING_FACTOR / 1000000, | ||
115 | .max = 1000000LL * FIXED_POINT_SCALING_FACTOR / 1000000, | ||
116 | .def = 30 * FIXED_POINT_SCALING_FACTOR / 1000000, | ||
117 | .step = 1, | ||
118 | }, | ||
119 | { | ||
120 | .ops = &imx185_ctrl_ops, | ||
121 | .id = V4L2_CID_FRAME_RATE, | ||
122 | .name = "Frame Rate", | ||
123 | .type = V4L2_CTRL_TYPE_INTEGER64, | ||
124 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
125 | .min = 1 * FIXED_POINT_SCALING_FACTOR, | ||
126 | .max = 60 * FIXED_POINT_SCALING_FACTOR, | ||
127 | .def = 30 * FIXED_POINT_SCALING_FACTOR, | ||
128 | .step = 1, | ||
129 | }, | ||
130 | { | ||
131 | .ops = &imx185_ctrl_ops, | ||
132 | .id = V4L2_CID_GROUP_HOLD, | ||
133 | .name = "Group Hold", | ||
134 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, | ||
135 | .min = 0, | ||
136 | .max = ARRAY_SIZE(switch_ctrl_qmenu) - 1, | ||
137 | .menu_skip_mask = 0, | ||
138 | .def = 0, | ||
139 | .qmenu_int = switch_ctrl_qmenu, | ||
140 | }, | ||
141 | { | ||
142 | .ops = &imx185_ctrl_ops, | ||
143 | .id = V4L2_CID_HDR_EN, | ||
144 | .name = "HDR enable", | ||
145 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, | ||
146 | .min = 0, | ||
147 | .max = ARRAY_SIZE(switch_ctrl_qmenu) - 1, | ||
148 | .menu_skip_mask = 0, | ||
149 | .def = 0, | ||
150 | .qmenu_int = switch_ctrl_qmenu, | ||
151 | }, | ||
152 | { | ||
153 | .ops = &imx185_ctrl_ops, | ||
154 | .id = V4L2_CID_FUSE_ID, | ||
155 | .name = "Fuse ID", | ||
156 | .type = V4L2_CTRL_TYPE_STRING, | ||
157 | .flags = V4L2_CTRL_FLAG_READ_ONLY, | ||
158 | .min = 0, | ||
159 | .max = IMX185_FUSE_ID_STR_SIZE, | ||
160 | .step = 2, | ||
161 | }, | ||
162 | { | ||
163 | .ops = &imx185_ctrl_ops, | ||
164 | .id = V4L2_CID_SENSOR_MODE_ID, | ||
165 | .name = "Sensor Mode", | ||
166 | .type = V4L2_CTRL_TYPE_INTEGER64, | ||
167 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
168 | .min = 0, | ||
169 | .max = 0xFF, | ||
170 | .def = 0xFE, | ||
171 | .step = 1, | ||
172 | }, | ||
173 | }; | ||
174 | |||
175 | static inline void imx185_get_frame_length_regs(imx185_reg *regs, | ||
176 | u32 frame_length) | ||
177 | { | ||
178 | regs->addr = IMX185_FRAME_LENGTH_ADDR_MSB; | ||
179 | regs->val = (frame_length >> 16) & 0x01; | ||
180 | |||
181 | (regs + 1)->addr = IMX185_FRAME_LENGTH_ADDR_MID; | ||
182 | (regs + 1)->val = (frame_length >> 8) & 0xff; | ||
183 | |||
184 | (regs + 2)->addr = IMX185_FRAME_LENGTH_ADDR_LSB; | ||
185 | (regs + 2)->val = (frame_length) & 0xff; | ||
186 | } | ||
187 | |||
188 | static inline void imx185_get_coarse_time_regs_shs1(imx185_reg *regs, | ||
189 | u32 coarse_time) | ||
190 | { | ||
191 | regs->addr = IMX185_COARSE_TIME_SHS1_ADDR_MSB; | ||
192 | regs->val = (coarse_time >> 16) & 0x01; | ||
193 | |||
194 | (regs + 1)->addr = IMX185_COARSE_TIME_SHS1_ADDR_MID; | ||
195 | (regs + 1)->val = (coarse_time >> 8) & 0xff; | ||
196 | |||
197 | (regs + 2)->addr = IMX185_COARSE_TIME_SHS1_ADDR_LSB; | ||
198 | (regs + 2)->val = (coarse_time) & 0xff; | ||
199 | |||
200 | } | ||
201 | |||
202 | static inline void imx185_get_coarse_time_regs_shs2(imx185_reg *regs, | ||
203 | u32 coarse_time) | ||
204 | { | ||
205 | regs->addr = IMX185_COARSE_TIME_SHS2_ADDR_MSB; | ||
206 | regs->val = (coarse_time >> 16) & 0x01; | ||
207 | |||
208 | (regs + 1)->addr = IMX185_COARSE_TIME_SHS2_ADDR_MID; | ||
209 | (regs + 1)->val = (coarse_time >> 8) & 0xff; | ||
210 | |||
211 | (regs + 2)->addr = IMX185_COARSE_TIME_SHS2_ADDR_LSB; | ||
212 | (regs + 2)->val = (coarse_time) & 0xff; | ||
213 | |||
214 | } | ||
215 | |||
216 | static inline void imx185_get_gain_reg(imx185_reg *regs, | ||
217 | u8 gain) | ||
218 | { | ||
219 | regs->addr = IMX185_GAIN_ADDR; | ||
220 | regs->val = (gain) & 0xff; | ||
221 | } | ||
222 | |||
223 | static int test_mode; | ||
224 | module_param(test_mode, int, 0644); | ||
225 | |||
226 | static inline int imx185_read_reg(struct camera_common_data *s_data, | ||
227 | u16 addr, u8 *val) | ||
228 | { | ||
229 | struct imx185 *priv = (struct imx185 *)s_data->priv; | ||
230 | |||
231 | return regmap_read(priv->regmap, addr, (unsigned int *) val); | ||
232 | } | ||
233 | |||
234 | static int imx185_write_reg(struct camera_common_data *s_data, | ||
235 | u16 addr, u8 val) | ||
236 | { | ||
237 | int err; | ||
238 | struct imx185 *priv = (struct imx185 *)s_data->priv; | ||
239 | |||
240 | err = regmap_write(priv->regmap, addr, val); | ||
241 | if (err) | ||
242 | pr_err("%s:i2c write failed, 0x%x = %x\n", | ||
243 | __func__, addr, val); | ||
244 | |||
245 | return err; | ||
246 | } | ||
247 | |||
248 | static int imx185_write_table(struct imx185 *priv, | ||
249 | const imx185_reg table[]) | ||
250 | { | ||
251 | return regmap_util_write_table_8(priv->regmap, | ||
252 | table, | ||
253 | NULL, 0, | ||
254 | IMX185_TABLE_WAIT_MS, | ||
255 | IMX185_TABLE_END); | ||
256 | } | ||
257 | |||
258 | static int imx185_power_on(struct camera_common_data *s_data) | ||
259 | { | ||
260 | int err = 0; | ||
261 | struct imx185 *priv = (struct imx185 *)s_data->priv; | ||
262 | struct camera_common_power_rail *pw = &priv->power; | ||
263 | |||
264 | dev_dbg(&priv->i2c_client->dev, "%s: power on\n", __func__); | ||
265 | if (priv->pdata && priv->pdata->power_on) { | ||
266 | err = priv->pdata->power_on(pw); | ||
267 | if (err) | ||
268 | pr_err("%s failed.\n", __func__); | ||
269 | else | ||
270 | pw->state = SWITCH_ON; | ||
271 | return err; | ||
272 | } | ||
273 | |||
274 | /*exit reset mode: XCLR */ | ||
275 | if (pw->reset_gpio) { | ||
276 | gpio_set_value(pw->reset_gpio, 0); | ||
277 | usleep_range(30, 50); | ||
278 | gpio_set_value(pw->reset_gpio, 1); | ||
279 | usleep_range(30, 50); | ||
280 | } | ||
281 | |||
282 | pw->state = SWITCH_ON; | ||
283 | return 0; | ||
284 | |||
285 | } | ||
286 | |||
287 | static int imx185_power_off(struct camera_common_data *s_data) | ||
288 | { | ||
289 | int err = 0; | ||
290 | struct imx185 *priv = (struct imx185 *)s_data->priv; | ||
291 | struct camera_common_power_rail *pw = &priv->power; | ||
292 | |||
293 | dev_dbg(&priv->i2c_client->dev, "%s: power off\n", __func__); | ||
294 | |||
295 | if (priv->pdata && priv->pdata->power_off) { | ||
296 | err = priv->pdata->power_off(pw); | ||
297 | if (!err) | ||
298 | goto power_off_done; | ||
299 | else | ||
300 | pr_err("%s failed.\n", __func__); | ||
301 | return err; | ||
302 | } | ||
303 | /* enter reset mode: XCLR */ | ||
304 | usleep_range(1, 2); | ||
305 | if (pw->reset_gpio) | ||
306 | gpio_set_value(pw->reset_gpio, 0); | ||
307 | |||
308 | power_off_done: | ||
309 | pw->state = SWITCH_OFF; | ||
310 | |||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static int imx185_power_get(struct imx185 *priv) | ||
315 | { | ||
316 | struct camera_common_power_rail *pw = &priv->power; | ||
317 | struct camera_common_pdata *pdata = priv->pdata; | ||
318 | const char *mclk_name; | ||
319 | struct clk *parent; | ||
320 | int err = 0; | ||
321 | |||
322 | mclk_name = priv->pdata->mclk_name ? | ||
323 | priv->pdata->mclk_name : "extperiph1"; | ||
324 | pw->mclk = devm_clk_get(&priv->i2c_client->dev, mclk_name); | ||
325 | if (IS_ERR(pw->mclk)) { | ||
326 | dev_err(&priv->i2c_client->dev, | ||
327 | "unable to get clock %s\n", mclk_name); | ||
328 | return PTR_ERR(pw->mclk); | ||
329 | } | ||
330 | |||
331 | parent = devm_clk_get(&priv->i2c_client->dev, "pllp_grtba"); | ||
332 | if (IS_ERR(parent)) | ||
333 | dev_err(&priv->i2c_client->dev, "devm_clk_get failed for pllp_grtba"); | ||
334 | else | ||
335 | clk_set_parent(pw->mclk, parent); | ||
336 | |||
337 | pw->reset_gpio = pdata->reset_gpio; | ||
338 | |||
339 | pw->state = SWITCH_OFF; | ||
340 | return err; | ||
341 | } | ||
342 | |||
343 | static int imx185_set_coarse_time(struct imx185 *priv, s64 val); | ||
344 | static int imx185_set_coarse_time_hdr(struct imx185 *priv, s64 val); | ||
345 | static int imx185_set_gain(struct imx185 *priv, s64 val); | ||
346 | static int imx185_set_frame_rate(struct imx185 *priv, s64 val); | ||
347 | static int imx185_set_exposure(struct imx185 *priv, s64 val); | ||
348 | |||
349 | static int imx185_s_stream(struct v4l2_subdev *sd, int enable) | ||
350 | { | ||
351 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
352 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
353 | struct imx185 *priv = (struct imx185 *)s_data->priv; | ||
354 | struct v4l2_ext_controls ctrls; | ||
355 | struct v4l2_ext_control control[3]; | ||
356 | int err; | ||
357 | |||
358 | dev_dbg(&client->dev, "%s++ enable %d\n", __func__, enable); | ||
359 | |||
360 | if (!enable) { | ||
361 | err = imx185_write_table(priv, | ||
362 | mode_table[IMX185_MODE_STOP_STREAM]); | ||
363 | |||
364 | if (err) | ||
365 | return err; | ||
366 | |||
367 | /* SW_RESET will have no ACK */ | ||
368 | regmap_write(priv->regmap, IMX185_SW_RESET_ADDR, 0x01); | ||
369 | |||
370 | /* Wait for one frame to make sure sensor is set to | ||
371 | * software standby in V-blank | ||
372 | * | ||
373 | * delay = frame length rows * Tline (10 us) | ||
374 | */ | ||
375 | usleep_range(priv->frame_length * 10, | ||
376 | priv->frame_length * 10 + 1000); | ||
377 | return 0; | ||
378 | } | ||
379 | err = imx185_write_table(priv, mode_table[s_data->mode]); | ||
380 | if (err) | ||
381 | goto exit; | ||
382 | |||
383 | if (s_data->override_enable) { | ||
384 | /* write list of override regs for the asking gain, */ | ||
385 | /* frame rate and exposure time */ | ||
386 | memset(&ctrls, 0, sizeof(ctrls)); | ||
387 | ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(V4L2_CID_GAIN); | ||
388 | ctrls.count = 3; | ||
389 | ctrls.controls = control; | ||
390 | |||
391 | control[0].id = V4L2_CID_GAIN; | ||
392 | control[1].id = V4L2_CID_FRAME_RATE; | ||
393 | control[2].id = V4L2_CID_EXPOSURE; | ||
394 | |||
395 | err = v4l2_g_ext_ctrls(&priv->ctrl_handler, &ctrls); | ||
396 | if (err == 0) { | ||
397 | err |= imx185_set_gain(priv, control[0].value64); | ||
398 | if (err) | ||
399 | dev_err(&client->dev, | ||
400 | "%s: error gain override\n", __func__); | ||
401 | |||
402 | err |= imx185_set_frame_rate(priv, control[1].value64); | ||
403 | if (err) | ||
404 | dev_err(&client->dev, | ||
405 | "%s: error frame length override\n", | ||
406 | __func__); | ||
407 | |||
408 | err |= imx185_set_exposure(priv, control[2].value64); | ||
409 | if (err) | ||
410 | dev_err(&client->dev, | ||
411 | "%s: error exposure override\n", | ||
412 | __func__); | ||
413 | |||
414 | } else { | ||
415 | dev_err(&client->dev, "%s: faile to get overrides\n", | ||
416 | __func__); | ||
417 | } | ||
418 | } | ||
419 | |||
420 | if (test_mode) { | ||
421 | err = imx185_write_table(priv, | ||
422 | mode_table[IMX185_MODE_TEST_PATTERN]); | ||
423 | if (err) | ||
424 | goto exit; | ||
425 | } | ||
426 | |||
427 | err = imx185_write_table(priv, mode_table[IMX185_MODE_START_STREAM]); | ||
428 | if (err) | ||
429 | goto exit; | ||
430 | |||
431 | return 0; | ||
432 | exit: | ||
433 | dev_err(&client->dev, "%s: error setting stream\n", __func__); | ||
434 | return err; | ||
435 | } | ||
436 | |||
437 | static int imx185_g_input_status(struct v4l2_subdev *sd, u32 *status) | ||
438 | { | ||
439 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
440 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
441 | struct imx185 *priv = (struct imx185 *)s_data->priv; | ||
442 | struct camera_common_power_rail *pw = &priv->power; | ||
443 | |||
444 | *status = pw->state == SWITCH_ON; | ||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | static struct v4l2_subdev_video_ops imx185_subdev_video_ops = { | ||
449 | .s_stream = imx185_s_stream, | ||
450 | .g_mbus_config = camera_common_g_mbus_config, | ||
451 | .g_input_status = imx185_g_input_status, | ||
452 | }; | ||
453 | |||
454 | static struct v4l2_subdev_core_ops imx185_subdev_core_ops = { | ||
455 | .s_power = camera_common_s_power, | ||
456 | }; | ||
457 | |||
458 | static int imx185_get_fmt(struct v4l2_subdev *sd, | ||
459 | struct v4l2_subdev_pad_config *cfg, | ||
460 | struct v4l2_subdev_format *format) | ||
461 | { | ||
462 | return camera_common_g_fmt(sd, &format->format); | ||
463 | } | ||
464 | |||
465 | static int imx185_set_fmt(struct v4l2_subdev *sd, | ||
466 | struct v4l2_subdev_pad_config *cfg, | ||
467 | struct v4l2_subdev_format *format) | ||
468 | { | ||
469 | int ret; | ||
470 | |||
471 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) | ||
472 | ret = camera_common_try_fmt(sd, &format->format); | ||
473 | else | ||
474 | ret = camera_common_s_fmt(sd, &format->format); | ||
475 | |||
476 | return ret; | ||
477 | } | ||
478 | |||
479 | static struct v4l2_subdev_pad_ops imx185_subdev_pad_ops = { | ||
480 | .set_fmt = imx185_set_fmt, | ||
481 | .get_fmt = imx185_get_fmt, | ||
482 | .enum_mbus_code = camera_common_enum_mbus_code, | ||
483 | .enum_frame_size = camera_common_enum_framesizes, | ||
484 | .enum_frame_interval = camera_common_enum_frameintervals, | ||
485 | }; | ||
486 | |||
487 | static struct v4l2_subdev_ops imx185_subdev_ops = { | ||
488 | .core = &imx185_subdev_core_ops, | ||
489 | .video = &imx185_subdev_video_ops, | ||
490 | .pad = &imx185_subdev_pad_ops, | ||
491 | }; | ||
492 | |||
493 | const struct of_device_id imx185_of_match[] = { | ||
494 | { .compatible = "nvidia,imx185",}, | ||
495 | { }, | ||
496 | }; | ||
497 | |||
498 | static struct camera_common_sensor_ops imx185_common_ops = { | ||
499 | .power_on = imx185_power_on, | ||
500 | .power_off = imx185_power_off, | ||
501 | .write_reg = imx185_write_reg, | ||
502 | .read_reg = imx185_read_reg, | ||
503 | }; | ||
504 | |||
505 | static int imx185_set_group_hold(struct imx185 *priv, s32 val) | ||
506 | { | ||
507 | int err; | ||
508 | int gh_en = switch_ctrl_qmenu[val]; | ||
509 | |||
510 | priv->group_hold_prev = val; | ||
511 | if (gh_en == SWITCH_ON) { | ||
512 | |||
513 | err = imx185_write_reg(priv->s_data, | ||
514 | IMX185_GROUP_HOLD_ADDR, 0x1); | ||
515 | if (err) | ||
516 | goto fail; | ||
517 | } else if (gh_en == SWITCH_OFF) { | ||
518 | err = imx185_write_reg(priv->s_data, | ||
519 | IMX185_GROUP_HOLD_ADDR, 0x0); | ||
520 | if (err) | ||
521 | goto fail; | ||
522 | } | ||
523 | return 0; | ||
524 | fail: | ||
525 | dev_dbg(&priv->i2c_client->dev, | ||
526 | "%s: Group hold control error\n", __func__); | ||
527 | return err; | ||
528 | } | ||
529 | |||
530 | static int imx185_set_gain(struct imx185 *priv, s64 val) | ||
531 | { | ||
532 | imx185_reg reg_list[1]; | ||
533 | int err; | ||
534 | s64 gain64; | ||
535 | u8 gain; | ||
536 | |||
537 | /* translate value */ | ||
538 | gain64 = (s64)(val / FIXED_POINT_SCALING_FACTOR); | ||
539 | gain = (u8)(gain64 * 160 / 48); | ||
540 | dev_dbg(&priv->i2c_client->dev, | ||
541 | "%s: gain reg: %d, db: %lld\n", __func__, gain, gain64); | ||
542 | |||
543 | imx185_get_gain_reg(reg_list, gain); | ||
544 | |||
545 | err = imx185_write_reg(priv->s_data, reg_list[0].addr, | ||
546 | reg_list[0].val); | ||
547 | if (err) | ||
548 | goto fail; | ||
549 | |||
550 | return 0; | ||
551 | |||
552 | fail: | ||
553 | dev_dbg(&priv->i2c_client->dev, | ||
554 | "%s: GAIN control error\n", __func__); | ||
555 | return err; | ||
556 | } | ||
557 | |||
558 | static int imx185_set_frame_rate(struct imx185 *priv, s64 val) | ||
559 | { | ||
560 | imx185_reg reg_list[3]; | ||
561 | int err; | ||
562 | s64 frame_length; | ||
563 | struct camera_common_mode_info *mode = priv->pdata->mode_info; | ||
564 | struct camera_common_data *s_data = priv->s_data; | ||
565 | struct v4l2_control control; | ||
566 | int hdr_en; | ||
567 | int i = 0; | ||
568 | |||
569 | frame_length = mode[s_data->mode].pixel_clock * | ||
570 | FIXED_POINT_SCALING_FACTOR / | ||
571 | mode[s_data->mode].line_length / val; | ||
572 | |||
573 | priv->frame_length = (u32) frame_length; | ||
574 | if (priv->frame_length > IMX185_MAX_FRAME_LENGTH) | ||
575 | priv->frame_length = IMX185_MAX_FRAME_LENGTH; | ||
576 | |||
577 | dev_dbg(&priv->i2c_client->dev, | ||
578 | "%s: val: %lld, , frame_length: %d\n", __func__, | ||
579 | val, priv->frame_length); | ||
580 | |||
581 | imx185_get_frame_length_regs(reg_list, priv->frame_length); | ||
582 | |||
583 | for (i = 0; i < 3; i++) { | ||
584 | err = imx185_write_reg(priv->s_data, reg_list[i].addr, | ||
585 | reg_list[i].val); | ||
586 | if (err) | ||
587 | goto fail; | ||
588 | } | ||
589 | |||
590 | /* check hdr enable ctrl */ | ||
591 | control.id = V4L2_CID_HDR_EN; | ||
592 | err = camera_common_g_ctrl(priv->s_data, &control); | ||
593 | if (err < 0) { | ||
594 | dev_err(&priv->i2c_client->dev, | ||
595 | "could not find device ctrl.\n"); | ||
596 | return err; | ||
597 | } | ||
598 | |||
599 | hdr_en = switch_ctrl_qmenu[control.value]; | ||
600 | if ((hdr_en == SWITCH_ON) && (priv->last_wdr_et_val != 0)) { | ||
601 | err = imx185_set_coarse_time_hdr(priv, priv->last_wdr_et_val); | ||
602 | if (err) | ||
603 | dev_dbg(&priv->i2c_client->dev, | ||
604 | "%s: error coarse time SHS1 SHS2 override\n", __func__); | ||
605 | } | ||
606 | |||
607 | return 0; | ||
608 | |||
609 | fail: | ||
610 | dev_dbg(&priv->i2c_client->dev, | ||
611 | "%s: FRAME_LENGTH control error\n", __func__); | ||
612 | return err; | ||
613 | } | ||
614 | |||
615 | static int imx185_set_exposure(struct imx185 *priv, s64 val) | ||
616 | { | ||
617 | int err; | ||
618 | struct v4l2_control control; | ||
619 | int hdr_en; | ||
620 | |||
621 | dev_dbg(&priv->i2c_client->dev, | ||
622 | "%s: val: %lld\n", __func__, val); | ||
623 | |||
624 | /* check hdr enable ctrl */ | ||
625 | control.id = V4L2_CID_HDR_EN; | ||
626 | err = camera_common_g_ctrl(priv->s_data, &control); | ||
627 | if (err < 0) { | ||
628 | dev_err(&priv->i2c_client->dev, | ||
629 | "could not find device ctrl.\n"); | ||
630 | return err; | ||
631 | } | ||
632 | |||
633 | hdr_en = switch_ctrl_qmenu[control.value]; | ||
634 | if (hdr_en == SWITCH_ON) { | ||
635 | err = imx185_set_coarse_time_hdr(priv, val); | ||
636 | if (err) | ||
637 | dev_dbg(&priv->i2c_client->dev, | ||
638 | "%s: error coarse time SHS1 SHS2 override\n", __func__); | ||
639 | } else { | ||
640 | err = imx185_set_coarse_time(priv, val); | ||
641 | if (err) | ||
642 | dev_dbg(&priv->i2c_client->dev, | ||
643 | "%s: error coarse time SHS1 override\n", __func__); | ||
644 | } | ||
645 | return err; | ||
646 | } | ||
647 | |||
648 | static int imx185_set_coarse_time(struct imx185 *priv, s64 val) | ||
649 | { | ||
650 | struct camera_common_mode_info *mode = priv->pdata->mode_info; | ||
651 | struct camera_common_data *s_data = priv->s_data; | ||
652 | imx185_reg reg_list[3]; | ||
653 | int err; | ||
654 | u32 coarse_time_shs1; | ||
655 | u32 reg_shs1; | ||
656 | int i = 0; | ||
657 | |||
658 | coarse_time_shs1 = mode[s_data->mode].pixel_clock * val / | ||
659 | mode[s_data->mode].line_length / FIXED_POINT_SCALING_FACTOR; | ||
660 | |||
661 | if (priv->frame_length == 0) | ||
662 | priv->frame_length = IMX185_MIN_FRAME_LENGTH; | ||
663 | |||
664 | reg_shs1 = priv->frame_length - coarse_time_shs1 - 1; | ||
665 | |||
666 | dev_dbg(&priv->i2c_client->dev, | ||
667 | "%s: coarse1:%d, shs1:%d, FL:%d\n", __func__, | ||
668 | coarse_time_shs1, reg_shs1, priv->frame_length); | ||
669 | |||
670 | imx185_get_coarse_time_regs_shs1(reg_list, reg_shs1); | ||
671 | |||
672 | for (i = 0; i < 3; i++) { | ||
673 | err = imx185_write_reg(priv->s_data, reg_list[i].addr, | ||
674 | reg_list[i].val); | ||
675 | if (err) | ||
676 | goto fail; | ||
677 | } | ||
678 | |||
679 | return 0; | ||
680 | |||
681 | fail: | ||
682 | dev_dbg(&priv->i2c_client->dev, | ||
683 | "%s: set coarse time error\n", __func__); | ||
684 | return err; | ||
685 | } | ||
686 | |||
687 | static int imx185_set_coarse_time_hdr(struct imx185 *priv, s64 val) | ||
688 | { | ||
689 | struct camera_common_mode_info *mode = priv->pdata->mode_info; | ||
690 | struct camera_common_data *s_data = priv->s_data; | ||
691 | imx185_reg reg_list_shs1[3]; | ||
692 | imx185_reg reg_list_shs2[3]; | ||
693 | u32 coarse_time_shs1; | ||
694 | u32 coarse_time_shs2; | ||
695 | u32 reg_shs1; | ||
696 | u32 reg_shs2; | ||
697 | int err; | ||
698 | int i = 0; | ||
699 | |||
700 | if (priv->frame_length == 0) | ||
701 | priv->frame_length = IMX185_MIN_FRAME_LENGTH; | ||
702 | |||
703 | priv->last_wdr_et_val = val; | ||
704 | |||
705 | /*WDR, update SHS1 as short ET, and SHS2 is 16x of short*/ | ||
706 | coarse_time_shs1 = mode[s_data->mode].pixel_clock * val / | ||
707 | mode[s_data->mode].line_length / | ||
708 | FIXED_POINT_SCALING_FACTOR / 16; | ||
709 | if (coarse_time_shs1 < IMX185_MIN_SHS1_1080P_HDR) | ||
710 | coarse_time_shs1 = IMX185_MIN_SHS1_1080P_HDR; | ||
711 | if (coarse_time_shs1 > IMX185_MAX_SHS1_1080P_HDR) | ||
712 | coarse_time_shs1 = IMX185_MAX_SHS1_1080P_HDR; | ||
713 | |||
714 | coarse_time_shs2 = (coarse_time_shs1 - IMX185_MIN_SHS1_1080P_HDR) * 16 + | ||
715 | IMX185_MIN_SHS2_1080P_HDR; | ||
716 | |||
717 | reg_shs1 = priv->frame_length - coarse_time_shs1 - 1; | ||
718 | reg_shs2 = priv->frame_length - coarse_time_shs2 - 1; | ||
719 | |||
720 | imx185_get_coarse_time_regs_shs1(reg_list_shs1, reg_shs1); | ||
721 | imx185_get_coarse_time_regs_shs2(reg_list_shs2, reg_shs2); | ||
722 | |||
723 | dev_dbg(&priv->i2c_client->dev, | ||
724 | "%s: coarse1:%d, shs1:%d, coarse2:%d, shs2: %d, FL:%d\n", | ||
725 | __func__, | ||
726 | coarse_time_shs1, reg_shs1, | ||
727 | coarse_time_shs2, reg_shs2, | ||
728 | priv->frame_length); | ||
729 | |||
730 | for (i = 0; i < 3; i++) { | ||
731 | err = imx185_write_reg(priv->s_data, reg_list_shs1[i].addr, | ||
732 | reg_list_shs1[i].val); | ||
733 | if (err) | ||
734 | goto fail; | ||
735 | |||
736 | err = imx185_write_reg(priv->s_data, reg_list_shs2[i].addr, | ||
737 | reg_list_shs2[i].val); | ||
738 | if (err) | ||
739 | goto fail; | ||
740 | } | ||
741 | |||
742 | return 0; | ||
743 | |||
744 | fail: | ||
745 | dev_dbg(&priv->i2c_client->dev, | ||
746 | "%s: set WDR coarse time error\n", __func__); | ||
747 | return err; | ||
748 | } | ||
749 | |||
750 | static int imx185_fuse_id_setup(struct imx185 *priv) | ||
751 | { | ||
752 | int err; | ||
753 | int i; | ||
754 | struct i2c_client *client = v4l2_get_subdevdata(priv->subdev); | ||
755 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
756 | |||
757 | struct v4l2_ctrl *ctrl; | ||
758 | u8 fuse_id[IMX185_FUSE_ID_SIZE]; | ||
759 | u8 bak = 0; | ||
760 | |||
761 | err = camera_common_s_power(priv->subdev, true); | ||
762 | if (err) | ||
763 | return -ENODEV; | ||
764 | |||
765 | for (i = 0; i < IMX185_FUSE_ID_SIZE; i++) { | ||
766 | err |= imx185_read_reg(s_data, | ||
767 | IMX185_FUSE_ID_ADDR + i, &bak); | ||
768 | if (!err) | ||
769 | fuse_id[i] = bak; | ||
770 | else { | ||
771 | pr_err("%s: can not read fuse id\n", __func__); | ||
772 | return -EINVAL; | ||
773 | } | ||
774 | } | ||
775 | |||
776 | ctrl = v4l2_ctrl_find(&priv->ctrl_handler, V4L2_CID_FUSE_ID); | ||
777 | if (!ctrl) { | ||
778 | dev_err(&priv->i2c_client->dev, | ||
779 | "could not find device ctrl.\n"); | ||
780 | return -EINVAL; | ||
781 | } | ||
782 | |||
783 | for (i = 0; i < IMX185_FUSE_ID_SIZE; i++) | ||
784 | sprintf(&ctrl->p_new.p_char[i*2], "%02x", | ||
785 | fuse_id[i]); | ||
786 | ctrl->p_cur.p_char = ctrl->p_new.p_char; | ||
787 | dev_info(&client->dev, "%s, fuse id: %s\n", __func__, | ||
788 | ctrl->p_cur.p_char); | ||
789 | |||
790 | err = camera_common_s_power(priv->subdev, false); | ||
791 | if (err) | ||
792 | return -ENODEV; | ||
793 | |||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | static int imx185_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | ||
798 | { | ||
799 | struct imx185 *priv = | ||
800 | container_of(ctrl->handler, struct imx185, ctrl_handler); | ||
801 | int err = 0; | ||
802 | |||
803 | if (priv->power.state == SWITCH_OFF) | ||
804 | return 0; | ||
805 | |||
806 | switch (ctrl->id) { | ||
807 | |||
808 | default: | ||
809 | pr_err("%s: unknown ctrl id.\n", __func__); | ||
810 | return -EINVAL; | ||
811 | } | ||
812 | |||
813 | return err; | ||
814 | } | ||
815 | |||
816 | static int imx185_s_ctrl(struct v4l2_ctrl *ctrl) | ||
817 | { | ||
818 | struct imx185 *priv = | ||
819 | container_of(ctrl->handler, struct imx185, ctrl_handler); | ||
820 | struct camera_common_data *s_data = priv->s_data; | ||
821 | int err = 0; | ||
822 | |||
823 | if (priv->power.state == SWITCH_OFF) | ||
824 | return 0; | ||
825 | |||
826 | switch (ctrl->id) { | ||
827 | case V4L2_CID_GAIN: | ||
828 | err = imx185_set_gain(priv, *ctrl->p_new.p_s64); | ||
829 | break; | ||
830 | case V4L2_CID_EXPOSURE: | ||
831 | err = imx185_set_exposure(priv, *ctrl->p_new.p_s64); | ||
832 | break; | ||
833 | case V4L2_CID_FRAME_RATE: | ||
834 | err = imx185_set_frame_rate(priv, *ctrl->p_new.p_s64); | ||
835 | break; | ||
836 | case V4L2_CID_GROUP_HOLD: | ||
837 | err = imx185_set_group_hold(priv, ctrl->val); | ||
838 | break; | ||
839 | case V4L2_CID_HDR_EN: | ||
840 | break; | ||
841 | case V4L2_CID_SENSOR_MODE_ID: | ||
842 | s_data->sensor_mode_id = (int) (*ctrl->p_new.p_s64); | ||
843 | break; | ||
844 | default: | ||
845 | pr_err("%s: unknown ctrl id.\n", __func__); | ||
846 | return -EINVAL; | ||
847 | } | ||
848 | |||
849 | return err; | ||
850 | } | ||
851 | |||
852 | static int imx185_ctrls_init(struct imx185 *priv) | ||
853 | { | ||
854 | struct i2c_client *client = priv->i2c_client; | ||
855 | struct v4l2_ctrl *ctrl; | ||
856 | int num_ctrls; | ||
857 | int err; | ||
858 | int i; | ||
859 | |||
860 | dev_dbg(&client->dev, "%s++\n", __func__); | ||
861 | |||
862 | num_ctrls = ARRAY_SIZE(ctrl_config_list); | ||
863 | v4l2_ctrl_handler_init(&priv->ctrl_handler, num_ctrls); | ||
864 | |||
865 | for (i = 0; i < num_ctrls; i++) { | ||
866 | ctrl = v4l2_ctrl_new_custom(&priv->ctrl_handler, | ||
867 | &ctrl_config_list[i], NULL); | ||
868 | if (ctrl == NULL) { | ||
869 | dev_err(&client->dev, "Failed to init %s ctrl\n", | ||
870 | ctrl_config_list[i].name); | ||
871 | continue; | ||
872 | } | ||
873 | |||
874 | if (ctrl_config_list[i].type == V4L2_CTRL_TYPE_STRING && | ||
875 | ctrl_config_list[i].flags & V4L2_CTRL_FLAG_READ_ONLY) { | ||
876 | ctrl->p_new.p_char = devm_kzalloc(&client->dev, | ||
877 | ctrl_config_list[i].max + 1, GFP_KERNEL); | ||
878 | } | ||
879 | priv->ctrls[i] = ctrl; | ||
880 | } | ||
881 | |||
882 | priv->numctrls = num_ctrls; | ||
883 | priv->subdev->ctrl_handler = &priv->ctrl_handler; | ||
884 | if (priv->ctrl_handler.error) { | ||
885 | dev_err(&client->dev, "Error %d adding controls\n", | ||
886 | priv->ctrl_handler.error); | ||
887 | err = priv->ctrl_handler.error; | ||
888 | goto error; | ||
889 | } | ||
890 | |||
891 | err = v4l2_ctrl_handler_setup(&priv->ctrl_handler); | ||
892 | if (err) { | ||
893 | dev_err(&client->dev, | ||
894 | "Error %d setting default controls\n", err); | ||
895 | goto error; | ||
896 | } | ||
897 | |||
898 | err = imx185_fuse_id_setup(priv); | ||
899 | if (err) { | ||
900 | dev_err(&client->dev, | ||
901 | "Error %d reading fuse id data\n", err); | ||
902 | goto error; | ||
903 | } | ||
904 | |||
905 | return 0; | ||
906 | |||
907 | error: | ||
908 | v4l2_ctrl_handler_free(&priv->ctrl_handler); | ||
909 | return err; | ||
910 | } | ||
911 | |||
912 | MODULE_DEVICE_TABLE(of, imx185_of_match); | ||
913 | |||
914 | static struct camera_common_pdata *imx185_parse_dt(struct imx185 *priv, | ||
915 | struct i2c_client *client, | ||
916 | struct camera_common_data *s_data) | ||
917 | { | ||
918 | struct device_node *np = client->dev.of_node; | ||
919 | struct camera_common_pdata *board_priv_pdata; | ||
920 | const struct of_device_id *match; | ||
921 | int err; | ||
922 | const char *str; | ||
923 | |||
924 | if (!np) | ||
925 | return NULL; | ||
926 | |||
927 | match = of_match_device(imx185_of_match, &client->dev); | ||
928 | if (!match) { | ||
929 | dev_err(&client->dev, "Failed to find matching dt id\n"); | ||
930 | return NULL; | ||
931 | } | ||
932 | |||
933 | err = of_property_read_string(np, "use_sensor_mode_id", &str); | ||
934 | if (!err) { | ||
935 | if (!strcmp(str, "true")) | ||
936 | s_data->use_sensor_mode_id = true; | ||
937 | else | ||
938 | s_data->use_sensor_mode_id = false; | ||
939 | } | ||
940 | board_priv_pdata = devm_kzalloc(&client->dev, | ||
941 | sizeof(*board_priv_pdata), GFP_KERNEL); | ||
942 | |||
943 | err = of_property_read_string(np, "mclk", | ||
944 | &board_priv_pdata->mclk_name); | ||
945 | if (err) | ||
946 | dev_err(&client->dev, "mclk not in DT\n"); | ||
947 | |||
948 | board_priv_pdata->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0); | ||
949 | if (err) { | ||
950 | dev_err(&client->dev, "reset-gpios not found %d\n", err); | ||
951 | board_priv_pdata->reset_gpio = 0; | ||
952 | } | ||
953 | |||
954 | err = camera_common_parse_sensor_mode(client, board_priv_pdata); | ||
955 | if (err) | ||
956 | dev_err(&client->dev, "Failed to load mode info %d\n", err); | ||
957 | |||
958 | return board_priv_pdata; | ||
959 | } | ||
960 | |||
961 | static int imx185_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
962 | { | ||
963 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
964 | |||
965 | dev_dbg(&client->dev, "%s:\n", __func__); | ||
966 | |||
967 | return 0; | ||
968 | } | ||
969 | |||
970 | static const struct v4l2_subdev_internal_ops imx185_subdev_internal_ops = { | ||
971 | .open = imx185_open, | ||
972 | }; | ||
973 | |||
974 | static const struct media_entity_operations imx185_media_ops = { | ||
975 | .link_validate = v4l2_subdev_link_validate, | ||
976 | }; | ||
977 | |||
978 | static int imx185_probe(struct i2c_client *client, | ||
979 | const struct i2c_device_id *id) | ||
980 | { | ||
981 | struct camera_common_data *common_data; | ||
982 | struct imx185 *priv; | ||
983 | char debugfs_name[10]; | ||
984 | int err; | ||
985 | |||
986 | dev_info(&client->dev, "[IMX185]: probing v4l2 sensor at addr 0x%0x.\n", | ||
987 | client->addr); | ||
988 | |||
989 | if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) | ||
990 | return -EINVAL; | ||
991 | |||
992 | common_data = devm_kzalloc(&client->dev, | ||
993 | sizeof(struct camera_common_data), GFP_KERNEL); | ||
994 | |||
995 | priv = devm_kzalloc(&client->dev, | ||
996 | sizeof(struct imx185) + sizeof(struct v4l2_ctrl *) * | ||
997 | ARRAY_SIZE(ctrl_config_list), | ||
998 | GFP_KERNEL); | ||
999 | if (!priv) { | ||
1000 | dev_err(&client->dev, "unable to allocate memory!\n"); | ||
1001 | return -ENOMEM; | ||
1002 | } | ||
1003 | |||
1004 | priv->regmap = devm_regmap_init_i2c(client, &sensor_regmap_config); | ||
1005 | if (IS_ERR(priv->regmap)) { | ||
1006 | dev_err(&client->dev, | ||
1007 | "regmap init failed: %ld\n", PTR_ERR(priv->regmap)); | ||
1008 | return -ENODEV; | ||
1009 | } | ||
1010 | |||
1011 | if (client->dev.of_node) | ||
1012 | priv->pdata = imx185_parse_dt(priv, client, common_data); | ||
1013 | if (!priv->pdata) { | ||
1014 | dev_err(&client->dev, "unable to get platform data\n"); | ||
1015 | return -EFAULT; | ||
1016 | } | ||
1017 | |||
1018 | common_data->ops = &imx185_common_ops; | ||
1019 | common_data->ctrl_handler = &priv->ctrl_handler; | ||
1020 | common_data->i2c_client = client; | ||
1021 | common_data->frmfmt = &imx185_frmfmt[0]; | ||
1022 | common_data->colorfmt = camera_common_find_datafmt( | ||
1023 | IMX185_DEFAULT_DATAFMT); | ||
1024 | common_data->power = &priv->power; | ||
1025 | common_data->ctrls = priv->ctrls; | ||
1026 | common_data->priv = (void *)priv; | ||
1027 | common_data->numctrls = ARRAY_SIZE(ctrl_config_list); | ||
1028 | common_data->numfmts = ARRAY_SIZE(imx185_frmfmt); | ||
1029 | common_data->def_mode = IMX185_DEFAULT_MODE; | ||
1030 | common_data->def_width = IMX185_DEFAULT_WIDTH; | ||
1031 | common_data->def_height = IMX185_DEFAULT_HEIGHT; | ||
1032 | common_data->fmt_width = common_data->def_width; | ||
1033 | common_data->fmt_height = common_data->def_height; | ||
1034 | common_data->def_clk_freq = IMX185_DEFAULT_CLK_FREQ; | ||
1035 | |||
1036 | priv->i2c_client = client; | ||
1037 | priv->s_data = common_data; | ||
1038 | priv->subdev = &common_data->subdev; | ||
1039 | priv->subdev->dev = &client->dev; | ||
1040 | priv->s_data->dev = &client->dev; | ||
1041 | priv->last_wdr_et_val = 0; | ||
1042 | |||
1043 | err = imx185_power_get(priv); | ||
1044 | if (err) | ||
1045 | return err; | ||
1046 | |||
1047 | err = camera_common_parse_ports(client, common_data); | ||
1048 | if (err) { | ||
1049 | dev_err(&client->dev, "Failed to find port info\n"); | ||
1050 | return err; | ||
1051 | } | ||
1052 | sprintf(debugfs_name, "imx185_%c", common_data->csi_port + 'a'); | ||
1053 | dev_dbg(&client->dev, "%s: name %s\n", __func__, debugfs_name); | ||
1054 | |||
1055 | camera_common_create_debugfs(common_data, debugfs_name); | ||
1056 | |||
1057 | v4l2_i2c_subdev_init(priv->subdev, client, &imx185_subdev_ops); | ||
1058 | |||
1059 | err = imx185_ctrls_init(priv); | ||
1060 | if (err) | ||
1061 | return err; | ||
1062 | |||
1063 | priv->subdev->internal_ops = &imx185_subdev_internal_ops; | ||
1064 | priv->subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | | ||
1065 | V4L2_SUBDEV_FL_HAS_EVENTS; | ||
1066 | |||
1067 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
1068 | priv->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
1069 | priv->subdev->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; | ||
1070 | priv->subdev->entity.ops = &imx185_media_ops; | ||
1071 | err = media_entity_init(&priv->subdev->entity, 1, &priv->pad, 0); | ||
1072 | if (err < 0) { | ||
1073 | dev_err(&client->dev, "unable to init media entity\n"); | ||
1074 | return err; | ||
1075 | } | ||
1076 | #endif | ||
1077 | |||
1078 | err = v4l2_async_register_subdev(priv->subdev); | ||
1079 | if (err) | ||
1080 | return err; | ||
1081 | |||
1082 | dev_info(&client->dev, "Detected IMX185 sensor\n"); | ||
1083 | |||
1084 | return 0; | ||
1085 | } | ||
1086 | |||
1087 | static int | ||
1088 | imx185_remove(struct i2c_client *client) | ||
1089 | { | ||
1090 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
1091 | struct imx185 *priv = (struct imx185 *)s_data->priv; | ||
1092 | |||
1093 | v4l2_async_unregister_subdev(priv->subdev); | ||
1094 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
1095 | media_entity_cleanup(&priv->subdev->entity); | ||
1096 | #endif | ||
1097 | |||
1098 | v4l2_ctrl_handler_free(&priv->ctrl_handler); | ||
1099 | camera_common_remove_debugfs(s_data); | ||
1100 | return 0; | ||
1101 | } | ||
1102 | |||
1103 | static const struct i2c_device_id imx185_id[] = { | ||
1104 | { "imx185", 0 }, | ||
1105 | { } | ||
1106 | }; | ||
1107 | |||
1108 | MODULE_DEVICE_TABLE(i2c, imx185_id); | ||
1109 | |||
1110 | static struct i2c_driver imx185_i2c_driver = { | ||
1111 | .driver = { | ||
1112 | .name = "imx185", | ||
1113 | .owner = THIS_MODULE, | ||
1114 | .of_match_table = of_match_ptr(imx185_of_match), | ||
1115 | }, | ||
1116 | .probe = imx185_probe, | ||
1117 | .remove = imx185_remove, | ||
1118 | .id_table = imx185_id, | ||
1119 | }; | ||
1120 | |||
1121 | module_i2c_driver(imx185_i2c_driver); | ||
1122 | |||
1123 | MODULE_DESCRIPTION("Media Controller driver for Sony IMX185"); | ||
1124 | MODULE_AUTHOR("NVIDIA Corporation"); | ||
1125 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/i2c/imx185_mode_tbls.h b/drivers/media/i2c/imx185_mode_tbls.h new file mode 100644 index 000000000..bf7042ee5 --- /dev/null +++ b/drivers/media/i2c/imx185_mode_tbls.h | |||
@@ -0,0 +1,1009 @@ | |||
1 | /* | ||
2 | * imx185_mode_tbls.h - imx185 sensor mode tables | ||
3 | * | ||
4 | * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #ifndef __IMX185_I2C_TABLES__ | ||
19 | #define __IMX185_I2C_TABLES__ | ||
20 | |||
21 | #include <media/camera_common.h> | ||
22 | #include <linux/miscdevice.h> | ||
23 | |||
24 | #define IMX185_TABLE_WAIT_MS 0 | ||
25 | #define IMX185_TABLE_END 1 | ||
26 | #define IMX185_MAX_RETRIES 3 | ||
27 | #define IMX185_WAIT_MS_STOP 1 | ||
28 | #define IMX185_WAIT_MS_START 30 | ||
29 | #define IMX185_WAIT_MS_STREAM 210 | ||
30 | #define IMX185_GAIN_TABLE_SIZE 255 | ||
31 | |||
32 | /* #define INIT_ET_INSETTING 1 */ | ||
33 | |||
34 | #define imx185_reg struct reg_8 | ||
35 | |||
36 | static imx185_reg imx185_start[] = { | ||
37 | {0x3000, 0x00 }, | ||
38 | {IMX185_TABLE_WAIT_MS, IMX185_WAIT_MS_START}, | ||
39 | {0x3002, 0x00}, | ||
40 | {0x3049, 0x0a}, | ||
41 | {IMX185_TABLE_WAIT_MS, IMX185_WAIT_MS_STREAM}, | ||
42 | { IMX185_TABLE_END, 0x00 } | ||
43 | }; | ||
44 | |||
45 | static imx185_reg imx185_stop[] = { | ||
46 | {0x3000, 0x01 }, | ||
47 | {IMX185_TABLE_WAIT_MS, IMX185_WAIT_MS_STOP}, | ||
48 | {IMX185_TABLE_END, 0x00 } | ||
49 | }; | ||
50 | |||
51 | static imx185_reg tp_colorbars[] = { | ||
52 | {0x300A, 0x00},/*BLC for PG*/ | ||
53 | {0x300E, 0x00}, | ||
54 | {0x3089, 0x00}, | ||
55 | {0x308C, 0x13}, | ||
56 | /* | ||
57 | * bit 0: PG mode enable | ||
58 | * bit 1: Back Ground Transient: | ||
59 | * bit [4-7]: PG mode setting, Set at 0h to Fh, suggest 1 or 5 | ||
60 | * raw12 max output FFEh | ||
61 | */ | ||
62 | {IMX185_TABLE_WAIT_MS, IMX185_WAIT_MS_STOP}, | ||
63 | {IMX185_TABLE_END, 0x00} | ||
64 | }; | ||
65 | |||
66 | static imx185_reg imx185_1920x1080_crop_60fps[] = { | ||
67 | {0x3002, 0x01}, | ||
68 | {0x3005, 0x01}, | ||
69 | {0x3006, 0x00}, | ||
70 | {0x3007, 0x50}, | ||
71 | {0x3009, 0x01}, | ||
72 | {0x300a, 0xf0}, | ||
73 | {0x300f, 0x01}, | ||
74 | {0x3018, 0x65}, | ||
75 | {0x3019, 0x04}, | ||
76 | {0x301b, 0x4c}, | ||
77 | {0x301c, 0x04}, | ||
78 | {0x301d, 0x08}, | ||
79 | {0x301e, 0x02}, | ||
80 | |||
81 | {0x3036, 0x06}, | ||
82 | {0x3038, 0x08}, | ||
83 | {0x3039, 0x00}, | ||
84 | {0x303a, 0x40}, | ||
85 | {0x303b, 0x04}, | ||
86 | {0x303c, 0x0c}, | ||
87 | {0x303d, 0x00}, | ||
88 | {0x303e, 0x7c}, | ||
89 | {0x303f, 0x07}, | ||
90 | |||
91 | {0x3044, 0xe1}, | ||
92 | {0x3048, 0x33}, | ||
93 | |||
94 | {0x305C, 0x20}, | ||
95 | {0x305D, 0x00}, | ||
96 | {0x305E, 0x18}, | ||
97 | {0x305F, 0x00}, | ||
98 | {0x3063, 0x74}, | ||
99 | |||
100 | {0x3084, 0x0f}, | ||
101 | {0x3086, 0x10}, | ||
102 | {0x30A1, 0x44}, | ||
103 | {0x30cf, 0xe1}, | ||
104 | {0x30d0, 0x29}, | ||
105 | {0x30d2, 0x9b}, | ||
106 | {0x30d3, 0x01}, | ||
107 | |||
108 | {0x311d, 0x0a}, | ||
109 | {0x3123, 0x0f}, | ||
110 | {0x3126, 0xdf}, | ||
111 | {0x3147, 0x87}, | ||
112 | {0x31e0, 0x01}, | ||
113 | {0x31e1, 0x9e}, | ||
114 | {0x31e2, 0x01}, | ||
115 | {0x31e5, 0x05}, | ||
116 | {0x31e6, 0x05}, | ||
117 | {0x31e7, 0x3a}, | ||
118 | {0x31e8, 0x3a}, | ||
119 | |||
120 | {0x3203, 0xc8}, | ||
121 | {0x3207, 0x54}, | ||
122 | {0x3213, 0x16}, | ||
123 | {0x3215, 0xf6}, | ||
124 | {0x321a, 0x14}, | ||
125 | {0x321b, 0x51}, | ||
126 | {0x3229, 0xe7}, | ||
127 | {0x322a, 0xf0}, | ||
128 | {0x322b, 0x10}, | ||
129 | {0x3231, 0xe7}, | ||
130 | {0x3232, 0xf0}, | ||
131 | {0x3233, 0x10}, | ||
132 | {0x323c, 0xe8}, | ||
133 | {0x323d, 0x70}, | ||
134 | {0x3243, 0x08}, | ||
135 | {0x3244, 0xe1}, | ||
136 | {0x3245, 0x10}, | ||
137 | {0x3247, 0xe7}, | ||
138 | {0x3248, 0x60}, | ||
139 | {0x3249, 0x1e}, | ||
140 | {0x324b, 0x00}, | ||
141 | {0x324c, 0x41}, | ||
142 | {0x3250, 0x30}, | ||
143 | {0x3251, 0x0a}, | ||
144 | {0x3252, 0xff}, | ||
145 | {0x3253, 0xff}, | ||
146 | {0x3254, 0xff}, | ||
147 | {0x3255, 0x02}, | ||
148 | {0x3257, 0xf0}, | ||
149 | {0x325a, 0xa6}, | ||
150 | {0x325d, 0x14}, | ||
151 | {0x325e, 0x51}, | ||
152 | {0x3260, 0x00}, | ||
153 | {0x3261, 0x61}, | ||
154 | {0x3266, 0x30}, | ||
155 | {0x3267, 0x05}, | ||
156 | {0x3275, 0xe7}, | ||
157 | {0x3281, 0xea}, | ||
158 | {0x3282, 0x70}, | ||
159 | {0x3285, 0xff}, | ||
160 | {0x328a, 0xf0}, | ||
161 | {0x328d, 0xb6}, | ||
162 | {0x328e, 0x40}, | ||
163 | {0x3290, 0x42}, | ||
164 | {0x3291, 0x51}, | ||
165 | {0x3292, 0x1e}, | ||
166 | {0x3294, 0xc4}, | ||
167 | {0x3295, 0x20}, | ||
168 | {0x3297, 0x50}, | ||
169 | {0x3298, 0x31}, | ||
170 | {0x3299, 0x1f}, | ||
171 | {0x329b, 0xc0}, | ||
172 | {0x329c, 0x60}, | ||
173 | {0x329e, 0x4c}, | ||
174 | {0x329f, 0x71}, | ||
175 | {0x32a0, 0x1f}, | ||
176 | {0x32a2, 0xb6}, | ||
177 | {0x32a3, 0xc0}, | ||
178 | {0x32a4, 0x0b}, | ||
179 | {0x32a9, 0x24}, | ||
180 | {0x32aa, 0x41}, | ||
181 | {0x32b0, 0x25}, | ||
182 | {0x32b1, 0x51}, | ||
183 | {0x32b7, 0x1c}, | ||
184 | {0x32b8, 0xc1}, | ||
185 | {0x32b9, 0x12}, | ||
186 | {0x32be, 0x1d}, | ||
187 | {0x32bf, 0xd1}, | ||
188 | {0x32c0, 0x12}, | ||
189 | {0x32c2, 0xa8}, | ||
190 | {0x32c3, 0xc0}, | ||
191 | {0x32c4, 0x0a}, | ||
192 | {0x32c5, 0x1e}, | ||
193 | {0x32c6, 0x21}, | ||
194 | {0x32c9, 0xb0}, | ||
195 | {0x32ca, 0x40}, | ||
196 | {0x32cc, 0x26}, | ||
197 | {0x32cd, 0xa1}, | ||
198 | {0x32d0, 0xb6}, | ||
199 | {0x32d1, 0xc0}, | ||
200 | {0x32d2, 0x0b}, | ||
201 | {0x32d4, 0xe2}, | ||
202 | {0x32d5, 0x40}, | ||
203 | {0x32d8, 0x4e}, | ||
204 | {0x32d9, 0xa1}, | ||
205 | {0x32ec, 0xf0}, | ||
206 | |||
207 | {0x3303, 0x00}, | ||
208 | {0x3305, 0x03}, | ||
209 | {0x3314, 0x04}, | ||
210 | {0x3315, 0x01}, | ||
211 | {0x3316, 0x04}, | ||
212 | {0x3317, 0x04}, | ||
213 | {0x3318, 0x38}, | ||
214 | {0x3319, 0x04}, | ||
215 | {0x332c, 0x40}, | ||
216 | {0x332d, 0x20}, | ||
217 | {0x332e, 0x03}, | ||
218 | {0x333e, 0x0c}, | ||
219 | {0x333f, 0x0c}, | ||
220 | {0x3340, 0x03}, | ||
221 | {0x3341, 0x20}, | ||
222 | {0x3342, 0x25}, | ||
223 | {0x3343, 0x68}, | ||
224 | {0x3344, 0x20}, | ||
225 | {0x3345, 0x40}, | ||
226 | {0x3346, 0x28}, | ||
227 | {0x3347, 0x20}, | ||
228 | {0x3348, 0x18}, | ||
229 | {0x3349, 0x78}, | ||
230 | {0x334a, 0x28}, | ||
231 | {0x334e, 0xb4}, | ||
232 | {0x334f, 0x01}, | ||
233 | #ifdef INIT_ET_INSETTING | ||
234 | {0x3020, 0xe1}, | ||
235 | {0x3021, 0x04}, | ||
236 | #endif | ||
237 | {IMX185_TABLE_END, 0x00} | ||
238 | }; | ||
239 | |||
240 | static imx185_reg imx185_1920x1080_crop_30fps[] = { | ||
241 | {0x3002, 0x01}, | ||
242 | {0x3005, 0x01}, | ||
243 | {0x3006, 0x00}, | ||
244 | {0x3007, 0x50}, | ||
245 | {0x3009, 0x02}, | ||
246 | {0x300a, 0xf0}, | ||
247 | {0x300f, 0x01}, | ||
248 | {0x3018, 0x65}, | ||
249 | {0x3019, 0x04}, | ||
250 | {0x301b, 0x89}, | ||
251 | {0x301c, 0x08}, | ||
252 | {0x301d, 0x08}, | ||
253 | {0x301e, 0x02}, | ||
254 | |||
255 | {0x3036, 0x06}, | ||
256 | {0x3038, 0x08}, | ||
257 | {0x3039, 0x00}, | ||
258 | {0x303a, 0x40}, | ||
259 | {0x303b, 0x04}, | ||
260 | {0x303c, 0x0c}, | ||
261 | {0x303d, 0x00}, | ||
262 | {0x303e, 0x7c}, | ||
263 | {0x303f, 0x07}, | ||
264 | |||
265 | {0x3048, 0x33}, | ||
266 | |||
267 | {0x305C, 0x20}, | ||
268 | {0x305D, 0x00}, | ||
269 | {0x305E, 0x18}, | ||
270 | {0x305F, 0x00}, | ||
271 | {0x3063, 0x74}, | ||
272 | |||
273 | {0x3084, 0x0f}, | ||
274 | {0x3086, 0x10}, | ||
275 | {0x30cf, 0xe1}, | ||
276 | {0x30d0, 0x29}, | ||
277 | {0x30d2, 0x9b}, | ||
278 | {0x30d3, 0x01}, | ||
279 | |||
280 | {0x311d, 0x0a}, | ||
281 | {0x3123, 0x0f}, | ||
282 | {0x3126, 0xdf}, | ||
283 | {0x3147, 0x87}, | ||
284 | {0x31e0, 0x01}, | ||
285 | {0x31e1, 0x9e}, | ||
286 | {0x31e2, 0x01}, | ||
287 | {0x31e5, 0x05}, | ||
288 | {0x31e6, 0x05}, | ||
289 | {0x31e7, 0x3a}, | ||
290 | {0x31e8, 0x3a}, | ||
291 | |||
292 | {0x3203, 0xc8}, | ||
293 | {0x3207, 0x54}, | ||
294 | {0x3213, 0x16}, | ||
295 | {0x3215, 0xf6}, | ||
296 | {0x321a, 0x14}, | ||
297 | {0x321b, 0x51}, | ||
298 | {0x3229, 0xe7}, | ||
299 | {0x322a, 0xf0}, | ||
300 | {0x322b, 0x10}, | ||
301 | {0x3231, 0xe7}, | ||
302 | {0x3232, 0xf0}, | ||
303 | {0x3233, 0x10}, | ||
304 | {0x323c, 0xe8}, | ||
305 | {0x323d, 0x70}, | ||
306 | {0x3243, 0x08}, | ||
307 | {0x3244, 0xe1}, | ||
308 | {0x3245, 0x10}, | ||
309 | {0x3247, 0xe7}, | ||
310 | {0x3248, 0x60}, | ||
311 | {0x3249, 0x1e}, | ||
312 | {0x324b, 0x00}, | ||
313 | {0x324c, 0x41}, | ||
314 | {0x3250, 0x30}, | ||
315 | {0x3251, 0x0a}, | ||
316 | {0x3252, 0xff}, | ||
317 | {0x3253, 0xff}, | ||
318 | {0x3254, 0xff}, | ||
319 | {0x3255, 0x02}, | ||
320 | {0x3257, 0xf0}, | ||
321 | {0x325a, 0xa6}, | ||
322 | {0x325d, 0x14}, | ||
323 | {0x325e, 0x51}, | ||
324 | {0x3260, 0x00}, | ||
325 | {0x3261, 0x61}, | ||
326 | {0x3266, 0x30}, | ||
327 | {0x3267, 0x05}, | ||
328 | {0x3275, 0xe7}, | ||
329 | {0x3281, 0xea}, | ||
330 | {0x3282, 0x70}, | ||
331 | {0x3285, 0xff}, | ||
332 | {0x328a, 0xf0}, | ||
333 | {0x328d, 0xb6}, | ||
334 | {0x328e, 0x40}, | ||
335 | {0x3290, 0x42}, | ||
336 | {0x3291, 0x51}, | ||
337 | {0x3292, 0x1e}, | ||
338 | {0x3294, 0xc4}, | ||
339 | {0x3295, 0x20}, | ||
340 | {0x3297, 0x50}, | ||
341 | {0x3298, 0x31}, | ||
342 | {0x3299, 0x1f}, | ||
343 | {0x329b, 0xc0}, | ||
344 | {0x329c, 0x60}, | ||
345 | {0x329e, 0x4c}, | ||
346 | {0x329f, 0x71}, | ||
347 | {0x32a0, 0x1f}, | ||
348 | {0x32a2, 0xb6}, | ||
349 | {0x32a3, 0xc0}, | ||
350 | {0x32a4, 0x0b}, | ||
351 | {0x32a9, 0x24}, | ||
352 | {0x32aa, 0x41}, | ||
353 | {0x32b0, 0x25}, | ||
354 | {0x32b1, 0x51}, | ||
355 | {0x32b7, 0x1c}, | ||
356 | {0x32b8, 0xc1}, | ||
357 | {0x32b9, 0x12}, | ||
358 | {0x32be, 0x1d}, | ||
359 | {0x32bf, 0xd1}, | ||
360 | {0x32c0, 0x12}, | ||
361 | {0x32c2, 0xa8}, | ||
362 | {0x32c3, 0xc0}, | ||
363 | {0x32c4, 0x0a}, | ||
364 | {0x32c5, 0x1e}, | ||
365 | {0x32c6, 0x21}, | ||
366 | {0x32c9, 0xb0}, | ||
367 | {0x32ca, 0x40}, | ||
368 | {0x32cc, 0x26}, | ||
369 | {0x32cd, 0xa1}, | ||
370 | {0x32d0, 0xb6}, | ||
371 | {0x32d1, 0xc0}, | ||
372 | {0x32d2, 0x0b}, | ||
373 | {0x32d4, 0xe2}, | ||
374 | {0x32d5, 0x40}, | ||
375 | {0x32d8, 0x4e}, | ||
376 | {0x32d9, 0xa1}, | ||
377 | {0x32ec, 0xf0}, | ||
378 | |||
379 | {0x3303, 0x10}, | ||
380 | {0x3305, 0x03}, | ||
381 | {0x3314, 0x04}, | ||
382 | {0x3315, 0x01}, | ||
383 | {0x3316, 0x04}, | ||
384 | {0x3317, 0x04}, | ||
385 | {0x3318, 0x38}, | ||
386 | {0x3319, 0x04}, | ||
387 | {0x332c, 0x30}, | ||
388 | {0x332d, 0x20}, | ||
389 | {0x332e, 0x03}, | ||
390 | {0x333e, 0x0c}, | ||
391 | {0x333f, 0x0c}, | ||
392 | {0x3340, 0x03}, | ||
393 | {0x3341, 0x20}, | ||
394 | {0x3342, 0x25}, | ||
395 | {0x3343, 0x58}, | ||
396 | {0x3344, 0x10}, | ||
397 | {0x3345, 0x30}, | ||
398 | {0x3346, 0x18}, | ||
399 | {0x3347, 0x10}, | ||
400 | {0x3348, 0x10}, | ||
401 | {0x3349, 0x48}, | ||
402 | {0x334a, 0x28}, | ||
403 | {0x334e, 0xb4}, | ||
404 | {0x334f, 0x01}, | ||
405 | #ifdef INIT_ET_INSETTING | ||
406 | {0x3020, 0xe1}, | ||
407 | {0x3021, 0x04}, | ||
408 | #endif | ||
409 | {IMX185_TABLE_END, 0x00} | ||
410 | }; | ||
411 | |||
412 | static imx185_reg imx185_1920x1080_hdr_crop_30fps[] = { | ||
413 | {0x3002, 0x01}, | ||
414 | {0x3005, 0x01}, | ||
415 | {0x3006, 0x00}, | ||
416 | {0x3007, 0x50}, | ||
417 | {0x3009, 0x02}, | ||
418 | {0x300a, 0xf0}, | ||
419 | |||
420 | {0x300c, 0x02}, | ||
421 | {0x300f, 0x01}, | ||
422 | {0x3010, 0x38}, | ||
423 | {0x3011, 0x00}, | ||
424 | {0x3012, 0x0f}, | ||
425 | {0x3013, 0x00}, | ||
426 | |||
427 | {0x3018, 0x65}, | ||
428 | {0x3019, 0x04}, | ||
429 | {0x301b, 0x98}, | ||
430 | {0x301c, 0x08}, | ||
431 | {0x301d, 0x08}, | ||
432 | {0x301e, 0x02}, | ||
433 | |||
434 | {0x3036, 0x06}, | ||
435 | {0x3038, 0x08}, | ||
436 | {0x3039, 0x00}, | ||
437 | {0x303a, 0x40}, | ||
438 | {0x303b, 0x04}, | ||
439 | {0x303c, 0x0c}, | ||
440 | {0x303d, 0x00}, | ||
441 | {0x303e, 0x7c}, | ||
442 | {0x303f, 0x07}, | ||
443 | |||
444 | {0x3044, 0xe1}, | ||
445 | {0x3048, 0x33}, | ||
446 | #ifdef INIT_ET_INSETTING | ||
447 | {0x3020, 0x1F},/*SHS1 1055, coarse 69*/ | ||
448 | {0x3021, 0x04}, | ||
449 | {0x3022, 0x00}, | ||
450 | {0x3023, 0x12},/*SHS2 18, coarse 1106*/ | ||
451 | {0x3024, 0x00}, | ||
452 | {0x3025, 0x00}, | ||
453 | #endif | ||
454 | {0x3056, 0xc9}, | ||
455 | {0x3057, 0x64}, | ||
456 | |||
457 | {0x305C, 0x20}, | ||
458 | {0x305D, 0x00}, | ||
459 | {0x305E, 0x18}, | ||
460 | {0x305F, 0x00}, | ||
461 | {0x3063, 0x74}, | ||
462 | |||
463 | {0x3065, 0x00}, | ||
464 | |||
465 | {0x3084, 0x0f}, | ||
466 | {0x3086, 0x10}, | ||
467 | {0x30cf, 0xe1}, | ||
468 | {0x30d0, 0x29}, | ||
469 | {0x30d2, 0x9b}, | ||
470 | {0x30d3, 0x01}, | ||
471 | |||
472 | {0x311d, 0x0a}, | ||
473 | {0x3123, 0x0f}, | ||
474 | {0x3126, 0xdf}, | ||
475 | {0x3147, 0x87}, | ||
476 | {0x31e0, 0x01}, | ||
477 | {0x31e1, 0x9e}, | ||
478 | {0x31e2, 0x01}, | ||
479 | {0x31e5, 0x05}, | ||
480 | {0x31e6, 0x05}, | ||
481 | {0x31e7, 0x3a}, | ||
482 | {0x31e8, 0x3a}, | ||
483 | |||
484 | {0x3203, 0xc8}, | ||
485 | {0x3207, 0x54}, | ||
486 | {0x3213, 0x16}, | ||
487 | {0x3215, 0xf6}, | ||
488 | {0x321a, 0x14}, | ||
489 | {0x321b, 0x51}, | ||
490 | {0x3229, 0xe7}, | ||
491 | {0x322a, 0xf0}, | ||
492 | {0x322b, 0x10}, | ||
493 | {0x3231, 0xe7}, | ||
494 | {0x3232, 0xf0}, | ||
495 | {0x3233, 0x10}, | ||
496 | {0x323c, 0xe8}, | ||
497 | {0x323d, 0x70}, | ||
498 | {0x3243, 0x08}, | ||
499 | {0x3244, 0xe1}, | ||
500 | {0x3245, 0x10}, | ||
501 | {0x3247, 0xe7}, | ||
502 | {0x3248, 0x60}, | ||
503 | {0x3249, 0x1e}, | ||
504 | {0x324b, 0x00}, | ||
505 | {0x324c, 0x41}, | ||
506 | {0x3250, 0x30}, | ||
507 | {0x3251, 0x0a}, | ||
508 | {0x3252, 0xff}, | ||
509 | {0x3253, 0xff}, | ||
510 | {0x3254, 0xff}, | ||
511 | {0x3255, 0x02}, | ||
512 | {0x3257, 0xf0}, | ||
513 | {0x325a, 0xa6}, | ||
514 | {0x325d, 0x14}, | ||
515 | {0x325e, 0x51}, | ||
516 | {0x3260, 0x00}, | ||
517 | {0x3261, 0x61}, | ||
518 | {0x3266, 0x30}, | ||
519 | {0x3267, 0x05}, | ||
520 | {0x3275, 0xe7}, | ||
521 | {0x3281, 0xea}, | ||
522 | {0x3282, 0x70}, | ||
523 | {0x3285, 0xff}, | ||
524 | {0x328a, 0xf0}, | ||
525 | {0x328d, 0xb6}, | ||
526 | {0x328e, 0x40}, | ||
527 | {0x3290, 0x42}, | ||
528 | {0x3291, 0x51}, | ||
529 | {0x3292, 0x1e}, | ||
530 | {0x3294, 0xc4}, | ||
531 | {0x3295, 0x20}, | ||
532 | {0x3297, 0x50}, | ||
533 | {0x3298, 0x31}, | ||
534 | {0x3299, 0x1f}, | ||
535 | {0x329b, 0xc0}, | ||
536 | {0x329c, 0x60}, | ||
537 | {0x329e, 0x4c}, | ||
538 | {0x329f, 0x71}, | ||
539 | {0x32a0, 0x1f}, | ||
540 | {0x32a2, 0xb6}, | ||
541 | {0x32a3, 0xc0}, | ||
542 | {0x32a4, 0x0b}, | ||
543 | {0x32a9, 0x24}, | ||
544 | {0x32aa, 0x41}, | ||
545 | {0x32b0, 0x25}, | ||
546 | {0x32b1, 0x51}, | ||
547 | {0x32b7, 0x1c}, | ||
548 | {0x32b8, 0xc1}, | ||
549 | {0x32b9, 0x12}, | ||
550 | {0x32be, 0x1d}, | ||
551 | {0x32bf, 0xd1}, | ||
552 | {0x32c0, 0x12}, | ||
553 | {0x32c2, 0xa8}, | ||
554 | {0x32c3, 0xc0}, | ||
555 | {0x32c4, 0x0a}, | ||
556 | {0x32c5, 0x1e}, | ||
557 | {0x32c6, 0x21}, | ||
558 | {0x32c9, 0xb0}, | ||
559 | {0x32ca, 0x40}, | ||
560 | {0x32cc, 0x26}, | ||
561 | {0x32cd, 0xa1}, | ||
562 | {0x32d0, 0xb6}, | ||
563 | {0x32d1, 0xc0}, | ||
564 | {0x32d2, 0x0b}, | ||
565 | {0x32d4, 0xe2}, | ||
566 | {0x32d5, 0x40}, | ||
567 | {0x32d8, 0x4e}, | ||
568 | {0x32d9, 0xa1}, | ||
569 | {0x32ec, 0xf0}, | ||
570 | |||
571 | {0x3303, 0x10}, | ||
572 | {0x3305, 0x03}, | ||
573 | {0x3314, 0x04}, | ||
574 | {0x3315, 0x01}, | ||
575 | {0x3316, 0x04}, | ||
576 | {0x3317, 0x04}, | ||
577 | {0x3318, 0x38}, | ||
578 | {0x3319, 0x04}, | ||
579 | {0x332c, 0x30}, | ||
580 | {0x332d, 0x20}, | ||
581 | {0x332e, 0x03}, | ||
582 | {0x333e, 0x0c}, | ||
583 | {0x333f, 0x0c}, | ||
584 | {0x3340, 0x03}, | ||
585 | |||
586 | {0x3341, 0x20}, | ||
587 | {0x3342, 0x25}, | ||
588 | {0x3343, 0x58}, | ||
589 | {0x3344, 0x10}, | ||
590 | {0x3345, 0x30}, | ||
591 | {0x3346, 0x18}, | ||
592 | {0x3347, 0x10}, | ||
593 | {0x3348, 0x10}, | ||
594 | {0x3349, 0x48}, | ||
595 | {0x334a, 0x28}, | ||
596 | {0x334e, 0xb4}, | ||
597 | {0x334f, 0x01}, | ||
598 | |||
599 | #ifdef INIT_ET_INSETTING | ||
600 | {0x3020, 0x1F}, | ||
601 | {0x3021, 0x04}, | ||
602 | {0x3022, 0x00}, | ||
603 | {0x3023, 0x12}, | ||
604 | {0x3024, 0x00}, | ||
605 | {0x3025, 0x00}, | ||
606 | #endif | ||
607 | {0x300C, 0x02}, | ||
608 | {0x300F, 0x05}, | ||
609 | {0x3010, 0x38}, | ||
610 | {0x3012, 0x0F}, | ||
611 | {0x3084, 0x0F}, | ||
612 | {0x3065, 0x00}, | ||
613 | {IMX185_TABLE_END, 0x00} | ||
614 | }; | ||
615 | |||
616 | static imx185_reg imx185_1920x1080_crop_10bit_60fps[] = { | ||
617 | {0x3002, 0x01}, | ||
618 | {0x3005, 0x00},/*10BIT*/ | ||
619 | {0x3006, 0x00}, | ||
620 | {0x3007, 0x50}, | ||
621 | {0x3009, 0x01}, | ||
622 | {0x300a, 0x3c},/*10BIT*/ | ||
623 | {0x300f, 0x01}, | ||
624 | {0x3018, 0x65}, | ||
625 | {0x3019, 0x04}, | ||
626 | {0x301b, 0x4c}, | ||
627 | {0x301c, 0x04}, | ||
628 | {0x301d, 0x08}, | ||
629 | {0x301e, 0x02}, | ||
630 | |||
631 | {0x3036, 0x06}, | ||
632 | {0x3038, 0x08}, | ||
633 | {0x3039, 0x00}, | ||
634 | {0x303a, 0x40}, | ||
635 | {0x303b, 0x04}, | ||
636 | {0x303c, 0x0c}, | ||
637 | {0x303d, 0x00}, | ||
638 | {0x303e, 0x7c}, | ||
639 | {0x303f, 0x07}, | ||
640 | |||
641 | {0x3044, 0xe1}, | ||
642 | {0x3048, 0x33}, | ||
643 | |||
644 | {0x305C, 0x20}, | ||
645 | {0x305D, 0x00}, | ||
646 | {0x305E, 0x18}, | ||
647 | {0x305F, 0x00}, | ||
648 | {0x3063, 0x74}, | ||
649 | |||
650 | {0x3084, 0x0f}, | ||
651 | {0x3086, 0x10}, | ||
652 | {0x30A1, 0x44}, | ||
653 | {0x30cf, 0xe1}, | ||
654 | {0x30d0, 0x29}, | ||
655 | {0x30d2, 0x9b}, | ||
656 | {0x30d3, 0x01}, | ||
657 | |||
658 | {0x311d, 0x0a}, | ||
659 | {0x3123, 0x0f}, | ||
660 | {0x3126, 0xdf}, | ||
661 | {0x3147, 0x87}, | ||
662 | {0x31e0, 0x01}, | ||
663 | {0x31e1, 0x9e}, | ||
664 | {0x31e2, 0x01}, | ||
665 | {0x31e5, 0x05}, | ||
666 | {0x31e6, 0x05}, | ||
667 | {0x31e7, 0x3a}, | ||
668 | {0x31e8, 0x3a}, | ||
669 | |||
670 | {0x3203, 0xc8}, | ||
671 | {0x3207, 0x54}, | ||
672 | {0x3213, 0x16}, | ||
673 | {0x3215, 0xf6}, | ||
674 | {0x321a, 0x14}, | ||
675 | {0x321b, 0x51}, | ||
676 | {0x3229, 0xe7}, | ||
677 | {0x322a, 0xf0}, | ||
678 | {0x322b, 0x10}, | ||
679 | {0x3231, 0xe7}, | ||
680 | {0x3232, 0xf0}, | ||
681 | {0x3233, 0x10}, | ||
682 | {0x323c, 0xe8}, | ||
683 | {0x323d, 0x70}, | ||
684 | {0x3243, 0x08}, | ||
685 | {0x3244, 0xe1}, | ||
686 | {0x3245, 0x10}, | ||
687 | {0x3247, 0xe7}, | ||
688 | {0x3248, 0x60}, | ||
689 | {0x3249, 0x1e}, | ||
690 | {0x324b, 0x00}, | ||
691 | {0x324c, 0x41}, | ||
692 | {0x3250, 0x30}, | ||
693 | {0x3251, 0x0a}, | ||
694 | {0x3252, 0xff}, | ||
695 | {0x3253, 0xff}, | ||
696 | {0x3254, 0xff}, | ||
697 | {0x3255, 0x02}, | ||
698 | {0x3257, 0xf0}, | ||
699 | {0x325a, 0xa6}, | ||
700 | {0x325d, 0x14}, | ||
701 | {0x325e, 0x51}, | ||
702 | {0x3260, 0x00}, | ||
703 | {0x3261, 0x61}, | ||
704 | {0x3266, 0x30}, | ||
705 | {0x3267, 0x05}, | ||
706 | {0x3275, 0xe7}, | ||
707 | {0x3281, 0xea}, | ||
708 | {0x3282, 0x70}, | ||
709 | {0x3285, 0xff}, | ||
710 | {0x328a, 0xf0}, | ||
711 | {0x328d, 0xb6}, | ||
712 | {0x328e, 0x40}, | ||
713 | {0x3290, 0x42}, | ||
714 | {0x3291, 0x51}, | ||
715 | {0x3292, 0x1e}, | ||
716 | {0x3294, 0xc4}, | ||
717 | {0x3295, 0x20}, | ||
718 | {0x3297, 0x50}, | ||
719 | {0x3298, 0x31}, | ||
720 | {0x3299, 0x1f}, | ||
721 | {0x329b, 0xc0}, | ||
722 | {0x329c, 0x60}, | ||
723 | {0x329e, 0x4c}, | ||
724 | {0x329f, 0x71}, | ||
725 | {0x32a0, 0x1f}, | ||
726 | {0x32a2, 0xb6}, | ||
727 | {0x32a3, 0xc0}, | ||
728 | {0x32a4, 0x0b}, | ||
729 | {0x32a9, 0x24}, | ||
730 | {0x32aa, 0x41}, | ||
731 | {0x32b0, 0x25}, | ||
732 | {0x32b1, 0x51}, | ||
733 | {0x32b7, 0x1c}, | ||
734 | {0x32b8, 0xc1}, | ||
735 | {0x32b9, 0x12}, | ||
736 | {0x32be, 0x1d}, | ||
737 | {0x32bf, 0xd1}, | ||
738 | {0x32c0, 0x12}, | ||
739 | {0x32c2, 0xa8}, | ||
740 | {0x32c3, 0xc0}, | ||
741 | {0x32c4, 0x0a}, | ||
742 | {0x32c5, 0x1e}, | ||
743 | {0x32c6, 0x21}, | ||
744 | {0x32c9, 0xb0}, | ||
745 | {0x32ca, 0x40}, | ||
746 | {0x32cc, 0x26}, | ||
747 | {0x32cd, 0xa1}, | ||
748 | {0x32d0, 0xb6}, | ||
749 | {0x32d1, 0xc0}, | ||
750 | {0x32d2, 0x0b}, | ||
751 | {0x32d4, 0xe2}, | ||
752 | {0x32d5, 0x40}, | ||
753 | {0x32d8, 0x4e}, | ||
754 | {0x32d9, 0xa1}, | ||
755 | {0x32ec, 0xf0}, | ||
756 | |||
757 | {0x3303, 0x00}, | ||
758 | {0x3305, 0x03}, | ||
759 | {0x3314, 0x04}, | ||
760 | {0x3315, 0x01}, | ||
761 | {0x3316, 0x04}, | ||
762 | {0x3317, 0x04}, | ||
763 | {0x3318, 0x38}, | ||
764 | {0x3319, 0x04}, | ||
765 | {0x332c, 0x40}, | ||
766 | {0x332d, 0x20}, | ||
767 | {0x332e, 0x03}, | ||
768 | {0x333e, 0x0a},/*10BIT*/ | ||
769 | {0x333f, 0x0a},/*10BIT*/ | ||
770 | {0x3340, 0x03}, | ||
771 | {0x3341, 0x20}, | ||
772 | {0x3342, 0x25}, | ||
773 | {0x3343, 0x68}, | ||
774 | {0x3344, 0x20}, | ||
775 | {0x3345, 0x40}, | ||
776 | {0x3346, 0x28}, | ||
777 | {0x3347, 0x20}, | ||
778 | {0x3348, 0x18}, | ||
779 | {0x3349, 0x78}, | ||
780 | {0x334a, 0x28}, | ||
781 | {0x334e, 0xb4}, | ||
782 | {0x334f, 0x01}, | ||
783 | #ifdef INIT_ET_INSETTING | ||
784 | {0x3020, 0xe1}, | ||
785 | {0x3021, 0x04}, | ||
786 | #endif | ||
787 | {IMX185_TABLE_END, 0x00} | ||
788 | }; | ||
789 | |||
790 | static imx185_reg imx185_1920x1080_crop_10bit_30fps[] = { | ||
791 | {0x3002, 0x01}, | ||
792 | {0x3005, 0x00}, | ||
793 | {0x3006, 0x00}, | ||
794 | {0x3007, 0x50}, | ||
795 | {0x3009, 0x02}, | ||
796 | {0x300a, 0x3c}, | ||
797 | {0x300f, 0x01}, | ||
798 | {0x3018, 0x65}, | ||
799 | {0x3019, 0x04}, | ||
800 | {0x301b, 0x98}, | ||
801 | {0x301c, 0x08}, | ||
802 | {0x301d, 0x08}, | ||
803 | {0x301e, 0x02}, | ||
804 | |||
805 | {0x3036, 0x06}, | ||
806 | {0x3038, 0x08}, | ||
807 | {0x3039, 0x00}, | ||
808 | {0x303a, 0x40}, | ||
809 | {0x303b, 0x04}, | ||
810 | {0x303c, 0x0c}, | ||
811 | {0x303d, 0x00}, | ||
812 | {0x303e, 0x7c}, | ||
813 | {0x303f, 0x07}, | ||
814 | |||
815 | {0x3044, 0xe1}, | ||
816 | {0x3048, 0x33}, | ||
817 | |||
818 | {0x305C, 0x20}, | ||
819 | {0x305D, 0x00}, | ||
820 | {0x305E, 0x18}, | ||
821 | {0x305F, 0x00}, | ||
822 | {0x3063, 0x74}, | ||
823 | |||
824 | {0x3084, 0x0f}, | ||
825 | {0x3086, 0x10}, | ||
826 | {0x30cf, 0xe1}, | ||
827 | {0x30d0, 0x29}, | ||
828 | {0x30d2, 0x9b}, | ||
829 | {0x30d3, 0x01}, | ||
830 | |||
831 | {0x311d, 0x0a}, | ||
832 | {0x3123, 0x0f}, | ||
833 | {0x3126, 0xdf}, | ||
834 | {0x3147, 0x87}, | ||
835 | {0x31e0, 0x01}, | ||
836 | {0x31e1, 0x9e}, | ||
837 | {0x31e2, 0x01}, | ||
838 | {0x31e5, 0x05}, | ||
839 | {0x31e6, 0x05}, | ||
840 | {0x31e7, 0x3a}, | ||
841 | {0x31e8, 0x3a}, | ||
842 | |||
843 | {0x3203, 0xc8}, | ||
844 | {0x3207, 0x54}, | ||
845 | {0x3213, 0x16}, | ||
846 | {0x3215, 0xf6}, | ||
847 | {0x321a, 0x14}, | ||
848 | {0x321b, 0x51}, | ||
849 | {0x3229, 0xe7}, | ||
850 | {0x322a, 0xf0}, | ||
851 | {0x322b, 0x10}, | ||
852 | {0x3231, 0xe7}, | ||
853 | {0x3232, 0xf0}, | ||
854 | {0x3233, 0x10}, | ||
855 | {0x323c, 0xe8}, | ||
856 | {0x323d, 0x70}, | ||
857 | {0x3243, 0x08}, | ||
858 | {0x3244, 0xe1}, | ||
859 | {0x3245, 0x10}, | ||
860 | {0x3247, 0xe7}, | ||
861 | {0x3248, 0x60}, | ||
862 | {0x3249, 0x1e}, | ||
863 | {0x324b, 0x00}, | ||
864 | {0x324c, 0x41}, | ||
865 | {0x3250, 0x30}, | ||
866 | {0x3251, 0x0a}, | ||
867 | {0x3252, 0xff}, | ||
868 | {0x3253, 0xff}, | ||
869 | {0x3254, 0xff}, | ||
870 | {0x3255, 0x02}, | ||
871 | {0x3257, 0xf0}, | ||
872 | {0x325a, 0xa6}, | ||
873 | {0x325d, 0x14}, | ||
874 | {0x325e, 0x51}, | ||
875 | {0x3260, 0x00}, | ||
876 | {0x3261, 0x61}, | ||
877 | {0x3266, 0x30}, | ||
878 | {0x3267, 0x05}, | ||
879 | {0x3275, 0xe7}, | ||
880 | {0x3281, 0xea}, | ||
881 | {0x3282, 0x70}, | ||
882 | {0x3285, 0xff}, | ||
883 | {0x328a, 0xf0}, | ||
884 | {0x328d, 0xb6}, | ||
885 | {0x328e, 0x40}, | ||
886 | {0x3290, 0x42}, | ||
887 | {0x3291, 0x51}, | ||
888 | {0x3292, 0x1e}, | ||
889 | {0x3294, 0xc4}, | ||
890 | {0x3295, 0x20}, | ||
891 | {0x3297, 0x50}, | ||
892 | {0x3298, 0x31}, | ||
893 | {0x3299, 0x1f}, | ||
894 | {0x329b, 0xc0}, | ||
895 | {0x329c, 0x60}, | ||
896 | {0x329e, 0x4c}, | ||
897 | {0x329f, 0x71}, | ||
898 | {0x32a0, 0x1f}, | ||
899 | {0x32a2, 0xb6}, | ||
900 | {0x32a3, 0xc0}, | ||
901 | {0x32a4, 0x0b}, | ||
902 | {0x32a9, 0x24}, | ||
903 | {0x32aa, 0x41}, | ||
904 | {0x32b0, 0x25}, | ||
905 | {0x32b1, 0x51}, | ||
906 | {0x32b7, 0x1c}, | ||
907 | {0x32b8, 0xc1}, | ||
908 | {0x32b9, 0x12}, | ||
909 | {0x32be, 0x1d}, | ||
910 | {0x32bf, 0xd1}, | ||
911 | {0x32c0, 0x12}, | ||
912 | {0x32c2, 0xa8}, | ||
913 | {0x32c3, 0xc0}, | ||
914 | {0x32c4, 0x0a}, | ||
915 | {0x32c5, 0x1e}, | ||
916 | {0x32c6, 0x21}, | ||
917 | {0x32c9, 0xb0}, | ||
918 | {0x32ca, 0x40}, | ||
919 | {0x32cc, 0x26}, | ||
920 | {0x32cd, 0xa1}, | ||
921 | {0x32d0, 0xb6}, | ||
922 | {0x32d1, 0xc0}, | ||
923 | {0x32d2, 0x0b}, | ||
924 | {0x32d4, 0xe2}, | ||
925 | {0x32d5, 0x40}, | ||
926 | {0x32d8, 0x4e}, | ||
927 | {0x32d9, 0xa1}, | ||
928 | {0x32ec, 0xf0}, | ||
929 | |||
930 | {0x3303, 0x10}, | ||
931 | {0x3305, 0x03}, | ||
932 | {0x3314, 0x04}, | ||
933 | {0x3315, 0x01}, | ||
934 | {0x3316, 0x04}, | ||
935 | {0x3317, 0x04}, | ||
936 | {0x3318, 0x38}, | ||
937 | {0x3319, 0x04}, | ||
938 | {0x332c, 0x30}, | ||
939 | {0x332d, 0x20}, | ||
940 | {0x332e, 0x03}, | ||
941 | {0x333e, 0x0a}, | ||
942 | {0x333f, 0x0a}, | ||
943 | {0x3340, 0x03}, | ||
944 | |||
945 | {0x3341, 0x20}, | ||
946 | {0x3342, 0x25}, | ||
947 | {0x3343, 0x58}, | ||
948 | {0x3344, 0x10}, | ||
949 | {0x3345, 0x30}, | ||
950 | {0x3346, 0x18}, | ||
951 | {0x3347, 0x10}, | ||
952 | {0x3348, 0x10}, | ||
953 | {0x3349, 0x48}, | ||
954 | {0x334a, 0x28}, | ||
955 | {0x334e, 0xb4}, | ||
956 | {0x334f, 0x01}, | ||
957 | #ifdef INIT_ET_INSETTING | ||
958 | {0x3020, 0xe1}, | ||
959 | {0x3021, 0x04}, | ||
960 | #endif | ||
961 | {IMX185_TABLE_END, 0x00} | ||
962 | }; | ||
963 | |||
964 | enum { | ||
965 | IMX185_MODE_1920X1080_CROP_30FPS, | ||
966 | IMX185_MODE_1920X1080_CROP_10BIT_30FPS, | ||
967 | IMX185_MODE_1920X1080_CROP_60FPS, | ||
968 | IMX185_MODE_1920X1080_CROP_10BIT_60FPS, | ||
969 | IMX185_MODE_1920X1080_CROP_HDR_30FPS, | ||
970 | IMX185_MODE_START_STREAM, | ||
971 | IMX185_MODE_STOP_STREAM, | ||
972 | IMX185_MODE_TEST_PATTERN | ||
973 | }; | ||
974 | |||
975 | static imx185_reg *mode_table[] = { | ||
976 | [IMX185_MODE_1920X1080_CROP_30FPS] = imx185_1920x1080_crop_30fps, | ||
977 | [IMX185_MODE_1920X1080_CROP_10BIT_30FPS] = | ||
978 | imx185_1920x1080_crop_10bit_30fps, | ||
979 | [IMX185_MODE_1920X1080_CROP_60FPS] = imx185_1920x1080_crop_60fps, | ||
980 | [IMX185_MODE_1920X1080_CROP_10BIT_60FPS] = | ||
981 | imx185_1920x1080_crop_10bit_60fps, | ||
982 | [IMX185_MODE_1920X1080_CROP_HDR_30FPS] = | ||
983 | imx185_1920x1080_hdr_crop_30fps, | ||
984 | [IMX185_MODE_START_STREAM] = imx185_start, | ||
985 | [IMX185_MODE_STOP_STREAM] = imx185_stop, | ||
986 | [IMX185_MODE_TEST_PATTERN] = tp_colorbars, | ||
987 | }; | ||
988 | |||
989 | static const int imx185_30fps[] = { | ||
990 | 30, | ||
991 | }; | ||
992 | |||
993 | static const int imx185_60fps[] = { | ||
994 | 60, | ||
995 | }; | ||
996 | |||
997 | static const struct camera_common_frmfmt imx185_frmfmt[] = { | ||
998 | {{1920, 1080}, imx185_30fps, 1, 0, | ||
999 | IMX185_MODE_1920X1080_CROP_30FPS}, | ||
1000 | {{1920, 1080}, imx185_30fps, 1, 0, | ||
1001 | IMX185_MODE_1920X1080_CROP_10BIT_30FPS}, | ||
1002 | {{1920, 1080}, imx185_60fps, 1, 0, | ||
1003 | IMX185_MODE_1920X1080_CROP_60FPS}, | ||
1004 | {{1920, 1080}, imx185_60fps, 1, 0, | ||
1005 | IMX185_MODE_1920X1080_CROP_10BIT_60FPS}, | ||
1006 | {{1920, 1080}, imx185_30fps, 1, 1, | ||
1007 | IMX185_MODE_1920X1080_CROP_HDR_30FPS}, | ||
1008 | }; | ||
1009 | #endif /* __IMX185_I2C_TABLES__ */ | ||
diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c new file mode 100644 index 000000000..adb0d16d4 --- /dev/null +++ b/drivers/media/i2c/imx214.c | |||
@@ -0,0 +1,1294 @@ | |||
1 | /* | ||
2 | * imx214.c - imx214 sensor driver | ||
3 | * | ||
4 | * Copyright (c) 2013-2016, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <linux/slab.h> | ||
20 | #include <linux/uaccess.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/module.h> | ||
23 | |||
24 | #include <linux/seq_file.h> | ||
25 | #include <linux/of.h> | ||
26 | #include <linux/of_device.h> | ||
27 | #include <linux/of_gpio.h> | ||
28 | |||
29 | #include <media/camera_common.h> | ||
30 | #include <media/imx214.h> | ||
31 | |||
32 | #include "imx214_mode_tbls.h" | ||
33 | |||
34 | #define IMX214_MAX_COARSE_DIFF 10 | ||
35 | |||
36 | #define IMX214_GAIN_SHIFT 8 | ||
37 | #define IMX214_MIN_GAIN (1 << IMX214_GAIN_SHIFT) | ||
38 | #define IMX214_MAX_GAIN (16 << IMX214_GAIN_SHIFT) | ||
39 | #define IMX214_MIN_FRAME_LENGTH (0x0) | ||
40 | #define IMX214_MAX_FRAME_LENGTH (0xffff) | ||
41 | #define IMX214_MIN_EXPOSURE_COARSE (0x0001) | ||
42 | #define IMX214_MAX_EXPOSURE_COARSE \ | ||
43 | (IMX214_MAX_FRAME_LENGTH-IMX214_MAX_COARSE_DIFF) | ||
44 | |||
45 | #define IMX214_DEFAULT_GAIN IMX214_MIN_GAIN | ||
46 | #define IMX214_DEFAULT_FRAME_LENGTH (0x0C7A) | ||
47 | #define IMX214_DEFAULT_EXPOSURE_COARSE \ | ||
48 | (IMX214_DEFAULT_FRAME_LENGTH-IMX214_MAX_COARSE_DIFF) | ||
49 | |||
50 | #define IMX214_DEFAULT_MODE IMX214_MODE_4096X3072 | ||
51 | #define IMX214_DEFAULT_HDR_MODE IMX214_MODE_4096X3072_HDR | ||
52 | #define IMX214_DEFAULT_WIDTH 4096 | ||
53 | #define IMX214_DEFAULT_HEIGHT 3072 | ||
54 | #define IMX214_DEFAULT_DATAFMT V4L2_MBUS_FMT_SRGGB10_1X10 | ||
55 | #define IMX214_DEFAULT_CLK_FREQ 24000000 | ||
56 | |||
57 | struct imx214 { | ||
58 | struct camera_common_power_rail power; | ||
59 | int numctrls; | ||
60 | struct v4l2_ctrl_handler ctrl_handler; | ||
61 | struct camera_common_eeprom_data eeprom[IMX214_EEPROM_NUM_BLOCKS]; | ||
62 | u8 eeprom_buf[IMX214_EEPROM_SIZE]; | ||
63 | struct i2c_client *i2c_client; | ||
64 | struct v4l2_subdev *subdev; | ||
65 | struct media_pad pad; | ||
66 | |||
67 | s32 group_hold_prev; | ||
68 | bool group_hold_en; | ||
69 | struct regmap *regmap; | ||
70 | struct camera_common_data *s_data; | ||
71 | struct camera_common_pdata *pdata; | ||
72 | struct v4l2_ctrl *ctrls[]; | ||
73 | }; | ||
74 | |||
75 | static const struct regmap_config sensor_regmap_config = { | ||
76 | .reg_bits = 16, | ||
77 | .val_bits = 8, | ||
78 | .cache_type = REGCACHE_RBTREE, | ||
79 | }; | ||
80 | |||
81 | static int imx214_g_volatile_ctrl(struct v4l2_ctrl *ctrl); | ||
82 | static int imx214_s_ctrl(struct v4l2_ctrl *ctrl); | ||
83 | |||
84 | static const struct v4l2_ctrl_ops imx214_ctrl_ops = { | ||
85 | .g_volatile_ctrl = imx214_g_volatile_ctrl, | ||
86 | .s_ctrl = imx214_s_ctrl, | ||
87 | }; | ||
88 | |||
89 | static struct v4l2_ctrl_config ctrl_config_list[] = { | ||
90 | /* Do not change the name field for the controls! */ | ||
91 | { | ||
92 | .ops = &imx214_ctrl_ops, | ||
93 | .id = V4L2_CID_GAIN, | ||
94 | .name = "Gain", | ||
95 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
96 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
97 | .min = IMX214_MIN_GAIN, | ||
98 | .max = IMX214_MAX_GAIN, | ||
99 | .def = IMX214_DEFAULT_GAIN, | ||
100 | .step = 1, | ||
101 | }, | ||
102 | { | ||
103 | .ops = &imx214_ctrl_ops, | ||
104 | .id = V4L2_CID_FRAME_LENGTH, | ||
105 | .name = "Frame Length", | ||
106 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
107 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
108 | .min = IMX214_MIN_FRAME_LENGTH, | ||
109 | .max = IMX214_MAX_FRAME_LENGTH, | ||
110 | .def = IMX214_DEFAULT_FRAME_LENGTH, | ||
111 | .step = 1, | ||
112 | }, | ||
113 | { | ||
114 | .ops = &imx214_ctrl_ops, | ||
115 | .id = V4L2_CID_COARSE_TIME, | ||
116 | .name = "Coarse Time", | ||
117 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
118 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
119 | .min = IMX214_MIN_EXPOSURE_COARSE, | ||
120 | .max = IMX214_MAX_EXPOSURE_COARSE, | ||
121 | .def = IMX214_DEFAULT_EXPOSURE_COARSE, | ||
122 | .step = 1, | ||
123 | }, | ||
124 | { | ||
125 | .ops = &imx214_ctrl_ops, | ||
126 | .id = V4L2_CID_COARSE_TIME_SHORT, | ||
127 | .name = "Coarse Time Short", | ||
128 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
129 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
130 | .min = IMX214_MIN_EXPOSURE_COARSE, | ||
131 | .max = IMX214_MAX_EXPOSURE_COARSE, | ||
132 | .def = IMX214_DEFAULT_EXPOSURE_COARSE, | ||
133 | .step = 1, | ||
134 | }, | ||
135 | { | ||
136 | .ops = &imx214_ctrl_ops, | ||
137 | .id = V4L2_CID_GROUP_HOLD, | ||
138 | .name = "Group Hold", | ||
139 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, | ||
140 | .min = 0, | ||
141 | .max = ARRAY_SIZE(switch_ctrl_qmenu) - 1, | ||
142 | .menu_skip_mask = 0, | ||
143 | .def = 0, | ||
144 | .qmenu_int = switch_ctrl_qmenu, | ||
145 | }, | ||
146 | { | ||
147 | .ops = &imx214_ctrl_ops, | ||
148 | .id = V4L2_CID_HDR_EN, | ||
149 | .name = "HDR enable", | ||
150 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, | ||
151 | .min = 0, | ||
152 | .max = ARRAY_SIZE(switch_ctrl_qmenu) - 1, | ||
153 | .menu_skip_mask = 0, | ||
154 | .def = 0, | ||
155 | .qmenu_int = switch_ctrl_qmenu, | ||
156 | }, | ||
157 | { | ||
158 | .ops = &imx214_ctrl_ops, | ||
159 | .id = V4L2_CID_EEPROM_DATA, | ||
160 | .name = "EEPROM Data", | ||
161 | .type = V4L2_CTRL_TYPE_STRING, | ||
162 | .flags = V4L2_CTRL_FLAG_VOLATILE, | ||
163 | .min = 0, | ||
164 | .max = IMX214_EEPROM_STR_SIZE, | ||
165 | .step = 2, | ||
166 | }, | ||
167 | { | ||
168 | .ops = &imx214_ctrl_ops, | ||
169 | .id = V4L2_CID_OTP_DATA, | ||
170 | .name = "OTP Data", | ||
171 | .type = V4L2_CTRL_TYPE_STRING, | ||
172 | .flags = V4L2_CTRL_FLAG_READ_ONLY, | ||
173 | .min = 0, | ||
174 | .max = IMX214_OTP_STR_SIZE, | ||
175 | .step = 2, | ||
176 | }, | ||
177 | { | ||
178 | .ops = &imx214_ctrl_ops, | ||
179 | .id = V4L2_CID_FUSE_ID, | ||
180 | .name = "Fuse ID", | ||
181 | .type = V4L2_CTRL_TYPE_STRING, | ||
182 | .flags = V4L2_CTRL_FLAG_READ_ONLY, | ||
183 | .min = 0, | ||
184 | .max = IMX214_FUSE_ID_STR_SIZE, | ||
185 | .step = 2, | ||
186 | }, | ||
187 | }; | ||
188 | |||
189 | static inline void imx214_get_frame_length_regs(imx214_reg *regs, | ||
190 | u16 frame_length) | ||
191 | { | ||
192 | regs->addr = IMX214_FRAME_LENGTH_ADDR_MSB; | ||
193 | regs->val = (frame_length >> 8) & 0xff; | ||
194 | (regs + 1)->addr = IMX214_FRAME_LENGTH_ADDR_LSB; | ||
195 | (regs + 1)->val = (frame_length) & 0xff; | ||
196 | } | ||
197 | |||
198 | static inline void imx214_get_coarse_time_regs(imx214_reg *regs, | ||
199 | u16 coarse_time) | ||
200 | { | ||
201 | regs->addr = IMX214_COARSE_TIME_ADDR_MSB; | ||
202 | regs->val = (coarse_time >> 8) & 0xff; | ||
203 | (regs + 1)->addr = IMX214_COARSE_TIME_ADDR_LSB; | ||
204 | (regs + 1)->val = (coarse_time) & 0xff; | ||
205 | } | ||
206 | |||
207 | static inline void imx214_get_coarse_time_short_regs(imx214_reg *regs, | ||
208 | u16 coarse_time) | ||
209 | { | ||
210 | regs->addr = IMX214_COARSE_TIME_SHORT_ADDR_MSB; | ||
211 | regs->val = (coarse_time >> 8) & 0xff; | ||
212 | (regs + 1)->addr = IMX214_COARSE_TIME_SHORT_ADDR_LSB; | ||
213 | (regs + 1)->val = (coarse_time) & 0xff; | ||
214 | } | ||
215 | |||
216 | static inline void imx214_get_gain_regs(imx214_reg *regs, | ||
217 | u16 gain) | ||
218 | { | ||
219 | regs->addr = IMX214_GAIN_ADDR_MSB; | ||
220 | regs->val = (gain >> 8) & 0xff; | ||
221 | (regs + 1)->addr = IMX214_GAIN_ADDR_LSB; | ||
222 | (regs + 1)->val = (gain) & 0xff; | ||
223 | } | ||
224 | |||
225 | static inline void imx214_get_gain_short_reg(imx214_reg *regs, | ||
226 | u16 gain) | ||
227 | { | ||
228 | regs->addr = IMX214_GAIN_SHORT_ADDR_MSB; | ||
229 | regs->val = (gain >> 8) & 0xff; | ||
230 | (regs + 1)->addr = IMX214_GAIN_SHORT_ADDR_LSB; | ||
231 | (regs + 1)->val = (gain) & 0xff; | ||
232 | } | ||
233 | |||
234 | static int test_mode; | ||
235 | module_param(test_mode, int, 0644); | ||
236 | |||
237 | static inline int imx214_read_reg(struct camera_common_data *s_data, | ||
238 | u16 addr, u8 *val) | ||
239 | { | ||
240 | struct imx214 *priv = (struct imx214 *)s_data->priv; | ||
241 | |||
242 | return regmap_read(priv->regmap, addr, (unsigned int *) val); | ||
243 | } | ||
244 | |||
245 | static int imx214_write_reg(struct camera_common_data *s_data, u16 addr, u8 val) | ||
246 | { | ||
247 | int err; | ||
248 | struct imx214 *priv = (struct imx214 *)s_data->priv; | ||
249 | |||
250 | err = regmap_write(priv->regmap, addr, val); | ||
251 | if (err) | ||
252 | pr_err("%s:i2c write failed, %x = %x\n", | ||
253 | __func__, addr, val); | ||
254 | |||
255 | return err; | ||
256 | } | ||
257 | |||
258 | static int imx214_write_table(struct imx214 *priv, | ||
259 | const imx214_reg table[]) | ||
260 | { | ||
261 | return regmap_util_write_table_8(priv->regmap, | ||
262 | table, | ||
263 | NULL, 0, | ||
264 | IMX214_TABLE_WAIT_MS, | ||
265 | IMX214_TABLE_END); | ||
266 | } | ||
267 | |||
268 | static int imx214_power_on(struct camera_common_data *s_data) | ||
269 | { | ||
270 | int err = 0; | ||
271 | struct imx214 *priv = (struct imx214 *)s_data->priv; | ||
272 | struct camera_common_power_rail *pw = &priv->power; | ||
273 | |||
274 | dev_dbg(&priv->i2c_client->dev, "%s: power on\n", __func__); | ||
275 | |||
276 | if (priv->pdata && priv->pdata->power_on) { | ||
277 | err = priv->pdata->power_on(pw); | ||
278 | if (err) | ||
279 | pr_err("%s failed.\n", __func__); | ||
280 | else | ||
281 | pw->state = SWITCH_ON; | ||
282 | return err; | ||
283 | } | ||
284 | |||
285 | /* sleep calls in the sequence below are for internal device | ||
286 | * signal propagation as specified by sensor vendor */ | ||
287 | |||
288 | if (pw->reset_gpio) | ||
289 | gpio_set_value(pw->reset_gpio, 0); | ||
290 | if (pw->af_gpio) | ||
291 | gpio_set_value(pw->af_gpio, 1); | ||
292 | if (pw->pwdn_gpio) | ||
293 | gpio_set_value(pw->pwdn_gpio, 0); | ||
294 | usleep_range(10, 20); | ||
295 | |||
296 | if (pw->avdd) | ||
297 | err = regulator_enable(pw->avdd); | ||
298 | if (err) | ||
299 | goto imx214_avdd_fail; | ||
300 | |||
301 | if (pw->iovdd) | ||
302 | err = regulator_enable(pw->iovdd); | ||
303 | if (err) | ||
304 | goto imx214_iovdd_fail; | ||
305 | |||
306 | udelay(1); | ||
307 | if (pw->reset_gpio) | ||
308 | gpio_set_value(pw->reset_gpio, 1); | ||
309 | if (pw->pwdn_gpio) | ||
310 | gpio_set_value(pw->pwdn_gpio, 1); | ||
311 | |||
312 | usleep_range(300, 310); | ||
313 | |||
314 | pw->state = SWITCH_ON; | ||
315 | return 0; | ||
316 | |||
317 | imx214_iovdd_fail: | ||
318 | regulator_disable(pw->avdd); | ||
319 | |||
320 | imx214_avdd_fail: | ||
321 | if (pw->af_gpio) | ||
322 | gpio_set_value(pw->af_gpio, 0); | ||
323 | |||
324 | pr_err("%s failed.\n", __func__); | ||
325 | return -ENODEV; | ||
326 | } | ||
327 | |||
328 | static int imx214_power_off(struct camera_common_data *s_data) | ||
329 | { | ||
330 | int err = 0; | ||
331 | struct imx214 *priv = (struct imx214 *)s_data->priv; | ||
332 | struct camera_common_power_rail *pw = &priv->power; | ||
333 | |||
334 | dev_dbg(&priv->i2c_client->dev, "%s: power off\n", __func__); | ||
335 | |||
336 | if (priv->pdata && priv->pdata->power_on) { | ||
337 | err = priv->pdata->power_off(pw); | ||
338 | if (err) { | ||
339 | pr_err("%s failed.\n", __func__); | ||
340 | return err; | ||
341 | } else { | ||
342 | goto power_off_done; | ||
343 | } | ||
344 | } | ||
345 | |||
346 | /* sleeps calls in the sequence below are for internal device | ||
347 | * signal propagation as specified by sensor vendor */ | ||
348 | |||
349 | usleep_range(1, 2); | ||
350 | if (pw->reset_gpio) | ||
351 | gpio_set_value(pw->reset_gpio, 0); | ||
352 | if (pw->af_gpio) | ||
353 | gpio_set_value(pw->af_gpio, 0); | ||
354 | if (pw->pwdn_gpio) | ||
355 | gpio_set_value(pw->pwdn_gpio, 0); | ||
356 | usleep_range(1, 2); | ||
357 | |||
358 | if (pw->iovdd) | ||
359 | regulator_disable(pw->iovdd); | ||
360 | if (pw->avdd) | ||
361 | regulator_disable(pw->avdd); | ||
362 | |||
363 | power_off_done: | ||
364 | pw->state = SWITCH_OFF; | ||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | static int imx214_power_put(struct imx214 *priv) | ||
369 | { | ||
370 | struct camera_common_power_rail *pw = &priv->power; | ||
371 | if (unlikely(!pw)) | ||
372 | return -EFAULT; | ||
373 | |||
374 | if (likely(pw->avdd)) | ||
375 | regulator_put(pw->avdd); | ||
376 | |||
377 | if (likely(pw->iovdd)) | ||
378 | regulator_put(pw->iovdd); | ||
379 | |||
380 | if (likely(pw->dvdd)) | ||
381 | regulator_put(pw->dvdd); | ||
382 | |||
383 | pw->avdd = NULL; | ||
384 | pw->iovdd = NULL; | ||
385 | pw->dvdd = NULL; | ||
386 | |||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | static int imx214_power_get(struct imx214 *priv) | ||
391 | { | ||
392 | struct camera_common_power_rail *pw = &priv->power; | ||
393 | struct camera_common_pdata *pdata = priv->pdata; | ||
394 | const char *mclk_name; | ||
395 | int err = 0; | ||
396 | |||
397 | mclk_name = priv->pdata->mclk_name ? | ||
398 | priv->pdata->mclk_name : "cam_mclk1"; | ||
399 | pw->mclk = devm_clk_get(&priv->i2c_client->dev, mclk_name); | ||
400 | if (IS_ERR(pw->mclk)) { | ||
401 | dev_err(&priv->i2c_client->dev, | ||
402 | "unable to get clock %s\n", mclk_name); | ||
403 | return PTR_ERR(pw->mclk); | ||
404 | } | ||
405 | |||
406 | /* analog 2.7v */ | ||
407 | err |= camera_common_regulator_get(priv->i2c_client, | ||
408 | &pw->avdd, pdata->regulators.avdd); | ||
409 | /* digital 1.2v */ | ||
410 | err |= camera_common_regulator_get(priv->i2c_client, | ||
411 | &pw->dvdd, pdata->regulators.dvdd); | ||
412 | /* IO 1.8v */ | ||
413 | err |= camera_common_regulator_get(priv->i2c_client, | ||
414 | &pw->iovdd, pdata->regulators.iovdd); | ||
415 | |||
416 | if (!err) { | ||
417 | pw->reset_gpio = pdata->reset_gpio; | ||
418 | pw->af_gpio = pdata->af_gpio; | ||
419 | pw->pwdn_gpio = pdata->pwdn_gpio; | ||
420 | } | ||
421 | |||
422 | pw->state = SWITCH_OFF; | ||
423 | return err; | ||
424 | } | ||
425 | |||
426 | static int imx214_set_gain(struct imx214 *priv, s32 val); | ||
427 | static int imx214_set_frame_length(struct imx214 *priv, s32 val); | ||
428 | static int imx214_set_coarse_time(struct imx214 *priv, s32 val); | ||
429 | static int imx214_set_coarse_time_short(struct imx214 *priv, s32 val); | ||
430 | |||
431 | static int imx214_s_stream(struct v4l2_subdev *sd, int enable) | ||
432 | { | ||
433 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
434 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
435 | struct imx214 *priv = (struct imx214 *)s_data->priv; | ||
436 | struct v4l2_control control; | ||
437 | int err; | ||
438 | |||
439 | dev_dbg(&client->dev, "%s++ enable %d\n", __func__, enable); | ||
440 | if (!enable) | ||
441 | return imx214_write_table(priv, | ||
442 | mode_table[IMX214_MODE_STOP_STREAM]); | ||
443 | |||
444 | err = imx214_write_table(priv, mode_table[IMX214_MODE_COMMON]); | ||
445 | if (err) | ||
446 | goto exit; | ||
447 | err = imx214_write_table(priv, mode_table[s_data->mode]); | ||
448 | if (err) | ||
449 | goto exit; | ||
450 | |||
451 | if (s_data->override_enable) { | ||
452 | /* write list of override regs for the asking frame length, */ | ||
453 | /* | ||
454 | * coarse integration time, and gain. Failures to write | ||
455 | * overrides are non-fatal | ||
456 | */ | ||
457 | control.id = V4L2_CID_GAIN; | ||
458 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
459 | err |= imx214_set_gain(priv, control.value); | ||
460 | if (err) | ||
461 | dev_dbg(&client->dev, "%s: warning gain override failed\n", | ||
462 | __func__); | ||
463 | |||
464 | control.id = V4L2_CID_FRAME_LENGTH; | ||
465 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
466 | err |= imx214_set_frame_length(priv, control.value); | ||
467 | if (err) | ||
468 | dev_dbg(&client->dev, | ||
469 | "%s: frame length override failed\n", __func__); | ||
470 | |||
471 | control.id = V4L2_CID_COARSE_TIME; | ||
472 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
473 | err |= imx214_set_coarse_time(priv, control.value); | ||
474 | if (err) | ||
475 | dev_dbg(&client->dev, | ||
476 | "%s: coarse time override failed\n", __func__); | ||
477 | |||
478 | control.id = V4L2_CID_COARSE_TIME_SHORT; | ||
479 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
480 | err |= imx214_set_coarse_time_short(priv, control.value); | ||
481 | if (err) | ||
482 | dev_dbg(&client->dev, | ||
483 | "%s: warning coarse time short override failed\n", | ||
484 | __func__); | ||
485 | } | ||
486 | |||
487 | err = imx214_write_table(priv, mode_table[IMX214_MODE_START_STREAM]); | ||
488 | if (err) | ||
489 | goto exit; | ||
490 | |||
491 | if (test_mode) | ||
492 | err = imx214_write_table(priv, | ||
493 | mode_table[IMX214_MODE_TEST_PATTERN]); | ||
494 | |||
495 | return 0; | ||
496 | exit: | ||
497 | dev_dbg(&client->dev, "%s: error setting stream\n", __func__); | ||
498 | return err; | ||
499 | } | ||
500 | |||
501 | static struct v4l2_subdev_video_ops imx214_subdev_video_ops = { | ||
502 | .s_stream = imx214_s_stream, | ||
503 | .s_mbus_fmt = camera_common_s_fmt, | ||
504 | .g_mbus_fmt = camera_common_g_fmt, | ||
505 | .try_mbus_fmt = camera_common_try_fmt, | ||
506 | .enum_mbus_fmt = camera_common_enum_fmt, | ||
507 | .g_mbus_config = camera_common_g_mbus_config, | ||
508 | }; | ||
509 | |||
510 | static struct v4l2_subdev_core_ops imx214_subdev_core_ops = { | ||
511 | .s_power = camera_common_s_power, | ||
512 | }; | ||
513 | |||
514 | static struct v4l2_subdev_pad_ops imx214_subdev_pad_ops = { | ||
515 | .enum_mbus_code = camera_common_enum_mbus_code, | ||
516 | }; | ||
517 | |||
518 | static struct v4l2_subdev_ops imx214_subdev_ops = { | ||
519 | .core = &imx214_subdev_core_ops, | ||
520 | .video = &imx214_subdev_video_ops, | ||
521 | .pad = &imx214_subdev_pad_ops, | ||
522 | }; | ||
523 | |||
524 | static struct of_device_id imx214_of_match[] = { | ||
525 | { .compatible = "nvidia,imx214", }, | ||
526 | { }, | ||
527 | }; | ||
528 | |||
529 | static struct camera_common_sensor_ops imx214_common_ops = { | ||
530 | .power_on = imx214_power_on, | ||
531 | .power_off = imx214_power_off, | ||
532 | .write_reg = imx214_write_reg, | ||
533 | .read_reg = imx214_read_reg, | ||
534 | }; | ||
535 | |||
536 | static int imx214_set_group_hold(struct imx214 *priv) | ||
537 | { | ||
538 | int err; | ||
539 | int gh_prev = switch_ctrl_qmenu[priv->group_hold_prev]; | ||
540 | |||
541 | if (priv->group_hold_en == true && gh_prev == SWITCH_OFF) { | ||
542 | err = imx214_write_reg(priv->s_data, | ||
543 | IMX214_GROUP_HOLD_ADDR, 0x1); | ||
544 | if (err) | ||
545 | goto fail; | ||
546 | priv->group_hold_prev = 1; | ||
547 | } else if (priv->group_hold_en == false && gh_prev == SWITCH_ON) { | ||
548 | err = imx214_write_reg(priv->s_data, | ||
549 | IMX214_GROUP_HOLD_ADDR, 0x0); | ||
550 | if (err) | ||
551 | goto fail; | ||
552 | priv->group_hold_prev = 0; | ||
553 | } | ||
554 | |||
555 | return 0; | ||
556 | |||
557 | fail: | ||
558 | dev_dbg(&priv->i2c_client->dev, | ||
559 | "%s: Group hold control error\n", __func__); | ||
560 | return err; | ||
561 | } | ||
562 | |||
563 | static int imx214_calculate_gain(u32 rep, int shift) | ||
564 | { | ||
565 | int gain; | ||
566 | int gain_int; | ||
567 | int gain_dec; | ||
568 | int min_int = (1 << shift); | ||
569 | int denom; | ||
570 | |||
571 | /* shift indicates number of least significant bits | ||
572 | * used for decimal representation of gain */ | ||
573 | gain_int = (int)(rep >> shift); | ||
574 | gain_dec = (int)(rep & ~(0xffff << shift)); | ||
575 | |||
576 | denom = gain_int * min_int + gain_dec; | ||
577 | gain = 512 - ((512 * min_int + (denom - 1)) / denom); | ||
578 | |||
579 | return gain; | ||
580 | } | ||
581 | |||
582 | static int imx214_set_gain(struct imx214 *priv, s32 val) | ||
583 | { | ||
584 | imx214_reg reg_list[2]; | ||
585 | imx214_reg reg_list_short[2]; | ||
586 | int err; | ||
587 | u16 gain; | ||
588 | int i = 0; | ||
589 | |||
590 | /* translate value */ | ||
591 | gain = (u16)imx214_calculate_gain(val, IMX214_GAIN_SHIFT); | ||
592 | |||
593 | dev_dbg(&priv->i2c_client->dev, | ||
594 | "%s: val: %d\n", __func__, gain); | ||
595 | |||
596 | imx214_get_gain_regs(reg_list, gain); | ||
597 | imx214_get_gain_short_reg(reg_list_short, gain); | ||
598 | imx214_set_group_hold(priv); | ||
599 | |||
600 | /* writing long gain */ | ||
601 | for (i = 0; i < 2; i++) { | ||
602 | err = imx214_write_reg(priv->s_data, reg_list[i].addr, | ||
603 | reg_list[i].val); | ||
604 | if (err) | ||
605 | goto fail; | ||
606 | } | ||
607 | /* writing short gain */ | ||
608 | for (i = 0; i < 2; i++) { | ||
609 | err = imx214_write_reg(priv->s_data, reg_list_short[i].addr, | ||
610 | reg_list_short[i].val); | ||
611 | if (err) | ||
612 | goto fail; | ||
613 | } | ||
614 | |||
615 | return 0; | ||
616 | |||
617 | fail: | ||
618 | dev_dbg(&priv->i2c_client->dev, | ||
619 | "%s: GAIN control error\n", __func__); | ||
620 | return err; | ||
621 | } | ||
622 | |||
623 | static int imx214_set_frame_length(struct imx214 *priv, s32 val) | ||
624 | { | ||
625 | imx214_reg reg_list[2]; | ||
626 | int err; | ||
627 | u16 frame_length; | ||
628 | int i = 0; | ||
629 | |||
630 | frame_length = (u16)val; | ||
631 | |||
632 | dev_dbg(&priv->i2c_client->dev, | ||
633 | "%s: val: %d\n", __func__, frame_length); | ||
634 | |||
635 | imx214_get_frame_length_regs(reg_list, frame_length); | ||
636 | imx214_set_group_hold(priv); | ||
637 | |||
638 | for (i = 0; i < 2; i++) { | ||
639 | err = imx214_write_reg(priv->s_data, reg_list[i].addr, | ||
640 | reg_list[i].val); | ||
641 | if (err) | ||
642 | goto fail; | ||
643 | } | ||
644 | |||
645 | return 0; | ||
646 | |||
647 | fail: | ||
648 | dev_dbg(&priv->i2c_client->dev, | ||
649 | "%s: FRAME_LENGTH control error\n", __func__); | ||
650 | return err; | ||
651 | } | ||
652 | |||
653 | static int imx214_set_coarse_time(struct imx214 *priv, s32 val) | ||
654 | { | ||
655 | imx214_reg reg_list[2]; | ||
656 | int err; | ||
657 | u16 coarse_time; | ||
658 | int i = 0; | ||
659 | |||
660 | coarse_time = (u16)val; | ||
661 | |||
662 | dev_dbg(&priv->i2c_client->dev, | ||
663 | "%s: val: %d\n", __func__, coarse_time); | ||
664 | |||
665 | imx214_get_coarse_time_regs(reg_list, coarse_time); | ||
666 | imx214_set_group_hold(priv); | ||
667 | |||
668 | for (i = 0; i < 2; i++) { | ||
669 | err = imx214_write_reg(priv->s_data, reg_list[i].addr, | ||
670 | reg_list[i].val); | ||
671 | if (err) | ||
672 | goto fail; | ||
673 | } | ||
674 | |||
675 | return 0; | ||
676 | |||
677 | fail: | ||
678 | dev_dbg(&priv->i2c_client->dev, | ||
679 | "%s: COARSE_TIME control error\n", __func__); | ||
680 | return err; | ||
681 | } | ||
682 | |||
683 | static int imx214_set_coarse_time_short(struct imx214 *priv, s32 val) | ||
684 | { | ||
685 | imx214_reg reg_list[2]; | ||
686 | int err; | ||
687 | struct v4l2_control hdr_control; | ||
688 | int hdr_en; | ||
689 | u16 coarse_time_short; | ||
690 | int i = 0; | ||
691 | |||
692 | /* check hdr enable ctrl */ | ||
693 | hdr_control.id = V4L2_CID_HDR_EN; | ||
694 | |||
695 | err = camera_common_g_ctrl(priv->s_data, &hdr_control); | ||
696 | if (err < 0) { | ||
697 | dev_err(&priv->i2c_client->dev, | ||
698 | "could not find device ctrl.\n"); | ||
699 | return err; | ||
700 | } | ||
701 | |||
702 | hdr_en = switch_ctrl_qmenu[hdr_control.value]; | ||
703 | if (hdr_en == SWITCH_OFF) | ||
704 | return 0; | ||
705 | |||
706 | coarse_time_short = (u16)val; | ||
707 | |||
708 | dev_dbg(&priv->i2c_client->dev, | ||
709 | "%s: val: %d\n", __func__, coarse_time_short); | ||
710 | |||
711 | imx214_get_coarse_time_short_regs(reg_list, coarse_time_short); | ||
712 | imx214_set_group_hold(priv); | ||
713 | |||
714 | for (i = 0; i < 2; i++) { | ||
715 | err = imx214_write_reg(priv->s_data, reg_list[i].addr, | ||
716 | reg_list[i].val); | ||
717 | if (err) | ||
718 | goto fail; | ||
719 | } | ||
720 | |||
721 | return 0; | ||
722 | |||
723 | fail: | ||
724 | dev_dbg(&priv->i2c_client->dev, | ||
725 | "%s: COARSE_TIME_SHORT control error\n", __func__); | ||
726 | return err; | ||
727 | } | ||
728 | |||
729 | static int imx214_eeprom_device_release(struct imx214 *priv) | ||
730 | { | ||
731 | int i; | ||
732 | |||
733 | for (i = 0; i < IMX214_EEPROM_NUM_BLOCKS; i++) { | ||
734 | if (priv->eeprom[i].i2c_client != NULL) { | ||
735 | i2c_unregister_device(priv->eeprom[i].i2c_client); | ||
736 | priv->eeprom[i].i2c_client = NULL; | ||
737 | } | ||
738 | } | ||
739 | |||
740 | return 0; | ||
741 | } | ||
742 | |||
743 | static int imx214_eeprom_device_init(struct imx214 *priv) | ||
744 | { | ||
745 | char *dev_name = "eeprom_imx214"; | ||
746 | static struct regmap_config eeprom_regmap_config = { | ||
747 | .reg_bits = 8, | ||
748 | .val_bits = 8, | ||
749 | }; | ||
750 | int i; | ||
751 | int err; | ||
752 | struct v4l2_ctrl *ctrl; | ||
753 | |||
754 | ctrl = v4l2_ctrl_find(&priv->ctrl_handler, V4L2_CID_EEPROM_DATA); | ||
755 | if (!ctrl) { | ||
756 | dev_err(&priv->i2c_client->dev, | ||
757 | "could not find device ctrl.\n"); | ||
758 | return -EINVAL; | ||
759 | } | ||
760 | |||
761 | for (i = 0; i < IMX214_EEPROM_NUM_BLOCKS; i++) { | ||
762 | priv->eeprom[i].adap = i2c_get_adapter( | ||
763 | priv->i2c_client->adapter->nr); | ||
764 | memset(&priv->eeprom[i].brd, 0, sizeof(priv->eeprom[i].brd)); | ||
765 | strncpy(priv->eeprom[i].brd.type, dev_name, | ||
766 | sizeof(priv->eeprom[i].brd.type)); | ||
767 | priv->eeprom[i].brd.addr = IMX214_EEPROM_ADDRESS + i; | ||
768 | priv->eeprom[i].i2c_client = i2c_new_device( | ||
769 | priv->eeprom[i].adap, &priv->eeprom[i].brd); | ||
770 | |||
771 | priv->eeprom[i].regmap = devm_regmap_init_i2c( | ||
772 | priv->eeprom[i].i2c_client, &eeprom_regmap_config); | ||
773 | if (IS_ERR(priv->eeprom[i].regmap)) { | ||
774 | err = PTR_ERR(priv->eeprom[i].regmap); | ||
775 | imx214_eeprom_device_release(priv); | ||
776 | ctrl->flags = V4L2_CTRL_FLAG_DISABLED; | ||
777 | return err; | ||
778 | } | ||
779 | } | ||
780 | |||
781 | return 0; | ||
782 | } | ||
783 | |||
784 | static int imx214_read_eeprom(struct imx214 *priv, | ||
785 | struct v4l2_ctrl *ctrl) | ||
786 | { | ||
787 | int err, i; | ||
788 | |||
789 | for (i = 0; i < IMX214_EEPROM_NUM_BLOCKS; i++) { | ||
790 | err = regmap_bulk_read(priv->eeprom[i].regmap, 0, | ||
791 | &priv->eeprom_buf[i * IMX214_EEPROM_BLOCK_SIZE], | ||
792 | IMX214_EEPROM_BLOCK_SIZE); | ||
793 | if (err) | ||
794 | return err; | ||
795 | } | ||
796 | |||
797 | for (i = 0; i < IMX214_EEPROM_SIZE; i++) | ||
798 | sprintf(&ctrl->string[i*2], "%02x", | ||
799 | priv->eeprom_buf[i]); | ||
800 | return 0; | ||
801 | } | ||
802 | |||
803 | static int imx214_write_eeprom(struct imx214 *priv, | ||
804 | char *string) | ||
805 | { | ||
806 | int err; | ||
807 | int i; | ||
808 | u8 curr[3]; | ||
809 | unsigned long data; | ||
810 | |||
811 | for (i = 0; i < IMX214_EEPROM_SIZE; i++) { | ||
812 | curr[0] = string[i*2]; | ||
813 | curr[1] = string[i*2+1]; | ||
814 | curr[2] = '\0'; | ||
815 | |||
816 | err = kstrtol(curr, 16, &data); | ||
817 | if (err) { | ||
818 | dev_err(&priv->i2c_client->dev, | ||
819 | "invalid eeprom string\n"); | ||
820 | return -EINVAL; | ||
821 | } | ||
822 | |||
823 | priv->eeprom_buf[i] = (u8)data; | ||
824 | err = regmap_write(priv->eeprom[i >> 8].regmap, | ||
825 | i & 0xFF, (u8)data); | ||
826 | if (err) | ||
827 | return err; | ||
828 | msleep(20); | ||
829 | } | ||
830 | return 0; | ||
831 | } | ||
832 | |||
833 | static int imx214_read_otp_page(struct imx214 *priv, | ||
834 | u8 *buf, int page, u16 addr, int size) | ||
835 | { | ||
836 | u8 status; | ||
837 | int err; | ||
838 | |||
839 | err = imx214_write_reg(priv->s_data, IMX214_OTP_PAGE_NUM_ADDR, page); | ||
840 | if (err) | ||
841 | return err; | ||
842 | err = imx214_write_reg(priv->s_data, IMX214_OTP_CTRL_ADDR, 0x01); | ||
843 | if (err) | ||
844 | return err; | ||
845 | err = imx214_read_reg(priv->s_data, IMX214_OTP_STATUS_ADDR, &status); | ||
846 | if (err) | ||
847 | return err; | ||
848 | if (status == IMX214_OTP_STATUS_IN_PROGRESS) { | ||
849 | dev_err(&priv->i2c_client->dev, | ||
850 | "another OTP read in progress\n"); | ||
851 | return err; | ||
852 | } | ||
853 | |||
854 | err = regmap_bulk_read(priv->regmap, addr, buf, size); | ||
855 | if (err) | ||
856 | return err; | ||
857 | |||
858 | err = imx214_read_reg(priv->s_data, IMX214_OTP_STATUS_ADDR, &status); | ||
859 | if (err) | ||
860 | return err; | ||
861 | if (status == IMX214_OTP_STATUS_READ_FAIL) { | ||
862 | dev_err(&priv->i2c_client->dev, "fuse id read error\n"); | ||
863 | return err; | ||
864 | } | ||
865 | |||
866 | return 0; | ||
867 | } | ||
868 | |||
869 | static int imx214_otp_setup(struct imx214 *priv) | ||
870 | { | ||
871 | int err; | ||
872 | int i; | ||
873 | struct v4l2_ctrl *ctrl; | ||
874 | u8 otp_buf[IMX214_OTP_SIZE]; | ||
875 | |||
876 | err = camera_common_s_power(priv->subdev, true); | ||
877 | if (err) | ||
878 | return -ENODEV; | ||
879 | |||
880 | for (i = 0; i < IMX214_OTP_NUM_PAGES; i++) { | ||
881 | imx214_read_otp_page(priv, | ||
882 | &otp_buf[i * IMX214_OTP_PAGE_SIZE], | ||
883 | i, | ||
884 | IMX214_OTP_PAGE_START_ADDR, | ||
885 | IMX214_OTP_PAGE_SIZE); | ||
886 | } | ||
887 | |||
888 | ctrl = v4l2_ctrl_find(&priv->ctrl_handler, V4L2_CID_OTP_DATA); | ||
889 | if (!ctrl) { | ||
890 | dev_err(&priv->i2c_client->dev, | ||
891 | "could not find device ctrl.\n"); | ||
892 | return -EINVAL; | ||
893 | } | ||
894 | |||
895 | for (i = 0; i < IMX214_OTP_SIZE; i++) | ||
896 | sprintf(&ctrl->string[i*2], "%02x", | ||
897 | otp_buf[i]); | ||
898 | ctrl->cur.string = ctrl->string; | ||
899 | |||
900 | err = camera_common_s_power(priv->subdev, false); | ||
901 | if (err) | ||
902 | return -ENODEV; | ||
903 | |||
904 | return 0; | ||
905 | } | ||
906 | |||
907 | static int imx214_fuse_id_setup(struct imx214 *priv) | ||
908 | { | ||
909 | int err; | ||
910 | int i; | ||
911 | struct v4l2_ctrl *ctrl; | ||
912 | u8 fuse_id[IMX214_FUSE_ID_SIZE]; | ||
913 | |||
914 | err = camera_common_s_power(priv->subdev, true); | ||
915 | if (err) | ||
916 | return -ENODEV; | ||
917 | |||
918 | imx214_read_otp_page(priv, | ||
919 | &fuse_id[0], | ||
920 | IMX214_FUSE_ID_OTP_PAGE, | ||
921 | IMX214_FUSE_ID_OTP_ROW_ADDR, | ||
922 | IMX214_FUSE_ID_SIZE); | ||
923 | |||
924 | ctrl = v4l2_ctrl_find(&priv->ctrl_handler, V4L2_CID_FUSE_ID); | ||
925 | if (!ctrl) { | ||
926 | dev_err(&priv->i2c_client->dev, | ||
927 | "could not find device ctrl.\n"); | ||
928 | return -EINVAL; | ||
929 | } | ||
930 | |||
931 | for (i = 0; i < IMX214_FUSE_ID_SIZE; i++) | ||
932 | sprintf(&ctrl->string[i*2], "%02x", | ||
933 | fuse_id[i]); | ||
934 | ctrl->cur.string = ctrl->string; | ||
935 | |||
936 | err = camera_common_s_power(priv->subdev, false); | ||
937 | if (err) | ||
938 | return -ENODEV; | ||
939 | |||
940 | return 0; | ||
941 | } | ||
942 | |||
943 | static int imx214_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | ||
944 | { | ||
945 | struct imx214 *priv = | ||
946 | container_of(ctrl->handler, struct imx214, ctrl_handler); | ||
947 | int err = 0; | ||
948 | |||
949 | if (priv->power.state == SWITCH_OFF) | ||
950 | return 0; | ||
951 | |||
952 | switch (ctrl->id) { | ||
953 | case V4L2_CID_EEPROM_DATA: | ||
954 | err = imx214_read_eeprom(priv, ctrl); | ||
955 | if (err) | ||
956 | return err; | ||
957 | break; | ||
958 | default: | ||
959 | pr_err("%s: unknown ctrl id.\n", __func__); | ||
960 | return -EINVAL; | ||
961 | } | ||
962 | |||
963 | return err; | ||
964 | } | ||
965 | |||
966 | static int imx214_s_ctrl(struct v4l2_ctrl *ctrl) | ||
967 | { | ||
968 | struct imx214 *priv = | ||
969 | container_of(ctrl->handler, struct imx214, ctrl_handler); | ||
970 | int err = 0; | ||
971 | |||
972 | if (priv->power.state == SWITCH_OFF) | ||
973 | return 0; | ||
974 | |||
975 | switch (ctrl->id) { | ||
976 | case V4L2_CID_GAIN: | ||
977 | err = imx214_set_gain(priv, ctrl->val); | ||
978 | break; | ||
979 | case V4L2_CID_FRAME_LENGTH: | ||
980 | err = imx214_set_frame_length(priv, ctrl->val); | ||
981 | break; | ||
982 | case V4L2_CID_COARSE_TIME: | ||
983 | err = imx214_set_coarse_time(priv, ctrl->val); | ||
984 | break; | ||
985 | case V4L2_CID_COARSE_TIME_SHORT: | ||
986 | err = imx214_set_coarse_time_short(priv, ctrl->val); | ||
987 | break; | ||
988 | case V4L2_CID_GROUP_HOLD: | ||
989 | if (switch_ctrl_qmenu[ctrl->val] == SWITCH_ON) { | ||
990 | priv->group_hold_en = true; | ||
991 | } else { | ||
992 | priv->group_hold_en = false; | ||
993 | err = imx214_set_group_hold(priv); | ||
994 | } | ||
995 | break; | ||
996 | case V4L2_CID_EEPROM_DATA: | ||
997 | if (!ctrl->string[0]) | ||
998 | break; | ||
999 | err = imx214_write_eeprom(priv, ctrl->string); | ||
1000 | if (err) | ||
1001 | return err; | ||
1002 | break; | ||
1003 | case V4L2_CID_HDR_EN: | ||
1004 | break; | ||
1005 | default: | ||
1006 | pr_err("%s: unknown ctrl id.\n", __func__); | ||
1007 | return -EINVAL; | ||
1008 | } | ||
1009 | |||
1010 | return err; | ||
1011 | } | ||
1012 | |||
1013 | static int imx214_ctrls_init(struct imx214 *priv) | ||
1014 | { | ||
1015 | struct i2c_client *client = priv->i2c_client; | ||
1016 | struct v4l2_ctrl *ctrl; | ||
1017 | int numctrls; | ||
1018 | int err; | ||
1019 | int i; | ||
1020 | |||
1021 | dev_dbg(&client->dev, "%s++\n", __func__); | ||
1022 | |||
1023 | numctrls = ARRAY_SIZE(ctrl_config_list); | ||
1024 | v4l2_ctrl_handler_init(&priv->ctrl_handler, numctrls); | ||
1025 | |||
1026 | for (i = 0; i < numctrls; i++) { | ||
1027 | ctrl = v4l2_ctrl_new_custom(&priv->ctrl_handler, | ||
1028 | &ctrl_config_list[i], NULL); | ||
1029 | if (ctrl == NULL) { | ||
1030 | dev_err(&client->dev, "Failed to init %s ctrl\n", | ||
1031 | ctrl_config_list[i].name); | ||
1032 | continue; | ||
1033 | } | ||
1034 | |||
1035 | if (ctrl_config_list[i].type == V4L2_CTRL_TYPE_STRING && | ||
1036 | ctrl_config_list[i].flags & V4L2_CTRL_FLAG_READ_ONLY) { | ||
1037 | ctrl->string = devm_kzalloc(&client->dev, | ||
1038 | ctrl_config_list[i].max + 1, GFP_KERNEL); | ||
1039 | if (!ctrl->string) { | ||
1040 | dev_err(&client->dev, | ||
1041 | "Failed to allocate otp data\n"); | ||
1042 | return -ENOMEM; | ||
1043 | } | ||
1044 | } | ||
1045 | priv->ctrls[i] = ctrl; | ||
1046 | } | ||
1047 | |||
1048 | priv->numctrls = numctrls; | ||
1049 | priv->subdev->ctrl_handler = &priv->ctrl_handler; | ||
1050 | if (priv->ctrl_handler.error) { | ||
1051 | dev_err(&client->dev, "Error %d adding controls\n", | ||
1052 | priv->ctrl_handler.error); | ||
1053 | err = priv->ctrl_handler.error; | ||
1054 | goto error; | ||
1055 | } | ||
1056 | |||
1057 | err = v4l2_ctrl_handler_setup(&priv->ctrl_handler); | ||
1058 | if (err) { | ||
1059 | dev_err(&client->dev, | ||
1060 | "Error %d setting default controls\n", err); | ||
1061 | goto error; | ||
1062 | } | ||
1063 | |||
1064 | err = imx214_otp_setup(priv); | ||
1065 | if (err) { | ||
1066 | dev_err(&client->dev, | ||
1067 | "Error %d reading otp data\n", err); | ||
1068 | goto error; | ||
1069 | } | ||
1070 | |||
1071 | err = imx214_fuse_id_setup(priv); | ||
1072 | if (err) { | ||
1073 | dev_err(&client->dev, | ||
1074 | "Error %d reading fuse id data\n", err); | ||
1075 | goto error; | ||
1076 | } | ||
1077 | |||
1078 | return 0; | ||
1079 | |||
1080 | error: | ||
1081 | v4l2_ctrl_handler_free(&priv->ctrl_handler); | ||
1082 | return err; | ||
1083 | } | ||
1084 | |||
1085 | MODULE_DEVICE_TABLE(of, imx214_of_match); | ||
1086 | |||
1087 | static struct camera_common_pdata *imx214_parse_dt(struct i2c_client *client) | ||
1088 | { | ||
1089 | struct device_node *np = client->dev.of_node; | ||
1090 | struct camera_common_pdata *board_priv_pdata; | ||
1091 | const struct of_device_id *match; | ||
1092 | |||
1093 | match = of_match_device(imx214_of_match, &client->dev); | ||
1094 | if (!match) { | ||
1095 | dev_err(&client->dev, "Failed to find matching dt id\n"); | ||
1096 | return NULL; | ||
1097 | } | ||
1098 | |||
1099 | board_priv_pdata = devm_kzalloc(&client->dev, | ||
1100 | sizeof(*board_priv_pdata), GFP_KERNEL); | ||
1101 | if (!board_priv_pdata) { | ||
1102 | dev_err(&client->dev, "Failed to allocate pdata\n"); | ||
1103 | return NULL; | ||
1104 | } | ||
1105 | |||
1106 | of_property_read_string(np, "mclk", &board_priv_pdata->mclk_name); | ||
1107 | board_priv_pdata->pwdn_gpio = of_get_named_gpio(np, "pwdn-gpios", 0); | ||
1108 | board_priv_pdata->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0); | ||
1109 | board_priv_pdata->af_gpio = of_get_named_gpio(np, "af-gpios", 0); | ||
1110 | |||
1111 | of_property_read_string(np, "avdd-reg", | ||
1112 | &board_priv_pdata->regulators.avdd); | ||
1113 | of_property_read_string(np, "dvdd-reg", | ||
1114 | &board_priv_pdata->regulators.dvdd); | ||
1115 | of_property_read_string(np, "iovdd-reg", | ||
1116 | &board_priv_pdata->regulators.iovdd); | ||
1117 | |||
1118 | return board_priv_pdata; | ||
1119 | } | ||
1120 | |||
1121 | static int imx214_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
1122 | { | ||
1123 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1124 | dev_dbg(&client->dev, "%s:\n", __func__); | ||
1125 | |||
1126 | |||
1127 | return 0; | ||
1128 | } | ||
1129 | |||
1130 | static const struct v4l2_subdev_internal_ops imx214_subdev_internal_ops = { | ||
1131 | .open = imx214_open, | ||
1132 | }; | ||
1133 | |||
1134 | static const struct media_entity_operations imx214_media_ops = { | ||
1135 | .link_validate = v4l2_subdev_link_validate, | ||
1136 | }; | ||
1137 | |||
1138 | static int imx214_probe(struct i2c_client *client, | ||
1139 | const struct i2c_device_id *id) | ||
1140 | { | ||
1141 | struct camera_common_data *common_data; | ||
1142 | struct device_node *node = client->dev.of_node; | ||
1143 | struct imx214 *priv; | ||
1144 | char debugfs_name[10]; | ||
1145 | int err; | ||
1146 | |||
1147 | pr_info("[IMX214]: probing v4l2 sensor.\n"); | ||
1148 | |||
1149 | if (!IS_ENABLED(CONFIG_OF) || !node) | ||
1150 | return -EINVAL; | ||
1151 | |||
1152 | common_data = devm_kzalloc(&client->dev, | ||
1153 | sizeof(struct camera_common_data), GFP_KERNEL); | ||
1154 | if (!common_data) { | ||
1155 | dev_err(&client->dev, "unable to allocate memory!\n"); | ||
1156 | return -ENOMEM; | ||
1157 | } | ||
1158 | |||
1159 | priv = devm_kzalloc(&client->dev, | ||
1160 | sizeof(struct imx214) + sizeof(struct v4l2_ctrl *) * | ||
1161 | ARRAY_SIZE(ctrl_config_list), | ||
1162 | GFP_KERNEL); | ||
1163 | if (!priv) { | ||
1164 | dev_err(&client->dev, "unable to allocate memory!\n"); | ||
1165 | return -ENOMEM; | ||
1166 | } | ||
1167 | |||
1168 | priv->regmap = devm_regmap_init_i2c(client, &sensor_regmap_config); | ||
1169 | if (IS_ERR(priv->regmap)) { | ||
1170 | dev_err(&client->dev, | ||
1171 | "regmap init failed: %ld\n", PTR_ERR(priv->regmap)); | ||
1172 | return -ENODEV; | ||
1173 | } | ||
1174 | |||
1175 | priv->pdata = imx214_parse_dt(client); | ||
1176 | if (!priv->pdata) { | ||
1177 | dev_err(&client->dev, "unable to get platform data\n"); | ||
1178 | return -EFAULT; | ||
1179 | } | ||
1180 | |||
1181 | common_data->ops = &imx214_common_ops; | ||
1182 | common_data->ctrl_handler = &priv->ctrl_handler; | ||
1183 | common_data->i2c_client = client; | ||
1184 | common_data->frmfmt = &imx214_frmfmt[0]; | ||
1185 | common_data->colorfmt = camera_common_find_datafmt( | ||
1186 | IMX214_DEFAULT_DATAFMT); | ||
1187 | common_data->ctrls = priv->ctrls; | ||
1188 | common_data->power = &priv->power; | ||
1189 | common_data->priv = (void *)priv; | ||
1190 | common_data->numctrls = ARRAY_SIZE(ctrl_config_list); | ||
1191 | common_data->numfmts = ARRAY_SIZE(imx214_frmfmt); | ||
1192 | common_data->def_mode = IMX214_DEFAULT_MODE; | ||
1193 | common_data->def_width = IMX214_DEFAULT_WIDTH; | ||
1194 | common_data->def_height = IMX214_DEFAULT_HEIGHT; | ||
1195 | common_data->fmt_width = common_data->def_width; | ||
1196 | common_data->fmt_height = common_data->def_height; | ||
1197 | common_data->def_clk_freq = IMX214_DEFAULT_CLK_FREQ; | ||
1198 | |||
1199 | priv->i2c_client = client; | ||
1200 | priv->s_data = common_data; | ||
1201 | priv->subdev = &common_data->subdev; | ||
1202 | priv->subdev->dev = &client->dev; | ||
1203 | priv->s_data->dev = &client->dev; | ||
1204 | |||
1205 | err = imx214_power_get(priv); | ||
1206 | if (err) | ||
1207 | return err; | ||
1208 | |||
1209 | err = camera_common_parse_ports(client, common_data); | ||
1210 | if (err) { | ||
1211 | dev_err(&client->dev, "Failed to find port info\n"); | ||
1212 | return err; | ||
1213 | } | ||
1214 | sprintf(debugfs_name, "imx214_%c", common_data->csi_port + 'a'); | ||
1215 | dev_dbg(&client->dev, "%s: name %s\n", __func__, debugfs_name); | ||
1216 | camera_common_create_debugfs(common_data, debugfs_name); | ||
1217 | |||
1218 | v4l2_i2c_subdev_init(priv->subdev, client, &imx214_subdev_ops); | ||
1219 | |||
1220 | err = imx214_ctrls_init(priv); | ||
1221 | if (err) | ||
1222 | return err; | ||
1223 | |||
1224 | /* eeprom interface */ | ||
1225 | err = imx214_eeprom_device_init(priv); | ||
1226 | if (err) | ||
1227 | dev_err(&client->dev, | ||
1228 | "Failed to allocate eeprom register map: %d\n", err); | ||
1229 | |||
1230 | priv->subdev->internal_ops = &imx214_subdev_internal_ops; | ||
1231 | priv->subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | | ||
1232 | V4L2_SUBDEV_FL_HAS_EVENTS; | ||
1233 | |||
1234 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
1235 | priv->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
1236 | priv->subdev->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; | ||
1237 | priv->subdev->entity.ops = &imx214_media_ops; | ||
1238 | err = media_entity_init(&priv->subdev->entity, 1, &priv->pad, 0); | ||
1239 | if (err < 0) { | ||
1240 | dev_err(&client->dev, "unable to init media entity\n"); | ||
1241 | return err; | ||
1242 | } | ||
1243 | #endif | ||
1244 | |||
1245 | err = v4l2_async_register_subdev(priv->subdev); | ||
1246 | if (err) | ||
1247 | return err; | ||
1248 | |||
1249 | dev_dbg(&client->dev, "Detected IMX214 sensor\n"); | ||
1250 | |||
1251 | return 0; | ||
1252 | } | ||
1253 | |||
1254 | static int | ||
1255 | imx214_remove(struct i2c_client *client) | ||
1256 | { | ||
1257 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
1258 | struct imx214 *priv = (struct imx214 *)s_data->priv; | ||
1259 | |||
1260 | v4l2_async_unregister_subdev(priv->subdev); | ||
1261 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
1262 | media_entity_cleanup(&priv->subdev->entity); | ||
1263 | #endif | ||
1264 | v4l2_ctrl_handler_free(&priv->ctrl_handler); | ||
1265 | imx214_power_put(priv); | ||
1266 | camera_common_remove_debugfs(s_data); | ||
1267 | |||
1268 | return 0; | ||
1269 | } | ||
1270 | |||
1271 | static const struct i2c_device_id imx214_id[] = { | ||
1272 | { "imx214", 0 }, | ||
1273 | { } | ||
1274 | }; | ||
1275 | |||
1276 | MODULE_DEVICE_TABLE(i2c, imx214_id); | ||
1277 | |||
1278 | static struct i2c_driver imx214_i2c_driver = { | ||
1279 | .driver = { | ||
1280 | .name = "imx214", | ||
1281 | .owner = THIS_MODULE, | ||
1282 | .of_match_table = of_match_ptr(imx214_of_match), | ||
1283 | }, | ||
1284 | .probe = imx214_probe, | ||
1285 | .remove = imx214_remove, | ||
1286 | .id_table = imx214_id, | ||
1287 | }; | ||
1288 | |||
1289 | module_i2c_driver(imx214_i2c_driver); | ||
1290 | |||
1291 | MODULE_DESCRIPTION("SoC Camera driver for Sony IMX214"); | ||
1292 | MODULE_AUTHOR("David Wang <davidw@nvidia.com>"); | ||
1293 | MODULE_LICENSE("GPL v2"); | ||
1294 | |||
diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c new file mode 100644 index 000000000..ba36dc721 --- /dev/null +++ b/drivers/media/i2c/imx219.c | |||
@@ -0,0 +1,873 @@ | |||
1 | /* | ||
2 | * imx219.c - imx219 sensor driver | ||
3 | * | ||
4 | * Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <dt-bindings/gpio/tegra-gpio.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/uaccess.h> | ||
22 | #include <linux/gpio.h> | ||
23 | #include <linux/module.h> | ||
24 | |||
25 | #include <linux/seq_file.h> | ||
26 | #include <linux/of.h> | ||
27 | #include <linux/of_device.h> | ||
28 | #include <linux/of_gpio.h> | ||
29 | |||
30 | #include <media/camera_common.h> | ||
31 | #include <media/soc_camera.h> | ||
32 | #include <media/imx219.h> | ||
33 | |||
34 | #include "imx219_mode_tbls.h" | ||
35 | |||
36 | #define IMX219_MAX_COARSE_DIFF 4 | ||
37 | |||
38 | #define IMX219_GAIN_SHIFT 8 | ||
39 | #define IMX219_MIN_GAIN (1 << IMX219_GAIN_SHIFT) | ||
40 | #define IMX219_MAX_GAIN (16 << IMX219_GAIN_SHIFT) | ||
41 | #define IMX219_MIN_FRAME_LENGTH (0x9C3) | ||
42 | #define IMX219_MAX_FRAME_LENGTH (0xFFFF) | ||
43 | #define IMX219_MIN_EXPOSURE_COARSE (0x0001) | ||
44 | #define IMX219_MAX_EXPOSURE_COARSE \ | ||
45 | (IMX219_MAX_FRAME_LENGTH-IMX219_MAX_COARSE_DIFF) | ||
46 | |||
47 | #define IMX219_DEFAULT_GAIN IMX219_MIN_GAIN | ||
48 | #define IMX219_DEFAULT_FRAME_LENGTH (0x09C3) | ||
49 | #define IMX219_DEFAULT_EXPOSURE_COARSE \ | ||
50 | (IMX219_DEFAULT_FRAME_LENGTH-IMX219_MAX_COARSE_DIFF) | ||
51 | |||
52 | #define IMX219_DEFAULT_MODE IMX219_MODE_3280x2464 | ||
53 | #define IMX219_DEFAULT_WIDTH 3280 | ||
54 | #define IMX219_DEFAULT_HEIGHT 2464 | ||
55 | #define IMX219_DEFAULT_DATAFMT MEDIA_BUS_FMT_SRGGB10_1X10 | ||
56 | #define IMX219_DEFAULT_CLK_FREQ 12000000 | ||
57 | |||
58 | struct imx219 { | ||
59 | struct camera_common_power_rail power; | ||
60 | int num_ctrls; | ||
61 | struct v4l2_ctrl_handler ctrl_handler; | ||
62 | struct i2c_client *i2c_client; | ||
63 | struct v4l2_subdev *subdev; | ||
64 | struct media_pad pad; | ||
65 | struct regmap *regmap; | ||
66 | struct camera_common_data *s_data; | ||
67 | struct camera_common_pdata *pdata; | ||
68 | struct v4l2_ctrl *ctrls[]; | ||
69 | }; | ||
70 | |||
71 | static const struct regmap_config sensor_regmap_config = { | ||
72 | .reg_bits = 16, | ||
73 | .val_bits = 8, | ||
74 | .cache_type = REGCACHE_RBTREE, | ||
75 | }; | ||
76 | |||
77 | static int imx219_g_volatile_ctrl(struct v4l2_ctrl *ctrl); | ||
78 | static int imx219_s_ctrl(struct v4l2_ctrl *ctrl); | ||
79 | |||
80 | static const struct v4l2_ctrl_ops imx219_ctrl_ops = { | ||
81 | .g_volatile_ctrl = imx219_g_volatile_ctrl, | ||
82 | .s_ctrl = imx219_s_ctrl, | ||
83 | }; | ||
84 | |||
85 | static struct v4l2_ctrl_config ctrl_config_list[] = { | ||
86 | /* Do not change the name field for the controls! */ | ||
87 | { | ||
88 | .ops = &imx219_ctrl_ops, | ||
89 | .id = V4L2_CID_GAIN, | ||
90 | .name = "Gain", | ||
91 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
92 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
93 | .min = IMX219_MIN_GAIN, | ||
94 | .max = IMX219_MAX_GAIN, | ||
95 | .def = IMX219_DEFAULT_GAIN, | ||
96 | .step = 1, | ||
97 | }, | ||
98 | { | ||
99 | .ops = &imx219_ctrl_ops, | ||
100 | .id = V4L2_CID_FRAME_LENGTH, | ||
101 | .name = "Frame Length", | ||
102 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
103 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
104 | .min = IMX219_MIN_FRAME_LENGTH, | ||
105 | .max = IMX219_MAX_FRAME_LENGTH, | ||
106 | .def = IMX219_DEFAULT_FRAME_LENGTH, | ||
107 | .step = 1, | ||
108 | }, | ||
109 | { | ||
110 | .ops = &imx219_ctrl_ops, | ||
111 | .id = V4L2_CID_COARSE_TIME, | ||
112 | .name = "Coarse Time", | ||
113 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
114 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
115 | .min = IMX219_MIN_EXPOSURE_COARSE, | ||
116 | .max = IMX219_MAX_EXPOSURE_COARSE, | ||
117 | .def = IMX219_DEFAULT_EXPOSURE_COARSE, | ||
118 | .step = 1, | ||
119 | }, | ||
120 | { | ||
121 | .ops = &imx219_ctrl_ops, | ||
122 | .id = V4L2_CID_GROUP_HOLD, | ||
123 | .name = "Group Hold", | ||
124 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, | ||
125 | .min = 0, | ||
126 | .max = ARRAY_SIZE(switch_ctrl_qmenu) - 1, | ||
127 | .menu_skip_mask = 0, | ||
128 | .def = 0, | ||
129 | .qmenu_int = switch_ctrl_qmenu, | ||
130 | }, | ||
131 | { | ||
132 | .ops = &imx219_ctrl_ops, | ||
133 | .id = V4L2_CID_HDR_EN, | ||
134 | .name = "HDR enable", | ||
135 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, | ||
136 | .min = 0, | ||
137 | .max = ARRAY_SIZE(switch_ctrl_qmenu) - 1, | ||
138 | .menu_skip_mask = 0, | ||
139 | .def = 0, | ||
140 | .qmenu_int = switch_ctrl_qmenu, | ||
141 | }, | ||
142 | { | ||
143 | .ops = &imx219_ctrl_ops, | ||
144 | .id = V4L2_CID_FUSE_ID, | ||
145 | .name = "Fuse ID", | ||
146 | .type = V4L2_CTRL_TYPE_STRING, | ||
147 | .flags = V4L2_CTRL_FLAG_READ_ONLY, | ||
148 | .min = 0, | ||
149 | .max = IMX219_FUSE_ID_STR_SIZE, | ||
150 | .step = 2, | ||
151 | }, | ||
152 | }; | ||
153 | |||
154 | static inline void imx219_get_gain_reg(struct reg_8 *regs, | ||
155 | u8 gain) | ||
156 | { | ||
157 | regs->addr = IMX219_GAIN_ADDR; | ||
158 | regs->val = gain & 0xff; | ||
159 | } | ||
160 | |||
161 | static int test_mode; | ||
162 | module_param(test_mode, int, 0644); | ||
163 | |||
164 | static inline int imx219_read_reg(struct camera_common_data *s_data, | ||
165 | u16 addr, u8 *val) | ||
166 | { | ||
167 | struct imx219 *priv = (struct imx219 *)s_data->priv; | ||
168 | return regmap_read(priv->regmap, addr, (unsigned int *) val); | ||
169 | } | ||
170 | |||
171 | static int imx219_write_reg(struct camera_common_data *s_data, u16 addr, u8 val) | ||
172 | { | ||
173 | int err; | ||
174 | struct imx219 *priv = (struct imx219 *)s_data->priv; | ||
175 | |||
176 | err = regmap_write(priv->regmap, addr, val); | ||
177 | if (err) | ||
178 | pr_err("%s:i2c write failed, %x = %x\n", | ||
179 | __func__, addr, val); | ||
180 | |||
181 | return err; | ||
182 | } | ||
183 | |||
184 | static int imx219_write_table(struct imx219 *priv, | ||
185 | const struct reg_8 table[]) | ||
186 | { | ||
187 | return regmap_util_write_table_8(priv->regmap, | ||
188 | table, | ||
189 | NULL, 0, | ||
190 | IMX219_TABLE_WAIT_MS, | ||
191 | IMX219_TABLE_END); | ||
192 | } | ||
193 | |||
194 | static void imx219_mclk_disable(struct camera_common_power_rail *pw) | ||
195 | { | ||
196 | clk_disable_unprepare(pw->mclk); | ||
197 | } | ||
198 | |||
199 | static void imx219_mclk_enable(struct camera_common_power_rail *pw) | ||
200 | { | ||
201 | clk_set_rate(pw->mclk, IMX219_DEFAULT_CLK_FREQ); | ||
202 | clk_prepare_enable(pw->mclk); | ||
203 | } | ||
204 | |||
205 | static int imx219_power_on(struct camera_common_data *s_data) | ||
206 | { | ||
207 | int err = 0; | ||
208 | struct imx219 *priv = (struct imx219 *)s_data->priv; | ||
209 | struct camera_common_power_rail *pw = &priv->power; | ||
210 | |||
211 | dev_dbg(&priv->i2c_client->dev, "%s: power on\n", __func__); | ||
212 | |||
213 | if (gpio_cansleep(pw->reset_gpio)) | ||
214 | gpio_set_value_cansleep(pw->reset_gpio, 0); | ||
215 | else | ||
216 | gpio_set_value(pw->reset_gpio, 0); | ||
217 | usleep_range(10, 20); | ||
218 | |||
219 | if (pw->avdd) | ||
220 | err = regulator_enable(pw->avdd); | ||
221 | if (err) | ||
222 | goto imx219_avdd_fail; | ||
223 | |||
224 | if (pw->iovdd) | ||
225 | err = regulator_enable(pw->iovdd); | ||
226 | if (err) | ||
227 | goto imx219_iovdd_fail; | ||
228 | |||
229 | if (pw->dvdd) | ||
230 | err = regulator_enable(pw->dvdd); | ||
231 | if (err) | ||
232 | goto imx219_dvdd_fail; | ||
233 | |||
234 | usleep_range(1, 2); | ||
235 | if (gpio_cansleep(pw->reset_gpio)) | ||
236 | gpio_set_value_cansleep(pw->reset_gpio, 1); | ||
237 | else | ||
238 | gpio_set_value(pw->reset_gpio, 1); | ||
239 | |||
240 | usleep_range(1, 2); | ||
241 | imx219_mclk_enable(pw); | ||
242 | |||
243 | /* Need to wait for t4 + t5 + t9 time as per the data sheet */ | ||
244 | /* t4 - 200us, t5 - 6ms, t9 - 1.2ms */ | ||
245 | usleep_range(7400, 7410); | ||
246 | |||
247 | pw->state = SWITCH_ON; | ||
248 | return 0; | ||
249 | |||
250 | imx219_dvdd_fail: | ||
251 | regulator_disable(pw->iovdd); | ||
252 | |||
253 | imx219_iovdd_fail: | ||
254 | regulator_disable(pw->avdd); | ||
255 | |||
256 | imx219_avdd_fail: | ||
257 | return -ENODEV; | ||
258 | } | ||
259 | |||
260 | static int imx219_power_off(struct camera_common_data *s_data) | ||
261 | { | ||
262 | struct imx219 *priv = (struct imx219 *)s_data->priv; | ||
263 | struct camera_common_power_rail *pw = &priv->power; | ||
264 | |||
265 | dev_dbg(&priv->i2c_client->dev, "%s: power off\n", __func__); | ||
266 | |||
267 | usleep_range(1, 2); | ||
268 | if (gpio_cansleep(pw->reset_gpio)) | ||
269 | gpio_set_value_cansleep(pw->reset_gpio, 0); | ||
270 | else | ||
271 | gpio_set_value(pw->reset_gpio, 0); | ||
272 | usleep_range(1, 2); | ||
273 | |||
274 | if (pw->dvdd) | ||
275 | regulator_disable(pw->dvdd); | ||
276 | if (pw->iovdd) | ||
277 | regulator_disable(pw->iovdd); | ||
278 | if (pw->avdd) | ||
279 | regulator_disable(pw->avdd); | ||
280 | |||
281 | imx219_mclk_disable(pw); | ||
282 | pw->state = SWITCH_OFF; | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static int imx219_power_put(struct imx219 *priv) | ||
287 | { | ||
288 | struct camera_common_power_rail *pw = &priv->power; | ||
289 | if (unlikely(!pw)) | ||
290 | return -EFAULT; | ||
291 | |||
292 | if (likely(pw->avdd)) | ||
293 | regulator_put(pw->avdd); | ||
294 | |||
295 | if (likely(pw->iovdd)) | ||
296 | regulator_put(pw->iovdd); | ||
297 | |||
298 | if (likely(pw->dvdd)) | ||
299 | regulator_put(pw->dvdd); | ||
300 | |||
301 | pw->avdd = NULL; | ||
302 | pw->iovdd = NULL; | ||
303 | pw->dvdd = NULL; | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static int imx219_power_get(struct imx219 *priv) | ||
309 | { | ||
310 | struct camera_common_power_rail *pw = &priv->power; | ||
311 | struct camera_common_pdata *pdata = priv->pdata; | ||
312 | const char *mclk_name; | ||
313 | int err = 0; | ||
314 | |||
315 | mclk_name = priv->pdata->mclk_name ? | ||
316 | priv->pdata->mclk_name : "cam_mclk1"; | ||
317 | pw->mclk = devm_clk_get(&priv->i2c_client->dev, mclk_name); | ||
318 | if (IS_ERR(pw->mclk)) { | ||
319 | dev_err(&priv->i2c_client->dev, | ||
320 | "unable to get clock %s\n", mclk_name); | ||
321 | return PTR_ERR(pw->mclk); | ||
322 | } | ||
323 | |||
324 | /* ananlog 2.7v */ | ||
325 | err |= camera_common_regulator_get(priv->i2c_client, | ||
326 | &pw->avdd, pdata->regulators.avdd); | ||
327 | /* digital 1.2v */ | ||
328 | err |= camera_common_regulator_get(priv->i2c_client, | ||
329 | &pw->dvdd, pdata->regulators.dvdd); | ||
330 | /* IO 1.8v */ | ||
331 | err |= camera_common_regulator_get(priv->i2c_client, | ||
332 | &pw->iovdd, pdata->regulators.iovdd); | ||
333 | |||
334 | if (!err) | ||
335 | pw->reset_gpio = pdata->reset_gpio; | ||
336 | |||
337 | pw->state = SWITCH_OFF; | ||
338 | return err; | ||
339 | } | ||
340 | |||
341 | static int imx219_set_gain(struct imx219 *priv, s32 val); | ||
342 | static int imx219_set_frame_length(struct imx219 *priv, s32 val); | ||
343 | static int imx219_set_coarse_time(struct imx219 *priv, s32 val); | ||
344 | |||
345 | static int imx219_s_stream(struct v4l2_subdev *sd, int enable) | ||
346 | { | ||
347 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
348 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
349 | struct imx219 *priv = (struct imx219 *)s_data->priv; | ||
350 | int err; | ||
351 | |||
352 | dev_dbg(&client->dev, "%s\n", __func__); | ||
353 | |||
354 | if (!enable) | ||
355 | return 0; | ||
356 | |||
357 | err = imx219_write_table(priv, mode_table[s_data->mode]); | ||
358 | if (err) | ||
359 | goto exit; | ||
360 | |||
361 | return 0; | ||
362 | exit: | ||
363 | dev_dbg(&client->dev, "%s: error setting stream\n", __func__); | ||
364 | return err; | ||
365 | } | ||
366 | |||
367 | static int imx219_g_input_status(struct v4l2_subdev *sd, u32 *status) | ||
368 | { | ||
369 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
370 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
371 | struct imx219 *priv = (struct imx219 *)s_data->priv; | ||
372 | struct camera_common_power_rail *pw = &priv->power; | ||
373 | |||
374 | *status = pw->state == SWITCH_ON; | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static int imx219_get_fmt(struct v4l2_subdev *sd, | ||
379 | struct v4l2_subdev_pad_config *cfg, | ||
380 | struct v4l2_subdev_format *format) | ||
381 | { | ||
382 | return camera_common_g_fmt(sd, &format->format); | ||
383 | } | ||
384 | |||
385 | static int imx219_set_fmt(struct v4l2_subdev *sd, | ||
386 | struct v4l2_subdev_pad_config *cfg, | ||
387 | struct v4l2_subdev_format *format) | ||
388 | { | ||
389 | int ret; | ||
390 | |||
391 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) | ||
392 | ret = camera_common_try_fmt(sd, &format->format); | ||
393 | else | ||
394 | ret = camera_common_s_fmt(sd, &format->format); | ||
395 | |||
396 | return ret; | ||
397 | } | ||
398 | |||
399 | static struct v4l2_subdev_video_ops imx219_subdev_video_ops = { | ||
400 | .s_stream = imx219_s_stream, | ||
401 | .g_mbus_config = camera_common_g_mbus_config, | ||
402 | .g_input_status = imx219_g_input_status, | ||
403 | }; | ||
404 | |||
405 | static struct v4l2_subdev_core_ops imx219_subdev_core_ops = { | ||
406 | .s_power = camera_common_s_power, | ||
407 | }; | ||
408 | |||
409 | static struct v4l2_subdev_pad_ops imx219_subdev_pad_ops = { | ||
410 | .enum_mbus_code = camera_common_enum_mbus_code, | ||
411 | .set_fmt = imx219_set_fmt, | ||
412 | .get_fmt = imx219_get_fmt, | ||
413 | .enum_frame_size = camera_common_enum_framesizes, | ||
414 | .enum_frame_interval = camera_common_enum_frameintervals, | ||
415 | }; | ||
416 | |||
417 | static struct v4l2_subdev_ops imx219_subdev_ops = { | ||
418 | .core = &imx219_subdev_core_ops, | ||
419 | .video = &imx219_subdev_video_ops, | ||
420 | .pad = &imx219_subdev_pad_ops, | ||
421 | }; | ||
422 | |||
423 | static struct of_device_id imx219_of_match[] = { | ||
424 | { .compatible = "nvidia,imx219", }, | ||
425 | { }, | ||
426 | }; | ||
427 | |||
428 | static struct camera_common_sensor_ops imx219_common_ops = { | ||
429 | .power_on = imx219_power_on, | ||
430 | .power_off = imx219_power_off, | ||
431 | .write_reg = imx219_write_reg, | ||
432 | .read_reg = imx219_read_reg, | ||
433 | }; | ||
434 | |||
435 | static int imx219_set_group_hold(struct imx219 *priv, s32 val) | ||
436 | { | ||
437 | /* IMX219 does not support group hold */ | ||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | static int imx219_set_gain(struct imx219 *priv, s32 val) | ||
442 | { | ||
443 | struct reg_8 reg; | ||
444 | int err; | ||
445 | u8 gain; | ||
446 | |||
447 | /* translate value */ | ||
448 | gain = 256 - (256 * (1 << IMX219_GAIN_SHIFT) / val); | ||
449 | dev_dbg(&priv->i2c_client->dev, | ||
450 | "%s: val: %d\n", __func__, gain); | ||
451 | |||
452 | imx219_get_gain_reg(®, gain); | ||
453 | |||
454 | err = imx219_write_reg(priv->s_data, reg.addr, reg.val); | ||
455 | if (err) | ||
456 | goto fail; | ||
457 | |||
458 | return 0; | ||
459 | |||
460 | fail: | ||
461 | dev_dbg(&priv->i2c_client->dev, | ||
462 | "%s: GAIN control error\n", __func__); | ||
463 | return err; | ||
464 | } | ||
465 | |||
466 | static int imx219_set_frame_length(struct imx219 *priv, s32 val) | ||
467 | { | ||
468 | u8 data[2]; | ||
469 | int err; | ||
470 | |||
471 | dev_dbg(&priv->i2c_client->dev, | ||
472 | "%s: val: %d\n", __func__, val); | ||
473 | |||
474 | data[0] = (val >> 8) & 0xff; | ||
475 | data[1] = val & 0xff; | ||
476 | err = regmap_raw_write(priv->regmap, IMX219_FRAME_LENGTH_ADDR_MSB, | ||
477 | data, 2); | ||
478 | if (err) | ||
479 | goto fail; | ||
480 | |||
481 | return 0; | ||
482 | |||
483 | fail: | ||
484 | dev_dbg(&priv->i2c_client->dev, | ||
485 | "%s: FRAME_LENGTH control error\n", __func__); | ||
486 | return err; | ||
487 | } | ||
488 | |||
489 | static int imx219_set_coarse_time(struct imx219 *priv, s32 val) | ||
490 | { | ||
491 | u8 data[2]; | ||
492 | int err; | ||
493 | |||
494 | dev_dbg(&priv->i2c_client->dev, | ||
495 | "%s: val: %d\n", __func__, val); | ||
496 | |||
497 | data[0] = (val >> 8) & 0xff; | ||
498 | data[1] = val & 0xff; | ||
499 | err = regmap_raw_write(priv->regmap, IMX219_COARSE_TIME_ADDR_MSB, | ||
500 | data, 2); | ||
501 | if (err) | ||
502 | goto fail; | ||
503 | |||
504 | return 0; | ||
505 | |||
506 | fail: | ||
507 | dev_dbg(&priv->i2c_client->dev, | ||
508 | "%s: COARSE_TIME control error\n", __func__); | ||
509 | return err; | ||
510 | } | ||
511 | |||
512 | static int imx219_verify_streaming(struct imx219 *priv) | ||
513 | { | ||
514 | int err = 0; | ||
515 | |||
516 | err = camera_common_s_power(priv->subdev, true); | ||
517 | if (err) | ||
518 | return err; | ||
519 | |||
520 | err = imx219_s_stream(priv->subdev, true); | ||
521 | if (err) | ||
522 | goto error; | ||
523 | |||
524 | error: | ||
525 | imx219_s_stream(priv->subdev, false); | ||
526 | camera_common_s_power(priv->subdev, false); | ||
527 | |||
528 | return err; | ||
529 | } | ||
530 | |||
531 | static int imx219_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | ||
532 | { | ||
533 | struct imx219 *priv = | ||
534 | container_of(ctrl->handler, struct imx219, ctrl_handler); | ||
535 | int err = 0; | ||
536 | |||
537 | if (priv->power.state == SWITCH_OFF) | ||
538 | return 0; | ||
539 | |||
540 | switch (ctrl->id) { | ||
541 | default: | ||
542 | pr_err("%s: unknown ctrl id.\n", __func__); | ||
543 | return -EINVAL; | ||
544 | } | ||
545 | |||
546 | return err; | ||
547 | } | ||
548 | |||
549 | static int imx219_s_ctrl(struct v4l2_ctrl *ctrl) | ||
550 | { | ||
551 | struct imx219 *priv = | ||
552 | container_of(ctrl->handler, struct imx219, ctrl_handler); | ||
553 | int err = 0; | ||
554 | |||
555 | if (priv->power.state == SWITCH_OFF) | ||
556 | return 0; | ||
557 | |||
558 | switch (ctrl->id) { | ||
559 | case V4L2_CID_GAIN: | ||
560 | err = imx219_set_gain(priv, ctrl->val); | ||
561 | break; | ||
562 | case V4L2_CID_FRAME_LENGTH: | ||
563 | err = imx219_set_frame_length(priv, ctrl->val); | ||
564 | break; | ||
565 | case V4L2_CID_COARSE_TIME: | ||
566 | err = imx219_set_coarse_time(priv, ctrl->val); | ||
567 | break; | ||
568 | case V4L2_CID_GROUP_HOLD: | ||
569 | err = imx219_set_group_hold(priv, ctrl->val); | ||
570 | break; | ||
571 | case V4L2_CID_HDR_EN: | ||
572 | break; | ||
573 | case V4L2_CID_FUSE_ID: | ||
574 | break; | ||
575 | default: | ||
576 | pr_err("%s: unknown ctrl id.\n", __func__); | ||
577 | return -EINVAL; | ||
578 | } | ||
579 | |||
580 | return err; | ||
581 | } | ||
582 | |||
583 | static int imx219_ctrls_init(struct imx219 *priv) | ||
584 | { | ||
585 | struct i2c_client *client = priv->i2c_client; | ||
586 | struct v4l2_ctrl *ctrl; | ||
587 | int num_ctrls; | ||
588 | int err; | ||
589 | int i; | ||
590 | |||
591 | dev_info(&client->dev, "%s++\n", __func__); | ||
592 | |||
593 | num_ctrls = ARRAY_SIZE(ctrl_config_list); | ||
594 | v4l2_ctrl_handler_init(&priv->ctrl_handler, num_ctrls); | ||
595 | |||
596 | for (i = 0; i < num_ctrls; i++) { | ||
597 | ctrl = v4l2_ctrl_new_custom(&priv->ctrl_handler, | ||
598 | &ctrl_config_list[i], NULL); | ||
599 | if (ctrl == NULL) { | ||
600 | dev_err(&client->dev, "Failed to init %s ctrl\n", | ||
601 | ctrl_config_list[i].name); | ||
602 | continue; | ||
603 | } | ||
604 | |||
605 | if (ctrl_config_list[i].type == V4L2_CTRL_TYPE_STRING && | ||
606 | ctrl_config_list[i].flags & V4L2_CTRL_FLAG_READ_ONLY) { | ||
607 | ctrl->p_new.p_char = devm_kzalloc(&client->dev, | ||
608 | ctrl_config_list[i].max + 1, GFP_KERNEL); | ||
609 | if (!ctrl->p_new.p_char) { | ||
610 | dev_err(&client->dev, | ||
611 | "Failed to allocate otp data\n"); | ||
612 | return -ENOMEM; | ||
613 | } | ||
614 | } | ||
615 | priv->ctrls[i] = ctrl; | ||
616 | } | ||
617 | |||
618 | priv->num_ctrls = num_ctrls; | ||
619 | priv->subdev->ctrl_handler = &priv->ctrl_handler; | ||
620 | if (priv->ctrl_handler.error) { | ||
621 | dev_err(&client->dev, "Error %d adding controls\n", | ||
622 | priv->ctrl_handler.error); | ||
623 | err = priv->ctrl_handler.error; | ||
624 | goto error; | ||
625 | } | ||
626 | |||
627 | err = v4l2_ctrl_handler_setup(&priv->ctrl_handler); | ||
628 | if (err) { | ||
629 | dev_err(&client->dev, | ||
630 | "Error %d setting default controls\n", err); | ||
631 | goto error; | ||
632 | } | ||
633 | |||
634 | return 0; | ||
635 | |||
636 | error: | ||
637 | v4l2_ctrl_handler_free(&priv->ctrl_handler); | ||
638 | return err; | ||
639 | } | ||
640 | |||
641 | MODULE_DEVICE_TABLE(of, imx219_of_match); | ||
642 | |||
643 | static struct camera_common_pdata *imx219_parse_dt(struct i2c_client *client) | ||
644 | { | ||
645 | struct device_node *np = client->dev.of_node; | ||
646 | struct camera_common_pdata *board_priv_pdata; | ||
647 | const struct of_device_id *match; | ||
648 | int gpio, err; | ||
649 | struct camera_common_pdata *ret = NULL; | ||
650 | |||
651 | match = of_match_device(imx219_of_match, &client->dev); | ||
652 | if (!match) { | ||
653 | dev_err(&client->dev, "Failed to find matching dt id\n"); | ||
654 | return NULL; | ||
655 | } | ||
656 | |||
657 | board_priv_pdata = devm_kzalloc(&client->dev, | ||
658 | sizeof(*board_priv_pdata), GFP_KERNEL); | ||
659 | if (!board_priv_pdata) { | ||
660 | dev_err(&client->dev, "Failed to allocate pdata\n"); | ||
661 | return NULL; | ||
662 | } | ||
663 | |||
664 | err = of_property_read_string(np, "mclk", &board_priv_pdata->mclk_name); | ||
665 | if (err) { | ||
666 | dev_err(&client->dev, "mclk not in DT\n"); | ||
667 | goto error; | ||
668 | } | ||
669 | |||
670 | gpio = of_get_named_gpio(np, "reset-gpios", 0); | ||
671 | if (gpio < 0) { | ||
672 | if (gpio == -EPROBE_DEFER) { | ||
673 | ret = ERR_PTR(-EPROBE_DEFER); | ||
674 | goto error; | ||
675 | } | ||
676 | dev_err(&client->dev, "reset gpios not in DT\n"); | ||
677 | goto error; | ||
678 | } | ||
679 | board_priv_pdata->reset_gpio = (unsigned int)gpio; | ||
680 | |||
681 | err = of_property_read_string(np, "avdd-reg", | ||
682 | &board_priv_pdata->regulators.avdd); | ||
683 | if (err) { | ||
684 | dev_err(&client->dev, "avdd-reg not in DT\n"); | ||
685 | goto error; | ||
686 | } | ||
687 | err = of_property_read_string(np, "dvdd-reg", | ||
688 | &board_priv_pdata->regulators.dvdd); | ||
689 | if (err) { | ||
690 | dev_err(&client->dev, "dvdd-reg not in DT\n"); | ||
691 | goto error; | ||
692 | } | ||
693 | err = of_property_read_string(np, "iovdd-reg", | ||
694 | &board_priv_pdata->regulators.iovdd); | ||
695 | if (err) { | ||
696 | dev_err(&client->dev, "iovdd-reg not in DT\n"); | ||
697 | goto error; | ||
698 | } | ||
699 | |||
700 | return board_priv_pdata; | ||
701 | |||
702 | error: | ||
703 | devm_kfree(&client->dev, board_priv_pdata); | ||
704 | return ret; | ||
705 | } | ||
706 | |||
707 | static int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
708 | { | ||
709 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
710 | dev_dbg(&client->dev, "%s:\n", __func__); | ||
711 | |||
712 | return 0; | ||
713 | } | ||
714 | |||
715 | static const struct v4l2_subdev_internal_ops imx219_subdev_internal_ops = { | ||
716 | .open = imx219_open, | ||
717 | }; | ||
718 | |||
719 | static const struct media_entity_operations imx219_media_ops = { | ||
720 | .link_validate = v4l2_subdev_link_validate, | ||
721 | }; | ||
722 | |||
723 | static int imx219_probe(struct i2c_client *client, | ||
724 | const struct i2c_device_id *id) | ||
725 | { | ||
726 | struct camera_common_data *common_data; | ||
727 | struct device_node *node = client->dev.of_node; | ||
728 | struct imx219 *priv; | ||
729 | int err; | ||
730 | char debugfs_name[32]; | ||
731 | |||
732 | if (!IS_ENABLED(CONFIG_OF) || !node) | ||
733 | return -EINVAL; | ||
734 | |||
735 | common_data = devm_kzalloc(&client->dev, | ||
736 | sizeof(struct camera_common_data), GFP_KERNEL); | ||
737 | if (!common_data) { | ||
738 | dev_err(&client->dev, "unable to allocate memory!\n"); | ||
739 | return -ENOMEM; | ||
740 | } | ||
741 | |||
742 | priv = devm_kzalloc(&client->dev, | ||
743 | sizeof(struct imx219) + sizeof(struct v4l2_ctrl *) * | ||
744 | ARRAY_SIZE(ctrl_config_list), | ||
745 | GFP_KERNEL); | ||
746 | if (!priv) { | ||
747 | dev_err(&client->dev, "unable to allocate memory!\n"); | ||
748 | return -ENOMEM; | ||
749 | } | ||
750 | |||
751 | priv->regmap = devm_regmap_init_i2c(client, &sensor_regmap_config); | ||
752 | if (IS_ERR(priv->regmap)) { | ||
753 | dev_err(&client->dev, | ||
754 | "regmap init failed: %ld\n", PTR_ERR(priv->regmap)); | ||
755 | return -ENODEV; | ||
756 | } | ||
757 | |||
758 | priv->pdata = imx219_parse_dt(client); | ||
759 | if (PTR_ERR(priv->pdata) == -EPROBE_DEFER) { | ||
760 | devm_kfree(&client->dev, priv); | ||
761 | return -EPROBE_DEFER; | ||
762 | } | ||
763 | if (!priv->pdata) { | ||
764 | dev_err(&client->dev, "unable to get platform data\n"); | ||
765 | return -EFAULT; | ||
766 | } | ||
767 | |||
768 | common_data->ops = &imx219_common_ops; | ||
769 | common_data->ctrl_handler = &priv->ctrl_handler; | ||
770 | common_data->i2c_client = client; | ||
771 | common_data->frmfmt = &imx219_frmfmt[0]; | ||
772 | common_data->colorfmt = camera_common_find_datafmt( | ||
773 | IMX219_DEFAULT_DATAFMT); | ||
774 | common_data->power = &priv->power; | ||
775 | common_data->ctrls = priv->ctrls; | ||
776 | common_data->priv = (void *)priv; | ||
777 | common_data->numctrls = ARRAY_SIZE(ctrl_config_list); | ||
778 | common_data->numfmts = ARRAY_SIZE(imx219_frmfmt); | ||
779 | common_data->def_mode = IMX219_DEFAULT_MODE; | ||
780 | common_data->def_width = IMX219_DEFAULT_WIDTH; | ||
781 | common_data->def_height = IMX219_DEFAULT_HEIGHT; | ||
782 | common_data->fmt_width = common_data->def_width; | ||
783 | common_data->fmt_height = common_data->def_height; | ||
784 | common_data->def_clk_freq = IMX219_DEFAULT_CLK_FREQ; | ||
785 | |||
786 | priv->i2c_client = client; | ||
787 | priv->s_data = common_data; | ||
788 | priv->subdev = &common_data->subdev; | ||
789 | priv->subdev->dev = &client->dev; | ||
790 | |||
791 | err = imx219_power_get(priv); | ||
792 | if (err) | ||
793 | return err; | ||
794 | |||
795 | snprintf(debugfs_name, sizeof(debugfs_name), "%s.%s", | ||
796 | dev_driver_string(&client->dev), dev_name(&client->dev)); | ||
797 | camera_common_create_debugfs(common_data, debugfs_name); | ||
798 | |||
799 | v4l2_i2c_subdev_init(&common_data->subdev, client, &imx219_subdev_ops); | ||
800 | |||
801 | err = imx219_ctrls_init(priv); | ||
802 | if (err) | ||
803 | return err; | ||
804 | |||
805 | err = imx219_verify_streaming(priv); | ||
806 | if (err) | ||
807 | return err; | ||
808 | |||
809 | priv->subdev->internal_ops = &imx219_subdev_internal_ops; | ||
810 | priv->subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | | ||
811 | V4L2_SUBDEV_FL_HAS_EVENTS; | ||
812 | |||
813 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
814 | priv->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
815 | priv->subdev->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; | ||
816 | priv->subdev->entity.ops = &imx219_media_ops; | ||
817 | err = media_entity_init(&priv->subdev->entity, 1, &priv->pad, 0); | ||
818 | if (err < 0) { | ||
819 | dev_err(&client->dev, "unable to init media entity\n"); | ||
820 | return err; | ||
821 | } | ||
822 | #endif | ||
823 | |||
824 | err = v4l2_async_register_subdev(priv->subdev); | ||
825 | if (err) | ||
826 | return err; | ||
827 | |||
828 | dev_dbg(&client->dev, "Detected IMX219 sensor\n"); | ||
829 | |||
830 | return 0; | ||
831 | } | ||
832 | |||
833 | static int | ||
834 | imx219_remove(struct i2c_client *client) | ||
835 | { | ||
836 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
837 | struct imx219 *priv = (struct imx219 *)s_data->priv; | ||
838 | |||
839 | v4l2_async_unregister_subdev(priv->subdev); | ||
840 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
841 | media_entity_cleanup(&priv->subdev->entity); | ||
842 | #endif | ||
843 | |||
844 | v4l2_ctrl_handler_free(&priv->ctrl_handler); | ||
845 | imx219_power_put(priv); | ||
846 | camera_common_remove_debugfs(s_data); | ||
847 | |||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | static const struct i2c_device_id imx219_id[] = { | ||
852 | { "imx219", 0 }, | ||
853 | { } | ||
854 | }; | ||
855 | |||
856 | MODULE_DEVICE_TABLE(i2c, imx219_id); | ||
857 | |||
858 | static struct i2c_driver imx219_i2c_driver = { | ||
859 | .driver = { | ||
860 | .name = "imx219", | ||
861 | .owner = THIS_MODULE, | ||
862 | .of_match_table = of_match_ptr(imx219_of_match), | ||
863 | }, | ||
864 | .probe = imx219_probe, | ||
865 | .remove = imx219_remove, | ||
866 | .id_table = imx219_id, | ||
867 | }; | ||
868 | |||
869 | module_i2c_driver(imx219_i2c_driver); | ||
870 | |||
871 | MODULE_DESCRIPTION("SoC Camera driver for Sony IMX219"); | ||
872 | MODULE_AUTHOR("Bryan Wu <pengw@nvidia.com>"); | ||
873 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/i2c/imx219_mode_tbls.h b/drivers/media/i2c/imx219_mode_tbls.h new file mode 100644 index 000000000..8bf129ffe --- /dev/null +++ b/drivers/media/i2c/imx219_mode_tbls.h | |||
@@ -0,0 +1,388 @@ | |||
1 | /* | ||
2 | * imx219_tables.h - sensor mode tables for imx219 HDR sensor. | ||
3 | * | ||
4 | * Copyright (c) 2015-2016, NVIDIA CORPORATION, All Rights Reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #ifndef IMX219_I2C_TABLES | ||
20 | #define IMX219_I2C_TABLES | ||
21 | |||
22 | #define IMX219_TABLE_WAIT_MS 0 | ||
23 | #define IMX219_TABLE_END 1 | ||
24 | #define IMX219_MAX_RETRIES 3 | ||
25 | #define IMX219_WAIT_MS 3 | ||
26 | |||
27 | static struct reg_8 mode_3280x2464[] = { | ||
28 | {IMX219_TABLE_WAIT_MS, 10}, | ||
29 | /* software reset */ | ||
30 | {0x0103, 0x01}, | ||
31 | /* global settings */ | ||
32 | {0x30EB, 0x05}, | ||
33 | {0x30EB, 0x0C}, | ||
34 | {0x300A, 0xFF}, | ||
35 | {0x300B, 0xFF}, | ||
36 | {0x30EB, 0x05}, | ||
37 | {0x30EB, 0x09}, | ||
38 | {0x0114, 0x01}, | ||
39 | {0x0128, 0x00}, | ||
40 | {0x012A, 0x0C}, | ||
41 | {0x012B, 0x00}, | ||
42 | {0x0160, 0x09}, | ||
43 | {0x0161, 0xC3}, | ||
44 | {0x0162, 0x0D}, | ||
45 | {0x0163, 0x78}, | ||
46 | {0x0164, 0x00}, | ||
47 | {0x0165, 0x00}, | ||
48 | {0x0166, 0x0C}, | ||
49 | {0x0167, 0xCF}, | ||
50 | {0x0168, 0x00}, | ||
51 | {0x0169, 0x00}, | ||
52 | {0x016A, 0x09}, | ||
53 | {0x016B, 0x9F}, | ||
54 | {0x016C, 0x0C}, | ||
55 | {0x016D, 0xD0}, | ||
56 | {0x016E, 0x09}, | ||
57 | {0x016F, 0xA0}, | ||
58 | {0x0170, 0x01}, | ||
59 | {0x0171, 0x01}, | ||
60 | {0x0174, 0x00}, | ||
61 | {0x0175, 0x00}, | ||
62 | {0x018C, 0x0A}, | ||
63 | {0x018D, 0x0A}, | ||
64 | {0x0301, 0x05}, | ||
65 | {0x0303, 0x01}, | ||
66 | {0x0304, 0x02}, | ||
67 | {0x0305, 0x02}, | ||
68 | {0x0306, 0x00}, | ||
69 | {0x0307, 0x4C}, | ||
70 | {0x0309, 0x0A}, | ||
71 | {0x030B, 0x01}, | ||
72 | {0x030C, 0x00}, | ||
73 | {0x030D, 0x98}, | ||
74 | {0x4767, 0x0F}, | ||
75 | {0x4750, 0x14}, | ||
76 | {0x47B4, 0x14}, | ||
77 | /* stream on */ | ||
78 | {0x0100, 0x01}, | ||
79 | {IMX219_TABLE_WAIT_MS, IMX219_WAIT_MS}, | ||
80 | {IMX219_TABLE_END, 0x00} | ||
81 | }; | ||
82 | |||
83 | static struct reg_8 mode_3280x2460[] = { | ||
84 | {IMX219_TABLE_WAIT_MS, 10}, | ||
85 | /* software reset */ | ||
86 | {0x0103, 0x01}, | ||
87 | /* global settings */ | ||
88 | {0x30EB, 0x05}, | ||
89 | {0x30EB, 0x0C}, | ||
90 | {0x300A, 0xFF}, | ||
91 | {0x300B, 0xFF}, | ||
92 | {0x30EB, 0x05}, | ||
93 | {0x30EB, 0x09}, | ||
94 | {0x0114, 0x03}, | ||
95 | {0x0128, 0x00}, | ||
96 | {0x012A, 0x18}, | ||
97 | {0x012B, 0x00}, | ||
98 | /* Bank A Settings */ | ||
99 | {0x0157, 0x00}, | ||
100 | {0x015A, 0x08}, | ||
101 | {0x015B, 0x8F}, | ||
102 | {0x0160, 0x0A}, | ||
103 | {0x0161, 0x83}, | ||
104 | {0x0162, 0x0D}, | ||
105 | {0x0163, 0x78}, | ||
106 | {0x0164, 0x00}, | ||
107 | {0x0165, 0x00}, | ||
108 | {0x0166, 0x0C}, | ||
109 | {0x0167, 0xCF}, | ||
110 | {0x0168, 0x00}, | ||
111 | {0x0169, 0x00}, | ||
112 | {0x016A, 0x09}, | ||
113 | {0x016B, 0x9F}, | ||
114 | {0x016C, 0x0C}, | ||
115 | {0x016D, 0xD0}, | ||
116 | {0x016E, 0x09}, | ||
117 | {0x016F, 0x9C}, | ||
118 | {0x0170, 0x01}, | ||
119 | {0x0171, 0x01}, | ||
120 | {0x0174, 0x00}, | ||
121 | {0x0175, 0x00}, | ||
122 | {0x018C, 0x0A}, | ||
123 | {0x018D, 0x0A}, | ||
124 | /* Bank B Settings */ | ||
125 | {0x0257, 0x00}, | ||
126 | {0x025A, 0x08}, | ||
127 | {0x025B, 0x8F}, | ||
128 | {0x0260, 0x0A}, | ||
129 | {0x0261, 0x83}, | ||
130 | {0x0262, 0x0D}, | ||
131 | {0x0263, 0x78}, | ||
132 | {0x0264, 0x00}, | ||
133 | {0x0265, 0x00}, | ||
134 | {0x0266, 0x0C}, | ||
135 | {0x0267, 0xCF}, | ||
136 | {0x0268, 0x00}, | ||
137 | {0x0269, 0x00}, | ||
138 | {0x026A, 0x09}, | ||
139 | {0x026B, 0x9F}, | ||
140 | {0x026C, 0x0C}, | ||
141 | {0x026D, 0xD0}, | ||
142 | {0x026E, 0x09}, | ||
143 | {0x026F, 0x9C}, | ||
144 | {0x0270, 0x01}, | ||
145 | {0x0271, 0x01}, | ||
146 | {0x0274, 0x00}, | ||
147 | {0x0275, 0x00}, | ||
148 | {0x028C, 0x0A}, | ||
149 | {0x028D, 0x0A}, | ||
150 | /* clock setting */ | ||
151 | {0x0301, 0x05}, | ||
152 | {0x0303, 0x01}, | ||
153 | {0x0304, 0x03}, | ||
154 | {0x0305, 0x03}, | ||
155 | {0x0306, 0x00}, | ||
156 | {0x0307, 0x57}, | ||
157 | {0x0309, 0x0A}, | ||
158 | {0x030B, 0x01}, | ||
159 | {0x030C, 0x00}, | ||
160 | {0x030D, 0x5A}, | ||
161 | {0x455E, 0x00}, | ||
162 | {0x471E, 0x4B}, | ||
163 | {0x4767, 0x0F}, | ||
164 | {0x4750, 0x14}, | ||
165 | {0x4540, 0x00}, | ||
166 | {0x47B4, 0x14}, | ||
167 | {0x4713, 0x30}, | ||
168 | {0x478B, 0x10}, | ||
169 | {0x478F, 0x10}, | ||
170 | {0x4793, 0x10}, | ||
171 | {0x4797, 0x0E}, | ||
172 | {0x479B, 0x0E}, | ||
173 | /* stream on */ | ||
174 | {0x0100, 0x01}, | ||
175 | {IMX219_TABLE_WAIT_MS, IMX219_WAIT_MS}, | ||
176 | {IMX219_TABLE_END, 0x00} | ||
177 | }; | ||
178 | static struct reg_8 mode_3280x1846[] = { | ||
179 | {IMX219_TABLE_WAIT_MS, 10}, | ||
180 | /* software reset */ | ||
181 | {0x0103, 0x01}, | ||
182 | /* global settings */ | ||
183 | {0x30EB, 0x05}, | ||
184 | {0x30EB, 0x0C}, | ||
185 | {0x300A, 0xFF}, | ||
186 | {0x300B, 0xFF}, | ||
187 | {0x30EB, 0x05}, | ||
188 | {0x30EB, 0x09}, | ||
189 | {0x0114, 0x03}, | ||
190 | {0x0128, 0x00}, | ||
191 | {0x012A, 0x18}, | ||
192 | {0x012B, 0x00}, | ||
193 | /* Bank A Settings */ | ||
194 | {0x0157, 0x00}, | ||
195 | {0x015A, 0x08}, | ||
196 | {0x015B, 0x8F}, | ||
197 | {0x0160, 0x07}, | ||
198 | {0x0161, 0x5E}, | ||
199 | {0x0162, 0x0D}, | ||
200 | {0x0163, 0x78}, | ||
201 | {0x0164, 0x00}, | ||
202 | {0x0165, 0x00}, | ||
203 | {0x0166, 0x0C}, | ||
204 | {0x0167, 0xCF}, | ||
205 | {0x0168, 0x01}, | ||
206 | {0x0169, 0x36}, | ||
207 | {0x016A, 0x08}, | ||
208 | {0x016B, 0x6B}, | ||
209 | {0x016C, 0x0C}, | ||
210 | {0x016D, 0xD0}, | ||
211 | {0x016E, 0x07}, | ||
212 | {0x016F, 0x36}, | ||
213 | {0x0170, 0x01}, | ||
214 | {0x0171, 0x01}, | ||
215 | {0x0174, 0x00}, | ||
216 | {0x0175, 0x00}, | ||
217 | {0x018C, 0x0A}, | ||
218 | {0x018D, 0x0A}, | ||
219 | /* Bank B Settings */ | ||
220 | {0x0257, 0x00}, | ||
221 | {0x025A, 0x08}, | ||
222 | {0x025B, 0x8F}, | ||
223 | {0x0260, 0x07}, | ||
224 | {0x0261, 0x5E}, | ||
225 | {0x0262, 0x0D}, | ||
226 | {0x0263, 0x78}, | ||
227 | {0x0264, 0x00}, | ||
228 | {0x0265, 0x00}, | ||
229 | {0x0266, 0x0C}, | ||
230 | {0x0267, 0xCF}, | ||
231 | {0x0268, 0x01}, | ||
232 | {0x0269, 0x36}, | ||
233 | {0x026A, 0x08}, | ||
234 | {0x026B, 0x6B}, | ||
235 | {0x026C, 0x0C}, | ||
236 | {0x026D, 0xD0}, | ||
237 | {0x026E, 0x07}, | ||
238 | {0x026F, 0x36}, | ||
239 | {0x0270, 0x01}, | ||
240 | {0x0271, 0x01}, | ||
241 | {0x0274, 0x00}, | ||
242 | {0x0275, 0x00}, | ||
243 | {0x028C, 0x0A}, | ||
244 | {0x028D, 0x0A}, | ||
245 | /* clock setting */ | ||
246 | {0x0301, 0x05}, | ||
247 | {0x0303, 0x01}, | ||
248 | {0x0304, 0x03}, | ||
249 | {0x0305, 0x03}, | ||
250 | {0x0306, 0x00}, | ||
251 | {0x0307, 0x57}, | ||
252 | {0x0309, 0x0A}, | ||
253 | {0x030B, 0x01}, | ||
254 | {0x030C, 0x00}, | ||
255 | {0x030D, 0x5A}, | ||
256 | {0x455E, 0x00}, | ||
257 | {0x471E, 0x4B}, | ||
258 | {0x4767, 0x0F}, | ||
259 | {0x4750, 0x14}, | ||
260 | {0x4540, 0x00}, | ||
261 | {0x47B4, 0x14}, | ||
262 | {0x4713, 0x30}, | ||
263 | {0x478B, 0x10}, | ||
264 | {0x478F, 0x10}, | ||
265 | {0x4793, 0x10}, | ||
266 | {0x4797, 0x0E}, | ||
267 | {0x479B, 0x0E}, | ||
268 | /* stream on */ | ||
269 | {0x0100, 0x01}, | ||
270 | {IMX219_TABLE_WAIT_MS, IMX219_WAIT_MS}, | ||
271 | {IMX219_TABLE_END, 0x00} | ||
272 | }; | ||
273 | |||
274 | static struct reg_8 mode_1280x720[] = { | ||
275 | {IMX219_TABLE_WAIT_MS, 10}, | ||
276 | /* software reset */ | ||
277 | {0x0103, 0x01}, | ||
278 | /* global settings */ | ||
279 | {0x30EB, 0x05}, | ||
280 | {0x30EB, 0x0C}, | ||
281 | {0x300A, 0xFF}, | ||
282 | {0x300B, 0xFF}, | ||
283 | {0x30EB, 0x05}, | ||
284 | {0x30EB, 0x09}, | ||
285 | {0x0114, 0x03}, | ||
286 | {0x0128, 0x00}, | ||
287 | {0x012A, 0x18}, | ||
288 | {0x012B, 0x00}, | ||
289 | /* Bank A Settings */ | ||
290 | {0x0160, 0x02}, | ||
291 | {0x0161, 0x8C}, | ||
292 | {0x0162, 0x0D}, | ||
293 | {0x0163, 0xE8}, | ||
294 | {0x0164, 0x01}, | ||
295 | {0x0165, 0x68}, | ||
296 | {0x0166, 0x0B}, | ||
297 | {0x0167, 0x67}, | ||
298 | {0x0168, 0x02}, | ||
299 | {0x0169, 0x00}, | ||
300 | {0x016A, 0x07}, | ||
301 | {0x016B, 0x9F}, | ||
302 | {0x016C, 0x05}, | ||
303 | {0x016D, 0x00}, | ||
304 | {0x016E, 0x02}, | ||
305 | {0x016F, 0xD0}, | ||
306 | {0x0170, 0x01}, | ||
307 | {0x0171, 0x01}, | ||
308 | {0x0174, 0x03}, | ||
309 | {0x0175, 0x03}, | ||
310 | {0x018C, 0x0A}, | ||
311 | {0x018D, 0x0A}, | ||
312 | /* Bank B Settings */ | ||
313 | {0x0260, 0x02}, | ||
314 | {0x0261, 0x8C}, | ||
315 | {0x0262, 0x0D}, | ||
316 | {0x0263, 0xE8}, | ||
317 | {0x0264, 0x01}, | ||
318 | {0x0265, 0x68}, | ||
319 | {0x0266, 0x0B}, | ||
320 | {0x0267, 0x67}, | ||
321 | {0x0268, 0x02}, | ||
322 | {0x0269, 0x00}, | ||
323 | {0x026A, 0x07}, | ||
324 | {0x026B, 0x9F}, | ||
325 | {0x026C, 0x05}, | ||
326 | {0x026D, 0x00}, | ||
327 | {0x026E, 0x02}, | ||
328 | {0x026F, 0xD0}, | ||
329 | {0x0270, 0x01}, | ||
330 | {0x0271, 0x01}, | ||
331 | {0x0274, 0x03}, | ||
332 | {0x0275, 0x03}, | ||
333 | {0x028C, 0x0A}, | ||
334 | {0x028D, 0x0A}, | ||
335 | /* clock setting */ | ||
336 | {0x0301, 0x05}, | ||
337 | {0x0303, 0x01}, | ||
338 | {0x0304, 0x03}, | ||
339 | {0x0305, 0x03}, | ||
340 | {0x0306, 0x00}, | ||
341 | {0x0307, 0x57}, | ||
342 | {0x0309, 0x0A}, | ||
343 | {0x030B, 0x01}, | ||
344 | {0x030C, 0x00}, | ||
345 | {0x030D, 0x5A}, | ||
346 | {0x455E, 0x00}, | ||
347 | {0x471E, 0x4B}, | ||
348 | {0x4767, 0x0F}, | ||
349 | {0x4750, 0x14}, | ||
350 | {0x4540, 0x00}, | ||
351 | {0x47B4, 0x14}, | ||
352 | {0x4713, 0x30}, | ||
353 | {0x478B, 0x10}, | ||
354 | {0x478F, 0x10}, | ||
355 | {0x4793, 0x10}, | ||
356 | {0x4797, 0x0E}, | ||
357 | {0x479B, 0x0E}, | ||
358 | /* stream on */ | ||
359 | {0x0100, 0x01}, | ||
360 | {IMX219_TABLE_WAIT_MS, IMX219_WAIT_MS}, | ||
361 | {IMX219_TABLE_END, 0x00} | ||
362 | }; | ||
363 | enum { | ||
364 | IMX219_MODE_3280x2464, | ||
365 | IMX219_MODE_3280x2460, | ||
366 | IMX219_MODE_3280x1846, | ||
367 | IMX219_MODE_1280x720, | ||
368 | }; | ||
369 | |||
370 | static struct reg_8 *mode_table[] = { | ||
371 | [IMX219_MODE_3280x2464] = mode_3280x2464, | ||
372 | [IMX219_MODE_3280x2460] = mode_3280x2460, | ||
373 | [IMX219_MODE_3280x1846] = mode_3280x1846, | ||
374 | [IMX219_MODE_1280x720] = mode_1280x720, | ||
375 | }; | ||
376 | |||
377 | static const int imx219_21fps[] = { | ||
378 | 20, | ||
379 | }; | ||
380 | |||
381 | static const struct camera_common_frmfmt imx219_frmfmt[] = { | ||
382 | {{3280, 2464}, imx219_21fps, 1, 0, IMX219_MODE_3280x2464}, | ||
383 | {{3280, 2460}, imx219_21fps, 1, 0, IMX219_MODE_3280x2460}, | ||
384 | {{3280, 1846}, imx219_21fps, 1, 0, IMX219_MODE_3280x1846}, | ||
385 | {{1280, 720}, NULL, 0, 0, IMX219_MODE_1280x720}, | ||
386 | }; | ||
387 | |||
388 | #endif | ||
diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c new file mode 100644 index 000000000..5a2382ed8 --- /dev/null +++ b/drivers/media/i2c/imx274.c | |||
@@ -0,0 +1,1041 @@ | |||
1 | /* | ||
2 | * imx274.c - imx274 sensor driver | ||
3 | * | ||
4 | * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <linux/slab.h> | ||
20 | #include <linux/uaccess.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/module.h> | ||
23 | |||
24 | #include <linux/seq_file.h> | ||
25 | #include <linux/of.h> | ||
26 | #include <linux/of_device.h> | ||
27 | #include <linux/of_gpio.h> | ||
28 | |||
29 | #include <media/camera_common.h> | ||
30 | #include <media/imx274.h> | ||
31 | |||
32 | #include "imx274_mode_tbls.h" | ||
33 | |||
34 | #define IMX274_MAX_COARSE_DIFF 10 | ||
35 | |||
36 | #define IMX274_GAIN_SHIFT 8 | ||
37 | #define IMX274_MIN_GAIN (1 << IMX274_GAIN_SHIFT) | ||
38 | #define IMX274_MAX_GAIN (23 << IMX274_GAIN_SHIFT) | ||
39 | #define IMX274_MIN_FRAME_LENGTH (0x8ED) | ||
40 | #define IMX274_MAX_FRAME_LENGTH (0xB292) | ||
41 | #define IMX274_MIN_EXPOSURE_COARSE (0x0001) | ||
42 | #define IMX274_MAX_EXPOSURE_COARSE \ | ||
43 | (IMX274_MAX_FRAME_LENGTH-IMX274_MAX_COARSE_DIFF) | ||
44 | |||
45 | #define IMX274_DEFAULT_GAIN IMX274_MIN_GAIN | ||
46 | #define IMX274_DEFAULT_FRAME_LENGTH (0x111B) | ||
47 | #define IMX274_DEFAULT_EXPOSURE_COARSE \ | ||
48 | (IMX274_DEFAULT_FRAME_LENGTH-IMX274_MAX_COARSE_DIFF) | ||
49 | |||
50 | #define IMX274_DEFAULT_MODE IMX274_MODE_3840X2160 | ||
51 | |||
52 | #define IMX274_DEFAULT_WIDTH 3864 | ||
53 | #define IMX274_DEFAULT_HEIGHT 2174 | ||
54 | #define IMX274_DEFAULT_DATAFMT MEDIA_BUS_FMT_SRGGB10_1X10 | ||
55 | #define IMX274_DEFAULT_CLK_FREQ 24000000 | ||
56 | |||
57 | struct imx274 { | ||
58 | struct camera_common_power_rail power; | ||
59 | int num_ctrls; | ||
60 | struct v4l2_ctrl_handler ctrl_handler; | ||
61 | struct i2c_client *i2c_client; | ||
62 | struct v4l2_subdev *subdev; | ||
63 | struct media_pad pad; | ||
64 | |||
65 | s32 group_hold_prev; | ||
66 | bool group_hold_en; | ||
67 | struct regmap *regmap; | ||
68 | struct camera_common_data *s_data; | ||
69 | struct camera_common_pdata *pdata; | ||
70 | struct v4l2_ctrl *ctrls[]; | ||
71 | }; | ||
72 | |||
73 | static const struct regmap_config sensor_regmap_config = { | ||
74 | .reg_bits = 16, | ||
75 | .val_bits = 8, | ||
76 | .cache_type = REGCACHE_RBTREE, | ||
77 | }; | ||
78 | |||
79 | static int imx274_s_ctrl(struct v4l2_ctrl *ctrl); | ||
80 | |||
81 | static const struct v4l2_ctrl_ops imx274_ctrl_ops = { | ||
82 | .s_ctrl = imx274_s_ctrl, | ||
83 | }; | ||
84 | |||
85 | static struct v4l2_ctrl_config ctrl_config_list[] = { | ||
86 | /* Do not change the name field for the controls! */ | ||
87 | { | ||
88 | .ops = &imx274_ctrl_ops, | ||
89 | .id = V4L2_CID_GAIN, | ||
90 | .name = "Gain", | ||
91 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
92 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
93 | .min = IMX274_MIN_GAIN, | ||
94 | .max = IMX274_MAX_GAIN, | ||
95 | .def = IMX274_DEFAULT_GAIN, | ||
96 | .step = 1, | ||
97 | }, | ||
98 | { | ||
99 | .ops = &imx274_ctrl_ops, | ||
100 | .id = V4L2_CID_FRAME_LENGTH, | ||
101 | .name = "Frame Length", | ||
102 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
103 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
104 | .min = IMX274_MIN_FRAME_LENGTH, | ||
105 | .max = IMX274_MAX_FRAME_LENGTH, | ||
106 | .def = IMX274_DEFAULT_FRAME_LENGTH, | ||
107 | .step = 1, | ||
108 | }, | ||
109 | { | ||
110 | .ops = &imx274_ctrl_ops, | ||
111 | .id = V4L2_CID_COARSE_TIME, | ||
112 | .name = "Coarse Time", | ||
113 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
114 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
115 | .min = IMX274_MIN_EXPOSURE_COARSE, | ||
116 | .max = IMX274_MAX_EXPOSURE_COARSE, | ||
117 | .def = IMX274_DEFAULT_EXPOSURE_COARSE, | ||
118 | .step = 1, | ||
119 | }, | ||
120 | { | ||
121 | .ops = &imx274_ctrl_ops, | ||
122 | .id = V4L2_CID_COARSE_TIME_SHORT, | ||
123 | .name = "Coarse Time Short", | ||
124 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
125 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
126 | .min = IMX274_MIN_EXPOSURE_COARSE, | ||
127 | .max = IMX274_MAX_EXPOSURE_COARSE, | ||
128 | .def = IMX274_DEFAULT_EXPOSURE_COARSE, | ||
129 | .step = 1, | ||
130 | }, | ||
131 | { | ||
132 | .ops = &imx274_ctrl_ops, | ||
133 | .id = V4L2_CID_GROUP_HOLD, | ||
134 | .name = "Group Hold", | ||
135 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, | ||
136 | .min = 0, | ||
137 | .max = ARRAY_SIZE(switch_ctrl_qmenu) - 1, | ||
138 | .menu_skip_mask = 0, | ||
139 | .def = 0, | ||
140 | .qmenu_int = switch_ctrl_qmenu, | ||
141 | }, | ||
142 | { | ||
143 | .ops = &imx274_ctrl_ops, | ||
144 | .id = V4L2_CID_HDR_EN, | ||
145 | .name = "HDR enable", | ||
146 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, | ||
147 | .min = 0, | ||
148 | .max = ARRAY_SIZE(switch_ctrl_qmenu) - 1, | ||
149 | .menu_skip_mask = 0, | ||
150 | .def = 0, | ||
151 | .qmenu_int = switch_ctrl_qmenu, | ||
152 | }, | ||
153 | }; | ||
154 | |||
155 | static inline void imx274_get_vmax_regs(imx274_reg *regs, | ||
156 | u32 vmax) | ||
157 | { | ||
158 | regs->addr = IMX274_VMAX_ADDR_MSB; | ||
159 | regs->val = (vmax >> 8) & 0xff; | ||
160 | (regs + 1)->addr = IMX274_VMAX_ADDR_LSB; | ||
161 | (regs + 1)->val = (vmax) & 0xff; | ||
162 | } | ||
163 | |||
164 | static inline void imx274_get_shr_regs(imx274_reg *regs, | ||
165 | u32 shr) | ||
166 | { | ||
167 | regs->addr = IMX274_SHR_ADDR_MSB; | ||
168 | regs->val = (shr >> 8) & 0xff; | ||
169 | (regs + 1)->addr = IMX274_SHR_ADDR_LSB; | ||
170 | (regs + 1)->val = (shr) & 0xff; | ||
171 | } | ||
172 | |||
173 | static inline void imx274_get_gain_reg(imx274_reg *regs, | ||
174 | u16 gain) | ||
175 | { | ||
176 | regs->addr = IMX274_GAIN_ADDR_MSB; | ||
177 | regs->val = (gain >> 8) & 0xff; | ||
178 | (regs + 1)->addr = IMX274_GAIN_ADDR_LSB; | ||
179 | (regs + 1)->val = (gain) & 0xff; | ||
180 | } | ||
181 | |||
182 | static int test_mode; | ||
183 | module_param(test_mode, int, 0644); | ||
184 | |||
185 | static inline int imx274_read_reg(struct camera_common_data *s_data, | ||
186 | u16 addr, u8 *val) | ||
187 | { | ||
188 | struct imx274 *priv = (struct imx274 *)s_data->priv; | ||
189 | return regmap_read(priv->regmap, addr, (unsigned int *) val); | ||
190 | } | ||
191 | |||
192 | static int imx274_write_reg(struct camera_common_data *s_data, u16 addr, u8 val) | ||
193 | { | ||
194 | int err; | ||
195 | struct imx274 *priv = (struct imx274 *)s_data->priv; | ||
196 | |||
197 | err = regmap_write(priv->regmap, addr, val); | ||
198 | if (err) | ||
199 | pr_err("%s:i2c write failed, %x = %x\n", | ||
200 | __func__, addr, val); | ||
201 | |||
202 | return err; | ||
203 | } | ||
204 | |||
205 | static int imx274_write_table(struct imx274 *priv, | ||
206 | const imx274_reg table[]) | ||
207 | { | ||
208 | return regmap_util_write_table_8(priv->regmap, | ||
209 | table, | ||
210 | NULL, 0, | ||
211 | IMX274_TABLE_WAIT_MS, | ||
212 | IMX274_TABLE_END); | ||
213 | } | ||
214 | |||
215 | static int imx274_power_on(struct camera_common_data *s_data) | ||
216 | { | ||
217 | int err = 0; | ||
218 | struct imx274 *priv = (struct imx274 *)s_data->priv; | ||
219 | struct camera_common_power_rail *pw = &priv->power; | ||
220 | |||
221 | dev_dbg(&priv->i2c_client->dev, "%s: power on\n", __func__); | ||
222 | |||
223 | if (priv->pdata && priv->pdata->power_on) { | ||
224 | err = priv->pdata->power_on(pw); | ||
225 | if (err) | ||
226 | pr_err("%s failed.\n", __func__); | ||
227 | else | ||
228 | pw->state = SWITCH_ON; | ||
229 | return err; | ||
230 | } | ||
231 | |||
232 | if (pw->reset_gpio) | ||
233 | gpio_set_value(pw->reset_gpio, 0); | ||
234 | if (pw->af_gpio) | ||
235 | gpio_set_value(pw->af_gpio, 1); | ||
236 | if (pw->pwdn_gpio) | ||
237 | gpio_set_value(pw->pwdn_gpio, 0); | ||
238 | usleep_range(10, 20); | ||
239 | |||
240 | |||
241 | if (pw->dvdd) | ||
242 | err = regulator_enable(pw->dvdd); | ||
243 | if (err) | ||
244 | goto imx274_dvdd_fail; | ||
245 | |||
246 | if (pw->iovdd) | ||
247 | err = regulator_enable(pw->iovdd); | ||
248 | if (err) | ||
249 | goto imx274_iovdd_fail; | ||
250 | |||
251 | if (pw->avdd) | ||
252 | err = regulator_enable(pw->avdd); | ||
253 | if (err) | ||
254 | goto imx274_avdd_fail; | ||
255 | |||
256 | usleep_range(1, 2); | ||
257 | if (pw->reset_gpio) | ||
258 | gpio_set_value(pw->reset_gpio, 1); | ||
259 | if (pw->pwdn_gpio) | ||
260 | gpio_set_value(pw->pwdn_gpio, 1); | ||
261 | |||
262 | usleep_range(300, 310); | ||
263 | |||
264 | pw->state = SWITCH_ON; | ||
265 | return 0; | ||
266 | |||
267 | imx274_dvdd_fail: | ||
268 | if (pw->af_gpio) | ||
269 | gpio_set_value(pw->af_gpio, 0); | ||
270 | |||
271 | imx274_iovdd_fail: | ||
272 | regulator_disable(pw->dvdd); | ||
273 | |||
274 | imx274_avdd_fail: | ||
275 | regulator_disable(pw->iovdd); | ||
276 | |||
277 | pr_err("%s failed.\n", __func__); | ||
278 | return -ENODEV; | ||
279 | } | ||
280 | |||
281 | static int imx274_power_off(struct camera_common_data *s_data) | ||
282 | { | ||
283 | int err = 0; | ||
284 | struct imx274 *priv = (struct imx274 *)s_data->priv; | ||
285 | struct camera_common_power_rail *pw = &priv->power; | ||
286 | |||
287 | dev_dbg(&priv->i2c_client->dev, "%s: power off\n", __func__); | ||
288 | |||
289 | if (priv->pdata->power_off) { | ||
290 | err = priv->pdata->power_off(pw); | ||
291 | if (err) { | ||
292 | pr_err("%s failed.\n", __func__); | ||
293 | return err; | ||
294 | } else { | ||
295 | goto power_off_done; | ||
296 | } | ||
297 | } | ||
298 | |||
299 | usleep_range(1, 2); | ||
300 | if (pw->reset_gpio) | ||
301 | gpio_set_value(pw->reset_gpio, 0); | ||
302 | if (pw->af_gpio) | ||
303 | gpio_set_value(pw->af_gpio, 0); | ||
304 | if (pw->pwdn_gpio) | ||
305 | gpio_set_value(pw->pwdn_gpio, 0); | ||
306 | usleep_range(1, 2); | ||
307 | |||
308 | if (pw->avdd) | ||
309 | regulator_disable(pw->avdd); | ||
310 | if (pw->iovdd) | ||
311 | regulator_disable(pw->iovdd); | ||
312 | if (pw->dvdd) | ||
313 | regulator_disable(pw->dvdd); | ||
314 | |||
315 | power_off_done: | ||
316 | pw->state = SWITCH_OFF; | ||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | static int imx274_power_put(struct imx274 *priv) | ||
321 | { | ||
322 | struct camera_common_power_rail *pw = &priv->power; | ||
323 | if (unlikely(!pw)) | ||
324 | return -EFAULT; | ||
325 | |||
326 | if (likely(pw->avdd)) | ||
327 | regulator_put(pw->avdd); | ||
328 | |||
329 | if (likely(pw->iovdd)) | ||
330 | regulator_put(pw->iovdd); | ||
331 | |||
332 | if (likely(pw->dvdd)) | ||
333 | regulator_put(pw->dvdd); | ||
334 | |||
335 | pw->avdd = NULL; | ||
336 | pw->iovdd = NULL; | ||
337 | pw->dvdd = NULL; | ||
338 | |||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | static int imx274_power_get(struct imx274 *priv) | ||
343 | { | ||
344 | struct camera_common_power_rail *pw = &priv->power; | ||
345 | struct camera_common_pdata *pdata = priv->pdata; | ||
346 | const char *mclk_name; | ||
347 | const char *parentclk_name; | ||
348 | struct clk *parent; | ||
349 | int err = 0; | ||
350 | |||
351 | mclk_name = priv->pdata->mclk_name ? | ||
352 | priv->pdata->mclk_name : "cam_mclk1"; | ||
353 | pw->mclk = devm_clk_get(&priv->i2c_client->dev, mclk_name); | ||
354 | if (IS_ERR(pw->mclk)) { | ||
355 | dev_err(&priv->i2c_client->dev, | ||
356 | "unable to get clock %s\n", mclk_name); | ||
357 | return PTR_ERR(pw->mclk); | ||
358 | } | ||
359 | |||
360 | parentclk_name = priv->pdata->parentclk_name; | ||
361 | if (parentclk_name) { | ||
362 | parent = devm_clk_get(&priv->i2c_client->dev, parentclk_name); | ||
363 | if (IS_ERR(parent)) { | ||
364 | dev_err(&priv->i2c_client->dev, | ||
365 | "unable to get parent clcok %s", | ||
366 | parentclk_name); | ||
367 | } else | ||
368 | clk_set_parent(pw->mclk, parent); | ||
369 | } | ||
370 | |||
371 | /* ananlog 2.7v */ | ||
372 | err |= camera_common_regulator_get(priv->i2c_client, | ||
373 | &pw->avdd, pdata->regulators.avdd); | ||
374 | /* digital 1.2v */ | ||
375 | err |= camera_common_regulator_get(priv->i2c_client, | ||
376 | &pw->dvdd, pdata->regulators.dvdd); | ||
377 | /* IO 1.8v */ | ||
378 | err |= camera_common_regulator_get(priv->i2c_client, | ||
379 | &pw->iovdd, pdata->regulators.iovdd); | ||
380 | |||
381 | if (!err) { | ||
382 | pw->reset_gpio = pdata->reset_gpio; | ||
383 | pw->af_gpio = pdata->af_gpio; | ||
384 | pw->pwdn_gpio = pdata->pwdn_gpio; | ||
385 | } | ||
386 | |||
387 | pw->state = SWITCH_OFF; | ||
388 | return err; | ||
389 | } | ||
390 | |||
391 | static int imx274_set_gain(struct imx274 *priv, s32 val); | ||
392 | static int imx274_set_frame_length(struct imx274 *priv, s32 val); | ||
393 | static int imx274_set_coarse_time(struct imx274 *priv, s32 val); | ||
394 | |||
395 | static int imx274_s_stream(struct v4l2_subdev *sd, int enable) | ||
396 | { | ||
397 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
398 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
399 | struct imx274 *priv = (struct imx274 *)s_data->priv; | ||
400 | struct v4l2_control control; | ||
401 | int err; | ||
402 | |||
403 | dev_dbg(&client->dev, "%s++\n", __func__); | ||
404 | |||
405 | imx274_write_table(priv, mode_table[IMX274_MODE_STOP_STREAM]); | ||
406 | |||
407 | if (!enable) | ||
408 | return 0; | ||
409 | |||
410 | dev_dbg(&client->dev, "%s mode[%d]\n", __func__, s_data->mode); | ||
411 | |||
412 | err = imx274_write_table(priv, mode_table[s_data->mode]); | ||
413 | if (err) | ||
414 | goto exit; | ||
415 | |||
416 | |||
417 | if (s_data->override_enable) { | ||
418 | /* write list of override regs for the asking frame length, */ | ||
419 | /* coarse integration time, and gain. */ | ||
420 | control.id = V4L2_CID_GAIN; | ||
421 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
422 | err |= imx274_set_gain(priv, control.value); | ||
423 | if (err) | ||
424 | dev_dbg(&client->dev, | ||
425 | "%s: error gain override\n", __func__); | ||
426 | |||
427 | control.id = V4L2_CID_FRAME_LENGTH; | ||
428 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
429 | err |= imx274_set_frame_length(priv, control.value); | ||
430 | if (err) | ||
431 | dev_dbg(&client->dev, | ||
432 | "%s: error frame length override\n", __func__); | ||
433 | |||
434 | control.id = V4L2_CID_COARSE_TIME; | ||
435 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
436 | err |= imx274_set_coarse_time(priv, control.value); | ||
437 | if (err) | ||
438 | dev_dbg(&client->dev, | ||
439 | "%s: error coarse time override\n", __func__); | ||
440 | } | ||
441 | |||
442 | if (test_mode) { | ||
443 | err = imx274_write_table(priv, | ||
444 | mode_table[IMX274_MODE_TEST_PATTERN]); | ||
445 | if (err) | ||
446 | goto exit; | ||
447 | } | ||
448 | |||
449 | err = imx274_write_table(priv, mode_table[IMX274_MODE_START_STREAM]); | ||
450 | if (err) | ||
451 | goto exit; | ||
452 | |||
453 | |||
454 | return 0; | ||
455 | exit: | ||
456 | dev_dbg(&client->dev, "%s: error setting stream\n", __func__); | ||
457 | return err; | ||
458 | } | ||
459 | |||
460 | static int imx274_get_fmt(struct v4l2_subdev *sd, | ||
461 | struct v4l2_subdev_pad_config *cfg, | ||
462 | struct v4l2_subdev_format *format) | ||
463 | { | ||
464 | return camera_common_g_fmt(sd, &format->format); | ||
465 | } | ||
466 | |||
467 | static int imx274_set_fmt(struct v4l2_subdev *sd, | ||
468 | struct v4l2_subdev_pad_config *cfg, | ||
469 | struct v4l2_subdev_format *format) | ||
470 | { | ||
471 | int ret; | ||
472 | |||
473 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) | ||
474 | ret = camera_common_try_fmt(sd, &format->format); | ||
475 | else | ||
476 | ret = camera_common_s_fmt(sd, &format->format); | ||
477 | |||
478 | return ret; | ||
479 | } | ||
480 | |||
481 | static int imx274_g_input_status(struct v4l2_subdev *sd, u32 *status) | ||
482 | { | ||
483 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
484 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
485 | struct imx274 *priv = (struct imx274 *)s_data->priv; | ||
486 | struct camera_common_power_rail *pw = &priv->power; | ||
487 | |||
488 | *status = pw->state == SWITCH_ON; | ||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | static struct v4l2_subdev_video_ops imx274_subdev_video_ops = { | ||
493 | .s_stream = imx274_s_stream, | ||
494 | .g_mbus_config = camera_common_g_mbus_config, | ||
495 | .g_input_status = imx274_g_input_status, | ||
496 | }; | ||
497 | |||
498 | static struct v4l2_subdev_core_ops imx274_subdev_core_ops = { | ||
499 | .s_power = camera_common_s_power, | ||
500 | }; | ||
501 | |||
502 | static struct v4l2_subdev_pad_ops imx274_subdev_pad_ops = { | ||
503 | .set_fmt = imx274_set_fmt, | ||
504 | .get_fmt = imx274_get_fmt, | ||
505 | .enum_mbus_code = camera_common_enum_mbus_code, | ||
506 | .enum_frame_size = camera_common_enum_framesizes, | ||
507 | .enum_frame_interval = camera_common_enum_frameintervals, | ||
508 | }; | ||
509 | |||
510 | static struct v4l2_subdev_ops imx274_subdev_ops = { | ||
511 | .core = &imx274_subdev_core_ops, | ||
512 | .video = &imx274_subdev_video_ops, | ||
513 | .pad = &imx274_subdev_pad_ops, | ||
514 | }; | ||
515 | |||
516 | static struct of_device_id imx274_of_match[] = { | ||
517 | { .compatible = "nvidia,imx274", }, | ||
518 | { }, | ||
519 | }; | ||
520 | |||
521 | static struct camera_common_sensor_ops imx274_common_ops = { | ||
522 | .power_on = imx274_power_on, | ||
523 | .power_off = imx274_power_off, | ||
524 | .write_reg = imx274_write_reg, | ||
525 | .read_reg = imx274_read_reg, | ||
526 | }; | ||
527 | |||
528 | static int imx274_set_group_hold(struct imx274 *priv) | ||
529 | { | ||
530 | int err; | ||
531 | int gh_prev = switch_ctrl_qmenu[priv->group_hold_prev]; | ||
532 | |||
533 | if (priv->group_hold_en == true && gh_prev == SWITCH_OFF) { | ||
534 | err = imx274_write_reg(priv->s_data, | ||
535 | IMX274_GROUP_HOLD_ADDR, 0x1); | ||
536 | if (err) | ||
537 | goto fail; | ||
538 | priv->group_hold_prev = 1; | ||
539 | } else if (priv->group_hold_en == false && gh_prev == SWITCH_ON) { | ||
540 | err = imx274_write_reg(priv->s_data, | ||
541 | IMX274_GROUP_HOLD_ADDR, 0x0); | ||
542 | if (err) | ||
543 | goto fail; | ||
544 | priv->group_hold_prev = 0; | ||
545 | } | ||
546 | |||
547 | return 0; | ||
548 | |||
549 | fail: | ||
550 | dev_dbg(&priv->i2c_client->dev, | ||
551 | "%s: Group hold control error\n", __func__); | ||
552 | return err; | ||
553 | } | ||
554 | |||
555 | static int imx274_set_gain(struct imx274 *priv, s32 val) | ||
556 | { | ||
557 | imx274_reg reg_list[2]; | ||
558 | int err; | ||
559 | int i = 0; | ||
560 | u16 gain; | ||
561 | |||
562 | dev_dbg(&priv->i2c_client->dev, | ||
563 | "%s: val: %d\n", __func__, val); | ||
564 | |||
565 | if (val < IMX274_MIN_GAIN) | ||
566 | val = IMX274_MIN_GAIN; | ||
567 | else if (val > IMX274_MAX_GAIN) | ||
568 | val = IMX274_MAX_GAIN; | ||
569 | |||
570 | gain = 2048 - (2048 * IMX274_MIN_GAIN / val); | ||
571 | |||
572 | imx274_get_gain_reg(reg_list, gain); | ||
573 | imx274_set_group_hold(priv); | ||
574 | |||
575 | /* writing analog gain */ | ||
576 | for (i = 0; i < 2; i++) { | ||
577 | err = imx274_write_reg(priv->s_data, reg_list[i].addr, | ||
578 | reg_list[i].val); | ||
579 | if (err) | ||
580 | goto fail; | ||
581 | } | ||
582 | |||
583 | return 0; | ||
584 | |||
585 | fail: | ||
586 | dev_dbg(&priv->i2c_client->dev, | ||
587 | "%s: GAIN control error\n", __func__); | ||
588 | return err; | ||
589 | } | ||
590 | |||
591 | static int imx274_set_frame_length(struct imx274 *priv, s32 val) | ||
592 | { | ||
593 | imx274_reg reg_list[2]; | ||
594 | int err; | ||
595 | u32 frame_length; | ||
596 | u32 frame_rate; | ||
597 | int i = 0; | ||
598 | u8 svr; | ||
599 | u32 vmax; | ||
600 | |||
601 | dev_dbg(&priv->i2c_client->dev, | ||
602 | "%s: val: %u\n", __func__, val); | ||
603 | |||
604 | frame_length = (u32)val; | ||
605 | |||
606 | frame_rate = (u32)(IMX274_PIXEL_CLK_HZ / | ||
607 | (u32)(frame_length * IMX274_LINE_LENGTH)); | ||
608 | |||
609 | imx274_read_reg(priv->s_data, IMX274_SVR_ADDR, &svr); | ||
610 | |||
611 | vmax = (u32)(72000000 / | ||
612 | (u32)(frame_rate * IMX274_HMAX * (svr + 1))) - 12; | ||
613 | |||
614 | imx274_get_vmax_regs(reg_list, vmax); | ||
615 | |||
616 | imx274_set_group_hold(priv); | ||
617 | |||
618 | for (i = 0; i < 2; i++) { | ||
619 | err = imx274_write_reg(priv->s_data, reg_list[i].addr, | ||
620 | reg_list[i].val); | ||
621 | if (err) | ||
622 | goto fail; | ||
623 | } | ||
624 | |||
625 | dev_dbg(&priv->i2c_client->dev, | ||
626 | "%s: frame_rate: %d vmax: %u\n", __func__, frame_rate, vmax); | ||
627 | return 0; | ||
628 | |||
629 | fail: | ||
630 | dev_info(&priv->i2c_client->dev, | ||
631 | "%s: FRAME_LENGTH control error\n", __func__); | ||
632 | return err; | ||
633 | } | ||
634 | |||
635 | static int imx274_calculate_shr(struct imx274 *priv, u32 rep) | ||
636 | { | ||
637 | u8 svr; | ||
638 | int shr; | ||
639 | int min; | ||
640 | int max; | ||
641 | u8 vmax_l; | ||
642 | u8 vmax_m; | ||
643 | u32 vmax; | ||
644 | |||
645 | imx274_read_reg(priv->s_data, IMX274_SVR_ADDR, &svr); | ||
646 | |||
647 | imx274_read_reg(priv->s_data, IMX274_VMAX_ADDR_LSB, &vmax_l); | ||
648 | imx274_read_reg(priv->s_data, IMX274_VMAX_ADDR_MSB, &vmax_m); | ||
649 | |||
650 | vmax = ((vmax_m << 8) + vmax_l); | ||
651 | |||
652 | min = IMX274_MODE1_SHR_MIN; | ||
653 | max = ((svr + 1) * IMX274_VMAX) - 4; | ||
654 | |||
655 | shr = vmax * (svr + 1) - | ||
656 | (rep * IMX274_ET_FACTOR - IMX274_MODE1_OFFSET) / | ||
657 | IMX274_HMAX; | ||
658 | |||
659 | if (shr < min) | ||
660 | shr = min; | ||
661 | |||
662 | if (shr > max) | ||
663 | shr = max; | ||
664 | |||
665 | dev_dbg(&priv->i2c_client->dev, | ||
666 | "%s: shr: %u vmax: %d\n", __func__, shr, vmax); | ||
667 | return shr; | ||
668 | } | ||
669 | |||
670 | static int imx274_set_coarse_time(struct imx274 *priv, s32 val) | ||
671 | { | ||
672 | imx274_reg reg_list[2]; | ||
673 | int err; | ||
674 | u32 coarse_time; | ||
675 | u32 shr; | ||
676 | int i = 0; | ||
677 | |||
678 | coarse_time = val; | ||
679 | |||
680 | dev_dbg(&priv->i2c_client->dev, | ||
681 | "%s: val: %d\n", __func__, coarse_time); | ||
682 | |||
683 | shr = imx274_calculate_shr(priv, coarse_time); | ||
684 | |||
685 | imx274_get_shr_regs(reg_list, shr); | ||
686 | imx274_set_group_hold(priv); | ||
687 | |||
688 | for (i = 0; i < 2; i++) { | ||
689 | err = imx274_write_reg(priv->s_data, reg_list[i].addr, | ||
690 | reg_list[i].val); | ||
691 | if (err) | ||
692 | goto fail; | ||
693 | } | ||
694 | |||
695 | return 0; | ||
696 | |||
697 | fail: | ||
698 | dev_dbg(&priv->i2c_client->dev, | ||
699 | "%s: COARSE_TIME control error\n", __func__); | ||
700 | return err; | ||
701 | } | ||
702 | |||
703 | static int imx274_verify_streaming(struct imx274 *priv) | ||
704 | { | ||
705 | int err = 0; | ||
706 | |||
707 | err = camera_common_s_power(priv->subdev, true); | ||
708 | if (err) | ||
709 | return err; | ||
710 | |||
711 | err = imx274_s_stream(priv->subdev, true); | ||
712 | if (err) | ||
713 | goto error; | ||
714 | |||
715 | error: | ||
716 | imx274_s_stream(priv->subdev, false); | ||
717 | camera_common_s_power(priv->subdev, false); | ||
718 | |||
719 | return err; | ||
720 | } | ||
721 | |||
722 | static int imx274_s_ctrl(struct v4l2_ctrl *ctrl) | ||
723 | { | ||
724 | struct imx274 *priv = | ||
725 | container_of(ctrl->handler, struct imx274, ctrl_handler); | ||
726 | int err = 0; | ||
727 | |||
728 | if (priv->power.state == SWITCH_OFF) | ||
729 | return 0; | ||
730 | |||
731 | switch (ctrl->id) { | ||
732 | case V4L2_CID_GAIN: | ||
733 | err = imx274_set_gain(priv, ctrl->val); | ||
734 | break; | ||
735 | case V4L2_CID_FRAME_LENGTH: | ||
736 | err = imx274_set_frame_length(priv, ctrl->val); | ||
737 | break; | ||
738 | case V4L2_CID_COARSE_TIME: | ||
739 | err = imx274_set_coarse_time(priv, ctrl->val); | ||
740 | break; | ||
741 | case V4L2_CID_COARSE_TIME_SHORT: | ||
742 | err = imx274_set_coarse_time(priv, ctrl->val); | ||
743 | break; | ||
744 | case V4L2_CID_GROUP_HOLD: | ||
745 | if (switch_ctrl_qmenu[ctrl->val] == SWITCH_ON) { | ||
746 | priv->group_hold_en = true; | ||
747 | } else { | ||
748 | priv->group_hold_en = false; | ||
749 | err = imx274_set_group_hold(priv); | ||
750 | } | ||
751 | break; | ||
752 | case V4L2_CID_HDR_EN: | ||
753 | break; | ||
754 | default: | ||
755 | pr_err("%s: unknown ctrl id.\n", __func__); | ||
756 | return -EINVAL; | ||
757 | } | ||
758 | |||
759 | return err; | ||
760 | } | ||
761 | |||
762 | static int imx274_ctrls_init(struct imx274 *priv) | ||
763 | { | ||
764 | struct i2c_client *client = priv->i2c_client; | ||
765 | struct v4l2_ctrl *ctrl; | ||
766 | int num_ctrls; | ||
767 | int err; | ||
768 | int i; | ||
769 | |||
770 | dev_dbg(&client->dev, "%s++\n", __func__); | ||
771 | |||
772 | num_ctrls = ARRAY_SIZE(ctrl_config_list); | ||
773 | v4l2_ctrl_handler_init(&priv->ctrl_handler, num_ctrls); | ||
774 | |||
775 | for (i = 0; i < num_ctrls; i++) { | ||
776 | ctrl = v4l2_ctrl_new_custom(&priv->ctrl_handler, | ||
777 | &ctrl_config_list[i], NULL); | ||
778 | if (ctrl == NULL) { | ||
779 | dev_err(&client->dev, "Failed to init %s ctrl\n", | ||
780 | ctrl_config_list[i].name); | ||
781 | continue; | ||
782 | } | ||
783 | |||
784 | if (ctrl_config_list[i].type == V4L2_CTRL_TYPE_STRING && | ||
785 | ctrl_config_list[i].flags & V4L2_CTRL_FLAG_READ_ONLY) { | ||
786 | ctrl->p_new.p_char = devm_kzalloc(&client->dev, | ||
787 | ctrl_config_list[i].max + 1, GFP_KERNEL); | ||
788 | } | ||
789 | priv->ctrls[i] = ctrl; | ||
790 | } | ||
791 | |||
792 | priv->num_ctrls = num_ctrls; | ||
793 | priv->subdev->ctrl_handler = &priv->ctrl_handler; | ||
794 | if (priv->ctrl_handler.error) { | ||
795 | dev_err(&client->dev, "Error %d adding controls\n", | ||
796 | priv->ctrl_handler.error); | ||
797 | err = priv->ctrl_handler.error; | ||
798 | goto error; | ||
799 | } | ||
800 | |||
801 | err = v4l2_ctrl_handler_setup(&priv->ctrl_handler); | ||
802 | if (err) { | ||
803 | dev_err(&client->dev, | ||
804 | "Error %d setting default controls\n", err); | ||
805 | goto error; | ||
806 | } | ||
807 | |||
808 | return 0; | ||
809 | |||
810 | error: | ||
811 | v4l2_ctrl_handler_free(&priv->ctrl_handler); | ||
812 | return err; | ||
813 | } | ||
814 | |||
815 | MODULE_DEVICE_TABLE(of, imx274_of_match); | ||
816 | |||
817 | static struct camera_common_pdata *imx274_parse_dt(struct i2c_client *client) | ||
818 | { | ||
819 | struct device_node *node = client->dev.of_node; | ||
820 | struct camera_common_pdata *board_priv_pdata; | ||
821 | const struct of_device_id *match; | ||
822 | int err; | ||
823 | |||
824 | if (!node) | ||
825 | return NULL; | ||
826 | |||
827 | match = of_match_device(imx274_of_match, &client->dev); | ||
828 | if (!match) { | ||
829 | dev_err(&client->dev, " Failed to find matching dt id\n"); | ||
830 | return NULL; | ||
831 | } | ||
832 | |||
833 | board_priv_pdata = devm_kzalloc(&client->dev, | ||
834 | sizeof(*board_priv_pdata), GFP_KERNEL); | ||
835 | if (!board_priv_pdata) { | ||
836 | dev_err(&client->dev, "Failed to allocate pdata\n"); | ||
837 | return NULL; | ||
838 | } | ||
839 | |||
840 | |||
841 | err = camera_common_parse_clocks(client, board_priv_pdata); | ||
842 | if (err) { | ||
843 | dev_err(&client->dev, "Failed to find clocks\n"); | ||
844 | goto error; | ||
845 | } | ||
846 | |||
847 | err = of_property_read_string(node, "mclk", | ||
848 | &board_priv_pdata->mclk_name); | ||
849 | if (err) | ||
850 | dev_err(&client->dev, "mclk not in DT\n"); | ||
851 | |||
852 | board_priv_pdata->reset_gpio = of_get_named_gpio(node, | ||
853 | "reset-gpios", 0); | ||
854 | |||
855 | of_property_read_string(node, "avdd-reg", | ||
856 | &board_priv_pdata->regulators.avdd); | ||
857 | of_property_read_string(node, "dvdd-reg", | ||
858 | &board_priv_pdata->regulators.dvdd); | ||
859 | of_property_read_string(node, "iovdd-reg", | ||
860 | &board_priv_pdata->regulators.iovdd); | ||
861 | |||
862 | return board_priv_pdata; | ||
863 | |||
864 | error: | ||
865 | devm_kfree(&client->dev, board_priv_pdata); | ||
866 | return NULL; | ||
867 | } | ||
868 | |||
869 | static int imx274_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
870 | { | ||
871 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
872 | dev_dbg(&client->dev, "%s:\n", __func__); | ||
873 | |||
874 | |||
875 | return 0; | ||
876 | } | ||
877 | |||
878 | static const struct v4l2_subdev_internal_ops imx274_subdev_internal_ops = { | ||
879 | .open = imx274_open, | ||
880 | }; | ||
881 | |||
882 | static const struct media_entity_operations imx274_media_ops = { | ||
883 | #ifdef CONFIG_MEDIA_CONTROLLER | ||
884 | .link_validate = v4l2_subdev_link_validate, | ||
885 | #endif | ||
886 | }; | ||
887 | |||
888 | static int imx274_probe(struct i2c_client *client, | ||
889 | const struct i2c_device_id *id) | ||
890 | { | ||
891 | struct camera_common_data *common_data; | ||
892 | struct device_node *node = client->dev.of_node; | ||
893 | struct imx274 *priv; | ||
894 | char debugfs_name[10]; | ||
895 | int err; | ||
896 | |||
897 | pr_info("[IMX274]: probing v4l2 sensor.\n"); | ||
898 | |||
899 | if (!IS_ENABLED(CONFIG_OF) || !node) | ||
900 | return -EINVAL; | ||
901 | |||
902 | common_data = devm_kzalloc(&client->dev, | ||
903 | sizeof(struct camera_common_data), GFP_KERNEL); | ||
904 | if (!common_data) { | ||
905 | dev_err(&client->dev, "unable to allocate memory!\n"); | ||
906 | return -ENOMEM; | ||
907 | } | ||
908 | |||
909 | priv = devm_kzalloc(&client->dev, | ||
910 | sizeof(struct imx274) + sizeof(struct v4l2_ctrl *) * | ||
911 | ARRAY_SIZE(ctrl_config_list), | ||
912 | GFP_KERNEL); | ||
913 | if (!priv) { | ||
914 | dev_err(&client->dev, "unable to allocate memory!\n"); | ||
915 | return -ENOMEM; | ||
916 | } | ||
917 | |||
918 | priv->regmap = devm_regmap_init_i2c(client, &sensor_regmap_config); | ||
919 | if (IS_ERR(priv->regmap)) { | ||
920 | dev_err(&client->dev, | ||
921 | "regmap init failed: %ld\n", PTR_ERR(priv->regmap)); | ||
922 | return -ENODEV; | ||
923 | } | ||
924 | |||
925 | priv->pdata = imx274_parse_dt(client); | ||
926 | if (!priv->pdata) { | ||
927 | dev_err(&client->dev, " unable to get platform data\n"); | ||
928 | return -EFAULT; | ||
929 | } | ||
930 | |||
931 | common_data->ops = &imx274_common_ops; | ||
932 | common_data->ctrl_handler = &priv->ctrl_handler; | ||
933 | common_data->i2c_client = client; | ||
934 | common_data->frmfmt = &imx274_frmfmt[0]; | ||
935 | common_data->colorfmt = camera_common_find_datafmt( | ||
936 | IMX274_DEFAULT_DATAFMT); | ||
937 | common_data->power = &priv->power; | ||
938 | common_data->ctrls = priv->ctrls; | ||
939 | common_data->priv = (void *)priv; | ||
940 | common_data->numctrls = ARRAY_SIZE(ctrl_config_list); | ||
941 | common_data->numfmts = ARRAY_SIZE(imx274_frmfmt); | ||
942 | common_data->def_mode = IMX274_DEFAULT_MODE; | ||
943 | common_data->def_width = IMX274_DEFAULT_WIDTH; | ||
944 | common_data->def_height = IMX274_DEFAULT_HEIGHT; | ||
945 | common_data->fmt_width = common_data->def_width; | ||
946 | common_data->fmt_height = common_data->def_height; | ||
947 | common_data->def_clk_freq = IMX274_DEFAULT_CLK_FREQ; | ||
948 | |||
949 | priv->i2c_client = client; | ||
950 | priv->s_data = common_data; | ||
951 | priv->subdev = &common_data->subdev; | ||
952 | priv->subdev->dev = &client->dev; | ||
953 | |||
954 | err = imx274_power_get(priv); | ||
955 | if (err) | ||
956 | return err; | ||
957 | |||
958 | err = camera_common_parse_ports(client, common_data); | ||
959 | if (err) { | ||
960 | dev_err(&client->dev, "Failed to find port info\n"); | ||
961 | return err; | ||
962 | } | ||
963 | sprintf(debugfs_name, "imx274_%c", common_data->csi_port + 'a'); | ||
964 | dev_dbg(&client->dev, "%s: name %s\n", __func__, debugfs_name); | ||
965 | |||
966 | camera_common_create_debugfs(common_data, "imx274"); | ||
967 | |||
968 | v4l2_i2c_subdev_init(priv->subdev, client, &imx274_subdev_ops); | ||
969 | |||
970 | err = imx274_ctrls_init(priv); | ||
971 | if (err) | ||
972 | return err; | ||
973 | |||
974 | err = imx274_verify_streaming(priv); | ||
975 | if (err) | ||
976 | return err; | ||
977 | |||
978 | priv->subdev->internal_ops = &imx274_subdev_internal_ops; | ||
979 | priv->subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | | ||
980 | V4L2_SUBDEV_FL_HAS_EVENTS; | ||
981 | |||
982 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
983 | priv->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
984 | priv->subdev->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; | ||
985 | priv->subdev->entity.ops = &imx274_media_ops; | ||
986 | err = media_entity_init(&priv->subdev->entity, 1, &priv->pad, 0); | ||
987 | if (err < 0) { | ||
988 | dev_err(&client->dev, "unable to init media entity\n"); | ||
989 | return err; | ||
990 | } | ||
991 | #endif | ||
992 | |||
993 | err = v4l2_async_register_subdev(priv->subdev); | ||
994 | if (err) | ||
995 | return err; | ||
996 | |||
997 | dev_dbg(&client->dev, "Detected IMX274 sensor\n"); | ||
998 | |||
999 | return 0; | ||
1000 | } | ||
1001 | |||
1002 | static int | ||
1003 | imx274_remove(struct i2c_client *client) | ||
1004 | { | ||
1005 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
1006 | struct imx274 *priv = (struct imx274 *)s_data->priv; | ||
1007 | |||
1008 | v4l2_async_unregister_subdev(priv->subdev); | ||
1009 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
1010 | media_entity_cleanup(&priv->subdev->entity); | ||
1011 | #endif | ||
1012 | |||
1013 | v4l2_ctrl_handler_free(&priv->ctrl_handler); | ||
1014 | imx274_power_put(priv); | ||
1015 | camera_common_remove_debugfs(s_data); | ||
1016 | |||
1017 | return 0; | ||
1018 | } | ||
1019 | |||
1020 | static const struct i2c_device_id imx274_id[] = { | ||
1021 | { "imx274", 0 }, | ||
1022 | { } | ||
1023 | }; | ||
1024 | |||
1025 | MODULE_DEVICE_TABLE(i2c, imx274_id); | ||
1026 | |||
1027 | static struct i2c_driver imx274_i2c_driver = { | ||
1028 | .driver = { | ||
1029 | .name = "imx274", | ||
1030 | .owner = THIS_MODULE, | ||
1031 | }, | ||
1032 | .probe = imx274_probe, | ||
1033 | .remove = imx274_remove, | ||
1034 | .id_table = imx274_id, | ||
1035 | }; | ||
1036 | |||
1037 | module_i2c_driver(imx274_i2c_driver); | ||
1038 | |||
1039 | MODULE_DESCRIPTION("Media Controller driver for Sony IMX274"); | ||
1040 | MODULE_AUTHOR("Josh Kuo <joshk@nvidia.com>"); | ||
1041 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/i2c/imx274_mode_tbls.h b/drivers/media/i2c/imx274_mode_tbls.h new file mode 100644 index 000000000..81ca2a289 --- /dev/null +++ b/drivers/media/i2c/imx274_mode_tbls.h | |||
@@ -0,0 +1,430 @@ | |||
1 | /* | ||
2 | * imx274.c - imx274 sensor driver | ||
3 | * | ||
4 | * Copyright (c) 2016-2017, NVIDIA CORPORATION, All Rights Reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #ifndef __IMX274_I2C_TABLES__ | ||
20 | #define __IMX274_I2C_TABLES__ | ||
21 | |||
22 | #include <media/camera_common.h> | ||
23 | |||
24 | |||
25 | #define IMX274_TABLE_WAIT_MS 0 | ||
26 | #define IMX274_TABLE_END 1 | ||
27 | #define IMX274_WAIT_MS 1 | ||
28 | |||
29 | #define imx274_reg struct reg_8 | ||
30 | |||
31 | static const imx274_reg imx274_start[] = { | ||
32 | {0x3000, 0x00}, /* mode select streaming on */ | ||
33 | {0x303E, 0x02}, | ||
34 | {IMX274_TABLE_WAIT_MS, IMX274_WAIT_MS}, | ||
35 | {0x30F4, 0x00}, | ||
36 | {0x3018, 0xA2}, | ||
37 | {IMX274_TABLE_WAIT_MS, IMX274_WAIT_MS}, | ||
38 | {IMX274_TABLE_END, 0x00} | ||
39 | }; | ||
40 | |||
41 | static const imx274_reg imx274_stop[] = { | ||
42 | {IMX274_TABLE_WAIT_MS, IMX274_WAIT_MS}, | ||
43 | {0x3000, 0x01}, /* mode select streaming off */ | ||
44 | {IMX274_TABLE_END, 0x00} | ||
45 | }; | ||
46 | |||
47 | static const imx274_reg tp_colorbars[] = { | ||
48 | /* test pattern */ | ||
49 | {0x303C, 0x11}, | ||
50 | {0x303D, 0x0B}, | ||
51 | {0x370B, 0x11}, | ||
52 | {0x370E, 0x00}, | ||
53 | {0x377F, 0x01}, | ||
54 | {0x3781, 0x01}, | ||
55 | {IMX274_TABLE_END, 0x00} | ||
56 | }; | ||
57 | |||
58 | |||
59 | /* Mode 1 : 3840X2160 10 bits 30fps*/ | ||
60 | static const imx274_reg mode_3840X2160[] = { | ||
61 | {IMX274_TABLE_WAIT_MS, IMX274_WAIT_MS}, | ||
62 | {0x3000, 0x12}, /* mode select streaming on */ | ||
63 | /* input freq. 24M */ | ||
64 | {0x3120, 0xF0}, | ||
65 | {0x3122, 0x02}, | ||
66 | {0x3129, 0x9c}, | ||
67 | {0x312A, 0x02}, | ||
68 | {0x312D, 0x02}, | ||
69 | |||
70 | {0x310B, 0x00}, | ||
71 | {0x304C, 0x00}, | ||
72 | {0x304D, 0x03}, | ||
73 | {0x331C, 0x1A}, | ||
74 | {0x3502, 0x02}, | ||
75 | {0x3529, 0x0E}, | ||
76 | {0x352A, 0x0E}, | ||
77 | {0x352B, 0x0E}, | ||
78 | {0x3538, 0x0E}, | ||
79 | {0x3539, 0x0E}, | ||
80 | {0x3553, 0x00}, | ||
81 | {0x357D, 0x05}, | ||
82 | {0x357F, 0x05}, | ||
83 | {0x3581, 0x04}, | ||
84 | {0x3583, 0x76}, | ||
85 | {0x3587, 0x01}, | ||
86 | {0x35BB, 0x0E}, | ||
87 | {0x35BC, 0x0E}, | ||
88 | {0x35BD, 0x0E}, | ||
89 | {0x35BE, 0x0E}, | ||
90 | {0x35BF, 0x0E}, | ||
91 | {0x366E, 0x00}, | ||
92 | {0x366F, 0x00}, | ||
93 | {0x3670, 0x00}, | ||
94 | {0x3671, 0x00}, | ||
95 | {0x30EE, 0x01}, | ||
96 | {0x3304, 0x32}, | ||
97 | {0x3306, 0x32}, | ||
98 | {0x3590, 0x32}, | ||
99 | {0x3686, 0x32}, | ||
100 | /* resolution */ | ||
101 | {0x30E2, 0x01}, | ||
102 | {0x30F6, 0x07}, | ||
103 | {0x30F7, 0x01}, | ||
104 | {0x30F8, 0xC6}, | ||
105 | {0x30F9, 0x11}, | ||
106 | {0x3130, 0x86}, | ||
107 | {0x3131, 0x08}, | ||
108 | {0x3132, 0x7E}, | ||
109 | {0x3133, 0x08}, | ||
110 | /* mode setting */ | ||
111 | {0x3004, 0x01}, | ||
112 | {0x3005, 0x01}, | ||
113 | {0x3006, 0x00}, | ||
114 | {0x3007, 0x02}, | ||
115 | {0x3A41, 0x08}, | ||
116 | {0x3342, 0x0A}, | ||
117 | {0x3343, 0x00}, | ||
118 | {0x3344, 0x16}, | ||
119 | {0x3345, 0x00}, | ||
120 | {0x3528, 0x0E}, | ||
121 | {0x3554, 0x1F}, | ||
122 | {0x3555, 0x01}, | ||
123 | {0x3556, 0x01}, | ||
124 | {0x3557, 0x01}, | ||
125 | {0x3558, 0x01}, | ||
126 | {0x3559, 0x00}, | ||
127 | {0x355A, 0x00}, | ||
128 | {0x35BA, 0x0E}, | ||
129 | {0x366A, 0x1B}, | ||
130 | {0x366B, 0x1A}, | ||
131 | {0x366C, 0x19}, | ||
132 | {0x366D, 0x17}, | ||
133 | {0x33A6, 0x01}, | ||
134 | {0x306B, 0x05}, | ||
135 | |||
136 | /* d gain setting */ | ||
137 | {0x3012, 0x01}, | ||
138 | {0x300E, 0x01}, | ||
139 | |||
140 | {IMX274_TABLE_WAIT_MS, IMX274_WAIT_MS}, | ||
141 | {IMX274_TABLE_END, 0x0000} | ||
142 | }; | ||
143 | |||
144 | /* Mode 1 : 3840X2160 10 bits 60fps*/ | ||
145 | static const imx274_reg mode_3840X2160_60fps[] = { | ||
146 | {IMX274_TABLE_WAIT_MS, IMX274_WAIT_MS}, | ||
147 | {0x3000, 0x12}, /* mode select streaming on */ | ||
148 | /* input freq. 24M */ | ||
149 | {0x3120, 0xF0}, | ||
150 | {0x3122, 0x02}, | ||
151 | {0x3129, 0x9c}, | ||
152 | {0x312A, 0x02}, | ||
153 | {0x312D, 0x02}, | ||
154 | |||
155 | {0x310B, 0x00}, | ||
156 | {0x304C, 0x00}, | ||
157 | {0x304D, 0x03}, | ||
158 | {0x331C, 0x1A}, | ||
159 | {0x3502, 0x02}, | ||
160 | {0x3529, 0x0E}, | ||
161 | {0x352A, 0x0E}, | ||
162 | {0x352B, 0x0E}, | ||
163 | {0x3538, 0x0E}, | ||
164 | {0x3539, 0x0E}, | ||
165 | {0x3553, 0x00}, | ||
166 | {0x357D, 0x05}, | ||
167 | {0x357F, 0x05}, | ||
168 | {0x3581, 0x04}, | ||
169 | {0x3583, 0x76}, | ||
170 | {0x3587, 0x01}, | ||
171 | {0x35BB, 0x0E}, | ||
172 | {0x35BC, 0x0E}, | ||
173 | {0x35BD, 0x0E}, | ||
174 | {0x35BE, 0x0E}, | ||
175 | {0x35BF, 0x0E}, | ||
176 | {0x366E, 0x00}, | ||
177 | {0x366F, 0x00}, | ||
178 | {0x3670, 0x00}, | ||
179 | {0x3671, 0x00}, | ||
180 | {0x30EE, 0x01}, | ||
181 | {0x3304, 0x32}, | ||
182 | {0x3306, 0x32}, | ||
183 | {0x3590, 0x32}, | ||
184 | {0x3686, 0x32}, | ||
185 | /* resolution */ | ||
186 | {0x30E2, 0x01}, | ||
187 | {0x30F6, 0x07}, | ||
188 | {0x30F7, 0x01}, | ||
189 | {0x30F8, 0xC6}, | ||
190 | {0x30F9, 0x11}, | ||
191 | {0x3130, 0x86}, | ||
192 | {0x3131, 0x08}, | ||
193 | {0x3132, 0x7E}, | ||
194 | {0x3133, 0x08}, | ||
195 | /* mode setting */ | ||
196 | {0x3004, 0x01}, | ||
197 | {0x3005, 0x01}, | ||
198 | {0x3006, 0x00}, | ||
199 | {0x3007, 0x02}, | ||
200 | {0x3A41, 0x08}, | ||
201 | {0x3342, 0x0A}, | ||
202 | {0x3343, 0x00}, | ||
203 | {0x3344, 0x16}, | ||
204 | {0x3345, 0x00}, | ||
205 | {0x3528, 0x0E}, | ||
206 | {0x3554, 0x1F}, | ||
207 | {0x3555, 0x01}, | ||
208 | {0x3556, 0x01}, | ||
209 | {0x3557, 0x01}, | ||
210 | {0x3558, 0x01}, | ||
211 | {0x3559, 0x00}, | ||
212 | {0x355A, 0x00}, | ||
213 | {0x35BA, 0x0E}, | ||
214 | {0x366A, 0x1B}, | ||
215 | {0x366B, 0x1A}, | ||
216 | {0x366C, 0x19}, | ||
217 | {0x366D, 0x17}, | ||
218 | {0x33A6, 0x01}, | ||
219 | {0x306B, 0x05}, | ||
220 | |||
221 | /* d gain setting */ | ||
222 | {0x3012, 0x01}, | ||
223 | {0x300E, 0x00}, | ||
224 | |||
225 | {IMX274_TABLE_WAIT_MS, IMX274_WAIT_MS}, | ||
226 | {IMX274_TABLE_END, 0x0000} | ||
227 | }; | ||
228 | |||
229 | /* Mode 3 : 1920X1080 10 bits 60fps*/ | ||
230 | static imx274_reg mode_1920X1080[] = { | ||
231 | {IMX274_TABLE_WAIT_MS, IMX274_WAIT_MS}, | ||
232 | {0x3000, 0x12}, /* mode select streaming on */ | ||
233 | /* input freq. 24M */ | ||
234 | {0x3120, 0xF0}, | ||
235 | {0x3122, 0x02}, | ||
236 | {0x3129, 0x9c}, | ||
237 | {0x312A, 0x02}, | ||
238 | {0x312D, 0x02}, | ||
239 | |||
240 | {0x310B, 0x00}, | ||
241 | {0x304C, 0x00}, | ||
242 | {0x304D, 0x03}, | ||
243 | {0x331C, 0x1A}, | ||
244 | {0x3502, 0x02}, | ||
245 | {0x3529, 0x0E}, | ||
246 | {0x352A, 0x0E}, | ||
247 | {0x352B, 0x0E}, | ||
248 | {0x3538, 0x0E}, | ||
249 | {0x3539, 0x0E}, | ||
250 | {0x3553, 0x00}, | ||
251 | {0x357D, 0x05}, | ||
252 | {0x357F, 0x05}, | ||
253 | {0x3581, 0x04}, | ||
254 | {0x3583, 0x76}, | ||
255 | {0x3587, 0x01}, | ||
256 | {0x35BB, 0x0E}, | ||
257 | {0x35BC, 0x0E}, | ||
258 | {0x35BD, 0x0E}, | ||
259 | {0x35BE, 0x0E}, | ||
260 | {0x35BF, 0x0E}, | ||
261 | {0x366E, 0x00}, | ||
262 | {0x366F, 0x00}, | ||
263 | {0x3670, 0x00}, | ||
264 | {0x3671, 0x00}, | ||
265 | {0x30EE, 0x01}, | ||
266 | {0x3304, 0x32}, | ||
267 | {0x3306, 0x32}, | ||
268 | {0x3590, 0x32}, | ||
269 | {0x3686, 0x32}, | ||
270 | /* resolution */ | ||
271 | {0x30E2, 0x02}, | ||
272 | {0x30F6, 0x04}, | ||
273 | {0x30F7, 0x01}, | ||
274 | {0x30F8, 0x06}, | ||
275 | {0x30F9, 0x09}, | ||
276 | {0x3130, 0x4E}, | ||
277 | {0x3131, 0x04}, | ||
278 | {0x3132, 0x46}, | ||
279 | {0x3133, 0x04}, | ||
280 | /* mode setting */ | ||
281 | {0x3004, 0x02}, | ||
282 | {0x3005, 0x21}, | ||
283 | {0x3006, 0x00}, | ||
284 | {0x3007, 0x11}, | ||
285 | {0x3A41, 0x08}, | ||
286 | {0x3342, 0x0A}, | ||
287 | {0x3343, 0x00}, | ||
288 | {0x3344, 0x1A}, | ||
289 | {0x3345, 0x00}, | ||
290 | {0x3528, 0x0E}, | ||
291 | {0x3554, 0x00}, | ||
292 | {0x3555, 0x01}, | ||
293 | {0x3556, 0x01}, | ||
294 | {0x3557, 0x01}, | ||
295 | {0x3558, 0x01}, | ||
296 | {0x3559, 0x00}, | ||
297 | {0x355A, 0x00}, | ||
298 | {0x35BA, 0x0E}, | ||
299 | {0x366A, 0x1B}, | ||
300 | {0x366B, 0x1A}, | ||
301 | {0x366C, 0x19}, | ||
302 | {0x366D, 0x17}, | ||
303 | {0x33A6, 0x01}, | ||
304 | {0x306B, 0x05}, | ||
305 | |||
306 | /* d gain setting */ | ||
307 | {0x3012, 0x01}, | ||
308 | {0x300E, 0x01}, | ||
309 | |||
310 | {IMX274_TABLE_WAIT_MS, IMX274_WAIT_MS}, | ||
311 | {IMX274_TABLE_END, 0x0000} | ||
312 | }; | ||
313 | |||
314 | /* Mode 5 : 1280X720 10 bits */ | ||
315 | static imx274_reg mode_1280X720[] = { | ||
316 | {IMX274_TABLE_WAIT_MS, IMX274_WAIT_MS}, | ||
317 | {0x3000, 0x12}, /* mode select streaming on */ | ||
318 | /* input freq. 24M */ | ||
319 | {0x3120, 0xF0}, | ||
320 | {0x3122, 0x02}, | ||
321 | {0x3129, 0x9c}, | ||
322 | {0x312A, 0x02}, | ||
323 | {0x312D, 0x02}, | ||
324 | |||
325 | {0x310B, 0x00}, | ||
326 | {0x304C, 0x00}, | ||
327 | {0x304D, 0x03}, | ||
328 | {0x331C, 0x1A}, | ||
329 | {0x3502, 0x02}, | ||
330 | {0x3529, 0x0E}, | ||
331 | {0x352A, 0x0E}, | ||
332 | {0x352B, 0x0E}, | ||
333 | {0x3538, 0x0E}, | ||
334 | {0x3539, 0x0E}, | ||
335 | {0x3553, 0x00}, | ||
336 | {0x357D, 0x05}, | ||
337 | {0x357F, 0x05}, | ||
338 | {0x3581, 0x04}, | ||
339 | {0x3583, 0x76}, | ||
340 | {0x3587, 0x01}, | ||
341 | {0x35BB, 0x0E}, | ||
342 | {0x35BC, 0x0E}, | ||
343 | {0x35BD, 0x0E}, | ||
344 | {0x35BE, 0x0E}, | ||
345 | {0x35BF, 0x0E}, | ||
346 | {0x366E, 0x00}, | ||
347 | {0x366F, 0x00}, | ||
348 | {0x3670, 0x00}, | ||
349 | {0x3671, 0x00}, | ||
350 | {0x30EE, 0x01}, | ||
351 | {0x3304, 0x32}, | ||
352 | {0x3306, 0x32}, | ||
353 | {0x3590, 0x32}, | ||
354 | {0x3686, 0x32}, | ||
355 | /* resolution */ | ||
356 | {0x30E2, 0x03}, | ||
357 | {0x30F6, 0x04}, | ||
358 | {0x30F7, 0x01}, | ||
359 | {0x30F8, 0x06}, | ||
360 | {0x30F9, 0x09}, | ||
361 | {0x3130, 0xE2}, | ||
362 | {0x3131, 0x02}, | ||
363 | {0x3132, 0xDE}, | ||
364 | {0x3133, 0x02}, | ||
365 | /* mode setting */ | ||
366 | {0x3004, 0x03}, | ||
367 | {0x3005, 0x31}, | ||
368 | {0x3006, 0x00}, | ||
369 | {0x3007, 0x09}, | ||
370 | {0x3A41, 0x04}, | ||
371 | {0x3342, 0x0A}, | ||
372 | {0x3343, 0x00}, | ||
373 | {0x3344, 0x1B}, | ||
374 | {0x3345, 0x00}, | ||
375 | {0x3528, 0x0E}, | ||
376 | {0x3554, 0x00}, | ||
377 | {0x3555, 0x01}, | ||
378 | {0x3556, 0x01}, | ||
379 | {0x3557, 0x01}, | ||
380 | {0x3558, 0x01}, | ||
381 | {0x3559, 0x00}, | ||
382 | {0x355A, 0x00}, | ||
383 | {0x35BA, 0x0E}, | ||
384 | {0x366A, 0x1B}, | ||
385 | {0x366B, 0x19}, | ||
386 | {0x366C, 0x17}, | ||
387 | {0x366D, 0x17}, | ||
388 | {0x33A6, 0x01}, | ||
389 | {0x306B, 0x05}, | ||
390 | |||
391 | /* d gain setting */ | ||
392 | {0x3012, 0x01}, | ||
393 | |||
394 | {IMX274_TABLE_WAIT_MS, IMX274_WAIT_MS}, | ||
395 | {IMX274_TABLE_END, 0x0000} | ||
396 | }; | ||
397 | |||
398 | enum { | ||
399 | IMX274_MODE_3840X2160, | ||
400 | IMX274_MODE_1920X1080, | ||
401 | IMX274_MODE_1280X720, | ||
402 | IMX274_MODE_START_STREAM, | ||
403 | IMX274_MODE_STOP_STREAM, | ||
404 | IMX274_MODE_TEST_PATTERN, | ||
405 | }; | ||
406 | |||
407 | static const imx274_reg *mode_table[] = { | ||
408 | [IMX274_MODE_3840X2160] = mode_3840X2160_60fps, | ||
409 | [IMX274_MODE_1920X1080] = mode_1920X1080, | ||
410 | [IMX274_MODE_1280X720] = mode_1280X720, | ||
411 | |||
412 | [IMX274_MODE_START_STREAM] = imx274_start, | ||
413 | [IMX274_MODE_STOP_STREAM] = imx274_stop, | ||
414 | [IMX274_MODE_TEST_PATTERN] = tp_colorbars, | ||
415 | }; | ||
416 | |||
417 | static const int imx274_30_fr[] = { | ||
418 | 30, | ||
419 | }; | ||
420 | |||
421 | static const int imx274_60_fr[] = { | ||
422 | 60, | ||
423 | }; | ||
424 | |||
425 | static const struct camera_common_frmfmt imx274_frmfmt[] = { | ||
426 | {{3864, 2174}, imx274_60_fr, 1, 0, IMX274_MODE_3840X2160}, | ||
427 | {{1920, 1080}, imx274_60_fr, 1, 0, IMX274_MODE_1920X1080}, | ||
428 | {{1280, 720}, imx274_60_fr, 1, 0, IMX274_MODE_1280X720}, | ||
429 | }; | ||
430 | #endif /* __IMX274_I2C_TABLES__ */ | ||
diff --git a/drivers/media/i2c/lc898212.c b/drivers/media/i2c/lc898212.c new file mode 100644 index 000000000..44cdb876e --- /dev/null +++ b/drivers/media/i2c/lc898212.c | |||
@@ -0,0 +1,645 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #include <linux/delay.h> | ||
18 | #include <linux/fs.h> | ||
19 | #include <linux/i2c.h> | ||
20 | #include <linux/miscdevice.h> | ||
21 | #include <linux/regulator/consumer.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/uaccess.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/regmap.h> | ||
26 | #include <linux/gpio.h> | ||
27 | #include <linux/of.h> | ||
28 | #include <linux/of_device.h> | ||
29 | #include <linux/of_gpio.h> | ||
30 | |||
31 | #include <media/camera_common.h> | ||
32 | |||
33 | #include "tegra_camera_dev_mfi.h" | ||
34 | |||
35 | #define LC898212_ACTUATOR_RANGE 1023 | ||
36 | #define LC898212_POS_LOW_DEFAULT (0) | ||
37 | #define LC898212_POS_HIGH_DEFAULT (1023) | ||
38 | #define LC898212_FOCUS_MACRO (896) | ||
39 | #define LC898212_FOCUS_INFINITY (128) | ||
40 | #define LC898212_PWR_DEV_OFF (0) | ||
41 | #define LC898212_PWR_DEV_ON (1) | ||
42 | |||
43 | #define SETTLETIME_MS (15) | ||
44 | #define FOCAL_LENGTH (47300) | ||
45 | #define MAX_APERTURE (22000) | ||
46 | #define FNUMBER (22000) | ||
47 | #define LC898212_MOVE_TIME_VALUE (0x43) | ||
48 | |||
49 | #define LC898212_MAX_RETRIES (3) | ||
50 | |||
51 | #define LC898212_WAIT_REPEAT 0xFE | ||
52 | #define LC898212_TABLE_END 0xFF | ||
53 | |||
54 | #define LC898212_REG_ACCESS 0x1 | ||
55 | #define LC898212_RAM_ACCESS 0x2 | ||
56 | |||
57 | #define AF_MIN 0 | ||
58 | #define AF_MAX 1023 | ||
59 | #define AF_RANGE (AF_MAX - AF_MIN + 1) | ||
60 | |||
61 | #define LC898212_RZ 0x04 | ||
62 | #define LC898212_ADOFFSET 0x3C | ||
63 | #define LC898212_EQENBL 0x87 | ||
64 | |||
65 | /** | ||
66 | * standard + custom controls | ||
67 | * custom controls not added for this focuser yet | ||
68 | */ | ||
69 | #define NUM_FOCUS_STD_CTRLS 1 | ||
70 | #define NUM_FOCUS_CUSTOM_CTRLS 0 | ||
71 | #define NUM_FOCUS_CTRLS (NUM_FOCUS_STD_CTRLS + NUM_FOCUS_CUSTOM_CTRLS) | ||
72 | |||
73 | static int lc898212_s_ctrl(struct v4l2_ctrl *ctrl); | ||
74 | |||
75 | struct lc898212_reg { | ||
76 | u8 type; | ||
77 | u8 addr; | ||
78 | u16 val; | ||
79 | }; | ||
80 | |||
81 | struct lc898212 { | ||
82 | struct i2c_client *i2c_client; | ||
83 | struct v4l2_subdev *subdev; | ||
84 | struct media_pad pad; | ||
85 | |||
86 | struct v4l2_ctrl_handler ctrl_handler; | ||
87 | struct regulator *regulator; | ||
88 | struct camera_common_focuser_data *s_data; | ||
89 | struct regmap *regmap8; | ||
90 | struct regmap *regmap16; | ||
91 | int numctrls; | ||
92 | struct camera_mfi_dev *cmfi_dev16; | ||
93 | bool support_mfi; | ||
94 | struct v4l2_ctrl *ctrls[]; | ||
95 | }; | ||
96 | |||
97 | static struct lc898212_reg lc898212_init_setting[] = { | ||
98 | {LC898212_REG_ACCESS, 0x80, 0x34}, | ||
99 | {LC898212_REG_ACCESS, 0x81, 0xA0}, | ||
100 | {LC898212_REG_ACCESS, 0x84, 0xE0}, | ||
101 | {LC898212_REG_ACCESS, 0x87, 0x05}, | ||
102 | {LC898212_REG_ACCESS, 0xA4, 0x24}, | ||
103 | {LC898212_RAM_ACCESS, 0x3A, 0x0000}, | ||
104 | {LC898212_RAM_ACCESS, 0x04, 0x0000}, | ||
105 | {LC898212_RAM_ACCESS, 0x02, 0x0000}, | ||
106 | {LC898212_RAM_ACCESS, 0x18, 0x0000}, | ||
107 | |||
108 | /* Filter Setting */ | ||
109 | {LC898212_RAM_ACCESS, 0x40, 0x4030}, | ||
110 | {LC898212_RAM_ACCESS, 0x42, 0x7150}, | ||
111 | {LC898212_RAM_ACCESS, 0x44, 0x8F90}, | ||
112 | {LC898212_RAM_ACCESS, 0x46, 0x61B0}, | ||
113 | {LC898212_RAM_ACCESS, 0x48, 0x7FF0}, | ||
114 | {LC898212_RAM_ACCESS, 0x4A, 0x3930}, | ||
115 | {LC898212_RAM_ACCESS, 0x4C, 0x4030}, | ||
116 | {LC898212_RAM_ACCESS, 0x4E, 0x8010}, | ||
117 | {LC898212_RAM_ACCESS, 0x50, 0x04F0}, | ||
118 | {LC898212_RAM_ACCESS, 0x52, 0x7610}, | ||
119 | {LC898212_RAM_ACCESS, 0x54, 0x2030}, | ||
120 | {LC898212_RAM_ACCESS, 0x56, 0x0000}, | ||
121 | {LC898212_RAM_ACCESS, 0x58, 0x7FF0}, | ||
122 | {LC898212_RAM_ACCESS, 0x5A, 0x0680}, | ||
123 | {LC898212_RAM_ACCESS, 0x5C, 0x72F0}, | ||
124 | {LC898212_RAM_ACCESS, 0x5E, 0x7F70}, | ||
125 | {LC898212_RAM_ACCESS, 0x60, 0x7ED0}, | ||
126 | {LC898212_RAM_ACCESS, 0x62, 0x7FF0}, | ||
127 | {LC898212_RAM_ACCESS, 0x64, 0x0000}, | ||
128 | {LC898212_RAM_ACCESS, 0x66, 0x0000}, | ||
129 | {LC898212_RAM_ACCESS, 0x68, 0x5130}, | ||
130 | {LC898212_RAM_ACCESS, 0x6A, 0x72F0}, | ||
131 | {LC898212_RAM_ACCESS, 0x6C, 0x8010}, | ||
132 | {LC898212_RAM_ACCESS, 0x6E, 0x0000}, | ||
133 | {LC898212_RAM_ACCESS, 0x70, 0x0000}, | ||
134 | {LC898212_RAM_ACCESS, 0x72, 0x18E0}, | ||
135 | {LC898212_RAM_ACCESS, 0x74, 0x4E30}, | ||
136 | {LC898212_RAM_ACCESS, 0x30, 0x0000}, | ||
137 | {LC898212_RAM_ACCESS, 0x76, 0x0C50}, | ||
138 | {LC898212_RAM_ACCESS, 0x78, 0x4000}, | ||
139 | |||
140 | {LC898212_REG_ACCESS, 0x86, 0x60}, | ||
141 | {LC898212_REG_ACCESS, 0x88, 0x70}, | ||
142 | {LC898212_RAM_ACCESS, 0x28, 0x8020}, | ||
143 | {LC898212_RAM_ACCESS, 0x4C, 0x4000}, | ||
144 | {LC898212_REG_ACCESS, 0x83, 0x2C}, | ||
145 | {LC898212_REG_ACCESS, 0x85, 0xC0}, | ||
146 | |||
147 | /* Repeat to read the register until the value turns 0x00 */ | ||
148 | {LC898212_REG_ACCESS, LC898212_WAIT_REPEAT, 0x85}, | ||
149 | |||
150 | {LC898212_REG_ACCESS, 0x84, 0xE3}, | ||
151 | {LC898212_REG_ACCESS, 0x97, 0x00}, | ||
152 | {LC898212_REG_ACCESS, 0x98, 0x42}, | ||
153 | {LC898212_REG_ACCESS, 0x99, 0x00}, | ||
154 | {LC898212_REG_ACCESS, 0x9A, 0x00}, | ||
155 | |||
156 | {LC898212_REG_ACCESS, LC898212_TABLE_END, 0x00} | ||
157 | }; | ||
158 | |||
159 | const struct of_device_id lc898212_of_match[] = { | ||
160 | { .compatible = "nvidia,lc898212", }, | ||
161 | { }, | ||
162 | }; | ||
163 | MODULE_DEVICE_TABLE(of, lc898212_of_match); | ||
164 | |||
165 | static int lc898212_set_position(struct lc898212 *priv, u32 position) | ||
166 | { | ||
167 | int ret = 0; | ||
168 | s16 new_pos = 0; | ||
169 | struct camera_common_focuser_data *s_data = priv->s_data; | ||
170 | struct nv_focuser_config *cfg = &s_data->config; | ||
171 | |||
172 | dev_dbg(&s_data->i2c_client->dev, "%s++\n", __func__); | ||
173 | if (position < cfg->pos_actual_low || | ||
174 | position > cfg->pos_actual_high) { | ||
175 | dev_dbg(&priv->i2c_client->dev, | ||
176 | "%s: position(%d) out of bound([%d, %d])\n", | ||
177 | __func__, position, cfg->pos_actual_low, | ||
178 | cfg->pos_actual_high); | ||
179 | if (position < cfg->pos_actual_low) | ||
180 | position = cfg->pos_actual_low; | ||
181 | if (position > cfg->pos_actual_high) | ||
182 | position = cfg->pos_actual_high; | ||
183 | } | ||
184 | |||
185 | /* unsigned 10 bit to signed 16 bit */ | ||
186 | new_pos = ((s16) position - AF_RANGE / 2) * 64; | ||
187 | |||
188 | if (priv->support_mfi) { | ||
189 | ret = tegra_camera_dev_mfi_clear(priv->cmfi_dev16); | ||
190 | ret |= tegra_camera_dev_mfi_wr_add(priv->cmfi_dev16, | ||
191 | LC898212_RZ, | ||
192 | (u16) new_pos); | ||
193 | } else { | ||
194 | ret = regmap_write(priv->regmap16, LC898212_RZ, (u16) new_pos); | ||
195 | } | ||
196 | |||
197 | dev_dbg(&s_data->i2c_client->dev, "%s--\n", __func__); | ||
198 | return ret; | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * V4l2 controls | ||
203 | */ | ||
204 | |||
205 | static const struct v4l2_ctrl_ops lc898212_ctrl_ops = { | ||
206 | .s_ctrl = lc898212_s_ctrl, | ||
207 | }; | ||
208 | |||
209 | static int lc898212_s_ctrl(struct v4l2_ctrl *ctrl) | ||
210 | { | ||
211 | struct lc898212 *priv = | ||
212 | container_of(ctrl->handler, struct lc898212, ctrl_handler); | ||
213 | int err; | ||
214 | |||
215 | dev_dbg(&priv->s_data->i2c_client->dev, "%s++\n", __func__); | ||
216 | /* check for power state */ | ||
217 | if (priv->s_data->pwr_dev == LC898212_PWR_DEV_OFF) | ||
218 | return -ENODEV; | ||
219 | |||
220 | switch (ctrl->id) { | ||
221 | case V4L2_CID_FOCUS_ABSOLUTE: | ||
222 | err = lc898212_set_position(priv, ctrl->val); | ||
223 | break; | ||
224 | default: | ||
225 | pr_err("%s: unknown v4l2 ctlr id\n", __func__); | ||
226 | return -EINVAL; | ||
227 | } | ||
228 | |||
229 | return err; | ||
230 | } | ||
231 | |||
232 | static int lc898212_ctrls_init(struct camera_common_focuser_data *s_data) | ||
233 | { | ||
234 | struct lc898212 *priv = (struct lc898212 *)s_data->priv; | ||
235 | struct i2c_client *client = priv->i2c_client; | ||
236 | struct v4l2_ctrl *ctrl; | ||
237 | struct nv_focuser_config *cfg = &s_data->config; | ||
238 | int min = cfg->pos_actual_low; | ||
239 | int max = cfg->pos_actual_high; | ||
240 | int def = priv->s_data->def_position; | ||
241 | int err = 0; | ||
242 | |||
243 | v4l2_ctrl_handler_init(&priv->ctrl_handler, priv->numctrls); | ||
244 | priv->subdev->ctrl_handler = &priv->ctrl_handler; | ||
245 | err = priv->ctrl_handler.error; | ||
246 | if (err) { | ||
247 | dev_err(&client->dev, "Error %d adding controls\n", err); | ||
248 | goto error; | ||
249 | } | ||
250 | |||
251 | /* add std controls */ | ||
252 | ctrl = v4l2_ctrl_new_std(&priv->ctrl_handler, &lc898212_ctrl_ops, | ||
253 | V4L2_CID_FOCUS_ABSOLUTE, min, max, 1, def); | ||
254 | if (ctrl == NULL) { | ||
255 | dev_err(&client->dev, "Error initializing controls\n"); | ||
256 | err = -EINVAL; | ||
257 | goto error; | ||
258 | } | ||
259 | priv->ctrls[0] = ctrl; | ||
260 | |||
261 | err = v4l2_ctrl_handler_setup(&priv->ctrl_handler); | ||
262 | if (err) { | ||
263 | dev_err(&client->dev, "Error setting default controls\n"); | ||
264 | goto error; | ||
265 | } | ||
266 | |||
267 | return 0; | ||
268 | error: | ||
269 | v4l2_ctrl_handler_free(&priv->ctrl_handler); | ||
270 | return err; | ||
271 | } | ||
272 | |||
273 | static int lc898212_write_table(struct lc898212 *priv, | ||
274 | const struct lc898212_reg table[]) | ||
275 | { | ||
276 | int err; | ||
277 | const struct lc898212_reg *next; | ||
278 | u16 val; | ||
279 | |||
280 | for (next = table; next->addr != LC898212_TABLE_END; next++) { | ||
281 | val = next->val; | ||
282 | |||
283 | if (next->addr == LC898212_WAIT_REPEAT) { | ||
284 | u8 data = 0; | ||
285 | u8 count = 0; | ||
286 | |||
287 | err = regmap_read(priv->regmap8, val, | ||
288 | (unsigned int *) &data); | ||
289 | if (err) { | ||
290 | pr_err("%s: regmap_read: %d\n", __func__, err); | ||
291 | return err; | ||
292 | } | ||
293 | while (data != 0) { | ||
294 | if (count >= 10) | ||
295 | return -EFAULT; /* focuser not ready */ | ||
296 | |||
297 | usleep_range(10, 20); | ||
298 | err = regmap_read(priv->regmap8, val, | ||
299 | (unsigned int *) &data); | ||
300 | if (err) { | ||
301 | pr_err("%s: regmap_read: %d\n", | ||
302 | __func__, err); | ||
303 | return err; | ||
304 | } | ||
305 | count++; | ||
306 | } | ||
307 | continue; | ||
308 | } | ||
309 | |||
310 | if (next->type == LC898212_RAM_ACCESS) | ||
311 | err = regmap_write(priv->regmap16, next->addr, val); | ||
312 | else | ||
313 | err = regmap_write(priv->regmap8, next->addr, val); | ||
314 | if (err) { | ||
315 | pr_err("%s:lc898212_write_table:%d", __func__, err); | ||
316 | return err; | ||
317 | } | ||
318 | } | ||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | static unsigned int convert_signed16b_to_unsigned10b(s16 data) | ||
323 | { | ||
324 | return (u16)(data / 64 + (AF_RANGE>>1)); | ||
325 | } | ||
326 | |||
327 | static int lc898212_init(struct lc898212 *priv) | ||
328 | { | ||
329 | int err; | ||
330 | int data; | ||
331 | |||
332 | err = lc898212_write_table(priv, lc898212_init_setting); | ||
333 | |||
334 | err |= regmap_read(priv->regmap16, LC898212_ADOFFSET, &data); | ||
335 | priv->s_data->def_position = | ||
336 | convert_signed16b_to_unsigned10b((s16)(data & 0xffff)); | ||
337 | err |= regmap_write(priv->regmap16, LC898212_RZ, data); | ||
338 | |||
339 | /* Servo On */ | ||
340 | err |= regmap_write(priv->regmap8, LC898212_EQENBL, 0x85); | ||
341 | |||
342 | return err; | ||
343 | } | ||
344 | |||
345 | static int lc898212_load_config(struct camera_common_focuser_data *s_data) | ||
346 | { | ||
347 | struct nv_focuser_config *cfg = &s_data->config; | ||
348 | |||
349 | /* load default configuration */ | ||
350 | /* TODO: parse these values from DT */ | ||
351 | |||
352 | cfg->focal_length = FOCAL_LENGTH; | ||
353 | cfg->fnumber = FNUMBER; | ||
354 | cfg->max_aperture = MAX_APERTURE; | ||
355 | cfg->range_ends_reversed = 0; | ||
356 | |||
357 | cfg->pos_working_low = LC898212_FOCUS_INFINITY; | ||
358 | cfg->pos_working_high = LC898212_FOCUS_MACRO; | ||
359 | cfg->pos_actual_low = LC898212_POS_LOW_DEFAULT; | ||
360 | cfg->pos_actual_high = LC898212_POS_HIGH_DEFAULT; | ||
361 | |||
362 | cfg->num_focuser_sets = 1; | ||
363 | cfg->focuser_set[0].macro = LC898212_FOCUS_MACRO; | ||
364 | cfg->focuser_set[0].hyper = LC898212_FOCUS_INFINITY; | ||
365 | cfg->focuser_set[0].inf = LC898212_FOCUS_INFINITY; | ||
366 | cfg->focuser_set[0].settle_time = SETTLETIME_MS; | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | static int lc898212_power_off(struct camera_common_focuser_data *s_data) | ||
372 | { | ||
373 | struct lc898212 *priv = (struct lc898212 *)s_data->priv; | ||
374 | |||
375 | dev_dbg(&s_data->i2c_client->dev, "%s++\n", __func__); | ||
376 | if (priv->regulator) | ||
377 | regulator_disable(priv->regulator); | ||
378 | s_data->pwr_dev = LC898212_PWR_DEV_OFF; | ||
379 | |||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static int lc898212_power_on(struct camera_common_focuser_data *s_data) | ||
384 | { | ||
385 | int err = 0; | ||
386 | struct lc898212 *priv = (struct lc898212 *)s_data->priv; | ||
387 | |||
388 | dev_dbg(&s_data->i2c_client->dev, "%s++\n", __func__); | ||
389 | if (priv->regulator) { | ||
390 | err = regulator_enable(priv->regulator); | ||
391 | if (err) { | ||
392 | dev_err(&s_data->i2c_client->dev, | ||
393 | "%s:regulator enabled failed\n", __func__); | ||
394 | return err; | ||
395 | } | ||
396 | } | ||
397 | |||
398 | err = lc898212_init(priv); | ||
399 | if (err) | ||
400 | return err; | ||
401 | |||
402 | s_data->pwr_dev = LC898212_PWR_DEV_ON; | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static struct camera_common_focuser_ops lc898212_ops = { | ||
408 | .power_on = lc898212_power_on, | ||
409 | .power_off = lc898212_power_off, | ||
410 | .load_config = lc898212_load_config, | ||
411 | .ctrls_init = lc898212_ctrls_init, | ||
412 | }; | ||
413 | |||
414 | #if 0 | ||
415 | static int lc898212_s_stream(struct v4l2_subdev *sd, int enable) | ||
416 | { | ||
417 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
418 | struct camera_common_focuser_data *s_data = | ||
419 | to_camera_common_focuser_data(client); | ||
420 | struct lc898212 *priv = (struct lc898212 *)s_data->priv; | ||
421 | struct v4l2_control control; | ||
422 | int err = 0; | ||
423 | |||
424 | dev_dbg(&client->dev, "%s++\n", __func__); | ||
425 | err = lc898212_init(priv); | ||
426 | if (err) | ||
427 | return err; | ||
428 | |||
429 | /* write override registers for focus position */ | ||
430 | control.id = V4L2_CID_FOCUS_ABSOLUTE; | ||
431 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
432 | err |= lc898212_set_position(priv, control.value); | ||
433 | if (err) | ||
434 | dev_dbg(&client->dev, "%s:warning focus pos %d set failed\n", | ||
435 | __func__, control.value); | ||
436 | |||
437 | dev_dbg(&client->dev, "%s--\n", __func__); | ||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | static struct v4l2_subdev_video_ops lc898212_subdev_video_ops = { | ||
442 | .s_stream = lc898212_s_stream, | ||
443 | }; | ||
444 | |||
445 | #endif | ||
446 | |||
447 | static int lc898212_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
448 | { | ||
449 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
450 | |||
451 | dev_dbg(&client->dev, "%s:\n", __func__); | ||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | static struct v4l2_subdev_core_ops lc898212_subdev_core_ops = { | ||
456 | .s_power = camera_common_focuser_s_power, | ||
457 | }; | ||
458 | |||
459 | static struct v4l2_subdev_ops lc898212_subdev_ops = { | ||
460 | .core = &lc898212_subdev_core_ops, | ||
461 | }; | ||
462 | |||
463 | static const struct v4l2_subdev_internal_ops lc898212_subdev_internal_ops = { | ||
464 | .open = lc898212_open, | ||
465 | }; | ||
466 | |||
467 | static const struct media_entity_operations lc898212_media_ops = { | ||
468 | #ifdef CONFIG_MEDIA_CONTROLLER | ||
469 | .link_validate = v4l2_subdev_link_validate, | ||
470 | #endif | ||
471 | }; | ||
472 | |||
473 | static int lc898212_probe(struct i2c_client *client, | ||
474 | const struct i2c_device_id *id) | ||
475 | { | ||
476 | int err; | ||
477 | struct lc898212 *priv; | ||
478 | struct camera_common_focuser_data *common_data; | ||
479 | char dev_id[20]; | ||
480 | const char *p_mfi_str; | ||
481 | |||
482 | static struct regmap_config lc898212_regmap_config8 = { | ||
483 | .reg_bits = 8, | ||
484 | .val_bits = 8, | ||
485 | .name = "8bit", | ||
486 | }; | ||
487 | static struct regmap_config lc898212_regmap_config16 = { | ||
488 | .reg_bits = 8, | ||
489 | .val_bits = 16, | ||
490 | .name = "16bit", | ||
491 | }; | ||
492 | |||
493 | pr_info("[lc898212]: probing sensor\n"); | ||
494 | |||
495 | common_data = devm_kzalloc(&client->dev, | ||
496 | sizeof(struct camera_common_focuser_data), GFP_KERNEL); | ||
497 | if (!common_data) | ||
498 | return -ENOMEM; | ||
499 | |||
500 | priv = devm_kzalloc(&client->dev, (sizeof(struct lc898212) + | ||
501 | sizeof(struct v4l2_ctrl *) * NUM_FOCUS_CTRLS), GFP_KERNEL); | ||
502 | if (!priv) | ||
503 | return -ENOMEM; | ||
504 | |||
505 | priv->regulator = devm_regulator_get(&client->dev, "vvcm"); | ||
506 | if (IS_ERR(priv->regulator)) { | ||
507 | dev_err(&client->dev, "unable to get regulator %s\n", | ||
508 | dev_name(&client->dev)); | ||
509 | priv->regulator = NULL; | ||
510 | } | ||
511 | |||
512 | priv->regmap8 = devm_regmap_init_i2c(client, | ||
513 | &lc898212_regmap_config8); | ||
514 | if (IS_ERR(priv->regmap8)) { | ||
515 | err = PTR_ERR(priv->regmap8); | ||
516 | dev_err(&client->dev, | ||
517 | "Failed to allocate register map 8: %d\n", err); | ||
518 | goto ERROR_RET; | ||
519 | } | ||
520 | priv->regmap16 = devm_regmap_init_i2c(client, | ||
521 | &lc898212_regmap_config16); | ||
522 | if (IS_ERR(priv->regmap16)) { | ||
523 | err = PTR_ERR(priv->regmap16); | ||
524 | dev_err(&client->dev, | ||
525 | "Failed to allocate register map 16: %d\n", err); | ||
526 | goto ERROR_RET; | ||
527 | } | ||
528 | |||
529 | common_data->ops = &lc898212_ops; | ||
530 | common_data->ctrl_handler = &priv->ctrl_handler; | ||
531 | common_data->i2c_client = client; | ||
532 | common_data->ctrls = priv->ctrls; | ||
533 | common_data->priv = (void *)priv; | ||
534 | priv->numctrls = NUM_FOCUS_CTRLS; | ||
535 | priv->i2c_client = client; | ||
536 | priv->s_data = common_data; | ||
537 | priv->subdev = &common_data->subdev; | ||
538 | priv->subdev->dev = &client->dev; | ||
539 | |||
540 | if (client->dev.of_node) { | ||
541 | err = of_property_read_string(client->dev.of_node, | ||
542 | "support_mfi", | ||
543 | &p_mfi_str); | ||
544 | if (err < 0) { | ||
545 | dev_err(&client->dev, | ||
546 | "%s unable to read MFI property\n", | ||
547 | __func__); | ||
548 | goto ERROR_RET; | ||
549 | } | ||
550 | |||
551 | priv->support_mfi = !strcmp(p_mfi_str, "true") ? true : false; | ||
552 | |||
553 | if (priv->support_mfi) { | ||
554 | int remain; | ||
555 | |||
556 | memset(dev_id, 0, sizeof(dev_id)); | ||
557 | strncpy(dev_id, "lc898212", (sizeof(dev_id) - 1)); | ||
558 | /* calculate how many bytes remaining in dev_id[] */ | ||
559 | remain = sizeof(dev_id) - strlen(dev_id) - 1; | ||
560 | /* strncat most of 'remain' bytes from dev_name[] */ | ||
561 | strncat(dev_id, dev_name(&client->dev), remain); | ||
562 | err = tegra_camera_dev_mfi_add_regmap(&priv->cmfi_dev16, | ||
563 | dev_id, priv->regmap16); | ||
564 | if (err < 0) { | ||
565 | dev_err(&client->dev, | ||
566 | "%s unable to add to mfi regmap\n", | ||
567 | __func__); | ||
568 | goto ERROR_RET; | ||
569 | } | ||
570 | } | ||
571 | } | ||
572 | |||
573 | err = camera_common_focuser_init(common_data); | ||
574 | if (err) { | ||
575 | dev_err(&client->dev, "unable to initialize focuser\n"); | ||
576 | goto ERROR_RET; | ||
577 | } | ||
578 | |||
579 | v4l2_i2c_subdev_init(priv->subdev, client, &lc898212_subdev_ops); | ||
580 | |||
581 | priv->subdev->internal_ops = &lc898212_subdev_internal_ops; | ||
582 | priv->subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | | ||
583 | V4L2_SUBDEV_FL_HAS_EVENTS; | ||
584 | |||
585 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
586 | priv->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
587 | priv->subdev->entity.type = MEDIA_ENT_T_V4L2_SUBDEV; | ||
588 | priv->subdev->entity.ops = &lc898212_media_ops; | ||
589 | err = media_entity_init(&priv->subdev->entity, 1, &priv->pad, 0); | ||
590 | if (err < 0) { | ||
591 | dev_err(&client->dev, "unable to init media entity\n"); | ||
592 | goto ERROR_RET; | ||
593 | } | ||
594 | #endif | ||
595 | |||
596 | err = v4l2_async_register_subdev(priv->subdev); | ||
597 | if (err) | ||
598 | goto ERROR_RET; | ||
599 | |||
600 | dev_dbg(&client->dev, "Detected lc898212 sensor\n"); | ||
601 | return 0; | ||
602 | |||
603 | ERROR_RET: | ||
604 | dev_err(&client->dev, "lc898212: probing sensor failed!!\n"); | ||
605 | return err; | ||
606 | } | ||
607 | |||
608 | static int lc898212_remove(struct i2c_client *client) | ||
609 | { | ||
610 | struct camera_common_focuser_data *s_data = | ||
611 | to_camera_common_focuser_data(client); | ||
612 | struct lc898212 *priv = (struct lc898212 *)s_data->priv; | ||
613 | |||
614 | v4l2_async_unregister_subdev(priv->subdev); | ||
615 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
616 | media_entity_cleanup(&priv->subdev->entity); | ||
617 | #endif | ||
618 | v4l2_ctrl_handler_free(&priv->ctrl_handler); | ||
619 | |||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | static const struct i2c_device_id lc898212_id[] = { | ||
624 | { "lc898212", 0 }, | ||
625 | { }, | ||
626 | }; | ||
627 | |||
628 | MODULE_DEVICE_TABLE(i2c, lc898212_id); | ||
629 | |||
630 | static struct i2c_driver lc898212_i2c_driver = { | ||
631 | .driver = { | ||
632 | .name = "lc898212", | ||
633 | .owner = THIS_MODULE, | ||
634 | .of_match_table = of_match_ptr(lc898212_of_match), | ||
635 | }, | ||
636 | .probe = lc898212_probe, | ||
637 | .remove = lc898212_remove, | ||
638 | .id_table = lc898212_id, | ||
639 | }; | ||
640 | |||
641 | module_i2c_driver(lc898212_i2c_driver); | ||
642 | |||
643 | MODULE_DESCRIPTION("I2C driver for LC898212"); | ||
644 | MODULE_AUTHOR("Bhanu Murthy V <bmurthyv@nvidia.com>"); | ||
645 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/i2c/ov10823.c b/drivers/media/i2c/ov10823.c new file mode 100644 index 000000000..660578777 --- /dev/null +++ b/drivers/media/i2c/ov10823.c | |||
@@ -0,0 +1,1224 @@ | |||
1 | /* | ||
2 | * ov10823.c - ov10823 sensor driver | ||
3 | * | ||
4 | * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/uaccess.h> | ||
20 | #include <linux/gpio.h> | ||
21 | #include <linux/module.h> | ||
22 | |||
23 | #include <linux/seq_file.h> | ||
24 | #include <linux/of.h> | ||
25 | #include <linux/of_device.h> | ||
26 | #include <linux/of_gpio.h> | ||
27 | |||
28 | #include <media/tegra_v4l2_camera.h> | ||
29 | #include <media/camera_common.h> | ||
30 | #include <media/ov10823.h> | ||
31 | |||
32 | #include "ov10823_mode_tbls.h" | ||
33 | |||
34 | #define OV10823_SC_CHIP_ID_HIGH_ADDR 0x300A | ||
35 | #define OV10823_SC_CHIP_ID_LOW_ADDR 0x300B | ||
36 | #define OV10823_SC_SCCB_ID_ADDR 0x300C | ||
37 | |||
38 | #define OV10823_MAX_COARSE_DIFF 8 | ||
39 | |||
40 | #define OV10823_GAIN_SHIFT 8 | ||
41 | #define OV10823_MIN_GAIN (1 << OV10823_GAIN_SHIFT) | ||
42 | #define OV10823_MAX_GAIN \ | ||
43 | ((15 << OV10823_GAIN_SHIFT) | (1 << (OV10823_GAIN_SHIFT - 1))) | ||
44 | #define OV10823_MIN_FRAME_LENGTH (0x04F0) | ||
45 | #define OV10823_MAX_FRAME_LENGTH (0x7FFF) | ||
46 | #define OV10823_MIN_EXPOSURE_COARSE (0x8) | ||
47 | #define OV10823_MAX_EXPOSURE_COARSE \ | ||
48 | (OV10823_MAX_FRAME_LENGTH-OV10823_MAX_COARSE_DIFF) | ||
49 | |||
50 | #define OV10823_DEFAULT_GAIN OV10823_MIN_GAIN | ||
51 | #define OV10823_DEFAULT_FRAME_LENGTH OV10823_MIN_FRAME_LENGTH | ||
52 | #define OV10823_DEFAULT_EXPOSURE_COARSE \ | ||
53 | (OV10823_DEFAULT_FRAME_LENGTH-OV10823_MAX_COARSE_DIFF) | ||
54 | |||
55 | #define OV10823_DEFAULT_MODE OV10823_MODE_2168X1220_60FPS | ||
56 | #define OV10823_DEFAULT_WIDTH 2168 | ||
57 | #define OV10823_DEFAULT_HEIGHT 1220 | ||
58 | #define OV10823_DEFAULT_DATAFMT MEDIA_BUS_FMT_SRGGB10_1X10 | ||
59 | #define OV10823_DEFAULT_CLK_FREQ 26000000 | ||
60 | |||
61 | #define OV10823_DEFAULT_I2C_ADDRESS_20 (0x20 >> 1) | ||
62 | #define OV10823_DEFAULT_I2C_ADDRESS_6C (0x6C >> 1) | ||
63 | |||
64 | struct ov10823 { | ||
65 | struct camera_common_power_rail power; | ||
66 | int num_ctrls; | ||
67 | int fsync; | ||
68 | int cam_sid_gpio; | ||
69 | int mcu_boot_gpio; | ||
70 | int mcu_reset_gpio; | ||
71 | struct v4l2_ctrl_handler ctrl_handler; | ||
72 | struct i2c_client *i2c_client; | ||
73 | struct v4l2_subdev *subdev; | ||
74 | struct media_pad pad; | ||
75 | |||
76 | s32 group_hold_prev; | ||
77 | bool group_hold_en; | ||
78 | struct regmap *regmap; | ||
79 | struct camera_common_data *s_data; | ||
80 | struct camera_common_pdata *pdata; | ||
81 | struct v4l2_ctrl *ctrls[]; | ||
82 | }; | ||
83 | |||
84 | static const struct regmap_config sensor_regmap_config = { | ||
85 | .reg_bits = 16, | ||
86 | .val_bits = 8, | ||
87 | .cache_type = REGCACHE_RBTREE, | ||
88 | }; | ||
89 | |||
90 | u16 ov10823_to_gain(u32 rep, int shift) | ||
91 | { | ||
92 | u16 gain; | ||
93 | int gain_int; | ||
94 | int gain_dec; | ||
95 | int min_int = (1 << shift); | ||
96 | |||
97 | if (rep < OV10823_MIN_GAIN) | ||
98 | rep = OV10823_MIN_GAIN; | ||
99 | else if (rep > OV10823_MAX_GAIN) | ||
100 | rep = OV10823_MAX_GAIN; | ||
101 | |||
102 | /* shift indicates number of least significant bits */ | ||
103 | /* used for decimal representation of gain */ | ||
104 | gain_int = (int)(rep >> shift); | ||
105 | gain_dec = (int)(rep & ~(0xffff << shift)); | ||
106 | |||
107 | /* derived from formulat gain = (x * 16 + 0.5) */ | ||
108 | gain = ((gain_int * min_int + gain_dec) * 32 + min_int) / (2 * min_int); | ||
109 | |||
110 | return gain; | ||
111 | } | ||
112 | |||
113 | static int ov10823_g_volatile_ctrl(struct v4l2_ctrl *ctrl); | ||
114 | static int ov10823_s_ctrl(struct v4l2_ctrl *ctrl); | ||
115 | |||
116 | static const struct v4l2_ctrl_ops ov10823_ctrl_ops = { | ||
117 | .g_volatile_ctrl = ov10823_g_volatile_ctrl, | ||
118 | .s_ctrl = ov10823_s_ctrl, | ||
119 | }; | ||
120 | |||
121 | static struct v4l2_ctrl_config ctrl_config_list[] = { | ||
122 | /* Do not change the name field for the controls! */ | ||
123 | { | ||
124 | .ops = &ov10823_ctrl_ops, | ||
125 | .id = V4L2_CID_GAIN, | ||
126 | .name = "Gain", | ||
127 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
128 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
129 | .min = OV10823_MIN_GAIN, | ||
130 | .max = OV10823_MAX_GAIN, | ||
131 | .def = OV10823_DEFAULT_GAIN, | ||
132 | .step = 1, | ||
133 | }, | ||
134 | { | ||
135 | .ops = &ov10823_ctrl_ops, | ||
136 | .id = V4L2_CID_FRAME_LENGTH, | ||
137 | .name = "Frame Length", | ||
138 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
139 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
140 | .min = OV10823_MIN_FRAME_LENGTH, | ||
141 | .max = OV10823_MAX_FRAME_LENGTH, | ||
142 | .def = OV10823_DEFAULT_FRAME_LENGTH, | ||
143 | .step = 1, | ||
144 | }, | ||
145 | { | ||
146 | .ops = &ov10823_ctrl_ops, | ||
147 | .id = V4L2_CID_COARSE_TIME, | ||
148 | .name = "Coarse Time", | ||
149 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
150 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
151 | .min = OV10823_MIN_EXPOSURE_COARSE, | ||
152 | .max = OV10823_MAX_EXPOSURE_COARSE, | ||
153 | .def = OV10823_DEFAULT_EXPOSURE_COARSE, | ||
154 | .step = 1, | ||
155 | }, | ||
156 | { | ||
157 | .ops = &ov10823_ctrl_ops, | ||
158 | .id = V4L2_CID_GROUP_HOLD, | ||
159 | .name = "Group Hold", | ||
160 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, | ||
161 | .min = 0, | ||
162 | .max = ARRAY_SIZE(switch_ctrl_qmenu) - 1, | ||
163 | .menu_skip_mask = 0, | ||
164 | .def = 0, | ||
165 | .qmenu_int = switch_ctrl_qmenu, | ||
166 | }, | ||
167 | { | ||
168 | .ops = &ov10823_ctrl_ops, | ||
169 | .id = V4L2_CID_HDR_EN, | ||
170 | .name = "HDR enable", | ||
171 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, | ||
172 | .min = 0, | ||
173 | .max = ARRAY_SIZE(switch_ctrl_qmenu) - 1, | ||
174 | .menu_skip_mask = 0, | ||
175 | .def = 0, | ||
176 | .qmenu_int = switch_ctrl_qmenu, | ||
177 | }, | ||
178 | { | ||
179 | .ops = &ov10823_ctrl_ops, | ||
180 | .id = V4L2_CID_OTP_DATA, | ||
181 | .name = "OTP Data", | ||
182 | .type = V4L2_CTRL_TYPE_STRING, | ||
183 | .flags = V4L2_CTRL_FLAG_READ_ONLY, | ||
184 | .min = 0, | ||
185 | .max = OV10823_OTP_STR_SIZE, | ||
186 | .step = 2, | ||
187 | }, | ||
188 | { | ||
189 | .ops = &ov10823_ctrl_ops, | ||
190 | .id = V4L2_CID_FUSE_ID, | ||
191 | .name = "Fuse ID", | ||
192 | .type = V4L2_CTRL_TYPE_STRING, | ||
193 | .flags = V4L2_CTRL_FLAG_READ_ONLY, | ||
194 | .min = 0, | ||
195 | .max = OV10823_FUSE_ID_STR_SIZE, | ||
196 | .step = 2, | ||
197 | }, | ||
198 | }; | ||
199 | |||
200 | static inline void ov10823_get_frame_length_regs(ov10823_reg *regs, | ||
201 | u16 frame_length, int fsync) | ||
202 | { | ||
203 | /* 2 registers for FL, i.e., 2-byte FL */ | ||
204 | regs->addr = 0x380e; | ||
205 | regs->val = (frame_length >> 8) & 0xff; | ||
206 | (regs + 1)->addr = 0x380f; | ||
207 | (regs + 1)->val = (frame_length) & 0xff; | ||
208 | if (fsync == OV10823_FSYNC_SLAVE) { | ||
209 | (regs + 2)->addr = 0x3826; | ||
210 | (regs + 2)->val = ((frame_length - 4) >> 8) & 0xff; | ||
211 | (regs + 3)->addr = 0x3827; | ||
212 | (regs + 3)->val = (frame_length - 4) & 0xff; | ||
213 | } else { | ||
214 | (regs + 2)->addr = 0x3830; | ||
215 | (regs + 2)->val = ((frame_length - 4) >> 8) & 0xff; | ||
216 | (regs + 3)->addr = 0x3831; | ||
217 | (regs + 3)->val = (frame_length - 4) & 0xff; | ||
218 | } | ||
219 | (regs + 4)->addr = OV10823_TABLE_END; | ||
220 | (regs + 4)->val = 0; | ||
221 | } | ||
222 | |||
223 | static inline void ov10823_get_coarse_time_regs(ov10823_reg *regs, | ||
224 | u16 coarse_time) | ||
225 | { | ||
226 | /* 3 registers for CT, i.e., 3-byte CT */ | ||
227 | regs->addr = 0x3500; | ||
228 | regs->val = (coarse_time >> 12) & 0xff; | ||
229 | (regs + 1)->addr = 0x3501; | ||
230 | (regs + 1)->val = (coarse_time >> 4) & 0xff; | ||
231 | (regs + 2)->addr = 0x3502; | ||
232 | (regs + 2)->val = (coarse_time & 0xf) << 4; | ||
233 | (regs + 3)->addr = OV10823_TABLE_END; | ||
234 | (regs + 3)->val = 0; | ||
235 | } | ||
236 | |||
237 | static inline void ov10823_get_gain_reg(ov10823_reg *regs, | ||
238 | u16 gain) | ||
239 | { | ||
240 | /* 2 register for gain, i.e., 2-byte gain */ | ||
241 | regs->addr = 0x350a; | ||
242 | regs->val = (gain >> 8) & 0xff; | ||
243 | (regs + 1)->addr = 0x350b; | ||
244 | (regs + 1)->val = (gain) & 0xff; | ||
245 | (regs + 2)->addr = OV10823_TABLE_END; | ||
246 | (regs + 2)->val = 0; | ||
247 | } | ||
248 | |||
249 | static inline int ov10823_read_reg(struct camera_common_data *s_data, | ||
250 | u16 addr, u8 *val) | ||
251 | { | ||
252 | struct ov10823 *priv = (struct ov10823 *)s_data->priv; | ||
253 | unsigned int temp_val; | ||
254 | int err; | ||
255 | |||
256 | err = regmap_read(priv->regmap, addr, &temp_val); | ||
257 | if (!err) | ||
258 | *val = temp_val; | ||
259 | |||
260 | return err; | ||
261 | } | ||
262 | |||
263 | static int ov10823_write_reg(struct camera_common_data *s_data, | ||
264 | u16 addr, u8 val) | ||
265 | { | ||
266 | int err; | ||
267 | struct ov10823 *priv = (struct ov10823 *)s_data->priv; | ||
268 | |||
269 | err = regmap_write(priv->regmap, addr, val); | ||
270 | if (err) | ||
271 | pr_err("%s:i2c write failed, %x = %x\n", | ||
272 | __func__, addr, val); | ||
273 | |||
274 | return err; | ||
275 | } | ||
276 | |||
277 | static int ov10823_write_table(struct ov10823 *priv, | ||
278 | const ov10823_reg table[]) | ||
279 | { | ||
280 | return regmap_util_write_table_8(priv->regmap, | ||
281 | table, | ||
282 | NULL, 0, | ||
283 | OV10823_TABLE_WAIT_MS, | ||
284 | OV10823_TABLE_END); | ||
285 | } | ||
286 | |||
287 | static int ov10823_power_on(struct camera_common_data *s_data) | ||
288 | { | ||
289 | int err = 0; | ||
290 | struct ov10823 *priv = (struct ov10823 *)s_data->priv; | ||
291 | struct camera_common_power_rail *pw = &priv->power; | ||
292 | |||
293 | dev_dbg(&priv->i2c_client->dev, "%s: power on\n", __func__); | ||
294 | |||
295 | if (priv->pdata->power_on) { | ||
296 | err = priv->pdata->power_on(pw); | ||
297 | if (err) | ||
298 | pr_err("%s failed.\n", __func__); | ||
299 | else | ||
300 | pw->state = SWITCH_ON; | ||
301 | return err; | ||
302 | } | ||
303 | |||
304 | usleep_range(5350, 5360); | ||
305 | pw->state = SWITCH_ON; | ||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static int ov10823_power_off(struct camera_common_data *s_data) | ||
310 | { | ||
311 | int err = 0; | ||
312 | struct ov10823 *priv = (struct ov10823 *)s_data->priv; | ||
313 | struct camera_common_power_rail *pw = &priv->power; | ||
314 | |||
315 | dev_dbg(&priv->i2c_client->dev, "%s: power off\n", __func__); | ||
316 | ov10823_write_table(priv, mode_table[OV10823_MODE_STOP_STREAM]); | ||
317 | |||
318 | if (priv->pdata->power_off) { | ||
319 | err = priv->pdata->power_off(pw); | ||
320 | if (err) | ||
321 | pr_err("%s failed.\n", __func__); | ||
322 | else | ||
323 | goto power_off_done; | ||
324 | } | ||
325 | |||
326 | return err; | ||
327 | |||
328 | power_off_done: | ||
329 | pw->state = SWITCH_OFF; | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | static int ov10823_power_put(struct ov10823 *priv) | ||
334 | { | ||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | static int ov10823_power_get(struct ov10823 *priv) | ||
339 | { | ||
340 | struct camera_common_power_rail *pw = &priv->power; | ||
341 | const char *mclk_name; | ||
342 | int err = 0; | ||
343 | |||
344 | mclk_name = priv->pdata->mclk_name ? | ||
345 | priv->pdata->mclk_name : "cam_mclk1"; | ||
346 | pw->mclk = devm_clk_get(&priv->i2c_client->dev, mclk_name); | ||
347 | if (IS_ERR(pw->mclk)) { | ||
348 | dev_err(&priv->i2c_client->dev, | ||
349 | "unable to get clock %s\n", mclk_name); | ||
350 | return PTR_ERR(pw->mclk); | ||
351 | } | ||
352 | |||
353 | pw->state = SWITCH_OFF; | ||
354 | return err; | ||
355 | } | ||
356 | |||
357 | static int ov10823_verify_chip_id(struct ov10823 *priv) | ||
358 | { | ||
359 | struct i2c_client *client = priv->i2c_client; | ||
360 | struct camera_common_data *s_data = priv->s_data; | ||
361 | u8 chip_id_hi, chip_id_lo; | ||
362 | u16 chip_id; | ||
363 | int err; | ||
364 | |||
365 | err = camera_common_s_power(priv->subdev, true); | ||
366 | if (err) | ||
367 | return -ENODEV; | ||
368 | |||
369 | err = ov10823_read_reg(s_data, OV10823_SC_CHIP_ID_HIGH_ADDR, | ||
370 | &chip_id_hi); | ||
371 | if (err) { | ||
372 | dev_err(&client->dev, "Failed to read chip ID\n"); | ||
373 | return err; | ||
374 | } | ||
375 | err = ov10823_read_reg(s_data, OV10823_SC_CHIP_ID_LOW_ADDR, | ||
376 | &chip_id_lo); | ||
377 | if (err) { | ||
378 | dev_err(&client->dev, "Failed to read chip ID\n"); | ||
379 | return err; | ||
380 | } | ||
381 | |||
382 | chip_id = (chip_id_hi << 8) | chip_id_lo; | ||
383 | if (chip_id != 0xA820) { | ||
384 | dev_err(&client->dev, "Read unknown chip ID 0x%04x\n", chip_id); | ||
385 | return -EINVAL; | ||
386 | } | ||
387 | |||
388 | err = camera_common_s_power(priv->subdev, false); | ||
389 | if (err) | ||
390 | return -ENODEV; | ||
391 | |||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | static int ov10823_set_gain(struct ov10823 *priv, s32 val); | ||
396 | static int ov10823_set_frame_length(struct ov10823 *priv, s32 val); | ||
397 | static int ov10823_set_coarse_time(struct ov10823 *priv, s32 val); | ||
398 | |||
399 | static int ov10823_s_stream(struct v4l2_subdev *sd, int enable) | ||
400 | { | ||
401 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
402 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
403 | struct ov10823 *priv = (struct ov10823 *)s_data->priv; | ||
404 | struct v4l2_control control; | ||
405 | int err; | ||
406 | |||
407 | if (!enable) { | ||
408 | dev_dbg(&client->dev, "%s: stream off\n", __func__); | ||
409 | return ov10823_write_table(priv, | ||
410 | mode_table[OV10823_MODE_STOP_STREAM]); | ||
411 | } | ||
412 | |||
413 | dev_dbg(&client->dev, "%s: write mode table %d\n", | ||
414 | __func__, s_data->mode); | ||
415 | err = ov10823_write_table(priv, mode_table[s_data->mode]); | ||
416 | |||
417 | if (fsync_table[priv->fsync]) { | ||
418 | dev_dbg(&client->dev, "%s: write fsync table %d\n", __func__, | ||
419 | priv->fsync); | ||
420 | err = ov10823_write_table(priv, fsync_table[priv->fsync]); | ||
421 | if (err) | ||
422 | goto exit; | ||
423 | } | ||
424 | |||
425 | if (s_data->override_enable) { | ||
426 | /* write list of override regs for the asking frame length, */ | ||
427 | /* coarse integration time, and gain. Failures to write */ | ||
428 | /* overrides are non-fatal. */ | ||
429 | control.id = V4L2_CID_GAIN; | ||
430 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
431 | err |= ov10823_set_gain(priv, control.value); | ||
432 | if (err) | ||
433 | dev_dbg(&client->dev, | ||
434 | "%s: error gain override\n", __func__); | ||
435 | |||
436 | control.id = V4L2_CID_FRAME_LENGTH; | ||
437 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
438 | err |= ov10823_set_frame_length(priv, control.value); | ||
439 | if (err) | ||
440 | dev_dbg(&client->dev, | ||
441 | "%s: error frame length override\n", __func__); | ||
442 | |||
443 | control.id = V4L2_CID_COARSE_TIME; | ||
444 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
445 | err |= ov10823_set_coarse_time(priv, control.value); | ||
446 | if (err) | ||
447 | dev_dbg(&client->dev, | ||
448 | "%s: error coarse time override\n", __func__); | ||
449 | } | ||
450 | |||
451 | dev_dbg(&client->dev, "%s: stream on\n", __func__); | ||
452 | err = ov10823_write_table(priv, mode_table[OV10823_MODE_START_STREAM]); | ||
453 | if (err) | ||
454 | goto exit; | ||
455 | |||
456 | /* | ||
457 | * If the sensor is in fsync slave mode, and is in the middle of | ||
458 | * sending a frame when it gets a strobe on the fsin pin, it may | ||
459 | * prematurely end the frame, resulting in a short frame on our | ||
460 | * camera host. So, after starting streaming, we assume fsync | ||
461 | * master has already been told to start streaming, and we wait some | ||
462 | * amount of time in order to skip the possible short frame. The | ||
463 | * length of time to wait should be at least our sample period. | ||
464 | * Assume worse case of 30fps (33.3ms), and add a bit more. | ||
465 | */ | ||
466 | if (priv->fsync == OV10823_FSYNC_SLAVE) | ||
467 | msleep(40); | ||
468 | |||
469 | return 0; | ||
470 | exit: | ||
471 | dev_dbg(&client->dev, "%s: error setting stream\n", __func__); | ||
472 | return err; | ||
473 | } | ||
474 | |||
475 | static int ov10823_g_input_status(struct v4l2_subdev *sd, u32 *status) | ||
476 | { | ||
477 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
478 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
479 | struct ov10823 *priv = (struct ov10823 *)s_data->priv; | ||
480 | struct camera_common_power_rail *pw = &priv->power; | ||
481 | |||
482 | *status = pw->state == SWITCH_ON; | ||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | static struct v4l2_subdev_video_ops ov10823_subdev_video_ops = { | ||
487 | .s_stream = ov10823_s_stream, | ||
488 | .g_mbus_config = camera_common_g_mbus_config, | ||
489 | .g_input_status = ov10823_g_input_status, | ||
490 | }; | ||
491 | |||
492 | static struct v4l2_subdev_core_ops ov10823_subdev_core_ops = { | ||
493 | .s_power = camera_common_s_power, | ||
494 | }; | ||
495 | |||
496 | static int ov10823_get_fmt(struct v4l2_subdev *sd, | ||
497 | struct v4l2_subdev_pad_config *cfg, | ||
498 | struct v4l2_subdev_format *format) | ||
499 | { | ||
500 | return camera_common_g_fmt(sd, &format->format); | ||
501 | } | ||
502 | |||
503 | static int ov10823_set_fmt(struct v4l2_subdev *sd, | ||
504 | struct v4l2_subdev_pad_config *cfg, | ||
505 | struct v4l2_subdev_format *format) | ||
506 | { | ||
507 | int ret; | ||
508 | |||
509 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) | ||
510 | ret = camera_common_try_fmt(sd, &format->format); | ||
511 | else | ||
512 | ret = camera_common_s_fmt(sd, &format->format); | ||
513 | |||
514 | return ret; | ||
515 | } | ||
516 | |||
517 | static struct v4l2_subdev_pad_ops ov10823_subdev_pad_ops = { | ||
518 | .set_fmt = ov10823_set_fmt, | ||
519 | .get_fmt = ov10823_get_fmt, | ||
520 | .enum_mbus_code = camera_common_enum_mbus_code, | ||
521 | .enum_frame_size = camera_common_enum_framesizes, | ||
522 | .enum_frame_interval = camera_common_enum_frameintervals, | ||
523 | }; | ||
524 | |||
525 | static struct v4l2_subdev_ops ov10823_subdev_ops = { | ||
526 | .core = &ov10823_subdev_core_ops, | ||
527 | .video = &ov10823_subdev_video_ops, | ||
528 | .pad = &ov10823_subdev_pad_ops, | ||
529 | }; | ||
530 | |||
531 | static struct of_device_id ov10823_of_match[] = { | ||
532 | { .compatible = "nvidia,ov10823", }, | ||
533 | { }, | ||
534 | }; | ||
535 | |||
536 | static struct camera_common_sensor_ops ov10823_common_ops = { | ||
537 | .power_on = ov10823_power_on, | ||
538 | .power_off = ov10823_power_off, | ||
539 | .write_reg = ov10823_write_reg, | ||
540 | .read_reg = ov10823_read_reg, | ||
541 | }; | ||
542 | |||
543 | static int ov10823_set_group_hold(struct ov10823 *priv) | ||
544 | { | ||
545 | int err; | ||
546 | int gh_prev = switch_ctrl_qmenu[priv->group_hold_prev]; | ||
547 | |||
548 | if (priv->group_hold_en == true && gh_prev == SWITCH_OFF) { | ||
549 | /* group hold start */ | ||
550 | err = ov10823_write_reg(priv->s_data, | ||
551 | OV10823_GROUP_HOLD_ADDR, 0x00); | ||
552 | if (err) | ||
553 | goto fail; | ||
554 | priv->group_hold_prev = 1; | ||
555 | } else if (priv->group_hold_en == false && gh_prev == SWITCH_ON) { | ||
556 | /* group hold end */ | ||
557 | err = ov10823_write_reg(priv->s_data, | ||
558 | OV10823_GROUP_HOLD_ADDR, 0x10); | ||
559 | /* quick launch */ | ||
560 | err |= ov10823_write_reg(priv->s_data, | ||
561 | OV10823_GROUP_HOLD_ADDR, 0xA0); | ||
562 | if (err) | ||
563 | goto fail; | ||
564 | priv->group_hold_prev = 0; | ||
565 | } | ||
566 | |||
567 | return 0; | ||
568 | |||
569 | fail: | ||
570 | dev_dbg(&priv->i2c_client->dev, | ||
571 | "%s: Group hold control error\n", __func__); | ||
572 | return err; | ||
573 | } | ||
574 | |||
575 | static int ov10823_set_gain(struct ov10823 *priv, s32 val) | ||
576 | { | ||
577 | ov10823_reg reg_list[3]; | ||
578 | int err; | ||
579 | u16 gain; | ||
580 | |||
581 | /* max_gain 15.5x ---> 0x350A=0x00, 0x350B=0xF8 */ | ||
582 | /* min_gain 1.0x ---> 0x350A=0x00, 0x350B=0x10 */ | ||
583 | /* translate value */ | ||
584 | gain = ov10823_to_gain((u32)val, OV10823_GAIN_SHIFT); | ||
585 | |||
586 | dev_dbg(&priv->i2c_client->dev, | ||
587 | "%s: gain: %d\n", __func__, gain); | ||
588 | |||
589 | ov10823_get_gain_reg(reg_list, gain); | ||
590 | ov10823_set_group_hold(priv); | ||
591 | err = ov10823_write_table(priv, reg_list); | ||
592 | if (err) | ||
593 | goto fail; | ||
594 | |||
595 | return 0; | ||
596 | |||
597 | fail: | ||
598 | dev_dbg(&priv->i2c_client->dev, | ||
599 | "%s: GAIN control error\n", __func__); | ||
600 | return err; | ||
601 | } | ||
602 | |||
603 | static int ov10823_set_frame_length(struct ov10823 *priv, s32 val) | ||
604 | { | ||
605 | ov10823_reg reg_list[5]; | ||
606 | int err; | ||
607 | u16 frame_length; | ||
608 | |||
609 | /* | ||
610 | * This is a workaround for nvbug 1865041, where setting the VTS | ||
611 | * timing registers when the sensor is set up for fsync master or | ||
612 | * slave leads to streaming instability. | ||
613 | */ | ||
614 | if (priv->fsync != OV10823_FSYNC_NONE) | ||
615 | return 0; | ||
616 | |||
617 | frame_length = (u16)val; | ||
618 | |||
619 | dev_dbg(&priv->i2c_client->dev, | ||
620 | "%s: frame_length: %d\n", __func__, frame_length); | ||
621 | |||
622 | ov10823_get_frame_length_regs(reg_list, frame_length, priv->fsync); | ||
623 | ov10823_set_group_hold(priv); | ||
624 | err = ov10823_write_table(priv, reg_list); | ||
625 | if (err) | ||
626 | goto fail; | ||
627 | |||
628 | return 0; | ||
629 | |||
630 | fail: | ||
631 | dev_dbg(&priv->i2c_client->dev, | ||
632 | "%s: FRAME_LENGTH control error\n", __func__); | ||
633 | return err; | ||
634 | } | ||
635 | |||
636 | static int ov10823_set_coarse_time(struct ov10823 *priv, s32 val) | ||
637 | { | ||
638 | ov10823_reg reg_list[4]; | ||
639 | int err; | ||
640 | u16 coarse_time; | ||
641 | |||
642 | coarse_time = (u16)val; | ||
643 | |||
644 | dev_dbg(&priv->i2c_client->dev, | ||
645 | "%s: coarse_time: %d\n", __func__, coarse_time); | ||
646 | |||
647 | ov10823_get_coarse_time_regs(reg_list, coarse_time); | ||
648 | ov10823_set_group_hold(priv); | ||
649 | err = ov10823_write_table(priv, reg_list); | ||
650 | if (err) | ||
651 | goto fail; | ||
652 | |||
653 | return 0; | ||
654 | |||
655 | fail: | ||
656 | dev_dbg(&priv->i2c_client->dev, | ||
657 | "%s: COARSE_TIME control error\n", __func__); | ||
658 | return err; | ||
659 | } | ||
660 | |||
661 | static int ov10823_read_otp(struct ov10823 *priv, u8 *buf, | ||
662 | u16 addr, int size) | ||
663 | { | ||
664 | int err; | ||
665 | |||
666 | err = ov10823_write_reg(priv->s_data, OV10823_ISP_CTRL_ADDR, 0x00); | ||
667 | if (err) | ||
668 | return err; | ||
669 | /* Start streaming before write or read */ | ||
670 | err = ov10823_write_reg(priv->s_data, 0x0100, 0x01); | ||
671 | if (err) | ||
672 | return err; | ||
673 | msleep(20); | ||
674 | |||
675 | /* By default otp loading works in auto mode, but we can switch to */ | ||
676 | /* manual mode through OV10823_OTP_MODE_CTRL_ADDR[6] and the start */ | ||
677 | /* addr and end addr of manual mode can be configured by registers */ | ||
678 | /* accordingly */ | ||
679 | |||
680 | /* Loading enable */ | ||
681 | /* 1: manual mode */ | ||
682 | /* 0: auto mode */ | ||
683 | err = ov10823_write_reg(priv->s_data, OV10823_OTP_LOAD_CTRL_ADDR, 0x01); | ||
684 | if (err) | ||
685 | return err; | ||
686 | |||
687 | msleep(20); | ||
688 | err = regmap_bulk_read(priv->regmap, addr, buf, size); | ||
689 | if (err) | ||
690 | return err; | ||
691 | |||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | static int ov10823_otp_setup(struct ov10823 *priv) | ||
696 | { | ||
697 | int err; | ||
698 | int i; | ||
699 | struct v4l2_ctrl *ctrl; | ||
700 | u8 otp_buf[OV10823_OTP_SIZE]; | ||
701 | |||
702 | err = camera_common_s_power(priv->subdev, true); | ||
703 | if (err) | ||
704 | return -ENODEV; | ||
705 | |||
706 | ov10823_read_otp(priv, &otp_buf[0], | ||
707 | OV10823_OTP_SRAM_START_ADDR, | ||
708 | OV10823_OTP_SIZE); | ||
709 | |||
710 | ctrl = v4l2_ctrl_find(&priv->ctrl_handler, V4L2_CID_OTP_DATA); | ||
711 | if (!ctrl) { | ||
712 | dev_err(&priv->i2c_client->dev, | ||
713 | "could not find device ctrl.\n"); | ||
714 | return -EINVAL; | ||
715 | } | ||
716 | |||
717 | for (i = 0; i < OV10823_OTP_SIZE; i++) | ||
718 | sprintf(&ctrl->p_new.p_char[i*2], "%02x", | ||
719 | otp_buf[i]); | ||
720 | ctrl->p_cur.p_char = ctrl->p_new.p_char; | ||
721 | |||
722 | err = camera_common_s_power(priv->subdev, false); | ||
723 | if (err) | ||
724 | return -ENODEV; | ||
725 | |||
726 | return 0; | ||
727 | } | ||
728 | |||
729 | static int ov10823_fuse_id_setup(struct ov10823 *priv) | ||
730 | { | ||
731 | int err; | ||
732 | int i; | ||
733 | struct v4l2_ctrl *ctrl; | ||
734 | u8 fuse_id[OV10823_FUSE_ID_SIZE]; | ||
735 | |||
736 | err = camera_common_s_power(priv->subdev, true); | ||
737 | if (err) | ||
738 | return -ENODEV; | ||
739 | |||
740 | ov10823_read_otp(priv, &fuse_id[0], | ||
741 | OV10823_FUSE_ID_OTP_BASE_ADDR, | ||
742 | OV10823_FUSE_ID_SIZE); | ||
743 | |||
744 | ctrl = v4l2_ctrl_find(&priv->ctrl_handler, V4L2_CID_FUSE_ID); | ||
745 | if (!ctrl) { | ||
746 | dev_err(&priv->i2c_client->dev, | ||
747 | "could not find device ctrl.\n"); | ||
748 | return -EINVAL; | ||
749 | } | ||
750 | |||
751 | for (i = 0; i < OV10823_FUSE_ID_SIZE; i++) | ||
752 | sprintf(&ctrl->p_new.p_char[i*2], "%02x", | ||
753 | fuse_id[i]); | ||
754 | ctrl->p_cur.p_char = ctrl->p_new.p_char; | ||
755 | |||
756 | err = camera_common_s_power(priv->subdev, false); | ||
757 | if (err) | ||
758 | return -ENODEV; | ||
759 | |||
760 | return 0; | ||
761 | } | ||
762 | |||
763 | static int ov10823_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | ||
764 | { | ||
765 | struct ov10823 *priv = | ||
766 | container_of(ctrl->handler, struct ov10823, ctrl_handler); | ||
767 | int err = 0; | ||
768 | |||
769 | if (priv->power.state == SWITCH_OFF) | ||
770 | return 0; | ||
771 | |||
772 | switch (ctrl->id) { | ||
773 | default: | ||
774 | pr_err("%s: unknown ctrl id.\n", __func__); | ||
775 | return -EINVAL; | ||
776 | } | ||
777 | |||
778 | return err; | ||
779 | } | ||
780 | |||
781 | static int ov10823_s_ctrl(struct v4l2_ctrl *ctrl) | ||
782 | { | ||
783 | struct ov10823 *priv = | ||
784 | container_of(ctrl->handler, struct ov10823, ctrl_handler); | ||
785 | int err = 0; | ||
786 | |||
787 | if (priv->power.state == SWITCH_OFF) | ||
788 | return 0; | ||
789 | |||
790 | switch (ctrl->id) { | ||
791 | case V4L2_CID_GAIN: | ||
792 | err = ov10823_set_gain(priv, ctrl->val); | ||
793 | break; | ||
794 | case V4L2_CID_FRAME_LENGTH: | ||
795 | err = ov10823_set_frame_length(priv, ctrl->val); | ||
796 | break; | ||
797 | case V4L2_CID_COARSE_TIME: | ||
798 | err = ov10823_set_coarse_time(priv, ctrl->val); | ||
799 | break; | ||
800 | case V4L2_CID_GROUP_HOLD: | ||
801 | if (switch_ctrl_qmenu[ctrl->val] == SWITCH_ON) { | ||
802 | priv->group_hold_en = true; | ||
803 | } else { | ||
804 | priv->group_hold_en = false; | ||
805 | err = ov10823_set_group_hold(priv); | ||
806 | } | ||
807 | break; | ||
808 | case V4L2_CID_HDR_EN: | ||
809 | break; | ||
810 | default: | ||
811 | pr_err("%s: unknown ctrl id.\n", __func__); | ||
812 | return -EINVAL; | ||
813 | } | ||
814 | |||
815 | return err; | ||
816 | } | ||
817 | |||
818 | static int ov10823_ctrls_init(struct ov10823 *priv) | ||
819 | { | ||
820 | struct i2c_client *client = priv->i2c_client; | ||
821 | struct v4l2_ctrl *ctrl; | ||
822 | int num_ctrls; | ||
823 | int err; | ||
824 | int i; | ||
825 | |||
826 | dev_dbg(&client->dev, "%s++\n", __func__); | ||
827 | |||
828 | num_ctrls = ARRAY_SIZE(ctrl_config_list); | ||
829 | v4l2_ctrl_handler_init(&priv->ctrl_handler, num_ctrls); | ||
830 | |||
831 | for (i = 0; i < num_ctrls; i++) { | ||
832 | ctrl = v4l2_ctrl_new_custom(&priv->ctrl_handler, | ||
833 | &ctrl_config_list[i], NULL); | ||
834 | if (ctrl == NULL) { | ||
835 | dev_err(&client->dev, "Failed to init %s ctrl\n", | ||
836 | ctrl_config_list[i].name); | ||
837 | continue; | ||
838 | } | ||
839 | |||
840 | if (ctrl_config_list[i].type == V4L2_CTRL_TYPE_STRING && | ||
841 | ctrl_config_list[i].flags & V4L2_CTRL_FLAG_READ_ONLY) { | ||
842 | ctrl->p_new.p_char = devm_kzalloc(&client->dev, | ||
843 | ctrl_config_list[i].max + 1, GFP_KERNEL); | ||
844 | } | ||
845 | priv->ctrls[i] = ctrl; | ||
846 | } | ||
847 | |||
848 | priv->num_ctrls = num_ctrls; | ||
849 | priv->subdev->ctrl_handler = &priv->ctrl_handler; | ||
850 | if (priv->ctrl_handler.error) { | ||
851 | dev_err(&client->dev, "Error %d adding controls\n", | ||
852 | priv->ctrl_handler.error); | ||
853 | err = priv->ctrl_handler.error; | ||
854 | goto error; | ||
855 | } | ||
856 | |||
857 | err = v4l2_ctrl_handler_setup(&priv->ctrl_handler); | ||
858 | if (err) { | ||
859 | dev_err(&client->dev, | ||
860 | "Error %d setting default controls\n", err); | ||
861 | goto error; | ||
862 | } | ||
863 | |||
864 | return 0; | ||
865 | |||
866 | error: | ||
867 | v4l2_ctrl_handler_free(&priv->ctrl_handler); | ||
868 | return err; | ||
869 | } | ||
870 | |||
871 | MODULE_DEVICE_TABLE(of, ov10823_of_match); | ||
872 | |||
873 | static int ov10823_parse_dt(struct i2c_client *client, struct ov10823 *priv) | ||
874 | { | ||
875 | struct device_node *np = client->dev.of_node; | ||
876 | const char *fsync_str; | ||
877 | int gpio; | ||
878 | int err; | ||
879 | |||
880 | err = of_property_read_string(np, "mclk", &priv->pdata->mclk_name); | ||
881 | if (err) { | ||
882 | dev_err(&client->dev, "mclk not in DT\n"); | ||
883 | return -EINVAL; | ||
884 | } | ||
885 | |||
886 | err = of_property_read_string(np, "fsync", &fsync_str); | ||
887 | if (!err && fsync_str && (strcmp(fsync_str, "master") == 0)) | ||
888 | priv->fsync = OV10823_FSYNC_MASTER; | ||
889 | else if (!err && fsync_str && (strcmp(fsync_str, "slave") == 0)) | ||
890 | priv->fsync = OV10823_FSYNC_SLAVE; | ||
891 | else | ||
892 | priv->fsync = OV10823_FSYNC_NONE; | ||
893 | |||
894 | gpio = of_get_named_gpio(np, "pwdn-gpios", 0); | ||
895 | if (gpio < 0) { | ||
896 | dev_dbg(&client->dev, "pwdn gpios not in DT\n"); | ||
897 | gpio = 0; | ||
898 | } | ||
899 | priv->pdata->pwdn_gpio = (unsigned int)gpio; | ||
900 | |||
901 | gpio = of_get_named_gpio(np, "reset-gpios", 0); | ||
902 | if (gpio < 0) { | ||
903 | dev_dbg(&client->dev, "reset gpios not in DT\n"); | ||
904 | gpio = 0; | ||
905 | } | ||
906 | priv->pdata->reset_gpio = (unsigned int)gpio; | ||
907 | |||
908 | priv->mcu_boot_gpio = | ||
909 | of_get_named_gpio(np, "mcu-boot-gpios", 0); | ||
910 | priv->mcu_reset_gpio = | ||
911 | of_get_named_gpio(np, "mcu-reset-gpios", 0); | ||
912 | |||
913 | priv->cam_sid_gpio = of_get_named_gpio(np, "cam-sid-gpios", 0); | ||
914 | |||
915 | return 0; | ||
916 | } | ||
917 | |||
918 | static int ov10823_i2c_addr_assign(struct ov10823 *priv, u8 i2c_addr) | ||
919 | { | ||
920 | struct i2c_msg msg; | ||
921 | unsigned char data[3]; | ||
922 | int err; | ||
923 | |||
924 | /* | ||
925 | * I wish i2c_check_addr_validity() was available. Oh well. | ||
926 | * 7-bit address, reject the general call address | ||
927 | */ | ||
928 | if ((i2c_addr == 0x00) || (i2c_addr > 0x7f)) | ||
929 | return -EINVAL; | ||
930 | |||
931 | /* | ||
932 | * It seems that the way SID works for the OV10823 I2C slave address is | ||
933 | * that: | ||
934 | * | ||
935 | * SID 0 = 0x20 | ||
936 | * SID 1 = 0x6c | ||
937 | * | ||
938 | * Address 0x20 is programmable via register 0x300c, and | ||
939 | * address 0x6c is programmable via register 0x3661. | ||
940 | * | ||
941 | * So, the scheme to assign addresses to an (almost) arbitrary | ||
942 | * number of sensors is to consider 0x20 to be the "off" address. | ||
943 | * Start each sensor with SID as 0 so that they appear to be off. | ||
944 | * | ||
945 | * Then, to assign an address to one sensor: | ||
946 | * | ||
947 | * 0. Set corresponding SID to 1 (now only that sensor responds | ||
948 | * to 0x6c). | ||
949 | * 1. Use 0x6C to program address 0x20 to the new address. | ||
950 | * 2. Set corresponding SID back to 0 (so it no longer responds | ||
951 | * to 0x6c, but instead responds to the new address). | ||
952 | */ | ||
953 | |||
954 | if (i2c_addr == OV10823_DEFAULT_I2C_ADDRESS_20) { | ||
955 | dev_info(&priv->i2c_client->dev, | ||
956 | "Using default I2C address 0x%02x\n", i2c_addr); | ||
957 | if (gpio_is_valid(priv->cam_sid_gpio)) { | ||
958 | gpio_set_value(priv->cam_sid_gpio, 0); | ||
959 | msleep_range(1); | ||
960 | } | ||
961 | return 0; | ||
962 | } else if (i2c_addr == OV10823_DEFAULT_I2C_ADDRESS_6C) { | ||
963 | dev_info(&priv->i2c_client->dev, | ||
964 | "Using default I2C address 0x%02x\n", i2c_addr); | ||
965 | if (gpio_is_valid(priv->cam_sid_gpio)) { | ||
966 | gpio_set_value(priv->cam_sid_gpio, 1); | ||
967 | msleep_range(1); | ||
968 | } | ||
969 | return 0; | ||
970 | } | ||
971 | |||
972 | /* | ||
973 | * From this point on, we are trying to program the programmable | ||
974 | * slave address. We necessarily need to have a cam-sid-gpio for this. | ||
975 | */ | ||
976 | if (!gpio_is_valid(priv->cam_sid_gpio)) { | ||
977 | dev_err(&priv->i2c_client->dev, | ||
978 | "Missing cam-sid-gpio, cannot program I2C address\n"); | ||
979 | return -EINVAL; | ||
980 | } | ||
981 | |||
982 | gpio_set_value(priv->cam_sid_gpio, 1); | ||
983 | msleep_range(1); | ||
984 | |||
985 | dev_info(&priv->i2c_client->dev, "Changing I2C address to 0x%02x\n", | ||
986 | i2c_addr); | ||
987 | |||
988 | /* | ||
989 | * Have to make the I2C message manually because we are using a | ||
990 | * different I2C slave address for this transaction, rather than | ||
991 | * the one in the device tree for this device. | ||
992 | */ | ||
993 | data[0] = (OV10823_SC_SCCB_ID_ADDR >> 8) & 0xff; | ||
994 | data[1] = OV10823_SC_SCCB_ID_ADDR & 0xff; | ||
995 | data[2] = ((i2c_addr) << 1) & 0xff; | ||
996 | /* | ||
997 | * Use the programmable default I2C slave address so that if we have | ||
998 | * multiple sensors of this same kind, when we change one sensor's | ||
999 | * address, the next sensor address change message won't go to that | ||
1000 | * same sensor. | ||
1001 | */ | ||
1002 | msg.addr = OV10823_DEFAULT_I2C_ADDRESS_6C; | ||
1003 | msg.flags = 0; | ||
1004 | msg.len = 3; | ||
1005 | msg.buf = data; | ||
1006 | |||
1007 | err = camera_common_s_power(priv->subdev, true); | ||
1008 | if (err) | ||
1009 | goto done; | ||
1010 | |||
1011 | if (i2c_transfer(priv->i2c_client->adapter, &msg, 1) != 1) | ||
1012 | err = -EIO; | ||
1013 | |||
1014 | camera_common_s_power(priv->subdev, false); | ||
1015 | |||
1016 | done: | ||
1017 | gpio_set_value(priv->cam_sid_gpio, 0); | ||
1018 | msleep_range(1); | ||
1019 | |||
1020 | return err; | ||
1021 | } | ||
1022 | |||
1023 | static int ov10823_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
1024 | { | ||
1025 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1026 | |||
1027 | dev_dbg(&client->dev, "%s:\n", __func__); | ||
1028 | |||
1029 | return 0; | ||
1030 | } | ||
1031 | |||
1032 | static const struct v4l2_subdev_internal_ops ov10823_subdev_internal_ops = { | ||
1033 | .open = ov10823_open, | ||
1034 | }; | ||
1035 | |||
1036 | static const struct media_entity_operations ov10823_media_ops = { | ||
1037 | .link_validate = v4l2_subdev_link_validate, | ||
1038 | }; | ||
1039 | |||
1040 | static int ov10823_probe(struct i2c_client *client, | ||
1041 | const struct i2c_device_id *id) | ||
1042 | { | ||
1043 | struct camera_common_data *common_data; | ||
1044 | struct ov10823 *priv; | ||
1045 | char dev_name[10]; | ||
1046 | int err; | ||
1047 | |||
1048 | pr_info("[OV10823]: probing v4l2 sensor.\n"); | ||
1049 | |||
1050 | common_data = devm_kzalloc(&client->dev, | ||
1051 | sizeof(struct camera_common_data), GFP_KERNEL); | ||
1052 | |||
1053 | priv = devm_kzalloc(&client->dev, | ||
1054 | sizeof(struct ov10823) + sizeof(struct v4l2_ctrl *) * | ||
1055 | ARRAY_SIZE(ctrl_config_list), | ||
1056 | GFP_KERNEL); | ||
1057 | if (!priv) { | ||
1058 | dev_err(&client->dev, "unable to allocate memory!\n"); | ||
1059 | return -ENOMEM; | ||
1060 | } | ||
1061 | |||
1062 | priv->regmap = devm_regmap_init_i2c(client, &sensor_regmap_config); | ||
1063 | if (IS_ERR(priv->regmap)) { | ||
1064 | dev_err(&client->dev, | ||
1065 | "regmap init failed: %ld\n", PTR_ERR(priv->regmap)); | ||
1066 | return -ENODEV; | ||
1067 | } | ||
1068 | |||
1069 | priv->pdata = devm_kzalloc(&client->dev, | ||
1070 | sizeof(struct camera_common_pdata), | ||
1071 | GFP_KERNEL); | ||
1072 | if (!priv->pdata) { | ||
1073 | dev_err(&client->dev, | ||
1074 | "unable to allocate camera_common_pdata\n"); | ||
1075 | return -ENOMEM; | ||
1076 | } | ||
1077 | |||
1078 | err = ov10823_parse_dt(client, priv); | ||
1079 | if (err) | ||
1080 | return err; | ||
1081 | |||
1082 | common_data->ops = &ov10823_common_ops; | ||
1083 | common_data->ctrl_handler = &priv->ctrl_handler; | ||
1084 | common_data->i2c_client = client; | ||
1085 | common_data->frmfmt = ov10823_frmfmt; | ||
1086 | common_data->colorfmt = camera_common_find_datafmt( | ||
1087 | OV10823_DEFAULT_DATAFMT); | ||
1088 | common_data->power = &priv->power; | ||
1089 | common_data->ctrls = priv->ctrls; | ||
1090 | common_data->priv = (void *)priv; | ||
1091 | common_data->numctrls = ARRAY_SIZE(ctrl_config_list); | ||
1092 | common_data->numfmts = ARRAY_SIZE(ov10823_frmfmt); | ||
1093 | common_data->def_mode = OV10823_DEFAULT_MODE; | ||
1094 | common_data->def_width = OV10823_DEFAULT_WIDTH; | ||
1095 | common_data->def_height = OV10823_DEFAULT_HEIGHT; | ||
1096 | common_data->def_clk_freq = OV10823_DEFAULT_CLK_FREQ; | ||
1097 | common_data->fmt_width = common_data->def_width; | ||
1098 | common_data->fmt_height = common_data->def_height; | ||
1099 | |||
1100 | priv->i2c_client = client; | ||
1101 | priv->s_data = common_data; | ||
1102 | priv->subdev = &common_data->subdev; | ||
1103 | priv->subdev->dev = &client->dev; | ||
1104 | priv->group_hold_prev = 0; | ||
1105 | |||
1106 | err = ov10823_power_get(priv); | ||
1107 | if (err) | ||
1108 | return err; | ||
1109 | |||
1110 | /* | ||
1111 | * If our device tree node is given MCU GPIOs, then we are expected to | ||
1112 | * reset the MCU. | ||
1113 | */ | ||
1114 | if (gpio_is_valid(priv->mcu_boot_gpio) && | ||
1115 | gpio_is_valid(priv->mcu_reset_gpio)) { | ||
1116 | dev_info(&client->dev, "Resetting MCU\n"); | ||
1117 | gpio_set_value(priv->mcu_boot_gpio, 0); | ||
1118 | gpio_set_value(priv->mcu_reset_gpio, 0); | ||
1119 | msleep_range(1); | ||
1120 | gpio_set_value(priv->mcu_reset_gpio, 1); | ||
1121 | } | ||
1122 | |||
1123 | err = camera_common_parse_ports(client, common_data); | ||
1124 | if (err) { | ||
1125 | dev_err(&client->dev, "Failed to find port info\n"); | ||
1126 | return err; | ||
1127 | } | ||
1128 | sprintf(dev_name, "ov10823_%c", common_data->csi_port + 'a'); | ||
1129 | dev_dbg(&client->dev, "%s: name %s\n", __func__, dev_name); | ||
1130 | camera_common_create_debugfs(common_data, dev_name); | ||
1131 | |||
1132 | v4l2_i2c_subdev_init(&common_data->subdev, client, | ||
1133 | &ov10823_subdev_ops); | ||
1134 | |||
1135 | err = ov10823_ctrls_init(priv); | ||
1136 | if (err) | ||
1137 | return err; | ||
1138 | |||
1139 | err = ov10823_i2c_addr_assign(priv, client->addr); | ||
1140 | if (err) | ||
1141 | return err; | ||
1142 | |||
1143 | err = ov10823_verify_chip_id(priv); | ||
1144 | if (err) | ||
1145 | return err; | ||
1146 | |||
1147 | err = ov10823_otp_setup(priv); | ||
1148 | if (err) { | ||
1149 | dev_err(&client->dev, | ||
1150 | "Error %d reading otp data\n", err); | ||
1151 | return err; | ||
1152 | } | ||
1153 | |||
1154 | err = ov10823_fuse_id_setup(priv); | ||
1155 | if (err) { | ||
1156 | dev_err(&client->dev, | ||
1157 | "Error %d reading fuse id data\n", err); | ||
1158 | return err; | ||
1159 | } | ||
1160 | |||
1161 | priv->subdev->internal_ops = &ov10823_subdev_internal_ops; | ||
1162 | priv->subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | | ||
1163 | V4L2_SUBDEV_FL_HAS_EVENTS; | ||
1164 | |||
1165 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
1166 | priv->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
1167 | priv->subdev->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; | ||
1168 | priv->subdev->entity.ops = &ov10823_media_ops; | ||
1169 | err = media_entity_init(&priv->subdev->entity, 1, &priv->pad, 0); | ||
1170 | if (err < 0) { | ||
1171 | dev_err(&client->dev, "unable to init media entity\n"); | ||
1172 | return err; | ||
1173 | } | ||
1174 | #endif | ||
1175 | |||
1176 | err = v4l2_async_register_subdev(priv->subdev); | ||
1177 | if (err) | ||
1178 | return err; | ||
1179 | |||
1180 | dev_info(&client->dev, "Detected OV10823 sensor\n"); | ||
1181 | |||
1182 | return 0; | ||
1183 | } | ||
1184 | |||
1185 | static int | ||
1186 | ov10823_remove(struct i2c_client *client) | ||
1187 | { | ||
1188 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
1189 | struct ov10823 *priv = (struct ov10823 *)s_data->priv; | ||
1190 | |||
1191 | v4l2_async_unregister_subdev(priv->subdev); | ||
1192 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
1193 | media_entity_cleanup(&priv->subdev->entity); | ||
1194 | #endif | ||
1195 | v4l2_ctrl_handler_free(&priv->ctrl_handler); | ||
1196 | ov10823_power_put(priv); | ||
1197 | camera_common_remove_debugfs(s_data); | ||
1198 | |||
1199 | return 0; | ||
1200 | } | ||
1201 | |||
1202 | static const struct i2c_device_id ov10823_id[] = { | ||
1203 | { "ov10823", 0 }, | ||
1204 | { } | ||
1205 | }; | ||
1206 | |||
1207 | MODULE_DEVICE_TABLE(i2c, ov10823_id); | ||
1208 | |||
1209 | static struct i2c_driver ov10823_i2c_driver = { | ||
1210 | .driver = { | ||
1211 | .name = "ov10823", | ||
1212 | .owner = THIS_MODULE, | ||
1213 | .of_match_table = of_match_ptr(ov10823_of_match), | ||
1214 | }, | ||
1215 | .probe = ov10823_probe, | ||
1216 | .remove = ov10823_remove, | ||
1217 | .id_table = ov10823_id, | ||
1218 | }; | ||
1219 | |||
1220 | module_i2c_driver(ov10823_i2c_driver); | ||
1221 | |||
1222 | MODULE_DESCRIPTION("SoC Camera driver for Omnivison OV10823"); | ||
1223 | MODULE_AUTHOR("NVIDIA Corporation"); | ||
1224 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/i2c/ov10823_mode_tbls.h b/drivers/media/i2c/ov10823_mode_tbls.h new file mode 100644 index 000000000..543097d31 --- /dev/null +++ b/drivers/media/i2c/ov10823_mode_tbls.h | |||
@@ -0,0 +1,1637 @@ | |||
1 | /* | ||
2 | * ov10823.c - ov10823 sensor driver | ||
3 | * | ||
4 | * Copyright (c) 2016-2017, NVIDIA CORPORATION, All Rights Reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <media/camera_common.h> | ||
20 | |||
21 | #ifndef __OV10823_I2C_TABLES__ | ||
22 | #define __OV10823_I2C_TABLES__ | ||
23 | |||
24 | #define OV10823_TABLE_WAIT_MS 0 | ||
25 | #define OV10823_TABLE_END 1 | ||
26 | #define OV10823_MAX_RETRIES 3 | ||
27 | #define OV10823_WAIT_MS 3 | ||
28 | #define OV10823_ADJUST_HS_PREPARE 1 | ||
29 | |||
30 | #define ov10823_reg struct reg_8 | ||
31 | |||
32 | static ov10823_reg ov10823_start[] = { | ||
33 | { 0x0100, 0x01 }, | ||
34 | {OV10823_TABLE_WAIT_MS, 66}, | ||
35 | { OV10823_TABLE_END, 0x00 } | ||
36 | }; | ||
37 | |||
38 | static ov10823_reg ov10823_stop[] = { | ||
39 | { 0x0100, 0x00 }, | ||
40 | { OV10823_TABLE_END, 0x00 } | ||
41 | }; | ||
42 | |||
43 | static ov10823_reg fsync_master[] = { | ||
44 | {0x3002, 0x88}, | ||
45 | {0x3009, 0x06}, | ||
46 | {0x3823, 0x00}, | ||
47 | |||
48 | {OV10823_TABLE_END, 0x00} | ||
49 | }; | ||
50 | |||
51 | static ov10823_reg fsync_slave[] = { | ||
52 | {0x3002, 0x80}, | ||
53 | {0x3009, 0x02}, | ||
54 | {0x3823, 0x30}, | ||
55 | |||
56 | {OV10823_TABLE_END, 0x00} | ||
57 | }; | ||
58 | |||
59 | #ifdef OV10823_UNUSED_MODES | ||
60 | static ov10823_reg mode_4336x2440_24MhzMCLK[] = { | ||
61 | |||
62 | /* PLL */ | ||
63 | {0x3080, 0x04}, | ||
64 | {0x3083, 0x00}, | ||
65 | {0x3084, 0x03}, | ||
66 | {0x308b, 0x05}, | ||
67 | {0x308d, 0xae}, | ||
68 | {0x308e, 0x00}, | ||
69 | {0x308f, 0x09}, | ||
70 | |||
71 | {0x3011, 0xd0}, | ||
72 | {0x3012, 0x41}, | ||
73 | {0x3031, 0x0c}, | ||
74 | {0x3032, 0xc0}, | ||
75 | {0x3503, 0x07}, | ||
76 | {0x3603, 0x04}, | ||
77 | {0x3641, 0x83}, | ||
78 | {0x3643, 0x02}, | ||
79 | {0x3645, 0x41}, | ||
80 | {0x3646, 0x83}, | ||
81 | {0x3648, 0x0d}, | ||
82 | {0x3649, 0x86}, | ||
83 | {0x3653, 0x37}, | ||
84 | {0x3658, 0x8b}, | ||
85 | {0x3659, 0x87}, | ||
86 | {0x365c, 0x5a}, | ||
87 | {0x3660, 0x82}, | ||
88 | {0x3705, 0x22}, | ||
89 | {0x3719, 0x0c}, | ||
90 | {0x371b, 0x00}, | ||
91 | {0x371c, 0x80}, | ||
92 | {0x371e, 0x00}, | ||
93 | {0x371f, 0x20}, | ||
94 | {0x3720, 0xa0}, | ||
95 | {0x3721, 0xf0}, | ||
96 | {0x3723, 0x78}, | ||
97 | {0x372a, 0x08}, | ||
98 | {0x372c, 0x11}, | ||
99 | {0x373c, 0x02}, | ||
100 | {0x3749, 0xd7}, | ||
101 | {0x374a, 0x8c}, | ||
102 | {0x3752, 0x80}, | ||
103 | {0x3821, 0x00}, | ||
104 | {0x382e, 0x04}, | ||
105 | {0x3901, 0x80}, | ||
106 | {0x3902, 0xc6}, | ||
107 | {0x4004, 0x00}, | ||
108 | {0x4005, 0x20}, | ||
109 | {0x400d, 0x10}, | ||
110 | {0x401b, 0x00}, | ||
111 | {0x401d, 0x00}, | ||
112 | {0x401f, 0x00}, | ||
113 | {0x4020, 0x01}, | ||
114 | {0x4022, 0x03}, | ||
115 | {0x4024, 0x0e}, | ||
116 | {0x4025, 0x10}, | ||
117 | {0x4026, 0x0f}, | ||
118 | {0x4027, 0x9f}, | ||
119 | {0x4028, 0x00}, | ||
120 | {0x4029, 0x04}, | ||
121 | {0x402d, 0x04}, | ||
122 | {0x402f, 0x08}, | ||
123 | {0x4602, 0x02}, | ||
124 | |||
125 | #if OV10823_ADJUST_HS_PREPARE | ||
126 | /* Bit[7] is hs_preparei_sel */ | ||
127 | {0x4800, 0x20}, | ||
128 | {0x4831, 0x6a}, | ||
129 | #endif | ||
130 | |||
131 | {0x4810, 0x00}, | ||
132 | {0x4811, 0x1f}, | ||
133 | {0x4819, 0xa0}, | ||
134 | {0x481b, 0x35}, | ||
135 | {0x481f, 0x30}, | ||
136 | {0x4823, 0x35}, | ||
137 | {0x4d00, 0x04}, | ||
138 | {0x4d01, 0x71}, | ||
139 | {0x4d03, 0xf5}, | ||
140 | {0x4d04, 0x0c}, | ||
141 | {0x4d05, 0xcc}, | ||
142 | {0x4d0b, 0x01}, | ||
143 | {0x5002, 0x08}, | ||
144 | {0x5a01, 0x08}, | ||
145 | {0x5a03, 0x06}, | ||
146 | {0x5a04, 0x10}, | ||
147 | {0x5a05, 0xf0}, | ||
148 | {0x5a06, 0x09}, | ||
149 | {0x5a07, 0x88}, | ||
150 | {0x5a08, 0x01}, | ||
151 | {0x5a04, 0x00}, | ||
152 | {0x5a06, 0x00}, | ||
153 | {0x5b01, 0x10}, | ||
154 | {0x5b05, 0xec}, | ||
155 | {0x5b09, 0x02}, | ||
156 | {0x5e10, 0x0c}, | ||
157 | |||
158 | {0x3082, 0x6c}, | ||
159 | {0x3092, 0x04}, | ||
160 | |||
161 | {0x300d, 0x22}, | ||
162 | {0x301b, 0xb4}, | ||
163 | {0x3033, 0x5c}, | ||
164 | {0x3034, 0x91}, | ||
165 | {0x3035, 0x6e}, | ||
166 | {0x3036, 0xa4}, | ||
167 | {0x3037, 0x6e}, | ||
168 | {0x3038, 0xa4}, | ||
169 | |||
170 | {0x3642, 0x35}, | ||
171 | {0x3663, 0x01}, | ||
172 | |||
173 | {0x3700, 0x44}, | ||
174 | {0x3701, 0x1c}, | ||
175 | {0x3702, 0x90}, | ||
176 | {0x3703, 0x60}, | ||
177 | {0x3704, 0x20}, | ||
178 | {0x3706, 0x18}, | ||
179 | {0x3707, 0x5d}, | ||
180 | {0x3708, 0x74}, | ||
181 | {0x3709, 0x40}, | ||
182 | {0x370a, 0x31}, | ||
183 | {0x370b, 0x33}, | ||
184 | {0x370c, 0x8a}, | ||
185 | {0x370d, 0x03}, | ||
186 | {0x370e, 0x28}, | ||
187 | {0x370f, 0x3b}, | ||
188 | {0x3710, 0x21}, | ||
189 | {0x3711, 0x15}, | ||
190 | {0x3712, 0x19}, | ||
191 | {0x3714, 0x42}, | ||
192 | {0x3730, 0x01}, | ||
193 | {0x3731, 0x6e}, | ||
194 | {0x3732, 0x01}, | ||
195 | {0x3733, 0x03}, | ||
196 | {0x3738, 0x02}, | ||
197 | {0x3739, 0x19}, | ||
198 | {0x373a, 0x01}, | ||
199 | {0x373b, 0xe6}, | ||
200 | {0x373d, 0xa3}, | ||
201 | {0x373e, 0x02}, | ||
202 | {0x373f, 0x70}, | ||
203 | {0x3740, 0x03}, | ||
204 | {0x3741, 0x33}, | ||
205 | {0x3742, 0x02}, | ||
206 | {0x3743, 0xf8}, | ||
207 | {0x3748, 0xa5}, | ||
208 | {0x374c, 0x88}, | ||
209 | |||
210 | {0x3802, 0x00}, | ||
211 | {0x3803, 0x08}, | ||
212 | {0x3806, 0x09}, | ||
213 | {0x3807, 0x98}, | ||
214 | {0x3808, 0x10}, | ||
215 | {0x3809, 0xf0}, | ||
216 | {0x380a, 0x09}, | ||
217 | {0x380b, 0x88}, | ||
218 | {0x380c, 0x15}, | ||
219 | {0x380d, 0x86}, | ||
220 | {0x380e, 0x09}, | ||
221 | {0x380f, 0xe0}, | ||
222 | {0x3810, 0x00}, | ||
223 | {0x3811, 0x08}, | ||
224 | {0x3813, 0x04}, | ||
225 | {0x3815, 0x11}, | ||
226 | {0x3820, 0x04}, | ||
227 | {0x3834, 0x00}, | ||
228 | {0x4001, 0x00}, | ||
229 | {0x4003, 0x30}, | ||
230 | {0x402a, 0x0c}, | ||
231 | {0x402b, 0x08}, | ||
232 | {0x402e, 0x1c}, | ||
233 | {0x4837, 0x11}, | ||
234 | {0x5b04, 0x02}, | ||
235 | |||
236 | /* Exposure/Gain */ | ||
237 | {0x3500, 0x00}, | ||
238 | {0x3501, 0x9c}, | ||
239 | {0x3502, 0x00}, | ||
240 | {0x350b, 0x40}, | ||
241 | |||
242 | /* fsync */ | ||
243 | {0x3002, 0x80}, | ||
244 | {0x3009, 0x06}, | ||
245 | {0x3823, 0x00}, | ||
246 | {0x3826, 0x00}, | ||
247 | {0x3827, 0x00}, | ||
248 | {0x3830, 0x00}, | ||
249 | {0x3831, 0x00}, | ||
250 | |||
251 | {OV10823_TABLE_END, 0x00} | ||
252 | }; | ||
253 | |||
254 | static ov10823_reg mode_3000x2440_24MhzMCLK[] = { | ||
255 | |||
256 | /* PLL */ | ||
257 | {0x3080, 0x04}, | ||
258 | {0x3083, 0x00}, | ||
259 | {0x3084, 0x03}, | ||
260 | {0x308b, 0x05}, | ||
261 | {0x308d, 0xae}, | ||
262 | {0x308e, 0x00}, | ||
263 | {0x308f, 0x09}, | ||
264 | |||
265 | {0x3011, 0xd0}, | ||
266 | {0x3012, 0x41}, | ||
267 | {0x3031, 0x0c}, | ||
268 | {0x3032, 0xc0}, | ||
269 | {0x3503, 0x07}, | ||
270 | {0x3603, 0x04}, | ||
271 | {0x3641, 0x83}, | ||
272 | {0x3643, 0x02}, | ||
273 | {0x3645, 0x41}, | ||
274 | {0x3646, 0x83}, | ||
275 | {0x3648, 0x0d}, | ||
276 | {0x3649, 0x86}, | ||
277 | {0x3653, 0x37}, | ||
278 | {0x3658, 0x8b}, | ||
279 | {0x3659, 0x87}, | ||
280 | {0x365c, 0x5a}, | ||
281 | {0x3660, 0x82}, | ||
282 | {0x3705, 0x22}, | ||
283 | {0x3719, 0x0c}, | ||
284 | {0x371b, 0x00}, | ||
285 | {0x371c, 0x80}, | ||
286 | {0x371e, 0x00}, | ||
287 | {0x371f, 0x20}, | ||
288 | {0x3720, 0xa0}, | ||
289 | {0x3721, 0xf0}, | ||
290 | {0x3723, 0x78}, | ||
291 | {0x372a, 0x08}, | ||
292 | {0x372c, 0x11}, | ||
293 | {0x373c, 0x02}, | ||
294 | {0x3749, 0xd7}, | ||
295 | {0x374a, 0x8c}, | ||
296 | {0x3752, 0x80}, | ||
297 | {0x3821, 0x04}, | ||
298 | {0x382e, 0x04}, | ||
299 | {0x3901, 0x80}, | ||
300 | {0x3902, 0xc6}, | ||
301 | {0x4004, 0x00}, | ||
302 | {0x4005, 0x20}, | ||
303 | {0x400d, 0x10}, | ||
304 | {0x401b, 0x00}, | ||
305 | {0x401d, 0x00}, | ||
306 | {0x401f, 0x00}, | ||
307 | {0x4020, 0x01}, | ||
308 | {0x4022, 0x03}, | ||
309 | {0x4024, 0x0e}, | ||
310 | {0x4025, 0x10}, | ||
311 | {0x4026, 0x0f}, | ||
312 | {0x4027, 0x9f}, | ||
313 | {0x4028, 0x00}, | ||
314 | {0x4029, 0x04}, | ||
315 | {0x402d, 0x04}, | ||
316 | {0x402f, 0x08}, | ||
317 | {0x4602, 0x02}, | ||
318 | |||
319 | #if OV10823_ADJUST_HS_PREPARE | ||
320 | /* Bit[7] is hs_preparei_sel */ | ||
321 | {0x4802, 0x80}, | ||
322 | {0x4826, 0x10}, | ||
323 | #endif | ||
324 | |||
325 | {0x4810, 0x00}, | ||
326 | {0x4811, 0x1f}, | ||
327 | {0x4819, 0xa0}, | ||
328 | {0x481b, 0x35}, | ||
329 | {0x481f, 0x30}, | ||
330 | {0x4823, 0x35}, | ||
331 | {0x4d00, 0x04}, | ||
332 | {0x4d01, 0x71}, | ||
333 | {0x4d03, 0xf5}, | ||
334 | {0x4d04, 0x0c}, | ||
335 | {0x4d05, 0xcc}, | ||
336 | {0x4d0b, 0x01}, | ||
337 | {0x5002, 0x08}, | ||
338 | {0x5a00, 0x02}, | ||
339 | {0x5a01, 0xf6}, | ||
340 | {0x5a03, 0x06}, | ||
341 | {0x5a04, 0x0b}, | ||
342 | {0x5a05, 0xb8}, | ||
343 | {0x5a06, 0x09}, | ||
344 | {0x5a07, 0x88}, | ||
345 | {0x5a08, 0x01}, | ||
346 | {0x5b01, 0x10}, | ||
347 | {0x5b05, 0xec}, | ||
348 | {0x5b09, 0x02}, | ||
349 | {0x5e10, 0x0c}, | ||
350 | |||
351 | {0x3082, 0x6c}, | ||
352 | {0x3092, 0x04}, | ||
353 | |||
354 | {0x300d, 0x22}, | ||
355 | {0x301b, 0xb4}, | ||
356 | {0x3033, 0x5c}, | ||
357 | {0x3034, 0x91}, | ||
358 | {0x3035, 0x6e}, | ||
359 | {0x3036, 0xa4}, | ||
360 | {0x3037, 0x6e}, | ||
361 | {0x3038, 0xa4}, | ||
362 | |||
363 | {0x3642, 0x35}, | ||
364 | {0x3663, 0x01}, | ||
365 | |||
366 | {0x3700, 0x44}, | ||
367 | {0x3701, 0x1c}, | ||
368 | {0x3702, 0x90}, | ||
369 | {0x3703, 0x60}, | ||
370 | {0x3704, 0x20}, | ||
371 | {0x3706, 0x18}, | ||
372 | {0x3707, 0x5d}, | ||
373 | {0x3708, 0x74}, | ||
374 | {0x3709, 0x40}, | ||
375 | {0x370a, 0x31}, | ||
376 | {0x370b, 0x33}, | ||
377 | {0x370c, 0x8a}, | ||
378 | {0x370d, 0x03}, | ||
379 | {0x370e, 0x28}, | ||
380 | {0x370f, 0x3b}, | ||
381 | {0x3710, 0x21}, | ||
382 | {0x3711, 0x15}, | ||
383 | {0x3712, 0x19}, | ||
384 | {0x3714, 0x42}, | ||
385 | {0x3730, 0x01}, | ||
386 | {0x3731, 0x6e}, | ||
387 | {0x3732, 0x01}, | ||
388 | {0x3733, 0x03}, | ||
389 | {0x3738, 0x02}, | ||
390 | {0x3739, 0x19}, | ||
391 | {0x373a, 0x01}, | ||
392 | {0x373b, 0xe6}, | ||
393 | {0x373d, 0xa3}, | ||
394 | {0x373e, 0x02}, | ||
395 | {0x373f, 0x70}, | ||
396 | {0x3740, 0x03}, | ||
397 | {0x3741, 0x33}, | ||
398 | {0x3742, 0x02}, | ||
399 | {0x3743, 0xf8}, | ||
400 | {0x3748, 0xa5}, | ||
401 | {0x374c, 0x88}, | ||
402 | |||
403 | {0x3802, 0x00}, | ||
404 | {0x3803, 0x08}, | ||
405 | {0x3806, 0x09}, | ||
406 | {0x3807, 0x98}, | ||
407 | {0x3808, 0x0b}, | ||
408 | {0x3809, 0xb8}, | ||
409 | {0x380a, 0x09}, | ||
410 | {0x380b, 0x88}, | ||
411 | {0x380c, 0x15}, | ||
412 | {0x380d, 0x80}, | ||
413 | {0x380e, 0x09}, | ||
414 | {0x380f, 0xe0}, | ||
415 | {0x3810, 0x02}, | ||
416 | {0x3811, 0xf6}, | ||
417 | {0x3813, 0x04}, | ||
418 | {0x3815, 0x11}, | ||
419 | {0x3820, 0x04}, | ||
420 | {0x3821, 0x00}, | ||
421 | {0x3834, 0x00}, | ||
422 | {0x4001, 0x00}, | ||
423 | {0x4003, 0x30}, | ||
424 | {0x402a, 0x0c}, | ||
425 | {0x402b, 0x08}, | ||
426 | {0x402e, 0x1c}, | ||
427 | {0x4837, 0x12}, | ||
428 | {0x5b04, 0x02}, | ||
429 | |||
430 | /* Exposure/Gain */ | ||
431 | {0x3500, 0x00}, | ||
432 | {0x3501, 0x9c}, | ||
433 | {0x3502, 0x00}, | ||
434 | {0x350b, 0x40}, | ||
435 | |||
436 | /* fsync */ | ||
437 | {0x3002, 0x80}, | ||
438 | {0x3009, 0x06}, | ||
439 | {0x3823, 0x00}, | ||
440 | {0x3826, 0x00}, | ||
441 | {0x3827, 0x00}, | ||
442 | {0x3830, 0x00}, | ||
443 | {0x3831, 0x00}, | ||
444 | |||
445 | {OV10823_TABLE_END, 0x00} | ||
446 | }; | ||
447 | |||
448 | static ov10823_reg mode_2168x1220_24MhzMCLK[] = { | ||
449 | |||
450 | /* PLL */ | ||
451 | {0x3080, 0x04}, | ||
452 | {0x3083, 0x00}, | ||
453 | {0x3084, 0x03}, | ||
454 | {0x308b, 0x05}, | ||
455 | {0x308d, 0xae}, | ||
456 | {0x308e, 0x00}, | ||
457 | {0x308f, 0x09}, | ||
458 | |||
459 | {0x3011, 0xd0}, | ||
460 | {0x3012, 0x41}, | ||
461 | {0x3031, 0x0c}, | ||
462 | {0x3032, 0xc0}, | ||
463 | {0x3503, 0x07}, | ||
464 | {0x3603, 0x04}, | ||
465 | {0x3641, 0x83}, | ||
466 | {0x3643, 0x02}, | ||
467 | {0x3645, 0x41}, | ||
468 | {0x3646, 0x83}, | ||
469 | {0x3648, 0x0d}, | ||
470 | {0x3649, 0x86}, | ||
471 | {0x3653, 0x37}, | ||
472 | {0x3658, 0x8b}, | ||
473 | {0x3659, 0x87}, | ||
474 | {0x365c, 0x5a}, | ||
475 | {0x3660, 0x82}, | ||
476 | {0x3705, 0x22}, | ||
477 | {0x3719, 0x0c}, | ||
478 | {0x371b, 0x00}, | ||
479 | {0x371c, 0x80}, | ||
480 | {0x371e, 0x00}, | ||
481 | {0x371f, 0x20}, | ||
482 | {0x3720, 0xa0}, | ||
483 | {0x3721, 0xf0}, | ||
484 | {0x3723, 0x78}, | ||
485 | {0x372a, 0x08}, | ||
486 | {0x372c, 0x11}, | ||
487 | {0x373c, 0x02}, | ||
488 | {0x3749, 0xd7}, | ||
489 | {0x374a, 0x8c}, | ||
490 | {0x3752, 0x80}, | ||
491 | {0x3821, 0x04}, | ||
492 | {0x382e, 0x04}, | ||
493 | {0x3901, 0x80}, | ||
494 | {0x3902, 0xc6}, | ||
495 | {0x4004, 0x00}, | ||
496 | {0x4005, 0x20}, | ||
497 | {0x400d, 0x10}, | ||
498 | {0x401b, 0x00}, | ||
499 | {0x401d, 0x00}, | ||
500 | {0x401f, 0x00}, | ||
501 | {0x4020, 0x01}, | ||
502 | {0x4022, 0x03}, | ||
503 | {0x4024, 0x0e}, | ||
504 | {0x4025, 0x10}, | ||
505 | {0x4026, 0x0f}, | ||
506 | {0x4027, 0x9f}, | ||
507 | {0x4028, 0x00}, | ||
508 | {0x4029, 0x04}, | ||
509 | {0x402d, 0x04}, | ||
510 | {0x402f, 0x08}, | ||
511 | {0x4602, 0x02}, | ||
512 | |||
513 | #if OV10823_ADJUST_HS_PREPARE | ||
514 | /* Bit[7] is hs_preparei_sel */ | ||
515 | {0x4802, 0x80}, | ||
516 | {0x4826, 0x10}, | ||
517 | #endif | ||
518 | |||
519 | {0x4810, 0x00}, | ||
520 | {0x4811, 0x1f}, | ||
521 | {0x4819, 0xa0}, | ||
522 | {0x481b, 0x35}, | ||
523 | {0x481f, 0x30}, | ||
524 | {0x4823, 0x35}, | ||
525 | {0x4d00, 0x04}, | ||
526 | {0x4d01, 0x71}, | ||
527 | {0x4d03, 0xf5}, | ||
528 | {0x4d04, 0x0c}, | ||
529 | {0x4d05, 0xcc}, | ||
530 | {0x4d0b, 0x01}, | ||
531 | {0x5002, 0x08}, | ||
532 | {0x5a04, 0x00}, | ||
533 | {0x5a06, 0x00}, | ||
534 | {0x5b01, 0x10}, | ||
535 | {0x5b05, 0xec}, | ||
536 | {0x5b09, 0x02}, | ||
537 | {0x5e10, 0x0c}, | ||
538 | |||
539 | {0x3082, 0x6c}, | ||
540 | {0x3092, 0x04}, | ||
541 | |||
542 | {0x300d, 0x22}, | ||
543 | {0x301b, 0xb4}, | ||
544 | {0x3033, 0x5c}, | ||
545 | {0x3034, 0x91}, | ||
546 | {0x3035, 0x6e}, | ||
547 | {0x3036, 0xa4}, | ||
548 | {0x3037, 0x6e}, | ||
549 | {0x3038, 0xa4}, | ||
550 | |||
551 | {0x3642, 0x35}, | ||
552 | {0x3663, 0x11}, | ||
553 | |||
554 | {0x3700, 0x44}, | ||
555 | {0x3701, 0x1c}, | ||
556 | {0x3702, 0x90}, | ||
557 | {0x3703, 0x60}, | ||
558 | {0x3704, 0x20}, | ||
559 | {0x3706, 0x18}, | ||
560 | {0x3707, 0x5d}, | ||
561 | {0x3708, 0x74}, | ||
562 | {0x3709, 0x40}, | ||
563 | {0x370a, 0x33}, | ||
564 | {0x370b, 0x33}, | ||
565 | {0x370c, 0x8a}, | ||
566 | {0x370d, 0x03}, | ||
567 | {0x370e, 0x28}, | ||
568 | {0x370f, 0x3b}, | ||
569 | {0x3710, 0x21}, | ||
570 | {0x3711, 0x15}, | ||
571 | {0x3712, 0x19}, | ||
572 | {0x3714, 0x42}, | ||
573 | {0x3730, 0x01}, | ||
574 | {0x3731, 0x6e}, | ||
575 | {0x3732, 0x01}, | ||
576 | {0x3733, 0x03}, | ||
577 | {0x3738, 0x02}, | ||
578 | {0x3739, 0x19}, | ||
579 | {0x373a, 0x01}, | ||
580 | {0x373b, 0xe6}, | ||
581 | {0x373d, 0xa3}, | ||
582 | {0x373e, 0x02}, | ||
583 | {0x373f, 0x00}, | ||
584 | {0x3740, 0x03}, | ||
585 | {0x3741, 0x33}, | ||
586 | {0x3742, 0x02}, | ||
587 | {0x3743, 0xf8}, | ||
588 | {0x3748, 0xa5}, | ||
589 | {0x374c, 0x88}, | ||
590 | |||
591 | {0x3802, 0x00}, | ||
592 | {0x3803, 0x08}, | ||
593 | {0x3806, 0x09}, | ||
594 | {0x3807, 0x97}, | ||
595 | {0x3808, 0x08}, | ||
596 | {0x3809, 0x78}, | ||
597 | {0x380a, 0x04}, | ||
598 | {0x380b, 0xc4}, | ||
599 | {0x380c, 0x15}, | ||
600 | {0x380d, 0x80}, | ||
601 | {0x380e, 0x09}, | ||
602 | {0x380f, 0xe0}, | ||
603 | {0x3810, 0x00}, | ||
604 | {0x3811, 0x04}, | ||
605 | {0x3813, 0x02}, | ||
606 | {0x3815, 0x31}, | ||
607 | {0x3820, 0x06}, | ||
608 | {0x3821, 0x00}, | ||
609 | {0x3834, 0x01}, | ||
610 | {0x4001, 0x00}, | ||
611 | {0x4003, 0x1c}, | ||
612 | {0x402a, 0x0a}, | ||
613 | {0x402b, 0x06}, | ||
614 | {0x402e, 0x14}, | ||
615 | {0x4837, 0x12}, | ||
616 | {0x5b04, 0x02}, | ||
617 | |||
618 | /* Exposure/Gain */ | ||
619 | {0x3500, 0x00}, | ||
620 | {0x3501, 0x9c}, | ||
621 | {0x3502, 0x00}, | ||
622 | {0x350b, 0x40}, | ||
623 | |||
624 | /* fsync */ | ||
625 | {0x3002, 0x80}, | ||
626 | {0x3009, 0x06}, | ||
627 | {0x3823, 0x00}, | ||
628 | {0x3826, 0x00}, | ||
629 | {0x3827, 0x00}, | ||
630 | {0x3830, 0x00}, | ||
631 | {0x3831, 0x00}, | ||
632 | |||
633 | {OV10823_TABLE_END, 0x00} | ||
634 | }; | ||
635 | |||
636 | static ov10823_reg mode_4336x2440_26MhzMCLK[] = { | ||
637 | |||
638 | /* PLL */ | ||
639 | {0x3080, 0x04}, | ||
640 | {0x3083, 0x00}, | ||
641 | {0x3084, 0x03}, | ||
642 | {0x308b, 0x06}, | ||
643 | {0x308d, 0xf1}, | ||
644 | {0x308e, 0x00}, | ||
645 | {0x308f, 0x09}, | ||
646 | |||
647 | {0x3011, 0xd0}, | ||
648 | {0x3012, 0x41}, | ||
649 | {0x3031, 0x0c}, | ||
650 | {0x3032, 0xc0}, | ||
651 | {0x3503, 0x07}, | ||
652 | {0x3603, 0x04}, | ||
653 | {0x3641, 0x83}, | ||
654 | {0x3643, 0x02}, | ||
655 | {0x3645, 0x41}, | ||
656 | {0x3646, 0x83}, | ||
657 | {0x3648, 0x0d}, | ||
658 | {0x3649, 0x86}, | ||
659 | {0x3653, 0x37}, | ||
660 | {0x3658, 0x8b}, | ||
661 | {0x3659, 0x87}, | ||
662 | {0x365c, 0x5a}, | ||
663 | {0x3660, 0x82}, | ||
664 | {0x3705, 0x22}, | ||
665 | {0x3719, 0x0c}, | ||
666 | {0x371b, 0x00}, | ||
667 | {0x371c, 0x80}, | ||
668 | {0x371e, 0x00}, | ||
669 | {0x371f, 0x20}, | ||
670 | {0x3720, 0xa0}, | ||
671 | {0x3721, 0xf0}, | ||
672 | {0x3723, 0x78}, | ||
673 | {0x372a, 0x08}, | ||
674 | {0x372c, 0x11}, | ||
675 | {0x373c, 0x02}, | ||
676 | {0x3749, 0xd7}, | ||
677 | {0x374a, 0x8c}, | ||
678 | {0x3752, 0x80}, | ||
679 | {0x3821, 0x00}, | ||
680 | {0x382e, 0x04}, | ||
681 | {0x3901, 0x80}, | ||
682 | {0x3902, 0xc6}, | ||
683 | {0x4004, 0x00}, | ||
684 | {0x4005, 0x20}, | ||
685 | {0x400d, 0x10}, | ||
686 | {0x401b, 0x00}, | ||
687 | {0x401d, 0x00}, | ||
688 | {0x401f, 0x00}, | ||
689 | {0x4020, 0x01}, | ||
690 | {0x4022, 0x03}, | ||
691 | {0x4024, 0x0e}, | ||
692 | {0x4025, 0x10}, | ||
693 | {0x4026, 0x0f}, | ||
694 | {0x4027, 0x9f}, | ||
695 | {0x4028, 0x00}, | ||
696 | {0x4029, 0x04}, | ||
697 | {0x402d, 0x04}, | ||
698 | {0x402f, 0x08}, | ||
699 | {0x4602, 0x02}, | ||
700 | |||
701 | #if OV10823_ADJUST_HS_PREPARE | ||
702 | {0x4800, 0x20}, | ||
703 | {0x4831, 0x6a}, | ||
704 | #endif | ||
705 | |||
706 | {0x4810, 0x00}, | ||
707 | {0x4811, 0x1f}, | ||
708 | {0x4819, 0xa0}, | ||
709 | {0x481b, 0x35}, | ||
710 | {0x481f, 0x30}, | ||
711 | {0x4823, 0x35}, | ||
712 | {0x4d00, 0x04}, | ||
713 | {0x4d01, 0x71}, | ||
714 | {0x4d03, 0xf5}, | ||
715 | {0x4d04, 0x0c}, | ||
716 | {0x4d05, 0xcc}, | ||
717 | {0x4d0b, 0x01}, | ||
718 | {0x5002, 0x08}, | ||
719 | {0x5a01, 0x08}, | ||
720 | {0x5a03, 0x06}, | ||
721 | {0x5a04, 0x10}, | ||
722 | {0x5a05, 0xf0}, | ||
723 | {0x5a06, 0x09}, | ||
724 | {0x5a07, 0x88}, | ||
725 | {0x5a08, 0x01}, | ||
726 | {0x5b01, 0x10}, | ||
727 | {0x5b05, 0xec}, | ||
728 | {0x5b09, 0x02}, | ||
729 | {0x5e10, 0x0c}, | ||
730 | |||
731 | {0x3082, 0x69}, | ||
732 | {0x3092, 0x04}, | ||
733 | |||
734 | {0x300d, 0x22}, | ||
735 | {0x301b, 0xb4}, | ||
736 | {0x3033, 0x5c}, | ||
737 | {0x3034, 0x91}, | ||
738 | {0x3035, 0x6e}, | ||
739 | {0x3036, 0xa4}, | ||
740 | {0x3037, 0x6e}, | ||
741 | {0x3038, 0xa4}, | ||
742 | |||
743 | {0x3642, 0x35}, | ||
744 | {0x3663, 0x01}, | ||
745 | |||
746 | {0x3700, 0x44}, | ||
747 | {0x3701, 0x1c}, | ||
748 | {0x3702, 0x90}, | ||
749 | {0x3703, 0x60}, | ||
750 | {0x3704, 0x20}, | ||
751 | {0x3706, 0x18}, | ||
752 | {0x3707, 0x5d}, | ||
753 | {0x3708, 0x74}, | ||
754 | {0x3709, 0x40}, | ||
755 | {0x370a, 0x31}, | ||
756 | {0x370b, 0x33}, | ||
757 | {0x370c, 0x8a}, | ||
758 | {0x370d, 0x03}, | ||
759 | {0x370e, 0x28}, | ||
760 | {0x370f, 0x3b}, | ||
761 | {0x3710, 0x21}, | ||
762 | {0x3711, 0x15}, | ||
763 | {0x3712, 0x19}, | ||
764 | {0x3714, 0x42}, | ||
765 | {0x3730, 0x01}, | ||
766 | {0x3731, 0x6e}, | ||
767 | {0x3732, 0x01}, | ||
768 | {0x3733, 0x03}, | ||
769 | {0x3738, 0x02}, | ||
770 | {0x3739, 0x19}, | ||
771 | {0x373a, 0x01}, | ||
772 | {0x373b, 0xe6}, | ||
773 | {0x373d, 0xa3}, | ||
774 | {0x373e, 0x02}, | ||
775 | {0x373f, 0x70}, | ||
776 | {0x3740, 0x03}, | ||
777 | {0x3741, 0x33}, | ||
778 | {0x3742, 0x02}, | ||
779 | {0x3743, 0xf8}, | ||
780 | {0x3748, 0xa5}, | ||
781 | {0x374c, 0x88}, | ||
782 | |||
783 | {0x3802, 0x00}, | ||
784 | {0x3803, 0x08}, | ||
785 | {0x3806, 0x09}, | ||
786 | {0x3807, 0x98}, | ||
787 | {0x3808, 0x10}, | ||
788 | {0x3809, 0xf0}, | ||
789 | {0x380a, 0x09}, | ||
790 | {0x380b, 0x88}, | ||
791 | {0x380c, 0x15}, | ||
792 | {0x380d, 0x86}, | ||
793 | {0x380e, 0x09}, | ||
794 | {0x380f, 0xe0}, | ||
795 | {0x3810, 0x00}, | ||
796 | {0x3811, 0x08}, | ||
797 | {0x3813, 0x04}, | ||
798 | {0x3815, 0x11}, | ||
799 | {0x3820, 0x04}, | ||
800 | {0x3834, 0x00}, | ||
801 | {0x4001, 0x00}, | ||
802 | {0x4003, 0x30}, | ||
803 | {0x402a, 0x0c}, | ||
804 | {0x402b, 0x08}, | ||
805 | {0x402e, 0x1c}, | ||
806 | {0x4837, 0x11}, | ||
807 | {0x5b04, 0x02}, | ||
808 | |||
809 | /* Exposure/Gain */ | ||
810 | {0x3500, 0x00}, | ||
811 | {0x3501, 0x9c}, | ||
812 | {0x3502, 0x00}, | ||
813 | {0x350b, 0x40}, | ||
814 | |||
815 | /* fsync */ | ||
816 | {0x3002, 0x80}, | ||
817 | {0x3009, 0x06}, | ||
818 | {0x3823, 0x00}, | ||
819 | {0x3826, 0x00}, | ||
820 | {0x3827, 0x00}, | ||
821 | {0x3830, 0x00}, | ||
822 | {0x3831, 0x00}, | ||
823 | |||
824 | {OV10823_TABLE_END, 0x00} | ||
825 | }; | ||
826 | |||
827 | static ov10823_reg mode_3000x2440_26MhzMCLK[] = { | ||
828 | |||
829 | /* PLL */ | ||
830 | {0x3080, 0x04}, | ||
831 | {0x3083, 0x00}, | ||
832 | {0x3084, 0x03}, | ||
833 | {0x308b, 0x06}, | ||
834 | {0x308d, 0xf1}, | ||
835 | {0x308e, 0x00}, | ||
836 | {0x308f, 0x09}, | ||
837 | |||
838 | {0x3011, 0xd0}, | ||
839 | {0x3012, 0x41}, | ||
840 | {0x3031, 0x0c}, | ||
841 | {0x3032, 0xc0}, | ||
842 | {0x3503, 0x07}, | ||
843 | {0x3603, 0x04}, | ||
844 | {0x3641, 0x83}, | ||
845 | {0x3643, 0x02}, | ||
846 | {0x3645, 0x41}, | ||
847 | {0x3646, 0x83}, | ||
848 | {0x3648, 0x0d}, | ||
849 | {0x3649, 0x86}, | ||
850 | {0x3653, 0x37}, | ||
851 | {0x3658, 0x8b}, | ||
852 | {0x3659, 0x87}, | ||
853 | {0x365c, 0x5a}, | ||
854 | {0x3660, 0x82}, | ||
855 | {0x3705, 0x22}, | ||
856 | {0x3719, 0x0c}, | ||
857 | {0x371b, 0x00}, | ||
858 | {0x371c, 0x80}, | ||
859 | {0x371e, 0x00}, | ||
860 | {0x371f, 0x20}, | ||
861 | {0x3720, 0xa0}, | ||
862 | {0x3721, 0xf0}, | ||
863 | {0x3723, 0x78}, | ||
864 | {0x372a, 0x08}, | ||
865 | {0x372c, 0x11}, | ||
866 | {0x373c, 0x02}, | ||
867 | {0x3749, 0xd7}, | ||
868 | {0x374a, 0x8c}, | ||
869 | {0x3752, 0x80}, | ||
870 | {0x3821, 0x04}, | ||
871 | {0x382e, 0x04}, | ||
872 | {0x3901, 0x80}, | ||
873 | {0x3902, 0xc6}, | ||
874 | {0x4004, 0x00}, | ||
875 | {0x4005, 0x20}, | ||
876 | {0x400d, 0x10}, | ||
877 | {0x401b, 0x00}, | ||
878 | {0x401d, 0x00}, | ||
879 | {0x401f, 0x00}, | ||
880 | {0x4020, 0x01}, | ||
881 | {0x4022, 0x03}, | ||
882 | {0x4024, 0x0e}, | ||
883 | {0x4025, 0x10}, | ||
884 | {0x4026, 0x0f}, | ||
885 | {0x4027, 0x9f}, | ||
886 | {0x4028, 0x00}, | ||
887 | {0x4029, 0x04}, | ||
888 | {0x402d, 0x04}, | ||
889 | {0x402f, 0x08}, | ||
890 | {0x4602, 0x02}, | ||
891 | |||
892 | #if OV10823_ADJUST_HS_PREPARE | ||
893 | {0x4800, 0x20}, | ||
894 | {0x4831, 0x6a}, | ||
895 | #endif | ||
896 | |||
897 | {0x4810, 0x00}, | ||
898 | {0x4811, 0x1f}, | ||
899 | {0x4819, 0xa0}, | ||
900 | {0x481b, 0x35}, | ||
901 | {0x481f, 0x30}, | ||
902 | {0x4823, 0x35}, | ||
903 | {0x4d00, 0x04}, | ||
904 | {0x4d01, 0x71}, | ||
905 | {0x4d03, 0xf5}, | ||
906 | {0x4d04, 0x0c}, | ||
907 | {0x4d05, 0xcc}, | ||
908 | {0x4d0b, 0x01}, | ||
909 | {0x5002, 0x08}, | ||
910 | {0x5a00, 0x02}, | ||
911 | {0x5a01, 0xf6}, | ||
912 | {0x5a03, 0x06}, | ||
913 | {0x5a04, 0x0b}, | ||
914 | {0x5a05, 0xb8}, | ||
915 | {0x5a06, 0x09}, | ||
916 | {0x5a07, 0x88}, | ||
917 | {0x5a08, 0x01}, | ||
918 | {0x5b01, 0x10}, | ||
919 | {0x5b05, 0xec}, | ||
920 | {0x5b09, 0x02}, | ||
921 | {0x5e10, 0x0c}, | ||
922 | |||
923 | {0x3082, 0x64}, | ||
924 | {0x3092, 0x04}, | ||
925 | |||
926 | {0x300d, 0x22}, | ||
927 | {0x301b, 0xb4}, | ||
928 | {0x3033, 0x5c}, | ||
929 | {0x3034, 0x91}, | ||
930 | {0x3035, 0x6e}, | ||
931 | {0x3036, 0xa4}, | ||
932 | {0x3037, 0x6e}, | ||
933 | {0x3038, 0xa4}, | ||
934 | |||
935 | {0x3642, 0x35}, | ||
936 | {0x3663, 0x01}, | ||
937 | |||
938 | {0x3700, 0x44}, | ||
939 | {0x3701, 0x1c}, | ||
940 | {0x3702, 0x90}, | ||
941 | {0x3703, 0x60}, | ||
942 | {0x3704, 0x20}, | ||
943 | {0x3706, 0x18}, | ||
944 | {0x3707, 0x5d}, | ||
945 | {0x3708, 0x74}, | ||
946 | {0x3709, 0x40}, | ||
947 | {0x370a, 0x31}, | ||
948 | {0x370b, 0x33}, | ||
949 | {0x370c, 0x8a}, | ||
950 | {0x370d, 0x03}, | ||
951 | {0x370e, 0x28}, | ||
952 | {0x370f, 0x3b}, | ||
953 | {0x3710, 0x21}, | ||
954 | {0x3711, 0x15}, | ||
955 | {0x3712, 0x19}, | ||
956 | {0x3714, 0x42}, | ||
957 | {0x3730, 0x01}, | ||
958 | {0x3731, 0x6e}, | ||
959 | {0x3732, 0x01}, | ||
960 | {0x3733, 0x03}, | ||
961 | {0x3738, 0x02}, | ||
962 | {0x3739, 0x19}, | ||
963 | {0x373a, 0x01}, | ||
964 | {0x373b, 0xe6}, | ||
965 | {0x373d, 0xa3}, | ||
966 | {0x373e, 0x02}, | ||
967 | {0x373f, 0x70}, | ||
968 | {0x3740, 0x03}, | ||
969 | {0x3741, 0x33}, | ||
970 | {0x3742, 0x02}, | ||
971 | {0x3743, 0xf8}, | ||
972 | {0x3748, 0xa5}, | ||
973 | {0x374c, 0x88}, | ||
974 | |||
975 | {0x3802, 0x00}, | ||
976 | {0x3803, 0x08}, | ||
977 | {0x3806, 0x09}, | ||
978 | {0x3807, 0x98}, | ||
979 | {0x3808, 0x0b}, | ||
980 | {0x3809, 0xb8}, | ||
981 | {0x380a, 0x09}, | ||
982 | {0x380b, 0x88}, | ||
983 | {0x380c, 0x15}, | ||
984 | {0x380d, 0x80}, | ||
985 | {0x380e, 0x09}, | ||
986 | {0x380f, 0xe0}, | ||
987 | {0x3810, 0x02}, | ||
988 | {0x3811, 0xf6}, | ||
989 | {0x3813, 0x04}, | ||
990 | {0x3815, 0x11}, | ||
991 | {0x3820, 0x04}, | ||
992 | {0x3821, 0x00}, | ||
993 | {0x3834, 0x00}, | ||
994 | {0x4001, 0x00}, | ||
995 | {0x4003, 0x30}, | ||
996 | {0x402a, 0x0c}, | ||
997 | {0x402b, 0x08}, | ||
998 | {0x402e, 0x1c}, | ||
999 | {0x4837, 0x12}, | ||
1000 | {0x5b04, 0x02}, | ||
1001 | |||
1002 | /* Exposure/Gain */ | ||
1003 | {0x3500, 0x00}, | ||
1004 | {0x3501, 0x9c}, | ||
1005 | {0x3502, 0x00}, | ||
1006 | {0x350b, 0x40}, | ||
1007 | |||
1008 | /* fsync */ | ||
1009 | {0x3002, 0x80}, | ||
1010 | {0x3009, 0x06}, | ||
1011 | {0x3823, 0x00}, | ||
1012 | {0x3826, 0x00}, | ||
1013 | {0x3827, 0x00}, | ||
1014 | {0x3830, 0x00}, | ||
1015 | {0x3831, 0x00}, | ||
1016 | |||
1017 | {OV10823_TABLE_END, 0x00} | ||
1018 | }; | ||
1019 | |||
1020 | static ov10823_reg mode_2168x1220_26MhzMCLK[] = { | ||
1021 | |||
1022 | /* PLL */ | ||
1023 | {0x3080, 0x04}, | ||
1024 | {0x3083, 0x00}, | ||
1025 | {0x3084, 0x03}, | ||
1026 | {0x308b, 0x06}, | ||
1027 | {0x308d, 0xf1}, | ||
1028 | {0x308e, 0x00}, | ||
1029 | {0x308f, 0x09}, | ||
1030 | |||
1031 | {0x3011, 0xd0}, | ||
1032 | {0x3012, 0x41}, | ||
1033 | {0x3031, 0x0c}, | ||
1034 | {0x3032, 0xc0}, | ||
1035 | {0x3503, 0x07}, | ||
1036 | {0x3603, 0x04}, | ||
1037 | {0x3641, 0x83}, | ||
1038 | {0x3643, 0x02}, | ||
1039 | {0x3645, 0x41}, | ||
1040 | {0x3646, 0x83}, | ||
1041 | {0x3648, 0x0d}, | ||
1042 | {0x3649, 0x86}, | ||
1043 | {0x3653, 0x37}, | ||
1044 | {0x3658, 0x8b}, | ||
1045 | {0x3659, 0x87}, | ||
1046 | {0x365c, 0x5a}, | ||
1047 | {0x3660, 0x82}, | ||
1048 | {0x3705, 0x22}, | ||
1049 | {0x3719, 0x0c}, | ||
1050 | {0x371b, 0x00}, | ||
1051 | {0x371c, 0x80}, | ||
1052 | {0x371e, 0x00}, | ||
1053 | {0x371f, 0x20}, | ||
1054 | {0x3720, 0xa0}, | ||
1055 | {0x3721, 0xf0}, | ||
1056 | {0x3723, 0x78}, | ||
1057 | {0x372a, 0x08}, | ||
1058 | {0x372c, 0x11}, | ||
1059 | {0x373c, 0x02}, | ||
1060 | {0x3749, 0xd7}, | ||
1061 | {0x374a, 0x8c}, | ||
1062 | {0x3752, 0x80}, | ||
1063 | {0x3821, 0x04}, | ||
1064 | {0x382e, 0x04}, | ||
1065 | {0x3901, 0x80}, | ||
1066 | {0x3902, 0xc6}, | ||
1067 | {0x4004, 0x00}, | ||
1068 | {0x4005, 0x20}, | ||
1069 | {0x400d, 0x10}, | ||
1070 | {0x401b, 0x00}, | ||
1071 | {0x401d, 0x00}, | ||
1072 | {0x401f, 0x00}, | ||
1073 | {0x4020, 0x01}, | ||
1074 | {0x4022, 0x03}, | ||
1075 | {0x4024, 0x0e}, | ||
1076 | {0x4025, 0x10}, | ||
1077 | {0x4026, 0x0f}, | ||
1078 | {0x4027, 0x9f}, | ||
1079 | {0x4028, 0x00}, | ||
1080 | {0x4029, 0x04}, | ||
1081 | {0x402d, 0x04}, | ||
1082 | {0x402f, 0x08}, | ||
1083 | {0x4602, 0x02}, | ||
1084 | |||
1085 | #if OV10823_ADJUST_HS_PREPARE | ||
1086 | /* Bit[7] is hs_preparei_sel */ | ||
1087 | {0x4802, 0x80}, | ||
1088 | {0x4826, 0x10}, | ||
1089 | #endif | ||
1090 | |||
1091 | {0x4810, 0x00}, | ||
1092 | {0x4811, 0x1f}, | ||
1093 | {0x4819, 0xa0}, | ||
1094 | {0x481b, 0x35}, | ||
1095 | {0x481f, 0x30}, | ||
1096 | {0x4823, 0x35}, | ||
1097 | {0x4d00, 0x04}, | ||
1098 | {0x4d01, 0x71}, | ||
1099 | {0x4d03, 0xf5}, | ||
1100 | {0x4d04, 0x0c}, | ||
1101 | {0x4d05, 0xcc}, | ||
1102 | {0x4d0b, 0x01}, | ||
1103 | {0x5002, 0x08}, | ||
1104 | {0x5a04, 0x00}, | ||
1105 | {0x5a06, 0x00}, | ||
1106 | {0x5b01, 0x10}, | ||
1107 | {0x5b05, 0xec}, | ||
1108 | {0x5b09, 0x02}, | ||
1109 | {0x5e10, 0x0c}, | ||
1110 | |||
1111 | {0x3082, 0x64}, | ||
1112 | {0x3092, 0x04}, | ||
1113 | |||
1114 | {0x300d, 0x22}, | ||
1115 | {0x301b, 0xb4}, | ||
1116 | {0x3033, 0x5c}, | ||
1117 | {0x3034, 0x91}, | ||
1118 | {0x3035, 0x6e}, | ||
1119 | {0x3036, 0xa4}, | ||
1120 | {0x3037, 0x6e}, | ||
1121 | {0x3038, 0xa4}, | ||
1122 | |||
1123 | {0x3642, 0x35}, | ||
1124 | {0x3663, 0x11}, | ||
1125 | |||
1126 | {0x3700, 0x44}, | ||
1127 | {0x3701, 0x1c}, | ||
1128 | {0x3702, 0x90}, | ||
1129 | {0x3703, 0x60}, | ||
1130 | {0x3704, 0x20}, | ||
1131 | {0x3706, 0x18}, | ||
1132 | {0x3707, 0x5d}, | ||
1133 | {0x3708, 0x74}, | ||
1134 | {0x3709, 0x40}, | ||
1135 | {0x370a, 0x33}, | ||
1136 | {0x370b, 0x33}, | ||
1137 | {0x370c, 0x8a}, | ||
1138 | {0x370d, 0x03}, | ||
1139 | {0x370e, 0x28}, | ||
1140 | {0x370f, 0x3b}, | ||
1141 | {0x3710, 0x21}, | ||
1142 | {0x3711, 0x15}, | ||
1143 | {0x3712, 0x19}, | ||
1144 | {0x3714, 0x42}, | ||
1145 | {0x3730, 0x01}, | ||
1146 | {0x3731, 0x6e}, | ||
1147 | {0x3732, 0x01}, | ||
1148 | {0x3733, 0x03}, | ||
1149 | {0x3738, 0x02}, | ||
1150 | {0x3739, 0x19}, | ||
1151 | {0x373a, 0x01}, | ||
1152 | {0x373b, 0xe6}, | ||
1153 | {0x373d, 0xa3}, | ||
1154 | {0x373e, 0x02}, | ||
1155 | {0x373f, 0x00}, | ||
1156 | {0x3740, 0x03}, | ||
1157 | {0x3741, 0x33}, | ||
1158 | {0x3742, 0x02}, | ||
1159 | {0x3743, 0xf8}, | ||
1160 | {0x3748, 0xa5}, | ||
1161 | {0x374c, 0x88}, | ||
1162 | |||
1163 | {0x3802, 0x00}, | ||
1164 | {0x3803, 0x08}, | ||
1165 | {0x3806, 0x09}, | ||
1166 | {0x3807, 0x97}, | ||
1167 | {0x3808, 0x08}, | ||
1168 | {0x3809, 0x78}, | ||
1169 | {0x380a, 0x04}, | ||
1170 | {0x380b, 0xc4}, | ||
1171 | {0x380c, 0x15}, | ||
1172 | {0x380d, 0x80}, | ||
1173 | {0x380e, 0x09}, | ||
1174 | {0x380f, 0xe0}, | ||
1175 | {0x3810, 0x00}, | ||
1176 | {0x3811, 0x04}, | ||
1177 | {0x3813, 0x02}, | ||
1178 | {0x3815, 0x31}, | ||
1179 | {0x3820, 0x06}, | ||
1180 | {0x3821, 0x00}, | ||
1181 | {0x3834, 0x01}, | ||
1182 | {0x4001, 0x00}, | ||
1183 | {0x4003, 0x1c}, | ||
1184 | {0x402a, 0x0a}, | ||
1185 | {0x402b, 0x06}, | ||
1186 | {0x402e, 0x14}, | ||
1187 | {0x4837, 0x12}, | ||
1188 | {0x5b04, 0x02}, | ||
1189 | |||
1190 | /* Exposure/Gain */ | ||
1191 | {0x3500, 0x00}, | ||
1192 | {0x3501, 0x9c}, | ||
1193 | {0x3502, 0x00}, | ||
1194 | {0x350b, 0x40}, | ||
1195 | |||
1196 | /* fsync */ | ||
1197 | {0x3002, 0x80}, | ||
1198 | {0x3009, 0x06}, | ||
1199 | {0x3823, 0x00}, | ||
1200 | {0x3826, 0x00}, | ||
1201 | {0x3827, 0x00}, | ||
1202 | {0x3830, 0x00}, | ||
1203 | {0x3831, 0x00}, | ||
1204 | |||
1205 | {OV10823_TABLE_END, 0x00} | ||
1206 | }; | ||
1207 | |||
1208 | static ov10823_reg mode_4336x1220_60fps_26MhzMCLK[] = { | ||
1209 | |||
1210 | /* PLL */ | ||
1211 | {0x3080, 0x04}, | ||
1212 | {0x3083, 0x00}, | ||
1213 | {0x3084, 0x03}, | ||
1214 | {0x308b, 0x06}, | ||
1215 | {0x308d, 0xf1}, | ||
1216 | {0x308e, 0x00}, | ||
1217 | {0x308f, 0x09}, | ||
1218 | |||
1219 | {0x3011, 0xd0}, | ||
1220 | {0x3012, 0x41}, | ||
1221 | {0x3031, 0x0c}, | ||
1222 | {0x3032, 0xc0}, | ||
1223 | {0x3503, 0x07}, | ||
1224 | {0x3603, 0x04}, | ||
1225 | {0x3641, 0x83}, | ||
1226 | {0x3643, 0x02}, | ||
1227 | {0x3645, 0x41}, | ||
1228 | {0x3646, 0x83}, | ||
1229 | {0x3648, 0x0d}, | ||
1230 | {0x3649, 0x86}, | ||
1231 | {0x3653, 0x37}, | ||
1232 | {0x3658, 0x8b}, | ||
1233 | {0x3659, 0x87}, | ||
1234 | {0x365c, 0x5a}, | ||
1235 | {0x3660, 0x82}, | ||
1236 | {0x3705, 0x22}, | ||
1237 | {0x3719, 0x0c}, | ||
1238 | {0x371b, 0x00}, | ||
1239 | {0x371c, 0x80}, | ||
1240 | {0x371e, 0x00}, | ||
1241 | {0x371f, 0x20}, | ||
1242 | {0x3720, 0xf0}, | ||
1243 | {0x3721, 0xf0}, | ||
1244 | {0x3723, 0x78}, | ||
1245 | {0x372a, 0x08}, | ||
1246 | {0x372c, 0x11}, | ||
1247 | {0x373c, 0x02}, | ||
1248 | {0x3749, 0xd7}, | ||
1249 | {0x374a, 0x8c}, | ||
1250 | {0x3752, 0x80}, | ||
1251 | {0x3821, 0x00}, | ||
1252 | {0x382e, 0x04}, | ||
1253 | {0x3901, 0x00}, | ||
1254 | {0x3902, 0xc6}, | ||
1255 | {0x4004, 0x00}, | ||
1256 | {0x4005, 0x20}, | ||
1257 | {0x400d, 0x10}, | ||
1258 | {0x401b, 0x00}, | ||
1259 | {0x401d, 0x00}, | ||
1260 | {0x401f, 0x00}, | ||
1261 | {0x4020, 0x01}, | ||
1262 | {0x4022, 0x03}, | ||
1263 | {0x4024, 0x0e}, | ||
1264 | {0x4025, 0x10}, | ||
1265 | {0x4026, 0x0f}, | ||
1266 | {0x4027, 0x9f}, | ||
1267 | {0x4028, 0x00}, | ||
1268 | {0x4029, 0x04}, | ||
1269 | {0x402d, 0x04}, | ||
1270 | {0x402f, 0x08}, | ||
1271 | {0x4602, 0x02}, | ||
1272 | |||
1273 | #if OV10823_ADJUST_HS_PREPARE | ||
1274 | {0x4802, 0x80}, | ||
1275 | {0x4826, 0x10}, | ||
1276 | #endif | ||
1277 | |||
1278 | {0x4810, 0x00}, | ||
1279 | {0x4811, 0x1f}, | ||
1280 | {0x4819, 0xa0}, | ||
1281 | {0x481b, 0x35}, | ||
1282 | {0x481f, 0x30}, | ||
1283 | {0x4823, 0x35}, | ||
1284 | {0x4d00, 0x04}, | ||
1285 | {0x4d01, 0x71}, | ||
1286 | {0x4d03, 0xf5}, | ||
1287 | {0x4d04, 0x0c}, | ||
1288 | {0x4d05, 0xcc}, | ||
1289 | {0x4d0b, 0x01}, | ||
1290 | {0x5001, 0x03}, | ||
1291 | {0x5002, 0x08}, | ||
1292 | {0x5a04, 0x00}, | ||
1293 | {0x5a06, 0x00}, | ||
1294 | {0x5b01, 0x10}, | ||
1295 | {0x5b05, 0xec}, | ||
1296 | {0x5b09, 0x02}, | ||
1297 | {0x5e10, 0x0c}, | ||
1298 | |||
1299 | {0x3082, 0x64}, | ||
1300 | {0x3092, 0x04}, | ||
1301 | |||
1302 | {0x300d, 0x22}, | ||
1303 | {0x301b, 0xb4}, | ||
1304 | {0x3033, 0x5c}, | ||
1305 | {0x3034, 0x91}, | ||
1306 | {0x3035, 0x6e}, | ||
1307 | {0x3036, 0xa4}, | ||
1308 | {0x3037, 0x6e}, | ||
1309 | {0x3038, 0xa4}, | ||
1310 | |||
1311 | {0x3642, 0x35}, | ||
1312 | {0x3663, 0x01}, | ||
1313 | |||
1314 | {0x3700, 0x44}, | ||
1315 | {0x3701, 0x1c}, | ||
1316 | {0x3702, 0x90}, | ||
1317 | {0x3703, 0x60}, | ||
1318 | {0x3704, 0x20}, | ||
1319 | {0x3706, 0x18}, | ||
1320 | {0x3707, 0x5d}, | ||
1321 | {0x3708, 0x74}, | ||
1322 | {0x3709, 0x40}, | ||
1323 | {0x370a, 0x33}, | ||
1324 | {0x370b, 0x33}, | ||
1325 | {0x370c, 0x8a}, | ||
1326 | {0x370d, 0x03}, | ||
1327 | {0x370e, 0x28}, | ||
1328 | {0x370f, 0x3b}, | ||
1329 | {0x3710, 0x21}, | ||
1330 | {0x3711, 0x15}, | ||
1331 | {0x3712, 0x19}, | ||
1332 | {0x3714, 0x42}, | ||
1333 | {0x3730, 0x01}, | ||
1334 | {0x3731, 0x6e}, | ||
1335 | {0x3732, 0x01}, | ||
1336 | {0x3733, 0x03}, | ||
1337 | {0x3738, 0x02}, | ||
1338 | {0x3739, 0x19}, | ||
1339 | {0x373a, 0x01}, | ||
1340 | {0x373b, 0xe6}, | ||
1341 | {0x373d, 0xa3}, | ||
1342 | {0x373e, 0x02}, | ||
1343 | {0x373f, 0x70}, | ||
1344 | {0x3740, 0x03}, | ||
1345 | {0x3741, 0x33}, | ||
1346 | {0x3742, 0x02}, | ||
1347 | {0x3743, 0xf8}, | ||
1348 | {0x3748, 0xa5}, | ||
1349 | {0x374c, 0x88}, | ||
1350 | |||
1351 | {0x3802, 0x00}, | ||
1352 | {0x3803, 0x08}, | ||
1353 | {0x3806, 0x09}, | ||
1354 | {0x3807, 0x97}, | ||
1355 | {0x3808, 0x10}, | ||
1356 | {0x3809, 0xf0}, | ||
1357 | {0x380a, 0x04}, | ||
1358 | {0x380b, 0xc4}, | ||
1359 | {0x380c, 0x15}, | ||
1360 | {0x380d, 0x80}, | ||
1361 | {0x380e, 0x04}, | ||
1362 | {0x380f, 0xf0}, | ||
1363 | {0x3810, 0x00}, | ||
1364 | {0x3811, 0x08}, | ||
1365 | {0x3813, 0x02}, | ||
1366 | {0x3815, 0x31}, | ||
1367 | {0x3820, 0x06}, | ||
1368 | {0x3821, 0x00}, | ||
1369 | {0x3834, 0x00}, | ||
1370 | {0x4001, 0x00}, | ||
1371 | {0x4003, 0x1c}, | ||
1372 | {0x402a, 0x0a}, | ||
1373 | {0x402b, 0x06}, | ||
1374 | {0x402e, 0x14}, | ||
1375 | {0x4837, 0x12}, | ||
1376 | {0x5b04, 0x02}, | ||
1377 | |||
1378 | /* Exposure/Gain */ | ||
1379 | {0x3500, 0x00}, | ||
1380 | {0x3501, 0x4d}, | ||
1381 | {0x3502, 0x00}, | ||
1382 | {0x350b, 0x40}, | ||
1383 | |||
1384 | /* fsync */ | ||
1385 | {0x3002, 0x80}, | ||
1386 | {0x3009, 0x06}, | ||
1387 | {0x3823, 0x00}, | ||
1388 | {0x3826, 0x00}, | ||
1389 | {0x3827, 0x00}, | ||
1390 | {0x3830, 0x00}, | ||
1391 | {0x3831, 0x00}, | ||
1392 | |||
1393 | {OV10823_TABLE_END, 0x00} | ||
1394 | }; | ||
1395 | #endif /* OV10823_UNUSED_MODES */ | ||
1396 | |||
1397 | static ov10823_reg mode_2168x1220_60fps_26MhzMCLK[] = { | ||
1398 | |||
1399 | /* PLL */ | ||
1400 | {0x3080, 0x04}, | ||
1401 | {0x3083, 0x00}, | ||
1402 | {0x3084, 0x03}, | ||
1403 | {0x308b, 0x06}, | ||
1404 | {0x308d, 0xf1}, | ||
1405 | {0x308e, 0x00}, | ||
1406 | {0x308f, 0x09}, | ||
1407 | |||
1408 | {0x3011, 0xd0}, | ||
1409 | {0x3012, 0x41}, | ||
1410 | {0x3031, 0x0c}, | ||
1411 | {0x3032, 0xc0}, | ||
1412 | {0x3503, 0x07}, | ||
1413 | {0x3603, 0x04}, | ||
1414 | {0x3641, 0x83}, | ||
1415 | {0x3643, 0x02}, | ||
1416 | {0x3645, 0x41}, | ||
1417 | {0x3646, 0x83}, | ||
1418 | {0x3648, 0x0d}, | ||
1419 | {0x3649, 0x86}, | ||
1420 | {0x3653, 0x37}, | ||
1421 | {0x3658, 0x8b}, | ||
1422 | {0x3659, 0x87}, | ||
1423 | {0x365c, 0x5a}, | ||
1424 | {0x3660, 0x82}, | ||
1425 | {0x3705, 0x22}, | ||
1426 | {0x3719, 0x0c}, | ||
1427 | {0x371b, 0x00}, | ||
1428 | {0x371c, 0x80}, | ||
1429 | {0x371e, 0x00}, | ||
1430 | {0x371f, 0x20}, | ||
1431 | {0x3720, 0xf0}, | ||
1432 | {0x3721, 0xf0}, | ||
1433 | {0x3723, 0x78}, | ||
1434 | {0x372a, 0x08}, | ||
1435 | {0x372c, 0x11}, | ||
1436 | {0x373c, 0x02}, | ||
1437 | {0x3749, 0xd7}, | ||
1438 | {0x374a, 0x8c}, | ||
1439 | {0x3752, 0x80}, | ||
1440 | {0x3821, 0x04}, | ||
1441 | {0x382e, 0x04}, | ||
1442 | {0x3901, 0x00}, | ||
1443 | {0x3902, 0xc6}, | ||
1444 | {0x4004, 0x00}, | ||
1445 | {0x4005, 0x20}, | ||
1446 | {0x400d, 0x10}, | ||
1447 | {0x401b, 0x00}, | ||
1448 | {0x401d, 0x00}, | ||
1449 | {0x401f, 0x00}, | ||
1450 | {0x4020, 0x01}, | ||
1451 | {0x4022, 0x03}, | ||
1452 | {0x4024, 0x0e}, | ||
1453 | {0x4025, 0x10}, | ||
1454 | {0x4026, 0x0f}, | ||
1455 | {0x4027, 0x9f}, | ||
1456 | {0x4028, 0x00}, | ||
1457 | {0x4029, 0x04}, | ||
1458 | {0x402d, 0x04}, | ||
1459 | {0x402f, 0x08}, | ||
1460 | {0x4602, 0x02}, | ||
1461 | |||
1462 | #if OV10823_ADJUST_HS_PREPARE | ||
1463 | /* Bit[7] is hs_preparei_sel */ | ||
1464 | {0x4802, 0x80}, | ||
1465 | {0x4826, 0x10}, | ||
1466 | #endif | ||
1467 | |||
1468 | {0x4810, 0x00}, | ||
1469 | {0x4811, 0x1f}, | ||
1470 | {0x4819, 0xa0}, | ||
1471 | {0x481b, 0x35}, | ||
1472 | {0x481f, 0x30}, | ||
1473 | {0x4823, 0x35}, | ||
1474 | {0x4d00, 0x04}, | ||
1475 | {0x4d01, 0x71}, | ||
1476 | {0x4d03, 0xf5}, | ||
1477 | {0x4d04, 0x0c}, | ||
1478 | {0x4d05, 0xcc}, | ||
1479 | {0x4d0b, 0x01}, | ||
1480 | {0x5001, 0x03}, | ||
1481 | {0x5002, 0x08}, | ||
1482 | {0x5a04, 0x00}, | ||
1483 | {0x5a06, 0x00}, | ||
1484 | {0x5b01, 0x10}, | ||
1485 | {0x5b05, 0xec}, | ||
1486 | {0x5b09, 0x02}, | ||
1487 | {0x5e10, 0x0c}, | ||
1488 | |||
1489 | {0x3082, 0x64}, | ||
1490 | {0x3092, 0x04}, | ||
1491 | |||
1492 | {0x300d, 0x22}, | ||
1493 | {0x301b, 0xb4}, | ||
1494 | {0x3033, 0x5c}, | ||
1495 | {0x3034, 0x91}, | ||
1496 | {0x3035, 0x6e}, | ||
1497 | {0x3036, 0xa4}, | ||
1498 | {0x3037, 0x6e}, | ||
1499 | {0x3038, 0xa4}, | ||
1500 | |||
1501 | {0x3642, 0x35}, | ||
1502 | {0x3663, 0x11}, | ||
1503 | |||
1504 | {0x3700, 0x44}, | ||
1505 | {0x3701, 0x1c}, | ||
1506 | {0x3702, 0x90}, | ||
1507 | {0x3703, 0x60}, | ||
1508 | {0x3704, 0x20}, | ||
1509 | {0x3706, 0x18}, | ||
1510 | {0x3707, 0x5d}, | ||
1511 | {0x3708, 0x74}, | ||
1512 | {0x3709, 0x40}, | ||
1513 | {0x370a, 0x33}, | ||
1514 | {0x370b, 0x33}, | ||
1515 | {0x370c, 0x8a}, | ||
1516 | {0x370d, 0x03}, | ||
1517 | {0x370e, 0x28}, | ||
1518 | {0x370f, 0x3b}, | ||
1519 | {0x3710, 0x21}, | ||
1520 | {0x3711, 0x15}, | ||
1521 | {0x3712, 0x19}, | ||
1522 | {0x3714, 0x42}, | ||
1523 | {0x3730, 0x01}, | ||
1524 | {0x3731, 0x6e}, | ||
1525 | {0x3732, 0x01}, | ||
1526 | {0x3733, 0x03}, | ||
1527 | {0x3738, 0x02}, | ||
1528 | {0x3739, 0x19}, | ||
1529 | {0x373a, 0x01}, | ||
1530 | {0x373b, 0xe6}, | ||
1531 | {0x373d, 0xa3}, | ||
1532 | {0x373e, 0x02}, | ||
1533 | {0x373f, 0x70}, | ||
1534 | {0x3740, 0x03}, | ||
1535 | {0x3741, 0x33}, | ||
1536 | {0x3742, 0x02}, | ||
1537 | {0x3743, 0xf8}, | ||
1538 | {0x3748, 0xa5}, | ||
1539 | {0x374c, 0x88}, | ||
1540 | |||
1541 | {0x3802, 0x00}, | ||
1542 | {0x3803, 0x08}, | ||
1543 | {0x3806, 0x09}, | ||
1544 | {0x3807, 0x97}, | ||
1545 | {0x3808, 0x08}, | ||
1546 | {0x3809, 0x78}, | ||
1547 | {0x380a, 0x04}, | ||
1548 | {0x380b, 0xc4}, | ||
1549 | {0x380c, 0x15}, | ||
1550 | {0x380d, 0x80}, | ||
1551 | {0x380e, 0x04}, | ||
1552 | {0x380f, 0xf0}, | ||
1553 | {0x3810, 0x00}, | ||
1554 | {0x3811, 0x04}, | ||
1555 | {0x3813, 0x02}, | ||
1556 | {0x3815, 0x31}, | ||
1557 | {0x3820, 0x06}, | ||
1558 | {0x3821, 0x00}, | ||
1559 | {0x3834, 0x01}, | ||
1560 | {0x4001, 0x00}, | ||
1561 | {0x4003, 0x1c}, | ||
1562 | {0x402a, 0x0a}, | ||
1563 | {0x402b, 0x06}, | ||
1564 | {0x402e, 0x14}, | ||
1565 | {0x4837, 0x12}, | ||
1566 | {0x5b04, 0x02}, | ||
1567 | |||
1568 | /* Exposure/Gain */ | ||
1569 | {0x3500, 0x00}, | ||
1570 | {0x3501, 0x4d}, | ||
1571 | {0x3502, 0x00}, | ||
1572 | {0x350b, 0x40}, | ||
1573 | |||
1574 | /* fsync */ | ||
1575 | {0x3002, 0x80}, | ||
1576 | {0x3009, 0x06}, | ||
1577 | {0x3823, 0x00}, | ||
1578 | {0x3826, 0x00}, | ||
1579 | {0x3827, 0x00}, | ||
1580 | {0x3830, 0x00}, | ||
1581 | {0x3831, 0x00}, | ||
1582 | |||
1583 | {OV10823_TABLE_END, 0x00} | ||
1584 | }; | ||
1585 | |||
1586 | enum { | ||
1587 | #ifdef OV10823_UNUSED_MODES | ||
1588 | OV10823_MODE_4336X2440, | ||
1589 | OV10823_MODE_3000X2440, | ||
1590 | OV10823_MODE_2168X1220, | ||
1591 | #endif | ||
1592 | OV10823_MODE_2168X1220_60FPS, | ||
1593 | OV10823_MODE_START_STREAM, | ||
1594 | OV10823_MODE_STOP_STREAM, | ||
1595 | }; | ||
1596 | |||
1597 | static ov10823_reg *mode_table[] = { | ||
1598 | #ifdef OV10823_UNUSED_MODES | ||
1599 | [OV10823_MODE_4336X2440] = mode_4336x2440_26MhzMCLK, | ||
1600 | [OV10823_MODE_3000X2440] = mode_3000x2440_26MhzMCLK, | ||
1601 | [OV10823_MODE_2168X1220] = mode_2168x1220_26MhzMCLK, | ||
1602 | #endif | ||
1603 | [OV10823_MODE_2168X1220_60FPS] = mode_2168x1220_60fps_26MhzMCLK, | ||
1604 | |||
1605 | [OV10823_MODE_START_STREAM] = ov10823_start, | ||
1606 | [OV10823_MODE_STOP_STREAM] = ov10823_stop, | ||
1607 | }; | ||
1608 | |||
1609 | enum { | ||
1610 | OV10823_FSYNC_NONE, | ||
1611 | OV10823_FSYNC_MASTER, | ||
1612 | OV10823_FSYNC_SLAVE, | ||
1613 | }; | ||
1614 | |||
1615 | static ov10823_reg *fsync_table[] = { | ||
1616 | [OV10823_FSYNC_NONE] = NULL, | ||
1617 | [OV10823_FSYNC_MASTER] = fsync_master, | ||
1618 | [OV10823_FSYNC_SLAVE] = fsync_slave, | ||
1619 | }; | ||
1620 | |||
1621 | static const int ov10823_30fps[] = { | ||
1622 | 30, | ||
1623 | }; | ||
1624 | |||
1625 | static const int ov10823_60fps[] = { | ||
1626 | 60, | ||
1627 | }; | ||
1628 | |||
1629 | static const struct camera_common_frmfmt ov10823_frmfmt[] = { | ||
1630 | #ifdef OV10823_UNUSED_MODES | ||
1631 | {{4336, 2440}, ov10823_30fps, 1, 0, OV10823_MODE_4336X2440}, | ||
1632 | {{3000, 2440}, ov10823_30fps, 1, 0, OV10823_MODE_3000X2440}, | ||
1633 | {{2168, 1220}, ov10823_30fps, 1, 0, OV10823_MODE_2168X1220}, | ||
1634 | #endif | ||
1635 | {{2168, 1220}, ov10823_60fps, 1, 0, OV10823_MODE_2168X1220_60FPS}, | ||
1636 | }; | ||
1637 | #endif /* __OV10823_I2C_TABLES__ */ | ||
diff --git a/drivers/media/i2c/ov23850.c b/drivers/media/i2c/ov23850.c new file mode 100644 index 000000000..710314fba --- /dev/null +++ b/drivers/media/i2c/ov23850.c | |||
@@ -0,0 +1,1443 @@ | |||
1 | /* | ||
2 | * ov23850.c - ov23850 sensor driver | ||
3 | * | ||
4 | * Copyright (c) 2013-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <linux/slab.h> | ||
20 | #include <linux/uaccess.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/module.h> | ||
23 | |||
24 | #include <linux/seq_file.h> | ||
25 | #include <linux/of.h> | ||
26 | #include <linux/of_device.h> | ||
27 | #include <linux/of_gpio.h> | ||
28 | |||
29 | #include <media/tegra_v4l2_camera.h> | ||
30 | #include <media/camera_common.h> | ||
31 | #include <media/ov23850.h> | ||
32 | |||
33 | #include "ov23850_mode_tbls.h" | ||
34 | |||
35 | #define OV23850_MAX_COARSE_DIFF 0x20 | ||
36 | |||
37 | #define OV23850_GAIN_SHIFT 8 | ||
38 | #define OV23850_MIN_GAIN (1 << OV23850_GAIN_SHIFT) | ||
39 | #define OV23850_MAX_GAIN (16 << OV23850_GAIN_SHIFT) | ||
40 | #define OV23850_MIN_FRAME_LENGTH (0x0) | ||
41 | #define OV23850_MAX_FRAME_LENGTH (0x7fff) | ||
42 | #define OV23850_MIN_EXPOSURE_COARSE (0x0002) | ||
43 | #define OV23850_MAX_EXPOSURE_COARSE \ | ||
44 | (OV23850_MAX_FRAME_LENGTH-OV23850_MAX_COARSE_DIFF) | ||
45 | |||
46 | #define OV23850_DEFAULT_GAIN OV23850_MIN_GAIN | ||
47 | #define OV23850_DEFAULT_FRAME_LENGTH (0x12C6) | ||
48 | #define OV23850_DEFAULT_EXPOSURE_COARSE \ | ||
49 | (OV23850_DEFAULT_FRAME_LENGTH-OV23850_MAX_COARSE_DIFF) | ||
50 | |||
51 | #define OV23850_DEFAULT_MODE OV23850_MODE_5632X4224 | ||
52 | #define OV23850_DEFAULT_WIDTH 5632 | ||
53 | #define OV23850_DEFAULT_HEIGHT 4224 | ||
54 | #define OV23850_DEFAULT_DATAFMT MEDIA_BUS_FMT_SRGGB10_1X10 | ||
55 | #define OV23850_DEFAULT_CLK_FREQ 24000000 | ||
56 | |||
57 | struct ov23850 { | ||
58 | struct mutex ov23850_camera_lock; | ||
59 | struct camera_common_power_rail power; | ||
60 | int numctrls; | ||
61 | struct v4l2_ctrl_handler ctrl_handler; | ||
62 | #if 0 | ||
63 | struct camera_common_eeprom_data eeprom[OV23850_EEPROM_NUM_BLOCKS]; | ||
64 | u8 eeprom_buf[OV23850_EEPROM_SIZE]; | ||
65 | #endif | ||
66 | struct i2c_client *i2c_client; | ||
67 | struct v4l2_subdev *subdev; | ||
68 | struct media_pad pad; | ||
69 | |||
70 | u32 frame_length; | ||
71 | s32 group_hold_prev; | ||
72 | bool group_hold_en; | ||
73 | struct regmap *regmap; | ||
74 | struct camera_common_data *s_data; | ||
75 | struct camera_common_pdata *pdata; | ||
76 | struct v4l2_ctrl *ctrls[]; | ||
77 | }; | ||
78 | |||
79 | static const struct regmap_config sensor_regmap_config = { | ||
80 | .reg_bits = 16, | ||
81 | .val_bits = 8, | ||
82 | .cache_type = REGCACHE_RBTREE, | ||
83 | }; | ||
84 | |||
85 | u16 ov23850_to_gain(u32 rep, int shift) | ||
86 | { | ||
87 | u16 gain; | ||
88 | int gain_int; | ||
89 | int gain_dec; | ||
90 | int min_int = (1 << shift); | ||
91 | int step = 1; | ||
92 | int num_step; | ||
93 | int i; | ||
94 | |||
95 | if (rep < 0x0100) | ||
96 | rep = 0x0100; | ||
97 | else if (rep > 0x0F80) | ||
98 | rep = 0x0F80; | ||
99 | |||
100 | /* last 4 bit of rep is | ||
101 | * decimal representation of gain */ | ||
102 | gain_int = (int)(rep >> shift); | ||
103 | gain_dec = (int)(rep & ~(0xffff << shift)); | ||
104 | |||
105 | for (i = 1; gain_int >> i != 0; i++) | ||
106 | ; | ||
107 | step = step << (5 - i); | ||
108 | |||
109 | num_step = gain_dec * step / min_int; | ||
110 | gain = 16 * gain_int + 16 * num_step / step; | ||
111 | |||
112 | return gain; | ||
113 | } | ||
114 | |||
115 | static int ov23850_g_volatile_ctrl(struct v4l2_ctrl *ctrl); | ||
116 | static int ov23850_s_ctrl(struct v4l2_ctrl *ctrl); | ||
117 | |||
118 | static const struct v4l2_ctrl_ops ov23850_ctrl_ops = { | ||
119 | .g_volatile_ctrl = ov23850_g_volatile_ctrl, | ||
120 | .s_ctrl = ov23850_s_ctrl, | ||
121 | }; | ||
122 | |||
123 | static struct v4l2_ctrl_config ctrl_config_list[] = { | ||
124 | /* Do not change the name field for the controls! */ | ||
125 | { | ||
126 | .ops = &ov23850_ctrl_ops, | ||
127 | .id = V4L2_CID_GAIN, | ||
128 | .name = "Gain", | ||
129 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
130 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
131 | .min = OV23850_MIN_GAIN, | ||
132 | .max = OV23850_MAX_GAIN, | ||
133 | .def = OV23850_DEFAULT_GAIN, | ||
134 | .step = 1, | ||
135 | }, | ||
136 | { | ||
137 | .ops = &ov23850_ctrl_ops, | ||
138 | .id = V4L2_CID_FRAME_LENGTH, | ||
139 | .name = "Frame Length", | ||
140 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
141 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
142 | .min = OV23850_MIN_FRAME_LENGTH, | ||
143 | .max = OV23850_MAX_FRAME_LENGTH, | ||
144 | .def = OV23850_DEFAULT_FRAME_LENGTH, | ||
145 | .step = 1, | ||
146 | }, | ||
147 | { | ||
148 | .ops = &ov23850_ctrl_ops, | ||
149 | .id = V4L2_CID_COARSE_TIME, | ||
150 | .name = "Coarse Time", | ||
151 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
152 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
153 | .min = OV23850_MIN_EXPOSURE_COARSE, | ||
154 | .max = OV23850_MAX_EXPOSURE_COARSE, | ||
155 | .def = OV23850_DEFAULT_EXPOSURE_COARSE, | ||
156 | .step = 1, | ||
157 | }, | ||
158 | { | ||
159 | .ops = &ov23850_ctrl_ops, | ||
160 | .id = V4L2_CID_COARSE_TIME_SHORT, | ||
161 | .name = "Coarse Time Short", | ||
162 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
163 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
164 | .min = OV23850_MIN_EXPOSURE_COARSE, | ||
165 | .max = OV23850_MAX_EXPOSURE_COARSE, | ||
166 | .def = OV23850_DEFAULT_EXPOSURE_COARSE, | ||
167 | .step = 1, | ||
168 | }, | ||
169 | { | ||
170 | .ops = &ov23850_ctrl_ops, | ||
171 | .id = V4L2_CID_GROUP_HOLD, | ||
172 | .name = "Group Hold", | ||
173 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, | ||
174 | .min = 0, | ||
175 | .max = ARRAY_SIZE(switch_ctrl_qmenu) - 1, | ||
176 | .menu_skip_mask = 0, | ||
177 | .def = 0, | ||
178 | .qmenu_int = switch_ctrl_qmenu, | ||
179 | }, | ||
180 | { | ||
181 | .ops = &ov23850_ctrl_ops, | ||
182 | .id = V4L2_CID_HDR_EN, | ||
183 | .name = "HDR enable", | ||
184 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, | ||
185 | .min = 0, | ||
186 | .max = 0, | ||
187 | .menu_skip_mask = 0, | ||
188 | .def = 0, | ||
189 | .qmenu_int = switch_ctrl_qmenu, | ||
190 | }, | ||
191 | { | ||
192 | .ops = &ov23850_ctrl_ops, | ||
193 | .id = V4L2_CID_EEPROM_DATA, | ||
194 | .name = "EEPROM Data", | ||
195 | .type = V4L2_CTRL_TYPE_STRING, | ||
196 | .flags = V4L2_CTRL_FLAG_VOLATILE, | ||
197 | .min = 0, | ||
198 | .max = OV23850_EEPROM_STR_SIZE, | ||
199 | .step = 2, | ||
200 | }, | ||
201 | { | ||
202 | .ops = &ov23850_ctrl_ops, | ||
203 | .id = V4L2_CID_OTP_DATA, | ||
204 | .name = "OTP Data", | ||
205 | .type = V4L2_CTRL_TYPE_STRING, | ||
206 | .flags = V4L2_CTRL_FLAG_READ_ONLY, | ||
207 | .min = 0, | ||
208 | .max = OV23850_OTP_STR_SIZE, | ||
209 | .step = 2, | ||
210 | }, | ||
211 | { | ||
212 | .ops = &ov23850_ctrl_ops, | ||
213 | .id = V4L2_CID_FUSE_ID, | ||
214 | .name = "Fuse ID", | ||
215 | .type = V4L2_CTRL_TYPE_STRING, | ||
216 | .flags = V4L2_CTRL_FLAG_READ_ONLY, | ||
217 | .min = 0, | ||
218 | .max = OV23850_FUSE_ID_STR_SIZE, | ||
219 | .step = 2, | ||
220 | }, | ||
221 | }; | ||
222 | |||
223 | static inline void ov23850_get_frame_length_regs(ov23850_reg *regs, | ||
224 | u32 frame_length) | ||
225 | { | ||
226 | regs->addr = OV23850_FRAME_LENGTH_ADDR_MSB; | ||
227 | regs->val = (frame_length >> 8) & 0x7f; | ||
228 | (regs + 1)->addr = OV23850_FRAME_LENGTH_ADDR_LSB; | ||
229 | (regs + 1)->val = (frame_length) & 0xff; | ||
230 | } | ||
231 | |||
232 | static inline void ov23850_get_coarse_time_regs(ov23850_reg *regs, | ||
233 | u32 coarse_time) | ||
234 | { | ||
235 | regs->addr = OV23850_COARSE_TIME_ADDR_MSB; | ||
236 | regs->val = (coarse_time >> 8) & 0x7f; | ||
237 | (regs + 1)->addr = OV23850_COARSE_TIME_ADDR_LSB; | ||
238 | (regs + 1)->val = (coarse_time) & 0xff; | ||
239 | } | ||
240 | |||
241 | static inline void ov23850_get_coarse_time_short_regs(ov23850_reg *regs, | ||
242 | u32 coarse_time) | ||
243 | { | ||
244 | regs->addr = OV23850_COARSE_TIME_SHORT_ADDR_MSB; | ||
245 | regs->val = (coarse_time >> 8) & 0xff; | ||
246 | (regs + 1)->addr = OV23850_COARSE_TIME_SHORT_ADDR_LSB; | ||
247 | (regs + 1)->val = (coarse_time) & 0xff; | ||
248 | } | ||
249 | |||
250 | static inline void ov23850_get_gain_reg(ov23850_reg *regs, | ||
251 | u16 gain) | ||
252 | { | ||
253 | regs->addr = OV23850_GAIN_ADDR_MSB; | ||
254 | regs->val = (gain >> 8) & 0x07; | ||
255 | (regs + 1)->addr = OV23850_GAIN_ADDR_LSB; | ||
256 | (regs + 1)->val = (gain) & 0xff; | ||
257 | } | ||
258 | |||
259 | static inline void ov23850_get_gain_short_reg(ov23850_reg *regs, | ||
260 | u16 gain) | ||
261 | { | ||
262 | regs->addr = OV23850_GAIN_SHORT_ADDR_MSB; | ||
263 | regs->val = (gain >> 8) & 0x07; | ||
264 | (regs + 1)->addr = OV23850_GAIN_SHORT_ADDR_LSB; | ||
265 | (regs + 1)->val = (gain) & 0xff; | ||
266 | } | ||
267 | |||
268 | static int test_mode; | ||
269 | module_param(test_mode, int, 0644); | ||
270 | |||
271 | static inline int ov23850_read_reg(struct camera_common_data *s_data, | ||
272 | u16 addr, u8 *val) | ||
273 | { | ||
274 | struct ov23850 *priv = (struct ov23850 *)s_data->priv; | ||
275 | |||
276 | return regmap_read(priv->regmap, addr, (unsigned int *) val); | ||
277 | } | ||
278 | |||
279 | static int ov23850_write_reg(struct camera_common_data *s_data, | ||
280 | u16 addr, u8 val) | ||
281 | { | ||
282 | int err; | ||
283 | struct ov23850 *priv = (struct ov23850 *)s_data->priv; | ||
284 | |||
285 | err = regmap_write(priv->regmap, addr, val); | ||
286 | if (err) | ||
287 | pr_err("%s:i2c write failed, %x = %x\n", | ||
288 | __func__, addr, val); | ||
289 | |||
290 | return err; | ||
291 | } | ||
292 | |||
293 | static int ov23850_write_table(struct ov23850 *priv, | ||
294 | const ov23850_reg table[]) | ||
295 | { | ||
296 | return regmap_util_write_table_8(priv->regmap, | ||
297 | table, | ||
298 | NULL, 0, | ||
299 | OV23850_TABLE_WAIT_MS, | ||
300 | OV23850_TABLE_END); | ||
301 | } | ||
302 | |||
303 | static int ov23850_power_on(struct camera_common_data *s_data) | ||
304 | { | ||
305 | int err = 0; | ||
306 | struct ov23850 *priv = (struct ov23850 *)s_data->priv; | ||
307 | struct camera_common_power_rail *pw = &priv->power; | ||
308 | |||
309 | dev_dbg(&priv->i2c_client->dev, "%s: power on\n", __func__); | ||
310 | |||
311 | if (priv->pdata->power_on) { | ||
312 | err = priv->pdata->power_on(pw); | ||
313 | if (err) | ||
314 | pr_err("%s failed.\n", __func__); | ||
315 | else | ||
316 | pw->state = SWITCH_ON; | ||
317 | return err; | ||
318 | } | ||
319 | |||
320 | if (pw->reset_gpio) | ||
321 | gpio_set_value(pw->reset_gpio, 0); | ||
322 | if (pw->pwdn_gpio) | ||
323 | gpio_set_value(pw->pwdn_gpio, 0); | ||
324 | usleep_range(10, 20); | ||
325 | |||
326 | if (pw->avdd) | ||
327 | err = regulator_enable(pw->avdd); | ||
328 | if (err) | ||
329 | goto ov23850_avdd_fail; | ||
330 | |||
331 | if (pw->dvdd) | ||
332 | err = regulator_enable(pw->dvdd); | ||
333 | if (err) | ||
334 | goto ov23850_dvdd_fail; | ||
335 | |||
336 | if (pw->iovdd) | ||
337 | err = regulator_enable(pw->iovdd); | ||
338 | if (err) | ||
339 | goto ov23850_iovdd_fail; | ||
340 | |||
341 | if (pw->vcmvdd) | ||
342 | err = regulator_enable(pw->vcmvdd); | ||
343 | if (err) | ||
344 | goto ov23850_vcmvdd_fail; | ||
345 | |||
346 | if (pw->pwdn_gpio) | ||
347 | gpio_set_value(pw->pwdn_gpio, 1); | ||
348 | if (pw->reset_gpio) | ||
349 | gpio_set_value(pw->reset_gpio, 1); | ||
350 | |||
351 | usleep_range(5350, 5360); /* 5ms + 8192 EXTCLK cycles */ | ||
352 | |||
353 | pw->state = SWITCH_ON; | ||
354 | return 0; | ||
355 | |||
356 | ov23850_vcmvdd_fail: | ||
357 | regulator_disable(pw->iovdd); | ||
358 | |||
359 | ov23850_iovdd_fail: | ||
360 | regulator_disable(pw->dvdd); | ||
361 | |||
362 | ov23850_dvdd_fail: | ||
363 | regulator_disable(pw->avdd); | ||
364 | |||
365 | ov23850_avdd_fail: | ||
366 | pr_err("%s failed.\n", __func__); | ||
367 | return -ENODEV; | ||
368 | } | ||
369 | |||
370 | static int ov23850_power_off(struct camera_common_data *s_data) | ||
371 | { | ||
372 | int err = 0; | ||
373 | struct ov23850 *priv = (struct ov23850 *)s_data->priv; | ||
374 | struct camera_common_power_rail *pw = &priv->power; | ||
375 | |||
376 | dev_dbg(&priv->i2c_client->dev, "%s: power off\n", __func__); | ||
377 | |||
378 | if (priv->pdata->power_off) { | ||
379 | err = priv->pdata->power_off(pw); | ||
380 | if (!err) | ||
381 | goto power_off_done; | ||
382 | else | ||
383 | pr_err("%s failed.\n", __func__); | ||
384 | return err; | ||
385 | } | ||
386 | |||
387 | usleep_range(1, 2); | ||
388 | if (pw->reset_gpio) | ||
389 | gpio_set_value(pw->reset_gpio, 0); | ||
390 | if (pw->pwdn_gpio) | ||
391 | gpio_set_value(pw->pwdn_gpio, 0); | ||
392 | usleep_range(1, 2); | ||
393 | |||
394 | if (pw->vcmvdd) | ||
395 | regulator_disable(pw->vcmvdd); | ||
396 | if (pw->iovdd) | ||
397 | regulator_disable(pw->iovdd); | ||
398 | if (pw->dvdd) | ||
399 | regulator_disable(pw->dvdd); | ||
400 | if (pw->avdd) | ||
401 | regulator_disable(pw->avdd); | ||
402 | |||
403 | power_off_done: | ||
404 | pw->state = SWITCH_OFF; | ||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static int ov23850_power_put(struct ov23850 *priv) | ||
409 | { | ||
410 | struct camera_common_power_rail *pw = &priv->power; | ||
411 | |||
412 | if (unlikely(!pw)) | ||
413 | return -EFAULT; | ||
414 | |||
415 | if (likely(pw->avdd)) | ||
416 | regulator_put(pw->avdd); | ||
417 | |||
418 | if (likely(pw->iovdd)) | ||
419 | regulator_put(pw->iovdd); | ||
420 | |||
421 | if (likely(pw->dvdd)) | ||
422 | regulator_put(pw->dvdd); | ||
423 | |||
424 | pw->avdd = NULL; | ||
425 | pw->iovdd = NULL; | ||
426 | pw->dvdd = NULL; | ||
427 | |||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | static int ov23850_power_get(struct ov23850 *priv) | ||
432 | { | ||
433 | struct camera_common_power_rail *pw = &priv->power; | ||
434 | struct camera_common_pdata *pdata = priv->pdata; | ||
435 | const char *mclk_name; | ||
436 | struct clk *parent; | ||
437 | int err = 0; | ||
438 | |||
439 | mclk_name = priv->pdata->mclk_name ? | ||
440 | priv->pdata->mclk_name : "cam_mclk1"; | ||
441 | pw->mclk = devm_clk_get(&priv->i2c_client->dev, mclk_name); | ||
442 | if (IS_ERR(pw->mclk)) { | ||
443 | dev_err(&priv->i2c_client->dev, | ||
444 | "unable to get clock %s\n", mclk_name); | ||
445 | return PTR_ERR(pw->mclk); | ||
446 | } | ||
447 | |||
448 | parent = devm_clk_get(&priv->i2c_client->dev, "pllp_grtba"); | ||
449 | if (IS_ERR(parent)) | ||
450 | dev_err(&priv->i2c_client->dev, "devm_clk_get failed for pllp_grtba"); | ||
451 | else | ||
452 | clk_set_parent(pw->mclk, parent); | ||
453 | |||
454 | /* ananlog 2.7v */ | ||
455 | err |= camera_common_regulator_get(priv->i2c_client, | ||
456 | &pw->avdd, pdata->regulators.avdd); | ||
457 | /* digital 1.2v */ | ||
458 | err |= camera_common_regulator_get(priv->i2c_client, | ||
459 | &pw->dvdd, pdata->regulators.dvdd); | ||
460 | /* IO 1.8v */ | ||
461 | err |= camera_common_regulator_get(priv->i2c_client, | ||
462 | &pw->iovdd, pdata->regulators.iovdd); | ||
463 | |||
464 | if (!err) { | ||
465 | pw->reset_gpio = pdata->reset_gpio; | ||
466 | pw->pwdn_gpio = pdata->pwdn_gpio; | ||
467 | } | ||
468 | |||
469 | pw->state = SWITCH_OFF; | ||
470 | return err; | ||
471 | } | ||
472 | |||
473 | static int ov23850_set_gain(struct ov23850 *priv, s32 val); | ||
474 | static int ov23850_set_frame_length(struct ov23850 *priv, s32 val); | ||
475 | static int ov23850_set_coarse_time(struct ov23850 *priv, s32 val); | ||
476 | static int ov23850_set_coarse_time_short(struct ov23850 *priv, s32 val); | ||
477 | |||
478 | static int ov23850_s_stream(struct v4l2_subdev *sd, int enable) | ||
479 | { | ||
480 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
481 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
482 | struct ov23850 *priv = (struct ov23850 *)s_data->priv; | ||
483 | struct v4l2_control control; | ||
484 | int err; | ||
485 | |||
486 | dev_dbg(&client->dev, "%s++\n", __func__); | ||
487 | |||
488 | if (!enable) { | ||
489 | err = ov23850_write_table(priv, | ||
490 | mode_table[OV23850_MODE_STOP_STREAM]); | ||
491 | if (err) | ||
492 | return err; | ||
493 | |||
494 | /* Wait for one frame to make sure sensor is set to | ||
495 | * software standby in V-blank | ||
496 | * | ||
497 | * delay = frame length rows * Tline (10 us) | ||
498 | */ | ||
499 | usleep_range(priv->frame_length * 10, | ||
500 | priv->frame_length * 10 + 1000); | ||
501 | return 0; | ||
502 | } | ||
503 | |||
504 | err = ov23850_write_table(priv, mode_table[OV23850_MODE_COMMON]); | ||
505 | if (err) | ||
506 | goto exit; | ||
507 | err = ov23850_write_table(priv, mode_table[s_data->mode]); | ||
508 | if (err) | ||
509 | goto exit; | ||
510 | |||
511 | if (s_data->override_enable) { | ||
512 | /* write list of override regs for the asking frame length, */ | ||
513 | /* coarse integration time, and gain. */ | ||
514 | control.id = V4L2_CID_GAIN; | ||
515 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
516 | err |= ov23850_set_gain(priv, control.value); | ||
517 | if (err) | ||
518 | dev_dbg(&client->dev, "%s: error gain override\n", | ||
519 | __func__); | ||
520 | |||
521 | control.id = V4L2_CID_FRAME_LENGTH; | ||
522 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
523 | err |= ov23850_set_frame_length(priv, control.value); | ||
524 | if (err) | ||
525 | dev_dbg(&client->dev, | ||
526 | "%s: error frame length override\n", __func__); | ||
527 | |||
528 | control.id = V4L2_CID_COARSE_TIME; | ||
529 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
530 | err |= ov23850_set_coarse_time(priv, control.value); | ||
531 | if (err) | ||
532 | dev_dbg(&client->dev, | ||
533 | "%s: error coarse time override\n", __func__); | ||
534 | |||
535 | control.id = V4L2_CID_COARSE_TIME_SHORT; | ||
536 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
537 | err |= ov23850_set_coarse_time_short(priv, control.value); | ||
538 | if (err) | ||
539 | dev_dbg(&client->dev, | ||
540 | "%s: error coarse time short override\n", | ||
541 | __func__); | ||
542 | } | ||
543 | |||
544 | err = ov23850_write_table(priv, mode_table[OV23850_MODE_START_STREAM]); | ||
545 | if (err) | ||
546 | goto exit; | ||
547 | |||
548 | if (test_mode) | ||
549 | err = ov23850_write_table(priv, | ||
550 | mode_table[OV23850_MODE_TEST_PATTERN]); | ||
551 | |||
552 | return 0; | ||
553 | exit: | ||
554 | dev_dbg(&client->dev, "%s: error setting stream\n", __func__); | ||
555 | return err; | ||
556 | } | ||
557 | |||
558 | static int ov23850_g_input_status(struct v4l2_subdev *sd, u32 *status) | ||
559 | { | ||
560 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
561 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
562 | struct ov23850 *priv = (struct ov23850 *)s_data->priv; | ||
563 | struct camera_common_power_rail *pw = &priv->power; | ||
564 | |||
565 | *status = pw->state == SWITCH_ON; | ||
566 | return 0; | ||
567 | } | ||
568 | |||
569 | static struct v4l2_subdev_video_ops ov23850_subdev_video_ops = { | ||
570 | .s_stream = ov23850_s_stream, | ||
571 | .g_mbus_config = camera_common_g_mbus_config, | ||
572 | .g_input_status = ov23850_g_input_status, | ||
573 | }; | ||
574 | |||
575 | static struct v4l2_subdev_core_ops ov23850_subdev_core_ops = { | ||
576 | .s_power = camera_common_s_power, | ||
577 | }; | ||
578 | |||
579 | static int ov23850_get_fmt(struct v4l2_subdev *sd, | ||
580 | struct v4l2_subdev_pad_config *cfg, | ||
581 | struct v4l2_subdev_format *format) | ||
582 | { | ||
583 | return camera_common_g_fmt(sd, &format->format); | ||
584 | } | ||
585 | |||
586 | static int ov23850_set_fmt(struct v4l2_subdev *sd, | ||
587 | struct v4l2_subdev_pad_config *cfg, | ||
588 | struct v4l2_subdev_format *format) | ||
589 | { | ||
590 | int ret; | ||
591 | |||
592 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) | ||
593 | ret = camera_common_try_fmt(sd, &format->format); | ||
594 | else | ||
595 | ret = camera_common_s_fmt(sd, &format->format); | ||
596 | |||
597 | return ret; | ||
598 | } | ||
599 | |||
600 | static struct v4l2_subdev_pad_ops ov23850_subdev_pad_ops = { | ||
601 | .set_fmt = ov23850_set_fmt, | ||
602 | .get_fmt = ov23850_get_fmt, | ||
603 | .enum_mbus_code = camera_common_enum_mbus_code, | ||
604 | .enum_frame_size = camera_common_enum_framesizes, | ||
605 | .enum_frame_interval = camera_common_enum_frameintervals, | ||
606 | }; | ||
607 | |||
608 | static struct v4l2_subdev_ops ov23850_subdev_ops = { | ||
609 | .core = &ov23850_subdev_core_ops, | ||
610 | .video = &ov23850_subdev_video_ops, | ||
611 | .pad = &ov23850_subdev_pad_ops, | ||
612 | }; | ||
613 | |||
614 | const struct of_device_id ov23850_of_match[] = { | ||
615 | { .compatible = "nvidia,ov23850", }, | ||
616 | { }, | ||
617 | }; | ||
618 | |||
619 | static struct camera_common_sensor_ops ov23850_common_ops = { | ||
620 | .power_on = ov23850_power_on, | ||
621 | .power_off = ov23850_power_off, | ||
622 | .write_reg = ov23850_write_reg, | ||
623 | .read_reg = ov23850_read_reg, | ||
624 | }; | ||
625 | |||
626 | static int ov23850_set_group_hold(struct ov23850 *priv) | ||
627 | { | ||
628 | int err; | ||
629 | int gh_prev = switch_ctrl_qmenu[priv->group_hold_prev]; | ||
630 | |||
631 | if (priv->group_hold_en == true && gh_prev == SWITCH_OFF) { | ||
632 | err = ov23850_write_reg(priv->s_data, | ||
633 | OV23850_GROUP_HOLD_ADDR, 0x00); | ||
634 | if (err) | ||
635 | goto fail; | ||
636 | priv->group_hold_prev = 1; | ||
637 | } else if (priv->group_hold_en == false && gh_prev == SWITCH_ON) { | ||
638 | err = ov23850_write_reg(priv->s_data, | ||
639 | OV23850_GROUP_HOLD_ADDR, 0x10); | ||
640 | err |= ov23850_write_reg(priv->s_data, | ||
641 | OV23850_GROUP_HOLD_ADDR, 0xE0); | ||
642 | if (err) | ||
643 | goto fail; | ||
644 | priv->group_hold_prev = 0; | ||
645 | } | ||
646 | |||
647 | return 0; | ||
648 | |||
649 | fail: | ||
650 | dev_dbg(&priv->i2c_client->dev, | ||
651 | "%s: Group hold control error\n", __func__); | ||
652 | return err; | ||
653 | } | ||
654 | |||
655 | static int ov23850_set_gain(struct ov23850 *priv, s32 val) | ||
656 | { | ||
657 | ov23850_reg reg_list[2]; | ||
658 | ov23850_reg reg_list_short[2]; | ||
659 | int err; | ||
660 | u16 gain; | ||
661 | int i = 0; | ||
662 | |||
663 | /* translate value */ | ||
664 | gain = ov23850_to_gain((u32)val, OV23850_GAIN_SHIFT); | ||
665 | |||
666 | dev_dbg(&priv->i2c_client->dev, | ||
667 | "%s: val: %d\n", __func__, gain); | ||
668 | |||
669 | ov23850_get_gain_reg(reg_list, gain); | ||
670 | ov23850_get_gain_short_reg(reg_list_short, gain); | ||
671 | ov23850_set_group_hold(priv); | ||
672 | |||
673 | /* writing long gain */ | ||
674 | for (i = 0; i < 2; i++) { | ||
675 | err = ov23850_write_reg(priv->s_data, reg_list[i].addr, | ||
676 | reg_list[i].val); | ||
677 | if (err) | ||
678 | goto fail; | ||
679 | } | ||
680 | /* writing short gain */ | ||
681 | for (i = 0; i < 2; i++) { | ||
682 | err = ov23850_write_reg(priv->s_data, reg_list_short[i].addr, | ||
683 | reg_list_short[i].val); | ||
684 | if (err) | ||
685 | goto fail; | ||
686 | } | ||
687 | |||
688 | return 0; | ||
689 | |||
690 | fail: | ||
691 | dev_dbg(&priv->i2c_client->dev, | ||
692 | "%s: GAIN control error\n", __func__); | ||
693 | return err; | ||
694 | } | ||
695 | |||
696 | static int ov23850_set_frame_length(struct ov23850 *priv, s32 val) | ||
697 | { | ||
698 | ov23850_reg reg_list[2]; | ||
699 | int err; | ||
700 | u32 frame_length; | ||
701 | int i = 0; | ||
702 | |||
703 | frame_length = val; | ||
704 | |||
705 | dev_dbg(&priv->i2c_client->dev, | ||
706 | "%s: val: %d\n", __func__, frame_length); | ||
707 | |||
708 | ov23850_get_frame_length_regs(reg_list, frame_length); | ||
709 | ov23850_set_group_hold(priv); | ||
710 | |||
711 | for (i = 0; i < 2; i++) { | ||
712 | err = ov23850_write_reg(priv->s_data, reg_list[i].addr, | ||
713 | reg_list[i].val); | ||
714 | if (err) | ||
715 | goto fail; | ||
716 | } | ||
717 | |||
718 | priv->frame_length = frame_length; | ||
719 | |||
720 | return 0; | ||
721 | |||
722 | fail: | ||
723 | dev_dbg(&priv->i2c_client->dev, | ||
724 | "%s: FRAME_LENGTH control error\n", __func__); | ||
725 | return err; | ||
726 | } | ||
727 | |||
728 | static int ov23850_set_coarse_time(struct ov23850 *priv, s32 val) | ||
729 | { | ||
730 | ov23850_reg reg_list[2]; | ||
731 | int err; | ||
732 | u32 coarse_time; | ||
733 | int i = 0; | ||
734 | |||
735 | coarse_time = val; | ||
736 | |||
737 | dev_dbg(&priv->i2c_client->dev, | ||
738 | "%s: val: %d\n", __func__, coarse_time); | ||
739 | |||
740 | ov23850_get_coarse_time_regs(reg_list, coarse_time); | ||
741 | ov23850_set_group_hold(priv); | ||
742 | |||
743 | for (i = 0; i < 2; i++) { | ||
744 | err = ov23850_write_reg(priv->s_data, reg_list[i].addr, | ||
745 | reg_list[i].val); | ||
746 | if (err) | ||
747 | goto fail; | ||
748 | } | ||
749 | |||
750 | return 0; | ||
751 | |||
752 | fail: | ||
753 | dev_dbg(&priv->i2c_client->dev, | ||
754 | "%s: COARSE_TIME control error\n", __func__); | ||
755 | return err; | ||
756 | } | ||
757 | |||
758 | static int ov23850_set_coarse_time_short(struct ov23850 *priv, s32 val) | ||
759 | { | ||
760 | ov23850_reg reg_list[2]; | ||
761 | int err; | ||
762 | struct v4l2_control hdr_control; | ||
763 | int hdr_en; | ||
764 | u32 coarse_time_short; | ||
765 | int i = 0; | ||
766 | |||
767 | /* check hdr enable ctrl */ | ||
768 | hdr_control.id = V4L2_CID_HDR_EN; | ||
769 | |||
770 | err = camera_common_g_ctrl(priv->s_data, &hdr_control); | ||
771 | if (err < 0) { | ||
772 | dev_err(&priv->i2c_client->dev, | ||
773 | "could not find device ctrl.\n"); | ||
774 | return err; | ||
775 | } | ||
776 | |||
777 | hdr_en = switch_ctrl_qmenu[hdr_control.value]; | ||
778 | if (hdr_en == SWITCH_OFF) | ||
779 | return 0; | ||
780 | |||
781 | coarse_time_short = val; | ||
782 | |||
783 | dev_dbg(&priv->i2c_client->dev, | ||
784 | "%s: val: %d\n", __func__, coarse_time_short); | ||
785 | |||
786 | ov23850_get_coarse_time_short_regs(reg_list, coarse_time_short); | ||
787 | ov23850_set_group_hold(priv); | ||
788 | |||
789 | for (i = 0; i < 2; i++) { | ||
790 | err = ov23850_write_reg(priv->s_data, reg_list[i].addr, | ||
791 | reg_list[i].val); | ||
792 | if (err) | ||
793 | goto fail; | ||
794 | } | ||
795 | |||
796 | return 0; | ||
797 | |||
798 | fail: | ||
799 | dev_dbg(&priv->i2c_client->dev, | ||
800 | "%s: COARSE_TIME_SHORT control error\n", __func__); | ||
801 | return err; | ||
802 | } | ||
803 | |||
804 | #if 0 | ||
805 | static int ov23850_eeprom_device_release(struct ov23850 *priv) | ||
806 | { | ||
807 | int i; | ||
808 | |||
809 | for (i = 0; i < OV23850_EEPROM_NUM_BLOCKS; i++) { | ||
810 | if (priv->eeprom[i].i2c_client != NULL) { | ||
811 | i2c_unregister_device(priv->eeprom[i].i2c_client); | ||
812 | priv->eeprom[i].i2c_client = NULL; | ||
813 | } | ||
814 | } | ||
815 | |||
816 | return 0; | ||
817 | } | ||
818 | |||
819 | static int ov23850_eeprom_device_init(struct ov23850 *priv) | ||
820 | { | ||
821 | char *dev_name = "eeprom_ov23850"; | ||
822 | static struct regmap_config eeprom_regmap_config = { | ||
823 | .reg_bits = 8, | ||
824 | .val_bits = 8, | ||
825 | }; | ||
826 | int i; | ||
827 | int err; | ||
828 | |||
829 | for (i = 0; i < OV23850_EEPROM_NUM_BLOCKS; i++) { | ||
830 | priv->eeprom[i].adap = i2c_get_adapter( | ||
831 | priv->i2c_client->adapter->nr); | ||
832 | memset(&priv->eeprom[i].brd, 0, sizeof(priv->eeprom[i].brd)); | ||
833 | strncpy(priv->eeprom[i].brd.type, dev_name, | ||
834 | sizeof(priv->eeprom[i].brd.type)); | ||
835 | priv->eeprom[i].brd.addr = OV23850_EEPROM_ADDRESS + i; | ||
836 | priv->eeprom[i].i2c_client = i2c_new_device( | ||
837 | priv->eeprom[i].adap, &priv->eeprom[i].brd); | ||
838 | |||
839 | priv->eeprom[i].regmap = devm_regmap_init_i2c( | ||
840 | priv->eeprom[i].i2c_client, &eeprom_regmap_config); | ||
841 | if (IS_ERR(priv->eeprom[i].regmap)) { | ||
842 | err = PTR_ERR(priv->eeprom[i].regmap); | ||
843 | ov23850_eeprom_device_release(priv); | ||
844 | return err; | ||
845 | } | ||
846 | } | ||
847 | |||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | static int ov23850_read_eeprom(struct ov23850 *priv, | ||
852 | struct v4l2_ctrl *ctrl) | ||
853 | { | ||
854 | int err, i; | ||
855 | |||
856 | for (i = 0; i < OV23850_EEPROM_NUM_BLOCKS; i++) { | ||
857 | err = regmap_bulk_read(priv->eeprom[i].regmap, 0, | ||
858 | &priv->eeprom_buf[i * OV23850_EEPROM_BLOCK_SIZE], | ||
859 | OV23850_EEPROM_BLOCK_SIZE); | ||
860 | if (err) | ||
861 | return err; | ||
862 | } | ||
863 | |||
864 | for (i = 0; i < OV23850_EEPROM_SIZE; i++) | ||
865 | sprintf(&ctrl->p_new.p_char[i*2], "%02x", | ||
866 | priv->eeprom_buf[i]); | ||
867 | return 0; | ||
868 | } | ||
869 | |||
870 | static int ov23850_write_eeprom(struct ov23850 *priv, | ||
871 | char *string) | ||
872 | { | ||
873 | int err; | ||
874 | int i; | ||
875 | u8 curr[3]; | ||
876 | unsigned long data; | ||
877 | |||
878 | for (i = 0; i < OV23850_EEPROM_SIZE; i++) { | ||
879 | curr[0] = string[i*2]; | ||
880 | curr[1] = string[i*2+1]; | ||
881 | curr[2] = '\0'; | ||
882 | |||
883 | err = kstrtol(curr, 16, &data); | ||
884 | if (err) { | ||
885 | dev_err(&priv->i2c_client->dev, | ||
886 | "invalid eeprom string\n"); | ||
887 | return -EINVAL; | ||
888 | } | ||
889 | |||
890 | priv->eeprom_buf[i] = (u8)data; | ||
891 | err = regmap_write(priv->eeprom[i >> 8].regmap, | ||
892 | i & 0xFF, (u8)data); | ||
893 | if (err) | ||
894 | return err; | ||
895 | msleep(20); | ||
896 | } | ||
897 | return 0; | ||
898 | } | ||
899 | #endif | ||
900 | |||
901 | static int ov23850_read_otp_manual(struct ov23850 *priv, | ||
902 | u8 *buf, u16 addr_start, u16 addr_end) | ||
903 | { | ||
904 | u8 status; | ||
905 | int i; | ||
906 | int err; | ||
907 | int size = addr_end - addr_start + 1; | ||
908 | u8 isp; | ||
909 | u16 addr_start_capped = addr_start; | ||
910 | |||
911 | if (addr_start > 0x6A00) | ||
912 | addr_start_capped = 0x69FF; | ||
913 | |||
914 | usleep_range(10000, 11000); | ||
915 | err = ov23850_write_table(priv, mode_table[OV23850_MODE_START_STREAM]); | ||
916 | if (err) | ||
917 | return err; | ||
918 | |||
919 | err = ov23850_read_reg(priv->s_data, OV23850_OTP_ISP_CTRL_ADDR, &isp); | ||
920 | if (err) | ||
921 | return err; | ||
922 | err = ov23850_write_reg(priv->s_data, OV23850_OTP_ISP_CTRL_ADDR, | ||
923 | isp & 0xfe); | ||
924 | if (err) | ||
925 | return err; | ||
926 | |||
927 | err = ov23850_write_reg(priv->s_data, OV23850_OTP_MODE_CTRL_ADDR, 0x40); | ||
928 | if (err) | ||
929 | return err; | ||
930 | |||
931 | |||
932 | err = ov23850_write_reg(priv->s_data, OV23850_OTP_START_REG_ADDR_MSB, | ||
933 | (addr_start_capped >> 8) & 0xff); | ||
934 | if (err) | ||
935 | return err; | ||
936 | err = ov23850_write_reg(priv->s_data, OV23850_OTP_START_REG_ADDR_LSB, | ||
937 | addr_start_capped & 0xff); | ||
938 | if (err) | ||
939 | return err; | ||
940 | |||
941 | err = ov23850_write_reg(priv->s_data, OV23850_OTP_END_REG_ADDR_MSB, | ||
942 | (addr_end >> 8) & 0xff); | ||
943 | if (err) | ||
944 | return err; | ||
945 | err = ov23850_write_reg(priv->s_data, OV23850_OTP_END_REG_ADDR_LSB, | ||
946 | addr_end & 0xff); | ||
947 | if (err) | ||
948 | return err; | ||
949 | |||
950 | err = ov23850_write_reg(priv->s_data, OV23850_OTP_LOAD_CTRL_ADDR, 0x01); | ||
951 | if (err) | ||
952 | return err; | ||
953 | |||
954 | usleep_range(10000, 11000); | ||
955 | for (i = 0; i < size; i++) { | ||
956 | err = ov23850_read_reg(priv->s_data, addr_start + i, &buf[i]); | ||
957 | if (err) | ||
958 | return err; | ||
959 | |||
960 | err = ov23850_read_reg(priv->s_data, | ||
961 | OV23850_OTP_LOAD_CTRL_ADDR, &status); | ||
962 | if (err) | ||
963 | return err; | ||
964 | |||
965 | if (status & OV23850_OTP_RD_BUSY_MASK) { | ||
966 | dev_err(&priv->i2c_client->dev, | ||
967 | "another OTP read in progress\n"); | ||
968 | return err; | ||
969 | } else if (status & OV23850_OTP_BIST_ERROR_MASK) { | ||
970 | dev_err(&priv->i2c_client->dev, "fuse id read error\n"); | ||
971 | return err; | ||
972 | } | ||
973 | } | ||
974 | |||
975 | err = ov23850_write_table(priv, | ||
976 | mode_table[OV23850_MODE_STOP_STREAM]); | ||
977 | if (err) | ||
978 | return err; | ||
979 | |||
980 | err = ov23850_read_reg(priv->s_data, OV23850_OTP_ISP_CTRL_ADDR, &isp); | ||
981 | if (err) | ||
982 | return err; | ||
983 | err = ov23850_write_reg(priv->s_data, OV23850_OTP_ISP_CTRL_ADDR, | ||
984 | isp | 0x01); | ||
985 | if (err) | ||
986 | return err; | ||
987 | |||
988 | return 0; | ||
989 | } | ||
990 | |||
991 | static int ov23850_otp_setup(struct ov23850 *priv) | ||
992 | { | ||
993 | int err; | ||
994 | int i; | ||
995 | struct v4l2_ctrl *ctrl; | ||
996 | u8 otp_buf[OV23850_OTP_SIZE]; | ||
997 | |||
998 | err = camera_common_s_power(priv->subdev, true); | ||
999 | if (err) | ||
1000 | return -ENODEV; | ||
1001 | |||
1002 | err = ov23850_read_otp_manual(priv, | ||
1003 | otp_buf, | ||
1004 | OV23850_OTP_START_ADDR, | ||
1005 | OV23850_OTP_END_ADDR); | ||
1006 | if (err) | ||
1007 | return -ENODEV; | ||
1008 | |||
1009 | ctrl = v4l2_ctrl_find(&priv->ctrl_handler, V4L2_CID_OTP_DATA); | ||
1010 | if (!ctrl) { | ||
1011 | dev_err(&priv->i2c_client->dev, | ||
1012 | "could not find device ctrl.\n"); | ||
1013 | return -EINVAL; | ||
1014 | } | ||
1015 | |||
1016 | for (i = 0; i < OV23850_OTP_SIZE; i++) | ||
1017 | sprintf(&ctrl->p_new.p_char[i*2], "%02x", | ||
1018 | otp_buf[i]); | ||
1019 | ctrl->p_cur.p_char = ctrl->p_new.p_char; | ||
1020 | |||
1021 | err = camera_common_s_power(priv->subdev, false); | ||
1022 | if (err) | ||
1023 | return -ENODEV; | ||
1024 | |||
1025 | return 0; | ||
1026 | } | ||
1027 | |||
1028 | static int ov23850_fuse_id_setup(struct ov23850 *priv) | ||
1029 | { | ||
1030 | int err; | ||
1031 | int i; | ||
1032 | struct v4l2_ctrl *ctrl; | ||
1033 | u8 fuse_id[OV23850_FUSE_ID_SIZE]; | ||
1034 | |||
1035 | err = camera_common_s_power(priv->subdev, true); | ||
1036 | if (err) | ||
1037 | return -ENODEV; | ||
1038 | |||
1039 | err = ov23850_read_otp_manual(priv, | ||
1040 | fuse_id, | ||
1041 | OV23850_FUSE_ID_OTP_START_ADDR, | ||
1042 | OV23850_FUSE_ID_OTP_END_ADDR); | ||
1043 | if (err) | ||
1044 | return -ENODEV; | ||
1045 | |||
1046 | ctrl = v4l2_ctrl_find(&priv->ctrl_handler, V4L2_CID_FUSE_ID); | ||
1047 | if (!ctrl) { | ||
1048 | dev_err(&priv->i2c_client->dev, | ||
1049 | "could not find device ctrl.\n"); | ||
1050 | return -EINVAL; | ||
1051 | } | ||
1052 | |||
1053 | for (i = 0; i < OV23850_FUSE_ID_SIZE; i++) | ||
1054 | sprintf(&ctrl->p_new.p_char[i*2], "%02x", | ||
1055 | fuse_id[i]); | ||
1056 | ctrl->p_cur.p_char = ctrl->p_new.p_char; | ||
1057 | |||
1058 | err = camera_common_s_power(priv->subdev, false); | ||
1059 | if (err) | ||
1060 | return -ENODEV; | ||
1061 | |||
1062 | return 0; | ||
1063 | } | ||
1064 | |||
1065 | static int ov23850_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | ||
1066 | { | ||
1067 | struct ov23850 *priv = | ||
1068 | container_of(ctrl->handler, struct ov23850, ctrl_handler); | ||
1069 | int err = 0; | ||
1070 | |||
1071 | if (priv->power.state == SWITCH_OFF) | ||
1072 | return 0; | ||
1073 | |||
1074 | switch (ctrl->id) { | ||
1075 | case V4L2_CID_EEPROM_DATA: | ||
1076 | #if 0 | ||
1077 | err = ov23850_read_eeprom(priv, ctrl); | ||
1078 | if (err) | ||
1079 | return err; | ||
1080 | #endif | ||
1081 | break; | ||
1082 | default: | ||
1083 | pr_err("%s: unknown ctrl id.\n", __func__); | ||
1084 | return -EINVAL; | ||
1085 | } | ||
1086 | |||
1087 | return err; | ||
1088 | } | ||
1089 | |||
1090 | static int ov23850_s_ctrl(struct v4l2_ctrl *ctrl) | ||
1091 | { | ||
1092 | struct ov23850 *priv = | ||
1093 | container_of(ctrl->handler, struct ov23850, ctrl_handler); | ||
1094 | int err = 0; | ||
1095 | |||
1096 | if (priv->power.state == SWITCH_OFF) | ||
1097 | return 0; | ||
1098 | |||
1099 | switch (ctrl->id) { | ||
1100 | case V4L2_CID_GAIN: | ||
1101 | err = ov23850_set_gain(priv, ctrl->val); | ||
1102 | break; | ||
1103 | case V4L2_CID_FRAME_LENGTH: | ||
1104 | err = ov23850_set_frame_length(priv, ctrl->val); | ||
1105 | break; | ||
1106 | case V4L2_CID_COARSE_TIME: | ||
1107 | err = ov23850_set_coarse_time(priv, ctrl->val); | ||
1108 | break; | ||
1109 | case V4L2_CID_COARSE_TIME_SHORT: | ||
1110 | err = ov23850_set_coarse_time_short(priv, ctrl->val); | ||
1111 | break; | ||
1112 | case V4L2_CID_GROUP_HOLD: | ||
1113 | if (switch_ctrl_qmenu[ctrl->val] == SWITCH_ON) { | ||
1114 | priv->group_hold_en = true; | ||
1115 | } else { | ||
1116 | priv->group_hold_en = false; | ||
1117 | err = ov23850_set_group_hold(priv); | ||
1118 | } | ||
1119 | break; | ||
1120 | case V4L2_CID_EEPROM_DATA: | ||
1121 | #if 0 | ||
1122 | if (!ctrl->p_new.p_char[0]) | ||
1123 | break; | ||
1124 | err = ov23850_write_eeprom(priv, ctrl->p_new.p_char); | ||
1125 | if (err) | ||
1126 | return err; | ||
1127 | #endif | ||
1128 | break; | ||
1129 | case V4L2_CID_HDR_EN: | ||
1130 | break; | ||
1131 | default: | ||
1132 | pr_err("%s: unknown ctrl id.\n", __func__); | ||
1133 | return -EINVAL; | ||
1134 | } | ||
1135 | |||
1136 | return err; | ||
1137 | } | ||
1138 | |||
1139 | static int ov23850_ctrls_init(struct ov23850 *priv) | ||
1140 | { | ||
1141 | struct i2c_client *client = priv->i2c_client; | ||
1142 | struct v4l2_ctrl *ctrl; | ||
1143 | int numctrls; | ||
1144 | int err; | ||
1145 | int i; | ||
1146 | |||
1147 | dev_dbg(&client->dev, "%s++\n", __func__); | ||
1148 | |||
1149 | numctrls = ARRAY_SIZE(ctrl_config_list); | ||
1150 | v4l2_ctrl_handler_init(&priv->ctrl_handler, numctrls); | ||
1151 | |||
1152 | for (i = 0; i < numctrls; i++) { | ||
1153 | ctrl = v4l2_ctrl_new_custom(&priv->ctrl_handler, | ||
1154 | &ctrl_config_list[i], NULL); | ||
1155 | if (ctrl == NULL) { | ||
1156 | dev_err(&client->dev, "Failed to init %s ctrl\n", | ||
1157 | ctrl_config_list[i].name); | ||
1158 | continue; | ||
1159 | } | ||
1160 | |||
1161 | if (ctrl_config_list[i].type == V4L2_CTRL_TYPE_STRING && | ||
1162 | ctrl_config_list[i].flags & V4L2_CTRL_FLAG_READ_ONLY) { | ||
1163 | ctrl->p_new.p_char = devm_kzalloc(&client->dev, | ||
1164 | ctrl_config_list[i].max + 1, GFP_KERNEL); | ||
1165 | } | ||
1166 | priv->ctrls[i] = ctrl; | ||
1167 | } | ||
1168 | |||
1169 | priv->numctrls = numctrls; | ||
1170 | priv->subdev->ctrl_handler = &priv->ctrl_handler; | ||
1171 | if (priv->ctrl_handler.error) { | ||
1172 | dev_err(&client->dev, "Error %d adding controls\n", | ||
1173 | priv->ctrl_handler.error); | ||
1174 | err = priv->ctrl_handler.error; | ||
1175 | goto error; | ||
1176 | } | ||
1177 | |||
1178 | err = v4l2_ctrl_handler_setup(&priv->ctrl_handler); | ||
1179 | if (err) { | ||
1180 | dev_err(&client->dev, | ||
1181 | "Error %d setting default controls\n", err); | ||
1182 | goto error; | ||
1183 | } | ||
1184 | |||
1185 | err = ov23850_otp_setup(priv); | ||
1186 | if (err) { | ||
1187 | dev_err(&client->dev, | ||
1188 | "Error %d reading otp data\n", err); | ||
1189 | goto error; | ||
1190 | } | ||
1191 | |||
1192 | err = ov23850_fuse_id_setup(priv); | ||
1193 | if (err) { | ||
1194 | dev_err(&client->dev, | ||
1195 | "Error %d reading fuse id data\n", err); | ||
1196 | goto error; | ||
1197 | } | ||
1198 | |||
1199 | return 0; | ||
1200 | |||
1201 | error: | ||
1202 | v4l2_ctrl_handler_free(&priv->ctrl_handler); | ||
1203 | return err; | ||
1204 | } | ||
1205 | |||
1206 | MODULE_DEVICE_TABLE(of, ov23850_of_match); | ||
1207 | |||
1208 | static struct camera_common_pdata *ov23850_parse_dt(struct i2c_client *client) | ||
1209 | { | ||
1210 | struct device_node *np = client->dev.of_node; | ||
1211 | struct camera_common_pdata *board_priv_pdata; | ||
1212 | const struct of_device_id *match; | ||
1213 | int gpio; | ||
1214 | int err; | ||
1215 | |||
1216 | match = of_match_device(ov23850_of_match, &client->dev); | ||
1217 | if (!match) { | ||
1218 | dev_err(&client->dev, "Failed to find matching dt id\n"); | ||
1219 | return NULL; | ||
1220 | } | ||
1221 | |||
1222 | board_priv_pdata = devm_kzalloc(&client->dev, | ||
1223 | sizeof(*board_priv_pdata), GFP_KERNEL); | ||
1224 | |||
1225 | err = of_property_read_string(np, "mclk", | ||
1226 | &board_priv_pdata->mclk_name); | ||
1227 | if (err) { | ||
1228 | dev_err(&client->dev, "mclk not in DT\n"); | ||
1229 | goto error; | ||
1230 | } | ||
1231 | |||
1232 | gpio = of_get_named_gpio(np, "pwdn-gpios", 0); | ||
1233 | if (gpio < 0) { | ||
1234 | dev_err(&client->dev, "pwdn gpios not in DT\n"); | ||
1235 | goto error; | ||
1236 | } | ||
1237 | board_priv_pdata->pwdn_gpio = (unsigned int)gpio; | ||
1238 | |||
1239 | gpio = of_get_named_gpio(np, "reset-gpios", 0); | ||
1240 | if (gpio < 0) { | ||
1241 | dev_err(&client->dev, "reset gpios not in DT\n"); | ||
1242 | goto error; | ||
1243 | } | ||
1244 | board_priv_pdata->reset_gpio = (unsigned int)gpio; | ||
1245 | |||
1246 | err = of_property_read_string(np, "avdd-reg", | ||
1247 | &board_priv_pdata->regulators.avdd); | ||
1248 | if (err) { | ||
1249 | dev_err(&client->dev, "avdd-reg not in DT\n"); | ||
1250 | goto error; | ||
1251 | } | ||
1252 | err = of_property_read_string(np, "dvdd-reg", | ||
1253 | &board_priv_pdata->regulators.dvdd); | ||
1254 | if (err) { | ||
1255 | dev_err(&client->dev, "dvdd-reg not in DT\n"); | ||
1256 | goto error; | ||
1257 | } | ||
1258 | err = of_property_read_string(np, "iovdd-reg", | ||
1259 | &board_priv_pdata->regulators.iovdd); | ||
1260 | if (err) { | ||
1261 | dev_err(&client->dev, "iovdd-reg not in DT\n"); | ||
1262 | goto error; | ||
1263 | } | ||
1264 | err = of_property_read_string(np, "vcmvdd-reg", | ||
1265 | &board_priv_pdata->regulators.vcmvdd); | ||
1266 | if (err) { | ||
1267 | dev_err(&client->dev, "vcmdd-reg not in DT\n"); | ||
1268 | goto error; | ||
1269 | } | ||
1270 | |||
1271 | return board_priv_pdata; | ||
1272 | |||
1273 | error: | ||
1274 | devm_kfree(&client->dev, board_priv_pdata); | ||
1275 | return NULL; | ||
1276 | } | ||
1277 | |||
1278 | static int ov23850_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
1279 | { | ||
1280 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1281 | |||
1282 | dev_dbg(&client->dev, "%s:\n", __func__); | ||
1283 | return 0; | ||
1284 | } | ||
1285 | |||
1286 | static const struct v4l2_subdev_internal_ops ov23850_subdev_internal_ops = { | ||
1287 | .open = ov23850_open, | ||
1288 | }; | ||
1289 | |||
1290 | static const struct media_entity_operations ov23850_media_ops = { | ||
1291 | .link_validate = v4l2_subdev_link_validate, | ||
1292 | }; | ||
1293 | |||
1294 | static int ov23850_probe(struct i2c_client *client, | ||
1295 | const struct i2c_device_id *id) | ||
1296 | { | ||
1297 | struct camera_common_data *common_data; | ||
1298 | struct ov23850 *priv; | ||
1299 | char debugfs_name[10]; | ||
1300 | int err; | ||
1301 | |||
1302 | pr_info("[OV23850]: probing v4l2 sensor at addr 0x%0x.\n", | ||
1303 | client->addr); | ||
1304 | |||
1305 | common_data = devm_kzalloc(&client->dev, | ||
1306 | sizeof(struct camera_common_data), GFP_KERNEL); | ||
1307 | |||
1308 | priv = devm_kzalloc(&client->dev, | ||
1309 | sizeof(struct ov23850) + sizeof(struct v4l2_ctrl *) | ||
1310 | * ARRAY_SIZE(ctrl_config_list), GFP_KERNEL); | ||
1311 | |||
1312 | priv->regmap = devm_regmap_init_i2c(client, &sensor_regmap_config); | ||
1313 | if (IS_ERR(priv->regmap)) { | ||
1314 | dev_err(&client->dev, | ||
1315 | "regmap init failed: %ld\n", PTR_ERR(priv->regmap)); | ||
1316 | return -ENODEV; | ||
1317 | } | ||
1318 | |||
1319 | |||
1320 | priv->pdata = ov23850_parse_dt(client); | ||
1321 | if (!priv->pdata) { | ||
1322 | dev_err(&client->dev, "unable to get platform data\n"); | ||
1323 | return -EFAULT; | ||
1324 | } | ||
1325 | |||
1326 | common_data->ops = &ov23850_common_ops; | ||
1327 | common_data->ctrl_handler = &priv->ctrl_handler; | ||
1328 | common_data->i2c_client = client; | ||
1329 | common_data->frmfmt = &ov23850_frmfmt[0]; | ||
1330 | common_data->colorfmt = camera_common_find_datafmt( | ||
1331 | OV23850_DEFAULT_DATAFMT); | ||
1332 | common_data->power = &priv->power; | ||
1333 | common_data->ctrls = priv->ctrls; | ||
1334 | common_data->priv = (void *)priv; | ||
1335 | common_data->numctrls = ARRAY_SIZE(ctrl_config_list); | ||
1336 | common_data->numfmts = ARRAY_SIZE(ov23850_frmfmt); | ||
1337 | common_data->def_mode = OV23850_DEFAULT_MODE; | ||
1338 | common_data->def_width = OV23850_DEFAULT_WIDTH; | ||
1339 | common_data->def_height = OV23850_DEFAULT_HEIGHT; | ||
1340 | common_data->fmt_width = common_data->def_width; | ||
1341 | common_data->fmt_height = common_data->def_height; | ||
1342 | common_data->def_clk_freq = OV23850_DEFAULT_CLK_FREQ; | ||
1343 | |||
1344 | priv->i2c_client = client; | ||
1345 | priv->s_data = common_data; | ||
1346 | priv->subdev = &common_data->subdev; | ||
1347 | priv->subdev->dev = &client->dev; | ||
1348 | priv->s_data->dev = &client->dev; | ||
1349 | priv->group_hold_prev = 0; | ||
1350 | |||
1351 | err = ov23850_power_get(priv); | ||
1352 | if (err) | ||
1353 | return err; | ||
1354 | |||
1355 | err = camera_common_parse_ports(client, common_data); | ||
1356 | if (err) { | ||
1357 | dev_err(&client->dev, "Failed to find port info\n"); | ||
1358 | return err; | ||
1359 | } | ||
1360 | sprintf(debugfs_name, "ov23850_%c", common_data->csi_port + 'a'); | ||
1361 | dev_dbg(&client->dev, "%s: dt node name %s\n", __func__, debugfs_name); | ||
1362 | camera_common_create_debugfs(common_data, debugfs_name); | ||
1363 | |||
1364 | v4l2_i2c_subdev_init(&common_data->subdev, client, | ||
1365 | &ov23850_subdev_ops); | ||
1366 | |||
1367 | err = ov23850_ctrls_init(priv); | ||
1368 | if (err) | ||
1369 | return err; | ||
1370 | |||
1371 | #if 0 | ||
1372 | /* eeprom interface */ | ||
1373 | err = ov23850_eeprom_device_init(priv); | ||
1374 | if (err) | ||
1375 | dev_err(&client->dev, | ||
1376 | "Failed to allocate eeprom register map: %d\n", err); | ||
1377 | #endif | ||
1378 | |||
1379 | priv->subdev->internal_ops = &ov23850_subdev_internal_ops; | ||
1380 | priv->subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | | ||
1381 | V4L2_SUBDEV_FL_HAS_EVENTS; | ||
1382 | |||
1383 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
1384 | priv->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
1385 | priv->subdev->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; | ||
1386 | priv->subdev->entity.ops = &ov23850_media_ops; | ||
1387 | err = media_entity_init(&priv->subdev->entity, 1, &priv->pad, 0); | ||
1388 | if (err < 0) { | ||
1389 | dev_err(&client->dev, "unable to init media entity\n"); | ||
1390 | return err; | ||
1391 | } | ||
1392 | #endif | ||
1393 | |||
1394 | err = v4l2_async_register_subdev(priv->subdev); | ||
1395 | if (err) | ||
1396 | return err; | ||
1397 | |||
1398 | dev_info(&client->dev, "Detected OV23850 sensor\n"); | ||
1399 | |||
1400 | return 0; | ||
1401 | } | ||
1402 | |||
1403 | static int | ||
1404 | ov23850_remove(struct i2c_client *client) | ||
1405 | { | ||
1406 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
1407 | struct ov23850 *priv = (struct ov23850 *)s_data->priv; | ||
1408 | |||
1409 | v4l2_async_unregister_subdev(priv->subdev); | ||
1410 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
1411 | media_entity_cleanup(&priv->subdev->entity); | ||
1412 | #endif | ||
1413 | v4l2_ctrl_handler_free(&priv->ctrl_handler); | ||
1414 | ov23850_power_put(priv); | ||
1415 | camera_common_remove_debugfs(s_data); | ||
1416 | |||
1417 | return 0; | ||
1418 | } | ||
1419 | |||
1420 | static const struct i2c_device_id ov23850_id[] = { | ||
1421 | { "ov23850", 0 }, | ||
1422 | { } | ||
1423 | }; | ||
1424 | |||
1425 | MODULE_DEVICE_TABLE(i2c, ov23850_id); | ||
1426 | |||
1427 | static struct i2c_driver ov23850_i2c_driver = { | ||
1428 | .driver = { | ||
1429 | .name = "ov23850", | ||
1430 | .owner = THIS_MODULE, | ||
1431 | .of_match_table = of_match_ptr(ov23850_of_match), | ||
1432 | }, | ||
1433 | .probe = ov23850_probe, | ||
1434 | .remove = ov23850_remove, | ||
1435 | .id_table = ov23850_id, | ||
1436 | }; | ||
1437 | |||
1438 | module_i2c_driver(ov23850_i2c_driver); | ||
1439 | |||
1440 | MODULE_DESCRIPTION("I2C driver for OmniVision OV23850"); | ||
1441 | MODULE_AUTHOR("David Wang <davidw@nvidia.com>"); | ||
1442 | MODULE_LICENSE("GPL v2"); | ||
1443 | |||
diff --git a/drivers/media/i2c/ov23850_mode_tbls.h b/drivers/media/i2c/ov23850_mode_tbls.h new file mode 100644 index 000000000..350aae19d --- /dev/null +++ b/drivers/media/i2c/ov23850_mode_tbls.h | |||
@@ -0,0 +1,4094 @@ | |||
1 | /* | ||
2 | * ov23850.c - ov23850 sensor driver | ||
3 | * | ||
4 | * Copyright (c) 2015-2016, NVIDIA CORPORATION, All Rights Reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http: | ||
17 | */ | ||
18 | |||
19 | #include <media/camera_common.h> | ||
20 | |||
21 | #ifndef __OV23850_I2C_TABLES__ | ||
22 | #define __OV23850_I2C_TABLES__ | ||
23 | |||
24 | #define OV23850_TABLE_WAIT_MS 0 | ||
25 | #define OV23850_TABLE_END 1 | ||
26 | #define OV23850_MAX_RETRIES 3 | ||
27 | #define OV23850_WAIT_MS 3 | ||
28 | |||
29 | #define ov23850_reg struct reg_8 | ||
30 | |||
31 | static ov23850_reg ov23850_start[] = { | ||
32 | { 0x0100, 0x01 }, /* mode select streaming on */ | ||
33 | { OV23850_TABLE_END, 0x00 } | ||
34 | }; | ||
35 | |||
36 | static ov23850_reg ov23850_stop[] = { | ||
37 | { 0x0100, 0x00 }, /* mode select streaming off */ | ||
38 | { OV23850_TABLE_END, 0x00 } | ||
39 | }; | ||
40 | |||
41 | static ov23850_reg tp_colorbars[] = { | ||
42 | {0x0600, 0x00}, | ||
43 | {0x0601, 0x02}, | ||
44 | |||
45 | {OV23850_TABLE_WAIT_MS, OV23850_WAIT_MS}, | ||
46 | {OV23850_TABLE_END, 0x00} | ||
47 | }; | ||
48 | |||
49 | static ov23850_reg mode_5632x4224_20fps[] = { | ||
50 | {0x0316, 0x1e}, | ||
51 | {0x0317, 0x00}, | ||
52 | {0x0318, 0x03}, | ||
53 | {0x031c, 0x01}, | ||
54 | {0x031d, 0x02}, | ||
55 | {0x031e, 0x09}, | ||
56 | {0x2b05, 0x02}, | ||
57 | {0x2b06, 0x87}, | ||
58 | {0x2b07, 0x01}, | ||
59 | {0x2b08, 0xa8}, | ||
60 | {0x0320, 0x02}, | ||
61 | {0x3002, 0x00}, | ||
62 | {0x300f, 0x11}, | ||
63 | {0x3010, 0x01}, | ||
64 | {0x3012, 0x41}, | ||
65 | {0x3016, 0xd2}, | ||
66 | {0x3018, 0x70}, | ||
67 | {0x3019, 0xc3}, | ||
68 | {0x301b, 0x96}, | ||
69 | {0x3022, 0x0f}, | ||
70 | {0x3023, 0xb4}, | ||
71 | {0x3031, 0x91}, | ||
72 | {0x3034, 0x41}, | ||
73 | {0x340c, 0xff}, | ||
74 | {0x3501, 0x12}, | ||
75 | {0x3502, 0xa6}, | ||
76 | {0x3503, 0x00}, | ||
77 | {0x3507, 0x00}, | ||
78 | {0x3508, 0x00}, | ||
79 | {0x3509, 0x12}, | ||
80 | {0x350a, 0x00}, | ||
81 | {0x350b, 0x80}, | ||
82 | {0x350f, 0x10}, | ||
83 | {0x3541, 0x02}, | ||
84 | {0x3542, 0x00}, | ||
85 | {0x3543, 0x00}, | ||
86 | {0x3547, 0x00}, | ||
87 | {0x3548, 0x00}, | ||
88 | {0x3549, 0x12}, | ||
89 | {0x354b, 0x10}, | ||
90 | {0x354f, 0x10}, | ||
91 | {0x3601, 0xa4}, | ||
92 | {0x3603, 0x97}, | ||
93 | {0x3604, 0x02}, | ||
94 | {0x3605, 0xf2}, | ||
95 | {0x3606, 0xe8}, | ||
96 | {0x3607, 0x11}, | ||
97 | {0x360a, 0x34}, | ||
98 | {0x360c, 0x13}, | ||
99 | {0x3618, 0xcc}, | ||
100 | {0x3620, 0x50}, | ||
101 | {0x3621, 0x99}, | ||
102 | {0x3622, 0x7d}, | ||
103 | {0x3624, 0x05}, | ||
104 | {0x362a, 0x25}, | ||
105 | {0x3650, 0x04}, | ||
106 | {0x3660, 0xc0}, | ||
107 | {0x3661, 0x00}, | ||
108 | {0x3662, 0x00}, | ||
109 | {0x3664, 0x88}, | ||
110 | {0x3667, 0x00}, | ||
111 | {0x366a, 0x5c}, | ||
112 | {0x366c, 0x80}, | ||
113 | {0x3700, 0x62}, | ||
114 | {0x3701, 0x08}, | ||
115 | {0x3702, 0x10}, | ||
116 | {0x3703, 0x3e}, | ||
117 | {0x3704, 0x26}, | ||
118 | {0x3705, 0x01}, | ||
119 | {0x3706, 0x3a}, | ||
120 | {0x3707, 0xc4}, | ||
121 | {0x3708, 0x3c}, | ||
122 | {0x3709, 0x1c}, | ||
123 | {0x370a, 0x23}, | ||
124 | {0x370b, 0x2c}, | ||
125 | {0x370c, 0x42}, | ||
126 | {0x370d, 0xa4}, | ||
127 | {0x370e, 0x14}, | ||
128 | {0x370f, 0x0a}, | ||
129 | {0x3710, 0x15}, | ||
130 | {0x3711, 0x0a}, | ||
131 | {0x3712, 0xa2}, | ||
132 | {0x3713, 0x00}, | ||
133 | {0x371e, 0x2a}, | ||
134 | {0x371f, 0x13}, | ||
135 | {0x3714, 0x00}, | ||
136 | {0x3717, 0x00}, | ||
137 | {0x3719, 0x00}, | ||
138 | {0x371c, 0x04}, | ||
139 | {0x3720, 0xaa}, | ||
140 | {0x3721, 0x10}, | ||
141 | {0x3722, 0x50}, | ||
142 | {0x3725, 0xf0}, | ||
143 | {0x3726, 0x22}, | ||
144 | {0x3727, 0x44}, | ||
145 | {0x3728, 0x40}, | ||
146 | {0x3729, 0x00}, | ||
147 | {0x372b, 0x00}, | ||
148 | {0x372c, 0x92}, | ||
149 | {0x372d, 0x0c}, | ||
150 | {0x372e, 0x22}, | ||
151 | {0x372f, 0x91}, | ||
152 | {0x3732, 0x01}, | ||
153 | {0x3733, 0xd0}, | ||
154 | {0x3730, 0x01}, | ||
155 | {0x3731, 0xc8}, | ||
156 | {0x3744, 0x01}, | ||
157 | {0x3745, 0x24}, | ||
158 | {0x3746, 0x00}, | ||
159 | {0x3747, 0xd0}, | ||
160 | {0x3748, 0x27}, | ||
161 | {0x374a, 0x4b}, | ||
162 | {0x374b, 0x44}, | ||
163 | {0x3760, 0xd1}, | ||
164 | {0x3761, 0x52}, | ||
165 | {0x3762, 0xa4}, | ||
166 | {0x3763, 0x14}, | ||
167 | {0x3766, 0x0c}, | ||
168 | {0x3767, 0x25}, | ||
169 | {0x3768, 0x0c}, | ||
170 | {0x3769, 0x24}, | ||
171 | {0x376a, 0x09}, | ||
172 | {0x376b, 0x02}, | ||
173 | {0x376d, 0x01}, | ||
174 | {0x376e, 0x53}, | ||
175 | {0x376f, 0x01}, | ||
176 | {0x378c, 0x08}, | ||
177 | {0x378d, 0x46}, | ||
178 | {0x378e, 0x14}, | ||
179 | {0x378f, 0x02}, | ||
180 | {0x3790, 0xc4}, | ||
181 | {0x3792, 0x64}, | ||
182 | {0x3793, 0x5d}, | ||
183 | {0x3794, 0x29}, | ||
184 | {0x3795, 0x4f}, | ||
185 | {0x3796, 0x43}, | ||
186 | {0x3797, 0x09}, | ||
187 | {0x3798, 0x02}, | ||
188 | {0x3799, 0x33}, | ||
189 | {0x379a, 0x09}, | ||
190 | {0x379b, 0x1e}, | ||
191 | {0x379f, 0x3e}, | ||
192 | {0x37a0, 0x44}, | ||
193 | {0x37a1, 0x00}, | ||
194 | {0x37a2, 0x44}, | ||
195 | {0x37a3, 0x41}, | ||
196 | {0x37a4, 0x88}, | ||
197 | {0x37a5, 0x69}, | ||
198 | {0x37b0, 0x48}, | ||
199 | {0x37b1, 0x20}, | ||
200 | {0x37b2, 0x03}, | ||
201 | {0x37b3, 0x48}, | ||
202 | {0x37b4, 0x02}, | ||
203 | {0x37b5, 0x33}, | ||
204 | {0x37b6, 0x22}, | ||
205 | {0x37b8, 0x02}, | ||
206 | {0x37bc, 0x02}, | ||
207 | {0x37c0, 0x3b}, | ||
208 | {0x37c1, 0xc2}, | ||
209 | {0x37c2, 0x06}, | ||
210 | {0x37c3, 0x06}, | ||
211 | {0x37c5, 0x33}, | ||
212 | {0x37c6, 0x35}, | ||
213 | {0x37c7, 0x00}, | ||
214 | {0x3800, 0x00}, | ||
215 | {0x3801, 0x14}, | ||
216 | {0x3802, 0x00}, | ||
217 | {0x3803, 0x0c}, | ||
218 | {0x3804, 0x10}, | ||
219 | {0x3805, 0x8b}, | ||
220 | {0x3806, 0x0c}, | ||
221 | {0x3807, 0x43}, | ||
222 | {0x3808, 0x16}, | ||
223 | {0x3809, 0x00}, | ||
224 | {0x380a, 0x10}, | ||
225 | {0x380b, 0x80}, | ||
226 | {0x380c, 0x1C}, | ||
227 | {0x380d, 0x20}, | ||
228 | {0x380e, 0x12}, | ||
229 | {0x380f, 0xc6}, | ||
230 | {0x3810, 0x00}, | ||
231 | {0x3811, 0x03}, | ||
232 | {0x3813, 0x06}, | ||
233 | {0x3814, 0x11}, | ||
234 | {0x3815, 0x11}, | ||
235 | {0x3820, 0x00}, | ||
236 | {0x3821, 0x04}, | ||
237 | {0x3834, 0x00}, | ||
238 | {0x3835, 0x04}, | ||
239 | {0x3836, 0x18}, | ||
240 | {0x3837, 0x02}, | ||
241 | {0x382f, 0x84}, | ||
242 | {0x383c, 0xc8}, | ||
243 | {0x383d, 0xff}, | ||
244 | {0x3842, 0x00}, | ||
245 | {0x384b, 0x00}, | ||
246 | {0x3d85, 0x16}, | ||
247 | {0x3d8c, 0x77}, | ||
248 | {0x3d8d, 0x10}, | ||
249 | {0x3f00, 0x52}, | ||
250 | {0x4000, 0x17}, | ||
251 | {0x4001, 0x60}, | ||
252 | {0x4001, 0x60}, | ||
253 | {0x4008, 0x00}, | ||
254 | {0x4009, 0x13}, | ||
255 | {0x400f, 0x00}, | ||
256 | {0x4011, 0xfb}, | ||
257 | {0x4017, 0x08}, | ||
258 | {0x4018, 0x00}, | ||
259 | {0x401a, 0xce}, | ||
260 | {0x4019, 0x18}, | ||
261 | {0x4020, 0x08}, | ||
262 | {0x4022, 0x08}, | ||
263 | {0x4024, 0x08}, | ||
264 | {0x4026, 0x08}, | ||
265 | {0x4028, 0x08}, | ||
266 | {0x402a, 0x08}, | ||
267 | {0x402c, 0x08}, | ||
268 | {0x402e, 0x08}, | ||
269 | {0x4030, 0x08}, | ||
270 | {0x4032, 0x08}, | ||
271 | {0x4034, 0x08}, | ||
272 | {0x4036, 0x08}, | ||
273 | {0x4038, 0x08}, | ||
274 | {0x403a, 0x08}, | ||
275 | {0x403c, 0x08}, | ||
276 | {0x403e, 0x08}, | ||
277 | {0x405c, 0x3f}, | ||
278 | {0x4066, 0x04}, | ||
279 | {0x4051, 0x03}, | ||
280 | {0x4052, 0x00}, | ||
281 | {0x4053, 0x80}, | ||
282 | {0x4054, 0x00}, | ||
283 | {0x4055, 0x80}, | ||
284 | {0x4056, 0x00}, | ||
285 | {0x4057, 0x80}, | ||
286 | {0x4058, 0x00}, | ||
287 | {0x4059, 0x80}, | ||
288 | {0x4202, 0x00}, | ||
289 | {0x4203, 0x01}, | ||
290 | {0x430b, 0xff}, | ||
291 | {0x430d, 0x00}, | ||
292 | {0x4500, 0x72}, | ||
293 | {0x4605, 0x00}, | ||
294 | {0x4640, 0x01}, | ||
295 | {0x4641, 0x04}, | ||
296 | {0x4645, 0x00}, | ||
297 | {0x4800, 0x04}, | ||
298 | {0x4809, 0x2b}, | ||
299 | {0x4813, 0x90}, | ||
300 | {0x4817, 0x04}, | ||
301 | {0x4833, 0x18}, | ||
302 | {0x4837, 0x0A}, | ||
303 | {0x484b, 0x01}, | ||
304 | {0x4850, 0x5c}, | ||
305 | {0x4852, 0x27}, | ||
306 | {0x4856, 0x5c}, | ||
307 | {0x4857, 0x55}, | ||
308 | {0x486a, 0xaa}, | ||
309 | {0x486e, 0x03}, | ||
310 | {0x486f, 0x55}, | ||
311 | {0x4875, 0xf0}, | ||
312 | {0x4b04, 0x80}, | ||
313 | {0x4b05, 0xb3}, | ||
314 | {0x4b06, 0x00}, | ||
315 | {0x4c01, 0xdf}, | ||
316 | {0x4d00, 0x04}, | ||
317 | {0x4d01, 0xf0}, | ||
318 | {0x4d02, 0xb8}, | ||
319 | {0x4d03, 0xf2}, | ||
320 | {0x4d04, 0x88}, | ||
321 | {0x4d05, 0x9d}, | ||
322 | {0x4e00, 0x04}, | ||
323 | {0x4e17, 0x04}, | ||
324 | {0x4e33, 0x18}, | ||
325 | {0x4e37, 0x11}, | ||
326 | {0x4e4b, 0x01}, | ||
327 | {0x4e50, 0x5c}, | ||
328 | {0x4e52, 0x27}, | ||
329 | {0x4e56, 0x5c}, | ||
330 | {0x4e57, 0x55}, | ||
331 | {0x4e6a, 0xaa}, | ||
332 | {0x4e6e, 0x03}, | ||
333 | {0x4e6f, 0x55}, | ||
334 | {0x4e75, 0xf0}, | ||
335 | {0x5000, 0x9b}, | ||
336 | {0x5001, 0x42}, | ||
337 | {0x5002, 0x10}, | ||
338 | {0x5003, 0x01}, | ||
339 | {0x5004, 0x00}, | ||
340 | {0x5005, 0x00}, | ||
341 | {0x501d, 0x00}, | ||
342 | {0x501f, 0x06}, | ||
343 | {0x5020, 0x03}, | ||
344 | {0x5021, 0x00}, | ||
345 | {0x5022, 0x13}, | ||
346 | {0x5061, 0xff}, | ||
347 | {0x5062, 0xff}, | ||
348 | {0x5063, 0xff}, | ||
349 | {0x5064, 0xff}, | ||
350 | {0x506f, 0x00}, | ||
351 | {0x5280, 0x00}, | ||
352 | {0x5282, 0x00}, | ||
353 | {0x5283, 0x01}, | ||
354 | {0x5200, 0x00}, | ||
355 | {0x5201, 0x71}, | ||
356 | {0x5203, 0x04}, | ||
357 | {0x5204, 0x00}, | ||
358 | {0x5205, 0x88}, | ||
359 | {0x5209, 0x00}, | ||
360 | {0x520a, 0x80}, | ||
361 | {0x520b, 0x04}, | ||
362 | {0x520c, 0x01}, | ||
363 | {0x5210, 0x10}, | ||
364 | {0x5211, 0xa0}, | ||
365 | {0x5292, 0x04}, | ||
366 | {0x5500, 0x00}, | ||
367 | {0x5501, 0x00}, | ||
368 | {0x5502, 0x00}, | ||
369 | {0x5503, 0x00}, | ||
370 | {0x5504, 0x00}, | ||
371 | {0x5505, 0x00}, | ||
372 | {0x5506, 0x00}, | ||
373 | {0x5507, 0x00}, | ||
374 | {0x5508, 0x10}, | ||
375 | {0x5509, 0x00}, | ||
376 | {0x550a, 0x10}, | ||
377 | {0x550b, 0x00}, | ||
378 | {0x550c, 0x20}, | ||
379 | {0x550d, 0x00}, | ||
380 | {0x550e, 0x20}, | ||
381 | {0x550f, 0x00}, | ||
382 | {0x5510, 0x00}, | ||
383 | {0x5511, 0x00}, | ||
384 | {0x5512, 0x00}, | ||
385 | {0x5513, 0x00}, | ||
386 | {0x5514, 0x00}, | ||
387 | {0x5515, 0x00}, | ||
388 | {0x5516, 0x00}, | ||
389 | {0x5517, 0x00}, | ||
390 | {0x5518, 0x00}, | ||
391 | {0x5519, 0x00}, | ||
392 | {0x551a, 0x00}, | ||
393 | {0x551b, 0x00}, | ||
394 | {0x551c, 0x00}, | ||
395 | {0x551d, 0x00}, | ||
396 | {0x551e, 0x00}, | ||
397 | {0x551f, 0x00}, | ||
398 | {0x5520, 0x00}, | ||
399 | {0x5521, 0x00}, | ||
400 | {0x5522, 0x00}, | ||
401 | {0x5523, 0x00}, | ||
402 | {0x5524, 0x00}, | ||
403 | {0x5525, 0x00}, | ||
404 | {0x5526, 0x00}, | ||
405 | {0x5527, 0x00}, | ||
406 | {0x5528, 0x00}, | ||
407 | {0x5529, 0x10}, | ||
408 | {0x552a, 0x00}, | ||
409 | {0x552b, 0x10}, | ||
410 | {0x552c, 0x00}, | ||
411 | {0x552d, 0x20}, | ||
412 | {0x552e, 0x00}, | ||
413 | {0x552f, 0x20}, | ||
414 | {0x5530, 0x00}, | ||
415 | {0x5531, 0x00}, | ||
416 | {0x5532, 0x00}, | ||
417 | {0x5533, 0x00}, | ||
418 | {0x5534, 0x00}, | ||
419 | {0x5535, 0x00}, | ||
420 | {0x5536, 0x00}, | ||
421 | {0x5537, 0x00}, | ||
422 | {0x5538, 0x00}, | ||
423 | {0x5539, 0x00}, | ||
424 | {0x553a, 0x00}, | ||
425 | {0x553b, 0x00}, | ||
426 | {0x553c, 0x00}, | ||
427 | {0x553d, 0x00}, | ||
428 | {0x553e, 0x00}, | ||
429 | {0x553f, 0x00}, | ||
430 | {0x5540, 0x00}, | ||
431 | {0x5541, 0x00}, | ||
432 | {0x5542, 0x00}, | ||
433 | {0x5543, 0x00}, | ||
434 | {0x5544, 0x00}, | ||
435 | {0x5545, 0x00}, | ||
436 | {0x5546, 0x00}, | ||
437 | {0x5547, 0x00}, | ||
438 | {0x5548, 0x01}, | ||
439 | {0x5549, 0x00}, | ||
440 | {0x554a, 0x01}, | ||
441 | {0x554b, 0x00}, | ||
442 | {0x554c, 0x02}, | ||
443 | {0x554d, 0x00}, | ||
444 | {0x554e, 0x02}, | ||
445 | {0x554f, 0x00}, | ||
446 | {0x5550, 0x00}, | ||
447 | {0x5551, 0x00}, | ||
448 | {0x5552, 0x00}, | ||
449 | {0x5553, 0x00}, | ||
450 | {0x5554, 0x00}, | ||
451 | {0x5555, 0x00}, | ||
452 | {0x5556, 0x00}, | ||
453 | {0x5557, 0x00}, | ||
454 | {0x5558, 0x00}, | ||
455 | {0x5559, 0x00}, | ||
456 | {0x555a, 0x00}, | ||
457 | {0x555b, 0x00}, | ||
458 | {0x555c, 0x00}, | ||
459 | {0x555d, 0x00}, | ||
460 | {0x555e, 0x00}, | ||
461 | {0x555f, 0x00}, | ||
462 | {0x5560, 0x00}, | ||
463 | {0x5561, 0x00}, | ||
464 | {0x5562, 0x00}, | ||
465 | {0x5563, 0x00}, | ||
466 | {0x5564, 0x00}, | ||
467 | {0x5565, 0x00}, | ||
468 | {0x5566, 0x00}, | ||
469 | {0x5567, 0x00}, | ||
470 | {0x5568, 0x00}, | ||
471 | {0x5569, 0x10}, | ||
472 | {0x556a, 0x00}, | ||
473 | {0x556b, 0x10}, | ||
474 | {0x556c, 0x00}, | ||
475 | {0x556d, 0x20}, | ||
476 | {0x556e, 0x00}, | ||
477 | {0x556f, 0x20}, | ||
478 | {0x5570, 0x00}, | ||
479 | {0x5571, 0x00}, | ||
480 | {0x5572, 0x00}, | ||
481 | {0x5573, 0x00}, | ||
482 | {0x5574, 0x00}, | ||
483 | {0x5575, 0x00}, | ||
484 | {0x5576, 0x00}, | ||
485 | {0x5577, 0x00}, | ||
486 | {0x5578, 0x00}, | ||
487 | {0x5579, 0x00}, | ||
488 | {0x557a, 0x00}, | ||
489 | {0x557b, 0x00}, | ||
490 | {0x557c, 0x00}, | ||
491 | {0x557d, 0x00}, | ||
492 | {0x557e, 0x00}, | ||
493 | {0x557f, 0x00}, | ||
494 | {0x5580, 0x00}, | ||
495 | {0x5581, 0x00}, | ||
496 | {0x5582, 0x00}, | ||
497 | {0x5583, 0x00}, | ||
498 | {0x5584, 0x10}, | ||
499 | {0x5585, 0x00}, | ||
500 | {0x5586, 0x10}, | ||
501 | {0x5587, 0x00}, | ||
502 | {0x5588, 0x38}, | ||
503 | {0x5589, 0x00}, | ||
504 | {0x558a, 0x38}, | ||
505 | {0x558b, 0x00}, | ||
506 | {0x558c, 0x70}, | ||
507 | {0x558d, 0x00}, | ||
508 | {0x558e, 0x70}, | ||
509 | {0x558f, 0x00}, | ||
510 | {0x5590, 0x20}, | ||
511 | {0x5591, 0x00}, | ||
512 | {0x5592, 0x20}, | ||
513 | {0x5593, 0x00}, | ||
514 | {0x5594, 0x00}, | ||
515 | {0x5595, 0x00}, | ||
516 | {0x5596, 0x00}, | ||
517 | {0x5597, 0x00}, | ||
518 | {0x5598, 0x00}, | ||
519 | {0x5599, 0x00}, | ||
520 | {0x559a, 0x00}, | ||
521 | {0x559b, 0x00}, | ||
522 | {0x559c, 0x00}, | ||
523 | {0x559d, 0x00}, | ||
524 | {0x559e, 0x00}, | ||
525 | {0x559f, 0x00}, | ||
526 | {0x55a0, 0x00}, | ||
527 | {0x55a1, 0x00}, | ||
528 | {0x55a2, 0x00}, | ||
529 | {0x55a3, 0x00}, | ||
530 | {0x55a4, 0x00}, | ||
531 | {0x55a5, 0x10}, | ||
532 | {0x55a6, 0x00}, | ||
533 | {0x55a7, 0x10}, | ||
534 | {0x55a8, 0x00}, | ||
535 | {0x55a9, 0x38}, | ||
536 | {0x55aa, 0x00}, | ||
537 | {0x55ab, 0x38}, | ||
538 | {0x55ac, 0x00}, | ||
539 | {0x55ad, 0x70}, | ||
540 | {0x55ae, 0x00}, | ||
541 | {0x55af, 0x70}, | ||
542 | {0x55b0, 0x00}, | ||
543 | {0x55b1, 0x20}, | ||
544 | {0x55b2, 0x00}, | ||
545 | {0x55b3, 0x20}, | ||
546 | {0x55b4, 0x00}, | ||
547 | {0x55b5, 0x00}, | ||
548 | {0x55b6, 0x00}, | ||
549 | {0x55b7, 0x00}, | ||
550 | {0x55b8, 0x00}, | ||
551 | {0x55b9, 0x00}, | ||
552 | {0x55ba, 0x00}, | ||
553 | {0x55bb, 0x00}, | ||
554 | {0x55bc, 0x00}, | ||
555 | {0x55bd, 0x00}, | ||
556 | {0x55be, 0x00}, | ||
557 | {0x55bf, 0x00}, | ||
558 | {0x55c0, 0x00}, | ||
559 | {0x55c1, 0x00}, | ||
560 | {0x55c2, 0x00}, | ||
561 | {0x55c3, 0x00}, | ||
562 | {0x55c4, 0x01}, | ||
563 | {0x55c5, 0x00}, | ||
564 | {0x55c6, 0x01}, | ||
565 | {0x55c7, 0x00}, | ||
566 | {0x55c8, 0x03}, | ||
567 | {0x55c9, 0x80}, | ||
568 | {0x55ca, 0x03}, | ||
569 | {0x55cb, 0x80}, | ||
570 | {0x55cc, 0x07}, | ||
571 | {0x55cd, 0x00}, | ||
572 | {0x55ce, 0x07}, | ||
573 | {0x55cf, 0x00}, | ||
574 | {0x55d0, 0x02}, | ||
575 | {0x55d1, 0x00}, | ||
576 | {0x55d2, 0x02}, | ||
577 | {0x55d3, 0x00}, | ||
578 | {0x55d4, 0x00}, | ||
579 | {0x55d5, 0x00}, | ||
580 | {0x55d6, 0x00}, | ||
581 | {0x55d7, 0x00}, | ||
582 | {0x55d8, 0x00}, | ||
583 | {0x55d9, 0x00}, | ||
584 | {0x55da, 0x00}, | ||
585 | {0x55db, 0x00}, | ||
586 | {0x55dc, 0x00}, | ||
587 | {0x55dd, 0x00}, | ||
588 | {0x55de, 0x00}, | ||
589 | {0x55df, 0x00}, | ||
590 | {0x55e0, 0x00}, | ||
591 | {0x55e1, 0x00}, | ||
592 | {0x55e2, 0x00}, | ||
593 | {0x55e3, 0x00}, | ||
594 | {0x55e4, 0x00}, | ||
595 | {0x55e5, 0x10}, | ||
596 | {0x55e6, 0x00}, | ||
597 | {0x55e7, 0x10}, | ||
598 | {0x55e8, 0x00}, | ||
599 | {0x55e9, 0x38}, | ||
600 | {0x55ea, 0x00}, | ||
601 | {0x55eb, 0x38}, | ||
602 | {0x55ec, 0x00}, | ||
603 | {0x55ed, 0x70}, | ||
604 | {0x55ee, 0x00}, | ||
605 | {0x55ef, 0x70}, | ||
606 | {0x55f0, 0x00}, | ||
607 | {0x55f1, 0x20}, | ||
608 | {0x55f2, 0x00}, | ||
609 | {0x55f3, 0x20}, | ||
610 | {0x55f4, 0x00}, | ||
611 | {0x55f5, 0x00}, | ||
612 | {0x55f6, 0x00}, | ||
613 | {0x55f7, 0x00}, | ||
614 | {0x55f8, 0x00}, | ||
615 | {0x55f9, 0x00}, | ||
616 | {0x55fa, 0x00}, | ||
617 | {0x55fb, 0x00}, | ||
618 | {0x55fc, 0x00}, | ||
619 | {0x55fd, 0x00}, | ||
620 | {0x55fe, 0x00}, | ||
621 | {0x55ff, 0x00}, | ||
622 | {0x5600, 0x30}, | ||
623 | {0x5601, 0x00}, | ||
624 | {0x5602, 0x00}, | ||
625 | {0x5603, 0x00}, | ||
626 | {0x5604, 0x00}, | ||
627 | {0x5605, 0x00}, | ||
628 | {0x5606, 0x00}, | ||
629 | {0x5607, 0x01}, | ||
630 | {0x5608, 0x01}, | ||
631 | {0x5609, 0x01}, | ||
632 | {0x560f, 0xfc}, | ||
633 | {0x5610, 0xf0}, | ||
634 | {0x5611, 0x10}, | ||
635 | {0x562f, 0xfc}, | ||
636 | {0x5630, 0xf0}, | ||
637 | {0x5631, 0x10}, | ||
638 | {0x564f, 0xfc}, | ||
639 | {0x5650, 0xf0}, | ||
640 | {0x5651, 0x10}, | ||
641 | {0x566f, 0xfc}, | ||
642 | {0x5670, 0xf0}, | ||
643 | {0x5671, 0x10}, | ||
644 | {0x567b, 0x40}, | ||
645 | {0x5690, 0x00}, | ||
646 | {0x5691, 0x00}, | ||
647 | {0x5692, 0x00}, | ||
648 | {0x5693, 0x0a}, | ||
649 | {0x5694, 0x80}, | ||
650 | {0x5696, 0x06}, | ||
651 | {0x5697, 0x0a}, | ||
652 | {0x5698, 0x00}, | ||
653 | {0x5699, 0x90}, | ||
654 | {0x569a, 0x15}, | ||
655 | {0x569b, 0x90}, | ||
656 | {0x569c, 0x00}, | ||
657 | {0x569d, 0x50}, | ||
658 | {0x569e, 0x10}, | ||
659 | {0x569f, 0x50}, | ||
660 | {0x56a0, 0x36}, | ||
661 | {0x56a1, 0x50}, | ||
662 | {0x56a2, 0x16}, | ||
663 | {0x56a3, 0x20}, | ||
664 | {0x56a4, 0x10}, | ||
665 | {0x56a5, 0xa0}, | ||
666 | {0x5c80, 0x06}, | ||
667 | {0x5c81, 0x80}, | ||
668 | {0x5c82, 0x09}, | ||
669 | {0x5c83, 0x5f}, | ||
670 | {0x5d04, 0x01}, | ||
671 | {0x5d05, 0x1a}, | ||
672 | {0x5d06, 0x01}, | ||
673 | {0x5d07, 0x1a}, | ||
674 | {0x5d12, 0xf7}, | ||
675 | {0x5d13, 0xdd}, | ||
676 | {0x5d14, 0x97}, | ||
677 | {0x5d15, 0x69}, | ||
678 | {0x5d16, 0x61}, | ||
679 | {0x5d17, 0x5b}, | ||
680 | {0x5d18, 0x62}, | ||
681 | {0x5d19, 0x8d}, | ||
682 | {0x5d1a, 0xdd}, | ||
683 | {0x5d1b, 0xff}, | ||
684 | {0x5d24, 0x00}, | ||
685 | {0x5d25, 0x00}, | ||
686 | {0x5d26, 0x00}, | ||
687 | {0x5d27, 0x0a}, | ||
688 | {0x5d28, 0x80}, | ||
689 | {0x5d2a, 0x00}, | ||
690 | {0x5d2b, 0x90}, | ||
691 | {0x5d2c, 0x15}, | ||
692 | {0x5d2d, 0x90}, | ||
693 | {0x5d2e, 0x00}, | ||
694 | {0x5d2f, 0x50}, | ||
695 | {0x5d30, 0x10}, | ||
696 | {0x5d31, 0x50}, | ||
697 | {0x5d32, 0x10}, | ||
698 | {0x5d34, 0x36}, | ||
699 | {0x5d35, 0x20}, | ||
700 | {0x5d36, 0x90}, | ||
701 | {0x5d37, 0xa0}, | ||
702 | {0x5d38, 0x5c}, | ||
703 | {0x5d39, 0x7b}, | ||
704 | {0x5d1c, 0x00}, | ||
705 | {0x5d1d, 0x90}, | ||
706 | {0x5d1e, 0x00}, | ||
707 | {0x5d1f, 0x50}, | ||
708 | {0x5d20, 0x15}, | ||
709 | {0x5d21, 0x00}, | ||
710 | {0x5d22, 0x10}, | ||
711 | {0x5d23, 0x00}, | ||
712 | {0x5d29, 0xc0}, | ||
713 | {0x3008, 0x01}, | ||
714 | {0x3663, 0x60}, | ||
715 | {0x3002, 0x01}, | ||
716 | {0x3c00, 0x3c}, | ||
717 | {0x3025, 0x03}, | ||
718 | {0x3668, 0xf0}, | ||
719 | {0x3400, 0x04}, | ||
720 | {OV23850_TABLE_END, 0x00}, | ||
721 | }; | ||
722 | |||
723 | static ov23850_reg mode_5632x4224_8fps_dpcm[] = { | ||
724 | {0x0303, 0x20}, | ||
725 | {0x0316, 0x1e}, | ||
726 | {0x0318, 0x03}, | ||
727 | {0x031c, 0x01}, | ||
728 | {0x031d, 0x02}, | ||
729 | {0x031e, 0x00}, | ||
730 | {0x2b05, 0x02}, | ||
731 | {0x2b06, 0x87}, | ||
732 | {0x2b07, 0x01}, | ||
733 | {0x2b08, 0xa8}, | ||
734 | {0x0320, 0x02}, | ||
735 | {0x3002, 0x00}, | ||
736 | {0x300f, 0x11}, | ||
737 | {0x3010, 0x01}, | ||
738 | {0x3012, 0x41}, | ||
739 | {0x3031, 0x91}, | ||
740 | {0x3034, 0x41}, | ||
741 | {0x340c, 0xff}, | ||
742 | {0x3501, 0x12}, | ||
743 | {0x3502, 0xa6}, | ||
744 | {0x3503, 0x00}, | ||
745 | {0x3507, 0x00}, | ||
746 | {0x3508, 0x00}, | ||
747 | {0x3509, 0x12}, | ||
748 | {0x350a, 0x00}, | ||
749 | {0x350b, 0x80}, | ||
750 | {0x350f, 0x10}, | ||
751 | {0x3541, 0x02}, | ||
752 | {0x3542, 0x00}, | ||
753 | {0x3543, 0x00}, | ||
754 | {0x3547, 0x00}, | ||
755 | {0x3548, 0x00}, | ||
756 | {0x3549, 0x12}, | ||
757 | {0x354b, 0x10}, | ||
758 | {0x354f, 0x10}, | ||
759 | {0x3603, 0x97}, | ||
760 | {0x3606, 0xe8}, | ||
761 | {0x3607, 0x11}, | ||
762 | {0x360a, 0x44}, | ||
763 | {0x360c, 0x11}, | ||
764 | {0x3618, 0xcc}, | ||
765 | {0x3620, 0x60}, | ||
766 | {0x3621, 0x99}, | ||
767 | {0x3622, 0x7c}, | ||
768 | {0x3624, 0x05}, | ||
769 | {0x362a, 0x25}, | ||
770 | {0x3650, 0x04}, | ||
771 | {0x3660, 0xc4}, | ||
772 | {0x3661, 0x00}, | ||
773 | {0x3662, 0x00}, | ||
774 | {0x3664, 0x88}, | ||
775 | {0x3667, 0x00}, | ||
776 | {0x366a, 0x1c}, | ||
777 | {0x366c, 0x80}, | ||
778 | {0x3700, 0x62}, | ||
779 | {0x3701, 0x08}, | ||
780 | {0x3702, 0x10}, | ||
781 | {0x3703, 0x38}, | ||
782 | {0x3704, 0x26}, | ||
783 | {0x3705, 0x01}, | ||
784 | {0x3706, 0x3a}, | ||
785 | {0x3707, 0xc4}, | ||
786 | {0x3708, 0x3c}, | ||
787 | {0x3709, 0x30}, | ||
788 | {0x370a, 0x23}, | ||
789 | {0x370b, 0x2c}, | ||
790 | {0x370c, 0x42}, | ||
791 | {0x370d, 0xa4}, | ||
792 | {0x370e, 0x14}, | ||
793 | {0x370f, 0x0a}, | ||
794 | {0x3710, 0x15}, | ||
795 | {0x3711, 0x0a}, | ||
796 | {0x3712, 0xa2}, | ||
797 | {0x3713, 0x00}, | ||
798 | {0x371e, 0x2a}, | ||
799 | {0x371f, 0x13}, | ||
800 | {0x3714, 0x00}, | ||
801 | {0x3717, 0x00}, | ||
802 | {0x3719, 0x00}, | ||
803 | {0x371c, 0x04}, | ||
804 | {0x3720, 0xaa}, | ||
805 | {0x3721, 0x10}, | ||
806 | {0x3722, 0x50}, | ||
807 | {0x3726, 0x22}, | ||
808 | {0x3727, 0x44}, | ||
809 | {0x3728, 0x40}, | ||
810 | {0x3729, 0x00}, | ||
811 | {0x372b, 0x00}, | ||
812 | {0x372c, 0x92}, | ||
813 | {0x372d, 0x0c}, | ||
814 | {0x372e, 0x22}, | ||
815 | {0x372f, 0x91}, | ||
816 | {0x3732, 0x01}, | ||
817 | {0x3733, 0xd0}, | ||
818 | {0x3730, 0x01}, | ||
819 | {0x3731, 0xc8}, | ||
820 | {0x3744, 0x01}, | ||
821 | {0x3745, 0x24}, | ||
822 | {0x3746, 0x00}, | ||
823 | {0x3747, 0xd0}, | ||
824 | {0x3748, 0x27}, | ||
825 | {0x374a, 0x4b}, | ||
826 | {0x374b, 0x44}, | ||
827 | {0x3760, 0xd1}, | ||
828 | {0x3761, 0x52}, | ||
829 | {0x3762, 0xa4}, | ||
830 | {0x3763, 0x14}, | ||
831 | {0x3766, 0x0c}, | ||
832 | {0x3767, 0x25}, | ||
833 | {0x3768, 0x0c}, | ||
834 | {0x3769, 0x24}, | ||
835 | {0x376a, 0x09}, | ||
836 | {0x376b, 0x02}, | ||
837 | {0x376d, 0x01}, | ||
838 | {0x376e, 0x53}, | ||
839 | {0x376f, 0x01}, | ||
840 | {0x378c, 0x08}, | ||
841 | {0x378d, 0x46}, | ||
842 | {0x378e, 0x14}, | ||
843 | {0x378f, 0x02}, | ||
844 | {0x3790, 0xc4}, | ||
845 | {0x3792, 0x64}, | ||
846 | {0x3793, 0x5d}, | ||
847 | {0x3794, 0x29}, | ||
848 | {0x3795, 0x4f}, | ||
849 | {0x3796, 0x43}, | ||
850 | {0x3797, 0x09}, | ||
851 | {0x3798, 0x02}, | ||
852 | {0x3799, 0x33}, | ||
853 | {0x379a, 0x09}, | ||
854 | {0x379b, 0x1e}, | ||
855 | {0x379f, 0x3e}, | ||
856 | {0x37a0, 0x44}, | ||
857 | {0x37a1, 0x00}, | ||
858 | {0x37a2, 0x44}, | ||
859 | {0x37a3, 0x41}, | ||
860 | {0x37a4, 0x88}, | ||
861 | {0x37a5, 0x69}, | ||
862 | {0x37b0, 0x48}, | ||
863 | {0x37b1, 0x20}, | ||
864 | {0x37b2, 0x03}, | ||
865 | {0x37b3, 0x48}, | ||
866 | {0x37b4, 0x02}, | ||
867 | {0x37b5, 0x33}, | ||
868 | {0x37b6, 0x22}, | ||
869 | {0x37b8, 0x02}, | ||
870 | {0x37bc, 0x02}, | ||
871 | {0x37c0, 0x3b}, | ||
872 | {0x37c1, 0xc2}, | ||
873 | {0x37c2, 0x06}, | ||
874 | {0x37c3, 0x06}, | ||
875 | {0x37c5, 0x33}, | ||
876 | {0x37c6, 0x35}, | ||
877 | {0x37c7, 0x00}, | ||
878 | {0x3800, 0x00}, | ||
879 | {0x3801, 0x14}, | ||
880 | {0x3802, 0x00}, | ||
881 | {0x3803, 0x0c}, | ||
882 | {0x3804, 0x10}, | ||
883 | {0x3805, 0x8b}, | ||
884 | {0x3806, 0x0c}, | ||
885 | {0x3807, 0x43}, | ||
886 | {0x3808, 0x16}, | ||
887 | {0x3809, 0x00}, | ||
888 | {0x380a, 0x10}, | ||
889 | {0x380b, 0x80}, | ||
890 | {0x380c, 0x18}, | ||
891 | {0x380d, 0x60}, | ||
892 | {0x380e, 0x12}, | ||
893 | {0x380f, 0xc6}, | ||
894 | {0x3810, 0x00}, | ||
895 | {0x3811, 0x03}, | ||
896 | {0x3813, 0x02}, | ||
897 | {0x3814, 0x11}, | ||
898 | {0x3815, 0x11}, | ||
899 | {0x3820, 0x00}, | ||
900 | {0x3821, 0x04}, | ||
901 | {0x3834, 0x00}, | ||
902 | {0x3835, 0x04}, | ||
903 | {0x3836, 0x18}, | ||
904 | {0x3837, 0x02}, | ||
905 | {0x382f, 0x84}, | ||
906 | {0x383c, 0xc8}, | ||
907 | {0x383d, 0xff}, | ||
908 | {0x3842, 0x00}, | ||
909 | {0x384b, 0x00}, | ||
910 | {0x3d85, 0x16}, | ||
911 | {0x3f00, 0x12}, | ||
912 | {0x4000, 0x17}, | ||
913 | {0x4001, 0x60}, | ||
914 | {0x4001, 0x60}, | ||
915 | {0x4008, 0x00}, | ||
916 | {0x4009, 0x13}, | ||
917 | {0x400f, 0x00}, | ||
918 | {0x4011, 0xfb}, | ||
919 | {0x4017, 0x08}, | ||
920 | {0x4018, 0x00}, | ||
921 | {0x401a, 0x4e}, | ||
922 | {0x4019, 0x18}, | ||
923 | {0x4020, 0x08}, | ||
924 | {0x4022, 0x08}, | ||
925 | {0x4024, 0x08}, | ||
926 | {0x4026, 0x08}, | ||
927 | {0x4028, 0x08}, | ||
928 | {0x402a, 0x08}, | ||
929 | {0x402c, 0x08}, | ||
930 | {0x402e, 0x08}, | ||
931 | {0x4030, 0x08}, | ||
932 | {0x4032, 0x08}, | ||
933 | {0x4034, 0x08}, | ||
934 | {0x4036, 0x08}, | ||
935 | {0x4038, 0x08}, | ||
936 | {0x403a, 0x08}, | ||
937 | {0x403c, 0x08}, | ||
938 | {0x403e, 0x08}, | ||
939 | {0x405c, 0x3f}, | ||
940 | {0x4066, 0x04}, | ||
941 | {0x4051, 0x03}, | ||
942 | {0x4052, 0x00}, | ||
943 | {0x4053, 0x80}, | ||
944 | {0x4054, 0x00}, | ||
945 | {0x4055, 0x80}, | ||
946 | {0x4056, 0x00}, | ||
947 | {0x4057, 0x80}, | ||
948 | {0x4058, 0x00}, | ||
949 | {0x4059, 0x80}, | ||
950 | {0x4202, 0x00}, | ||
951 | {0x4203, 0x01}, | ||
952 | {0x430b, 0xff}, | ||
953 | {0x430d, 0x00}, | ||
954 | {0x4500, 0x72}, | ||
955 | {0x4605, 0x00}, | ||
956 | {0x4640, 0x01}, | ||
957 | {0x4641, 0x04}, | ||
958 | {0x4645, 0x00}, | ||
959 | {0x4800, 0x04}, | ||
960 | {0x4809, 0x2b}, | ||
961 | {0x4813, 0x90}, | ||
962 | {0x4817, 0x04}, | ||
963 | {0x4833, 0x18}, | ||
964 | {0x4837, 0x20}, | ||
965 | {0x484b, 0x01}, | ||
966 | {0x4850, 0x5c}, | ||
967 | {0x4852, 0x27}, | ||
968 | {0x4856, 0x5c}, | ||
969 | {0x4857, 0x55}, | ||
970 | {0x486a, 0xaa}, | ||
971 | {0x486e, 0x03}, | ||
972 | {0x486f, 0x55}, | ||
973 | {0x4875, 0xf0}, | ||
974 | {0x4b04, 0x80}, | ||
975 | {0x4b06, 0x00}, | ||
976 | {0x4c01, 0xdf}, | ||
977 | {0x4e00, 0x04}, | ||
978 | {0x4e17, 0x04}, | ||
979 | {0x4e33, 0x18}, | ||
980 | {0x4e37, 0x11}, | ||
981 | {0x4e4b, 0x01}, | ||
982 | {0x4e50, 0x5c}, | ||
983 | {0x4e52, 0x27}, | ||
984 | {0x4e56, 0x5c}, | ||
985 | {0x4e57, 0x55}, | ||
986 | {0x4e6a, 0xaa}, | ||
987 | {0x4e6e, 0x03}, | ||
988 | {0x4e6f, 0x55}, | ||
989 | {0x4e75, 0xf0}, | ||
990 | {0x5000, 0x99}, | ||
991 | {0x5001, 0x42}, | ||
992 | {0x5002, 0x04}, | ||
993 | {0x5003, 0x01}, | ||
994 | {0x5004, 0x00}, | ||
995 | {0x5005, 0x00}, | ||
996 | {0x501d, 0x00}, | ||
997 | {0x501f, 0x06}, | ||
998 | {0x5021, 0x00}, | ||
999 | {0x5022, 0x13}, | ||
1000 | {0x5061, 0xff}, | ||
1001 | {0x5062, 0xff}, | ||
1002 | {0x5063, 0xff}, | ||
1003 | {0x5064, 0xff}, | ||
1004 | {0x5280, 0x00}, | ||
1005 | {0x5282, 0x00}, | ||
1006 | {0x5283, 0x01}, | ||
1007 | {0x5200, 0x00}, | ||
1008 | {0x5201, 0x71}, | ||
1009 | {0x5203, 0x04}, | ||
1010 | {0x5204, 0x00}, | ||
1011 | {0x5205, 0x88}, | ||
1012 | {0x5209, 0x00}, | ||
1013 | {0x520a, 0x80}, | ||
1014 | {0x520b, 0x04}, | ||
1015 | {0x520c, 0x01}, | ||
1016 | {0x5210, 0x10}, | ||
1017 | {0x5211, 0xa0}, | ||
1018 | {0x5292, 0x00}, | ||
1019 | {0x5500, 0x00}, | ||
1020 | {0x5501, 0x00}, | ||
1021 | {0x5502, 0x00}, | ||
1022 | {0x5503, 0x00}, | ||
1023 | {0x5504, 0x00}, | ||
1024 | {0x5505, 0x00}, | ||
1025 | {0x5506, 0x00}, | ||
1026 | {0x5507, 0x00}, | ||
1027 | {0x5508, 0x00}, | ||
1028 | {0x5509, 0x00}, | ||
1029 | {0x550a, 0x00}, | ||
1030 | {0x550b, 0x00}, | ||
1031 | {0x550c, 0x00}, | ||
1032 | {0x550d, 0x00}, | ||
1033 | {0x550e, 0x00}, | ||
1034 | {0x550f, 0x00}, | ||
1035 | {0x5510, 0x04}, | ||
1036 | {0x5511, 0x04}, | ||
1037 | {0x5512, 0x04}, | ||
1038 | {0x5513, 0x04}, | ||
1039 | {0x5514, 0x08}, | ||
1040 | {0x5515, 0x08}, | ||
1041 | {0x5516, 0x08}, | ||
1042 | {0x5517, 0x08}, | ||
1043 | {0x5518, 0x00}, | ||
1044 | {0x5519, 0x00}, | ||
1045 | {0x551a, 0x00}, | ||
1046 | {0x551b, 0x00}, | ||
1047 | {0x551c, 0x00}, | ||
1048 | {0x551d, 0x00}, | ||
1049 | {0x551e, 0x00}, | ||
1050 | {0x551f, 0x00}, | ||
1051 | {0x5520, 0x00}, | ||
1052 | {0x5521, 0x00}, | ||
1053 | {0x5522, 0x00}, | ||
1054 | {0x5523, 0x00}, | ||
1055 | {0x5524, 0x00}, | ||
1056 | {0x5525, 0x00}, | ||
1057 | {0x5526, 0x00}, | ||
1058 | {0x5527, 0x00}, | ||
1059 | {0x5528, 0x00}, | ||
1060 | {0x5529, 0x00}, | ||
1061 | {0x552a, 0x00}, | ||
1062 | {0x552b, 0x00}, | ||
1063 | {0x552c, 0x00}, | ||
1064 | {0x552d, 0x00}, | ||
1065 | {0x552e, 0x00}, | ||
1066 | {0x552f, 0x00}, | ||
1067 | {0x5530, 0x04}, | ||
1068 | {0x5531, 0x04}, | ||
1069 | {0x5532, 0x04}, | ||
1070 | {0x5533, 0x04}, | ||
1071 | {0x5534, 0x08}, | ||
1072 | {0x5535, 0x08}, | ||
1073 | {0x5536, 0x08}, | ||
1074 | {0x5537, 0x08}, | ||
1075 | {0x5538, 0x00}, | ||
1076 | {0x5539, 0x00}, | ||
1077 | {0x553a, 0x00}, | ||
1078 | {0x553b, 0x00}, | ||
1079 | {0x553c, 0x00}, | ||
1080 | {0x553d, 0x00}, | ||
1081 | {0x553e, 0x00}, | ||
1082 | {0x553f, 0x00}, | ||
1083 | {0x5540, 0x00}, | ||
1084 | {0x5541, 0x00}, | ||
1085 | {0x5542, 0x00}, | ||
1086 | {0x5543, 0x00}, | ||
1087 | {0x5544, 0x00}, | ||
1088 | {0x5545, 0x00}, | ||
1089 | {0x5546, 0x00}, | ||
1090 | {0x5547, 0x00}, | ||
1091 | {0x5548, 0x00}, | ||
1092 | {0x5549, 0x00}, | ||
1093 | {0x554a, 0x00}, | ||
1094 | {0x554b, 0x00}, | ||
1095 | {0x554c, 0x00}, | ||
1096 | {0x554d, 0x00}, | ||
1097 | {0x554e, 0x00}, | ||
1098 | {0x554f, 0x00}, | ||
1099 | {0x5550, 0x04}, | ||
1100 | {0x5551, 0x04}, | ||
1101 | {0x5552, 0x04}, | ||
1102 | {0x5553, 0x04}, | ||
1103 | {0x5554, 0x08}, | ||
1104 | {0x5555, 0x08}, | ||
1105 | {0x5556, 0x08}, | ||
1106 | {0x5557, 0x08}, | ||
1107 | {0x5558, 0x00}, | ||
1108 | {0x5559, 0x00}, | ||
1109 | {0x555a, 0x00}, | ||
1110 | {0x555b, 0x00}, | ||
1111 | {0x555c, 0x00}, | ||
1112 | {0x555d, 0x00}, | ||
1113 | {0x555e, 0x00}, | ||
1114 | {0x555f, 0x00}, | ||
1115 | {0x5560, 0x00}, | ||
1116 | {0x5561, 0x00}, | ||
1117 | {0x5562, 0x00}, | ||
1118 | {0x5563, 0x00}, | ||
1119 | {0x5564, 0x00}, | ||
1120 | {0x5565, 0x00}, | ||
1121 | {0x5566, 0x00}, | ||
1122 | {0x5567, 0x00}, | ||
1123 | {0x5568, 0x00}, | ||
1124 | {0x5569, 0x00}, | ||
1125 | {0x556a, 0x00}, | ||
1126 | {0x556b, 0x00}, | ||
1127 | {0x556c, 0x00}, | ||
1128 | {0x556d, 0x00}, | ||
1129 | {0x556e, 0x00}, | ||
1130 | {0x556f, 0x00}, | ||
1131 | {0x5570, 0x04}, | ||
1132 | {0x5571, 0x04}, | ||
1133 | {0x5572, 0x04}, | ||
1134 | {0x5573, 0x04}, | ||
1135 | {0x5574, 0x08}, | ||
1136 | {0x5575, 0x08}, | ||
1137 | {0x5576, 0x08}, | ||
1138 | {0x5577, 0x08}, | ||
1139 | {0x5578, 0x00}, | ||
1140 | {0x5579, 0x00}, | ||
1141 | {0x557a, 0x00}, | ||
1142 | {0x557b, 0x00}, | ||
1143 | {0x557c, 0x00}, | ||
1144 | {0x557d, 0x00}, | ||
1145 | {0x557e, 0x00}, | ||
1146 | {0x557f, 0x00}, | ||
1147 | {0x5580, 0x00}, | ||
1148 | {0x5581, 0x00}, | ||
1149 | {0x5582, 0x00}, | ||
1150 | {0x5583, 0x00}, | ||
1151 | {0x5584, 0x00}, | ||
1152 | {0x5585, 0x00}, | ||
1153 | {0x5586, 0x00}, | ||
1154 | {0x5587, 0x00}, | ||
1155 | {0x5588, 0x00}, | ||
1156 | {0x5589, 0x00}, | ||
1157 | {0x558a, 0x00}, | ||
1158 | {0x558b, 0x00}, | ||
1159 | {0x558c, 0x04}, | ||
1160 | {0x558d, 0x04}, | ||
1161 | {0x558e, 0x04}, | ||
1162 | {0x558f, 0x04}, | ||
1163 | {0x5590, 0x0e}, | ||
1164 | {0x5591, 0x0e}, | ||
1165 | {0x5592, 0x0e}, | ||
1166 | {0x5593, 0x0e}, | ||
1167 | {0x5594, 0x1c}, | ||
1168 | {0x5595, 0x1c}, | ||
1169 | {0x5596, 0x1c}, | ||
1170 | {0x5597, 0x1c}, | ||
1171 | {0x5598, 0x08}, | ||
1172 | {0x5599, 0x08}, | ||
1173 | {0x559a, 0x08}, | ||
1174 | {0x559b, 0x08}, | ||
1175 | {0x559c, 0x00}, | ||
1176 | {0x559d, 0x00}, | ||
1177 | {0x559e, 0x00}, | ||
1178 | {0x559f, 0x00}, | ||
1179 | {0x55a0, 0x00}, | ||
1180 | {0x55a1, 0x00}, | ||
1181 | {0x55a2, 0x00}, | ||
1182 | {0x55a3, 0x00}, | ||
1183 | {0x55a4, 0x00}, | ||
1184 | {0x55a5, 0x00}, | ||
1185 | {0x55a6, 0x00}, | ||
1186 | {0x55a7, 0x00}, | ||
1187 | {0x55a8, 0x00}, | ||
1188 | {0x55a9, 0x00}, | ||
1189 | {0x55aa, 0x00}, | ||
1190 | {0x55ab, 0x00}, | ||
1191 | {0x55ac, 0x04}, | ||
1192 | {0x55ad, 0x04}, | ||
1193 | {0x55ae, 0x04}, | ||
1194 | {0x55af, 0x04}, | ||
1195 | {0x55b0, 0x0e}, | ||
1196 | {0x55b1, 0x0e}, | ||
1197 | {0x55b2, 0x0e}, | ||
1198 | {0x55b3, 0x0e}, | ||
1199 | {0x55b4, 0x1c}, | ||
1200 | {0x55b5, 0x1c}, | ||
1201 | {0x55b6, 0x1c}, | ||
1202 | {0x55b7, 0x1c}, | ||
1203 | {0x55b8, 0x08}, | ||
1204 | {0x55b9, 0x08}, | ||
1205 | {0x55ba, 0x08}, | ||
1206 | {0x55bb, 0x08}, | ||
1207 | {0x55bc, 0x00}, | ||
1208 | {0x55bd, 0x00}, | ||
1209 | {0x55be, 0x00}, | ||
1210 | {0x55bf, 0x00}, | ||
1211 | {0x55c0, 0x00}, | ||
1212 | {0x55c1, 0x00}, | ||
1213 | {0x55c2, 0x00}, | ||
1214 | {0x55c3, 0x00}, | ||
1215 | {0x55c4, 0x00}, | ||
1216 | {0x55c5, 0x00}, | ||
1217 | {0x55c6, 0x00}, | ||
1218 | {0x55c7, 0x00}, | ||
1219 | {0x55c8, 0x00}, | ||
1220 | {0x55c9, 0x00}, | ||
1221 | {0x55ca, 0x00}, | ||
1222 | {0x55cb, 0x00}, | ||
1223 | {0x55cc, 0x04}, | ||
1224 | {0x55cd, 0x04}, | ||
1225 | {0x55ce, 0x04}, | ||
1226 | {0x55cf, 0x04}, | ||
1227 | {0x55d0, 0x0e}, | ||
1228 | {0x55d1, 0x0e}, | ||
1229 | {0x55d2, 0x0e}, | ||
1230 | {0x55d3, 0x0e}, | ||
1231 | {0x55d4, 0x1c}, | ||
1232 | {0x55d5, 0x1c}, | ||
1233 | {0x55d6, 0x1c}, | ||
1234 | {0x55d7, 0x1c}, | ||
1235 | {0x55d8, 0x08}, | ||
1236 | {0x55d9, 0x08}, | ||
1237 | {0x55da, 0x08}, | ||
1238 | {0x55db, 0x08}, | ||
1239 | {0x55dc, 0x00}, | ||
1240 | {0x55dd, 0x00}, | ||
1241 | {0x55de, 0x00}, | ||
1242 | {0x55df, 0x00}, | ||
1243 | {0x55e0, 0x00}, | ||
1244 | {0x55e1, 0x00}, | ||
1245 | {0x55e2, 0x00}, | ||
1246 | {0x55e3, 0x00}, | ||
1247 | {0x55e4, 0x00}, | ||
1248 | {0x55e5, 0x00}, | ||
1249 | {0x55e6, 0x00}, | ||
1250 | {0x55e7, 0x00}, | ||
1251 | {0x55e8, 0x00}, | ||
1252 | {0x55e9, 0x00}, | ||
1253 | {0x55ea, 0x00}, | ||
1254 | {0x55eb, 0x00}, | ||
1255 | {0x55ec, 0x04}, | ||
1256 | {0x55ed, 0x04}, | ||
1257 | {0x55ee, 0x04}, | ||
1258 | {0x55ef, 0x04}, | ||
1259 | {0x55f0, 0x0e}, | ||
1260 | {0x55f1, 0x0e}, | ||
1261 | {0x55f2, 0x0e}, | ||
1262 | {0x55f3, 0x0e}, | ||
1263 | {0x55f4, 0x1c}, | ||
1264 | {0x55f5, 0x1c}, | ||
1265 | {0x55f6, 0x1c}, | ||
1266 | {0x55f7, 0x1c}, | ||
1267 | {0x55f8, 0x08}, | ||
1268 | {0x55f9, 0x08}, | ||
1269 | {0x55fa, 0x08}, | ||
1270 | {0x55fb, 0x08}, | ||
1271 | {0x55fc, 0x00}, | ||
1272 | {0x55fd, 0x00}, | ||
1273 | {0x55fe, 0x00}, | ||
1274 | {0x55ff, 0x00}, | ||
1275 | {0x567b, 0x00}, | ||
1276 | {0x5690, 0x00}, | ||
1277 | {0x5691, 0x00}, | ||
1278 | {0x5692, 0x00}, | ||
1279 | {0x5693, 0x0a}, | ||
1280 | {0x5694, 0xc0}, | ||
1281 | {0x5696, 0x06}, | ||
1282 | {0x5697, 0x0a}, | ||
1283 | {0x5698, 0x00}, | ||
1284 | {0x5699, 0x1c}, | ||
1285 | {0x569a, 0x16}, | ||
1286 | {0x569b, 0x04}, | ||
1287 | {0x569c, 0x00}, | ||
1288 | {0x569d, 0x1c}, | ||
1289 | {0x569e, 0x10}, | ||
1290 | {0x569f, 0x84}, | ||
1291 | {0x56a0, 0x36}, | ||
1292 | {0x56a1, 0x50}, | ||
1293 | {0x56a2, 0x16}, | ||
1294 | {0x56a3, 0x20}, | ||
1295 | {0x56a4, 0x10}, | ||
1296 | {0x56a5, 0xa0}, | ||
1297 | {0x5c80, 0x06}, | ||
1298 | {0x5c81, 0x80}, | ||
1299 | {0x5c82, 0x09}, | ||
1300 | {0x5c83, 0x5f}, | ||
1301 | {0x5d00, 0x01}, | ||
1302 | {0x5d01, 0x00}, | ||
1303 | {0x5d02, 0x01}, | ||
1304 | {0x5d03, 0x00}, | ||
1305 | {0x5d04, 0x02}, | ||
1306 | {0x5d05, 0x00}, | ||
1307 | {0x5d06, 0x02}, | ||
1308 | {0x5d07, 0x00}, | ||
1309 | {0x5d08, 0x70}, | ||
1310 | {0x5d09, 0x74}, | ||
1311 | {0x5d0a, 0x78}, | ||
1312 | {0x5d0b, 0x7c}, | ||
1313 | {0x5d0c, 0x80}, | ||
1314 | {0x5d0d, 0x80}, | ||
1315 | {0x5d0e, 0x7c}, | ||
1316 | {0x5d0f, 0x78}, | ||
1317 | {0x5d10, 0x74}, | ||
1318 | {0x5d11, 0x70}, | ||
1319 | {0x5d12, 0x98}, | ||
1320 | {0x5d13, 0x96}, | ||
1321 | {0x5d14, 0x63}, | ||
1322 | {0x5d15, 0x3a}, | ||
1323 | {0x5d16, 0x38}, | ||
1324 | {0x5d17, 0x39}, | ||
1325 | {0x5d18, 0x37}, | ||
1326 | {0x5d19, 0x53}, | ||
1327 | {0x5d1a, 0x8b}, | ||
1328 | {0x5d1b, 0x9d}, | ||
1329 | {0x5d24, 0x00}, | ||
1330 | {0x5d25, 0x00}, | ||
1331 | {0x5d26, 0x00}, | ||
1332 | {0x5d27, 0x0a}, | ||
1333 | {0x5d28, 0xc0}, | ||
1334 | {0x5d2a, 0x00}, | ||
1335 | {0x5d2b, 0x1c}, | ||
1336 | {0x5d2c, 0x16}, | ||
1337 | {0x5d2d, 0x04}, | ||
1338 | {0x5d2e, 0x00}, | ||
1339 | {0x5d2f, 0x1c}, | ||
1340 | {0x5d30, 0x10}, | ||
1341 | {0x5d31, 0x84}, | ||
1342 | {0x5d32, 0x10}, | ||
1343 | {0x5d34, 0x16}, | ||
1344 | {0x5d35, 0x20}, | ||
1345 | {0x5d36, 0x10}, | ||
1346 | {0x5d37, 0xa0}, | ||
1347 | {0x5d38, 0x5c}, | ||
1348 | {0x5d39, 0x7b}, | ||
1349 | {0x5d1c, 0x00}, | ||
1350 | {0x5d1d, 0x1c}, | ||
1351 | {0x5d1e, 0x00}, | ||
1352 | {0x5d1f, 0x1c}, | ||
1353 | {0x5d20, 0x15}, | ||
1354 | {0x5d21, 0xe0}, | ||
1355 | {0x5d22, 0x10}, | ||
1356 | {0x5d23, 0x40}, | ||
1357 | {0x5d29, 0x40}, | ||
1358 | {0x3008, 0x01}, | ||
1359 | {0x3663, 0x60}, | ||
1360 | {0x3002, 0x01}, | ||
1361 | {0x3c00, 0x3c}, | ||
1362 | {0x3025, 0x03}, | ||
1363 | {0x3668, 0xf0}, | ||
1364 | {0x3400, 0x04}, | ||
1365 | {OV23850_TABLE_END, 0x00}, | ||
1366 | }; | ||
1367 | |||
1368 | static ov23850_reg mode_5632x4224_8fps[] = { | ||
1369 | {0x0303, 0x20}, | ||
1370 | {0x0316, 0x1e}, | ||
1371 | {0x0317, 0x04}, | ||
1372 | {0x0318, 0x03}, | ||
1373 | {0x031c, 0x01}, | ||
1374 | {0x031d, 0x02}, | ||
1375 | {0x031e, 0x01}, | ||
1376 | {0x2b05, 0x02}, | ||
1377 | {0x2b06, 0x87}, | ||
1378 | {0x2b07, 0x01}, | ||
1379 | {0x2b08, 0xa8}, | ||
1380 | {0x0320, 0x02}, | ||
1381 | {0x3002, 0x00}, | ||
1382 | {0x300f, 0x11}, | ||
1383 | {0x3010, 0x01}, | ||
1384 | {0x3012, 0x41}, | ||
1385 | {0x3016, 0xd2}, | ||
1386 | {0x3018, 0x70}, | ||
1387 | {0x3019, 0xe1}, | ||
1388 | {0x301b, 0x96}, | ||
1389 | {0x3022, 0x0f}, | ||
1390 | {0x3023, 0xb4}, | ||
1391 | {0x3031, 0x91}, | ||
1392 | {0x3034, 0x41}, | ||
1393 | {0x340c, 0xff}, | ||
1394 | {0x3501, 0x12}, | ||
1395 | {0x3502, 0xa6}, | ||
1396 | {0x3503, 0x00}, | ||
1397 | {0x3507, 0x00}, | ||
1398 | {0x3508, 0x00}, | ||
1399 | {0x3509, 0x12}, | ||
1400 | {0x350a, 0x00}, | ||
1401 | {0x350b, 0x80}, | ||
1402 | {0x350f, 0x10}, | ||
1403 | {0x3541, 0x02}, | ||
1404 | {0x3542, 0x00}, | ||
1405 | {0x3543, 0x00}, | ||
1406 | {0x3547, 0x00}, | ||
1407 | {0x3548, 0x00}, | ||
1408 | {0x3549, 0x12}, | ||
1409 | {0x354b, 0x10}, | ||
1410 | {0x354f, 0x10}, | ||
1411 | {0x3601, 0xa4}, | ||
1412 | {0x3603, 0x97}, | ||
1413 | {0x3604, 0x02}, | ||
1414 | {0x3605, 0xf2}, | ||
1415 | {0x3606, 0xe8}, | ||
1416 | {0x3607, 0x11}, | ||
1417 | {0x360a, 0x34}, | ||
1418 | {0x360c, 0x13}, | ||
1419 | {0x3618, 0xcc}, | ||
1420 | {0x3620, 0x50}, | ||
1421 | {0x3621, 0x99}, | ||
1422 | {0x3622, 0x7d}, | ||
1423 | {0x3624, 0x05}, | ||
1424 | {0x362a, 0x25}, | ||
1425 | {0x3650, 0x04}, | ||
1426 | {0x3660, 0xc0}, | ||
1427 | {0x3661, 0x00}, | ||
1428 | {0x3662, 0x00}, | ||
1429 | {0x3664, 0x88}, | ||
1430 | {0x3667, 0x00}, | ||
1431 | {0x366a, 0x5c}, | ||
1432 | {0x366c, 0x80}, | ||
1433 | {0x3700, 0x62}, | ||
1434 | {0x3701, 0x08}, | ||
1435 | {0x3702, 0x10}, | ||
1436 | {0x3703, 0x3e}, | ||
1437 | {0x3704, 0x26}, | ||
1438 | {0x3705, 0x01}, | ||
1439 | {0x3706, 0x3a}, | ||
1440 | {0x3707, 0xc4}, | ||
1441 | {0x3708, 0x3c}, | ||
1442 | {0x3709, 0x1c}, | ||
1443 | {0x370a, 0x23}, | ||
1444 | {0x370b, 0x2c}, | ||
1445 | {0x370c, 0x42}, | ||
1446 | {0x370d, 0xa4}, | ||
1447 | {0x370e, 0x14}, | ||
1448 | {0x370f, 0x0a}, | ||
1449 | {0x3710, 0x15}, | ||
1450 | {0x3711, 0x0a}, | ||
1451 | {0x3712, 0xa2}, | ||
1452 | {0x3713, 0x00}, | ||
1453 | {0x371e, 0x2a}, | ||
1454 | {0x371f, 0x13}, | ||
1455 | {0x3714, 0x00}, | ||
1456 | {0x3717, 0x00}, | ||
1457 | {0x3719, 0x00}, | ||
1458 | {0x371c, 0x04}, | ||
1459 | {0x3720, 0xaa}, | ||
1460 | {0x3721, 0x10}, | ||
1461 | {0x3722, 0x50}, | ||
1462 | {0x3725, 0xf0}, | ||
1463 | {0x3726, 0x22}, | ||
1464 | {0x3727, 0x44}, | ||
1465 | {0x3728, 0x40}, | ||
1466 | {0x3729, 0x00}, | ||
1467 | {0x372b, 0x00}, | ||
1468 | {0x372c, 0x92}, | ||
1469 | {0x372d, 0x0c}, | ||
1470 | {0x372e, 0x22}, | ||
1471 | {0x372f, 0x91}, | ||
1472 | {0x3732, 0x01}, | ||
1473 | {0x3733, 0xd0}, | ||
1474 | {0x3730, 0x01}, | ||
1475 | {0x3731, 0xc8}, | ||
1476 | {0x3744, 0x01}, | ||
1477 | {0x3745, 0x24}, | ||
1478 | {0x3746, 0x00}, | ||
1479 | {0x3747, 0xd0}, | ||
1480 | {0x3748, 0x27}, | ||
1481 | {0x374a, 0x4b}, | ||
1482 | {0x374b, 0x44}, | ||
1483 | {0x3760, 0xd1}, | ||
1484 | {0x3761, 0x52}, | ||
1485 | {0x3762, 0xa4}, | ||
1486 | {0x3763, 0x14}, | ||
1487 | {0x3766, 0x0c}, | ||
1488 | {0x3767, 0x25}, | ||
1489 | {0x3768, 0x0c}, | ||
1490 | {0x3769, 0x24}, | ||
1491 | {0x376a, 0x09}, | ||
1492 | {0x376b, 0x02}, | ||
1493 | {0x376d, 0x01}, | ||
1494 | {0x376e, 0x53}, | ||
1495 | {0x376f, 0x01}, | ||
1496 | {0x378c, 0x08}, | ||
1497 | {0x378d, 0x46}, | ||
1498 | {0x378e, 0x14}, | ||
1499 | {0x378f, 0x02}, | ||
1500 | {0x3790, 0xc4}, | ||
1501 | {0x3792, 0x64}, | ||
1502 | {0x3793, 0x5d}, | ||
1503 | {0x3794, 0x29}, | ||
1504 | {0x3795, 0x4f}, | ||
1505 | {0x3796, 0x43}, | ||
1506 | {0x3797, 0x09}, | ||
1507 | {0x3798, 0x02}, | ||
1508 | {0x3799, 0x33}, | ||
1509 | {0x379a, 0x09}, | ||
1510 | {0x379b, 0x1e}, | ||
1511 | {0x379f, 0x3e}, | ||
1512 | {0x37a0, 0x44}, | ||
1513 | {0x37a1, 0x00}, | ||
1514 | {0x37a2, 0x44}, | ||
1515 | {0x37a3, 0x41}, | ||
1516 | {0x37a4, 0x88}, | ||
1517 | {0x37a5, 0x69}, | ||
1518 | {0x37b0, 0x48}, | ||
1519 | {0x37b1, 0x20}, | ||
1520 | {0x37b2, 0x03}, | ||
1521 | {0x37b3, 0x48}, | ||
1522 | {0x37b4, 0x02}, | ||
1523 | {0x37b5, 0x33}, | ||
1524 | {0x37b6, 0x22}, | ||
1525 | {0x37b8, 0x02}, | ||
1526 | {0x37bc, 0x02}, | ||
1527 | {0x37c0, 0x3b}, | ||
1528 | {0x37c1, 0xc2}, | ||
1529 | {0x37c2, 0x06}, | ||
1530 | {0x37c3, 0x06}, | ||
1531 | {0x37c5, 0x33}, | ||
1532 | {0x37c6, 0x35}, | ||
1533 | {0x37c7, 0x00}, | ||
1534 | {0x3800, 0x00}, | ||
1535 | {0x3801, 0x14}, | ||
1536 | {0x3802, 0x00}, | ||
1537 | {0x3803, 0x0c}, | ||
1538 | {0x3804, 0x10}, | ||
1539 | {0x3805, 0x8b}, | ||
1540 | {0x3806, 0x0c}, | ||
1541 | {0x3807, 0x43}, | ||
1542 | {0x3808, 0x16}, | ||
1543 | {0x3809, 0x00}, | ||
1544 | {0x380a, 0x10}, | ||
1545 | {0x380b, 0x80}, | ||
1546 | {0x380c, 0x1c}, | ||
1547 | {0x380d, 0x20}, | ||
1548 | {0x380e, 0x12}, | ||
1549 | {0x380f, 0xc6}, | ||
1550 | {0x3810, 0x00}, | ||
1551 | {0x3811, 0x03}, | ||
1552 | {0x3813, 0x06}, | ||
1553 | {0x3814, 0x11}, | ||
1554 | {0x3815, 0x11}, | ||
1555 | {0x3820, 0x00}, | ||
1556 | {0x3821, 0x04}, | ||
1557 | {0x3834, 0x00}, | ||
1558 | {0x3835, 0x04}, | ||
1559 | {0x3836, 0x18}, | ||
1560 | {0x3837, 0x02}, | ||
1561 | {0x382f, 0x84}, | ||
1562 | {0x383c, 0xc8}, | ||
1563 | {0x383d, 0xff}, | ||
1564 | {0x3842, 0x00}, | ||
1565 | {0x384b, 0x00}, | ||
1566 | {0x3d85, 0x16}, | ||
1567 | {0x3d8c, 0x77}, | ||
1568 | {0x3d8d, 0x10}, | ||
1569 | {0x3f00, 0x52}, | ||
1570 | {0x4000, 0x17}, | ||
1571 | {0x4001, 0x60}, | ||
1572 | {0x4001, 0x60}, | ||
1573 | {0x4008, 0x00}, | ||
1574 | {0x4009, 0x13}, | ||
1575 | {0x400f, 0x00}, | ||
1576 | {0x4011, 0xfb}, | ||
1577 | {0x4017, 0x08}, | ||
1578 | {0x4018, 0x00}, | ||
1579 | {0x401a, 0xce}, | ||
1580 | {0x4019, 0x18}, | ||
1581 | {0x4020, 0x08}, | ||
1582 | {0x4022, 0x08}, | ||
1583 | {0x4024, 0x08}, | ||
1584 | {0x4026, 0x08}, | ||
1585 | {0x4028, 0x08}, | ||
1586 | {0x402a, 0x08}, | ||
1587 | {0x402c, 0x08}, | ||
1588 | {0x402e, 0x08}, | ||
1589 | {0x4030, 0x08}, | ||
1590 | {0x4032, 0x08}, | ||
1591 | {0x4034, 0x08}, | ||
1592 | {0x4036, 0x08}, | ||
1593 | {0x4038, 0x08}, | ||
1594 | {0x403a, 0x08}, | ||
1595 | {0x403c, 0x08}, | ||
1596 | {0x403e, 0x08}, | ||
1597 | {0x405c, 0x3f}, | ||
1598 | {0x4066, 0x04}, | ||
1599 | {0x4051, 0x03}, | ||
1600 | {0x4052, 0x00}, | ||
1601 | {0x4053, 0x80}, | ||
1602 | {0x4054, 0x00}, | ||
1603 | {0x4055, 0x80}, | ||
1604 | {0x4056, 0x00}, | ||
1605 | {0x4057, 0x80}, | ||
1606 | {0x4058, 0x00}, | ||
1607 | {0x4059, 0x80}, | ||
1608 | {0x4202, 0x00}, | ||
1609 | {0x4203, 0x01}, | ||
1610 | {0x430b, 0xff}, | ||
1611 | {0x430d, 0x00}, | ||
1612 | {0x4500, 0x72}, | ||
1613 | {0x4605, 0x00}, | ||
1614 | {0x4640, 0x01}, | ||
1615 | {0x4641, 0x04}, | ||
1616 | {0x4645, 0x00}, | ||
1617 | {0x4800, 0x04}, | ||
1618 | {0x4809, 0x2b}, | ||
1619 | {0x4813, 0x90}, | ||
1620 | {0x4817, 0x04}, | ||
1621 | {0x4833, 0x18}, | ||
1622 | {0x4837, 0x20}, | ||
1623 | {0x484b, 0x01}, | ||
1624 | {0x4850, 0x5c}, | ||
1625 | {0x4852, 0x27}, | ||
1626 | {0x4856, 0x5c}, | ||
1627 | {0x4857, 0x55}, | ||
1628 | {0x486a, 0xaa}, | ||
1629 | {0x486e, 0x03}, | ||
1630 | {0x486f, 0x55}, | ||
1631 | {0x4875, 0xf0}, | ||
1632 | {0x4b04, 0x80}, | ||
1633 | {0x4b05, 0xb3}, | ||
1634 | {0x4b06, 0x00}, | ||
1635 | {0x4c01, 0xdf}, | ||
1636 | {0x4d00, 0x04}, | ||
1637 | {0x4d01, 0xf0}, | ||
1638 | {0x4d02, 0xb8}, | ||
1639 | {0x4d03, 0xf2}, | ||
1640 | {0x4d04, 0x88}, | ||
1641 | {0x4d05, 0x9d}, | ||
1642 | {0x4e00, 0x04}, | ||
1643 | {0x4e17, 0x04}, | ||
1644 | {0x4e33, 0x18}, | ||
1645 | {0x4e37, 0x11}, | ||
1646 | {0x4e4b, 0x01}, | ||
1647 | {0x4e50, 0x5c}, | ||
1648 | {0x4e52, 0x27}, | ||
1649 | {0x4e56, 0x5c}, | ||
1650 | {0x4e57, 0x55}, | ||
1651 | {0x4e6a, 0xaa}, | ||
1652 | {0x4e6e, 0x03}, | ||
1653 | {0x4e6f, 0x55}, | ||
1654 | {0x4e75, 0xf0}, | ||
1655 | {0x5000, 0x9b}, | ||
1656 | {0x5001, 0x42}, | ||
1657 | {0x5002, 0x10}, | ||
1658 | {0x5003, 0x01}, | ||
1659 | {0x5004, 0x00}, | ||
1660 | {0x5005, 0x00}, | ||
1661 | {0x501d, 0x00}, | ||
1662 | {0x501f, 0x06}, | ||
1663 | {0x5020, 0x03}, | ||
1664 | {0x5021, 0x00}, | ||
1665 | {0x5022, 0x13}, | ||
1666 | {0x5061, 0xff}, | ||
1667 | {0x5062, 0xff}, | ||
1668 | {0x5063, 0xff}, | ||
1669 | {0x5064, 0xff}, | ||
1670 | {0x506f, 0x00}, | ||
1671 | {0x5280, 0x00}, | ||
1672 | {0x5282, 0x00}, | ||
1673 | {0x5283, 0x01}, | ||
1674 | {0x5200, 0x00}, | ||
1675 | {0x5201, 0x71}, | ||
1676 | {0x5203, 0x04}, | ||
1677 | {0x5204, 0x00}, | ||
1678 | {0x5205, 0x88}, | ||
1679 | {0x5209, 0x00}, | ||
1680 | {0x520a, 0x80}, | ||
1681 | {0x520b, 0x04}, | ||
1682 | {0x520c, 0x01}, | ||
1683 | {0x5210, 0x10}, | ||
1684 | {0x5211, 0xa0}, | ||
1685 | {0x5292, 0x04}, | ||
1686 | {0x5500, 0x00}, | ||
1687 | {0x5501, 0x00}, | ||
1688 | {0x5502, 0x00}, | ||
1689 | {0x5503, 0x00}, | ||
1690 | {0x5504, 0x00}, | ||
1691 | {0x5505, 0x00}, | ||
1692 | {0x5506, 0x00}, | ||
1693 | {0x5507, 0x00}, | ||
1694 | {0x5508, 0x10}, | ||
1695 | {0x5509, 0x00}, | ||
1696 | {0x550a, 0x10}, | ||
1697 | {0x550b, 0x00}, | ||
1698 | {0x550c, 0x20}, | ||
1699 | {0x550d, 0x00}, | ||
1700 | {0x550e, 0x20}, | ||
1701 | {0x550f, 0x00}, | ||
1702 | {0x5510, 0x00}, | ||
1703 | {0x5511, 0x00}, | ||
1704 | {0x5512, 0x00}, | ||
1705 | {0x5513, 0x00}, | ||
1706 | {0x5514, 0x00}, | ||
1707 | {0x5515, 0x00}, | ||
1708 | {0x5516, 0x00}, | ||
1709 | {0x5517, 0x00}, | ||
1710 | {0x5518, 0x00}, | ||
1711 | {0x5519, 0x00}, | ||
1712 | {0x551a, 0x00}, | ||
1713 | {0x551b, 0x00}, | ||
1714 | {0x551c, 0x00}, | ||
1715 | {0x551d, 0x00}, | ||
1716 | {0x551e, 0x00}, | ||
1717 | {0x551f, 0x00}, | ||
1718 | {0x5520, 0x00}, | ||
1719 | {0x5521, 0x00}, | ||
1720 | {0x5522, 0x00}, | ||
1721 | {0x5523, 0x00}, | ||
1722 | {0x5524, 0x00}, | ||
1723 | {0x5525, 0x00}, | ||
1724 | {0x5526, 0x00}, | ||
1725 | {0x5527, 0x00}, | ||
1726 | {0x5528, 0x00}, | ||
1727 | {0x5529, 0x10}, | ||
1728 | {0x552a, 0x00}, | ||
1729 | {0x552b, 0x10}, | ||
1730 | {0x552c, 0x00}, | ||
1731 | {0x552d, 0x20}, | ||
1732 | {0x552e, 0x00}, | ||
1733 | {0x552f, 0x20}, | ||
1734 | {0x5530, 0x00}, | ||
1735 | {0x5531, 0x00}, | ||
1736 | {0x5532, 0x00}, | ||
1737 | {0x5533, 0x00}, | ||
1738 | {0x5534, 0x00}, | ||
1739 | {0x5535, 0x00}, | ||
1740 | {0x5536, 0x00}, | ||
1741 | {0x5537, 0x00}, | ||
1742 | {0x5538, 0x00}, | ||
1743 | {0x5539, 0x00}, | ||
1744 | {0x553a, 0x00}, | ||
1745 | {0x553b, 0x00}, | ||
1746 | {0x553c, 0x00}, | ||
1747 | {0x553d, 0x00}, | ||
1748 | {0x553e, 0x00}, | ||
1749 | {0x553f, 0x00}, | ||
1750 | {0x5540, 0x00}, | ||
1751 | {0x5541, 0x00}, | ||
1752 | {0x5542, 0x00}, | ||
1753 | {0x5543, 0x00}, | ||
1754 | {0x5544, 0x00}, | ||
1755 | {0x5545, 0x00}, | ||
1756 | {0x5546, 0x00}, | ||
1757 | {0x5547, 0x00}, | ||
1758 | {0x5548, 0x01}, | ||
1759 | {0x5549, 0x00}, | ||
1760 | {0x554a, 0x01}, | ||
1761 | {0x554b, 0x00}, | ||
1762 | {0x554c, 0x02}, | ||
1763 | {0x554d, 0x00}, | ||
1764 | {0x554e, 0x02}, | ||
1765 | {0x554f, 0x00}, | ||
1766 | {0x5550, 0x00}, | ||
1767 | {0x5551, 0x00}, | ||
1768 | {0x5552, 0x00}, | ||
1769 | {0x5553, 0x00}, | ||
1770 | {0x5554, 0x00}, | ||
1771 | {0x5555, 0x00}, | ||
1772 | {0x5556, 0x00}, | ||
1773 | {0x5557, 0x00}, | ||
1774 | {0x5558, 0x00}, | ||
1775 | {0x5559, 0x00}, | ||
1776 | {0x555a, 0x00}, | ||
1777 | {0x555b, 0x00}, | ||
1778 | {0x555c, 0x00}, | ||
1779 | {0x555d, 0x00}, | ||
1780 | {0x555e, 0x00}, | ||
1781 | {0x555f, 0x00}, | ||
1782 | {0x5560, 0x00}, | ||
1783 | {0x5561, 0x00}, | ||
1784 | {0x5562, 0x00}, | ||
1785 | {0x5563, 0x00}, | ||
1786 | {0x5564, 0x00}, | ||
1787 | {0x5565, 0x00}, | ||
1788 | {0x5566, 0x00}, | ||
1789 | {0x5567, 0x00}, | ||
1790 | {0x5568, 0x00}, | ||
1791 | {0x5569, 0x10}, | ||
1792 | {0x556a, 0x00}, | ||
1793 | {0x556b, 0x10}, | ||
1794 | {0x556c, 0x00}, | ||
1795 | {0x556d, 0x20}, | ||
1796 | {0x556e, 0x00}, | ||
1797 | {0x556f, 0x20}, | ||
1798 | {0x5570, 0x00}, | ||
1799 | {0x5571, 0x00}, | ||
1800 | {0x5572, 0x00}, | ||
1801 | {0x5573, 0x00}, | ||
1802 | {0x5574, 0x00}, | ||
1803 | {0x5575, 0x00}, | ||
1804 | {0x5576, 0x00}, | ||
1805 | {0x5577, 0x00}, | ||
1806 | {0x5578, 0x00}, | ||
1807 | {0x5579, 0x00}, | ||
1808 | {0x557a, 0x00}, | ||
1809 | {0x557b, 0x00}, | ||
1810 | {0x557c, 0x00}, | ||
1811 | {0x557d, 0x00}, | ||
1812 | {0x557e, 0x00}, | ||
1813 | {0x557f, 0x00}, | ||
1814 | {0x5580, 0x00}, | ||
1815 | {0x5581, 0x00}, | ||
1816 | {0x5582, 0x00}, | ||
1817 | {0x5583, 0x00}, | ||
1818 | {0x5584, 0x10}, | ||
1819 | {0x5585, 0x00}, | ||
1820 | {0x5586, 0x10}, | ||
1821 | {0x5587, 0x00}, | ||
1822 | {0x5588, 0x38}, | ||
1823 | {0x5589, 0x00}, | ||
1824 | {0x558a, 0x38}, | ||
1825 | {0x558b, 0x00}, | ||
1826 | {0x558c, 0x70}, | ||
1827 | {0x558d, 0x00}, | ||
1828 | {0x558e, 0x70}, | ||
1829 | {0x558f, 0x00}, | ||
1830 | {0x5590, 0x20}, | ||
1831 | {0x5591, 0x00}, | ||
1832 | {0x5592, 0x20}, | ||
1833 | {0x5593, 0x00}, | ||
1834 | {0x5594, 0x00}, | ||
1835 | {0x5595, 0x00}, | ||
1836 | {0x5596, 0x00}, | ||
1837 | {0x5597, 0x00}, | ||
1838 | {0x5598, 0x00}, | ||
1839 | {0x5599, 0x00}, | ||
1840 | {0x559a, 0x00}, | ||
1841 | {0x559b, 0x00}, | ||
1842 | {0x559c, 0x00}, | ||
1843 | {0x559d, 0x00}, | ||
1844 | {0x559e, 0x00}, | ||
1845 | {0x559f, 0x00}, | ||
1846 | {0x55a0, 0x00}, | ||
1847 | {0x55a1, 0x00}, | ||
1848 | {0x55a2, 0x00}, | ||
1849 | {0x55a3, 0x00}, | ||
1850 | {0x55a4, 0x00}, | ||
1851 | {0x55a5, 0x10}, | ||
1852 | {0x55a6, 0x00}, | ||
1853 | {0x55a7, 0x10}, | ||
1854 | {0x55a8, 0x00}, | ||
1855 | {0x55a9, 0x38}, | ||
1856 | {0x55aa, 0x00}, | ||
1857 | {0x55ab, 0x38}, | ||
1858 | {0x55ac, 0x00}, | ||
1859 | {0x55ad, 0x70}, | ||
1860 | {0x55ae, 0x00}, | ||
1861 | {0x55af, 0x70}, | ||
1862 | {0x55b0, 0x00}, | ||
1863 | {0x55b1, 0x20}, | ||
1864 | {0x55b2, 0x00}, | ||
1865 | {0x55b3, 0x20}, | ||
1866 | {0x55b4, 0x00}, | ||
1867 | {0x55b5, 0x00}, | ||
1868 | {0x55b6, 0x00}, | ||
1869 | {0x55b7, 0x00}, | ||
1870 | {0x55b8, 0x00}, | ||
1871 | {0x55b9, 0x00}, | ||
1872 | {0x55ba, 0x00}, | ||
1873 | {0x55bb, 0x00}, | ||
1874 | {0x55bc, 0x00}, | ||
1875 | {0x55bd, 0x00}, | ||
1876 | {0x55be, 0x00}, | ||
1877 | {0x55bf, 0x00}, | ||
1878 | {0x55c0, 0x00}, | ||
1879 | {0x55c1, 0x00}, | ||
1880 | {0x55c2, 0x00}, | ||
1881 | {0x55c3, 0x00}, | ||
1882 | {0x55c4, 0x01}, | ||
1883 | {0x55c5, 0x00}, | ||
1884 | {0x55c6, 0x01}, | ||
1885 | {0x55c7, 0x00}, | ||
1886 | {0x55c8, 0x03}, | ||
1887 | {0x55c9, 0x80}, | ||
1888 | {0x55ca, 0x03}, | ||
1889 | {0x55cb, 0x80}, | ||
1890 | {0x55cc, 0x07}, | ||
1891 | {0x55cd, 0x00}, | ||
1892 | {0x55ce, 0x07}, | ||
1893 | {0x55cf, 0x00}, | ||
1894 | {0x55d0, 0x02}, | ||
1895 | {0x55d1, 0x00}, | ||
1896 | {0x55d2, 0x02}, | ||
1897 | {0x55d3, 0x00}, | ||
1898 | {0x55d4, 0x00}, | ||
1899 | {0x55d5, 0x00}, | ||
1900 | {0x55d6, 0x00}, | ||
1901 | {0x55d7, 0x00}, | ||
1902 | {0x55d8, 0x00}, | ||
1903 | {0x55d9, 0x00}, | ||
1904 | {0x55da, 0x00}, | ||
1905 | {0x55db, 0x00}, | ||
1906 | {0x55dc, 0x00}, | ||
1907 | {0x55dd, 0x00}, | ||
1908 | {0x55de, 0x00}, | ||
1909 | {0x55df, 0x00}, | ||
1910 | {0x55e0, 0x00}, | ||
1911 | {0x55e1, 0x00}, | ||
1912 | {0x55e2, 0x00}, | ||
1913 | {0x55e3, 0x00}, | ||
1914 | {0x55e4, 0x00}, | ||
1915 | {0x55e5, 0x10}, | ||
1916 | {0x55e6, 0x00}, | ||
1917 | {0x55e7, 0x10}, | ||
1918 | {0x55e8, 0x00}, | ||
1919 | {0x55e9, 0x38}, | ||
1920 | {0x55ea, 0x00}, | ||
1921 | {0x55eb, 0x38}, | ||
1922 | {0x55ec, 0x00}, | ||
1923 | {0x55ed, 0x70}, | ||
1924 | {0x55ee, 0x00}, | ||
1925 | {0x55ef, 0x70}, | ||
1926 | {0x55f0, 0x00}, | ||
1927 | {0x55f1, 0x20}, | ||
1928 | {0x55f2, 0x00}, | ||
1929 | {0x55f3, 0x20}, | ||
1930 | {0x55f4, 0x00}, | ||
1931 | {0x55f5, 0x00}, | ||
1932 | {0x55f6, 0x00}, | ||
1933 | {0x55f7, 0x00}, | ||
1934 | {0x55f8, 0x00}, | ||
1935 | {0x55f9, 0x00}, | ||
1936 | {0x55fa, 0x00}, | ||
1937 | {0x55fb, 0x00}, | ||
1938 | {0x55fc, 0x00}, | ||
1939 | {0x55fd, 0x00}, | ||
1940 | {0x55fe, 0x00}, | ||
1941 | {0x55ff, 0x00}, | ||
1942 | {0x5600, 0x30}, | ||
1943 | {0x5601, 0x00}, | ||
1944 | {0x5602, 0x00}, | ||
1945 | {0x5603, 0x00}, | ||
1946 | {0x5604, 0x00}, | ||
1947 | {0x5605, 0x00}, | ||
1948 | {0x5606, 0x00}, | ||
1949 | {0x5607, 0x01}, | ||
1950 | {0x5608, 0x01}, | ||
1951 | {0x5609, 0x01}, | ||
1952 | {0x560f, 0xfc}, | ||
1953 | {0x5610, 0xf0}, | ||
1954 | {0x5611, 0x10}, | ||
1955 | {0x562f, 0xfc}, | ||
1956 | {0x5630, 0xf0}, | ||
1957 | {0x5631, 0x10}, | ||
1958 | {0x564f, 0xfc}, | ||
1959 | {0x5650, 0xf0}, | ||
1960 | {0x5651, 0x10}, | ||
1961 | {0x566f, 0xfc}, | ||
1962 | {0x5670, 0xf0}, | ||
1963 | {0x5671, 0x10}, | ||
1964 | {0x567b, 0x40}, | ||
1965 | {0x5690, 0x00}, | ||
1966 | {0x5691, 0x00}, | ||
1967 | {0x5692, 0x00}, | ||
1968 | {0x5693, 0x0a}, | ||
1969 | {0x5694, 0x80}, | ||
1970 | {0x5696, 0x06}, | ||
1971 | {0x5697, 0x0a}, | ||
1972 | {0x5698, 0x00}, | ||
1973 | {0x5699, 0x90}, | ||
1974 | {0x569a, 0x15}, | ||
1975 | {0x569b, 0x90}, | ||
1976 | {0x569c, 0x00}, | ||
1977 | {0x569d, 0x50}, | ||
1978 | {0x569e, 0x10}, | ||
1979 | {0x569f, 0x50}, | ||
1980 | {0x56a0, 0x36}, | ||
1981 | {0x56a1, 0x50}, | ||
1982 | {0x56a2, 0x16}, | ||
1983 | {0x56a3, 0x20}, | ||
1984 | {0x56a4, 0x10}, | ||
1985 | {0x56a5, 0xa0}, | ||
1986 | {0x5c80, 0x06}, | ||
1987 | {0x5c81, 0x80}, | ||
1988 | {0x5c82, 0x09}, | ||
1989 | {0x5c83, 0x5f}, | ||
1990 | {0x5d04, 0x01}, | ||
1991 | {0x5d05, 0x1a}, | ||
1992 | {0x5d06, 0x01}, | ||
1993 | {0x5d07, 0x1a}, | ||
1994 | {0x5d12, 0xf7}, | ||
1995 | {0x5d13, 0xdd}, | ||
1996 | {0x5d14, 0x97}, | ||
1997 | {0x5d15, 0x69}, | ||
1998 | {0x5d16, 0x61}, | ||
1999 | {0x5d17, 0x5b}, | ||
2000 | {0x5d18, 0x62}, | ||
2001 | {0x5d19, 0x8d}, | ||
2002 | {0x5d1a, 0xdd}, | ||
2003 | {0x5d1b, 0xff}, | ||
2004 | {0x5d24, 0x00}, | ||
2005 | {0x5d25, 0x00}, | ||
2006 | {0x5d26, 0x00}, | ||
2007 | {0x5d27, 0x0a}, | ||
2008 | {0x5d28, 0x80}, | ||
2009 | {0x5d2a, 0x00}, | ||
2010 | {0x5d2b, 0x90}, | ||
2011 | {0x5d2c, 0x15}, | ||
2012 | {0x5d2d, 0x90}, | ||
2013 | {0x5d2e, 0x00}, | ||
2014 | {0x5d2f, 0x50}, | ||
2015 | {0x5d30, 0x10}, | ||
2016 | {0x5d31, 0x50}, | ||
2017 | {0x5d32, 0x10}, | ||
2018 | {0x5d34, 0x36}, | ||
2019 | {0x5d35, 0x20}, | ||
2020 | {0x5d36, 0x90}, | ||
2021 | {0x5d37, 0xa0}, | ||
2022 | {0x5d38, 0x5c}, | ||
2023 | {0x5d39, 0x7b}, | ||
2024 | {0x5d1c, 0x00}, | ||
2025 | {0x5d1d, 0x90}, | ||
2026 | {0x5d1e, 0x00}, | ||
2027 | {0x5d1f, 0x50}, | ||
2028 | {0x5d20, 0x15}, | ||
2029 | {0x5d21, 0x00}, | ||
2030 | {0x5d22, 0x10}, | ||
2031 | {0x5d23, 0x00}, | ||
2032 | {0x5d29, 0xc0}, | ||
2033 | {0x3008, 0x01}, | ||
2034 | {0x3663, 0x60}, | ||
2035 | {0x3002, 0x01}, | ||
2036 | {0x3c00, 0x3c}, | ||
2037 | {0x3025, 0x03}, | ||
2038 | {0x3668, 0xf0}, | ||
2039 | {0x3400, 0x04}, | ||
2040 | {OV23850_TABLE_END, 0x00} | ||
2041 | }; | ||
2042 | |||
2043 | static ov23850_reg mode_5632x4224_24fps_dpcm[] = { | ||
2044 | {0x0317, 0x00}, | ||
2045 | {0x0318, 0x03}, | ||
2046 | {0x0316, 0x1e}, | ||
2047 | {0x0318, 0x03}, | ||
2048 | {0x031c, 0x01}, | ||
2049 | {0x031d, 0x02}, | ||
2050 | {0x031e, 0x00}, | ||
2051 | {0x2b05, 0x02}, | ||
2052 | {0x2b06, 0x87}, | ||
2053 | {0x2b07, 0x01}, | ||
2054 | {0x2b08, 0xa8}, | ||
2055 | {0x0320, 0x02}, | ||
2056 | {0x3002, 0x00}, | ||
2057 | {0x300f, 0x11}, | ||
2058 | {0x3010, 0x01}, | ||
2059 | {0x3012, 0x41}, | ||
2060 | {0x3031, 0x91}, | ||
2061 | {0x3034, 0x41}, | ||
2062 | {0x340c, 0xff}, | ||
2063 | {0x3501, 0x12}, | ||
2064 | {0x3502, 0xa6}, | ||
2065 | {0x3503, 0x00}, | ||
2066 | {0x3507, 0x00}, | ||
2067 | {0x3508, 0x00}, | ||
2068 | {0x3509, 0x12}, | ||
2069 | {0x350a, 0x00}, | ||
2070 | {0x350b, 0x80}, | ||
2071 | {0x350f, 0x10}, | ||
2072 | {0x3541, 0x02}, | ||
2073 | {0x3542, 0x00}, | ||
2074 | {0x3543, 0x00}, | ||
2075 | {0x3547, 0x00}, | ||
2076 | {0x3548, 0x00}, | ||
2077 | {0x3549, 0x12}, | ||
2078 | {0x354b, 0x10}, | ||
2079 | {0x354f, 0x10}, | ||
2080 | {0x3603, 0x97}, | ||
2081 | {0x3606, 0xe8}, | ||
2082 | {0x3607, 0x11}, | ||
2083 | {0x360a, 0x44}, | ||
2084 | {0x360c, 0x11}, | ||
2085 | {0x3618, 0xcc}, | ||
2086 | {0x3620, 0x60}, | ||
2087 | {0x3621, 0x99}, | ||
2088 | {0x3622, 0x7c}, | ||
2089 | {0x3624, 0x05}, | ||
2090 | {0x362a, 0x25}, | ||
2091 | {0x3650, 0x04}, | ||
2092 | {0x3660, 0xc4}, | ||
2093 | {0x3661, 0x00}, | ||
2094 | {0x3662, 0x00}, | ||
2095 | {0x3664, 0x88}, | ||
2096 | {0x3667, 0x00}, | ||
2097 | {0x366a, 0x1c}, | ||
2098 | {0x366c, 0x80}, | ||
2099 | {0x3700, 0x62}, | ||
2100 | {0x3701, 0x08}, | ||
2101 | {0x3702, 0x10}, | ||
2102 | {0x3703, 0x38}, | ||
2103 | {0x3704, 0x26}, | ||
2104 | {0x3705, 0x01}, | ||
2105 | {0x3706, 0x3a}, | ||
2106 | {0x3707, 0xc4}, | ||
2107 | {0x3708, 0x3c}, | ||
2108 | {0x3709, 0x30}, | ||
2109 | {0x370a, 0x23}, | ||
2110 | {0x370b, 0x2c}, | ||
2111 | {0x370c, 0x42}, | ||
2112 | {0x370d, 0xa4}, | ||
2113 | {0x370e, 0x14}, | ||
2114 | {0x370f, 0x0a}, | ||
2115 | {0x3710, 0x15}, | ||
2116 | {0x3711, 0x0a}, | ||
2117 | {0x3712, 0xa2}, | ||
2118 | {0x3713, 0x00}, | ||
2119 | {0x371e, 0x2a}, | ||
2120 | {0x371f, 0x13}, | ||
2121 | {0x3714, 0x00}, | ||
2122 | {0x3717, 0x00}, | ||
2123 | {0x3719, 0x00}, | ||
2124 | {0x371c, 0x04}, | ||
2125 | {0x3720, 0xaa}, | ||
2126 | {0x3721, 0x10}, | ||
2127 | {0x3722, 0x50}, | ||
2128 | {0x3726, 0x22}, | ||
2129 | {0x3727, 0x44}, | ||
2130 | {0x3728, 0x40}, | ||
2131 | {0x3729, 0x00}, | ||
2132 | {0x372b, 0x00}, | ||
2133 | {0x372c, 0x92}, | ||
2134 | {0x372d, 0x0c}, | ||
2135 | {0x372e, 0x22}, | ||
2136 | {0x372f, 0x91}, | ||
2137 | {0x3732, 0x01}, | ||
2138 | {0x3733, 0xd0}, | ||
2139 | {0x3730, 0x01}, | ||
2140 | {0x3731, 0xc8}, | ||
2141 | {0x3744, 0x01}, | ||
2142 | {0x3745, 0x24}, | ||
2143 | {0x3746, 0x00}, | ||
2144 | {0x3747, 0xd0}, | ||
2145 | {0x3748, 0x27}, | ||
2146 | {0x374a, 0x4b}, | ||
2147 | {0x374b, 0x44}, | ||
2148 | {0x3760, 0xd1}, | ||
2149 | {0x3761, 0x52}, | ||
2150 | {0x3762, 0xa4}, | ||
2151 | {0x3763, 0x14}, | ||
2152 | {0x3766, 0x0c}, | ||
2153 | {0x3767, 0x25}, | ||
2154 | {0x3768, 0x0c}, | ||
2155 | {0x3769, 0x24}, | ||
2156 | {0x376a, 0x09}, | ||
2157 | {0x376b, 0x02}, | ||
2158 | {0x376d, 0x01}, | ||
2159 | {0x376e, 0x53}, | ||
2160 | {0x376f, 0x01}, | ||
2161 | {0x378c, 0x08}, | ||
2162 | {0x378d, 0x46}, | ||
2163 | {0x378e, 0x14}, | ||
2164 | {0x378f, 0x02}, | ||
2165 | {0x3790, 0xc4}, | ||
2166 | {0x3792, 0x64}, | ||
2167 | {0x3793, 0x5d}, | ||
2168 | {0x3794, 0x29}, | ||
2169 | {0x3795, 0x4f}, | ||
2170 | {0x3796, 0x43}, | ||
2171 | {0x3797, 0x09}, | ||
2172 | {0x3798, 0x02}, | ||
2173 | {0x3799, 0x33}, | ||
2174 | {0x379a, 0x09}, | ||
2175 | {0x379b, 0x1e}, | ||
2176 | {0x379f, 0x3e}, | ||
2177 | {0x37a0, 0x44}, | ||
2178 | {0x37a1, 0x00}, | ||
2179 | {0x37a2, 0x44}, | ||
2180 | {0x37a3, 0x41}, | ||
2181 | {0x37a4, 0x88}, | ||
2182 | {0x37a5, 0x69}, | ||
2183 | {0x37b0, 0x48}, | ||
2184 | {0x37b1, 0x20}, | ||
2185 | {0x37b2, 0x03}, | ||
2186 | {0x37b3, 0x48}, | ||
2187 | {0x37b4, 0x02}, | ||
2188 | {0x37b5, 0x33}, | ||
2189 | {0x37b6, 0x22}, | ||
2190 | {0x37b8, 0x02}, | ||
2191 | {0x37bc, 0x02}, | ||
2192 | {0x37c0, 0x3b}, | ||
2193 | {0x37c1, 0xc2}, | ||
2194 | {0x37c2, 0x06}, | ||
2195 | {0x37c3, 0x06}, | ||
2196 | {0x37c5, 0x33}, | ||
2197 | {0x37c6, 0x35}, | ||
2198 | {0x37c7, 0x00}, | ||
2199 | {0x3800, 0x00}, | ||
2200 | {0x3801, 0x14}, | ||
2201 | {0x3802, 0x00}, | ||
2202 | {0x3803, 0x0c}, | ||
2203 | {0x3804, 0x10}, | ||
2204 | {0x3805, 0x8b}, | ||
2205 | {0x3806, 0x0c}, | ||
2206 | {0x3807, 0x43}, | ||
2207 | {0x3808, 0x16}, | ||
2208 | {0x3809, 0x00}, | ||
2209 | {0x380a, 0x10}, | ||
2210 | {0x380b, 0x80}, | ||
2211 | {0x380c, 0x18}, | ||
2212 | {0x380d, 0x60}, | ||
2213 | {0x380e, 0x12}, | ||
2214 | {0x380f, 0xc6}, | ||
2215 | {0x3810, 0x00}, | ||
2216 | {0x3811, 0x03}, | ||
2217 | {0x3813, 0x02}, | ||
2218 | {0x3814, 0x11}, | ||
2219 | {0x3815, 0x11}, | ||
2220 | {0x3820, 0x00}, | ||
2221 | {0x3821, 0x04}, | ||
2222 | {0x3834, 0x00}, | ||
2223 | {0x3835, 0x04}, | ||
2224 | {0x3836, 0x18}, | ||
2225 | {0x3837, 0x02}, | ||
2226 | {0x382f, 0x84}, | ||
2227 | {0x383c, 0xc8}, | ||
2228 | {0x383d, 0xff}, | ||
2229 | {0x3842, 0x00}, | ||
2230 | {0x384b, 0x00}, | ||
2231 | {0x3d85, 0x16}, | ||
2232 | {0x3f00, 0x12}, | ||
2233 | {0x4000, 0x17}, | ||
2234 | {0x4001, 0x60}, | ||
2235 | {0x4001, 0x60}, | ||
2236 | {0x4008, 0x00}, | ||
2237 | {0x4009, 0x13}, | ||
2238 | {0x400f, 0x00}, | ||
2239 | {0x4011, 0xfb}, | ||
2240 | {0x4017, 0x08}, | ||
2241 | {0x4018, 0x00}, | ||
2242 | {0x401a, 0x4e}, | ||
2243 | {0x4019, 0x18}, | ||
2244 | {0x4020, 0x08}, | ||
2245 | {0x4022, 0x08}, | ||
2246 | {0x4024, 0x08}, | ||
2247 | {0x4026, 0x08}, | ||
2248 | {0x4028, 0x08}, | ||
2249 | {0x402a, 0x08}, | ||
2250 | {0x402c, 0x08}, | ||
2251 | {0x402e, 0x08}, | ||
2252 | {0x4030, 0x08}, | ||
2253 | {0x4032, 0x08}, | ||
2254 | {0x4034, 0x08}, | ||
2255 | {0x4036, 0x08}, | ||
2256 | {0x4038, 0x08}, | ||
2257 | {0x403a, 0x08}, | ||
2258 | {0x403c, 0x08}, | ||
2259 | {0x403e, 0x08}, | ||
2260 | {0x405c, 0x3f}, | ||
2261 | {0x4066, 0x04}, | ||
2262 | {0x4051, 0x03}, | ||
2263 | {0x4052, 0x00}, | ||
2264 | {0x4053, 0x80}, | ||
2265 | {0x4054, 0x00}, | ||
2266 | {0x4055, 0x80}, | ||
2267 | {0x4056, 0x00}, | ||
2268 | {0x4057, 0x80}, | ||
2269 | {0x4058, 0x00}, | ||
2270 | {0x4059, 0x80}, | ||
2271 | {0x4202, 0x00}, | ||
2272 | {0x4203, 0x01}, | ||
2273 | {0x430b, 0xff}, | ||
2274 | {0x430d, 0x00}, | ||
2275 | {0x4500, 0x72}, | ||
2276 | {0x4605, 0x00}, | ||
2277 | {0x4640, 0x01}, | ||
2278 | {0x4641, 0x04}, | ||
2279 | {0x4645, 0x00}, | ||
2280 | {0x4800, 0x04}, | ||
2281 | {0x4809, 0x2b}, | ||
2282 | {0x4813, 0x90}, | ||
2283 | {0x4817, 0x04}, | ||
2284 | {0x4833, 0x18}, | ||
2285 | {0x4837, 0x0A}, | ||
2286 | {0x484b, 0x01}, | ||
2287 | {0x4850, 0x5c}, | ||
2288 | {0x4852, 0x27}, | ||
2289 | {0x4856, 0x5c}, | ||
2290 | {0x4857, 0x55}, | ||
2291 | {0x486a, 0xaa}, | ||
2292 | {0x486e, 0x03}, | ||
2293 | {0x486f, 0x55}, | ||
2294 | {0x4875, 0xf0}, | ||
2295 | {0x4b04, 0x80}, | ||
2296 | {0x4b06, 0x00}, | ||
2297 | {0x4c01, 0xdf}, | ||
2298 | {0x4e00, 0x04}, | ||
2299 | {0x4e17, 0x04}, | ||
2300 | {0x4e33, 0x18}, | ||
2301 | {0x4e37, 0x11}, | ||
2302 | {0x4e4b, 0x01}, | ||
2303 | {0x4e50, 0x5c}, | ||
2304 | {0x4e52, 0x27}, | ||
2305 | {0x4e56, 0x5c}, | ||
2306 | {0x4e57, 0x55}, | ||
2307 | {0x4e6a, 0xaa}, | ||
2308 | {0x4e6e, 0x03}, | ||
2309 | {0x4e6f, 0x55}, | ||
2310 | {0x4e75, 0xf0}, | ||
2311 | {0x5000, 0x99}, | ||
2312 | {0x5001, 0x42}, | ||
2313 | {0x5002, 0x04}, | ||
2314 | {0x5003, 0x01}, | ||
2315 | {0x5004, 0x00}, | ||
2316 | {0x5005, 0x00}, | ||
2317 | {0x501d, 0x00}, | ||
2318 | {0x501f, 0x06}, | ||
2319 | {0x5021, 0x00}, | ||
2320 | {0x5022, 0x13}, | ||
2321 | {0x5061, 0xff}, | ||
2322 | {0x5062, 0xff}, | ||
2323 | {0x5063, 0xff}, | ||
2324 | {0x5064, 0xff}, | ||
2325 | {0x5280, 0x00}, | ||
2326 | {0x5282, 0x00}, | ||
2327 | {0x5283, 0x01}, | ||
2328 | {0x5200, 0x00}, | ||
2329 | {0x5201, 0x71}, | ||
2330 | {0x5203, 0x04}, | ||
2331 | {0x5204, 0x00}, | ||
2332 | {0x5205, 0x88}, | ||
2333 | {0x5209, 0x00}, | ||
2334 | {0x520a, 0x80}, | ||
2335 | {0x520b, 0x04}, | ||
2336 | {0x520c, 0x01}, | ||
2337 | {0x5210, 0x10}, | ||
2338 | {0x5211, 0xa0}, | ||
2339 | {0x5292, 0x00}, | ||
2340 | {0x5500, 0x00}, | ||
2341 | {0x5501, 0x00}, | ||
2342 | {0x5502, 0x00}, | ||
2343 | {0x5503, 0x00}, | ||
2344 | {0x5504, 0x00}, | ||
2345 | {0x5505, 0x00}, | ||
2346 | {0x5506, 0x00}, | ||
2347 | {0x5507, 0x00}, | ||
2348 | {0x5508, 0x00}, | ||
2349 | {0x5509, 0x00}, | ||
2350 | {0x550a, 0x00}, | ||
2351 | {0x550b, 0x00}, | ||
2352 | {0x550c, 0x00}, | ||
2353 | {0x550d, 0x00}, | ||
2354 | {0x550e, 0x00}, | ||
2355 | {0x550f, 0x00}, | ||
2356 | {0x5510, 0x04}, | ||
2357 | {0x5511, 0x04}, | ||
2358 | {0x5512, 0x04}, | ||
2359 | {0x5513, 0x04}, | ||
2360 | {0x5514, 0x08}, | ||
2361 | {0x5515, 0x08}, | ||
2362 | {0x5516, 0x08}, | ||
2363 | {0x5517, 0x08}, | ||
2364 | {0x5518, 0x00}, | ||
2365 | {0x5519, 0x00}, | ||
2366 | {0x551a, 0x00}, | ||
2367 | {0x551b, 0x00}, | ||
2368 | {0x551c, 0x00}, | ||
2369 | {0x551d, 0x00}, | ||
2370 | {0x551e, 0x00}, | ||
2371 | {0x551f, 0x00}, | ||
2372 | {0x5520, 0x00}, | ||
2373 | {0x5521, 0x00}, | ||
2374 | {0x5522, 0x00}, | ||
2375 | {0x5523, 0x00}, | ||
2376 | {0x5524, 0x00}, | ||
2377 | {0x5525, 0x00}, | ||
2378 | {0x5526, 0x00}, | ||
2379 | {0x5527, 0x00}, | ||
2380 | {0x5528, 0x00}, | ||
2381 | {0x5529, 0x00}, | ||
2382 | {0x552a, 0x00}, | ||
2383 | {0x552b, 0x00}, | ||
2384 | {0x552c, 0x00}, | ||
2385 | {0x552d, 0x00}, | ||
2386 | {0x552e, 0x00}, | ||
2387 | {0x552f, 0x00}, | ||
2388 | {0x5530, 0x04}, | ||
2389 | {0x5531, 0x04}, | ||
2390 | {0x5532, 0x04}, | ||
2391 | {0x5533, 0x04}, | ||
2392 | {0x5534, 0x08}, | ||
2393 | {0x5535, 0x08}, | ||
2394 | {0x5536, 0x08}, | ||
2395 | {0x5537, 0x08}, | ||
2396 | {0x5538, 0x00}, | ||
2397 | {0x5539, 0x00}, | ||
2398 | {0x553a, 0x00}, | ||
2399 | {0x553b, 0x00}, | ||
2400 | {0x553c, 0x00}, | ||
2401 | {0x553d, 0x00}, | ||
2402 | {0x553e, 0x00}, | ||
2403 | {0x553f, 0x00}, | ||
2404 | {0x5540, 0x00}, | ||
2405 | {0x5541, 0x00}, | ||
2406 | {0x5542, 0x00}, | ||
2407 | {0x5543, 0x00}, | ||
2408 | {0x5544, 0x00}, | ||
2409 | {0x5545, 0x00}, | ||
2410 | {0x5546, 0x00}, | ||
2411 | {0x5547, 0x00}, | ||
2412 | {0x5548, 0x00}, | ||
2413 | {0x5549, 0x00}, | ||
2414 | {0x554a, 0x00}, | ||
2415 | {0x554b, 0x00}, | ||
2416 | {0x554c, 0x00}, | ||
2417 | {0x554d, 0x00}, | ||
2418 | {0x554e, 0x00}, | ||
2419 | {0x554f, 0x00}, | ||
2420 | {0x5550, 0x04}, | ||
2421 | {0x5551, 0x04}, | ||
2422 | {0x5552, 0x04}, | ||
2423 | {0x5553, 0x04}, | ||
2424 | {0x5554, 0x08}, | ||
2425 | {0x5555, 0x08}, | ||
2426 | {0x5556, 0x08}, | ||
2427 | {0x5557, 0x08}, | ||
2428 | {0x5558, 0x00}, | ||
2429 | {0x5559, 0x00}, | ||
2430 | {0x555a, 0x00}, | ||
2431 | {0x555b, 0x00}, | ||
2432 | {0x555c, 0x00}, | ||
2433 | {0x555d, 0x00}, | ||
2434 | {0x555e, 0x00}, | ||
2435 | {0x555f, 0x00}, | ||
2436 | {0x5560, 0x00}, | ||
2437 | {0x5561, 0x00}, | ||
2438 | {0x5562, 0x00}, | ||
2439 | {0x5563, 0x00}, | ||
2440 | {0x5564, 0x00}, | ||
2441 | {0x5565, 0x00}, | ||
2442 | {0x5566, 0x00}, | ||
2443 | {0x5567, 0x00}, | ||
2444 | {0x5568, 0x00}, | ||
2445 | {0x5569, 0x00}, | ||
2446 | {0x556a, 0x00}, | ||
2447 | {0x556b, 0x00}, | ||
2448 | {0x556c, 0x00}, | ||
2449 | {0x556d, 0x00}, | ||
2450 | {0x556e, 0x00}, | ||
2451 | {0x556f, 0x00}, | ||
2452 | {0x5570, 0x04}, | ||
2453 | {0x5571, 0x04}, | ||
2454 | {0x5572, 0x04}, | ||
2455 | {0x5573, 0x04}, | ||
2456 | {0x5574, 0x08}, | ||
2457 | {0x5575, 0x08}, | ||
2458 | {0x5576, 0x08}, | ||
2459 | {0x5577, 0x08}, | ||
2460 | {0x5578, 0x00}, | ||
2461 | {0x5579, 0x00}, | ||
2462 | {0x557a, 0x00}, | ||
2463 | {0x557b, 0x00}, | ||
2464 | {0x557c, 0x00}, | ||
2465 | {0x557d, 0x00}, | ||
2466 | {0x557e, 0x00}, | ||
2467 | {0x557f, 0x00}, | ||
2468 | {0x5580, 0x00}, | ||
2469 | {0x5581, 0x00}, | ||
2470 | {0x5582, 0x00}, | ||
2471 | {0x5583, 0x00}, | ||
2472 | {0x5584, 0x00}, | ||
2473 | {0x5585, 0x00}, | ||
2474 | {0x5586, 0x00}, | ||
2475 | {0x5587, 0x00}, | ||
2476 | {0x5588, 0x00}, | ||
2477 | {0x5589, 0x00}, | ||
2478 | {0x558a, 0x00}, | ||
2479 | {0x558b, 0x00}, | ||
2480 | {0x558c, 0x04}, | ||
2481 | {0x558d, 0x04}, | ||
2482 | {0x558e, 0x04}, | ||
2483 | {0x558f, 0x04}, | ||
2484 | {0x5590, 0x0e}, | ||
2485 | {0x5591, 0x0e}, | ||
2486 | {0x5592, 0x0e}, | ||
2487 | {0x5593, 0x0e}, | ||
2488 | {0x5594, 0x1c}, | ||
2489 | {0x5595, 0x1c}, | ||
2490 | {0x5596, 0x1c}, | ||
2491 | {0x5597, 0x1c}, | ||
2492 | {0x5598, 0x08}, | ||
2493 | {0x5599, 0x08}, | ||
2494 | {0x559a, 0x08}, | ||
2495 | {0x559b, 0x08}, | ||
2496 | {0x559c, 0x00}, | ||
2497 | {0x559d, 0x00}, | ||
2498 | {0x559e, 0x00}, | ||
2499 | {0x559f, 0x00}, | ||
2500 | {0x55a0, 0x00}, | ||
2501 | {0x55a1, 0x00}, | ||
2502 | {0x55a2, 0x00}, | ||
2503 | {0x55a3, 0x00}, | ||
2504 | {0x55a4, 0x00}, | ||
2505 | {0x55a5, 0x00}, | ||
2506 | {0x55a6, 0x00}, | ||
2507 | {0x55a7, 0x00}, | ||
2508 | {0x55a8, 0x00}, | ||
2509 | {0x55a9, 0x00}, | ||
2510 | {0x55aa, 0x00}, | ||
2511 | {0x55ab, 0x00}, | ||
2512 | {0x55ac, 0x04}, | ||
2513 | {0x55ad, 0x04}, | ||
2514 | {0x55ae, 0x04}, | ||
2515 | {0x55af, 0x04}, | ||
2516 | {0x55b0, 0x0e}, | ||
2517 | {0x55b1, 0x0e}, | ||
2518 | {0x55b2, 0x0e}, | ||
2519 | {0x55b3, 0x0e}, | ||
2520 | {0x55b4, 0x1c}, | ||
2521 | {0x55b5, 0x1c}, | ||
2522 | {0x55b6, 0x1c}, | ||
2523 | {0x55b7, 0x1c}, | ||
2524 | {0x55b8, 0x08}, | ||
2525 | {0x55b9, 0x08}, | ||
2526 | {0x55ba, 0x08}, | ||
2527 | {0x55bb, 0x08}, | ||
2528 | {0x55bc, 0x00}, | ||
2529 | {0x55bd, 0x00}, | ||
2530 | {0x55be, 0x00}, | ||
2531 | {0x55bf, 0x00}, | ||
2532 | {0x55c0, 0x00}, | ||
2533 | {0x55c1, 0x00}, | ||
2534 | {0x55c2, 0x00}, | ||
2535 | {0x55c3, 0x00}, | ||
2536 | {0x55c4, 0x00}, | ||
2537 | {0x55c5, 0x00}, | ||
2538 | {0x55c6, 0x00}, | ||
2539 | {0x55c7, 0x00}, | ||
2540 | {0x55c8, 0x00}, | ||
2541 | {0x55c9, 0x00}, | ||
2542 | {0x55ca, 0x00}, | ||
2543 | {0x55cb, 0x00}, | ||
2544 | {0x55cc, 0x04}, | ||
2545 | {0x55cd, 0x04}, | ||
2546 | {0x55ce, 0x04}, | ||
2547 | {0x55cf, 0x04}, | ||
2548 | {0x55d0, 0x0e}, | ||
2549 | {0x55d1, 0x0e}, | ||
2550 | {0x55d2, 0x0e}, | ||
2551 | {0x55d3, 0x0e}, | ||
2552 | {0x55d4, 0x1c}, | ||
2553 | {0x55d5, 0x1c}, | ||
2554 | {0x55d6, 0x1c}, | ||
2555 | {0x55d7, 0x1c}, | ||
2556 | {0x55d8, 0x08}, | ||
2557 | {0x55d9, 0x08}, | ||
2558 | {0x55da, 0x08}, | ||
2559 | {0x55db, 0x08}, | ||
2560 | {0x55dc, 0x00}, | ||
2561 | {0x55dd, 0x00}, | ||
2562 | {0x55de, 0x00}, | ||
2563 | {0x55df, 0x00}, | ||
2564 | {0x55e0, 0x00}, | ||
2565 | {0x55e1, 0x00}, | ||
2566 | {0x55e2, 0x00}, | ||
2567 | {0x55e3, 0x00}, | ||
2568 | {0x55e4, 0x00}, | ||
2569 | {0x55e5, 0x00}, | ||
2570 | {0x55e6, 0x00}, | ||
2571 | {0x55e7, 0x00}, | ||
2572 | {0x55e8, 0x00}, | ||
2573 | {0x55e9, 0x00}, | ||
2574 | {0x55ea, 0x00}, | ||
2575 | {0x55eb, 0x00}, | ||
2576 | {0x55ec, 0x04}, | ||
2577 | {0x55ed, 0x04}, | ||
2578 | {0x55ee, 0x04}, | ||
2579 | {0x55ef, 0x04}, | ||
2580 | {0x55f0, 0x0e}, | ||
2581 | {0x55f1, 0x0e}, | ||
2582 | {0x55f2, 0x0e}, | ||
2583 | {0x55f3, 0x0e}, | ||
2584 | {0x55f4, 0x1c}, | ||
2585 | {0x55f5, 0x1c}, | ||
2586 | {0x55f6, 0x1c}, | ||
2587 | {0x55f7, 0x1c}, | ||
2588 | {0x55f8, 0x08}, | ||
2589 | {0x55f9, 0x08}, | ||
2590 | {0x55fa, 0x08}, | ||
2591 | {0x55fb, 0x08}, | ||
2592 | {0x55fc, 0x00}, | ||
2593 | {0x55fd, 0x00}, | ||
2594 | {0x55fe, 0x00}, | ||
2595 | {0x55ff, 0x00}, | ||
2596 | {0x567b, 0x00}, | ||
2597 | {0x5690, 0x00}, | ||
2598 | {0x5691, 0x00}, | ||
2599 | {0x5692, 0x00}, | ||
2600 | {0x5693, 0x0a}, | ||
2601 | {0x5694, 0xc0}, | ||
2602 | {0x5696, 0x06}, | ||
2603 | {0x5697, 0x0a}, | ||
2604 | {0x5698, 0x00}, | ||
2605 | {0x5699, 0x1c}, | ||
2606 | {0x569a, 0x16}, | ||
2607 | {0x569b, 0x04}, | ||
2608 | {0x569c, 0x00}, | ||
2609 | {0x569d, 0x1c}, | ||
2610 | {0x569e, 0x10}, | ||
2611 | {0x569f, 0x84}, | ||
2612 | {0x56a0, 0x36}, | ||
2613 | {0x56a1, 0x50}, | ||
2614 | {0x56a2, 0x16}, | ||
2615 | {0x56a3, 0x20}, | ||
2616 | {0x56a4, 0x10}, | ||
2617 | {0x56a5, 0xa0}, | ||
2618 | {0x5c80, 0x06}, | ||
2619 | {0x5c81, 0x80}, | ||
2620 | {0x5c82, 0x09}, | ||
2621 | {0x5c83, 0x5f}, | ||
2622 | {0x5d00, 0x01}, | ||
2623 | {0x5d01, 0x00}, | ||
2624 | {0x5d02, 0x01}, | ||
2625 | {0x5d03, 0x00}, | ||
2626 | {0x5d04, 0x02}, | ||
2627 | {0x5d05, 0x00}, | ||
2628 | {0x5d06, 0x02}, | ||
2629 | {0x5d07, 0x00}, | ||
2630 | {0x5d08, 0x70}, | ||
2631 | {0x5d09, 0x74}, | ||
2632 | {0x5d0a, 0x78}, | ||
2633 | {0x5d0b, 0x7c}, | ||
2634 | {0x5d0c, 0x80}, | ||
2635 | {0x5d0d, 0x80}, | ||
2636 | {0x5d0e, 0x7c}, | ||
2637 | {0x5d0f, 0x78}, | ||
2638 | {0x5d10, 0x74}, | ||
2639 | {0x5d11, 0x70}, | ||
2640 | {0x5d12, 0x98}, | ||
2641 | {0x5d13, 0x96}, | ||
2642 | {0x5d14, 0x63}, | ||
2643 | {0x5d15, 0x3a}, | ||
2644 | {0x5d16, 0x38}, | ||
2645 | {0x5d17, 0x39}, | ||
2646 | {0x5d18, 0x37}, | ||
2647 | {0x5d19, 0x53}, | ||
2648 | {0x5d1a, 0x8b}, | ||
2649 | {0x5d1b, 0x9d}, | ||
2650 | {0x5d24, 0x00}, | ||
2651 | {0x5d25, 0x00}, | ||
2652 | {0x5d26, 0x00}, | ||
2653 | {0x5d27, 0x0a}, | ||
2654 | {0x5d28, 0xc0}, | ||
2655 | {0x5d2a, 0x00}, | ||
2656 | {0x5d2b, 0x1c}, | ||
2657 | {0x5d2c, 0x16}, | ||
2658 | {0x5d2d, 0x04}, | ||
2659 | {0x5d2e, 0x00}, | ||
2660 | {0x5d2f, 0x1c}, | ||
2661 | {0x5d30, 0x10}, | ||
2662 | {0x5d31, 0x84}, | ||
2663 | {0x5d32, 0x10}, | ||
2664 | {0x5d34, 0x16}, | ||
2665 | {0x5d35, 0x20}, | ||
2666 | {0x5d36, 0x10}, | ||
2667 | {0x5d37, 0xa0}, | ||
2668 | {0x5d38, 0x5c}, | ||
2669 | {0x5d39, 0x7b}, | ||
2670 | {0x5d1c, 0x00}, | ||
2671 | {0x5d1d, 0x1c}, | ||
2672 | {0x5d1e, 0x00}, | ||
2673 | {0x5d1f, 0x1c}, | ||
2674 | {0x5d20, 0x15}, | ||
2675 | {0x5d21, 0xe0}, | ||
2676 | {0x5d22, 0x10}, | ||
2677 | {0x5d23, 0x40}, | ||
2678 | {0x5d29, 0x40}, | ||
2679 | {0x3008, 0x01}, | ||
2680 | {0x3663, 0x60}, | ||
2681 | {0x3002, 0x01}, | ||
2682 | {0x3c00, 0x3c}, | ||
2683 | {0x3025, 0x03}, | ||
2684 | {0x3668, 0xf0}, | ||
2685 | {0x3400, 0x04}, | ||
2686 | {OV23850_TABLE_END, 0x00} | ||
2687 | }; | ||
2688 | |||
2689 | static ov23850_reg mode_5632x3168_30fps[] = { | ||
2690 | {0x0316, 0x1e}, | ||
2691 | {0x0317, 0x00}, | ||
2692 | {0x0318, 0x03}, | ||
2693 | {0x031c, 0x01}, | ||
2694 | {0x031d, 0x02}, | ||
2695 | {0x031e, 0x09}, | ||
2696 | {0x2b05, 0x02}, | ||
2697 | {0x2b06, 0x87}, | ||
2698 | {0x2b07, 0x01}, | ||
2699 | {0x2b08, 0xa8}, | ||
2700 | {0x0320, 0x02}, | ||
2701 | {0x3002, 0x00}, | ||
2702 | {0x300f, 0x11}, | ||
2703 | {0x3010, 0x01}, | ||
2704 | {0x3012, 0x41}, | ||
2705 | {0x3016, 0xd2}, | ||
2706 | {0x3018, 0x70}, | ||
2707 | {0x3019, 0xc3}, | ||
2708 | {0x301b, 0x96}, | ||
2709 | {0x3022, 0x0f}, | ||
2710 | {0x3023, 0xb4}, | ||
2711 | {0x3031, 0x91}, | ||
2712 | {0x3034, 0x41}, | ||
2713 | {0x340c, 0xff}, | ||
2714 | {0x3501, 0x0D}, | ||
2715 | {0x3502, 0x28}, | ||
2716 | {0x3503, 0x00}, | ||
2717 | {0x3507, 0x00}, | ||
2718 | {0x3508, 0x00}, | ||
2719 | {0x3509, 0x12}, | ||
2720 | {0x350a, 0x00}, | ||
2721 | {0x350b, 0x80}, | ||
2722 | {0x350f, 0x10}, | ||
2723 | {0x3541, 0x02}, | ||
2724 | {0x3542, 0x00}, | ||
2725 | {0x3543, 0x00}, | ||
2726 | {0x3547, 0x00}, | ||
2727 | {0x3548, 0x00}, | ||
2728 | {0x3549, 0x12}, | ||
2729 | {0x354b, 0x10}, | ||
2730 | {0x354f, 0x10}, | ||
2731 | {0x3601, 0xa4}, | ||
2732 | {0x3603, 0x97}, | ||
2733 | {0x3604, 0x02}, | ||
2734 | {0x3605, 0xf2}, | ||
2735 | {0x3606, 0xe8}, | ||
2736 | {0x3607, 0x11}, | ||
2737 | {0x360a, 0x34}, | ||
2738 | {0x360c, 0x13}, | ||
2739 | {0x3618, 0xcc}, | ||
2740 | {0x3620, 0x50}, | ||
2741 | {0x3621, 0x99}, | ||
2742 | {0x3622, 0x7d}, | ||
2743 | {0x3624, 0x05}, | ||
2744 | {0x362a, 0x25}, | ||
2745 | {0x3650, 0x04}, | ||
2746 | {0x3660, 0xc0}, | ||
2747 | {0x3661, 0x00}, | ||
2748 | {0x3662, 0x00}, | ||
2749 | {0x3664, 0x88}, | ||
2750 | {0x3667, 0x00}, | ||
2751 | {0x366a, 0x5c}, | ||
2752 | {0x366c, 0x80}, | ||
2753 | {0x3700, 0x62}, | ||
2754 | {0x3701, 0x08}, | ||
2755 | {0x3702, 0x10}, | ||
2756 | {0x3703, 0x3e}, | ||
2757 | {0x3704, 0x26}, | ||
2758 | {0x3705, 0x01}, | ||
2759 | {0x3706, 0x3a}, | ||
2760 | {0x3707, 0xc4}, | ||
2761 | {0x3708, 0x3c}, | ||
2762 | {0x3709, 0x1c}, | ||
2763 | {0x370a, 0x23}, | ||
2764 | {0x370b, 0x2c}, | ||
2765 | {0x370c, 0x42}, | ||
2766 | {0x370d, 0xa4}, | ||
2767 | {0x370e, 0x14}, | ||
2768 | {0x370f, 0x0a}, | ||
2769 | {0x3710, 0x15}, | ||
2770 | {0x3711, 0x0a}, | ||
2771 | {0x3712, 0xa2}, | ||
2772 | {0x3713, 0x00}, | ||
2773 | {0x371e, 0x2a}, | ||
2774 | {0x371f, 0x13}, | ||
2775 | {0x3714, 0x00}, | ||
2776 | {0x3717, 0x00}, | ||
2777 | {0x3719, 0x00}, | ||
2778 | {0x371c, 0x04}, | ||
2779 | {0x3720, 0xaa}, | ||
2780 | {0x3721, 0x10}, | ||
2781 | {0x3722, 0x50}, | ||
2782 | {0x3725, 0xf0}, | ||
2783 | {0x3726, 0x22}, | ||
2784 | {0x3727, 0x44}, | ||
2785 | {0x3728, 0x40}, | ||
2786 | {0x3729, 0x00}, | ||
2787 | {0x372b, 0x00}, | ||
2788 | {0x372c, 0x92}, | ||
2789 | {0x372d, 0x0c}, | ||
2790 | {0x372e, 0x22}, | ||
2791 | {0x372f, 0x91}, | ||
2792 | {0x3732, 0x01}, | ||
2793 | {0x3733, 0xd0}, | ||
2794 | {0x3730, 0x01}, | ||
2795 | {0x3731, 0xc8}, | ||
2796 | {0x3744, 0x01}, | ||
2797 | {0x3745, 0x24}, | ||
2798 | {0x3746, 0x00}, | ||
2799 | {0x3747, 0xd0}, | ||
2800 | {0x3748, 0x27}, | ||
2801 | {0x374a, 0x4b}, | ||
2802 | {0x374b, 0x44}, | ||
2803 | {0x3760, 0xd1}, | ||
2804 | {0x3761, 0x52}, | ||
2805 | {0x3762, 0xa4}, | ||
2806 | {0x3763, 0x14}, | ||
2807 | {0x3766, 0x0c}, | ||
2808 | {0x3767, 0x25}, | ||
2809 | {0x3768, 0x0c}, | ||
2810 | {0x3769, 0x24}, | ||
2811 | {0x376a, 0x09}, | ||
2812 | {0x376b, 0x02}, | ||
2813 | {0x376d, 0x01}, | ||
2814 | {0x376e, 0x53}, | ||
2815 | {0x376f, 0x01}, | ||
2816 | {0x378c, 0x08}, | ||
2817 | {0x378d, 0x46}, | ||
2818 | {0x378e, 0x14}, | ||
2819 | {0x378f, 0x02}, | ||
2820 | {0x3790, 0xc4}, | ||
2821 | {0x3792, 0x64}, | ||
2822 | {0x3793, 0x5d}, | ||
2823 | {0x3794, 0x29}, | ||
2824 | {0x3795, 0x4f}, | ||
2825 | {0x3796, 0x43}, | ||
2826 | {0x3797, 0x09}, | ||
2827 | {0x3798, 0x02}, | ||
2828 | {0x3799, 0x33}, | ||
2829 | {0x379a, 0x09}, | ||
2830 | {0x379b, 0x1e}, | ||
2831 | {0x379f, 0x3e}, | ||
2832 | {0x37a0, 0x44}, | ||
2833 | {0x37a1, 0x00}, | ||
2834 | {0x37a2, 0x44}, | ||
2835 | {0x37a3, 0x41}, | ||
2836 | {0x37a4, 0x88}, | ||
2837 | {0x37a5, 0x69}, | ||
2838 | {0x37b0, 0x48}, | ||
2839 | {0x37b1, 0x20}, | ||
2840 | {0x37b2, 0x03}, | ||
2841 | {0x37b3, 0x48}, | ||
2842 | {0x37b4, 0x02}, | ||
2843 | {0x37b5, 0x33}, | ||
2844 | {0x37b6, 0x22}, | ||
2845 | {0x37b8, 0x02}, | ||
2846 | {0x37bc, 0x02}, | ||
2847 | {0x37c0, 0x3b}, | ||
2848 | {0x37c1, 0xc2}, | ||
2849 | {0x37c2, 0x06}, | ||
2850 | {0x37c3, 0x06}, | ||
2851 | {0x37c5, 0x33}, | ||
2852 | {0x37c6, 0x35}, | ||
2853 | {0x37c7, 0x00}, | ||
2854 | {0x3800, 0x00}, | ||
2855 | {0x3801, 0x14}, | ||
2856 | {0x3802, 0x00}, | ||
2857 | {0x3803, 0x0c}, | ||
2858 | {0x3804, 0x10}, | ||
2859 | {0x3805, 0x8b}, | ||
2860 | {0x3806, 0x0c}, | ||
2861 | {0x3807, 0x43}, | ||
2862 | {0x3808, 0x16}, | ||
2863 | {0x3809, 0x00}, | ||
2864 | {0x380a, 0x0C}, | ||
2865 | {0x380b, 0x60}, | ||
2866 | {0x380c, 0x1B}, | ||
2867 | {0x380d, 0xC4}, | ||
2868 | {0x380e, 0x0D}, | ||
2869 | {0x380f, 0x30}, | ||
2870 | {0x3810, 0x00}, | ||
2871 | {0x3811, 0x03}, | ||
2872 | {0x3813, 0x06}, | ||
2873 | {0x3814, 0x11}, | ||
2874 | {0x3815, 0x11}, | ||
2875 | {0x3820, 0x00}, | ||
2876 | {0x3821, 0x04}, | ||
2877 | {0x3834, 0x00}, | ||
2878 | {0x3835, 0x04}, | ||
2879 | {0x3836, 0x18}, | ||
2880 | {0x3837, 0x02}, | ||
2881 | {0x382f, 0x84}, | ||
2882 | {0x383c, 0xc8}, | ||
2883 | {0x383d, 0xff}, | ||
2884 | {0x3842, 0x00}, | ||
2885 | {0x384b, 0x00}, | ||
2886 | {0x3d85, 0x16}, | ||
2887 | {0x3d8c, 0x77}, | ||
2888 | {0x3d8d, 0x10}, | ||
2889 | {0x3f00, 0x52}, | ||
2890 | {0x4000, 0x17}, | ||
2891 | {0x4001, 0x60}, | ||
2892 | {0x4001, 0x60}, | ||
2893 | {0x4008, 0x00}, | ||
2894 | {0x4009, 0x13}, | ||
2895 | {0x400f, 0x00}, | ||
2896 | {0x4011, 0xfb}, | ||
2897 | {0x4017, 0x08}, | ||
2898 | {0x4018, 0x00}, | ||
2899 | {0x401a, 0xce}, | ||
2900 | {0x4019, 0x18}, | ||
2901 | {0x4020, 0x08}, | ||
2902 | {0x4022, 0x08}, | ||
2903 | {0x4024, 0x08}, | ||
2904 | {0x4026, 0x08}, | ||
2905 | {0x4028, 0x08}, | ||
2906 | {0x402a, 0x08}, | ||
2907 | {0x402c, 0x08}, | ||
2908 | {0x402e, 0x08}, | ||
2909 | {0x4030, 0x08}, | ||
2910 | {0x4032, 0x08}, | ||
2911 | {0x4034, 0x08}, | ||
2912 | {0x4036, 0x08}, | ||
2913 | {0x4038, 0x08}, | ||
2914 | {0x403a, 0x08}, | ||
2915 | {0x403c, 0x08}, | ||
2916 | {0x403e, 0x08}, | ||
2917 | {0x405c, 0x3f}, | ||
2918 | {0x4066, 0x04}, | ||
2919 | {0x4051, 0x03}, | ||
2920 | {0x4052, 0x00}, | ||
2921 | {0x4053, 0x80}, | ||
2922 | {0x4054, 0x00}, | ||
2923 | {0x4055, 0x80}, | ||
2924 | {0x4056, 0x00}, | ||
2925 | {0x4057, 0x80}, | ||
2926 | {0x4058, 0x00}, | ||
2927 | {0x4059, 0x80}, | ||
2928 | {0x4202, 0x00}, | ||
2929 | {0x4203, 0x01}, | ||
2930 | {0x430b, 0xff}, | ||
2931 | {0x430d, 0x00}, | ||
2932 | {0x4500, 0x72}, | ||
2933 | {0x4605, 0x00}, | ||
2934 | {0x4640, 0x01}, | ||
2935 | {0x4641, 0x04}, | ||
2936 | {0x4645, 0x00}, | ||
2937 | {0x4800, 0x04}, | ||
2938 | {0x4809, 0x2b}, | ||
2939 | {0x4813, 0x90}, | ||
2940 | {0x4817, 0x04}, | ||
2941 | {0x4833, 0x18}, | ||
2942 | {0x4837, 0x0A}, | ||
2943 | {0x484b, 0x01}, | ||
2944 | {0x4850, 0x5c}, | ||
2945 | {0x4852, 0x27}, | ||
2946 | {0x4856, 0x5c}, | ||
2947 | {0x4857, 0x55}, | ||
2948 | {0x486a, 0xaa}, | ||
2949 | {0x486e, 0x03}, | ||
2950 | {0x486f, 0x55}, | ||
2951 | {0x4875, 0xf0}, | ||
2952 | {0x4b04, 0x80}, | ||
2953 | {0x4b05, 0xb3}, | ||
2954 | {0x4b06, 0x00}, | ||
2955 | {0x4c01, 0xdf}, | ||
2956 | {0x4d00, 0x04}, | ||
2957 | {0x4d01, 0xf0}, | ||
2958 | {0x4d02, 0xb8}, | ||
2959 | {0x4d03, 0xf2}, | ||
2960 | {0x4d04, 0x88}, | ||
2961 | {0x4d05, 0x9d}, | ||
2962 | {0x4e00, 0x04}, | ||
2963 | {0x4e17, 0x04}, | ||
2964 | {0x4e33, 0x18}, | ||
2965 | {0x4e37, 0x11}, | ||
2966 | {0x4e4b, 0x01}, | ||
2967 | {0x4e50, 0x5c}, | ||
2968 | {0x4e52, 0x27}, | ||
2969 | {0x4e56, 0x5c}, | ||
2970 | {0x4e57, 0x55}, | ||
2971 | {0x4e6a, 0xaa}, | ||
2972 | {0x4e6e, 0x03}, | ||
2973 | {0x4e6f, 0x55}, | ||
2974 | {0x4e75, 0xf0}, | ||
2975 | {0x5000, 0x9b}, | ||
2976 | {0x5001, 0x42}, | ||
2977 | {0x5002, 0x10}, | ||
2978 | {0x5003, 0x01}, | ||
2979 | {0x5004, 0x00}, | ||
2980 | {0x5005, 0x00}, | ||
2981 | {0x501d, 0x00}, | ||
2982 | {0x501f, 0x06}, | ||
2983 | {0x5020, 0x03}, | ||
2984 | {0x5021, 0x00}, | ||
2985 | {0x5022, 0x13}, | ||
2986 | {0x5061, 0xff}, | ||
2987 | {0x5062, 0xff}, | ||
2988 | {0x5063, 0xff}, | ||
2989 | {0x5064, 0xff}, | ||
2990 | {0x506f, 0x00}, | ||
2991 | {0x5280, 0x00}, | ||
2992 | {0x5282, 0x00}, | ||
2993 | {0x5283, 0x01}, | ||
2994 | {0x5200, 0x00}, | ||
2995 | {0x5201, 0x71}, | ||
2996 | {0x5203, 0x04}, | ||
2997 | {0x5204, 0x00}, | ||
2998 | {0x5205, 0x88}, | ||
2999 | {0x5209, 0x00}, | ||
3000 | {0x520a, 0x80}, | ||
3001 | {0x520b, 0x04}, | ||
3002 | {0x520c, 0x01}, | ||
3003 | {0x5210, 0x10}, | ||
3004 | {0x5211, 0xa0}, | ||
3005 | {0x5292, 0x04}, | ||
3006 | {0x5500, 0x00}, | ||
3007 | {0x5501, 0x00}, | ||
3008 | {0x5502, 0x00}, | ||
3009 | {0x5503, 0x00}, | ||
3010 | {0x5504, 0x00}, | ||
3011 | {0x5505, 0x00}, | ||
3012 | {0x5506, 0x00}, | ||
3013 | {0x5507, 0x00}, | ||
3014 | {0x5508, 0x10}, | ||
3015 | {0x5509, 0x00}, | ||
3016 | {0x550a, 0x10}, | ||
3017 | {0x550b, 0x00}, | ||
3018 | {0x550c, 0x20}, | ||
3019 | {0x550d, 0x00}, | ||
3020 | {0x550e, 0x20}, | ||
3021 | {0x550f, 0x00}, | ||
3022 | {0x5510, 0x00}, | ||
3023 | {0x5511, 0x00}, | ||
3024 | {0x5512, 0x00}, | ||
3025 | {0x5513, 0x00}, | ||
3026 | {0x5514, 0x00}, | ||
3027 | {0x5515, 0x00}, | ||
3028 | {0x5516, 0x00}, | ||
3029 | {0x5517, 0x00}, | ||
3030 | {0x5518, 0x00}, | ||
3031 | {0x5519, 0x00}, | ||
3032 | {0x551a, 0x00}, | ||
3033 | {0x551b, 0x00}, | ||
3034 | {0x551c, 0x00}, | ||
3035 | {0x551d, 0x00}, | ||
3036 | {0x551e, 0x00}, | ||
3037 | {0x551f, 0x00}, | ||
3038 | {0x5520, 0x00}, | ||
3039 | {0x5521, 0x00}, | ||
3040 | {0x5522, 0x00}, | ||
3041 | {0x5523, 0x00}, | ||
3042 | {0x5524, 0x00}, | ||
3043 | {0x5525, 0x00}, | ||
3044 | {0x5526, 0x00}, | ||
3045 | {0x5527, 0x00}, | ||
3046 | {0x5528, 0x00}, | ||
3047 | {0x5529, 0x10}, | ||
3048 | {0x552a, 0x00}, | ||
3049 | {0x552b, 0x10}, | ||
3050 | {0x552c, 0x00}, | ||
3051 | {0x552d, 0x20}, | ||
3052 | {0x552e, 0x00}, | ||
3053 | {0x552f, 0x20}, | ||
3054 | {0x5530, 0x00}, | ||
3055 | {0x5531, 0x00}, | ||
3056 | {0x5532, 0x00}, | ||
3057 | {0x5533, 0x00}, | ||
3058 | {0x5534, 0x00}, | ||
3059 | {0x5535, 0x00}, | ||
3060 | {0x5536, 0x00}, | ||
3061 | {0x5537, 0x00}, | ||
3062 | {0x5538, 0x00}, | ||
3063 | {0x5539, 0x00}, | ||
3064 | {0x553a, 0x00}, | ||
3065 | {0x553b, 0x00}, | ||
3066 | {0x553c, 0x00}, | ||
3067 | {0x553d, 0x00}, | ||
3068 | {0x553e, 0x00}, | ||
3069 | {0x553f, 0x00}, | ||
3070 | {0x5540, 0x00}, | ||
3071 | {0x5541, 0x00}, | ||
3072 | {0x5542, 0x00}, | ||
3073 | {0x5543, 0x00}, | ||
3074 | {0x5544, 0x00}, | ||
3075 | {0x5545, 0x00}, | ||
3076 | {0x5546, 0x00}, | ||
3077 | {0x5547, 0x00}, | ||
3078 | {0x5548, 0x01}, | ||
3079 | {0x5549, 0x00}, | ||
3080 | {0x554a, 0x01}, | ||
3081 | {0x554b, 0x00}, | ||
3082 | {0x554c, 0x02}, | ||
3083 | {0x554d, 0x00}, | ||
3084 | {0x554e, 0x02}, | ||
3085 | {0x554f, 0x00}, | ||
3086 | {0x5550, 0x00}, | ||
3087 | {0x5551, 0x00}, | ||
3088 | {0x5552, 0x00}, | ||
3089 | {0x5553, 0x00}, | ||
3090 | {0x5554, 0x00}, | ||
3091 | {0x5555, 0x00}, | ||
3092 | {0x5556, 0x00}, | ||
3093 | {0x5557, 0x00}, | ||
3094 | {0x5558, 0x00}, | ||
3095 | {0x5559, 0x00}, | ||
3096 | {0x555a, 0x00}, | ||
3097 | {0x555b, 0x00}, | ||
3098 | {0x555c, 0x00}, | ||
3099 | {0x555d, 0x00}, | ||
3100 | {0x555e, 0x00}, | ||
3101 | {0x555f, 0x00}, | ||
3102 | {0x5560, 0x00}, | ||
3103 | {0x5561, 0x00}, | ||
3104 | {0x5562, 0x00}, | ||
3105 | {0x5563, 0x00}, | ||
3106 | {0x5564, 0x00}, | ||
3107 | {0x5565, 0x00}, | ||
3108 | {0x5566, 0x00}, | ||
3109 | {0x5567, 0x00}, | ||
3110 | {0x5568, 0x00}, | ||
3111 | {0x5569, 0x10}, | ||
3112 | {0x556a, 0x00}, | ||
3113 | {0x556b, 0x10}, | ||
3114 | {0x556c, 0x00}, | ||
3115 | {0x556d, 0x20}, | ||
3116 | {0x556e, 0x00}, | ||
3117 | {0x556f, 0x20}, | ||
3118 | {0x5570, 0x00}, | ||
3119 | {0x5571, 0x00}, | ||
3120 | {0x5572, 0x00}, | ||
3121 | {0x5573, 0x00}, | ||
3122 | {0x5574, 0x00}, | ||
3123 | {0x5575, 0x00}, | ||
3124 | {0x5576, 0x00}, | ||
3125 | {0x5577, 0x00}, | ||
3126 | {0x5578, 0x00}, | ||
3127 | {0x5579, 0x00}, | ||
3128 | {0x557a, 0x00}, | ||
3129 | {0x557b, 0x00}, | ||
3130 | {0x557c, 0x00}, | ||
3131 | {0x557d, 0x00}, | ||
3132 | {0x557e, 0x00}, | ||
3133 | {0x557f, 0x00}, | ||
3134 | {0x5580, 0x00}, | ||
3135 | {0x5581, 0x00}, | ||
3136 | {0x5582, 0x00}, | ||
3137 | {0x5583, 0x00}, | ||
3138 | {0x5584, 0x10}, | ||
3139 | {0x5585, 0x00}, | ||
3140 | {0x5586, 0x10}, | ||
3141 | {0x5587, 0x00}, | ||
3142 | {0x5588, 0x38}, | ||
3143 | {0x5589, 0x00}, | ||
3144 | {0x558a, 0x38}, | ||
3145 | {0x558b, 0x00}, | ||
3146 | {0x558c, 0x70}, | ||
3147 | {0x558d, 0x00}, | ||
3148 | {0x558e, 0x70}, | ||
3149 | {0x558f, 0x00}, | ||
3150 | {0x5590, 0x20}, | ||
3151 | {0x5591, 0x00}, | ||
3152 | {0x5592, 0x20}, | ||
3153 | {0x5593, 0x00}, | ||
3154 | {0x5594, 0x00}, | ||
3155 | {0x5595, 0x00}, | ||
3156 | {0x5596, 0x00}, | ||
3157 | {0x5597, 0x00}, | ||
3158 | {0x5598, 0x00}, | ||
3159 | {0x5599, 0x00}, | ||
3160 | {0x559a, 0x00}, | ||
3161 | {0x559b, 0x00}, | ||
3162 | {0x559c, 0x00}, | ||
3163 | {0x559d, 0x00}, | ||
3164 | {0x559e, 0x00}, | ||
3165 | {0x559f, 0x00}, | ||
3166 | {0x55a0, 0x00}, | ||
3167 | {0x55a1, 0x00}, | ||
3168 | {0x55a2, 0x00}, | ||
3169 | {0x55a3, 0x00}, | ||
3170 | {0x55a4, 0x00}, | ||
3171 | {0x55a5, 0x10}, | ||
3172 | {0x55a6, 0x00}, | ||
3173 | {0x55a7, 0x10}, | ||
3174 | {0x55a8, 0x00}, | ||
3175 | {0x55a9, 0x38}, | ||
3176 | {0x55aa, 0x00}, | ||
3177 | {0x55ab, 0x38}, | ||
3178 | {0x55ac, 0x00}, | ||
3179 | {0x55ad, 0x70}, | ||
3180 | {0x55ae, 0x00}, | ||
3181 | {0x55af, 0x70}, | ||
3182 | {0x55b0, 0x00}, | ||
3183 | {0x55b1, 0x20}, | ||
3184 | {0x55b2, 0x00}, | ||
3185 | {0x55b3, 0x20}, | ||
3186 | {0x55b4, 0x00}, | ||
3187 | {0x55b5, 0x00}, | ||
3188 | {0x55b6, 0x00}, | ||
3189 | {0x55b7, 0x00}, | ||
3190 | {0x55b8, 0x00}, | ||
3191 | {0x55b9, 0x00}, | ||
3192 | {0x55ba, 0x00}, | ||
3193 | {0x55bb, 0x00}, | ||
3194 | {0x55bc, 0x00}, | ||
3195 | {0x55bd, 0x00}, | ||
3196 | {0x55be, 0x00}, | ||
3197 | {0x55bf, 0x00}, | ||
3198 | {0x55c0, 0x00}, | ||
3199 | {0x55c1, 0x00}, | ||
3200 | {0x55c2, 0x00}, | ||
3201 | {0x55c3, 0x00}, | ||
3202 | {0x55c4, 0x01}, | ||
3203 | {0x55c5, 0x00}, | ||
3204 | {0x55c6, 0x01}, | ||
3205 | {0x55c7, 0x00}, | ||
3206 | {0x55c8, 0x03}, | ||
3207 | {0x55c9, 0x80}, | ||
3208 | {0x55ca, 0x03}, | ||
3209 | {0x55cb, 0x80}, | ||
3210 | {0x55cc, 0x07}, | ||
3211 | {0x55cd, 0x00}, | ||
3212 | {0x55ce, 0x07}, | ||
3213 | {0x55cf, 0x00}, | ||
3214 | {0x55d0, 0x02}, | ||
3215 | {0x55d1, 0x00}, | ||
3216 | {0x55d2, 0x02}, | ||
3217 | {0x55d3, 0x00}, | ||
3218 | {0x55d4, 0x00}, | ||
3219 | {0x55d5, 0x00}, | ||
3220 | {0x55d6, 0x00}, | ||
3221 | {0x55d7, 0x00}, | ||
3222 | {0x55d8, 0x00}, | ||
3223 | {0x55d9, 0x00}, | ||
3224 | {0x55da, 0x00}, | ||
3225 | {0x55db, 0x00}, | ||
3226 | {0x55dc, 0x00}, | ||
3227 | {0x55dd, 0x00}, | ||
3228 | {0x55de, 0x00}, | ||
3229 | {0x55df, 0x00}, | ||
3230 | {0x55e0, 0x00}, | ||
3231 | {0x55e1, 0x00}, | ||
3232 | {0x55e2, 0x00}, | ||
3233 | {0x55e3, 0x00}, | ||
3234 | {0x55e4, 0x00}, | ||
3235 | {0x55e5, 0x10}, | ||
3236 | {0x55e6, 0x00}, | ||
3237 | {0x55e7, 0x10}, | ||
3238 | {0x55e8, 0x00}, | ||
3239 | {0x55e9, 0x38}, | ||
3240 | {0x55ea, 0x00}, | ||
3241 | {0x55eb, 0x38}, | ||
3242 | {0x55ec, 0x00}, | ||
3243 | {0x55ed, 0x70}, | ||
3244 | {0x55ee, 0x00}, | ||
3245 | {0x55ef, 0x70}, | ||
3246 | {0x55f0, 0x00}, | ||
3247 | {0x55f1, 0x20}, | ||
3248 | {0x55f2, 0x00}, | ||
3249 | {0x55f3, 0x20}, | ||
3250 | {0x55f4, 0x00}, | ||
3251 | {0x55f5, 0x00}, | ||
3252 | {0x55f6, 0x00}, | ||
3253 | {0x55f7, 0x00}, | ||
3254 | {0x55f8, 0x00}, | ||
3255 | {0x55f9, 0x00}, | ||
3256 | {0x55fa, 0x00}, | ||
3257 | {0x55fb, 0x00}, | ||
3258 | {0x55fc, 0x00}, | ||
3259 | {0x55fd, 0x00}, | ||
3260 | {0x55fe, 0x00}, | ||
3261 | {0x55ff, 0x00}, | ||
3262 | {0x5600, 0x30}, | ||
3263 | {0x5601, 0x00}, | ||
3264 | {0x5602, 0x00}, | ||
3265 | {0x5603, 0x00}, | ||
3266 | {0x5604, 0x00}, | ||
3267 | {0x5605, 0x00}, | ||
3268 | {0x5606, 0x00}, | ||
3269 | {0x5607, 0x01}, | ||
3270 | {0x5608, 0x01}, | ||
3271 | {0x5609, 0x01}, | ||
3272 | {0x560f, 0xfc}, | ||
3273 | {0x5610, 0xf0}, | ||
3274 | {0x5611, 0x10}, | ||
3275 | {0x562f, 0xfc}, | ||
3276 | {0x5630, 0xf0}, | ||
3277 | {0x5631, 0x10}, | ||
3278 | {0x564f, 0xfc}, | ||
3279 | {0x5650, 0xf0}, | ||
3280 | {0x5651, 0x10}, | ||
3281 | {0x566f, 0xfc}, | ||
3282 | {0x5670, 0xf0}, | ||
3283 | {0x5671, 0x10}, | ||
3284 | {0x567b, 0x40}, | ||
3285 | {0x5690, 0x00}, | ||
3286 | {0x5691, 0x00}, | ||
3287 | {0x5692, 0x00}, | ||
3288 | {0x5693, 0x0a}, | ||
3289 | {0x5694, 0x80}, | ||
3290 | {0x5696, 0x06}, | ||
3291 | {0x5697, 0x0a}, | ||
3292 | {0x5698, 0x00}, | ||
3293 | {0x5699, 0x90}, | ||
3294 | {0x569a, 0x15}, | ||
3295 | {0x569b, 0x90}, | ||
3296 | {0x569c, 0x00}, | ||
3297 | {0x569d, 0x50}, | ||
3298 | {0x569e, 0x10}, | ||
3299 | {0x569f, 0x50}, | ||
3300 | {0x56a0, 0x36}, | ||
3301 | {0x56a1, 0x50}, | ||
3302 | {0x56a2, 0x16}, | ||
3303 | {0x56a3, 0x20}, | ||
3304 | {0x56a4, 0x10}, | ||
3305 | {0x56a5, 0xa0}, | ||
3306 | {0x5c80, 0x06}, | ||
3307 | {0x5c81, 0x80}, | ||
3308 | {0x5c82, 0x09}, | ||
3309 | {0x5c83, 0x5f}, | ||
3310 | {0x5d04, 0x01}, | ||
3311 | {0x5d05, 0x1a}, | ||
3312 | {0x5d06, 0x01}, | ||
3313 | {0x5d07, 0x1a}, | ||
3314 | {0x5d12, 0xf7}, | ||
3315 | {0x5d13, 0xdd}, | ||
3316 | {0x5d14, 0x97}, | ||
3317 | {0x5d15, 0x69}, | ||
3318 | {0x5d16, 0x61}, | ||
3319 | {0x5d17, 0x5b}, | ||
3320 | {0x5d18, 0x62}, | ||
3321 | {0x5d19, 0x8d}, | ||
3322 | {0x5d1a, 0xdd}, | ||
3323 | {0x5d1b, 0xff}, | ||
3324 | {0x5d24, 0x00}, | ||
3325 | {0x5d25, 0x00}, | ||
3326 | {0x5d26, 0x00}, | ||
3327 | {0x5d27, 0x0a}, | ||
3328 | {0x5d28, 0x80}, | ||
3329 | {0x5d2a, 0x00}, | ||
3330 | {0x5d2b, 0x90}, | ||
3331 | {0x5d2c, 0x15}, | ||
3332 | {0x5d2d, 0x90}, | ||
3333 | {0x5d2e, 0x00}, | ||
3334 | {0x5d2f, 0x50}, | ||
3335 | {0x5d30, 0x10}, | ||
3336 | {0x5d31, 0x50}, | ||
3337 | {0x5d32, 0x10}, | ||
3338 | {0x5d34, 0x36}, | ||
3339 | {0x5d35, 0x20}, | ||
3340 | {0x5d36, 0x90}, | ||
3341 | {0x5d37, 0xa0}, | ||
3342 | {0x5d38, 0x5c}, | ||
3343 | {0x5d39, 0x7b}, | ||
3344 | {0x5d1c, 0x00}, | ||
3345 | {0x5d1d, 0x90}, | ||
3346 | {0x5d1e, 0x00}, | ||
3347 | {0x5d1f, 0x50}, | ||
3348 | {0x5d20, 0x15}, | ||
3349 | {0x5d21, 0x00}, | ||
3350 | {0x5d22, 0x10}, | ||
3351 | {0x5d23, 0x00}, | ||
3352 | {0x5d29, 0xc0}, | ||
3353 | {0x3008, 0x01}, | ||
3354 | {0x3663, 0x60}, | ||
3355 | {0x3002, 0x01}, | ||
3356 | {0x3c00, 0x3c}, | ||
3357 | {0x3025, 0x03}, | ||
3358 | {0x3668, 0xf0}, | ||
3359 | {0x3400, 0x04}, | ||
3360 | {OV23850_TABLE_END, 0x00} | ||
3361 | }; | ||
3362 | |||
3363 | static ov23850_reg mode_5632x3168_30fps_dpcm[] = { | ||
3364 | {0x0316, 0x1e}, | ||
3365 | {0x0317, 0x00}, | ||
3366 | {0x0318, 0x03}, | ||
3367 | {0x031c, 0x01}, | ||
3368 | {0x031d, 0x02}, | ||
3369 | {0x031e, 0x08}, | ||
3370 | {0x2b05, 0x02}, | ||
3371 | {0x2b06, 0x87}, | ||
3372 | {0x2b07, 0x01}, | ||
3373 | {0x2b08, 0xa8}, | ||
3374 | {0x0320, 0x02}, | ||
3375 | {0x3002, 0x00}, | ||
3376 | {0x300f, 0x11}, | ||
3377 | {0x3010, 0x01}, | ||
3378 | {0x3012, 0x41}, | ||
3379 | {0x3016, 0xd2}, | ||
3380 | {0x3018, 0x70}, | ||
3381 | {0x3019, 0xe1}, | ||
3382 | {0x301b, 0x96}, | ||
3383 | {0x3022, 0x0f}, | ||
3384 | {0x3023, 0xb4}, | ||
3385 | {0x3031, 0x91}, | ||
3386 | {0x3034, 0x41}, | ||
3387 | {0x340c, 0xff}, | ||
3388 | {0x3501, 0x0D}, | ||
3389 | {0x3502, 0x28}, | ||
3390 | {0x3503, 0x00}, | ||
3391 | {0x3507, 0x00}, | ||
3392 | {0x3508, 0x00}, | ||
3393 | {0x3509, 0x12}, | ||
3394 | {0x350a, 0x00}, | ||
3395 | {0x350b, 0x80}, | ||
3396 | {0x350f, 0x10}, | ||
3397 | {0x3541, 0x02}, | ||
3398 | {0x3542, 0x00}, | ||
3399 | {0x3543, 0x00}, | ||
3400 | {0x3547, 0x00}, | ||
3401 | {0x3548, 0x00}, | ||
3402 | {0x3549, 0x12}, | ||
3403 | {0x354b, 0x10}, | ||
3404 | {0x354f, 0x10}, | ||
3405 | {0x3601, 0xa4}, | ||
3406 | {0x3603, 0x97}, | ||
3407 | {0x3604, 0x02}, | ||
3408 | {0x3605, 0xf2}, | ||
3409 | {0x3606, 0xe8}, | ||
3410 | {0x3607, 0x11}, | ||
3411 | {0x360a, 0x34}, | ||
3412 | {0x360c, 0x13}, | ||
3413 | {0x3618, 0xcc}, | ||
3414 | {0x3620, 0x50}, | ||
3415 | {0x3621, 0x99}, | ||
3416 | {0x3622, 0x7d}, | ||
3417 | {0x3624, 0x05}, | ||
3418 | {0x362a, 0x25}, | ||
3419 | {0x3650, 0x04}, | ||
3420 | {0x3660, 0xc4}, | ||
3421 | {0x3661, 0x00}, | ||
3422 | {0x3662, 0x00}, | ||
3423 | {0x3664, 0x88}, | ||
3424 | {0x3667, 0x00}, | ||
3425 | {0x366a, 0x5c}, | ||
3426 | {0x366c, 0x80}, | ||
3427 | {0x3700, 0x62}, | ||
3428 | {0x3701, 0x08}, | ||
3429 | {0x3702, 0x10}, | ||
3430 | {0x3703, 0x3e}, | ||
3431 | {0x3704, 0x26}, | ||
3432 | {0x3705, 0x01}, | ||
3433 | {0x3706, 0x3a}, | ||
3434 | {0x3707, 0xc4}, | ||
3435 | {0x3708, 0x3c}, | ||
3436 | {0x3709, 0x1c}, | ||
3437 | {0x370a, 0x23}, | ||
3438 | {0x370b, 0x2c}, | ||
3439 | {0x370c, 0x42}, | ||
3440 | {0x370d, 0xa4}, | ||
3441 | {0x370e, 0x14}, | ||
3442 | {0x370f, 0x0a}, | ||
3443 | {0x3710, 0x15}, | ||
3444 | {0x3711, 0x0a}, | ||
3445 | {0x3712, 0xa2}, | ||
3446 | {0x3713, 0x00}, | ||
3447 | {0x371e, 0x2a}, | ||
3448 | {0x371f, 0x13}, | ||
3449 | {0x3714, 0x00}, | ||
3450 | {0x3717, 0x00}, | ||
3451 | {0x3719, 0x00}, | ||
3452 | {0x371c, 0x04}, | ||
3453 | {0x3720, 0xaa}, | ||
3454 | {0x3721, 0x10}, | ||
3455 | {0x3722, 0x50}, | ||
3456 | {0x3725, 0xf0}, | ||
3457 | {0x3726, 0x22}, | ||
3458 | {0x3727, 0x44}, | ||
3459 | {0x3728, 0x40}, | ||
3460 | {0x3729, 0x00}, | ||
3461 | {0x372b, 0x00}, | ||
3462 | {0x372c, 0x92}, | ||
3463 | {0x372d, 0x0c}, | ||
3464 | {0x372e, 0x22}, | ||
3465 | {0x372f, 0x91}, | ||
3466 | {0x3732, 0x01}, | ||
3467 | {0x3733, 0xd0}, | ||
3468 | {0x3730, 0x01}, | ||
3469 | {0x3731, 0xc8}, | ||
3470 | {0x3744, 0x01}, | ||
3471 | {0x3745, 0x24}, | ||
3472 | {0x3746, 0x00}, | ||
3473 | {0x3747, 0xd0}, | ||
3474 | {0x3748, 0x27}, | ||
3475 | {0x374a, 0x4b}, | ||
3476 | {0x374b, 0x44}, | ||
3477 | {0x3760, 0xd1}, | ||
3478 | {0x3761, 0x52}, | ||
3479 | {0x3762, 0xa4}, | ||
3480 | {0x3763, 0x14}, | ||
3481 | {0x3766, 0x0c}, | ||
3482 | {0x3767, 0x25}, | ||
3483 | {0x3768, 0x0c}, | ||
3484 | {0x3769, 0x24}, | ||
3485 | {0x376a, 0x09}, | ||
3486 | {0x376b, 0x02}, | ||
3487 | {0x376d, 0x01}, | ||
3488 | {0x376e, 0x53}, | ||
3489 | {0x376f, 0x01}, | ||
3490 | {0x378c, 0x08}, | ||
3491 | {0x378d, 0x46}, | ||
3492 | {0x378e, 0x14}, | ||
3493 | {0x378f, 0x02}, | ||
3494 | {0x3790, 0xc4}, | ||
3495 | {0x3792, 0x64}, | ||
3496 | {0x3793, 0x5d}, | ||
3497 | {0x3794, 0x29}, | ||
3498 | {0x3795, 0x4f}, | ||
3499 | {0x3796, 0x43}, | ||
3500 | {0x3797, 0x09}, | ||
3501 | {0x3798, 0x02}, | ||
3502 | {0x3799, 0x33}, | ||
3503 | {0x379a, 0x09}, | ||
3504 | {0x379b, 0x1e}, | ||
3505 | {0x379f, 0x3e}, | ||
3506 | {0x37a0, 0x44}, | ||
3507 | {0x37a1, 0x00}, | ||
3508 | {0x37a2, 0x44}, | ||
3509 | {0x37a3, 0x41}, | ||
3510 | {0x37a4, 0x88}, | ||
3511 | {0x37a5, 0x69}, | ||
3512 | {0x37b0, 0x48}, | ||
3513 | {0x37b1, 0x20}, | ||
3514 | {0x37b2, 0x03}, | ||
3515 | {0x37b3, 0x48}, | ||
3516 | {0x37b4, 0x02}, | ||
3517 | {0x37b5, 0x33}, | ||
3518 | {0x37b6, 0x22}, | ||
3519 | {0x37b8, 0x02}, | ||
3520 | {0x37bc, 0x02}, | ||
3521 | {0x37c0, 0x3b}, | ||
3522 | {0x37c1, 0xc2}, | ||
3523 | {0x37c2, 0x06}, | ||
3524 | {0x37c3, 0x06}, | ||
3525 | {0x37c5, 0x33}, | ||
3526 | {0x37c6, 0x35}, | ||
3527 | {0x37c7, 0x00}, | ||
3528 | {0x3800, 0x00}, | ||
3529 | {0x3801, 0x14}, | ||
3530 | {0x3802, 0x00}, | ||
3531 | {0x3803, 0x0c}, | ||
3532 | {0x3804, 0x10}, | ||
3533 | {0x3805, 0x8b}, | ||
3534 | {0x3806, 0x0c}, | ||
3535 | {0x3807, 0x43}, | ||
3536 | {0x3808, 0x16}, | ||
3537 | {0x3809, 0x00}, | ||
3538 | {0x380a, 0x0C}, | ||
3539 | {0x380b, 0x60}, | ||
3540 | {0x380c, 0x1B}, | ||
3541 | {0x380d, 0xC4}, | ||
3542 | {0x380e, 0x0D}, | ||
3543 | {0x380f, 0x30}, | ||
3544 | {0x3810, 0x00}, | ||
3545 | {0x3811, 0x03}, | ||
3546 | {0x3813, 0x06}, | ||
3547 | {0x3814, 0x11}, | ||
3548 | {0x3815, 0x11}, | ||
3549 | {0x3820, 0x00}, | ||
3550 | {0x3821, 0x04}, | ||
3551 | {0x3834, 0x00}, | ||
3552 | {0x3835, 0x04}, | ||
3553 | {0x3836, 0x18}, | ||
3554 | {0x3837, 0x02}, | ||
3555 | {0x382f, 0x84}, | ||
3556 | {0x383c, 0xc8}, | ||
3557 | {0x383d, 0xff}, | ||
3558 | {0x3842, 0x00}, | ||
3559 | {0x384b, 0x00}, | ||
3560 | {0x3d85, 0x16}, | ||
3561 | {0x3d8c, 0x77}, | ||
3562 | {0x3d8d, 0x10}, | ||
3563 | {0x3f00, 0x52}, | ||
3564 | {0x4000, 0x17}, | ||
3565 | {0x4001, 0x60}, | ||
3566 | {0x4001, 0x60}, | ||
3567 | {0x4008, 0x00}, | ||
3568 | {0x4009, 0x13}, | ||
3569 | {0x400f, 0x00}, | ||
3570 | {0x4011, 0xfb}, | ||
3571 | {0x4017, 0x08}, | ||
3572 | {0x4018, 0x00}, | ||
3573 | {0x401a, 0xce}, | ||
3574 | {0x4019, 0x18}, | ||
3575 | {0x4020, 0x08}, | ||
3576 | {0x4022, 0x08}, | ||
3577 | {0x4024, 0x08}, | ||
3578 | {0x4026, 0x08}, | ||
3579 | {0x4028, 0x08}, | ||
3580 | {0x402a, 0x08}, | ||
3581 | {0x402c, 0x08}, | ||
3582 | {0x402e, 0x08}, | ||
3583 | {0x4030, 0x08}, | ||
3584 | {0x4032, 0x08}, | ||
3585 | {0x4034, 0x08}, | ||
3586 | {0x4036, 0x08}, | ||
3587 | {0x4038, 0x08}, | ||
3588 | {0x403a, 0x08}, | ||
3589 | {0x403c, 0x08}, | ||
3590 | {0x403e, 0x08}, | ||
3591 | {0x405c, 0x3f}, | ||
3592 | {0x4066, 0x04}, | ||
3593 | {0x4051, 0x03}, | ||
3594 | {0x4052, 0x00}, | ||
3595 | {0x4053, 0x80}, | ||
3596 | {0x4054, 0x00}, | ||
3597 | {0x4055, 0x80}, | ||
3598 | {0x4056, 0x00}, | ||
3599 | {0x4057, 0x80}, | ||
3600 | {0x4058, 0x00}, | ||
3601 | {0x4059, 0x80}, | ||
3602 | {0x4202, 0x00}, | ||
3603 | {0x4203, 0x01}, | ||
3604 | {0x430b, 0xff}, | ||
3605 | {0x430d, 0x00}, | ||
3606 | {0x4500, 0x72}, | ||
3607 | {0x4605, 0x00}, | ||
3608 | {0x4640, 0x01}, | ||
3609 | {0x4641, 0x04}, | ||
3610 | {0x4645, 0x00}, | ||
3611 | {0x4800, 0x04}, | ||
3612 | {0x4809, 0x2b}, | ||
3613 | {0x4813, 0x90}, | ||
3614 | {0x4817, 0x04}, | ||
3615 | {0x4833, 0x18}, | ||
3616 | {0x4837, 0x0A}, | ||
3617 | {0x484b, 0x01}, | ||
3618 | {0x4850, 0x5c}, | ||
3619 | {0x4852, 0x27}, | ||
3620 | {0x4856, 0x5c}, | ||
3621 | {0x4857, 0x55}, | ||
3622 | {0x486a, 0xaa}, | ||
3623 | {0x486e, 0x03}, | ||
3624 | {0x486f, 0x55}, | ||
3625 | {0x4875, 0xf0}, | ||
3626 | {0x4b04, 0x80}, | ||
3627 | {0x4b05, 0xb3}, | ||
3628 | {0x4b06, 0x00}, | ||
3629 | {0x4c01, 0xdf}, | ||
3630 | {0x4d00, 0x04}, | ||
3631 | {0x4d01, 0xf0}, | ||
3632 | {0x4d02, 0xb8}, | ||
3633 | {0x4d03, 0xf2}, | ||
3634 | {0x4d04, 0x88}, | ||
3635 | {0x4d05, 0x9d}, | ||
3636 | {0x4e00, 0x04}, | ||
3637 | {0x4e17, 0x04}, | ||
3638 | {0x4e33, 0x18}, | ||
3639 | {0x4e37, 0x11}, | ||
3640 | {0x4e4b, 0x01}, | ||
3641 | {0x4e50, 0x5c}, | ||
3642 | {0x4e52, 0x27}, | ||
3643 | {0x4e56, 0x5c}, | ||
3644 | {0x4e57, 0x55}, | ||
3645 | {0x4e6a, 0xaa}, | ||
3646 | {0x4e6e, 0x03}, | ||
3647 | {0x4e6f, 0x55}, | ||
3648 | {0x4e75, 0xf0}, | ||
3649 | {0x5000, 0x9b}, | ||
3650 | {0x5001, 0x42}, | ||
3651 | {0x5002, 0x10}, | ||
3652 | {0x5003, 0x01}, | ||
3653 | {0x5004, 0x00}, | ||
3654 | {0x5005, 0x00}, | ||
3655 | {0x501d, 0x00}, | ||
3656 | {0x501f, 0x06}, | ||
3657 | {0x5020, 0x03}, | ||
3658 | {0x5021, 0x00}, | ||
3659 | {0x5022, 0x13}, | ||
3660 | {0x5061, 0xff}, | ||
3661 | {0x5062, 0xff}, | ||
3662 | {0x5063, 0xff}, | ||
3663 | {0x5064, 0xff}, | ||
3664 | {0x506f, 0x00}, | ||
3665 | {0x5280, 0x00}, | ||
3666 | {0x5282, 0x00}, | ||
3667 | {0x5283, 0x01}, | ||
3668 | {0x5200, 0x00}, | ||
3669 | {0x5201, 0x71}, | ||
3670 | {0x5203, 0x04}, | ||
3671 | {0x5204, 0x00}, | ||
3672 | {0x5205, 0x88}, | ||
3673 | {0x5209, 0x00}, | ||
3674 | {0x520a, 0x80}, | ||
3675 | {0x520b, 0x04}, | ||
3676 | {0x520c, 0x01}, | ||
3677 | {0x5210, 0x10}, | ||
3678 | {0x5211, 0xa0}, | ||
3679 | {0x5292, 0x04}, | ||
3680 | {0x5500, 0x00}, | ||
3681 | {0x5501, 0x00}, | ||
3682 | {0x5502, 0x00}, | ||
3683 | {0x5503, 0x00}, | ||
3684 | {0x5504, 0x00}, | ||
3685 | {0x5505, 0x00}, | ||
3686 | {0x5506, 0x00}, | ||
3687 | {0x5507, 0x00}, | ||
3688 | {0x5508, 0x10}, | ||
3689 | {0x5509, 0x00}, | ||
3690 | {0x550a, 0x10}, | ||
3691 | {0x550b, 0x00}, | ||
3692 | {0x550c, 0x20}, | ||
3693 | {0x550d, 0x00}, | ||
3694 | {0x550e, 0x20}, | ||
3695 | {0x550f, 0x00}, | ||
3696 | {0x5510, 0x00}, | ||
3697 | {0x5511, 0x00}, | ||
3698 | {0x5512, 0x00}, | ||
3699 | {0x5513, 0x00}, | ||
3700 | {0x5514, 0x00}, | ||
3701 | {0x5515, 0x00}, | ||
3702 | {0x5516, 0x00}, | ||
3703 | {0x5517, 0x00}, | ||
3704 | {0x5518, 0x00}, | ||
3705 | {0x5519, 0x00}, | ||
3706 | {0x551a, 0x00}, | ||
3707 | {0x551b, 0x00}, | ||
3708 | {0x551c, 0x00}, | ||
3709 | {0x551d, 0x00}, | ||
3710 | {0x551e, 0x00}, | ||
3711 | {0x551f, 0x00}, | ||
3712 | {0x5520, 0x00}, | ||
3713 | {0x5521, 0x00}, | ||
3714 | {0x5522, 0x00}, | ||
3715 | {0x5523, 0x00}, | ||
3716 | {0x5524, 0x00}, | ||
3717 | {0x5525, 0x00}, | ||
3718 | {0x5526, 0x00}, | ||
3719 | {0x5527, 0x00}, | ||
3720 | {0x5528, 0x00}, | ||
3721 | {0x5529, 0x10}, | ||
3722 | {0x552a, 0x00}, | ||
3723 | {0x552b, 0x10}, | ||
3724 | {0x552c, 0x00}, | ||
3725 | {0x552d, 0x20}, | ||
3726 | {0x552e, 0x00}, | ||
3727 | {0x552f, 0x20}, | ||
3728 | {0x5530, 0x00}, | ||
3729 | {0x5531, 0x00}, | ||
3730 | {0x5532, 0x00}, | ||
3731 | {0x5533, 0x00}, | ||
3732 | {0x5534, 0x00}, | ||
3733 | {0x5535, 0x00}, | ||
3734 | {0x5536, 0x00}, | ||
3735 | {0x5537, 0x00}, | ||
3736 | {0x5538, 0x00}, | ||
3737 | {0x5539, 0x00}, | ||
3738 | {0x553a, 0x00}, | ||
3739 | {0x553b, 0x00}, | ||
3740 | {0x553c, 0x00}, | ||
3741 | {0x553d, 0x00}, | ||
3742 | {0x553e, 0x00}, | ||
3743 | {0x553f, 0x00}, | ||
3744 | {0x5540, 0x00}, | ||
3745 | {0x5541, 0x00}, | ||
3746 | {0x5542, 0x00}, | ||
3747 | {0x5543, 0x00}, | ||
3748 | {0x5544, 0x00}, | ||
3749 | {0x5545, 0x00}, | ||
3750 | {0x5546, 0x00}, | ||
3751 | {0x5547, 0x00}, | ||
3752 | {0x5548, 0x01}, | ||
3753 | {0x5549, 0x00}, | ||
3754 | {0x554a, 0x01}, | ||
3755 | {0x554b, 0x00}, | ||
3756 | {0x554c, 0x02}, | ||
3757 | {0x554d, 0x00}, | ||
3758 | {0x554e, 0x02}, | ||
3759 | {0x554f, 0x00}, | ||
3760 | {0x5550, 0x00}, | ||
3761 | {0x5551, 0x00}, | ||
3762 | {0x5552, 0x00}, | ||
3763 | {0x5553, 0x00}, | ||
3764 | {0x5554, 0x00}, | ||
3765 | {0x5555, 0x00}, | ||
3766 | {0x5556, 0x00}, | ||
3767 | {0x5557, 0x00}, | ||
3768 | {0x5558, 0x00}, | ||
3769 | {0x5559, 0x00}, | ||
3770 | {0x555a, 0x00}, | ||
3771 | {0x555b, 0x00}, | ||
3772 | {0x555c, 0x00}, | ||
3773 | {0x555d, 0x00}, | ||
3774 | {0x555e, 0x00}, | ||
3775 | {0x555f, 0x00}, | ||
3776 | {0x5560, 0x00}, | ||
3777 | {0x5561, 0x00}, | ||
3778 | {0x5562, 0x00}, | ||
3779 | {0x5563, 0x00}, | ||
3780 | {0x5564, 0x00}, | ||
3781 | {0x5565, 0x00}, | ||
3782 | {0x5566, 0x00}, | ||
3783 | {0x5567, 0x00}, | ||
3784 | {0x5568, 0x00}, | ||
3785 | {0x5569, 0x10}, | ||
3786 | {0x556a, 0x00}, | ||
3787 | {0x556b, 0x10}, | ||
3788 | {0x556c, 0x00}, | ||
3789 | {0x556d, 0x20}, | ||
3790 | {0x556e, 0x00}, | ||
3791 | {0x556f, 0x20}, | ||
3792 | {0x5570, 0x00}, | ||
3793 | {0x5571, 0x00}, | ||
3794 | {0x5572, 0x00}, | ||
3795 | {0x5573, 0x00}, | ||
3796 | {0x5574, 0x00}, | ||
3797 | {0x5575, 0x00}, | ||
3798 | {0x5576, 0x00}, | ||
3799 | {0x5577, 0x00}, | ||
3800 | {0x5578, 0x00}, | ||
3801 | {0x5579, 0x00}, | ||
3802 | {0x557a, 0x00}, | ||
3803 | {0x557b, 0x00}, | ||
3804 | {0x557c, 0x00}, | ||
3805 | {0x557d, 0x00}, | ||
3806 | {0x557e, 0x00}, | ||
3807 | {0x557f, 0x00}, | ||
3808 | {0x5580, 0x00}, | ||
3809 | {0x5581, 0x00}, | ||
3810 | {0x5582, 0x00}, | ||
3811 | {0x5583, 0x00}, | ||
3812 | {0x5584, 0x10}, | ||
3813 | {0x5585, 0x00}, | ||
3814 | {0x5586, 0x10}, | ||
3815 | {0x5587, 0x00}, | ||
3816 | {0x5588, 0x38}, | ||
3817 | {0x5589, 0x00}, | ||
3818 | {0x558a, 0x38}, | ||
3819 | {0x558b, 0x00}, | ||
3820 | {0x558c, 0x70}, | ||
3821 | {0x558d, 0x00}, | ||
3822 | {0x558e, 0x70}, | ||
3823 | {0x558f, 0x00}, | ||
3824 | {0x5590, 0x20}, | ||
3825 | {0x5591, 0x00}, | ||
3826 | {0x5592, 0x20}, | ||
3827 | {0x5593, 0x00}, | ||
3828 | {0x5594, 0x00}, | ||
3829 | {0x5595, 0x00}, | ||
3830 | {0x5596, 0x00}, | ||
3831 | {0x5597, 0x00}, | ||
3832 | {0x5598, 0x00}, | ||
3833 | {0x5599, 0x00}, | ||
3834 | {0x559a, 0x00}, | ||
3835 | {0x559b, 0x00}, | ||
3836 | {0x559c, 0x00}, | ||
3837 | {0x559d, 0x00}, | ||
3838 | {0x559e, 0x00}, | ||
3839 | {0x559f, 0x00}, | ||
3840 | {0x55a0, 0x00}, | ||
3841 | {0x55a1, 0x00}, | ||
3842 | {0x55a2, 0x00}, | ||
3843 | {0x55a3, 0x00}, | ||
3844 | {0x55a4, 0x00}, | ||
3845 | {0x55a5, 0x10}, | ||
3846 | {0x55a6, 0x00}, | ||
3847 | {0x55a7, 0x10}, | ||
3848 | {0x55a8, 0x00}, | ||
3849 | {0x55a9, 0x38}, | ||
3850 | {0x55aa, 0x00}, | ||
3851 | {0x55ab, 0x38}, | ||
3852 | {0x55ac, 0x00}, | ||
3853 | {0x55ad, 0x70}, | ||
3854 | {0x55ae, 0x00}, | ||
3855 | {0x55af, 0x70}, | ||
3856 | {0x55b0, 0x00}, | ||
3857 | {0x55b1, 0x20}, | ||
3858 | {0x55b2, 0x00}, | ||
3859 | {0x55b3, 0x20}, | ||
3860 | {0x55b4, 0x00}, | ||
3861 | {0x55b5, 0x00}, | ||
3862 | {0x55b6, 0x00}, | ||
3863 | {0x55b7, 0x00}, | ||
3864 | {0x55b8, 0x00}, | ||
3865 | {0x55b9, 0x00}, | ||
3866 | {0x55ba, 0x00}, | ||
3867 | {0x55bb, 0x00}, | ||
3868 | {0x55bc, 0x00}, | ||
3869 | {0x55bd, 0x00}, | ||
3870 | {0x55be, 0x00}, | ||
3871 | {0x55bf, 0x00}, | ||
3872 | {0x55c0, 0x00}, | ||
3873 | {0x55c1, 0x00}, | ||
3874 | {0x55c2, 0x00}, | ||
3875 | {0x55c3, 0x00}, | ||
3876 | {0x55c4, 0x01}, | ||
3877 | {0x55c5, 0x00}, | ||
3878 | {0x55c6, 0x01}, | ||
3879 | {0x55c7, 0x00}, | ||
3880 | {0x55c8, 0x03}, | ||
3881 | {0x55c9, 0x80}, | ||
3882 | {0x55ca, 0x03}, | ||
3883 | {0x55cb, 0x80}, | ||
3884 | {0x55cc, 0x07}, | ||
3885 | {0x55cd, 0x00}, | ||
3886 | {0x55ce, 0x07}, | ||
3887 | {0x55cf, 0x00}, | ||
3888 | {0x55d0, 0x02}, | ||
3889 | {0x55d1, 0x00}, | ||
3890 | {0x55d2, 0x02}, | ||
3891 | {0x55d3, 0x00}, | ||
3892 | {0x55d4, 0x00}, | ||
3893 | {0x55d5, 0x00}, | ||
3894 | {0x55d6, 0x00}, | ||
3895 | {0x55d7, 0x00}, | ||
3896 | {0x55d8, 0x00}, | ||
3897 | {0x55d9, 0x00}, | ||
3898 | {0x55da, 0x00}, | ||
3899 | {0x55db, 0x00}, | ||
3900 | {0x55dc, 0x00}, | ||
3901 | {0x55dd, 0x00}, | ||
3902 | {0x55de, 0x00}, | ||
3903 | {0x55df, 0x00}, | ||
3904 | {0x55e0, 0x00}, | ||
3905 | {0x55e1, 0x00}, | ||
3906 | {0x55e2, 0x00}, | ||
3907 | {0x55e3, 0x00}, | ||
3908 | {0x55e4, 0x00}, | ||
3909 | {0x55e5, 0x10}, | ||
3910 | {0x55e6, 0x00}, | ||
3911 | {0x55e7, 0x10}, | ||
3912 | {0x55e8, 0x00}, | ||
3913 | {0x55e9, 0x38}, | ||
3914 | {0x55ea, 0x00}, | ||
3915 | {0x55eb, 0x38}, | ||
3916 | {0x55ec, 0x00}, | ||
3917 | {0x55ed, 0x70}, | ||
3918 | {0x55ee, 0x00}, | ||
3919 | {0x55ef, 0x70}, | ||
3920 | {0x55f0, 0x00}, | ||
3921 | {0x55f1, 0x20}, | ||
3922 | {0x55f2, 0x00}, | ||
3923 | {0x55f3, 0x20}, | ||
3924 | {0x55f4, 0x00}, | ||
3925 | {0x55f5, 0x00}, | ||
3926 | {0x55f6, 0x00}, | ||
3927 | {0x55f7, 0x00}, | ||
3928 | {0x55f8, 0x00}, | ||
3929 | {0x55f9, 0x00}, | ||
3930 | {0x55fa, 0x00}, | ||
3931 | {0x55fb, 0x00}, | ||
3932 | {0x55fc, 0x00}, | ||
3933 | {0x55fd, 0x00}, | ||
3934 | {0x55fe, 0x00}, | ||
3935 | {0x55ff, 0x00}, | ||
3936 | {0x5600, 0x30}, | ||
3937 | {0x5601, 0x00}, | ||
3938 | {0x5602, 0x00}, | ||
3939 | {0x5603, 0x00}, | ||
3940 | {0x5604, 0x00}, | ||
3941 | {0x5605, 0x00}, | ||
3942 | {0x5606, 0x00}, | ||
3943 | {0x5607, 0x01}, | ||
3944 | {0x5608, 0x01}, | ||
3945 | {0x5609, 0x01}, | ||
3946 | {0x560f, 0xfc}, | ||
3947 | {0x5610, 0xf0}, | ||
3948 | {0x5611, 0x10}, | ||
3949 | {0x562f, 0xfc}, | ||
3950 | {0x5630, 0xf0}, | ||
3951 | {0x5631, 0x10}, | ||
3952 | {0x564f, 0xfc}, | ||
3953 | {0x5650, 0xf0}, | ||
3954 | {0x5651, 0x10}, | ||
3955 | {0x566f, 0xfc}, | ||
3956 | {0x5670, 0xf0}, | ||
3957 | {0x5671, 0x10}, | ||
3958 | {0x567b, 0x40}, | ||
3959 | {0x5690, 0x00}, | ||
3960 | {0x5691, 0x00}, | ||
3961 | {0x5692, 0x00}, | ||
3962 | {0x5693, 0x0a}, | ||
3963 | {0x5694, 0x80}, | ||
3964 | {0x5696, 0x06}, | ||
3965 | {0x5697, 0x0a}, | ||
3966 | {0x5698, 0x00}, | ||
3967 | {0x5699, 0x90}, | ||
3968 | {0x569a, 0x15}, | ||
3969 | {0x569b, 0x90}, | ||
3970 | {0x569c, 0x00}, | ||
3971 | {0x569d, 0x50}, | ||
3972 | {0x569e, 0x10}, | ||
3973 | {0x569f, 0x50}, | ||
3974 | {0x56a0, 0x36}, | ||
3975 | {0x56a1, 0x50}, | ||
3976 | {0x56a2, 0x16}, | ||
3977 | {0x56a3, 0x20}, | ||
3978 | {0x56a4, 0x10}, | ||
3979 | {0x56a5, 0xa0}, | ||
3980 | {0x5c80, 0x06}, | ||
3981 | {0x5c81, 0x80}, | ||
3982 | {0x5c82, 0x09}, | ||
3983 | {0x5c83, 0x5f}, | ||
3984 | {0x5d04, 0x01}, | ||
3985 | {0x5d05, 0x1a}, | ||
3986 | {0x5d06, 0x01}, | ||
3987 | {0x5d07, 0x1a}, | ||
3988 | {0x5d12, 0xf7}, | ||
3989 | {0x5d13, 0xdd}, | ||
3990 | {0x5d14, 0x97}, | ||
3991 | {0x5d15, 0x69}, | ||
3992 | {0x5d16, 0x61}, | ||
3993 | {0x5d17, 0x5b}, | ||
3994 | {0x5d18, 0x62}, | ||
3995 | {0x5d19, 0x8d}, | ||
3996 | {0x5d1a, 0xdd}, | ||
3997 | {0x5d1b, 0xff}, | ||
3998 | {0x5d24, 0x00}, | ||
3999 | {0x5d25, 0x00}, | ||
4000 | {0x5d26, 0x00}, | ||
4001 | {0x5d27, 0x0a}, | ||
4002 | {0x5d28, 0x80}, | ||
4003 | {0x5d2a, 0x00}, | ||
4004 | {0x5d2b, 0x90}, | ||
4005 | {0x5d2c, 0x15}, | ||
4006 | {0x5d2d, 0x90}, | ||
4007 | {0x5d2e, 0x00}, | ||
4008 | {0x5d2f, 0x50}, | ||
4009 | {0x5d30, 0x10}, | ||
4010 | {0x5d31, 0x50}, | ||
4011 | {0x5d32, 0x10}, | ||
4012 | {0x5d34, 0x36}, | ||
4013 | {0x5d35, 0x20}, | ||
4014 | {0x5d36, 0x90}, | ||
4015 | {0x5d37, 0xa0}, | ||
4016 | {0x5d38, 0x5c}, | ||
4017 | {0x5d39, 0x7b}, | ||
4018 | {0x5d1c, 0x00}, | ||
4019 | {0x5d1d, 0x90}, | ||
4020 | {0x5d1e, 0x00}, | ||
4021 | {0x5d1f, 0x50}, | ||
4022 | {0x5d20, 0x15}, | ||
4023 | {0x5d21, 0x00}, | ||
4024 | {0x5d22, 0x10}, | ||
4025 | {0x5d23, 0x00}, | ||
4026 | {0x5d29, 0xc0}, | ||
4027 | {0x3008, 0x01}, | ||
4028 | {0x3663, 0x60}, | ||
4029 | {0x3002, 0x01}, | ||
4030 | {0x3c00, 0x3c}, | ||
4031 | {0x3025, 0x03}, | ||
4032 | {0x3668, 0xf0}, | ||
4033 | {0x3400, 0x04}, | ||
4034 | {OV23850_TABLE_END, 0x00} | ||
4035 | }; | ||
4036 | |||
4037 | static ov23850_reg mode_table_common[] = { | ||
4038 | {0x301e, 0x00}, | ||
4039 | {OV23850_TABLE_WAIT_MS, OV23850_WAIT_MS}, | ||
4040 | {0x0103, 0x01}, | ||
4041 | {0x0300, 0x00}, | ||
4042 | {0x0301, 0x6C}, | ||
4043 | {0x0302, 0x10}, | ||
4044 | {0x0303, 0x00}, | ||
4045 | {0x0304, 0x3A}, | ||
4046 | {0x030d, 0x2d}, | ||
4047 | {0x030e, 0x00}, | ||
4048 | {0x030f, 0x05}, | ||
4049 | {0x0312, 0x02}, | ||
4050 | {0x0313, 0x11}, | ||
4051 | {OV23850_TABLE_END, 0x00}, | ||
4052 | }; | ||
4053 | |||
4054 | enum { | ||
4055 | OV23850_MODE_5632X4224, | ||
4056 | OV23850_MODE_5632X4224_8FPS, | ||
4057 | OV23850_MODE_5632X4224_8FPS_DPCM, | ||
4058 | OV23850_MODE_5632X4224_24FPS_DPCM, | ||
4059 | OV23850_MODE_5632X3168, | ||
4060 | OV23850_MODE_5632X3168_30FPS_DPCM, | ||
4061 | |||
4062 | OV23850_MODE_COMMON, | ||
4063 | OV23850_MODE_START_STREAM, | ||
4064 | OV23850_MODE_STOP_STREAM, | ||
4065 | OV23850_MODE_TEST_PATTERN, | ||
4066 | }; | ||
4067 | |||
4068 | static ov23850_reg *mode_table[] = { | ||
4069 | [OV23850_MODE_5632X4224] = mode_5632x4224_20fps, | ||
4070 | [OV23850_MODE_5632X4224_8FPS] = mode_5632x4224_8fps, | ||
4071 | [OV23850_MODE_5632X4224_8FPS_DPCM] = mode_5632x4224_8fps_dpcm, | ||
4072 | [OV23850_MODE_5632X4224_24FPS_DPCM] = mode_5632x4224_24fps_dpcm, | ||
4073 | [OV23850_MODE_5632X3168] = mode_5632x3168_30fps, | ||
4074 | [OV23850_MODE_5632X3168_30FPS_DPCM] = mode_5632x3168_30fps_dpcm, | ||
4075 | |||
4076 | [OV23850_MODE_COMMON] = mode_table_common, | ||
4077 | [OV23850_MODE_START_STREAM] = ov23850_start, | ||
4078 | [OV23850_MODE_STOP_STREAM] = ov23850_stop, | ||
4079 | [OV23850_MODE_TEST_PATTERN] = tp_colorbars, | ||
4080 | }; | ||
4081 | |||
4082 | static const int ov23850_20fps[] = { | ||
4083 | 20, | ||
4084 | }; | ||
4085 | |||
4086 | static const int ov23850_30fps[] = { | ||
4087 | 30, | ||
4088 | }; | ||
4089 | |||
4090 | static const struct camera_common_frmfmt ov23850_frmfmt[] = { | ||
4091 | {{5632, 4224}, ov23850_20fps, 1, 0, OV23850_MODE_5632X4224}, | ||
4092 | {{5632, 3168}, ov23850_30fps, 1, 0, OV23850_MODE_5632X3168}, | ||
4093 | }; | ||
4094 | #endif /* __OV23850_I2C_TABLES__ */ | ||
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c new file mode 100644 index 000000000..048fcfa6a --- /dev/null +++ b/drivers/media/i2c/ov5693.c | |||
@@ -0,0 +1,1507 @@ | |||
1 | /* | ||
2 | * ov5693_v4l2.c - ov5693 sensor driver | ||
3 | * | ||
4 | * Copyright (c) 2013-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <linux/slab.h> | ||
20 | #include <linux/uaccess.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/module.h> | ||
23 | |||
24 | #include <linux/seq_file.h> | ||
25 | #include <linux/of.h> | ||
26 | #include <linux/of_device.h> | ||
27 | #include <linux/of_gpio.h> | ||
28 | |||
29 | #include <media/camera_common.h> | ||
30 | #include <media/ov5693.h> | ||
31 | |||
32 | #include "../platform/tegra/camera/camera_gpio.h" | ||
33 | |||
34 | #include "ov5693_mode_tbls.h" | ||
35 | |||
36 | #define OV5693_MAX_COARSE_DIFF 6 | ||
37 | |||
38 | #define OV5693_GAIN_SHIFT 8 | ||
39 | #define OV5693_REAL_GAIN_SHIFT 4 | ||
40 | #define OV5693_MIN_GAIN (1 << OV5693_GAIN_SHIFT) | ||
41 | #define OV5693_MAX_GAIN (16 << OV5693_GAIN_SHIFT) | ||
42 | #define OV5693_MAX_UNREAL_GAIN (0x0F80) | ||
43 | #define OV5693_MIN_FRAME_LENGTH (0x0) | ||
44 | #define OV5693_MAX_FRAME_LENGTH (0x7fff) | ||
45 | #define OV5693_MIN_EXPOSURE_COARSE (0x0002) | ||
46 | #define OV5693_MAX_EXPOSURE_COARSE \ | ||
47 | (OV5693_MAX_FRAME_LENGTH-OV5693_MAX_COARSE_DIFF) | ||
48 | #define OV5693_DEFAULT_LINE_LENGTH (0xA80) | ||
49 | #define OV5693_DEFAULT_PIXEL_CLOCK (160) | ||
50 | |||
51 | #define OV5693_DEFAULT_GAIN OV5693_MIN_GAIN | ||
52 | #define OV5693_DEFAULT_FRAME_LENGTH (0x07C0) | ||
53 | #define OV5693_DEFAULT_EXPOSURE_COARSE \ | ||
54 | (OV5693_DEFAULT_FRAME_LENGTH-OV5693_MAX_COARSE_DIFF) | ||
55 | |||
56 | #define OV5693_DEFAULT_MODE OV5693_MODE_2592X1944 | ||
57 | #define OV5693_DEFAULT_HDR_MODE OV5693_MODE_2592X1944_HDR | ||
58 | #define OV5693_DEFAULT_WIDTH 2592 | ||
59 | #define OV5693_DEFAULT_HEIGHT 1944 | ||
60 | #define OV5693_DEFAULT_DATAFMT MEDIA_BUS_FMT_SRGGB10_1X10 | ||
61 | #define OV5693_DEFAULT_CLK_FREQ 24000000 | ||
62 | |||
63 | struct ov5693 { | ||
64 | struct camera_common_power_rail power; | ||
65 | int numctrls; | ||
66 | struct v4l2_ctrl_handler ctrl_handler; | ||
67 | struct camera_common_eeprom_data eeprom[OV5693_EEPROM_NUM_BLOCKS]; | ||
68 | u8 eeprom_buf[OV5693_EEPROM_SIZE]; | ||
69 | struct i2c_client *i2c_client; | ||
70 | struct v4l2_subdev *subdev; | ||
71 | struct media_pad pad; | ||
72 | |||
73 | int reg_offset; | ||
74 | |||
75 | s32 group_hold_prev; | ||
76 | u32 frame_length; | ||
77 | bool group_hold_en; | ||
78 | struct regmap *regmap; | ||
79 | struct camera_common_data *s_data; | ||
80 | struct camera_common_pdata *pdata; | ||
81 | struct v4l2_ctrl *ctrls[]; | ||
82 | }; | ||
83 | |||
84 | static struct regmap_config ov5693_regmap_config = { | ||
85 | .reg_bits = 16, | ||
86 | .val_bits = 8, | ||
87 | }; | ||
88 | |||
89 | static int ov5693_g_volatile_ctrl(struct v4l2_ctrl *ctrl); | ||
90 | static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl); | ||
91 | static void ov5693_update_ctrl_range(struct ov5693 *priv, s32 frame_length); | ||
92 | |||
93 | static const struct v4l2_ctrl_ops ov5693_ctrl_ops = { | ||
94 | .g_volatile_ctrl = ov5693_g_volatile_ctrl, | ||
95 | .s_ctrl = ov5693_s_ctrl, | ||
96 | }; | ||
97 | |||
98 | static struct v4l2_ctrl_config ctrl_config_list[] = { | ||
99 | /* Do not change the name field for the controls! */ | ||
100 | { | ||
101 | .ops = &ov5693_ctrl_ops, | ||
102 | .id = V4L2_CID_GAIN, | ||
103 | .name = "Gain", | ||
104 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
105 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
106 | .min = OV5693_MIN_GAIN, | ||
107 | .max = OV5693_MAX_GAIN, | ||
108 | .def = OV5693_DEFAULT_GAIN, | ||
109 | .step = 1, | ||
110 | }, | ||
111 | { | ||
112 | .ops = &ov5693_ctrl_ops, | ||
113 | .id = V4L2_CID_FRAME_LENGTH, | ||
114 | .name = "Frame Length", | ||
115 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
116 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
117 | .min = OV5693_MIN_FRAME_LENGTH, | ||
118 | .max = OV5693_MAX_FRAME_LENGTH, | ||
119 | .def = OV5693_DEFAULT_FRAME_LENGTH, | ||
120 | .step = 1, | ||
121 | }, | ||
122 | { | ||
123 | .ops = &ov5693_ctrl_ops, | ||
124 | .id = V4L2_CID_COARSE_TIME, | ||
125 | .name = "Coarse Time", | ||
126 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
127 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
128 | .min = OV5693_MIN_EXPOSURE_COARSE, | ||
129 | .max = OV5693_MAX_EXPOSURE_COARSE, | ||
130 | .def = OV5693_DEFAULT_EXPOSURE_COARSE, | ||
131 | .step = 1, | ||
132 | }, | ||
133 | { | ||
134 | .ops = &ov5693_ctrl_ops, | ||
135 | .id = V4L2_CID_COARSE_TIME_SHORT, | ||
136 | .name = "Coarse Time Short", | ||
137 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
138 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
139 | .min = OV5693_MIN_EXPOSURE_COARSE, | ||
140 | .max = OV5693_MAX_EXPOSURE_COARSE, | ||
141 | .def = OV5693_DEFAULT_EXPOSURE_COARSE, | ||
142 | .step = 1, | ||
143 | }, | ||
144 | { | ||
145 | .ops = &ov5693_ctrl_ops, | ||
146 | .id = V4L2_CID_GROUP_HOLD, | ||
147 | .name = "Group Hold", | ||
148 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, | ||
149 | .min = 0, | ||
150 | .max = ARRAY_SIZE(switch_ctrl_qmenu) - 1, | ||
151 | .menu_skip_mask = 0, | ||
152 | .def = 0, | ||
153 | .qmenu_int = switch_ctrl_qmenu, | ||
154 | }, | ||
155 | { | ||
156 | .ops = &ov5693_ctrl_ops, | ||
157 | .id = V4L2_CID_HDR_EN, | ||
158 | .name = "HDR enable", | ||
159 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, | ||
160 | .min = 0, | ||
161 | .max = ARRAY_SIZE(switch_ctrl_qmenu) - 1, | ||
162 | .menu_skip_mask = 0, | ||
163 | .def = 0, | ||
164 | .qmenu_int = switch_ctrl_qmenu, | ||
165 | }, | ||
166 | { | ||
167 | .ops = &ov5693_ctrl_ops, | ||
168 | .id = V4L2_CID_EEPROM_DATA, | ||
169 | .name = "EEPROM Data", | ||
170 | .type = V4L2_CTRL_TYPE_STRING, | ||
171 | .flags = V4L2_CTRL_FLAG_VOLATILE, | ||
172 | .min = 0, | ||
173 | .max = OV5693_EEPROM_STR_SIZE, | ||
174 | .step = 2, | ||
175 | }, | ||
176 | { | ||
177 | .ops = &ov5693_ctrl_ops, | ||
178 | .id = V4L2_CID_OTP_DATA, | ||
179 | .name = "OTP Data", | ||
180 | .type = V4L2_CTRL_TYPE_STRING, | ||
181 | .flags = V4L2_CTRL_FLAG_READ_ONLY, | ||
182 | .min = 0, | ||
183 | .max = OV5693_OTP_STR_SIZE, | ||
184 | .step = 2, | ||
185 | }, | ||
186 | { | ||
187 | .ops = &ov5693_ctrl_ops, | ||
188 | .id = V4L2_CID_FUSE_ID, | ||
189 | .name = "Fuse ID", | ||
190 | .type = V4L2_CTRL_TYPE_STRING, | ||
191 | .flags = V4L2_CTRL_FLAG_READ_ONLY, | ||
192 | .min = 0, | ||
193 | .max = OV5693_FUSE_ID_STR_SIZE, | ||
194 | .step = 2, | ||
195 | }, | ||
196 | }; | ||
197 | |||
198 | static inline void ov5693_get_frame_length_regs(ov5693_reg *regs, | ||
199 | u32 frame_length) | ||
200 | { | ||
201 | regs->addr = OV5693_FRAME_LENGTH_ADDR_MSB; | ||
202 | regs->val = (frame_length >> 8) & 0xff; | ||
203 | (regs + 1)->addr = OV5693_FRAME_LENGTH_ADDR_LSB; | ||
204 | (regs + 1)->val = (frame_length) & 0xff; | ||
205 | } | ||
206 | |||
207 | |||
208 | static inline void ov5693_get_coarse_time_regs(ov5693_reg *regs, | ||
209 | u32 coarse_time) | ||
210 | { | ||
211 | regs->addr = OV5693_COARSE_TIME_ADDR_1; | ||
212 | regs->val = (coarse_time >> 12) & 0xff; | ||
213 | (regs + 1)->addr = OV5693_COARSE_TIME_ADDR_2; | ||
214 | (regs + 1)->val = (coarse_time >> 4) & 0xff; | ||
215 | (regs + 2)->addr = OV5693_COARSE_TIME_ADDR_3; | ||
216 | (regs + 2)->val = (coarse_time & 0xf) << 4; | ||
217 | } | ||
218 | |||
219 | static inline void ov5693_get_coarse_time_short_regs(ov5693_reg *regs, | ||
220 | u32 coarse_time) | ||
221 | { | ||
222 | regs->addr = OV5693_COARSE_TIME_SHORT_ADDR_1; | ||
223 | regs->val = (coarse_time >> 12) & 0xff; | ||
224 | (regs + 1)->addr = OV5693_COARSE_TIME_SHORT_ADDR_2; | ||
225 | (regs + 1)->val = (coarse_time >> 4) & 0xff; | ||
226 | (regs + 2)->addr = OV5693_COARSE_TIME_SHORT_ADDR_3; | ||
227 | (regs + 2)->val = (coarse_time & 0xf) << 4; | ||
228 | } | ||
229 | |||
230 | static inline void ov5693_get_gain_regs(ov5693_reg *regs, | ||
231 | u16 gain) | ||
232 | { | ||
233 | regs->addr = OV5693_GAIN_ADDR_MSB; | ||
234 | regs->val = (gain >> 8) & 0xff; | ||
235 | |||
236 | (regs + 1)->addr = OV5693_GAIN_ADDR_LSB; | ||
237 | (regs + 1)->val = (gain) & 0xff; | ||
238 | } | ||
239 | |||
240 | static int test_mode; | ||
241 | module_param(test_mode, int, 0644); | ||
242 | |||
243 | static inline int ov5693_read_reg(struct camera_common_data *s_data, | ||
244 | u16 addr, u8 *val) | ||
245 | { | ||
246 | struct ov5693 *priv = (struct ov5693 *)s_data->priv; | ||
247 | |||
248 | return regmap_read(priv->regmap, addr, (unsigned int *) val); | ||
249 | } | ||
250 | |||
251 | static int ov5693_write_reg(struct camera_common_data *s_data, u16 addr, u8 val) | ||
252 | { | ||
253 | int err; | ||
254 | struct ov5693 *priv = (struct ov5693 *)s_data->priv; | ||
255 | |||
256 | err = regmap_write(priv->regmap, addr, val); | ||
257 | if (err) | ||
258 | pr_err("%s:i2c write failed, %x = %x\n", | ||
259 | __func__, addr, val); | ||
260 | |||
261 | return err; | ||
262 | } | ||
263 | |||
264 | static int ov5693_write_table(struct ov5693 *priv, | ||
265 | const ov5693_reg table[]) | ||
266 | { | ||
267 | return regmap_util_write_table_8(priv->regmap, | ||
268 | table, | ||
269 | NULL, 0, | ||
270 | OV5693_TABLE_WAIT_MS, | ||
271 | OV5693_TABLE_END); | ||
272 | } | ||
273 | |||
274 | static void ov5693_gpio_set(struct ov5693 *priv, | ||
275 | unsigned int gpio, int val) | ||
276 | { | ||
277 | if (priv->pdata && priv->pdata->use_cam_gpio) | ||
278 | cam_gpio_ctrl(priv->i2c_client, gpio, val, 1); | ||
279 | else { | ||
280 | if (gpio_cansleep(gpio)) | ||
281 | gpio_set_value_cansleep(gpio, val); | ||
282 | else | ||
283 | gpio_set_value(gpio, val); | ||
284 | } | ||
285 | } | ||
286 | |||
287 | static int ov5693_power_on(struct camera_common_data *s_data) | ||
288 | { | ||
289 | int err = 0; | ||
290 | struct ov5693 *priv = (struct ov5693 *)s_data->priv; | ||
291 | struct camera_common_power_rail *pw = &priv->power; | ||
292 | |||
293 | dev_dbg(&priv->i2c_client->dev, "%s: power on\n", __func__); | ||
294 | |||
295 | if (priv->pdata && priv->pdata->power_on) { | ||
296 | err = priv->pdata->power_on(pw); | ||
297 | if (err) | ||
298 | pr_err("%s failed.\n", __func__); | ||
299 | else | ||
300 | pw->state = SWITCH_ON; | ||
301 | return err; | ||
302 | } | ||
303 | |||
304 | /* sleeps calls in the sequence below are for internal device | ||
305 | * signal propagation as specified by sensor vendor */ | ||
306 | |||
307 | if (pw->avdd) | ||
308 | err = regulator_enable(pw->avdd); | ||
309 | if (err) | ||
310 | goto ov5693_avdd_fail; | ||
311 | |||
312 | if (pw->iovdd) | ||
313 | err = regulator_enable(pw->iovdd); | ||
314 | if (err) | ||
315 | goto ov5693_iovdd_fail; | ||
316 | |||
317 | usleep_range(1, 2); | ||
318 | if (pw->pwdn_gpio) | ||
319 | ov5693_gpio_set(priv, pw->pwdn_gpio, 1); | ||
320 | |||
321 | /* | ||
322 | * datasheet 2.9: reset requires ~2ms settling time | ||
323 | * a power on reset is generated after core power becomes stable | ||
324 | */ | ||
325 | usleep_range(2000, 2010); | ||
326 | |||
327 | if (pw->reset_gpio) | ||
328 | ov5693_gpio_set(priv, pw->reset_gpio, 1); | ||
329 | |||
330 | /* datasheet fig 2-9: t3 */ | ||
331 | usleep_range(2000, 2010); | ||
332 | |||
333 | pw->state = SWITCH_ON; | ||
334 | return 0; | ||
335 | |||
336 | ov5693_iovdd_fail: | ||
337 | regulator_disable(pw->avdd); | ||
338 | |||
339 | ov5693_avdd_fail: | ||
340 | pr_err("%s failed.\n", __func__); | ||
341 | return -ENODEV; | ||
342 | } | ||
343 | |||
344 | static int ov5693_power_off(struct camera_common_data *s_data) | ||
345 | { | ||
346 | int err = 0; | ||
347 | struct ov5693 *priv = (struct ov5693 *)s_data->priv; | ||
348 | struct camera_common_power_rail *pw = &priv->power; | ||
349 | |||
350 | dev_dbg(&priv->i2c_client->dev, "%s: power off\n", __func__); | ||
351 | |||
352 | if (priv->pdata && priv->pdata->power_off) { | ||
353 | err = priv->pdata->power_off(pw); | ||
354 | if (!err) { | ||
355 | goto power_off_done; | ||
356 | } else { | ||
357 | pr_err("%s failed.\n", __func__); | ||
358 | return err; | ||
359 | } | ||
360 | } | ||
361 | |||
362 | /* sleeps calls in the sequence below are for internal device | ||
363 | * signal propagation as specified by sensor vendor */ | ||
364 | |||
365 | usleep_range(21, 25); | ||
366 | if (pw->pwdn_gpio) | ||
367 | ov5693_gpio_set(priv, pw->pwdn_gpio, 0); | ||
368 | usleep_range(1, 2); | ||
369 | if (pw->reset_gpio) | ||
370 | ov5693_gpio_set(priv, pw->reset_gpio, 0); | ||
371 | |||
372 | /* datasheet 2.9: reset requires ~2ms settling time*/ | ||
373 | usleep_range(2000, 2010); | ||
374 | |||
375 | if (pw->iovdd) | ||
376 | regulator_disable(pw->iovdd); | ||
377 | if (pw->avdd) | ||
378 | regulator_disable(pw->avdd); | ||
379 | |||
380 | power_off_done: | ||
381 | pw->state = SWITCH_OFF; | ||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | static int ov5693_power_put(struct ov5693 *priv) | ||
386 | { | ||
387 | struct camera_common_power_rail *pw = &priv->power; | ||
388 | |||
389 | if (unlikely(!pw)) | ||
390 | return -EFAULT; | ||
391 | |||
392 | if (likely(pw->avdd)) | ||
393 | regulator_put(pw->avdd); | ||
394 | |||
395 | if (likely(pw->iovdd)) | ||
396 | regulator_put(pw->iovdd); | ||
397 | |||
398 | pw->avdd = NULL; | ||
399 | pw->iovdd = NULL; | ||
400 | |||
401 | if (priv->pdata && priv->pdata->use_cam_gpio) | ||
402 | cam_gpio_deregister(priv->i2c_client, pw->pwdn_gpio); | ||
403 | else { | ||
404 | gpio_free(pw->pwdn_gpio); | ||
405 | gpio_free(pw->reset_gpio); | ||
406 | } | ||
407 | |||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | static int ov5693_power_get(struct ov5693 *priv) | ||
412 | { | ||
413 | struct camera_common_power_rail *pw = &priv->power; | ||
414 | struct camera_common_pdata *pdata = priv->pdata; | ||
415 | const char *mclk_name; | ||
416 | const char *parentclk_name; | ||
417 | struct clk *parent; | ||
418 | int err = 0, ret = 0; | ||
419 | |||
420 | if (!pdata) { | ||
421 | dev_err(&priv->i2c_client->dev, "pdata missing\n"); | ||
422 | return -EFAULT; | ||
423 | } | ||
424 | |||
425 | mclk_name = pdata->mclk_name ? | ||
426 | pdata->mclk_name : "cam_mclk1"; | ||
427 | pw->mclk = devm_clk_get(&priv->i2c_client->dev, mclk_name); | ||
428 | if (IS_ERR(pw->mclk)) { | ||
429 | dev_err(&priv->i2c_client->dev, | ||
430 | "unable to get clock %s\n", mclk_name); | ||
431 | return PTR_ERR(pw->mclk); | ||
432 | } | ||
433 | |||
434 | parentclk_name = pdata->parentclk_name; | ||
435 | if (parentclk_name) { | ||
436 | parent = devm_clk_get(&priv->i2c_client->dev, parentclk_name); | ||
437 | if (IS_ERR(parent)) { | ||
438 | dev_err(&priv->i2c_client->dev, | ||
439 | "unable to get parent clcok %s", | ||
440 | parentclk_name); | ||
441 | } else | ||
442 | clk_set_parent(pw->mclk, parent); | ||
443 | } | ||
444 | |||
445 | |||
446 | /* analog 2.8v */ | ||
447 | err |= camera_common_regulator_get(priv->i2c_client, | ||
448 | &pw->avdd, pdata->regulators.avdd); | ||
449 | /* IO 1.8v */ | ||
450 | err |= camera_common_regulator_get(priv->i2c_client, | ||
451 | &pw->iovdd, pdata->regulators.iovdd); | ||
452 | |||
453 | if (!err) { | ||
454 | pw->reset_gpio = pdata->reset_gpio; | ||
455 | pw->pwdn_gpio = pdata->pwdn_gpio; | ||
456 | } | ||
457 | |||
458 | if (pdata->use_cam_gpio) { | ||
459 | err = cam_gpio_register(priv->i2c_client, pw->pwdn_gpio); | ||
460 | if (err) | ||
461 | dev_err(&priv->i2c_client->dev, | ||
462 | "%s ERR can't register cam gpio %u!\n", | ||
463 | __func__, pw->pwdn_gpio); | ||
464 | } else { | ||
465 | ret = gpio_request(pw->pwdn_gpio, "cam_pwdn_gpio"); | ||
466 | if (ret < 0) | ||
467 | dev_dbg(&priv->i2c_client->dev, | ||
468 | "%s can't request pwdn_gpio %d\n", | ||
469 | __func__, ret); | ||
470 | ret = gpio_request(pw->reset_gpio, "cam_reset_gpio"); | ||
471 | if (ret < 0) | ||
472 | dev_dbg(&priv->i2c_client->dev, | ||
473 | "%s can't request reset_gpio %d\n", | ||
474 | __func__, ret); | ||
475 | } | ||
476 | |||
477 | |||
478 | pw->state = SWITCH_OFF; | ||
479 | return err; | ||
480 | } | ||
481 | |||
482 | static int ov5693_set_gain(struct ov5693 *priv, s32 val); | ||
483 | static int ov5693_set_frame_length(struct ov5693 *priv, s32 val); | ||
484 | static int ov5693_set_coarse_time(struct ov5693 *priv, s32 val); | ||
485 | static int ov5693_set_coarse_time_short(struct ov5693 *priv, s32 val); | ||
486 | |||
487 | static int ov5693_s_stream(struct v4l2_subdev *sd, int enable) | ||
488 | { | ||
489 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
490 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
491 | struct ov5693 *priv = (struct ov5693 *)s_data->priv; | ||
492 | struct v4l2_control control; | ||
493 | int err; | ||
494 | u32 frame_time; | ||
495 | |||
496 | dev_dbg(&client->dev, "%s++\n", __func__); | ||
497 | |||
498 | if (!enable) { | ||
499 | ov5693_update_ctrl_range(priv, OV5693_MAX_FRAME_LENGTH); | ||
500 | |||
501 | err = ov5693_write_table(priv, | ||
502 | mode_table[OV5693_MODE_STOP_STREAM]); | ||
503 | if (err) | ||
504 | return err; | ||
505 | |||
506 | /* | ||
507 | * Wait for one frame to make sure sensor is set to | ||
508 | * software standby in V-blank | ||
509 | * | ||
510 | * frame_time = frame length rows * Tline | ||
511 | * Tline = line length / pixel clock (in MHz) | ||
512 | */ | ||
513 | frame_time = priv->frame_length * | ||
514 | OV5693_DEFAULT_LINE_LENGTH / OV5693_DEFAULT_PIXEL_CLOCK; | ||
515 | |||
516 | usleep_range(frame_time, frame_time + 1000); | ||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | err = ov5693_write_table(priv, mode_table[s_data->mode]); | ||
521 | if (err) | ||
522 | goto exit; | ||
523 | |||
524 | |||
525 | if (s_data->override_enable) { | ||
526 | /* | ||
527 | * write list of override regs for the asking frame length, | ||
528 | * coarse integration time, and gain. Failures to write | ||
529 | * overrides are non-fatal | ||
530 | */ | ||
531 | control.id = V4L2_CID_GAIN; | ||
532 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
533 | err |= ov5693_set_gain(priv, control.value); | ||
534 | if (err) | ||
535 | dev_dbg(&client->dev, "%s: warning gain override failed\n", | ||
536 | __func__); | ||
537 | |||
538 | control.id = V4L2_CID_FRAME_LENGTH; | ||
539 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
540 | err |= ov5693_set_frame_length(priv, control.value); | ||
541 | if (err) | ||
542 | dev_dbg(&client->dev, | ||
543 | "%s: warning frame length override failed\n", | ||
544 | __func__); | ||
545 | |||
546 | control.id = V4L2_CID_COARSE_TIME; | ||
547 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
548 | err |= ov5693_set_coarse_time(priv, control.value); | ||
549 | if (err) | ||
550 | dev_dbg(&client->dev, | ||
551 | "%s: warning coarse time override failed\n", | ||
552 | __func__); | ||
553 | |||
554 | control.id = V4L2_CID_COARSE_TIME_SHORT; | ||
555 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
556 | err |= ov5693_set_coarse_time_short(priv, control.value); | ||
557 | if (err) | ||
558 | dev_dbg(&client->dev, | ||
559 | "%s: warning coarse time short override failed\n", | ||
560 | __func__); | ||
561 | } | ||
562 | |||
563 | err = ov5693_write_table(priv, mode_table[OV5693_MODE_START_STREAM]); | ||
564 | if (err) | ||
565 | goto exit; | ||
566 | |||
567 | if (test_mode) | ||
568 | err = ov5693_write_table(priv, | ||
569 | mode_table[OV5693_MODE_TEST_PATTERN]); | ||
570 | |||
571 | dev_dbg(&client->dev, "%s--\n", __func__); | ||
572 | return 0; | ||
573 | exit: | ||
574 | dev_dbg(&client->dev, "%s: error setting stream\n", __func__); | ||
575 | return err; | ||
576 | } | ||
577 | |||
578 | static int ov5693_g_input_status(struct v4l2_subdev *sd, u32 *status) | ||
579 | { | ||
580 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
581 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
582 | struct ov5693 *priv = (struct ov5693 *)s_data->priv; | ||
583 | struct camera_common_power_rail *pw = &priv->power; | ||
584 | |||
585 | *status = pw->state == SWITCH_ON; | ||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | static struct v4l2_subdev_video_ops ov5693_subdev_video_ops = { | ||
590 | .s_stream = ov5693_s_stream, | ||
591 | .g_mbus_config = camera_common_g_mbus_config, | ||
592 | .g_input_status = ov5693_g_input_status, | ||
593 | }; | ||
594 | |||
595 | static struct v4l2_subdev_core_ops ov5693_subdev_core_ops = { | ||
596 | .s_power = camera_common_s_power, | ||
597 | }; | ||
598 | |||
599 | static int ov5693_get_fmt(struct v4l2_subdev *sd, | ||
600 | struct v4l2_subdev_pad_config *cfg, | ||
601 | struct v4l2_subdev_format *format) | ||
602 | { | ||
603 | return camera_common_g_fmt(sd, &format->format); | ||
604 | } | ||
605 | |||
606 | static int ov5693_set_fmt(struct v4l2_subdev *sd, | ||
607 | struct v4l2_subdev_pad_config *cfg, | ||
608 | struct v4l2_subdev_format *format) | ||
609 | { | ||
610 | int ret; | ||
611 | |||
612 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) | ||
613 | ret = camera_common_try_fmt(sd, &format->format); | ||
614 | else | ||
615 | ret = camera_common_s_fmt(sd, &format->format); | ||
616 | |||
617 | return ret; | ||
618 | } | ||
619 | |||
620 | static struct v4l2_subdev_pad_ops ov5693_subdev_pad_ops = { | ||
621 | .set_fmt = ov5693_set_fmt, | ||
622 | .get_fmt = ov5693_get_fmt, | ||
623 | .enum_mbus_code = camera_common_enum_mbus_code, | ||
624 | .enum_frame_size = camera_common_enum_framesizes, | ||
625 | .enum_frame_interval = camera_common_enum_frameintervals, | ||
626 | }; | ||
627 | |||
628 | static struct v4l2_subdev_ops ov5693_subdev_ops = { | ||
629 | .core = &ov5693_subdev_core_ops, | ||
630 | .video = &ov5693_subdev_video_ops, | ||
631 | .pad = &ov5693_subdev_pad_ops, | ||
632 | }; | ||
633 | |||
634 | static struct of_device_id ov5693_of_match[] = { | ||
635 | { .compatible = "nvidia,ov5693", }, | ||
636 | { }, | ||
637 | }; | ||
638 | |||
639 | static struct camera_common_sensor_ops ov5693_common_ops = { | ||
640 | .power_on = ov5693_power_on, | ||
641 | .power_off = ov5693_power_off, | ||
642 | .write_reg = ov5693_write_reg, | ||
643 | .read_reg = ov5693_read_reg, | ||
644 | }; | ||
645 | |||
646 | static int ov5693_set_group_hold(struct ov5693 *priv) | ||
647 | { | ||
648 | int err; | ||
649 | int gh_prev = switch_ctrl_qmenu[priv->group_hold_prev]; | ||
650 | |||
651 | if (priv->group_hold_en == true && gh_prev == SWITCH_OFF) { | ||
652 | /* enter group hold */ | ||
653 | err = ov5693_write_reg(priv->s_data, | ||
654 | OV5693_GROUP_HOLD_ADDR, 0x01); | ||
655 | if (err) | ||
656 | goto fail; | ||
657 | |||
658 | priv->group_hold_prev = 1; | ||
659 | |||
660 | dev_dbg(&priv->i2c_client->dev, | ||
661 | "%s: enter group hold\n", __func__); | ||
662 | } else if (priv->group_hold_en == false && gh_prev == SWITCH_ON) { | ||
663 | /* leave group hold */ | ||
664 | err = ov5693_write_reg(priv->s_data, | ||
665 | OV5693_GROUP_HOLD_ADDR, 0x11); | ||
666 | if (err) | ||
667 | goto fail; | ||
668 | |||
669 | err = ov5693_write_reg(priv->s_data, | ||
670 | OV5693_GROUP_HOLD_ADDR, 0x61); | ||
671 | if (err) | ||
672 | goto fail; | ||
673 | |||
674 | priv->group_hold_prev = 0; | ||
675 | |||
676 | dev_dbg(&priv->i2c_client->dev, | ||
677 | "%s: leave group hold\n", __func__); | ||
678 | } | ||
679 | |||
680 | return 0; | ||
681 | |||
682 | fail: | ||
683 | dev_dbg(&priv->i2c_client->dev, | ||
684 | "%s: Group hold control error\n", __func__); | ||
685 | return err; | ||
686 | } | ||
687 | |||
688 | static u16 ov5693_to_real_gain(u32 rep, int shift) | ||
689 | { | ||
690 | u16 gain; | ||
691 | int gain_int; | ||
692 | int gain_dec; | ||
693 | int min_int = (1 << shift); | ||
694 | |||
695 | if (rep < OV5693_MIN_GAIN) | ||
696 | rep = OV5693_MIN_GAIN; | ||
697 | else if (rep > OV5693_MAX_GAIN) | ||
698 | rep = OV5693_MAX_GAIN; | ||
699 | |||
700 | gain_int = (int)(rep >> shift); | ||
701 | gain_dec = (int)(rep & ~(0xffff << shift)); | ||
702 | |||
703 | /* derived from formulat gain = (x * 16 + 0.5) */ | ||
704 | gain = ((gain_int * min_int + gain_dec) * 32 + min_int) / (2 * min_int); | ||
705 | |||
706 | return gain; | ||
707 | } | ||
708 | |||
709 | static int ov5693_set_gain(struct ov5693 *priv, s32 val) | ||
710 | { | ||
711 | ov5693_reg reg_list[2]; | ||
712 | int err; | ||
713 | u16 gain; | ||
714 | int i; | ||
715 | |||
716 | if (!priv->group_hold_prev) | ||
717 | ov5693_set_group_hold(priv); | ||
718 | |||
719 | /* translate value */ | ||
720 | gain = ov5693_to_real_gain((u32)val, OV5693_GAIN_SHIFT); | ||
721 | |||
722 | ov5693_get_gain_regs(reg_list, gain); | ||
723 | dev_dbg(&priv->i2c_client->dev, | ||
724 | "%s: gain %04x val: %04x\n", __func__, val, gain); | ||
725 | |||
726 | for (i = 0; i < 2; i++) { | ||
727 | err = ov5693_write_reg(priv->s_data, reg_list[i].addr, | ||
728 | reg_list[i].val); | ||
729 | if (err) | ||
730 | goto fail; | ||
731 | } | ||
732 | |||
733 | return 0; | ||
734 | |||
735 | fail: | ||
736 | dev_dbg(&priv->i2c_client->dev, | ||
737 | "%s: GAIN control error\n", __func__); | ||
738 | return err; | ||
739 | } | ||
740 | |||
741 | static void ov5693_update_ctrl_range(struct ov5693 *priv, s32 frame_length) | ||
742 | { | ||
743 | struct v4l2_ctrl *ctrl = NULL; | ||
744 | int ctrl_ids[2] = {V4L2_CID_COARSE_TIME, | ||
745 | V4L2_CID_COARSE_TIME_SHORT}; | ||
746 | s32 max, min, def; | ||
747 | int i, j; | ||
748 | |||
749 | for (i = 0; i < ARRAY_SIZE(ctrl_ids); i++) { | ||
750 | for (j = 0; j < priv->numctrls; j++) { | ||
751 | if (priv->ctrls[j]->id == ctrl_ids[i]) { | ||
752 | ctrl = priv->ctrls[j]; | ||
753 | break; | ||
754 | } | ||
755 | } | ||
756 | |||
757 | if (j == priv->numctrls) { | ||
758 | dev_err(&priv->i2c_client->dev, | ||
759 | "could not find ctrl %x\n", | ||
760 | ctrl_ids[i]); | ||
761 | continue; | ||
762 | } | ||
763 | |||
764 | max = frame_length - OV5693_MAX_COARSE_DIFF; | ||
765 | /* clamp the value in case above is negative */ | ||
766 | max = clamp_val(max, OV5693_MIN_EXPOSURE_COARSE, | ||
767 | OV5693_MAX_EXPOSURE_COARSE); | ||
768 | min = OV5693_MIN_EXPOSURE_COARSE; | ||
769 | def = clamp_val(OV5693_DEFAULT_EXPOSURE_COARSE, min, max); | ||
770 | if (__v4l2_ctrl_modify_range(ctrl, min, max, 1, def)) | ||
771 | dev_err(&priv->i2c_client->dev, | ||
772 | "ctrl %x: range update failed\n", | ||
773 | ctrl_ids[i]); | ||
774 | } | ||
775 | |||
776 | } | ||
777 | |||
778 | static int ov5693_set_frame_length(struct ov5693 *priv, s32 val) | ||
779 | { | ||
780 | ov5693_reg reg_list[2]; | ||
781 | int err; | ||
782 | u32 frame_length; | ||
783 | int i; | ||
784 | |||
785 | if (!priv->group_hold_prev) | ||
786 | ov5693_set_group_hold(priv); | ||
787 | |||
788 | frame_length = (u32)val; | ||
789 | |||
790 | ov5693_get_frame_length_regs(reg_list, frame_length); | ||
791 | dev_dbg(&priv->i2c_client->dev, | ||
792 | "%s: val: %d\n", __func__, frame_length); | ||
793 | |||
794 | for (i = 0; i < 2; i++) { | ||
795 | err = ov5693_write_reg(priv->s_data, reg_list[i].addr, | ||
796 | reg_list[i].val); | ||
797 | if (err) | ||
798 | goto fail; | ||
799 | } | ||
800 | |||
801 | priv->frame_length = frame_length; | ||
802 | |||
803 | ov5693_update_ctrl_range(priv, val); | ||
804 | return 0; | ||
805 | |||
806 | fail: | ||
807 | dev_dbg(&priv->i2c_client->dev, | ||
808 | "%s: FRAME_LENGTH control error\n", __func__); | ||
809 | return err; | ||
810 | } | ||
811 | |||
812 | static int ov5693_set_coarse_time(struct ov5693 *priv, s32 val) | ||
813 | { | ||
814 | ov5693_reg reg_list[3]; | ||
815 | int err; | ||
816 | u32 coarse_time; | ||
817 | int i; | ||
818 | |||
819 | if (!priv->group_hold_prev) | ||
820 | ov5693_set_group_hold(priv); | ||
821 | |||
822 | coarse_time = (u32)val; | ||
823 | |||
824 | ov5693_get_coarse_time_regs(reg_list, coarse_time); | ||
825 | dev_dbg(&priv->i2c_client->dev, | ||
826 | "%s: val: %d\n", __func__, coarse_time); | ||
827 | |||
828 | for (i = 0; i < 3; i++) { | ||
829 | err = ov5693_write_reg(priv->s_data, reg_list[i].addr, | ||
830 | reg_list[i].val); | ||
831 | if (err) | ||
832 | goto fail; | ||
833 | } | ||
834 | |||
835 | return 0; | ||
836 | |||
837 | fail: | ||
838 | dev_dbg(&priv->i2c_client->dev, | ||
839 | "%s: COARSE_TIME control error\n", __func__); | ||
840 | return err; | ||
841 | } | ||
842 | |||
843 | static int ov5693_set_coarse_time_short(struct ov5693 *priv, s32 val) | ||
844 | { | ||
845 | ov5693_reg reg_list[3]; | ||
846 | int err; | ||
847 | struct v4l2_control hdr_control; | ||
848 | int hdr_en; | ||
849 | u32 coarse_time_short; | ||
850 | int i; | ||
851 | |||
852 | if (!priv->group_hold_prev) | ||
853 | ov5693_set_group_hold(priv); | ||
854 | |||
855 | /* check hdr enable ctrl */ | ||
856 | hdr_control.id = V4L2_CID_HDR_EN; | ||
857 | |||
858 | err = camera_common_g_ctrl(priv->s_data, &hdr_control); | ||
859 | if (err < 0) { | ||
860 | dev_err(&priv->i2c_client->dev, | ||
861 | "could not find device ctrl.\n"); | ||
862 | return err; | ||
863 | } | ||
864 | |||
865 | hdr_en = switch_ctrl_qmenu[hdr_control.value]; | ||
866 | if (hdr_en == SWITCH_OFF) | ||
867 | return 0; | ||
868 | |||
869 | coarse_time_short = (u32)val; | ||
870 | |||
871 | ov5693_get_coarse_time_short_regs(reg_list, coarse_time_short); | ||
872 | dev_dbg(&priv->i2c_client->dev, | ||
873 | "%s: val: %d\n", __func__, coarse_time_short); | ||
874 | |||
875 | for (i = 0; i < 3; i++) { | ||
876 | err = ov5693_write_reg(priv->s_data, reg_list[i].addr, | ||
877 | reg_list[i].val); | ||
878 | if (err) | ||
879 | goto fail; | ||
880 | } | ||
881 | |||
882 | return 0; | ||
883 | |||
884 | fail: | ||
885 | dev_dbg(&priv->i2c_client->dev, | ||
886 | "%s: COARSE_TIME_SHORT control error\n", __func__); | ||
887 | return err; | ||
888 | } | ||
889 | |||
890 | static int ov5693_eeprom_device_release(struct ov5693 *priv) | ||
891 | { | ||
892 | int i; | ||
893 | |||
894 | for (i = 0; i < OV5693_EEPROM_NUM_BLOCKS; i++) { | ||
895 | if (priv->eeprom[i].i2c_client != NULL) { | ||
896 | i2c_unregister_device(priv->eeprom[i].i2c_client); | ||
897 | priv->eeprom[i].i2c_client = NULL; | ||
898 | } | ||
899 | } | ||
900 | |||
901 | return 0; | ||
902 | } | ||
903 | |||
904 | static int ov5693_eeprom_device_init(struct ov5693 *priv) | ||
905 | { | ||
906 | char *dev_name = "eeprom_ov5693"; | ||
907 | static struct regmap_config eeprom_regmap_config = { | ||
908 | .reg_bits = 8, | ||
909 | .val_bits = 8, | ||
910 | }; | ||
911 | int i; | ||
912 | int err; | ||
913 | |||
914 | if (!priv->pdata->has_eeprom) | ||
915 | return -EINVAL; | ||
916 | |||
917 | for (i = 0; i < OV5693_EEPROM_NUM_BLOCKS; i++) { | ||
918 | priv->eeprom[i].adap = i2c_get_adapter( | ||
919 | priv->i2c_client->adapter->nr); | ||
920 | memset(&priv->eeprom[i].brd, 0, sizeof(priv->eeprom[i].brd)); | ||
921 | strncpy(priv->eeprom[i].brd.type, dev_name, | ||
922 | sizeof(priv->eeprom[i].brd.type)); | ||
923 | priv->eeprom[i].brd.addr = OV5693_EEPROM_ADDRESS + i; | ||
924 | priv->eeprom[i].i2c_client = i2c_new_device( | ||
925 | priv->eeprom[i].adap, &priv->eeprom[i].brd); | ||
926 | |||
927 | priv->eeprom[i].regmap = devm_regmap_init_i2c( | ||
928 | priv->eeprom[i].i2c_client, &eeprom_regmap_config); | ||
929 | if (IS_ERR(priv->eeprom[i].regmap)) { | ||
930 | err = PTR_ERR(priv->eeprom[i].regmap); | ||
931 | ov5693_eeprom_device_release(priv); | ||
932 | return err; | ||
933 | } | ||
934 | } | ||
935 | |||
936 | return 0; | ||
937 | } | ||
938 | |||
939 | static int ov5693_read_eeprom(struct ov5693 *priv, | ||
940 | struct v4l2_ctrl *ctrl) | ||
941 | { | ||
942 | int err, i; | ||
943 | |||
944 | for (i = 0; i < OV5693_EEPROM_NUM_BLOCKS; i++) { | ||
945 | err = regmap_bulk_read(priv->eeprom[i].regmap, 0, | ||
946 | &priv->eeprom_buf[i * OV5693_EEPROM_BLOCK_SIZE], | ||
947 | OV5693_EEPROM_BLOCK_SIZE); | ||
948 | if (err) | ||
949 | return err; | ||
950 | } | ||
951 | |||
952 | for (i = 0; i < OV5693_EEPROM_SIZE; i++) | ||
953 | sprintf(&ctrl->p_new.p_char[i*2], "%02x", | ||
954 | priv->eeprom_buf[i]); | ||
955 | return 0; | ||
956 | } | ||
957 | |||
958 | static int ov5693_write_eeprom(struct ov5693 *priv, | ||
959 | char *string) | ||
960 | { | ||
961 | int err; | ||
962 | int i; | ||
963 | u8 curr[3]; | ||
964 | unsigned long data; | ||
965 | |||
966 | for (i = 0; i < OV5693_EEPROM_SIZE; i++) { | ||
967 | curr[0] = string[i*2]; | ||
968 | curr[1] = string[i*2+1]; | ||
969 | curr[2] = '\0'; | ||
970 | |||
971 | err = kstrtol(curr, 16, &data); | ||
972 | if (err) { | ||
973 | dev_err(&priv->i2c_client->dev, | ||
974 | "invalid eeprom string\n"); | ||
975 | return -EINVAL; | ||
976 | } | ||
977 | |||
978 | priv->eeprom_buf[i] = (u8)data; | ||
979 | err = regmap_write(priv->eeprom[i >> 8].regmap, | ||
980 | i & 0xFF, (u8)data); | ||
981 | if (err) | ||
982 | return err; | ||
983 | msleep(20); | ||
984 | } | ||
985 | return 0; | ||
986 | } | ||
987 | |||
988 | static int ov5693_read_otp_bank(struct ov5693 *priv, | ||
989 | u8 *buf, int bank, u16 addr, int size) | ||
990 | { | ||
991 | int err; | ||
992 | |||
993 | /* sleeps calls in the sequence below are for internal device | ||
994 | * signal propagation as specified by sensor vendor */ | ||
995 | |||
996 | usleep_range(10000, 11000); | ||
997 | err = ov5693_write_table(priv, mode_table[OV5693_MODE_START_STREAM]); | ||
998 | if (err) | ||
999 | return err; | ||
1000 | |||
1001 | err = ov5693_write_reg(priv->s_data, OV5693_OTP_BANK_SELECT_ADDR, | ||
1002 | 0xC0 | bank); | ||
1003 | if (err) | ||
1004 | return err; | ||
1005 | |||
1006 | err = ov5693_write_reg(priv->s_data, OV5693_OTP_LOAD_CTRL_ADDR, 0x01); | ||
1007 | if (err) | ||
1008 | return err; | ||
1009 | |||
1010 | usleep_range(10000, 11000); | ||
1011 | err = regmap_bulk_read(priv->regmap, addr, buf, size); | ||
1012 | if (err) | ||
1013 | return err; | ||
1014 | |||
1015 | err = ov5693_write_table(priv, | ||
1016 | mode_table[OV5693_MODE_STOP_STREAM]); | ||
1017 | if (err) | ||
1018 | return err; | ||
1019 | |||
1020 | return 0; | ||
1021 | } | ||
1022 | |||
1023 | static int ov5693_otp_setup(struct ov5693 *priv) | ||
1024 | { | ||
1025 | int err; | ||
1026 | int i; | ||
1027 | struct v4l2_ctrl *ctrl; | ||
1028 | u8 otp_buf[OV5693_OTP_SIZE]; | ||
1029 | |||
1030 | err = camera_common_s_power(priv->subdev, true); | ||
1031 | if (err) | ||
1032 | return -ENODEV; | ||
1033 | |||
1034 | for (i = 0; i < OV5693_OTP_NUM_BANKS; i++) { | ||
1035 | err = ov5693_read_otp_bank(priv, | ||
1036 | &otp_buf[i * OV5693_OTP_BANK_SIZE], | ||
1037 | i, | ||
1038 | OV5693_OTP_BANK_START_ADDR, | ||
1039 | OV5693_OTP_BANK_SIZE); | ||
1040 | if (err) { | ||
1041 | dev_err(&priv->i2c_client->dev, | ||
1042 | "could not read otp bank\n"); | ||
1043 | goto ret; | ||
1044 | } | ||
1045 | } | ||
1046 | |||
1047 | ctrl = v4l2_ctrl_find(&priv->ctrl_handler, V4L2_CID_OTP_DATA); | ||
1048 | if (!ctrl) { | ||
1049 | dev_err(&priv->i2c_client->dev, | ||
1050 | "could not find device ctrl.\n"); | ||
1051 | err = -EINVAL; | ||
1052 | goto ret; | ||
1053 | } | ||
1054 | |||
1055 | for (i = 0; i < OV5693_OTP_SIZE; i++) | ||
1056 | sprintf(&ctrl->p_new.p_char[i*2], "%02x", | ||
1057 | otp_buf[i]); | ||
1058 | ctrl->p_cur.p_char = ctrl->p_new.p_char; | ||
1059 | |||
1060 | ret: | ||
1061 | camera_common_s_power(priv->subdev, false); | ||
1062 | |||
1063 | return err; | ||
1064 | } | ||
1065 | |||
1066 | static int ov5693_fuse_id_setup(struct ov5693 *priv) | ||
1067 | { | ||
1068 | int err; | ||
1069 | int i; | ||
1070 | struct v4l2_ctrl *ctrl; | ||
1071 | u8 fuse_id[OV5693_FUSE_ID_SIZE]; | ||
1072 | |||
1073 | err = camera_common_s_power(priv->subdev, true); | ||
1074 | if (err) | ||
1075 | return -ENODEV; | ||
1076 | |||
1077 | err = ov5693_read_otp_bank(priv, | ||
1078 | &fuse_id[0], | ||
1079 | OV5693_FUSE_ID_OTP_BANK, | ||
1080 | OV5693_FUSE_ID_OTP_START_ADDR, | ||
1081 | OV5693_FUSE_ID_SIZE); | ||
1082 | if (err) { | ||
1083 | dev_err(&priv->i2c_client->dev, | ||
1084 | "could not read otp bank\n"); | ||
1085 | goto ret; | ||
1086 | } | ||
1087 | |||
1088 | ctrl = v4l2_ctrl_find(&priv->ctrl_handler, V4L2_CID_FUSE_ID); | ||
1089 | if (!ctrl) { | ||
1090 | dev_err(&priv->i2c_client->dev, | ||
1091 | "could not find device ctrl.\n"); | ||
1092 | err = -EINVAL; | ||
1093 | goto ret; | ||
1094 | } | ||
1095 | |||
1096 | for (i = 0; i < OV5693_FUSE_ID_SIZE; i++) | ||
1097 | sprintf(&ctrl->p_new.p_char[i*2], "%02x", | ||
1098 | fuse_id[i]); | ||
1099 | ctrl->p_cur.p_char = ctrl->p_new.p_char; | ||
1100 | |||
1101 | ret: | ||
1102 | camera_common_s_power(priv->subdev, false); | ||
1103 | |||
1104 | return err; | ||
1105 | } | ||
1106 | |||
1107 | static int ov5693_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | ||
1108 | { | ||
1109 | struct ov5693 *priv = | ||
1110 | container_of(ctrl->handler, struct ov5693, ctrl_handler); | ||
1111 | int err = 0; | ||
1112 | |||
1113 | if (priv->power.state == SWITCH_OFF) | ||
1114 | return 0; | ||
1115 | |||
1116 | switch (ctrl->id) { | ||
1117 | case V4L2_CID_EEPROM_DATA: | ||
1118 | err = ov5693_read_eeprom(priv, ctrl); | ||
1119 | if (err) | ||
1120 | return err; | ||
1121 | break; | ||
1122 | default: | ||
1123 | pr_err("%s: unknown ctrl id.\n", __func__); | ||
1124 | return -EINVAL; | ||
1125 | } | ||
1126 | |||
1127 | return err; | ||
1128 | } | ||
1129 | |||
1130 | static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl) | ||
1131 | { | ||
1132 | struct ov5693 *priv = | ||
1133 | container_of(ctrl->handler, struct ov5693, ctrl_handler); | ||
1134 | int err = 0; | ||
1135 | |||
1136 | if (priv->power.state == SWITCH_OFF) | ||
1137 | return 0; | ||
1138 | |||
1139 | switch (ctrl->id) { | ||
1140 | case V4L2_CID_GAIN: | ||
1141 | err = ov5693_set_gain(priv, ctrl->val); | ||
1142 | break; | ||
1143 | case V4L2_CID_FRAME_LENGTH: | ||
1144 | err = ov5693_set_frame_length(priv, ctrl->val); | ||
1145 | break; | ||
1146 | case V4L2_CID_COARSE_TIME: | ||
1147 | err = ov5693_set_coarse_time(priv, ctrl->val); | ||
1148 | break; | ||
1149 | case V4L2_CID_COARSE_TIME_SHORT: | ||
1150 | err = ov5693_set_coarse_time_short(priv, ctrl->val); | ||
1151 | break; | ||
1152 | case V4L2_CID_GROUP_HOLD: | ||
1153 | if (switch_ctrl_qmenu[ctrl->val] == SWITCH_ON) { | ||
1154 | priv->group_hold_en = true; | ||
1155 | } else { | ||
1156 | priv->group_hold_en = false; | ||
1157 | err = ov5693_set_group_hold(priv); | ||
1158 | } | ||
1159 | break; | ||
1160 | case V4L2_CID_EEPROM_DATA: | ||
1161 | if (!ctrl->p_new.p_char[0]) | ||
1162 | break; | ||
1163 | err = ov5693_write_eeprom(priv, ctrl->p_new.p_char); | ||
1164 | if (err) | ||
1165 | return err; | ||
1166 | break; | ||
1167 | case V4L2_CID_HDR_EN: | ||
1168 | break; | ||
1169 | default: | ||
1170 | pr_err("%s: unknown ctrl id.\n", __func__); | ||
1171 | return -EINVAL; | ||
1172 | } | ||
1173 | |||
1174 | return err; | ||
1175 | } | ||
1176 | |||
1177 | static int ov5693_ctrls_init(struct ov5693 *priv, bool eeprom_ctrl) | ||
1178 | { | ||
1179 | struct i2c_client *client = priv->i2c_client; | ||
1180 | struct camera_common_data *common_data = priv->s_data; | ||
1181 | struct v4l2_ctrl *ctrl; | ||
1182 | int numctrls; | ||
1183 | int err; | ||
1184 | int i; | ||
1185 | |||
1186 | dev_dbg(&client->dev, "%s++\n", __func__); | ||
1187 | |||
1188 | numctrls = ARRAY_SIZE(ctrl_config_list); | ||
1189 | v4l2_ctrl_handler_init(&priv->ctrl_handler, numctrls); | ||
1190 | |||
1191 | for (i = 0; i < numctrls; i++) { | ||
1192 | /* Skip control 'V4L2_CID_EEPROM_DATA' if eeprom inint err */ | ||
1193 | if (ctrl_config_list[i].id == V4L2_CID_EEPROM_DATA) { | ||
1194 | if (!eeprom_ctrl) { | ||
1195 | common_data->numctrls -= 1; | ||
1196 | continue; | ||
1197 | } | ||
1198 | } | ||
1199 | |||
1200 | ctrl = v4l2_ctrl_new_custom(&priv->ctrl_handler, | ||
1201 | &ctrl_config_list[i], NULL); | ||
1202 | if (ctrl == NULL) { | ||
1203 | dev_err(&client->dev, "Failed to init %s ctrl\n", | ||
1204 | ctrl_config_list[i].name); | ||
1205 | continue; | ||
1206 | } | ||
1207 | |||
1208 | if (ctrl_config_list[i].type == V4L2_CTRL_TYPE_STRING && | ||
1209 | ctrl_config_list[i].flags & V4L2_CTRL_FLAG_READ_ONLY) { | ||
1210 | ctrl->p_new.p_char = devm_kzalloc(&client->dev, | ||
1211 | ctrl_config_list[i].max + 1, GFP_KERNEL); | ||
1212 | if (!ctrl->p_new.p_char) | ||
1213 | return -ENOMEM; | ||
1214 | } | ||
1215 | priv->ctrls[i] = ctrl; | ||
1216 | } | ||
1217 | |||
1218 | priv->numctrls = numctrls; | ||
1219 | priv->subdev->ctrl_handler = &priv->ctrl_handler; | ||
1220 | if (priv->ctrl_handler.error) { | ||
1221 | dev_err(&client->dev, "Error %d adding controls\n", | ||
1222 | priv->ctrl_handler.error); | ||
1223 | err = priv->ctrl_handler.error; | ||
1224 | goto error; | ||
1225 | } | ||
1226 | |||
1227 | err = v4l2_ctrl_handler_setup(&priv->ctrl_handler); | ||
1228 | if (err) { | ||
1229 | dev_err(&client->dev, | ||
1230 | "Error %d setting default controls\n", err); | ||
1231 | goto error; | ||
1232 | } | ||
1233 | |||
1234 | err = ov5693_otp_setup(priv); | ||
1235 | if (err) { | ||
1236 | dev_err(&client->dev, | ||
1237 | "Error %d reading otp data\n", err); | ||
1238 | goto error; | ||
1239 | } | ||
1240 | |||
1241 | err = ov5693_fuse_id_setup(priv); | ||
1242 | if (err) { | ||
1243 | dev_err(&client->dev, | ||
1244 | "Error %d reading fuse id data\n", err); | ||
1245 | goto error; | ||
1246 | } | ||
1247 | |||
1248 | return 0; | ||
1249 | |||
1250 | error: | ||
1251 | v4l2_ctrl_handler_free(&priv->ctrl_handler); | ||
1252 | return err; | ||
1253 | } | ||
1254 | |||
1255 | MODULE_DEVICE_TABLE(of, ov5693_of_match); | ||
1256 | |||
1257 | static struct camera_common_pdata *ov5693_parse_dt(struct i2c_client *client) | ||
1258 | { | ||
1259 | struct device_node *node = client->dev.of_node; | ||
1260 | struct camera_common_pdata *board_priv_pdata; | ||
1261 | const struct of_device_id *match; | ||
1262 | int gpio; | ||
1263 | int err; | ||
1264 | struct camera_common_pdata *ret = NULL; | ||
1265 | |||
1266 | if (!node) | ||
1267 | return NULL; | ||
1268 | |||
1269 | match = of_match_device(ov5693_of_match, &client->dev); | ||
1270 | if (!match) { | ||
1271 | dev_err(&client->dev, "Failed to find matching dt id\n"); | ||
1272 | return NULL; | ||
1273 | } | ||
1274 | |||
1275 | board_priv_pdata = devm_kzalloc(&client->dev, | ||
1276 | sizeof(*board_priv_pdata), GFP_KERNEL); | ||
1277 | if (!board_priv_pdata) | ||
1278 | return NULL; | ||
1279 | |||
1280 | err = camera_common_parse_clocks(client, board_priv_pdata); | ||
1281 | if (err) { | ||
1282 | dev_err(&client->dev, "Failed to find clocks\n"); | ||
1283 | goto error; | ||
1284 | } | ||
1285 | |||
1286 | gpio = of_get_named_gpio(node, "pwdn-gpios", 0); | ||
1287 | if (gpio < 0) { | ||
1288 | if (gpio == -EPROBE_DEFER) { | ||
1289 | ret = ERR_PTR(-EPROBE_DEFER); | ||
1290 | goto error; | ||
1291 | } | ||
1292 | dev_err(&client->dev, "pwdn gpios not in DT\n"); | ||
1293 | goto error; | ||
1294 | } | ||
1295 | board_priv_pdata->pwdn_gpio = (unsigned int)gpio; | ||
1296 | |||
1297 | gpio = of_get_named_gpio(node, "reset-gpios", 0); | ||
1298 | if (gpio < 0) { | ||
1299 | /* reset-gpio is not absolutely needed */ | ||
1300 | if (gpio == -EPROBE_DEFER) { | ||
1301 | ret = ERR_PTR(-EPROBE_DEFER); | ||
1302 | goto error; | ||
1303 | } | ||
1304 | dev_dbg(&client->dev, "reset gpios not in DT\n"); | ||
1305 | gpio = 0; | ||
1306 | } | ||
1307 | board_priv_pdata->reset_gpio = (unsigned int)gpio; | ||
1308 | |||
1309 | board_priv_pdata->use_cam_gpio = | ||
1310 | of_property_read_bool(node, "cam,use-cam-gpio"); | ||
1311 | |||
1312 | err = of_property_read_string(node, "avdd-reg", | ||
1313 | &board_priv_pdata->regulators.avdd); | ||
1314 | if (err) { | ||
1315 | dev_err(&client->dev, "avdd-reg not in DT\n"); | ||
1316 | goto error; | ||
1317 | } | ||
1318 | err = of_property_read_string(node, "iovdd-reg", | ||
1319 | &board_priv_pdata->regulators.iovdd); | ||
1320 | if (err) { | ||
1321 | dev_err(&client->dev, "iovdd-reg not in DT\n"); | ||
1322 | goto error; | ||
1323 | } | ||
1324 | |||
1325 | board_priv_pdata->has_eeprom = | ||
1326 | of_property_read_bool(node, "has-eeprom"); | ||
1327 | |||
1328 | return board_priv_pdata; | ||
1329 | |||
1330 | error: | ||
1331 | devm_kfree(&client->dev, board_priv_pdata); | ||
1332 | return ret; | ||
1333 | } | ||
1334 | |||
1335 | static int ov5693_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
1336 | { | ||
1337 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1338 | |||
1339 | dev_dbg(&client->dev, "%s:\n", __func__); | ||
1340 | return 0; | ||
1341 | } | ||
1342 | |||
1343 | static const struct v4l2_subdev_internal_ops ov5693_subdev_internal_ops = { | ||
1344 | .open = ov5693_open, | ||
1345 | }; | ||
1346 | |||
1347 | static const struct media_entity_operations ov5693_media_ops = { | ||
1348 | .link_validate = v4l2_subdev_link_validate, | ||
1349 | }; | ||
1350 | |||
1351 | static int ov5693_probe(struct i2c_client *client, | ||
1352 | const struct i2c_device_id *id) | ||
1353 | { | ||
1354 | struct camera_common_data *common_data; | ||
1355 | struct device_node *node = client->dev.of_node; | ||
1356 | struct ov5693 *priv; | ||
1357 | char debugfs_name[10]; | ||
1358 | int err; | ||
1359 | |||
1360 | pr_info("[OV5693]: probing v4l2 sensor.\n"); | ||
1361 | |||
1362 | if (!IS_ENABLED(CONFIG_OF) || !node) | ||
1363 | return -EINVAL; | ||
1364 | |||
1365 | common_data = devm_kzalloc(&client->dev, | ||
1366 | sizeof(struct camera_common_data), GFP_KERNEL); | ||
1367 | if (!common_data) | ||
1368 | return -ENOMEM; | ||
1369 | |||
1370 | priv = devm_kzalloc(&client->dev, | ||
1371 | sizeof(struct ov5693) + sizeof(struct v4l2_ctrl *) * | ||
1372 | ARRAY_SIZE(ctrl_config_list), | ||
1373 | GFP_KERNEL); | ||
1374 | if (!priv) | ||
1375 | return -ENOMEM; | ||
1376 | |||
1377 | priv->regmap = devm_regmap_init_i2c(client, &ov5693_regmap_config); | ||
1378 | if (IS_ERR(priv->regmap)) { | ||
1379 | dev_err(&client->dev, | ||
1380 | "regmap init failed: %ld\n", PTR_ERR(priv->regmap)); | ||
1381 | return -ENODEV; | ||
1382 | } | ||
1383 | |||
1384 | priv->pdata = ov5693_parse_dt(client); | ||
1385 | if (PTR_ERR(priv->pdata) == -EPROBE_DEFER) | ||
1386 | return -EPROBE_DEFER; | ||
1387 | if (!priv->pdata) { | ||
1388 | dev_err(&client->dev, "unable to get platform data\n"); | ||
1389 | return -EFAULT; | ||
1390 | } | ||
1391 | |||
1392 | common_data->ops = &ov5693_common_ops; | ||
1393 | common_data->ctrl_handler = &priv->ctrl_handler; | ||
1394 | common_data->i2c_client = client; | ||
1395 | common_data->frmfmt = ov5693_frmfmt; | ||
1396 | common_data->colorfmt = camera_common_find_datafmt( | ||
1397 | OV5693_DEFAULT_DATAFMT); | ||
1398 | common_data->power = &priv->power; | ||
1399 | common_data->ctrls = priv->ctrls; | ||
1400 | common_data->priv = (void *)priv; | ||
1401 | common_data->numctrls = ARRAY_SIZE(ctrl_config_list); | ||
1402 | common_data->numfmts = ARRAY_SIZE(ov5693_frmfmt); | ||
1403 | common_data->def_mode = OV5693_DEFAULT_MODE; | ||
1404 | common_data->def_width = OV5693_DEFAULT_WIDTH; | ||
1405 | common_data->def_height = OV5693_DEFAULT_HEIGHT; | ||
1406 | common_data->fmt_width = common_data->def_width; | ||
1407 | common_data->fmt_height = common_data->def_height; | ||
1408 | common_data->def_clk_freq = OV5693_DEFAULT_CLK_FREQ; | ||
1409 | |||
1410 | priv->i2c_client = client; | ||
1411 | priv->s_data = common_data; | ||
1412 | priv->subdev = &common_data->subdev; | ||
1413 | priv->subdev->dev = &client->dev; | ||
1414 | priv->s_data->dev = &client->dev; | ||
1415 | |||
1416 | err = ov5693_power_get(priv); | ||
1417 | if (err) | ||
1418 | return err; | ||
1419 | |||
1420 | err = camera_common_parse_ports(client, common_data); | ||
1421 | if (err) { | ||
1422 | dev_err(&client->dev, "Failed to find port info\n"); | ||
1423 | return err; | ||
1424 | } | ||
1425 | sprintf(debugfs_name, "ov5693_%c", common_data->csi_port + 'a'); | ||
1426 | dev_dbg(&client->dev, "%s: name %s\n", __func__, debugfs_name); | ||
1427 | camera_common_create_debugfs(common_data, debugfs_name); | ||
1428 | |||
1429 | v4l2_i2c_subdev_init(priv->subdev, client, &ov5693_subdev_ops); | ||
1430 | |||
1431 | /* eeprom interface */ | ||
1432 | err = ov5693_eeprom_device_init(priv); | ||
1433 | if (err && priv->pdata->has_eeprom) | ||
1434 | dev_err(&client->dev, | ||
1435 | "Failed to allocate eeprom reg map: %d\n", err); | ||
1436 | |||
1437 | err = ov5693_ctrls_init(priv, !err); | ||
1438 | if (err) | ||
1439 | return err; | ||
1440 | |||
1441 | priv->subdev->internal_ops = &ov5693_subdev_internal_ops; | ||
1442 | priv->subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | | ||
1443 | V4L2_SUBDEV_FL_HAS_EVENTS; | ||
1444 | |||
1445 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
1446 | priv->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
1447 | priv->subdev->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; | ||
1448 | priv->subdev->entity.ops = &ov5693_media_ops; | ||
1449 | err = media_entity_init(&priv->subdev->entity, 1, &priv->pad, 0); | ||
1450 | if (err < 0) { | ||
1451 | dev_err(&client->dev, "unable to init media entity\n"); | ||
1452 | return err; | ||
1453 | } | ||
1454 | #endif | ||
1455 | |||
1456 | err = v4l2_async_register_subdev(priv->subdev); | ||
1457 | if (err) | ||
1458 | return err; | ||
1459 | |||
1460 | dev_dbg(&client->dev, "Detected OV5693 sensor\n"); | ||
1461 | |||
1462 | |||
1463 | return 0; | ||
1464 | } | ||
1465 | |||
1466 | static int | ||
1467 | ov5693_remove(struct i2c_client *client) | ||
1468 | { | ||
1469 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
1470 | struct ov5693 *priv = (struct ov5693 *)s_data->priv; | ||
1471 | |||
1472 | v4l2_async_unregister_subdev(priv->subdev); | ||
1473 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
1474 | media_entity_cleanup(&priv->subdev->entity); | ||
1475 | #endif | ||
1476 | |||
1477 | v4l2_ctrl_handler_free(&priv->ctrl_handler); | ||
1478 | ov5693_power_put(priv); | ||
1479 | camera_common_remove_debugfs(s_data); | ||
1480 | |||
1481 | return 0; | ||
1482 | } | ||
1483 | |||
1484 | static const struct i2c_device_id ov5693_id[] = { | ||
1485 | { "ov5693", 0 }, | ||
1486 | { } | ||
1487 | }; | ||
1488 | |||
1489 | MODULE_DEVICE_TABLE(i2c, ov5693_id); | ||
1490 | |||
1491 | static struct i2c_driver ov5693_i2c_driver = { | ||
1492 | .driver = { | ||
1493 | .name = "ov5693", | ||
1494 | .owner = THIS_MODULE, | ||
1495 | .of_match_table = of_match_ptr(ov5693_of_match), | ||
1496 | }, | ||
1497 | .probe = ov5693_probe, | ||
1498 | .remove = ov5693_remove, | ||
1499 | .id_table = ov5693_id, | ||
1500 | }; | ||
1501 | |||
1502 | module_i2c_driver(ov5693_i2c_driver); | ||
1503 | |||
1504 | MODULE_DESCRIPTION("SoC Camera driver for Sony OV5693"); | ||
1505 | MODULE_AUTHOR("David Wang <davidw@nvidia.com>"); | ||
1506 | MODULE_LICENSE("GPL v2"); | ||
1507 | |||
diff --git a/drivers/media/i2c/ov5693_mode_tbls.h b/drivers/media/i2c/ov5693_mode_tbls.h new file mode 100644 index 000000000..1639a366e --- /dev/null +++ b/drivers/media/i2c/ov5693_mode_tbls.h | |||
@@ -0,0 +1,2135 @@ | |||
1 | /* | ||
2 | * ov5693_mode_tbls.h - ov5693 sensor mode tables | ||
3 | * | ||
4 | * Copyright (c) 2015-2017, NVIDIA CORPORATION, All Rights Reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #ifndef __OV5693_TABLES__ | ||
20 | #define __OV5693_TABLES__ | ||
21 | |||
22 | #include <media/camera_common.h> | ||
23 | |||
24 | #define OV5693_TABLE_WAIT_MS 0 | ||
25 | #define OV5693_TABLE_END 1 | ||
26 | #define OV5693_MAX_RETRIES 3 | ||
27 | #define OV5693_WAIT_MS 10 | ||
28 | |||
29 | #define ov5693_reg struct reg_8 | ||
30 | |||
31 | static const ov5693_reg ov5693_start[] = { | ||
32 | {0x0100, 0x01}, /* mode select streaming on */ | ||
33 | {OV5693_TABLE_END, 0x00} | ||
34 | }; | ||
35 | |||
36 | static const ov5693_reg ov5693_stop[] = { | ||
37 | {0x0100, 0x00}, /* mode select streaming on */ | ||
38 | {OV5693_TABLE_END, 0x00} | ||
39 | }; | ||
40 | |||
41 | static const ov5693_reg tp_colorbars[] = { | ||
42 | {0x0600, 0x00}, | ||
43 | {0x0601, 0x02}, | ||
44 | |||
45 | {OV5693_TABLE_WAIT_MS, OV5693_WAIT_MS}, | ||
46 | {OV5693_TABLE_END, 0x00} | ||
47 | }; | ||
48 | |||
49 | static const ov5693_reg mode_2592x1944[] = { | ||
50 | {OV5693_TABLE_WAIT_MS, OV5693_WAIT_MS}, | ||
51 | {0x0100, 0x00},/* Including sw reset */ | ||
52 | {0x3001, 0x0a}, | ||
53 | {0x3002, 0x80}, | ||
54 | {0x3006, 0x00}, | ||
55 | {0x3011, 0x21}, | ||
56 | {0x3012, 0x09}, | ||
57 | {0x3013, 0x10}, | ||
58 | {0x3014, 0x00}, | ||
59 | {0x3015, 0x08}, | ||
60 | {0x3016, 0xf0}, | ||
61 | {0x3017, 0xf0}, | ||
62 | {0x3018, 0xf0}, | ||
63 | {0x301b, 0xb4}, | ||
64 | {0x301d, 0x02}, | ||
65 | {0x3021, 0x00}, | ||
66 | {0x3022, 0x01}, | ||
67 | {0x3028, 0x44}, | ||
68 | {0x3090, 0x02}, | ||
69 | {0x3091, 0x0e}, | ||
70 | {0x3092, 0x00}, | ||
71 | {0x3093, 0x00}, | ||
72 | {0x3098, 0x03}, | ||
73 | {0x3099, 0x1e}, | ||
74 | {0x309a, 0x02}, | ||
75 | {0x309b, 0x01}, | ||
76 | {0x309c, 0x00}, | ||
77 | {0x30a0, 0xd2}, | ||
78 | {0x30a2, 0x01}, | ||
79 | {0x30b2, 0x00}, | ||
80 | {0x30b3, 0x68}, | ||
81 | {0x30b4, 0x03}, | ||
82 | {0x30b5, 0x04}, | ||
83 | {0x30b6, 0x01}, | ||
84 | {0x3104, 0x21}, | ||
85 | {0x3106, 0x00}, | ||
86 | {0x3406, 0x01}, | ||
87 | {0x3500, 0x00}, | ||
88 | {0x3501, 0x7b}, | ||
89 | {0x3502, 0x00}, | ||
90 | {0x3503, 0x07}, | ||
91 | {0x3504, 0x00}, | ||
92 | {0x3505, 0x00}, | ||
93 | {0x3506, 0x00}, | ||
94 | {0x3507, 0x02}, | ||
95 | {0x3508, 0x00}, | ||
96 | {0x3509, 0x10}, | ||
97 | {0x350a, 0x00}, | ||
98 | {0x350b, 0x40}, | ||
99 | {0x3601, 0x0a}, | ||
100 | {0x3602, 0x18}, | ||
101 | {0x3612, 0x80}, | ||
102 | {0x3620, 0x54}, | ||
103 | {0x3621, 0xc7}, | ||
104 | {0x3622, 0x0f}, | ||
105 | {0x3625, 0x10}, | ||
106 | {0x3630, 0x55}, | ||
107 | {0x3631, 0xf4}, | ||
108 | {0x3632, 0x00}, | ||
109 | {0x3633, 0x34}, | ||
110 | {0x3634, 0x02}, | ||
111 | {0x364d, 0x0d}, | ||
112 | {0x364f, 0xdd}, | ||
113 | {0x3660, 0x04}, | ||
114 | {0x3662, 0x10}, | ||
115 | {0x3663, 0xf1}, | ||
116 | {0x3665, 0x00}, | ||
117 | {0x3666, 0x20}, | ||
118 | {0x3667, 0x00}, | ||
119 | {0x366a, 0x80}, | ||
120 | {0x3680, 0xe0}, | ||
121 | {0x3681, 0x00}, | ||
122 | {0x3700, 0x42}, | ||
123 | {0x3701, 0x14}, | ||
124 | {0x3702, 0xa0}, | ||
125 | {0x3703, 0xd8}, | ||
126 | {0x3704, 0x78}, | ||
127 | {0x3705, 0x02}, | ||
128 | {0x3708, 0xe2}, | ||
129 | {0x3709, 0xc3}, | ||
130 | {0x370a, 0x00}, | ||
131 | {0x370b, 0x20}, | ||
132 | {0x370c, 0x0c}, | ||
133 | {0x370d, 0x11}, | ||
134 | {0x370e, 0x00}, | ||
135 | {0x370f, 0x40}, | ||
136 | {0x3710, 0x00}, | ||
137 | {0x371a, 0x1c}, | ||
138 | {0x371b, 0x05}, | ||
139 | {0x371c, 0x01}, | ||
140 | {0x371e, 0xa1}, | ||
141 | {0x371f, 0x0c}, | ||
142 | {0x3721, 0x00}, | ||
143 | {0x3724, 0x10}, | ||
144 | {0x3726, 0x00}, | ||
145 | {0x372a, 0x01}, | ||
146 | {0x3730, 0x10}, | ||
147 | {0x3738, 0x22}, | ||
148 | {0x3739, 0xe5}, | ||
149 | {0x373a, 0x50}, | ||
150 | {0x373b, 0x02}, | ||
151 | {0x373c, 0x41}, | ||
152 | {0x373f, 0x02}, | ||
153 | {0x3740, 0x42}, | ||
154 | {0x3741, 0x02}, | ||
155 | {0x3742, 0x18}, | ||
156 | {0x3743, 0x01}, | ||
157 | {0x3744, 0x02}, | ||
158 | {0x3747, 0x10}, | ||
159 | {0x374c, 0x04}, | ||
160 | {0x3751, 0xf0}, | ||
161 | {0x3752, 0x00}, | ||
162 | {0x3753, 0x00}, | ||
163 | {0x3754, 0xc0}, | ||
164 | {0x3755, 0x00}, | ||
165 | {0x3756, 0x1a}, | ||
166 | {0x3758, 0x00}, | ||
167 | {0x3759, 0x0f}, | ||
168 | {0x376b, 0x44}, | ||
169 | {0x375c, 0x04}, | ||
170 | {0x3776, 0x00}, | ||
171 | {0x377f, 0x08}, | ||
172 | {0x3780, 0x22}, | ||
173 | {0x3781, 0x0c}, | ||
174 | {0x3784, 0x2c}, | ||
175 | {0x3785, 0x1e}, | ||
176 | {0x378f, 0xf5}, | ||
177 | {0x3791, 0xb0}, | ||
178 | {0x3795, 0x00}, | ||
179 | {0x3796, 0x64}, | ||
180 | {0x3797, 0x11}, | ||
181 | {0x3798, 0x30}, | ||
182 | {0x3799, 0x41}, | ||
183 | {0x379a, 0x07}, | ||
184 | {0x379b, 0xb0}, | ||
185 | {0x379c, 0x0c}, | ||
186 | {0x37c5, 0x00}, | ||
187 | {0x37c6, 0x00}, | ||
188 | {0x37c7, 0x00}, | ||
189 | {0x37c9, 0x00}, | ||
190 | {0x37ca, 0x00}, | ||
191 | {0x37cb, 0x00}, | ||
192 | {0x37de, 0x00}, | ||
193 | {0x37df, 0x00}, | ||
194 | {0x3800, 0x00}, | ||
195 | {0x3801, 0x02}, | ||
196 | {0x3802, 0x00}, | ||
197 | {0x3803, 0x02}, | ||
198 | {0x3804, 0x0a}, | ||
199 | {0x3805, 0x41}, | ||
200 | {0x3806, 0x07}, | ||
201 | {0x3807, 0xa5}, | ||
202 | {0x3808, 0x0a}, | ||
203 | {0x3809, 0x20}, | ||
204 | {0x380a, 0x07}, | ||
205 | {0x380b, 0x98}, | ||
206 | {0x380c, 0x0a}, | ||
207 | {0x380d, 0x80}, | ||
208 | {0x380e, 0x07}, | ||
209 | {0x380f, 0xc0}, | ||
210 | {0x3810, 0x00}, | ||
211 | {0x3811, 0x02}, | ||
212 | {0x3812, 0x00}, | ||
213 | {0x3813, 0x02}, | ||
214 | {0x3814, 0x11}, | ||
215 | {0x3815, 0x11}, | ||
216 | {0x3820, 0x00}, | ||
217 | {0x3821, 0x1e}, | ||
218 | {0x3823, 0x00}, | ||
219 | {0x3824, 0x00}, | ||
220 | {0x3825, 0x00}, | ||
221 | {0x3826, 0x00}, | ||
222 | {0x3827, 0x00}, | ||
223 | {0x382a, 0x04}, | ||
224 | {0x3a04, 0x06}, | ||
225 | {0x3a05, 0x14}, | ||
226 | {0x3a06, 0x00}, | ||
227 | {0x3a07, 0xfe}, | ||
228 | {0x3b00, 0x00}, | ||
229 | {0x3b02, 0x00}, | ||
230 | {0x3b03, 0x00}, | ||
231 | {0x3b04, 0x00}, | ||
232 | {0x3b05, 0x00}, | ||
233 | {0x3d00, 0x00}, | ||
234 | {0x3d01, 0x00}, | ||
235 | {0x3d02, 0x00}, | ||
236 | {0x3d03, 0x00}, | ||
237 | {0x3d04, 0x00}, | ||
238 | {0x3d05, 0x00}, | ||
239 | {0x3d06, 0x00}, | ||
240 | {0x3d07, 0x00}, | ||
241 | {0x3d08, 0x00}, | ||
242 | {0x3d09, 0x00}, | ||
243 | {0x3d0a, 0x00}, | ||
244 | {0x3d0b, 0x00}, | ||
245 | {0x3d0c, 0x00}, | ||
246 | {0x3d0d, 0x00}, | ||
247 | {0x3d0e, 0x00}, | ||
248 | {0x3d0f, 0x00}, | ||
249 | {0x3d80, 0x00}, | ||
250 | {0x3d81, 0x00}, | ||
251 | {0x3d84, 0x00}, | ||
252 | {0x3e07, 0x20}, | ||
253 | {0x4000, 0x08}, | ||
254 | {0x4001, 0x04}, | ||
255 | {0x4002, 0x45}, | ||
256 | {0x4004, 0x08}, | ||
257 | {0x4005, 0x18}, | ||
258 | {0x4006, 0x20}, | ||
259 | {0x4008, 0x24}, | ||
260 | {0x4009, 0x10}, | ||
261 | {0x400c, 0x00}, | ||
262 | {0x400d, 0x00}, | ||
263 | {0x4058, 0x00}, | ||
264 | {0x4101, 0xb2}, | ||
265 | {0x4303, 0x00}, | ||
266 | {0x4304, 0x08}, | ||
267 | {0x4307, 0x30}, | ||
268 | {0x4311, 0x04}, | ||
269 | {0x4315, 0x01}, | ||
270 | {0x4511, 0x05}, | ||
271 | {0x4512, 0x01}, | ||
272 | {0x4800, 0x20}, /* dis-continuous */ | ||
273 | {0x4806, 0x00}, | ||
274 | {0x4816, 0x52}, | ||
275 | {0x481f, 0x30}, | ||
276 | {0x4826, 0x32}, | ||
277 | {0x4831, 0x6a}, | ||
278 | {0x4d00, 0x04}, | ||
279 | {0x4d01, 0x71}, | ||
280 | {0x4d02, 0xfd}, | ||
281 | {0x4d03, 0xf5}, | ||
282 | {0x4d04, 0x0c}, | ||
283 | {0x4d05, 0xcc}, | ||
284 | {0x4837, 0x0a}, | ||
285 | {0x5000, 0x06}, | ||
286 | {0x5001, 0x01}, | ||
287 | {0x5002, 0x00}, | ||
288 | {0x5003, 0x20}, | ||
289 | {0x5046, 0x0a}, | ||
290 | {0x5013, 0x00}, | ||
291 | {0x5046, 0x0a}, | ||
292 | {0x5780, 0x1c}, | ||
293 | {0x5786, 0x20}, | ||
294 | {0x5787, 0x10}, | ||
295 | {0x5788, 0x18}, | ||
296 | {0x578a, 0x04}, | ||
297 | {0x578b, 0x02}, | ||
298 | {0x578c, 0x02}, | ||
299 | {0x578e, 0x06}, | ||
300 | {0x578f, 0x02}, | ||
301 | {0x5790, 0x02}, | ||
302 | {0x5791, 0xff}, | ||
303 | {0x5842, 0x01}, | ||
304 | {0x5843, 0x2b}, | ||
305 | {0x5844, 0x01}, | ||
306 | {0x5845, 0x92}, | ||
307 | {0x5846, 0x01}, | ||
308 | {0x5847, 0x8f}, | ||
309 | {0x5848, 0x01}, | ||
310 | {0x5849, 0x0c}, | ||
311 | {0x5e00, 0x00}, | ||
312 | {0x5e10, 0x0c}, | ||
313 | {OV5693_TABLE_END, 0x0000} | ||
314 | }; | ||
315 | |||
316 | static const ov5693_reg mode_2592x1458[] = { | ||
317 | {OV5693_TABLE_WAIT_MS, OV5693_WAIT_MS}, | ||
318 | {0x0100, 0x00},/* Including sw reset */ | ||
319 | {0x3001, 0x0a}, | ||
320 | {0x3002, 0x80}, | ||
321 | {0x3006, 0x00}, | ||
322 | {0x3011, 0x21}, | ||
323 | {0x3012, 0x09}, | ||
324 | {0x3013, 0x10}, | ||
325 | {0x3014, 0x00}, | ||
326 | {0x3015, 0x08}, | ||
327 | {0x3016, 0xf0}, | ||
328 | {0x3017, 0xf0}, | ||
329 | {0x3018, 0xf0}, | ||
330 | {0x301b, 0xb4}, | ||
331 | {0x301d, 0x02}, | ||
332 | {0x3021, 0x00}, | ||
333 | {0x3022, 0x01}, | ||
334 | {0x3028, 0x44}, | ||
335 | {0x3098, 0x03}, | ||
336 | {0x3099, 0x1e}, | ||
337 | {0x309a, 0x02}, | ||
338 | {0x309b, 0x01}, | ||
339 | {0x309c, 0x00}, | ||
340 | {0x30a0, 0xd2}, | ||
341 | {0x30a2, 0x01}, | ||
342 | {0x30b2, 0x00}, | ||
343 | {0x30b3, 0x68}, | ||
344 | {0x30b4, 0x03}, | ||
345 | {0x30b5, 0x04}, | ||
346 | {0x30b6, 0x01}, | ||
347 | {0x3104, 0x21}, | ||
348 | {0x3106, 0x00}, | ||
349 | {0x3400, 0x04}, | ||
350 | {0x3401, 0x00}, | ||
351 | {0x3402, 0x04}, | ||
352 | {0x3403, 0x00}, | ||
353 | {0x3404, 0x04}, | ||
354 | {0x3405, 0x00}, | ||
355 | {0x3406, 0x01}, | ||
356 | {0x3500, 0x00}, | ||
357 | {0x3501, 0x7b}, | ||
358 | {0x3502, 0x00}, | ||
359 | {0x3503, 0x07}, | ||
360 | {0x3504, 0x00}, | ||
361 | {0x3505, 0x00}, | ||
362 | {0x3506, 0x00}, | ||
363 | {0x3507, 0x02}, | ||
364 | {0x3508, 0x00}, | ||
365 | {0x3509, 0x10}, | ||
366 | {0x350a, 0x00}, | ||
367 | {0x350b, 0x40}, | ||
368 | {0x3600, 0xbc}, | ||
369 | {0x3601, 0x0a}, | ||
370 | {0x3602, 0x38}, | ||
371 | {0x3612, 0x80}, | ||
372 | {0x3620, 0x44}, | ||
373 | {0x3621, 0xb5}, | ||
374 | {0x3622, 0x0c}, | ||
375 | {0x3625, 0x10}, | ||
376 | {0x3630, 0x55}, | ||
377 | {0x3631, 0xf4}, | ||
378 | {0x3632, 0x00}, | ||
379 | {0x3633, 0x34}, | ||
380 | {0x3634, 0x02}, | ||
381 | {0x364d, 0x0d}, | ||
382 | {0x364f, 0xdd}, | ||
383 | {0x3660, 0x04}, | ||
384 | {0x3662, 0x10}, | ||
385 | {0x3663, 0xf1}, | ||
386 | {0x3665, 0x00}, | ||
387 | {0x3666, 0x20}, | ||
388 | {0x3667, 0x00}, | ||
389 | {0x366a, 0x80}, | ||
390 | {0x3680, 0xe0}, | ||
391 | {0x3681, 0x00}, | ||
392 | {0x3700, 0x42}, | ||
393 | {0x3701, 0x14}, | ||
394 | {0x3702, 0xa0}, | ||
395 | {0x3703, 0xd8}, | ||
396 | {0x3704, 0x78}, | ||
397 | {0x3705, 0x02}, | ||
398 | {0x3708, 0xe2}, | ||
399 | {0x3709, 0xc3}, | ||
400 | {0x370a, 0x00}, | ||
401 | {0x370b, 0x20}, | ||
402 | {0x370c, 0x0c}, | ||
403 | {0x370d, 0x11}, | ||
404 | {0x370e, 0x00}, | ||
405 | {0x370f, 0x40}, | ||
406 | {0x3710, 0x00}, | ||
407 | {0x371a, 0x1c}, | ||
408 | {0x371b, 0x05}, | ||
409 | {0x371c, 0x01}, | ||
410 | {0x371e, 0xa1}, | ||
411 | {0x371f, 0x0c}, | ||
412 | {0x3721, 0x00}, | ||
413 | {0x3724, 0x10}, | ||
414 | {0x3726, 0x00}, | ||
415 | {0x372a, 0x01}, | ||
416 | {0x3730, 0x10}, | ||
417 | {0x3738, 0x22}, | ||
418 | {0x3739, 0xe5}, | ||
419 | {0x373a, 0x50}, | ||
420 | {0x373b, 0x02}, | ||
421 | {0x373c, 0x41}, | ||
422 | {0x373f, 0x02}, | ||
423 | {0x3740, 0x42}, | ||
424 | {0x3741, 0x02}, | ||
425 | {0x3742, 0x18}, | ||
426 | {0x3743, 0x01}, | ||
427 | {0x3744, 0x02}, | ||
428 | {0x3747, 0x10}, | ||
429 | {0x374c, 0x04}, | ||
430 | {0x3751, 0xf0}, | ||
431 | {0x3752, 0x00}, | ||
432 | {0x3753, 0x00}, | ||
433 | {0x3754, 0xc0}, | ||
434 | {0x3755, 0x00}, | ||
435 | {0x3756, 0x1a}, | ||
436 | {0x3758, 0x00}, | ||
437 | {0x3759, 0x0f}, | ||
438 | {0x376b, 0x44}, | ||
439 | {0x375c, 0x04}, | ||
440 | {0x3774, 0x10}, | ||
441 | {0x3776, 0x00}, | ||
442 | {0x377f, 0x08}, | ||
443 | {0x3780, 0x22}, | ||
444 | {0x3781, 0x0c}, | ||
445 | {0x3784, 0x2c}, | ||
446 | {0x3785, 0x1e}, | ||
447 | {0x378f, 0xf5}, | ||
448 | {0x3791, 0xb0}, | ||
449 | {0x3795, 0x00}, | ||
450 | {0x3796, 0x64}, | ||
451 | {0x3797, 0x11}, | ||
452 | {0x3798, 0x30}, | ||
453 | {0x3799, 0x41}, | ||
454 | {0x379a, 0x07}, | ||
455 | {0x379b, 0xb0}, | ||
456 | {0x379c, 0x0c}, | ||
457 | {0x37c5, 0x00}, | ||
458 | {0x37c6, 0x00}, | ||
459 | {0x37c7, 0x00}, | ||
460 | {0x37c9, 0x00}, | ||
461 | {0x37ca, 0x00}, | ||
462 | {0x37cb, 0x00}, | ||
463 | {0x37de, 0x00}, | ||
464 | {0x37df, 0x00}, | ||
465 | {0x3800, 0x00}, | ||
466 | {0x3801, 0x00}, | ||
467 | {0x3802, 0x00}, | ||
468 | {0x3803, 0xf4}, | ||
469 | {0x3804, 0x0a}, | ||
470 | {0x3805, 0x3f}, | ||
471 | {0x3806, 0x06}, | ||
472 | {0x3807, 0xb1}, | ||
473 | {0x3808, 0x0a}, | ||
474 | {0x3809, 0x20}, | ||
475 | {0x380a, 0x05}, | ||
476 | {0x380b, 0xb2}, | ||
477 | {0x380c, 0x0a}, | ||
478 | {0x380d, 0x80}, | ||
479 | {0x380e, 0x07}, | ||
480 | {0x380f, 0xc0}, | ||
481 | {0x3810, 0x00}, | ||
482 | {0x3811, 0x10}, | ||
483 | {0x3812, 0x00}, | ||
484 | {0x3813, 0x06}, | ||
485 | {0x3814, 0x11}, | ||
486 | {0x3815, 0x11}, | ||
487 | {0x3820, 0x00}, | ||
488 | {0x3821, 0x1e}, | ||
489 | {0x3823, 0x00}, | ||
490 | {0x3824, 0x00}, | ||
491 | {0x3825, 0x00}, | ||
492 | {0x3826, 0x00}, | ||
493 | {0x3827, 0x00}, | ||
494 | {0x382a, 0x04}, | ||
495 | {0x3a04, 0x06}, | ||
496 | {0x3a05, 0x14}, | ||
497 | {0x3a06, 0x00}, | ||
498 | {0x3a07, 0xfe}, | ||
499 | {0x3b00, 0x00}, | ||
500 | {0x3b02, 0x00}, | ||
501 | {0x3b03, 0x00}, | ||
502 | {0x3b04, 0x00}, | ||
503 | {0x3b05, 0x00}, | ||
504 | {0x3e07, 0x20}, | ||
505 | {0x4000, 0x08}, | ||
506 | {0x4001, 0x04}, | ||
507 | {0x4002, 0x45}, | ||
508 | {0x4004, 0x08}, | ||
509 | {0x4005, 0x18}, | ||
510 | {0x4006, 0x20}, | ||
511 | {0x4008, 0x24}, | ||
512 | {0x4009, 0x10}, | ||
513 | {0x400c, 0x00}, | ||
514 | {0x400d, 0x00}, | ||
515 | {0x4058, 0x00}, | ||
516 | {0x404e, 0x37}, | ||
517 | {0x404f, 0x8f}, | ||
518 | {0x4058, 0x00}, | ||
519 | {0x4101, 0xb2}, | ||
520 | {0x4303, 0x00}, | ||
521 | {0x4304, 0x08}, | ||
522 | {0x4307, 0x30}, | ||
523 | {0x4311, 0x04}, | ||
524 | {0x4315, 0x01}, | ||
525 | {0x4511, 0x05}, | ||
526 | {0x4512, 0x01}, | ||
527 | {0x4800, 0x20}, /* dis-continuous */ | ||
528 | {0x4806, 0x00}, | ||
529 | {0x4816, 0x52}, | ||
530 | {0x481f, 0x30}, | ||
531 | {0x4826, 0x32}, | ||
532 | {0x4831, 0x6a}, | ||
533 | {0x4d00, 0x04}, | ||
534 | {0x4d01, 0x71}, | ||
535 | {0x4d02, 0xfd}, | ||
536 | {0x4d03, 0xf5}, | ||
537 | {0x4d04, 0x0c}, | ||
538 | {0x4d05, 0xcc}, | ||
539 | {0x4837, 0x0a}, | ||
540 | {0x5000, 0x06}, | ||
541 | {0x5001, 0x01}, | ||
542 | {0x5002, 0x00}, | ||
543 | {0x5003, 0x20}, | ||
544 | {0x5046, 0x0a}, | ||
545 | {0x5013, 0x00}, | ||
546 | {0x5046, 0x0a}, | ||
547 | {0x5780, 0xfc}, | ||
548 | {0x5781, 0x13}, | ||
549 | {0x5782, 0x03}, | ||
550 | {0x5786, 0x20}, | ||
551 | {0x5787, 0x40}, | ||
552 | {0x5788, 0x08}, | ||
553 | {0x5789, 0x08}, | ||
554 | {0x578a, 0x02}, | ||
555 | {0x578b, 0x01}, | ||
556 | {0x578c, 0x01}, | ||
557 | {0x578d, 0x0c}, | ||
558 | {0x578e, 0x02}, | ||
559 | {0x578f, 0x01}, | ||
560 | {0x5790, 0x01}, | ||
561 | {0x5791, 0xff}, | ||
562 | {0x5842, 0x01}, | ||
563 | {0x5843, 0x2b}, | ||
564 | {0x5844, 0x01}, | ||
565 | {0x5845, 0x92}, | ||
566 | {0x5846, 0x01}, | ||
567 | {0x5847, 0x8f}, | ||
568 | {0x5848, 0x01}, | ||
569 | {0x5849, 0x0c}, | ||
570 | {0x5e00, 0x00}, | ||
571 | {0x5e10, 0x0c}, | ||
572 | {OV5693_TABLE_END, 0x0000} | ||
573 | }; | ||
574 | |||
575 | static const ov5693_reg mode_1920x1080[] = { | ||
576 | {OV5693_TABLE_WAIT_MS, OV5693_WAIT_MS}, | ||
577 | {0x0100, 0x00},/*, 0xIncluding, 0xsw, 0xreset, 0x*/ | ||
578 | {0x3001, 0x0a}, | ||
579 | {0x3002, 0x80}, | ||
580 | {0x3006, 0x00}, | ||
581 | {0x3011, 0x21}, | ||
582 | {0x3012, 0x09}, | ||
583 | {0x3013, 0x10}, | ||
584 | {0x3014, 0x00}, | ||
585 | {0x3015, 0x08}, | ||
586 | {0x3016, 0xf0}, | ||
587 | {0x3017, 0xf0}, | ||
588 | {0x3018, 0xf0}, | ||
589 | {0x301b, 0xb4}, | ||
590 | {0x301d, 0x02}, | ||
591 | {0x3021, 0x00}, | ||
592 | {0x3022, 0x01}, | ||
593 | {0x3028, 0x44}, | ||
594 | {0x3098, 0x03}, | ||
595 | {0x3099, 0x1e}, | ||
596 | {0x309a, 0x02}, | ||
597 | {0x309b, 0x01}, | ||
598 | {0x309c, 0x00}, | ||
599 | {0x30a0, 0xd2}, | ||
600 | {0x30a2, 0x01}, | ||
601 | {0x30b2, 0x00}, | ||
602 | {0x30b3, 0x68}, | ||
603 | {0x30b4, 0x03}, | ||
604 | {0x30b5, 0x04}, | ||
605 | {0x30b6, 0x01}, | ||
606 | {0x3104, 0x21}, | ||
607 | {0x3106, 0x00}, | ||
608 | {0x3406, 0x01}, | ||
609 | {0x3500, 0x00}, | ||
610 | {0x3501, 0x7b}, | ||
611 | {0x3502, 0x00}, | ||
612 | {0x3503, 0x07}, | ||
613 | {0x3504, 0x00}, | ||
614 | {0x3505, 0x00}, | ||
615 | {0x3506, 0x00}, | ||
616 | {0x3507, 0x02}, | ||
617 | {0x3508, 0x00}, | ||
618 | {0x3509, 0x10}, | ||
619 | {0x350a, 0x00}, | ||
620 | {0x350b, 0x40}, | ||
621 | {0x3601, 0x0a}, | ||
622 | {0x3602, 0x38}, | ||
623 | {0x3612, 0x80}, | ||
624 | {0x3620, 0x54}, | ||
625 | {0x3621, 0xc7}, | ||
626 | {0x3622, 0x0f}, | ||
627 | {0x3625, 0x10}, | ||
628 | {0x3630, 0x55}, | ||
629 | {0x3631, 0xf4}, | ||
630 | {0x3632, 0x00}, | ||
631 | {0x3633, 0x34}, | ||
632 | {0x3634, 0x02}, | ||
633 | {0x364d, 0x0d}, | ||
634 | {0x364f, 0xdd}, | ||
635 | {0x3660, 0x04}, | ||
636 | {0x3662, 0x10}, | ||
637 | {0x3663, 0xf1}, | ||
638 | {0x3665, 0x00}, | ||
639 | {0x3666, 0x20}, | ||
640 | {0x3667, 0x00}, | ||
641 | {0x366a, 0x80}, | ||
642 | {0x3680, 0xe0}, | ||
643 | {0x3681, 0x00}, | ||
644 | {0x3700, 0x42}, | ||
645 | {0x3701, 0x14}, | ||
646 | {0x3702, 0xa0}, | ||
647 | {0x3703, 0xd8}, | ||
648 | {0x3704, 0x78}, | ||
649 | {0x3705, 0x02}, | ||
650 | {0x3708, 0xe2}, | ||
651 | {0x3709, 0xc3}, | ||
652 | {0x370a, 0x00}, | ||
653 | {0x370b, 0x20}, | ||
654 | {0x370c, 0x0c}, | ||
655 | {0x370d, 0x11}, | ||
656 | {0x370e, 0x00}, | ||
657 | {0x370f, 0x40}, | ||
658 | {0x3710, 0x00}, | ||
659 | {0x371a, 0x1c}, | ||
660 | {0x371b, 0x05}, | ||
661 | {0x371c, 0x01}, | ||
662 | {0x371e, 0xa1}, | ||
663 | {0x371f, 0x0c}, | ||
664 | {0x3721, 0x00}, | ||
665 | {0x3724, 0x10}, | ||
666 | {0x3726, 0x00}, | ||
667 | {0x372a, 0x01}, | ||
668 | {0x3730, 0x10}, | ||
669 | {0x3738, 0x22}, | ||
670 | {0x3739, 0xe5}, | ||
671 | {0x373a, 0x50}, | ||
672 | {0x373b, 0x02}, | ||
673 | {0x373c, 0x41}, | ||
674 | {0x373f, 0x02}, | ||
675 | {0x3740, 0x42}, | ||
676 | {0x3741, 0x02}, | ||
677 | {0x3742, 0x18}, | ||
678 | {0x3743, 0x01}, | ||
679 | {0x3744, 0x02}, | ||
680 | {0x3747, 0x10}, | ||
681 | {0x374c, 0x04}, | ||
682 | {0x3751, 0xf0}, | ||
683 | {0x3752, 0x00}, | ||
684 | {0x3753, 0x00}, | ||
685 | {0x3754, 0xc0}, | ||
686 | {0x3755, 0x00}, | ||
687 | {0x3756, 0x1a}, | ||
688 | {0x3758, 0x00}, | ||
689 | {0x3759, 0x0f}, | ||
690 | {0x376b, 0x44}, | ||
691 | {0x375c, 0x04}, | ||
692 | {0x3774, 0x10}, | ||
693 | {0x3776, 0x00}, | ||
694 | {0x377f, 0x08}, | ||
695 | {0x3780, 0x22}, | ||
696 | {0x3781, 0x0c}, | ||
697 | {0x3784, 0x2c}, | ||
698 | {0x3785, 0x1e}, | ||
699 | {0x378f, 0xf5}, | ||
700 | {0x3791, 0xb0}, | ||
701 | {0x3795, 0x00}, | ||
702 | {0x3796, 0x64}, | ||
703 | {0x3797, 0x11}, | ||
704 | {0x3798, 0x30}, | ||
705 | {0x3799, 0x41}, | ||
706 | {0x379a, 0x07}, | ||
707 | {0x379b, 0xb0}, | ||
708 | {0x379c, 0x0c}, | ||
709 | {0x37c5, 0x00}, | ||
710 | {0x37c6, 0x00}, | ||
711 | {0x37c7, 0x00}, | ||
712 | {0x37c9, 0x00}, | ||
713 | {0x37ca, 0x00}, | ||
714 | {0x37cb, 0x00}, | ||
715 | {0x37de, 0x00}, | ||
716 | {0x37df, 0x00}, | ||
717 | {0x3800, 0x00}, | ||
718 | {0x3801, 0x00}, | ||
719 | {0x3802, 0x00}, | ||
720 | {0x3803, 0xf8}, | ||
721 | {0x3804, 0x0a}, | ||
722 | {0x3805, 0x3f}, | ||
723 | {0x3806, 0x06}, | ||
724 | {0x3807, 0xab}, | ||
725 | {0x3808, 0x07}, | ||
726 | {0x3809, 0x80}, | ||
727 | {0x380a, 0x04}, | ||
728 | {0x380b, 0x38}, | ||
729 | {0x380c, 0x0a}, | ||
730 | {0x380d, 0x80}, | ||
731 | {0x380e, 0x07}, | ||
732 | {0x380f, 0xc0}, | ||
733 | {0x3810, 0x00}, | ||
734 | {0x3811, 0x02}, | ||
735 | {0x3812, 0x00}, | ||
736 | {0x3813, 0x02}, | ||
737 | {0x3814, 0x11}, | ||
738 | {0x3815, 0x11}, | ||
739 | {0x3820, 0x00}, | ||
740 | {0x3821, 0x1e}, | ||
741 | {0x3823, 0x00}, | ||
742 | {0x3824, 0x00}, | ||
743 | {0x3825, 0x00}, | ||
744 | {0x3826, 0x00}, | ||
745 | {0x3827, 0x00}, | ||
746 | {0x382a, 0x04}, | ||
747 | {0x3a04, 0x06}, | ||
748 | {0x3a05, 0x14}, | ||
749 | {0x3a06, 0x00}, | ||
750 | {0x3a07, 0xfe}, | ||
751 | {0x3b00, 0x00}, | ||
752 | {0x3b02, 0x00}, | ||
753 | {0x3b03, 0x00}, | ||
754 | {0x3b04, 0x00}, | ||
755 | {0x3b05, 0x00}, | ||
756 | {0x3e07, 0x20}, | ||
757 | {0x4000, 0x08}, | ||
758 | {0x4001, 0x04}, | ||
759 | {0x4002, 0x45}, | ||
760 | {0x4004, 0x08}, | ||
761 | {0x4005, 0x18}, | ||
762 | {0x4006, 0x20}, | ||
763 | {0x4008, 0x24}, | ||
764 | {0x4009, 0x10}, | ||
765 | {0x400c, 0x00}, | ||
766 | {0x400d, 0x00}, | ||
767 | {0x4058, 0x00}, | ||
768 | {0x404e, 0x37}, | ||
769 | {0x404f, 0x8f}, | ||
770 | {0x4058, 0x00}, | ||
771 | {0x4101, 0xb2}, | ||
772 | {0x4303, 0x00}, | ||
773 | {0x4304, 0x08}, | ||
774 | {0x4307, 0x30}, | ||
775 | {0x4311, 0x04}, | ||
776 | {0x4315, 0x01}, | ||
777 | {0x4511, 0x05}, | ||
778 | {0x4512, 0x01}, | ||
779 | {0x4800, 0x20}, /* dis-continuous */ | ||
780 | {0x4806, 0x00}, | ||
781 | {0x4816, 0x52}, | ||
782 | {0x481f, 0x30}, | ||
783 | {0x4826, 0x32}, | ||
784 | {0x4831, 0x6a}, | ||
785 | {0x4d00, 0x04}, | ||
786 | {0x4d01, 0x71}, | ||
787 | {0x4d02, 0xfd}, | ||
788 | {0x4d03, 0xf5}, | ||
789 | {0x4d04, 0x0c}, | ||
790 | {0x4d05, 0xcc}, | ||
791 | {0x4837, 0x0a}, | ||
792 | {0x5000, 0x06}, | ||
793 | {0x5001, 0x01}, | ||
794 | {0x5002, 0x80}, | ||
795 | {0x5003, 0x20}, | ||
796 | {0x5046, 0x0a}, | ||
797 | {0x5013, 0x00}, | ||
798 | {0x5046, 0x0a}, | ||
799 | {0x5780, 0x1c}, | ||
800 | {0x5786, 0x20}, | ||
801 | {0x5787, 0x10}, | ||
802 | {0x5788, 0x18}, | ||
803 | {0x578a, 0x04}, | ||
804 | {0x578b, 0x02}, | ||
805 | {0x578c, 0x02}, | ||
806 | {0x578e, 0x06}, | ||
807 | {0x578f, 0x02}, | ||
808 | {0x5790, 0x02}, | ||
809 | {0x5791, 0xff}, | ||
810 | {0x5842, 0x01}, | ||
811 | {0x5843, 0x2b}, | ||
812 | {0x5844, 0x01}, | ||
813 | {0x5845, 0x92}, | ||
814 | {0x5846, 0x01}, | ||
815 | {0x5847, 0x8f}, | ||
816 | {0x5848, 0x01}, | ||
817 | {0x5849, 0x0c}, | ||
818 | {0x5e00, 0x00}, | ||
819 | {0x5e10, 0x0c}, | ||
820 | {OV5693_TABLE_END, 0x0000} | ||
821 | }; | ||
822 | |||
823 | static const ov5693_reg mode_1280x720_120fps[] = { | ||
824 | {OV5693_TABLE_WAIT_MS, OV5693_WAIT_MS}, | ||
825 | {0x0100, 0x00},/* Including sw reset */ | ||
826 | {0x3001, 0x0a}, | ||
827 | {0x3002, 0x80}, | ||
828 | {0x3006, 0x00}, | ||
829 | {0x3011, 0x21}, | ||
830 | {0x3012, 0x09}, | ||
831 | {0x3013, 0x10}, | ||
832 | {0x3014, 0x00}, | ||
833 | {0x3015, 0x08}, | ||
834 | {0x3016, 0xf0}, | ||
835 | {0x3017, 0xf0}, | ||
836 | {0x3018, 0xf0}, | ||
837 | {0x301b, 0xb4}, | ||
838 | {0x301d, 0x02}, | ||
839 | {0x3021, 0x00}, | ||
840 | {0x3022, 0x01}, | ||
841 | {0x3028, 0x44}, | ||
842 | {0x3098, 0x03}, | ||
843 | {0x3099, 0x1e}, | ||
844 | {0x309a, 0x02}, | ||
845 | {0x309b, 0x01}, | ||
846 | {0x309c, 0x00}, | ||
847 | {0x30a0, 0xd2}, | ||
848 | {0x30a2, 0x01}, | ||
849 | {0x30b2, 0x00}, | ||
850 | {0x30b3, 0x68}, | ||
851 | {0x30b4, 0x03}, | ||
852 | {0x30b5, 0x04}, | ||
853 | {0x30b6, 0x01}, | ||
854 | {0x3104, 0x21}, | ||
855 | {0x3106, 0x00}, | ||
856 | {0x3406, 0x01}, | ||
857 | {0x3500, 0x00}, | ||
858 | {0x3501, 0x2e}, | ||
859 | {0x3502, 0x80}, | ||
860 | {0x3503, 0x07}, | ||
861 | {0x3504, 0x00}, | ||
862 | {0x3505, 0x00}, | ||
863 | {0x3506, 0x00}, | ||
864 | {0x3507, 0x02}, | ||
865 | {0x3508, 0x00}, | ||
866 | {0x3509, 0x10}, | ||
867 | {0x350a, 0x00}, | ||
868 | {0x350b, 0x40}, | ||
869 | {0x3601, 0x0a}, | ||
870 | {0x3602, 0x38}, | ||
871 | {0x3612, 0x80}, | ||
872 | {0x3620, 0x54}, | ||
873 | {0x3621, 0xc7}, | ||
874 | {0x3622, 0x0f}, | ||
875 | {0x3625, 0x10}, | ||
876 | {0x3630, 0x55}, | ||
877 | {0x3631, 0xf4}, | ||
878 | {0x3632, 0x00}, | ||
879 | {0x3633, 0x34}, | ||
880 | {0x3634, 0x02}, | ||
881 | {0x364d, 0x0d}, | ||
882 | {0x364f, 0xdd}, | ||
883 | {0x3660, 0x04}, | ||
884 | {0x3662, 0x10}, | ||
885 | {0x3663, 0xf1}, | ||
886 | {0x3665, 0x00}, | ||
887 | {0x3666, 0x20}, | ||
888 | {0x3667, 0x00}, | ||
889 | {0x366a, 0x80}, | ||
890 | {0x3680, 0xe0}, | ||
891 | {0x3681, 0x00}, | ||
892 | {0x3700, 0x42}, | ||
893 | {0x3701, 0x14}, | ||
894 | {0x3702, 0xa0}, | ||
895 | {0x3703, 0xd8}, | ||
896 | {0x3704, 0x78}, | ||
897 | {0x3705, 0x02}, | ||
898 | {0x3708, 0xe6}, | ||
899 | {0x3709, 0xc7}, | ||
900 | {0x370a, 0x00}, | ||
901 | {0x370b, 0x20}, | ||
902 | {0x370c, 0x0c}, | ||
903 | {0x370d, 0x11}, | ||
904 | {0x370e, 0x00}, | ||
905 | {0x370f, 0x40}, | ||
906 | {0x3710, 0x00}, | ||
907 | {0x371a, 0x1c}, | ||
908 | {0x371b, 0x05}, | ||
909 | {0x371c, 0x01}, | ||
910 | {0x371e, 0xa1}, | ||
911 | {0x371f, 0x0c}, | ||
912 | {0x3721, 0x00}, | ||
913 | {0x3724, 0x10}, | ||
914 | {0x3726, 0x00}, | ||
915 | {0x372a, 0x01}, | ||
916 | {0x3730, 0x10}, | ||
917 | {0x3738, 0x22}, | ||
918 | {0x3739, 0xe5}, | ||
919 | {0x373a, 0x50}, | ||
920 | {0x373b, 0x02}, | ||
921 | {0x373c, 0x41}, | ||
922 | {0x373f, 0x02}, | ||
923 | {0x3740, 0x42}, | ||
924 | {0x3741, 0x02}, | ||
925 | {0x3742, 0x18}, | ||
926 | {0x3743, 0x01}, | ||
927 | {0x3744, 0x02}, | ||
928 | {0x3747, 0x10}, | ||
929 | {0x374c, 0x04}, | ||
930 | {0x3751, 0xf0}, | ||
931 | {0x3752, 0x00}, | ||
932 | {0x3753, 0x00}, | ||
933 | {0x3754, 0xc0}, | ||
934 | {0x3755, 0x00}, | ||
935 | {0x3756, 0x1a}, | ||
936 | {0x3758, 0x00}, | ||
937 | {0x3759, 0x0f}, | ||
938 | {0x376b, 0x44}, | ||
939 | {0x375c, 0x04}, | ||
940 | {0x3774, 0x10}, | ||
941 | {0x3776, 0x00}, | ||
942 | {0x377f, 0x08}, | ||
943 | {0x3780, 0x22}, | ||
944 | {0x3781, 0x0c}, | ||
945 | {0x3784, 0x2c}, | ||
946 | {0x3785, 0x1e}, | ||
947 | {0x378f, 0xf5}, | ||
948 | {0x3791, 0xb0}, | ||
949 | {0x3795, 0x00}, | ||
950 | {0x3796, 0x64}, | ||
951 | {0x3797, 0x11}, | ||
952 | {0x3798, 0x30}, | ||
953 | {0x3799, 0x41}, | ||
954 | {0x379a, 0x07}, | ||
955 | {0x379b, 0xb0}, | ||
956 | {0x379c, 0x0c}, | ||
957 | {0x37c5, 0x00}, | ||
958 | {0x37c6, 0x00}, | ||
959 | {0x37c7, 0x00}, | ||
960 | {0x37c9, 0x00}, | ||
961 | {0x37ca, 0x00}, | ||
962 | {0x37cb, 0x00}, | ||
963 | {0x37de, 0x00}, | ||
964 | {0x37df, 0x00}, | ||
965 | {0x3800, 0x00}, | ||
966 | {0x3801, 0x00}, | ||
967 | {0x3802, 0x00}, | ||
968 | {0x3803, 0xf4}, | ||
969 | {0x3804, 0x0a}, | ||
970 | {0x3805, 0x3f}, | ||
971 | {0x3806, 0x06}, | ||
972 | {0x3807, 0xab}, | ||
973 | {0x3808, 0x05}, | ||
974 | {0x3809, 0x00}, | ||
975 | {0x380a, 0x02}, | ||
976 | {0x380b, 0xd0}, | ||
977 | {0x380c, 0x06}, | ||
978 | {0x380d, 0xd8}, | ||
979 | {0x380e, 0x02}, | ||
980 | {0x380f, 0xf8}, | ||
981 | {0x3810, 0x00}, | ||
982 | {0x3811, 0x02}, | ||
983 | {0x3812, 0x00}, | ||
984 | {0x3813, 0x02}, | ||
985 | {0x3814, 0x31}, | ||
986 | {0x3815, 0x31}, | ||
987 | {0x3820, 0x04}, | ||
988 | {0x3821, 0x1f}, | ||
989 | {0x3823, 0x00}, | ||
990 | {0x3824, 0x00}, | ||
991 | {0x3825, 0x00}, | ||
992 | {0x3826, 0x00}, | ||
993 | {0x3827, 0x00}, | ||
994 | {0x382a, 0x04}, | ||
995 | {0x3a04, 0x06}, | ||
996 | {0x3a05, 0x14}, | ||
997 | {0x3a06, 0x00}, | ||
998 | {0x3a07, 0xfe}, | ||
999 | {0x3b00, 0x00}, | ||
1000 | {0x3b02, 0x00}, | ||
1001 | {0x3b03, 0x00}, | ||
1002 | {0x3b04, 0x00}, | ||
1003 | {0x3b05, 0x00}, | ||
1004 | {0x3e07, 0x20}, | ||
1005 | {0x4000, 0x08}, | ||
1006 | {0x4001, 0x04}, | ||
1007 | {0x4002, 0x45}, | ||
1008 | {0x4004, 0x08}, | ||
1009 | {0x4005, 0x18}, | ||
1010 | {0x4006, 0x20}, | ||
1011 | {0x4008, 0x24}, | ||
1012 | {0x4009, 0x10}, | ||
1013 | {0x400c, 0x00}, | ||
1014 | {0x400d, 0x00}, | ||
1015 | {0x4058, 0x00}, | ||
1016 | {0x404e, 0x37}, | ||
1017 | {0x404f, 0x8f}, | ||
1018 | {0x4058, 0x00}, | ||
1019 | {0x4101, 0xb2}, | ||
1020 | {0x4303, 0x00}, | ||
1021 | {0x4304, 0x08}, | ||
1022 | {0x4307, 0x30}, | ||
1023 | {0x4311, 0x04}, | ||
1024 | {0x4315, 0x01}, | ||
1025 | {0x4511, 0x05}, | ||
1026 | {0x4512, 0x00}, | ||
1027 | {0x4800, 0x20}, /* dis-continuous */ | ||
1028 | {0x4806, 0x00}, | ||
1029 | {0x4816, 0x52}, | ||
1030 | {0x481f, 0x30}, | ||
1031 | {0x4826, 0x32}, | ||
1032 | {0x4831, 0x6a}, | ||
1033 | {0x4d00, 0x04}, | ||
1034 | {0x4d01, 0x71}, | ||
1035 | {0x4d02, 0xfd}, | ||
1036 | {0x4d03, 0xf5}, | ||
1037 | {0x4d04, 0x0c}, | ||
1038 | {0x4d05, 0xcc}, | ||
1039 | {0x4837, 0x0a}, | ||
1040 | {0x5000, 0x06}, | ||
1041 | {0x5001, 0x01}, | ||
1042 | {0x5002, 0x00}, | ||
1043 | {0x5003, 0x20}, | ||
1044 | {0x5046, 0x0a}, | ||
1045 | {0x5013, 0x00}, | ||
1046 | {0x5046, 0x0a}, | ||
1047 | {0x5780, 0x1c}, | ||
1048 | {0x5786, 0x20}, | ||
1049 | {0x5787, 0x10}, | ||
1050 | {0x5788, 0x18}, | ||
1051 | {0x578a, 0x04}, | ||
1052 | {0x578b, 0x02}, | ||
1053 | {0x578c, 0x02}, | ||
1054 | {0x578e, 0x06}, | ||
1055 | {0x578f, 0x02}, | ||
1056 | {0x5790, 0x02}, | ||
1057 | {0x5791, 0xff}, | ||
1058 | {0x5842, 0x01}, | ||
1059 | {0x5843, 0x2b}, | ||
1060 | {0x5844, 0x01}, | ||
1061 | {0x5845, 0x92}, | ||
1062 | {0x5846, 0x01}, | ||
1063 | {0x5847, 0x8f}, | ||
1064 | {0x5848, 0x01}, | ||
1065 | {0x5849, 0x0c}, | ||
1066 | {0x5e00, 0x00}, | ||
1067 | {0x5e10, 0x0c}, | ||
1068 | {OV5693_TABLE_END, 0x0000} | ||
1069 | }; | ||
1070 | |||
1071 | static const ov5693_reg mode_2592x1944_HDR_24fps[] = { | ||
1072 | {OV5693_TABLE_WAIT_MS, OV5693_WAIT_MS}, | ||
1073 | {0x0100, 0x00},/* Including sw reset */ | ||
1074 | {0x0103, 0x01}, | ||
1075 | {0x3001, 0x0a}, | ||
1076 | {0x3002, 0x80}, | ||
1077 | {0x3006, 0x00}, | ||
1078 | {0x3011, 0x21}, | ||
1079 | {0x3012, 0x09}, | ||
1080 | {0x3013, 0x10}, | ||
1081 | {0x3014, 0x00}, | ||
1082 | {0x3015, 0x08}, | ||
1083 | {0x3016, 0xf0}, | ||
1084 | {0x3017, 0xf0}, | ||
1085 | {0x3018, 0xf0}, | ||
1086 | {0x301b, 0xb4}, | ||
1087 | {0x301d, 0x02}, | ||
1088 | {0x3021, 0x00}, | ||
1089 | {0x3022, 0x01}, | ||
1090 | {0x3028, 0x44}, | ||
1091 | {0x3098, 0x02}, | ||
1092 | {0x3099, 0x16}, | ||
1093 | {0x309a, 0x02}, | ||
1094 | {0x309b, 0x01}, | ||
1095 | {0x309c, 0x00}, | ||
1096 | {0x30b2, 0x00}, | ||
1097 | {0x30b3, 0x6e}, | ||
1098 | {0x30b4, 0x03}, | ||
1099 | {0x30a0, 0xd2}, | ||
1100 | {0x30a2, 0x01}, | ||
1101 | {0x30b5, 0x04}, | ||
1102 | {0x30b6, 0x01}, | ||
1103 | {0x3104, 0x21}, | ||
1104 | {0x3106, 0x00}, | ||
1105 | {0x3406, 0x01}, | ||
1106 | {0x3500, 0x00}, | ||
1107 | {0x3501, 0x7b}, | ||
1108 | {0x3502, 0x80}, | ||
1109 | {0x3503, 0x07}, | ||
1110 | {0x3504, 0x00}, | ||
1111 | {0x3505, 0x00}, | ||
1112 | {0x3506, 0x00}, | ||
1113 | {0x3507, 0x01}, | ||
1114 | {0x3508, 0x80}, | ||
1115 | {0x3509, 0x10}, | ||
1116 | {0x350a, 0x00}, | ||
1117 | {0x350b, 0x40}, | ||
1118 | {0x3601, 0x0a}, | ||
1119 | {0x3602, 0x38}, | ||
1120 | {0x3612, 0x80}, | ||
1121 | {0x3620, 0x54}, | ||
1122 | {0x3621, 0xc7}, | ||
1123 | {0x3622, 0x05}, | ||
1124 | {0x3625, 0x10}, | ||
1125 | {0x3630, 0x55}, | ||
1126 | {0x3631, 0xf4}, | ||
1127 | {0x3632, 0x00}, | ||
1128 | {0x3633, 0x34}, | ||
1129 | {0x3634, 0x02}, | ||
1130 | {0x364d, 0x0d}, | ||
1131 | {0x364f, 0xdd}, | ||
1132 | {0x3660, 0x04}, | ||
1133 | {0x3662, 0x10}, | ||
1134 | {0x3663, 0xf1}, | ||
1135 | {0x3665, 0x00}, | ||
1136 | {0x3666, 0x20}, | ||
1137 | {0x3667, 0x00}, | ||
1138 | {0x366a, 0x80}, | ||
1139 | {0x3680, 0xe0}, | ||
1140 | {0x3681, 0x00}, | ||
1141 | {0x3700, 0x42}, | ||
1142 | {0x3701, 0x14}, | ||
1143 | {0x3702, 0xa0}, | ||
1144 | {0x3703, 0xa8}, | ||
1145 | {0x3704, 0x78}, | ||
1146 | {0x3705, 0x02}, | ||
1147 | {0x3708, 0xe2}, | ||
1148 | {0x3709, 0xc3}, | ||
1149 | {0x370a, 0x00}, | ||
1150 | {0x370b, 0x20}, | ||
1151 | {0x370c, 0x0c}, | ||
1152 | {0x370d, 0x11}, | ||
1153 | {0x370e, 0x00}, | ||
1154 | {0x370f, 0x40}, | ||
1155 | {0x3710, 0x00}, | ||
1156 | {0x371a, 0x0c}, | ||
1157 | {0x371b, 0x05}, | ||
1158 | {0x371c, 0x01}, | ||
1159 | {0x371e, 0xa1}, | ||
1160 | {0x371f, 0x0c}, | ||
1161 | {0x3721, 0x00}, | ||
1162 | {0x3724, 0x10}, | ||
1163 | {0x3726, 0x00}, | ||
1164 | {0x372a, 0x01}, | ||
1165 | {0x3730, 0x10}, | ||
1166 | {0x3738, 0x22}, | ||
1167 | {0x3739, 0xe5}, | ||
1168 | {0x373a, 0x50}, | ||
1169 | {0x373b, 0x02}, | ||
1170 | {0x373c, 0x41}, | ||
1171 | {0x373f, 0x02}, | ||
1172 | {0x3740, 0x42}, | ||
1173 | {0x3741, 0x02}, | ||
1174 | {0x3742, 0x18}, | ||
1175 | {0x3743, 0x01}, | ||
1176 | {0x3744, 0x02}, | ||
1177 | {0x3747, 0x10}, | ||
1178 | {0x374c, 0x04}, | ||
1179 | {0x3751, 0xf0}, | ||
1180 | {0x3752, 0x00}, | ||
1181 | {0x3753, 0x00}, | ||
1182 | {0x3754, 0xc0}, | ||
1183 | {0x3755, 0x00}, | ||
1184 | {0x3756, 0x1a}, | ||
1185 | {0x3758, 0x00}, | ||
1186 | {0x3759, 0x0f}, | ||
1187 | {0x376b, 0x44}, | ||
1188 | {0x375c, 0x04}, | ||
1189 | {0x3774, 0x10}, | ||
1190 | {0x3776, 0x00}, | ||
1191 | {0x377f, 0x08}, | ||
1192 | {0x3780, 0x22}, | ||
1193 | {0x3781, 0x0c}, | ||
1194 | {0x3784, 0x2c}, | ||
1195 | {0x3785, 0x1e}, | ||
1196 | {0x378f, 0xf5}, | ||
1197 | {0x3791, 0xb0}, | ||
1198 | {0x3795, 0x00}, | ||
1199 | {0x3796, 0x64}, | ||
1200 | {0x3797, 0x11}, | ||
1201 | {0x3798, 0x30}, | ||
1202 | {0x3799, 0x41}, | ||
1203 | {0x379a, 0x07}, | ||
1204 | {0x379b, 0xb0}, | ||
1205 | {0x379c, 0x0c}, | ||
1206 | {0x37c5, 0x00}, | ||
1207 | {0x37c6, 0x00}, | ||
1208 | {0x37c7, 0x00}, | ||
1209 | {0x37c9, 0x00}, | ||
1210 | {0x37ca, 0x00}, | ||
1211 | {0x37cb, 0x00}, | ||
1212 | {0x37de, 0x00}, | ||
1213 | {0x37df, 0x00}, | ||
1214 | {0x3800, 0x00}, | ||
1215 | {0x3801, 0x02}, | ||
1216 | {0x3802, 0x00}, | ||
1217 | {0x3803, 0x06}, | ||
1218 | {0x3804, 0x0a}, | ||
1219 | {0x3805, 0x41}, | ||
1220 | {0x3806, 0x07}, | ||
1221 | {0x3807, 0xa1}, | ||
1222 | {0x3808, 0x0a}, | ||
1223 | {0x3809, 0x20}, | ||
1224 | {0x380a, 0x07}, | ||
1225 | {0x380b, 0x98}, | ||
1226 | {0x380c, 0x0e}, | ||
1227 | {0x380d, 0x70}, | ||
1228 | {0x380e, 0x07}, | ||
1229 | {0x380f, 0xc0}, | ||
1230 | {0x3810, 0x00}, | ||
1231 | {0x3811, 0x10}, | ||
1232 | {0x3812, 0x00}, | ||
1233 | {0x3813, 0x02}, | ||
1234 | {0x3814, 0x11}, | ||
1235 | {0x3815, 0x11}, | ||
1236 | {0x3820, 0x00}, | ||
1237 | {0x3821, 0x9e}, | ||
1238 | {0x3823, 0x00}, | ||
1239 | {0x3824, 0x00}, | ||
1240 | {0x3825, 0x00}, | ||
1241 | {0x3826, 0x00}, | ||
1242 | {0x3827, 0x00}, | ||
1243 | {0x382a, 0x04}, | ||
1244 | {0x3a04, 0x09}, | ||
1245 | {0x3a05, 0xa9}, | ||
1246 | {0x3a06, 0x00}, | ||
1247 | {0x3a07, 0xfe}, | ||
1248 | {0x3b00, 0x00}, | ||
1249 | {0x3b02, 0x00}, | ||
1250 | {0x3b03, 0x00}, | ||
1251 | {0x3b04, 0x00}, | ||
1252 | {0x3b05, 0x00}, | ||
1253 | {0x3e07, 0x20}, | ||
1254 | {0x4000, 0x08}, | ||
1255 | {0x4001, 0x04}, | ||
1256 | {0x4002, 0x45}, | ||
1257 | {0x4004, 0x08}, | ||
1258 | {0x4005, 0x18}, | ||
1259 | {0x4006, 0x20}, | ||
1260 | {0x4008, 0x24}, | ||
1261 | {0x4009, 0x10}, | ||
1262 | {0x400c, 0x00}, | ||
1263 | {0x400d, 0x00}, | ||
1264 | {0x4058, 0x00}, | ||
1265 | {0x404e, 0x37}, | ||
1266 | {0x404f, 0x8f}, | ||
1267 | {0x4058, 0x00}, | ||
1268 | {0x4101, 0xb2}, | ||
1269 | {0x4303, 0x00}, | ||
1270 | {0x4304, 0x08}, | ||
1271 | {0x4307, 0x30}, | ||
1272 | {0x4311, 0x04}, | ||
1273 | {0x4315, 0x01}, | ||
1274 | {0x4511, 0x05}, | ||
1275 | {0x4512, 0x01}, | ||
1276 | {0x4800, 0x20}, /* dis-continuous */ | ||
1277 | {0x4806, 0x00}, | ||
1278 | {0x4816, 0x52}, | ||
1279 | {0x481f, 0x30}, | ||
1280 | {0x4826, 0x32}, | ||
1281 | {0x4831, 0x6a}, | ||
1282 | {0x4d00, 0x04}, | ||
1283 | {0x4d01, 0x71}, | ||
1284 | {0x4d02, 0xfd}, | ||
1285 | {0x4d03, 0xf5}, | ||
1286 | {0x4d04, 0x0c}, | ||
1287 | {0x4d05, 0xcc}, | ||
1288 | {0x4837, 0x0a}, | ||
1289 | {0x5000, 0x06}, | ||
1290 | {0x5001, 0x01}, | ||
1291 | {0x5002, 0x00}, | ||
1292 | {0x5003, 0x20}, | ||
1293 | {0x5046, 0x0a}, | ||
1294 | {0x5013, 0x00}, | ||
1295 | {0x5046, 0x0a}, | ||
1296 | {0x5780, 0x1c}, | ||
1297 | {0x5786, 0x20}, | ||
1298 | {0x5787, 0x10}, | ||
1299 | {0x5788, 0x18}, | ||
1300 | {0x578a, 0x04}, | ||
1301 | {0x578b, 0x02}, | ||
1302 | {0x578c, 0x02}, | ||
1303 | {0x578e, 0x06}, | ||
1304 | {0x578f, 0x02}, | ||
1305 | {0x5790, 0x02}, | ||
1306 | {0x5791, 0xff}, | ||
1307 | {0x5842, 0x01}, | ||
1308 | {0x5843, 0x2b}, | ||
1309 | {0x5844, 0x01}, | ||
1310 | {0x5845, 0x92}, | ||
1311 | {0x5846, 0x01}, | ||
1312 | {0x5847, 0x8f}, | ||
1313 | {0x5848, 0x01}, | ||
1314 | {0x5849, 0x0c}, | ||
1315 | {0x5e00, 0x00}, | ||
1316 | {0x5e10, 0x0c}, | ||
1317 | {OV5693_TABLE_END, 0x0000} | ||
1318 | }; | ||
1319 | |||
1320 | static const ov5693_reg mode_1920x1080_HDR_30fps[] = { | ||
1321 | {OV5693_TABLE_WAIT_MS, OV5693_WAIT_MS}, | ||
1322 | {0x0100, 0x00},/* Including sw reset */ | ||
1323 | {0x0103, 0x01}, | ||
1324 | {0x3001, 0x0a}, | ||
1325 | {0x3002, 0x80}, | ||
1326 | {0x3006, 0x00}, | ||
1327 | {0x3011, 0x21}, | ||
1328 | {0x3012, 0x09}, | ||
1329 | {0x3013, 0x10}, | ||
1330 | {0x3014, 0x00}, | ||
1331 | {0x3015, 0x08}, | ||
1332 | {0x3016, 0xf0}, | ||
1333 | {0x3017, 0xf0}, | ||
1334 | {0x3018, 0xf0}, | ||
1335 | {0x301b, 0xb4}, | ||
1336 | {0x301d, 0x02}, | ||
1337 | {0x3021, 0x00}, | ||
1338 | {0x3022, 0x01}, | ||
1339 | {0x3028, 0x44}, | ||
1340 | {0x3098, 0x03}, | ||
1341 | {0x3099, 0x1e}, | ||
1342 | {0x309a, 0x02}, | ||
1343 | {0x309b, 0x01}, | ||
1344 | {0x309c, 0x00}, | ||
1345 | {0x30a0, 0xd2}, | ||
1346 | {0x30a2, 0x01}, | ||
1347 | {0x30b2, 0x00}, | ||
1348 | {0x30b3, 0x68}, | ||
1349 | {0x30b4, 0x03}, | ||
1350 | {0x30b5, 0x04}, | ||
1351 | {0x30b6, 0x01}, | ||
1352 | {0x3104, 0x21}, | ||
1353 | {0x3106, 0x00}, | ||
1354 | {0x3406, 0x01}, | ||
1355 | {0x3500, 0x00}, | ||
1356 | {0x3501, 0x72}, | ||
1357 | {0x3502, 0x00}, | ||
1358 | {0x3503, 0x07}, | ||
1359 | {0x3504, 0x00}, | ||
1360 | {0x3505, 0x00}, | ||
1361 | {0x3506, 0x00}, | ||
1362 | {0x3507, 0x01}, | ||
1363 | {0x3508, 0x80}, | ||
1364 | {0x3509, 0x10}, | ||
1365 | {0x350a, 0x00}, | ||
1366 | {0x350b, 0x40}, | ||
1367 | {0x3601, 0x0a}, | ||
1368 | {0x3602, 0x38}, | ||
1369 | {0x3612, 0x80}, | ||
1370 | {0x3620, 0x54}, | ||
1371 | {0x3621, 0xc7}, | ||
1372 | {0x3622, 0x0f}, | ||
1373 | {0x3625, 0x10}, | ||
1374 | {0x3630, 0x55}, | ||
1375 | {0x3631, 0xf4}, | ||
1376 | {0x3632, 0x00}, | ||
1377 | {0x3633, 0x34}, | ||
1378 | {0x3634, 0x02}, | ||
1379 | {0x364d, 0x0d}, | ||
1380 | {0x364f, 0xdd}, | ||
1381 | {0x3660, 0x04}, | ||
1382 | {0x3662, 0x10}, | ||
1383 | {0x3663, 0xf1}, | ||
1384 | {0x3665, 0x00}, | ||
1385 | {0x3666, 0x20}, | ||
1386 | {0x3667, 0x00}, | ||
1387 | {0x366a, 0x80}, | ||
1388 | {0x3680, 0xe0}, | ||
1389 | {0x3681, 0x00}, | ||
1390 | {0x3700, 0x42}, | ||
1391 | {0x3701, 0x14}, | ||
1392 | {0x3702, 0xa0}, | ||
1393 | {0x3703, 0xd8}, | ||
1394 | {0x3704, 0x78}, | ||
1395 | {0x3705, 0x02}, | ||
1396 | {0x3708, 0xe2}, | ||
1397 | {0x3709, 0xc3}, | ||
1398 | {0x370a, 0x00}, | ||
1399 | {0x370b, 0x20}, | ||
1400 | {0x370c, 0x0c}, | ||
1401 | {0x370d, 0x11}, | ||
1402 | {0x370e, 0x00}, | ||
1403 | {0x370f, 0x40}, | ||
1404 | {0x3710, 0x00}, | ||
1405 | {0x371a, 0x1c}, | ||
1406 | {0x371b, 0x05}, | ||
1407 | {0x371c, 0x01}, | ||
1408 | {0x371e, 0xa1}, | ||
1409 | {0x371f, 0x0c}, | ||
1410 | {0x3721, 0x00}, | ||
1411 | {0x3724, 0x10}, | ||
1412 | {0x3726, 0x00}, | ||
1413 | {0x372a, 0x01}, | ||
1414 | {0x3730, 0x10}, | ||
1415 | {0x3738, 0x22}, | ||
1416 | {0x3739, 0xe5}, | ||
1417 | {0x373a, 0x50}, | ||
1418 | {0x373b, 0x02}, | ||
1419 | {0x373c, 0x41}, | ||
1420 | {0x373f, 0x02}, | ||
1421 | {0x3740, 0x42}, | ||
1422 | {0x3741, 0x02}, | ||
1423 | {0x3742, 0x18}, | ||
1424 | {0x3743, 0x01}, | ||
1425 | {0x3744, 0x02}, | ||
1426 | {0x3747, 0x10}, | ||
1427 | {0x374c, 0x04}, | ||
1428 | {0x3751, 0xf0}, | ||
1429 | {0x3752, 0x00}, | ||
1430 | {0x3753, 0x00}, | ||
1431 | {0x3754, 0xc0}, | ||
1432 | {0x3755, 0x00}, | ||
1433 | {0x3756, 0x1a}, | ||
1434 | {0x3758, 0x00}, | ||
1435 | {0x3759, 0x0f}, | ||
1436 | {0x376b, 0x44}, | ||
1437 | {0x375c, 0x04}, | ||
1438 | {0x3774, 0x10}, | ||
1439 | {0x3776, 0x00}, | ||
1440 | {0x377f, 0x08}, | ||
1441 | {0x3780, 0x22}, | ||
1442 | {0x3781, 0x0c}, | ||
1443 | {0x3784, 0x2c}, | ||
1444 | {0x3785, 0x1e}, | ||
1445 | {0x378f, 0xf5}, | ||
1446 | {0x3791, 0xb0}, | ||
1447 | {0x3795, 0x00}, | ||
1448 | {0x3796, 0x64}, | ||
1449 | {0x3797, 0x11}, | ||
1450 | {0x3798, 0x30}, | ||
1451 | {0x3799, 0x41}, | ||
1452 | {0x379a, 0x07}, | ||
1453 | {0x379b, 0xb0}, | ||
1454 | {0x379c, 0x0c}, | ||
1455 | {0x37c5, 0x00}, | ||
1456 | {0x37c6, 0x00}, | ||
1457 | {0x37c7, 0x00}, | ||
1458 | {0x37c9, 0x00}, | ||
1459 | {0x37ca, 0x00}, | ||
1460 | {0x37cb, 0x00}, | ||
1461 | {0x37de, 0x00}, | ||
1462 | {0x37df, 0x00}, | ||
1463 | {0x3800, 0x01}, | ||
1464 | {0x3801, 0x70}, | ||
1465 | {0x3802, 0x01}, | ||
1466 | {0x3803, 0xbc}, | ||
1467 | {0x3804, 0x09}, | ||
1468 | {0x3805, 0x0f}, | ||
1469 | {0x3806, 0x05}, | ||
1470 | {0x3807, 0xff}, | ||
1471 | {0x3808, 0x07}, | ||
1472 | {0x3809, 0x80}, | ||
1473 | {0x380a, 0x04}, | ||
1474 | {0x380b, 0x38}, | ||
1475 | {0x380c, 0x0b}, | ||
1476 | {0x380d, 0x40}, | ||
1477 | {0x380e, 0x07}, | ||
1478 | {0x380f, 0x3a}, | ||
1479 | {0x3810, 0x00}, | ||
1480 | {0x3811, 0x02}, | ||
1481 | {0x3812, 0x00}, | ||
1482 | {0x3813, 0x02}, | ||
1483 | {0x3814, 0x11}, | ||
1484 | {0x3815, 0x11}, | ||
1485 | {0x3820, 0x00}, | ||
1486 | {0x3821, 0x9e}, | ||
1487 | {0x3823, 0x00}, | ||
1488 | {0x3824, 0x00}, | ||
1489 | {0x3825, 0x00}, | ||
1490 | {0x3826, 0x00}, | ||
1491 | {0x3827, 0x00}, | ||
1492 | {0x382a, 0x04}, | ||
1493 | {0x3a04, 0x09}, | ||
1494 | {0x3a05, 0xa9}, | ||
1495 | {0x3a06, 0x00}, | ||
1496 | {0x3a07, 0xfe}, | ||
1497 | {0x3b00, 0x00}, | ||
1498 | {0x3b02, 0x00}, | ||
1499 | {0x3b03, 0x00}, | ||
1500 | {0x3b04, 0x00}, | ||
1501 | {0x3b05, 0x00}, | ||
1502 | {0x3e07, 0x20}, | ||
1503 | {0x4000, 0x08}, | ||
1504 | {0x4001, 0x04}, | ||
1505 | {0x4002, 0x45}, | ||
1506 | {0x4004, 0x08}, | ||
1507 | {0x4005, 0x18}, | ||
1508 | {0x4006, 0x20}, | ||
1509 | {0x4008, 0x24}, | ||
1510 | {0x4009, 0x10}, | ||
1511 | {0x400c, 0x00}, | ||
1512 | {0x400d, 0x00}, | ||
1513 | {0x4058, 0x00}, | ||
1514 | {0x404e, 0x37}, | ||
1515 | {0x404f, 0x8f}, | ||
1516 | {0x4058, 0x00}, | ||
1517 | {0x4101, 0xb2}, | ||
1518 | {0x4303, 0x00}, | ||
1519 | {0x4304, 0x08}, | ||
1520 | {0x4307, 0x30}, | ||
1521 | {0x4311, 0x04}, | ||
1522 | {0x4315, 0x01}, | ||
1523 | {0x4511, 0x05}, | ||
1524 | {0x4512, 0x01}, | ||
1525 | {0x4800, 0x20}, /* dis-continuous */ | ||
1526 | {0x4806, 0x00}, | ||
1527 | {0x4816, 0x52}, | ||
1528 | {0x481f, 0x30}, | ||
1529 | {0x4826, 0x32}, | ||
1530 | {0x4831, 0x6a}, | ||
1531 | {0x4d00, 0x04}, | ||
1532 | {0x4d01, 0x71}, | ||
1533 | {0x4d02, 0xfd}, | ||
1534 | {0x4d03, 0xf5}, | ||
1535 | {0x4d04, 0x0c}, | ||
1536 | {0x4d05, 0xcc}, | ||
1537 | {0x4837, 0x0a}, | ||
1538 | {0x5000, 0x06}, | ||
1539 | {0x5001, 0x01}, | ||
1540 | {0x5002, 0x00}, | ||
1541 | {0x5003, 0x20}, | ||
1542 | {0x5046, 0x0a}, | ||
1543 | {0x5013, 0x00}, | ||
1544 | {0x5046, 0x0a}, | ||
1545 | {0x5780, 0x1c}, | ||
1546 | {0x5786, 0x20}, | ||
1547 | {0x5787, 0x10}, | ||
1548 | {0x5788, 0x18}, | ||
1549 | {0x578a, 0x04}, | ||
1550 | {0x578b, 0x02}, | ||
1551 | {0x578c, 0x02}, | ||
1552 | {0x578e, 0x06}, | ||
1553 | {0x578f, 0x02}, | ||
1554 | {0x5790, 0x02}, | ||
1555 | {0x5791, 0xff}, | ||
1556 | {0x5842, 0x01}, | ||
1557 | {0x5843, 0x2b}, | ||
1558 | {0x5844, 0x01}, | ||
1559 | {0x5845, 0x92}, | ||
1560 | {0x5846, 0x01}, | ||
1561 | {0x5847, 0x8f}, | ||
1562 | {0x5848, 0x01}, | ||
1563 | {0x5849, 0x0c}, | ||
1564 | {0x5e00, 0x00}, | ||
1565 | {0x5e10, 0x0c}, | ||
1566 | {OV5693_TABLE_END, 0x0000} | ||
1567 | }; | ||
1568 | |||
1569 | static const ov5693_reg mode_1280x720_HDR_60fps[] = { | ||
1570 | {OV5693_TABLE_WAIT_MS, OV5693_WAIT_MS}, | ||
1571 | {0x0100, 0x00},/* Including sw reset */ | ||
1572 | {0x0103, 0x01}, | ||
1573 | {0x3001, 0x0a}, | ||
1574 | {0x3002, 0x80}, | ||
1575 | {0x3006, 0x00}, | ||
1576 | {0x3011, 0x21}, | ||
1577 | {0x3012, 0x09}, | ||
1578 | {0x3013, 0x10}, | ||
1579 | {0x3014, 0x00}, | ||
1580 | {0x3015, 0x08}, | ||
1581 | {0x3016, 0xf0}, | ||
1582 | {0x3017, 0xf0}, | ||
1583 | {0x3018, 0xf0}, | ||
1584 | {0x301b, 0xb4}, | ||
1585 | {0x301d, 0x02}, | ||
1586 | {0x3021, 0x00}, | ||
1587 | {0x3022, 0x01}, | ||
1588 | {0x3028, 0x44}, | ||
1589 | {0x3098, 0x03}, | ||
1590 | {0x3099, 0x1e}, | ||
1591 | {0x309a, 0x02}, | ||
1592 | {0x309b, 0x01}, | ||
1593 | {0x309c, 0x00}, | ||
1594 | {0x30a0, 0xd2}, | ||
1595 | {0x30a2, 0x01}, | ||
1596 | {0x30b2, 0x00}, | ||
1597 | {0x30b3, 0x68}, | ||
1598 | {0x30b4, 0x03}, | ||
1599 | {0x30b5, 0x04}, | ||
1600 | {0x30b6, 0x01}, | ||
1601 | {0x3104, 0x21}, | ||
1602 | {0x3106, 0x00}, | ||
1603 | {0x3406, 0x01}, | ||
1604 | {0x3500, 0x00}, | ||
1605 | {0x3501, 0x39}, | ||
1606 | {0x3502, 0x00}, | ||
1607 | {0x3503, 0x07}, | ||
1608 | {0x3504, 0x00}, | ||
1609 | {0x3505, 0x00}, | ||
1610 | {0x3506, 0x00}, | ||
1611 | {0x3507, 0x01}, | ||
1612 | {0x3508, 0x80}, | ||
1613 | {0x3509, 0x10}, | ||
1614 | {0x350a, 0x00}, | ||
1615 | {0x350b, 0x40}, | ||
1616 | {0x3601, 0x0a}, | ||
1617 | {0x3602, 0x38}, | ||
1618 | {0x3612, 0x80}, | ||
1619 | {0x3620, 0x54}, | ||
1620 | {0x3621, 0xc7}, | ||
1621 | {0x3622, 0x0f}, | ||
1622 | {0x3625, 0x10}, | ||
1623 | {0x3630, 0x55}, | ||
1624 | {0x3631, 0xf4}, | ||
1625 | {0x3632, 0x00}, | ||
1626 | {0x3633, 0x34}, | ||
1627 | {0x3634, 0x02}, | ||
1628 | {0x364d, 0x0d}, | ||
1629 | {0x364f, 0xdd}, | ||
1630 | {0x3660, 0x04}, | ||
1631 | {0x3662, 0x10}, | ||
1632 | {0x3663, 0xf1}, | ||
1633 | {0x3665, 0x00}, | ||
1634 | {0x3666, 0x20}, | ||
1635 | {0x3667, 0x00}, | ||
1636 | {0x366a, 0x80}, | ||
1637 | {0x3680, 0xe0}, | ||
1638 | {0x3681, 0x00}, | ||
1639 | {0x3700, 0x42}, | ||
1640 | {0x3701, 0x14}, | ||
1641 | {0x3702, 0xa0}, | ||
1642 | {0x3703, 0xd8}, | ||
1643 | {0x3704, 0x78}, | ||
1644 | {0x3705, 0x02}, | ||
1645 | {0x3708, 0xe2}, | ||
1646 | {0x3709, 0xc3}, | ||
1647 | {0x370a, 0x00}, | ||
1648 | {0x370b, 0x20}, | ||
1649 | {0x370c, 0x0c}, | ||
1650 | {0x370d, 0x11}, | ||
1651 | {0x370e, 0x00}, | ||
1652 | {0x370f, 0x40}, | ||
1653 | {0x3710, 0x00}, | ||
1654 | {0x371a, 0x1c}, | ||
1655 | {0x371b, 0x05}, | ||
1656 | {0x371c, 0x01}, | ||
1657 | {0x371e, 0xa1}, | ||
1658 | {0x371f, 0x0c}, | ||
1659 | {0x3721, 0x00}, | ||
1660 | {0x3724, 0x10}, | ||
1661 | {0x3726, 0x00}, | ||
1662 | {0x372a, 0x01}, | ||
1663 | {0x3730, 0x10}, | ||
1664 | {0x3738, 0x22}, | ||
1665 | {0x3739, 0xe5}, | ||
1666 | {0x373a, 0x50}, | ||
1667 | {0x373b, 0x02}, | ||
1668 | {0x373c, 0x41}, | ||
1669 | {0x373f, 0x02}, | ||
1670 | {0x3740, 0x42}, | ||
1671 | {0x3741, 0x02}, | ||
1672 | {0x3742, 0x18}, | ||
1673 | {0x3743, 0x01}, | ||
1674 | {0x3744, 0x02}, | ||
1675 | {0x3747, 0x10}, | ||
1676 | {0x374c, 0x04}, | ||
1677 | {0x3751, 0xf0}, | ||
1678 | {0x3752, 0x00}, | ||
1679 | {0x3753, 0x00}, | ||
1680 | {0x3754, 0xc0}, | ||
1681 | {0x3755, 0x00}, | ||
1682 | {0x3756, 0x1a}, | ||
1683 | {0x3758, 0x00}, | ||
1684 | {0x3759, 0x0f}, | ||
1685 | {0x376b, 0x44}, | ||
1686 | {0x375c, 0x04}, | ||
1687 | {0x3774, 0x10}, | ||
1688 | {0x3776, 0x00}, | ||
1689 | {0x377f, 0x08}, | ||
1690 | {0x3780, 0x22}, | ||
1691 | {0x3781, 0x0c}, | ||
1692 | {0x3784, 0x2c}, | ||
1693 | {0x3785, 0x1e}, | ||
1694 | {0x378f, 0xf5}, | ||
1695 | {0x3791, 0xb0}, | ||
1696 | {0x3795, 0x00}, | ||
1697 | {0x3796, 0x64}, | ||
1698 | {0x3797, 0x11}, | ||
1699 | {0x3798, 0x30}, | ||
1700 | {0x3799, 0x41}, | ||
1701 | {0x379a, 0x07}, | ||
1702 | {0x379b, 0xb0}, | ||
1703 | {0x379c, 0x0c}, | ||
1704 | {0x37c5, 0x00}, | ||
1705 | {0x37c6, 0x00}, | ||
1706 | {0x37c7, 0x00}, | ||
1707 | {0x37c9, 0x00}, | ||
1708 | {0x37ca, 0x00}, | ||
1709 | {0x37cb, 0x00}, | ||
1710 | {0x37de, 0x00}, | ||
1711 | {0x37df, 0x00}, | ||
1712 | {0x3800, 0x02}, | ||
1713 | {0x3801, 0xa8}, | ||
1714 | {0x3802, 0x02}, | ||
1715 | {0x3803, 0x68}, | ||
1716 | {0x3804, 0x07}, | ||
1717 | {0x3805, 0xb7}, | ||
1718 | {0x3806, 0x05}, | ||
1719 | {0x3807, 0x3b}, | ||
1720 | {0x3808, 0x05}, | ||
1721 | {0x3809, 0x00}, | ||
1722 | {0x380a, 0x02}, | ||
1723 | {0x380b, 0xd0}, | ||
1724 | {0x380c, 0x0b}, | ||
1725 | {0x380d, 0x40}, | ||
1726 | {0x380e, 0x03}, | ||
1727 | {0x380f, 0x9e}, | ||
1728 | {0x3810, 0x00}, | ||
1729 | {0x3811, 0x02}, | ||
1730 | {0x3812, 0x00}, | ||
1731 | {0x3813, 0x02}, | ||
1732 | {0x3814, 0x11}, | ||
1733 | {0x3815, 0x11}, | ||
1734 | {0x3820, 0x00}, | ||
1735 | {0x3821, 0x9e}, | ||
1736 | {0x3823, 0x00}, | ||
1737 | {0x3824, 0x00}, | ||
1738 | {0x3825, 0x00}, | ||
1739 | {0x3826, 0x00}, | ||
1740 | {0x3827, 0x00}, | ||
1741 | {0x382a, 0x04}, | ||
1742 | {0x3a04, 0x09}, | ||
1743 | {0x3a05, 0xa9}, | ||
1744 | {0x3a06, 0x00}, | ||
1745 | {0x3a07, 0xfe}, | ||
1746 | {0x3b00, 0x00}, | ||
1747 | {0x3b02, 0x00}, | ||
1748 | {0x3b03, 0x00}, | ||
1749 | {0x3b04, 0x00}, | ||
1750 | {0x3b05, 0x00}, | ||
1751 | {0x3e07, 0x20}, | ||
1752 | {0x4000, 0x08}, | ||
1753 | {0x4001, 0x04}, | ||
1754 | {0x4002, 0x45}, | ||
1755 | {0x4004, 0x08}, | ||
1756 | {0x4005, 0x18}, | ||
1757 | {0x4006, 0x20}, | ||
1758 | {0x4008, 0x24}, | ||
1759 | {0x4009, 0x10}, | ||
1760 | {0x400c, 0x00}, | ||
1761 | {0x400d, 0x00}, | ||
1762 | {0x4058, 0x00}, | ||
1763 | {0x404e, 0x37}, | ||
1764 | {0x404f, 0x8f}, | ||
1765 | {0x4058, 0x00}, | ||
1766 | {0x4101, 0xb2}, | ||
1767 | {0x4303, 0x00}, | ||
1768 | {0x4304, 0x08}, | ||
1769 | {0x4307, 0x30}, | ||
1770 | {0x4311, 0x04}, | ||
1771 | {0x4315, 0x01}, | ||
1772 | {0x4511, 0x05}, | ||
1773 | {0x4512, 0x01}, | ||
1774 | {0x4800, 0x20}, /* dis-continuous */ | ||
1775 | {0x4806, 0x00}, | ||
1776 | {0x4816, 0x52}, | ||
1777 | {0x481f, 0x30}, | ||
1778 | {0x4826, 0x32}, | ||
1779 | {0x4831, 0x6a}, | ||
1780 | {0x4d00, 0x04}, | ||
1781 | {0x4d01, 0x71}, | ||
1782 | {0x4d02, 0xfd}, | ||
1783 | {0x4d03, 0xf5}, | ||
1784 | {0x4d04, 0x0c}, | ||
1785 | {0x4d05, 0xcc}, | ||
1786 | {0x4837, 0x0a}, | ||
1787 | {0x5000, 0x06}, | ||
1788 | {0x5001, 0x01}, | ||
1789 | {0x5002, 0x00}, | ||
1790 | {0x5003, 0x20}, | ||
1791 | {0x5046, 0x0a}, | ||
1792 | {0x5013, 0x00}, | ||
1793 | {0x5046, 0x0a}, | ||
1794 | {0x5780, 0x1c}, | ||
1795 | {0x5786, 0x20}, | ||
1796 | {0x5787, 0x10}, | ||
1797 | {0x5788, 0x18}, | ||
1798 | {0x578a, 0x04}, | ||
1799 | {0x578b, 0x02}, | ||
1800 | {0x578c, 0x02}, | ||
1801 | {0x578e, 0x06}, | ||
1802 | {0x578f, 0x02}, | ||
1803 | {0x5790, 0x02}, | ||
1804 | {0x5791, 0xff}, | ||
1805 | {0x5842, 0x01}, | ||
1806 | {0x5843, 0x2b}, | ||
1807 | {0x5844, 0x01}, | ||
1808 | {0x5845, 0x92}, | ||
1809 | {0x5846, 0x01}, | ||
1810 | {0x5847, 0x8f}, | ||
1811 | {0x5848, 0x01}, | ||
1812 | {0x5849, 0x0c}, | ||
1813 | {0x5e00, 0x00}, | ||
1814 | {0x5e10, 0x0c}, | ||
1815 | {OV5693_TABLE_END, 0x0000} | ||
1816 | }; | ||
1817 | |||
1818 | static const ov5693_reg mode_2592x1944_one_lane_15fps[] = { | ||
1819 | {0x0100, 0x00},/* Including sw reset */ | ||
1820 | {0x0103, 0x01}, | ||
1821 | {0x3001, 0x0a}, | ||
1822 | {0x3002, 0x80}, | ||
1823 | {0x3006, 0x00}, | ||
1824 | {0x3011, 0x11}, | ||
1825 | {0x3012, 0x09}, | ||
1826 | {0x3013, 0x10}, | ||
1827 | {0x3014, 0x00}, | ||
1828 | {0x3015, 0x28}, | ||
1829 | {0x3016, 0xf0}, | ||
1830 | {0x3017, 0xf0}, | ||
1831 | {0x3018, 0xf0}, | ||
1832 | {0x301b, 0xb4}, | ||
1833 | {0x301d, 0x02}, | ||
1834 | {0x3021, 0x00}, | ||
1835 | {0x3022, 0x01}, | ||
1836 | {0x3028, 0x44}, | ||
1837 | {0x3098, 0x03}, | ||
1838 | {0x3099, 0x1e}, | ||
1839 | {0x309a, 0x05}, | ||
1840 | {0x309b, 0x01}, | ||
1841 | {0x309c, 0x00}, | ||
1842 | {0x30a0, 0xd2}, | ||
1843 | {0x30a2, 0x01}, | ||
1844 | {0x30b2, 0x00}, | ||
1845 | {0x30b3, 0x64}, | ||
1846 | {0x30b4, 0x03}, | ||
1847 | {0x30b5, 0x04}, | ||
1848 | {0x30b6, 0x01}, | ||
1849 | {0x3104, 0x21}, | ||
1850 | {0x3106, 0x00}, | ||
1851 | {0x3400, 0x04}, | ||
1852 | {0x3401, 0x00}, | ||
1853 | {0x3402, 0x04}, | ||
1854 | {0x3403, 0x00}, | ||
1855 | {0x3404, 0x04}, | ||
1856 | {0x3405, 0x00}, | ||
1857 | {0x3406, 0x01}, | ||
1858 | {0x3500, 0x00}, | ||
1859 | {0x3501, 0x7b}, | ||
1860 | {0x3502, 0x00}, | ||
1861 | {0x3503, 0x07}, | ||
1862 | {0x3504, 0x00}, | ||
1863 | {0x3505, 0x00}, | ||
1864 | {0x3506, 0x00}, | ||
1865 | {0x3507, 0x02}, | ||
1866 | {0x3508, 0x00}, | ||
1867 | {0x3509, 0x10}, | ||
1868 | {0x350a, 0x00}, | ||
1869 | {0x350b, 0x20}, | ||
1870 | {0x3600, 0xbc}, | ||
1871 | {0x3601, 0x0a}, | ||
1872 | {0x3602, 0x38}, | ||
1873 | {0x3612, 0x80}, | ||
1874 | {0x3620, 0x44}, | ||
1875 | {0x3621, 0xb5}, | ||
1876 | {0x3622, 0x0c}, | ||
1877 | {0x3625, 0x10}, | ||
1878 | {0x3630, 0x55}, | ||
1879 | {0x3631, 0xf4}, | ||
1880 | {0x3632, 0x00}, | ||
1881 | {0x3633, 0x34}, | ||
1882 | {0x3634, 0x02}, | ||
1883 | {0x364d, 0x0d}, | ||
1884 | {0x364f, 0xdd}, | ||
1885 | {0x3660, 0x04}, | ||
1886 | {0x3662, 0x10}, | ||
1887 | {0x3663, 0xf1}, | ||
1888 | {0x3665, 0x00}, | ||
1889 | {0x3666, 0x20}, | ||
1890 | {0x3667, 0x00}, | ||
1891 | {0x366a, 0x80}, | ||
1892 | {0x3680, 0xe0}, | ||
1893 | {0x3681, 0x00}, | ||
1894 | {0x3700, 0x42}, | ||
1895 | {0x3701, 0x14}, | ||
1896 | {0x3702, 0xa0}, | ||
1897 | {0x3703, 0xd8}, | ||
1898 | {0x3704, 0x78}, | ||
1899 | {0x3705, 0x02}, | ||
1900 | {0x3708, 0xe2}, | ||
1901 | {0x3709, 0xc3}, | ||
1902 | {0x370a, 0x00}, | ||
1903 | {0x370b, 0x20}, | ||
1904 | {0x370c, 0x0c}, | ||
1905 | {0x370d, 0x11}, | ||
1906 | {0x370e, 0x00}, | ||
1907 | {0x370f, 0x40}, | ||
1908 | {0x3710, 0x00}, | ||
1909 | {0x371a, 0x1c}, | ||
1910 | {0x371b, 0x05}, | ||
1911 | {0x371c, 0x01}, | ||
1912 | {0x371e, 0xa1}, | ||
1913 | {0x371f, 0x0c}, | ||
1914 | {0x3721, 0x00}, | ||
1915 | {0x3724, 0x10}, | ||
1916 | {0x3726, 0x00}, | ||
1917 | {0x372a, 0x01}, | ||
1918 | {0x3730, 0x10}, | ||
1919 | {0x3738, 0x22}, | ||
1920 | {0x3739, 0xe5}, | ||
1921 | {0x373a, 0x50}, | ||
1922 | {0x373b, 0x02}, | ||
1923 | {0x373c, 0x41}, | ||
1924 | {0x373f, 0x02}, | ||
1925 | {0x3740, 0x42}, | ||
1926 | {0x3741, 0x02}, | ||
1927 | {0x3742, 0x18}, | ||
1928 | {0x3743, 0x01}, | ||
1929 | {0x3744, 0x02}, | ||
1930 | {0x3747, 0x10}, | ||
1931 | {0x374c, 0x04}, | ||
1932 | {0x3751, 0xf0}, | ||
1933 | {0x3752, 0x00}, | ||
1934 | {0x3753, 0x00}, | ||
1935 | {0x3754, 0xc0}, | ||
1936 | {0x3755, 0x00}, | ||
1937 | {0x3756, 0x1a}, | ||
1938 | {0x3758, 0x00}, | ||
1939 | {0x3759, 0x0f}, | ||
1940 | {0x376b, 0x44}, | ||
1941 | {0x375c, 0x04}, | ||
1942 | {0x3774, 0x10}, | ||
1943 | {0x3776, 0x00}, | ||
1944 | {0x377f, 0x08}, | ||
1945 | {0x3780, 0x22}, | ||
1946 | {0x3781, 0x0c}, | ||
1947 | {0x3784, 0x2c}, | ||
1948 | {0x3785, 0x1e}, | ||
1949 | {0x378f, 0xf5}, | ||
1950 | {0x3791, 0xb0}, | ||
1951 | {0x3795, 0x00}, | ||
1952 | {0x3796, 0x64}, | ||
1953 | {0x3797, 0x11}, | ||
1954 | {0x3798, 0x30}, | ||
1955 | {0x3799, 0x41}, | ||
1956 | {0x379a, 0x07}, | ||
1957 | {0x379b, 0xb0}, | ||
1958 | {0x379c, 0x0c}, | ||
1959 | {0x37c5, 0x00}, | ||
1960 | {0x37c6, 0x00}, | ||
1961 | {0x37c7, 0x00}, | ||
1962 | {0x37c9, 0x00}, | ||
1963 | {0x37ca, 0x00}, | ||
1964 | {0x37cb, 0x00}, | ||
1965 | {0x37de, 0x00}, | ||
1966 | {0x37df, 0x00}, | ||
1967 | {0x3800, 0x00}, | ||
1968 | {0x3801, 0x00}, | ||
1969 | {0x3802, 0x00}, | ||
1970 | {0x3803, 0x00}, | ||
1971 | {0x3804, 0x0a}, | ||
1972 | {0x3805, 0x3f}, | ||
1973 | {0x3806, 0x07}, | ||
1974 | {0x3807, 0xa3}, | ||
1975 | {0x3808, 0x0a}, | ||
1976 | {0x3809, 0x20}, | ||
1977 | {0x380a, 0x07}, | ||
1978 | {0x380b, 0x98}, | ||
1979 | {0x380c, 0x0a}, | ||
1980 | {0x380d, 0x80}, | ||
1981 | {0x380e, 0x07}, | ||
1982 | {0x380f, 0xc0}, | ||
1983 | {0x3810, 0x00}, | ||
1984 | {0x3811, 0x02}, | ||
1985 | {0x3812, 0x00}, | ||
1986 | {0x3813, 0x02}, | ||
1987 | {0x3814, 0x11}, | ||
1988 | {0x3815, 0x11}, | ||
1989 | {0x3820, 0x00}, | ||
1990 | {0x3821, 0x1e}, | ||
1991 | {0x3823, 0x00}, | ||
1992 | {0x3824, 0x00}, | ||
1993 | {0x3825, 0x00}, | ||
1994 | {0x3826, 0x00}, | ||
1995 | {0x3827, 0x00}, | ||
1996 | {0x382a, 0x04}, | ||
1997 | {0x3a04, 0x06}, | ||
1998 | {0x3a05, 0x14}, | ||
1999 | {0x3a06, 0x00}, | ||
2000 | {0x3a07, 0xfe}, | ||
2001 | {0x3b00, 0x00}, | ||
2002 | {0x3b02, 0x00}, | ||
2003 | {0x3b03, 0x00}, | ||
2004 | {0x3b04, 0x00}, | ||
2005 | {0x3b05, 0x00}, | ||
2006 | {0x3e07, 0x20}, | ||
2007 | {0x4000, 0x08}, | ||
2008 | {0x4001, 0x04}, | ||
2009 | {0x4002, 0x45}, | ||
2010 | {0x4004, 0x08}, | ||
2011 | {0x4005, 0x18}, | ||
2012 | {0x4006, 0x20}, | ||
2013 | {0x4008, 0x24}, | ||
2014 | {0x4009, 0x10}, | ||
2015 | {0x400c, 0x00}, | ||
2016 | {0x400d, 0x00}, | ||
2017 | {0x4058, 0x00}, | ||
2018 | {0x404e, 0x37}, | ||
2019 | {0x404f, 0x8f}, | ||
2020 | {0x4058, 0x00}, | ||
2021 | {0x4101, 0xb2}, | ||
2022 | {0x4303, 0x00}, | ||
2023 | {0x4304, 0x08}, | ||
2024 | {0x4307, 0x30}, | ||
2025 | {0x4311, 0x04}, | ||
2026 | {0x4315, 0x01}, | ||
2027 | {0x4511, 0x05}, | ||
2028 | {0x4512, 0x01}, | ||
2029 | {0x4806, 0x00}, | ||
2030 | {0x4816, 0x52}, | ||
2031 | {0x481f, 0x30}, | ||
2032 | {0x4826, 0x2c}, | ||
2033 | {0x4831, 0x64}, | ||
2034 | {0x4d00, 0x04}, | ||
2035 | {0x4d01, 0x71}, | ||
2036 | {0x4d02, 0xfd}, | ||
2037 | {0x4d03, 0xf5}, | ||
2038 | {0x4d04, 0x0c}, | ||
2039 | {0x4d05, 0xcc}, | ||
2040 | {0x4837, 0x0a}, | ||
2041 | {0x5000, 0x06}, | ||
2042 | {0x5001, 0x01}, | ||
2043 | {0x5002, 0x00}, | ||
2044 | {0x5003, 0x20}, | ||
2045 | {0x5046, 0x0a}, | ||
2046 | {0x5013, 0x00}, | ||
2047 | {0x5046, 0x0a}, | ||
2048 | {0x5780, 0xfc}, | ||
2049 | {0x5781, 0x13}, | ||
2050 | {0x5782, 0x03}, | ||
2051 | {0x5786, 0x20}, | ||
2052 | {0x5787, 0x40}, | ||
2053 | {0x5788, 0x08}, | ||
2054 | {0x5789, 0x08}, | ||
2055 | {0x578a, 0x02}, | ||
2056 | {0x578b, 0x01}, | ||
2057 | {0x578c, 0x01}, | ||
2058 | {0x578d, 0x0c}, | ||
2059 | {0x578e, 0x02}, | ||
2060 | {0x578f, 0x01}, | ||
2061 | {0x5790, 0x01}, | ||
2062 | {0x5791, 0xff}, | ||
2063 | {0x5842, 0x01}, | ||
2064 | {0x5843, 0x2b}, | ||
2065 | {0x5844, 0x01}, | ||
2066 | {0x5845, 0x92}, | ||
2067 | {0x5846, 0x01}, | ||
2068 | {0x5847, 0x8f}, | ||
2069 | {0x5848, 0x01}, | ||
2070 | {0x5849, 0x0c}, | ||
2071 | {0x5e00, 0x00}, | ||
2072 | {0x5e10, 0x0c}, | ||
2073 | {0x0100, 0x01}, | ||
2074 | {0x3810, 0x00}, | ||
2075 | {0x3811, 0x10}, | ||
2076 | {0x3812, 0x00}, | ||
2077 | {0x3813, 0x06}, | ||
2078 | {OV5693_TABLE_END, 0x0000} | ||
2079 | }; | ||
2080 | |||
2081 | enum { | ||
2082 | OV5693_MODE_2592X1944, | ||
2083 | OV5693_MODE_2592X1458, | ||
2084 | OV5693_MODE_1920X1080, | ||
2085 | OV5693_MODE_1280X720_120FPS, | ||
2086 | OV5693_MODE_2592X1944_HDR, | ||
2087 | OV5693_MODE_1920X1080_HDR, | ||
2088 | OV5693_MODE_2592x1944_15FPS, | ||
2089 | |||
2090 | OV5693_MODE_START_STREAM, | ||
2091 | OV5693_MODE_STOP_STREAM, | ||
2092 | OV5693_MODE_TEST_PATTERN | ||
2093 | }; | ||
2094 | |||
2095 | static const ov5693_reg *mode_table[] = { | ||
2096 | [OV5693_MODE_2592X1944] = mode_2592x1944, | ||
2097 | [OV5693_MODE_2592X1458] = mode_2592x1458, | ||
2098 | [OV5693_MODE_1920X1080] = mode_1920x1080, | ||
2099 | [OV5693_MODE_1280X720_120FPS] = mode_1280x720_120fps, | ||
2100 | [OV5693_MODE_2592X1944_HDR] = mode_2592x1944_HDR_24fps, | ||
2101 | [OV5693_MODE_1920X1080_HDR] = mode_1920x1080_HDR_30fps, | ||
2102 | [OV5693_MODE_2592x1944_15FPS] = mode_2592x1944_one_lane_15fps, | ||
2103 | |||
2104 | [OV5693_MODE_START_STREAM] = ov5693_start, | ||
2105 | [OV5693_MODE_STOP_STREAM] = ov5693_stop, | ||
2106 | [OV5693_MODE_TEST_PATTERN] = tp_colorbars, | ||
2107 | }; | ||
2108 | |||
2109 | static const int ov5693_15fps[] = { | ||
2110 | 15, | ||
2111 | }; | ||
2112 | |||
2113 | static const int ov5693_24fps[] = { | ||
2114 | 24, | ||
2115 | }; | ||
2116 | |||
2117 | static const int ov5693_30fps[] = { | ||
2118 | 30, | ||
2119 | }; | ||
2120 | |||
2121 | static const int ov5693_120fps[] = { | ||
2122 | 120, | ||
2123 | }; | ||
2124 | |||
2125 | static const struct camera_common_frmfmt ov5693_frmfmt[] = { | ||
2126 | {{2592, 1944}, ov5693_30fps, 1, 0, OV5693_MODE_2592X1944}, | ||
2127 | {{2592, 1458}, ov5693_30fps, 1, 0, OV5693_MODE_2592X1458}, | ||
2128 | {{1920, 1080}, ov5693_30fps, 1, 0, OV5693_MODE_1920X1080}, | ||
2129 | {{1280, 720}, ov5693_120fps, 1, 0, OV5693_MODE_1280X720_120FPS}, | ||
2130 | {{2592, 1944}, ov5693_24fps, 1, 1, OV5693_MODE_2592X1944_HDR}, | ||
2131 | {{1920, 1080}, ov5693_30fps, 1, 1, OV5693_MODE_1920X1080_HDR}, | ||
2132 | {{2592, 1944}, ov5693_15fps, 1, 1, OV5693_MODE_2592x1944_15FPS}, | ||
2133 | }; | ||
2134 | #endif /* __OV5693_TABLES__ */ | ||
2135 | |||
diff --git a/drivers/media/i2c/ov9281.c b/drivers/media/i2c/ov9281.c new file mode 100644 index 000000000..acbec072f --- /dev/null +++ b/drivers/media/i2c/ov9281.c | |||
@@ -0,0 +1,1216 @@ | |||
1 | /* | ||
2 | * ov9281.c - ov9281 sensor driver | ||
3 | * | ||
4 | * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/uaccess.h> | ||
20 | #include <linux/gpio.h> | ||
21 | #include <linux/module.h> | ||
22 | |||
23 | #include <linux/seq_file.h> | ||
24 | #include <linux/of.h> | ||
25 | #include <linux/of_device.h> | ||
26 | #include <linux/of_gpio.h> | ||
27 | |||
28 | #include <media/tegra_v4l2_camera.h> | ||
29 | #include <media/camera_common.h> | ||
30 | |||
31 | #include "ov9281_mode_tbls.h" | ||
32 | |||
33 | /* OV9281 Registers */ | ||
34 | #define OV9281_SC_MODE_SELECT_ADDR 0x0100 | ||
35 | #define OV9281_SC_MODE_SELECT_STREAMING 0x01 | ||
36 | #define OV9281_SC_CHIP_ID_HIGH_ADDR 0x300A | ||
37 | #define OV9281_SC_CHIP_ID_LOW_ADDR 0x300B | ||
38 | #define OV9281_SC_CTRL_SCCB_ID_ADDR 0x302B | ||
39 | #define OV9281_SC_CTRL_3B_ADDR 0x303B | ||
40 | #define OV9281_SC_CTRL_3B_SCCB_ID2_NACK_EN (1 << 0) | ||
41 | #define OV9281_SC_CTRL_3B_SCCB_PGM_ID_EN (1 << 1) | ||
42 | |||
43 | #define OV9281_GROUP_HOLD_ADDR 0x3208 | ||
44 | #define OV9281_GROUP_HOLD_START 0x00 | ||
45 | #define OV9281_GROUP_HOLD_END 0x10 | ||
46 | #define OV9281_GROUP_HOLD_LAUNCH_LBLANK 0x60 | ||
47 | #define OV9281_GROUP_HOLD_LAUNCH_VBLANK 0xA0 | ||
48 | #define OV9281_GROUP_HOLD_LAUNCH_IMMED 0xE0 | ||
49 | #define OV9281_GROUP_HOLD_BANK_0 0x00 | ||
50 | #define OV9281_GROUP_HOLD_BANK_1 0x01 | ||
51 | |||
52 | #define OV9281_EXPO_HIGH_ADDR 0x3500 | ||
53 | #define OV9281_EXPO_MID_ADDR 0x3501 | ||
54 | #define OV9281_EXPO_LOW_ADDR 0x3502 | ||
55 | |||
56 | #define OV9281_GAIN_SHIFT_ADDR 0x3507 | ||
57 | #define OV9281_GAIN_HIGH_ADDR 0x3508 | ||
58 | #define OV9281_GAIN_LOW_ADDR 0x3509 | ||
59 | |||
60 | #define OV9281_TIMING_VTS_HIGH_ADDR 0x380E | ||
61 | #define OV9281_TIMING_VTS_LOW_ADDR 0x380F | ||
62 | #define OV9281_TIMING_RST_FSIN_HIGH_ADDR 0x3826 | ||
63 | #define OV9281_TIMING_RST_FSIN_LOW_ADDR 0x3827 | ||
64 | |||
65 | #define OV9281_OTP_BUFFER_ADDR 0x3D00 | ||
66 | #define OV9281_OTP_BUFFER_SIZE 32 | ||
67 | #define OV9281_OTP_STR_SIZE (OV9281_OTP_BUFFER_SIZE * 2) | ||
68 | #define OV9281_FUSE_ID_OTP_BUFFER_ADDR 0x3D00 | ||
69 | #define OV9281_FUSE_ID_OTP_BUFFER_SIZE 16 | ||
70 | #define OV9281_FUSE_ID_STR_SIZE (OV9281_FUSE_ID_OTP_BUFFER_SIZE * 2) | ||
71 | #define OV9281_OTP_PROGRAM_CTRL_ADDR 0x3D80 | ||
72 | #define OV9281_OTP_LOAD_CTRL_ADDR 0x3D81 | ||
73 | #define OV9281_OTP_LOAD_CTRL_OTP_RD 0x01 | ||
74 | |||
75 | #define OV9281_PRE_CTRL00_ADDR 0x5E00 | ||
76 | #define OV9281_PRE_CTRL00_TEST_PATTERN_EN (1 << 7) | ||
77 | |||
78 | /* OV9281 Other Stuffs */ | ||
79 | #define OV9281_DEFAULT_GAIN 0x0010 /* 1.0x real gain */ | ||
80 | #define OV9281_MIN_GAIN 0x0001 | ||
81 | #define OV9281_MAX_GAIN 0x1FFF | ||
82 | |||
83 | #define OV9281_DEFAULT_FRAME_LENGTH 0x038E | ||
84 | #define OV9281_MIN_FRAME_LENGTH 0x0001 | ||
85 | #define OV9281_MAX_FRAME_LENGTH 0xFFFF | ||
86 | |||
87 | #define OV9281_MIN_EXPOSURE_COARSE 0x00000001 | ||
88 | #define OV9281_MAX_EXPOSURE_COARSE 0x000FFFFF | ||
89 | #define OV9281_DEFAULT_EXPOSURE_COARSE 0x00002A90 | ||
90 | |||
91 | #define OV9281_DEFAULT_MODE OV9281_MODE_1280X800 | ||
92 | #define OV9281_DEFAULT_WIDTH 1280 | ||
93 | #define OV9281_DEFAULT_HEIGHT 800 | ||
94 | #define OV9281_DEFAULT_DATAFMT MEDIA_BUS_FMT_SRGGB10_1X10 | ||
95 | #define OV9281_DEFAULT_CLK_FREQ 26000000 | ||
96 | |||
97 | #define OV9281_DEFAULT_I2C_ADDRESS_C0 (0xc0 >> 1) | ||
98 | #define OV9281_DEFAULT_I2C_ADDRESS_20 (0x20 >> 1) | ||
99 | #define OV9281_DEFAULT_I2C_ADDRESS_PROGRAMMABLE (0xe0 >> 1) | ||
100 | |||
101 | struct ov9281 { | ||
102 | struct camera_common_power_rail power; | ||
103 | int num_ctrls; | ||
104 | int fsync; | ||
105 | int cam_sid_gpio; | ||
106 | int mcu_boot_gpio; | ||
107 | int mcu_reset_gpio; | ||
108 | struct v4l2_ctrl_handler ctrl_handler; | ||
109 | struct i2c_client *i2c_client; | ||
110 | struct v4l2_subdev *subdev; | ||
111 | struct media_pad pad; | ||
112 | |||
113 | s32 group_hold_prev; | ||
114 | bool group_hold_en; | ||
115 | struct regmap *regmap; | ||
116 | struct camera_common_data *s_data; | ||
117 | struct camera_common_pdata *pdata; | ||
118 | struct v4l2_ctrl *ctrls[]; | ||
119 | }; | ||
120 | |||
121 | /* Register/regmap stuff */ | ||
122 | static int ov9281_read_reg(struct camera_common_data *s_data, u16 addr, u8 *val) | ||
123 | { | ||
124 | struct ov9281 *priv = (struct ov9281 *)s_data->priv; | ||
125 | unsigned int temp_val; | ||
126 | int err; | ||
127 | |||
128 | err = regmap_read(priv->regmap, addr, &temp_val); | ||
129 | if (!err) | ||
130 | *val = temp_val; | ||
131 | |||
132 | return err; | ||
133 | } | ||
134 | |||
135 | static int ov9281_write_reg(struct camera_common_data *s_data, u16 addr, u8 val) | ||
136 | { | ||
137 | struct ov9281 *priv = (struct ov9281 *)s_data->priv; | ||
138 | int err; | ||
139 | |||
140 | err = regmap_write(priv->regmap, addr, val); | ||
141 | if (err) | ||
142 | dev_err(&priv->i2c_client->dev, | ||
143 | "%s:i2c write failed, %x = %x\n", __func__, addr, val); | ||
144 | |||
145 | return err; | ||
146 | } | ||
147 | |||
148 | static int ov9281_write_table(struct ov9281 *priv, const ov9281_reg table[]) | ||
149 | { | ||
150 | return regmap_util_write_table_8(priv->regmap, table, NULL, 0, | ||
151 | OV9281_TABLE_WAIT_MS, | ||
152 | OV9281_TABLE_END); | ||
153 | } | ||
154 | |||
155 | static const struct regmap_config ov9281_regmap_config = { | ||
156 | .reg_bits = 16, | ||
157 | .val_bits = 8, | ||
158 | .cache_type = REGCACHE_RBTREE, | ||
159 | .use_single_rw = true, | ||
160 | }; | ||
161 | |||
162 | /* NVIDIA camera_common stuff */ | ||
163 | static int ov9281_power_on(struct camera_common_data *s_data) | ||
164 | { | ||
165 | struct ov9281 *priv = (struct ov9281 *)s_data->priv; | ||
166 | struct camera_common_power_rail *pw = &priv->power; | ||
167 | int err; | ||
168 | |||
169 | dev_dbg(&priv->i2c_client->dev, "%s: power on\n", __func__); | ||
170 | |||
171 | if (priv->pdata->power_on) { | ||
172 | err = priv->pdata->power_on(pw); | ||
173 | if (err) | ||
174 | dev_err(&priv->i2c_client->dev, "%s failed.\n", | ||
175 | __func__); | ||
176 | else | ||
177 | pw->state = SWITCH_ON; | ||
178 | return err; | ||
179 | } | ||
180 | |||
181 | usleep_range(5350, 5360); | ||
182 | pw->state = SWITCH_ON; | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static int ov9281_power_off(struct camera_common_data *s_data) | ||
187 | { | ||
188 | struct ov9281 *priv = (struct ov9281 *)s_data->priv; | ||
189 | struct camera_common_power_rail *pw = &priv->power; | ||
190 | int err = 0; | ||
191 | |||
192 | dev_dbg(&priv->i2c_client->dev, "%s: power off\n", __func__); | ||
193 | ov9281_write_table(priv, ov9281_mode_table[OV9281_MODE_STOP_STREAM]); | ||
194 | |||
195 | if (priv->pdata->power_off) { | ||
196 | err = priv->pdata->power_off(pw); | ||
197 | if (err) | ||
198 | dev_err(&priv->i2c_client->dev, "%s failed.\n", | ||
199 | __func__); | ||
200 | else | ||
201 | goto power_off_done; | ||
202 | } | ||
203 | |||
204 | return err; | ||
205 | |||
206 | power_off_done: | ||
207 | pw->state = SWITCH_OFF; | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static int ov9281_power_put(struct ov9281 *priv) | ||
212 | { | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static int ov9281_power_get(struct ov9281 *priv) | ||
217 | { | ||
218 | struct camera_common_power_rail *pw = &priv->power; | ||
219 | const char *mclk_name; | ||
220 | int err = 0; | ||
221 | |||
222 | mclk_name = priv->pdata->mclk_name ? | ||
223 | priv->pdata->mclk_name : "cam_mclk1"; | ||
224 | pw->mclk = devm_clk_get(&priv->i2c_client->dev, mclk_name); | ||
225 | if (IS_ERR(pw->mclk)) { | ||
226 | dev_err(&priv->i2c_client->dev, | ||
227 | "unable to get clock %s\n", mclk_name); | ||
228 | return PTR_ERR(pw->mclk); | ||
229 | } | ||
230 | |||
231 | pw->state = SWITCH_OFF; | ||
232 | return err; | ||
233 | } | ||
234 | |||
235 | static struct camera_common_sensor_ops ov9281_common_ops = { | ||
236 | .power_on = ov9281_power_on, | ||
237 | .power_off = ov9281_power_off, | ||
238 | .write_reg = ov9281_write_reg, | ||
239 | .read_reg = ov9281_read_reg, | ||
240 | }; | ||
241 | |||
242 | /* Miscellaneous OV9281-specific stuff */ | ||
243 | static int ov9281_i2c_addr_assign(struct ov9281 *priv, u8 i2c_addr) | ||
244 | { | ||
245 | struct i2c_msg msg; | ||
246 | unsigned char data[3]; | ||
247 | int err; | ||
248 | |||
249 | /* | ||
250 | * I wish i2c_check_addr_validity() was available. Oh well. | ||
251 | * 7-bit address, reject the general call address | ||
252 | */ | ||
253 | if ((i2c_addr == 0x00) || (i2c_addr > 0x7f)) | ||
254 | return -EINVAL; | ||
255 | |||
256 | /* | ||
257 | * It seems that the way SID works for the OV9281 I2C slave address is | ||
258 | * that: | ||
259 | * | ||
260 | * SID 0 = 0xc0, 0xe0 | ||
261 | * SID 1 = 0x20, 0xe0 | ||
262 | * | ||
263 | * Address 0xe0 is programmable via register 0x302B | ||
264 | * (OV9281_SC_CTRL_SCCB_ID_ADDR). | ||
265 | * | ||
266 | * So, the scheme to assign addresses to an (almost) arbitrary | ||
267 | * number of sensors is to consider 0x20 to be the "off" address. | ||
268 | * Start each sensor with SID as 1 so that they appear to be off. | ||
269 | * | ||
270 | * Then, to assign an address to one sensor: | ||
271 | * | ||
272 | * 0. Set corresponding SID to 0 (now only that sensor responds | ||
273 | * to 0xc0). | ||
274 | * 1. Use 0xc0 to program the address from the default programmable | ||
275 | * address of 0xe0 to the new address. | ||
276 | * 2. Set corresponding SID back to 1 (so it no longer responds | ||
277 | * to 0xc0). | ||
278 | */ | ||
279 | |||
280 | if (i2c_addr == OV9281_DEFAULT_I2C_ADDRESS_C0) { | ||
281 | dev_info(&priv->i2c_client->dev, | ||
282 | "Using default I2C address 0x%02x\n", i2c_addr); | ||
283 | if (gpio_is_valid(priv->cam_sid_gpio)) { | ||
284 | gpio_set_value(priv->cam_sid_gpio, 0); | ||
285 | msleep_range(1); | ||
286 | } | ||
287 | return 0; | ||
288 | } else if (i2c_addr == OV9281_DEFAULT_I2C_ADDRESS_20) { | ||
289 | dev_info(&priv->i2c_client->dev, | ||
290 | "Using default I2C address 0x%02x\n", i2c_addr); | ||
291 | if (gpio_is_valid(priv->cam_sid_gpio)) { | ||
292 | gpio_set_value(priv->cam_sid_gpio, 1); | ||
293 | msleep_range(1); | ||
294 | } | ||
295 | return 0; | ||
296 | } else if (i2c_addr == OV9281_DEFAULT_I2C_ADDRESS_PROGRAMMABLE) { | ||
297 | dev_info(&priv->i2c_client->dev, | ||
298 | "Using default I2C address 0x%02x\n", i2c_addr); | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | /* | ||
303 | * From this point on, we are trying to program the programmable | ||
304 | * slave address. We necessarily need to have a cam-sid-gpio for this. | ||
305 | */ | ||
306 | if (!gpio_is_valid(priv->cam_sid_gpio)) { | ||
307 | dev_err(&priv->i2c_client->dev, | ||
308 | "Missing cam-sid-gpio, cannot program I2C address\n"); | ||
309 | return -EINVAL; | ||
310 | } | ||
311 | |||
312 | gpio_set_value(priv->cam_sid_gpio, 0); | ||
313 | msleep_range(1); | ||
314 | |||
315 | dev_info(&priv->i2c_client->dev, "Changing I2C address to 0x%02x\n", | ||
316 | i2c_addr); | ||
317 | |||
318 | /* | ||
319 | * Have to make the I2C message manually because we are using a | ||
320 | * different I2C slave address for this transaction, rather than | ||
321 | * the one in the device tree for this device. | ||
322 | */ | ||
323 | data[0] = (OV9281_SC_CTRL_SCCB_ID_ADDR >> 8) & 0xff; | ||
324 | data[1] = OV9281_SC_CTRL_SCCB_ID_ADDR & 0xff; | ||
325 | data[2] = ((i2c_addr) << 1) & 0xff; | ||
326 | |||
327 | /* | ||
328 | * Use the programmable default I2C slave address so that if we have | ||
329 | * multiple sensors of this same kind, when we change one sensor's | ||
330 | * address, the next sensor address change message won't go to that | ||
331 | * same sensor. | ||
332 | */ | ||
333 | msg.addr = OV9281_DEFAULT_I2C_ADDRESS_C0; | ||
334 | msg.flags = 0; | ||
335 | msg.len = 3; | ||
336 | msg.buf = data; | ||
337 | |||
338 | err = camera_common_s_power(priv->subdev, true); | ||
339 | if (err) | ||
340 | goto done; | ||
341 | |||
342 | if (i2c_transfer(priv->i2c_client->adapter, &msg, 1) != 1) | ||
343 | err = -EIO; | ||
344 | |||
345 | camera_common_s_power(priv->subdev, false); | ||
346 | |||
347 | done: | ||
348 | gpio_set_value(priv->cam_sid_gpio, 1); | ||
349 | msleep_range(1); | ||
350 | |||
351 | return err; | ||
352 | } | ||
353 | |||
354 | static int ov9281_set_group_hold(struct ov9281 *priv) | ||
355 | { | ||
356 | int gh_prev = switch_ctrl_qmenu[priv->group_hold_prev]; | ||
357 | int err; | ||
358 | |||
359 | if (priv->group_hold_en == true && gh_prev == SWITCH_OFF) { | ||
360 | /* group hold start */ | ||
361 | err = ov9281_write_reg(priv->s_data, OV9281_GROUP_HOLD_ADDR, | ||
362 | (OV9281_GROUP_HOLD_START | | ||
363 | OV9281_GROUP_HOLD_BANK_0)); | ||
364 | if (err) | ||
365 | goto fail; | ||
366 | priv->group_hold_prev = 1; | ||
367 | } else if (priv->group_hold_en == false && gh_prev == SWITCH_ON) { | ||
368 | /* group hold end */ | ||
369 | err = ov9281_write_reg(priv->s_data, OV9281_GROUP_HOLD_ADDR, | ||
370 | (OV9281_GROUP_HOLD_END | | ||
371 | OV9281_GROUP_HOLD_BANK_0)); | ||
372 | /* quick launch */ | ||
373 | err |= ov9281_write_reg(priv->s_data, | ||
374 | OV9281_GROUP_HOLD_ADDR, | ||
375 | (OV9281_GROUP_HOLD_LAUNCH_VBLANK | | ||
376 | OV9281_GROUP_HOLD_BANK_0)); | ||
377 | if (err) | ||
378 | goto fail; | ||
379 | priv->group_hold_prev = 0; | ||
380 | } | ||
381 | |||
382 | return 0; | ||
383 | |||
384 | fail: | ||
385 | dev_dbg(&priv->i2c_client->dev, | ||
386 | "%s: Group hold control error\n", __func__); | ||
387 | return err; | ||
388 | } | ||
389 | |||
390 | static int ov9281_set_gain(struct ov9281 *priv, s32 val) | ||
391 | { | ||
392 | ov9281_reg regs[4]; | ||
393 | u16 gain; | ||
394 | int err; | ||
395 | |||
396 | if (val < OV9281_MIN_GAIN) | ||
397 | gain = OV9281_MIN_GAIN; | ||
398 | else if (val > OV9281_MAX_GAIN) | ||
399 | gain = OV9281_MAX_GAIN; | ||
400 | else | ||
401 | gain = val; | ||
402 | |||
403 | dev_dbg(&priv->i2c_client->dev, "%s: gain: %d\n", __func__, gain); | ||
404 | |||
405 | regs[0].addr = OV9281_GAIN_SHIFT_ADDR; | ||
406 | regs[0].val = 0x03; | ||
407 | regs[1].addr = OV9281_GAIN_HIGH_ADDR; | ||
408 | regs[1].val = gain >> 8; | ||
409 | regs[2].addr = OV9281_GAIN_LOW_ADDR; | ||
410 | regs[2].val = gain & 0xff; | ||
411 | regs[3].addr = OV9281_TABLE_END; | ||
412 | regs[3].val = 0; | ||
413 | |||
414 | ov9281_set_group_hold(priv); | ||
415 | err = ov9281_write_table(priv, regs); | ||
416 | if (err) | ||
417 | goto fail; | ||
418 | |||
419 | return 0; | ||
420 | |||
421 | fail: | ||
422 | dev_dbg(&priv->i2c_client->dev, "%s: GAIN control error\n", __func__); | ||
423 | return err; | ||
424 | } | ||
425 | |||
426 | static int ov9281_set_frame_length(struct ov9281 *priv, s32 val) | ||
427 | { | ||
428 | ov9281_reg regs[5]; | ||
429 | u16 frame_length; | ||
430 | int err; | ||
431 | |||
432 | /* | ||
433 | * This is a workaround for nvbug 1865041, where setting the VTS | ||
434 | * timing registers when the sensor is set up for fsync master or | ||
435 | * slave leads to streaming instability. | ||
436 | */ | ||
437 | if (priv->fsync != OV9281_FSYNC_NONE) | ||
438 | return 0; | ||
439 | |||
440 | frame_length = (u16)val; | ||
441 | |||
442 | dev_dbg(&priv->i2c_client->dev, | ||
443 | "%s: frame_length: %d\n", __func__, frame_length); | ||
444 | |||
445 | regs[0].addr = OV9281_TIMING_VTS_HIGH_ADDR; | ||
446 | regs[0].val = (frame_length >> 8) & 0xff; | ||
447 | regs[1].addr = OV9281_TIMING_VTS_LOW_ADDR; | ||
448 | regs[1].val = (frame_length) & 0xff; | ||
449 | regs[2].addr = OV9281_TABLE_END; | ||
450 | regs[2].val = 0; | ||
451 | |||
452 | if (priv->fsync == OV9281_FSYNC_SLAVE) { | ||
453 | regs[2].addr = OV9281_TIMING_RST_FSIN_HIGH_ADDR; | ||
454 | regs[2].val = ((frame_length - 4) >> 8) & 0xff; | ||
455 | regs[3].addr = OV9281_TIMING_RST_FSIN_LOW_ADDR; | ||
456 | regs[3].val = (frame_length - 4) & 0xff; | ||
457 | regs[4].addr = OV9281_TABLE_END; | ||
458 | regs[4].val = 0; | ||
459 | } | ||
460 | |||
461 | ov9281_set_group_hold(priv); | ||
462 | err = ov9281_write_table(priv, regs); | ||
463 | if (err) | ||
464 | goto fail; | ||
465 | |||
466 | return 0; | ||
467 | |||
468 | fail: | ||
469 | dev_dbg(&priv->i2c_client->dev, | ||
470 | "%s: FRAME_LENGTH control error\n", __func__); | ||
471 | return err; | ||
472 | } | ||
473 | |||
474 | static int ov9281_set_coarse_time(struct ov9281 *priv, s32 val) | ||
475 | { | ||
476 | ov9281_reg regs[4]; | ||
477 | u32 coarse_time; | ||
478 | int err; | ||
479 | |||
480 | coarse_time = (u32)val; | ||
481 | |||
482 | dev_dbg(&priv->i2c_client->dev, | ||
483 | "%s: coarse_time: %d\n", __func__, coarse_time); | ||
484 | |||
485 | regs[0].addr = OV9281_EXPO_HIGH_ADDR; | ||
486 | regs[0].val = (coarse_time >> 16) & 0xff; | ||
487 | regs[1].addr = OV9281_EXPO_MID_ADDR; | ||
488 | regs[1].val = (coarse_time >> 8) & 0xff; | ||
489 | regs[2].addr = OV9281_EXPO_LOW_ADDR; | ||
490 | regs[2].val = (coarse_time & 0xff); | ||
491 | regs[3].addr = OV9281_TABLE_END; | ||
492 | regs[3].val = 0; | ||
493 | |||
494 | ov9281_set_group_hold(priv); | ||
495 | err = ov9281_write_table(priv, regs); | ||
496 | if (err) | ||
497 | goto fail; | ||
498 | |||
499 | return 0; | ||
500 | |||
501 | fail: | ||
502 | dev_dbg(&priv->i2c_client->dev, | ||
503 | "%s: COARSE_TIME control error\n", __func__); | ||
504 | return err; | ||
505 | } | ||
506 | |||
507 | /* OTP stuff */ | ||
508 | static int ov9281_read_otp(struct ov9281 *priv, u8 *buf, u16 addr, int size) | ||
509 | { | ||
510 | int i; | ||
511 | int err; | ||
512 | |||
513 | err = ov9281_write_reg(priv->s_data, OV9281_SC_MODE_SELECT_ADDR, | ||
514 | OV9281_SC_MODE_SELECT_STREAMING); | ||
515 | if (err) | ||
516 | return err; | ||
517 | |||
518 | for (i = 0; i < size; i++) { | ||
519 | err = ov9281_write_reg(priv->s_data, addr + i, 0x00); | ||
520 | if (err) | ||
521 | return err; | ||
522 | } | ||
523 | |||
524 | err = ov9281_write_reg(priv->s_data, OV9281_OTP_LOAD_CTRL_ADDR, | ||
525 | OV9281_OTP_LOAD_CTRL_OTP_RD); | ||
526 | |||
527 | msleep(20); | ||
528 | |||
529 | return regmap_bulk_read(priv->regmap, addr, buf, size); | ||
530 | } | ||
531 | |||
532 | static int ov9281_otp_setup(struct ov9281 *priv) | ||
533 | { | ||
534 | struct v4l2_ctrl *ctrl; | ||
535 | u8 otp_buf[OV9281_OTP_BUFFER_SIZE]; | ||
536 | int i; | ||
537 | int err; | ||
538 | |||
539 | err = camera_common_s_power(priv->subdev, true); | ||
540 | if (err) | ||
541 | return -ENODEV; | ||
542 | |||
543 | err = ov9281_read_otp(priv, otp_buf, OV9281_OTP_BUFFER_ADDR, | ||
544 | OV9281_OTP_BUFFER_SIZE); | ||
545 | if (err) | ||
546 | return err; | ||
547 | |||
548 | ctrl = v4l2_ctrl_find(&priv->ctrl_handler, V4L2_CID_OTP_DATA); | ||
549 | if (!ctrl) { | ||
550 | dev_err(&priv->i2c_client->dev, | ||
551 | "could not find device ctrl.\n"); | ||
552 | return -EINVAL; | ||
553 | } | ||
554 | |||
555 | for (i = 0; i < OV9281_OTP_BUFFER_SIZE; i++) | ||
556 | sprintf(&ctrl->p_new.p_char[i*2], "%02x", otp_buf[i]); | ||
557 | ctrl->p_cur.p_char = ctrl->p_new.p_char; | ||
558 | |||
559 | err = camera_common_s_power(priv->subdev, false); | ||
560 | if (err) | ||
561 | return -ENODEV; | ||
562 | |||
563 | return 0; | ||
564 | } | ||
565 | |||
566 | static int ov9281_fuse_id_setup(struct ov9281 *priv) | ||
567 | { | ||
568 | struct v4l2_ctrl *ctrl; | ||
569 | u8 fuse_id[OV9281_FUSE_ID_OTP_BUFFER_SIZE]; | ||
570 | int i; | ||
571 | int err; | ||
572 | |||
573 | err = camera_common_s_power(priv->subdev, true); | ||
574 | if (err) | ||
575 | return -ENODEV; | ||
576 | |||
577 | err = ov9281_read_otp(priv, fuse_id, OV9281_FUSE_ID_OTP_BUFFER_ADDR, | ||
578 | OV9281_FUSE_ID_OTP_BUFFER_SIZE); | ||
579 | if (err) | ||
580 | return err; | ||
581 | |||
582 | ctrl = v4l2_ctrl_find(&priv->ctrl_handler, V4L2_CID_FUSE_ID); | ||
583 | if (!ctrl) { | ||
584 | dev_err(&priv->i2c_client->dev, | ||
585 | "could not find device ctrl.\n"); | ||
586 | return -EINVAL; | ||
587 | } | ||
588 | |||
589 | for (i = 0; i < OV9281_FUSE_ID_OTP_BUFFER_SIZE; i++) | ||
590 | sprintf(&ctrl->p_new.p_char[i*2], "%02x", fuse_id[i]); | ||
591 | ctrl->p_cur.p_char = ctrl->p_new.p_char; | ||
592 | |||
593 | err = camera_common_s_power(priv->subdev, false); | ||
594 | if (err) | ||
595 | return -ENODEV; | ||
596 | |||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | /* V4L2 subdev stuff */ | ||
601 | static int ov9281_s_stream(struct v4l2_subdev *sd, int enable) | ||
602 | { | ||
603 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
604 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
605 | struct ov9281 *priv = (struct ov9281 *)s_data->priv; | ||
606 | struct v4l2_control control; | ||
607 | int err; | ||
608 | |||
609 | if (!enable) { | ||
610 | dev_dbg(&client->dev, "%s: stream off\n", __func__); | ||
611 | return ov9281_write_table(priv, | ||
612 | ov9281_mode_table[OV9281_MODE_STOP_STREAM]); | ||
613 | } | ||
614 | |||
615 | dev_dbg(&client->dev, "%s: write mode table %d\n", __func__, | ||
616 | s_data->mode); | ||
617 | err = ov9281_write_table(priv, ov9281_mode_table[s_data->mode]); | ||
618 | if (err) | ||
619 | goto exit; | ||
620 | |||
621 | if (ov9281_fsync_table[priv->fsync]) { | ||
622 | dev_dbg(&client->dev, "%s: write fsync table %d\n", __func__, | ||
623 | priv->fsync); | ||
624 | err = ov9281_write_table(priv, ov9281_fsync_table[priv->fsync]); | ||
625 | if (err) | ||
626 | goto exit; | ||
627 | } | ||
628 | |||
629 | if (s_data->override_enable) { | ||
630 | /* write list of override regs for the asking frame length, */ | ||
631 | /* coarse integration time, and gain. Failures to write */ | ||
632 | /* overrides are non-fatal. */ | ||
633 | control.id = V4L2_CID_GAIN; | ||
634 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
635 | err |= ov9281_set_gain(priv, control.value); | ||
636 | if (err) | ||
637 | dev_warn(&client->dev, | ||
638 | "%s: error gain override\n", __func__); | ||
639 | |||
640 | control.id = V4L2_CID_FRAME_LENGTH; | ||
641 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
642 | err |= ov9281_set_frame_length(priv, control.value); | ||
643 | if (err) | ||
644 | dev_warn(&client->dev, | ||
645 | "%s: error frame length override\n", __func__); | ||
646 | |||
647 | control.id = V4L2_CID_COARSE_TIME; | ||
648 | err = v4l2_g_ctrl(&priv->ctrl_handler, &control); | ||
649 | err |= ov9281_set_coarse_time(priv, control.value); | ||
650 | if (err) | ||
651 | dev_warn(&client->dev, | ||
652 | "%s: error coarse time override\n", __func__); | ||
653 | } | ||
654 | |||
655 | #ifdef TPG | ||
656 | err = ov9281_write_reg(priv->s_data, OV9281_PRE_CTRL00_ADDR, | ||
657 | OV9281_PRE_CTRL00_TEST_PATTERN_EN); | ||
658 | if (err) | ||
659 | dev_warn(&client->dev, "%s: error enabling TPG\n", __func__); | ||
660 | #endif | ||
661 | |||
662 | dev_dbg(&client->dev, "%s: stream on\n", __func__); | ||
663 | err = ov9281_write_table(priv, | ||
664 | ov9281_mode_table[OV9281_MODE_START_STREAM]); | ||
665 | if (err) | ||
666 | goto exit; | ||
667 | |||
668 | /* | ||
669 | * If the sensor is in fsync slave mode, and is in the middle of | ||
670 | * sending a frame when it gets a strobe on the fsin pin, it may | ||
671 | * prematurely end the frame, resulting in a short frame on our | ||
672 | * camera host. So, after starting streaming, we assume fsync | ||
673 | * master has already been told to start streaming, and we wait some | ||
674 | * amount of time in order to skip the possible short frame. The | ||
675 | * length of time to wait should be at least our sample period. | ||
676 | * Assume worse case of 120fps (8.3ms), and add a bit more. | ||
677 | */ | ||
678 | if (priv->fsync == OV9281_FSYNC_SLAVE) | ||
679 | msleep_range(10); | ||
680 | |||
681 | return 0; | ||
682 | |||
683 | exit: | ||
684 | dev_err(&client->dev, "%s: error setting stream\n", __func__); | ||
685 | return err; | ||
686 | } | ||
687 | |||
688 | static int ov9281_g_input_status(struct v4l2_subdev *sd, u32 *status) | ||
689 | { | ||
690 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
691 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
692 | struct ov9281 *priv = (struct ov9281 *)s_data->priv; | ||
693 | struct camera_common_power_rail *pw = &priv->power; | ||
694 | |||
695 | *status = pw->state == SWITCH_ON; | ||
696 | return 0; | ||
697 | } | ||
698 | |||
699 | static int ov9281_set_fmt(struct v4l2_subdev *sd, | ||
700 | struct v4l2_subdev_pad_config *cfg, | ||
701 | struct v4l2_subdev_format *format) | ||
702 | { | ||
703 | int err; | ||
704 | |||
705 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) | ||
706 | err = camera_common_try_fmt(sd, &format->format); | ||
707 | else | ||
708 | err = camera_common_s_fmt(sd, &format->format); | ||
709 | |||
710 | return err; | ||
711 | } | ||
712 | |||
713 | static int ov9281_get_fmt(struct v4l2_subdev *sd, | ||
714 | struct v4l2_subdev_pad_config *cfg, | ||
715 | struct v4l2_subdev_format *format) | ||
716 | { | ||
717 | return camera_common_g_fmt(sd, &format->format); | ||
718 | } | ||
719 | |||
720 | static struct v4l2_subdev_core_ops ov9281_subdev_core_ops = { | ||
721 | .s_power = camera_common_s_power, | ||
722 | }; | ||
723 | |||
724 | static struct v4l2_subdev_video_ops ov9281_subdev_video_ops = { | ||
725 | .s_stream = ov9281_s_stream, | ||
726 | .g_mbus_config = camera_common_g_mbus_config, | ||
727 | .g_input_status = ov9281_g_input_status, | ||
728 | }; | ||
729 | |||
730 | static struct v4l2_subdev_pad_ops ov9281_subdev_pad_ops = { | ||
731 | .set_fmt = ov9281_set_fmt, | ||
732 | .get_fmt = ov9281_get_fmt, | ||
733 | .enum_mbus_code = camera_common_enum_mbus_code, | ||
734 | .enum_frame_size = camera_common_enum_framesizes, | ||
735 | .enum_frame_interval = camera_common_enum_frameintervals, | ||
736 | }; | ||
737 | |||
738 | static struct v4l2_subdev_ops ov9281_subdev_ops = { | ||
739 | .core = &ov9281_subdev_core_ops, | ||
740 | .video = &ov9281_subdev_video_ops, | ||
741 | .pad = &ov9281_subdev_pad_ops, | ||
742 | }; | ||
743 | |||
744 | /* V4L2 controls stuff */ | ||
745 | static int ov9281_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | ||
746 | { | ||
747 | struct ov9281 *priv = | ||
748 | container_of(ctrl->handler, struct ov9281, ctrl_handler); | ||
749 | int err = 0; | ||
750 | |||
751 | if (priv->power.state == SWITCH_OFF) | ||
752 | return 0; | ||
753 | |||
754 | switch (ctrl->id) { | ||
755 | default: | ||
756 | dev_err(&priv->i2c_client->dev, | ||
757 | "%s: unknown ctrl id.\n", __func__); | ||
758 | return -EINVAL; | ||
759 | } | ||
760 | |||
761 | return err; | ||
762 | } | ||
763 | |||
764 | static int ov9281_s_ctrl(struct v4l2_ctrl *ctrl) | ||
765 | { | ||
766 | struct ov9281 *priv = | ||
767 | container_of(ctrl->handler, struct ov9281, ctrl_handler); | ||
768 | int err = 0; | ||
769 | |||
770 | if (priv->power.state == SWITCH_OFF) | ||
771 | return 0; | ||
772 | |||
773 | switch (ctrl->id) { | ||
774 | case V4L2_CID_GAIN: | ||
775 | err = ov9281_set_gain(priv, ctrl->val); | ||
776 | break; | ||
777 | case V4L2_CID_FRAME_LENGTH: | ||
778 | err = ov9281_set_frame_length(priv, ctrl->val); | ||
779 | break; | ||
780 | case V4L2_CID_COARSE_TIME: | ||
781 | err = ov9281_set_coarse_time(priv, ctrl->val); | ||
782 | break; | ||
783 | case V4L2_CID_GROUP_HOLD: | ||
784 | if (switch_ctrl_qmenu[ctrl->val] == SWITCH_ON) { | ||
785 | priv->group_hold_en = true; | ||
786 | } else { | ||
787 | priv->group_hold_en = false; | ||
788 | err = ov9281_set_group_hold(priv); | ||
789 | } | ||
790 | break; | ||
791 | case V4L2_CID_HDR_EN: | ||
792 | break; | ||
793 | default: | ||
794 | dev_err(&priv->i2c_client->dev, "%s: unknown ctrl id.\n", | ||
795 | __func__); | ||
796 | return -EINVAL; | ||
797 | } | ||
798 | |||
799 | return err; | ||
800 | } | ||
801 | |||
802 | static const struct v4l2_ctrl_ops ov9281_ctrl_ops = { | ||
803 | .g_volatile_ctrl = ov9281_g_volatile_ctrl, | ||
804 | .s_ctrl = ov9281_s_ctrl, | ||
805 | }; | ||
806 | |||
807 | static struct v4l2_ctrl_config ctrl_config_list[] = { | ||
808 | /* Do not change the name field for the controls! */ | ||
809 | { | ||
810 | .ops = &ov9281_ctrl_ops, | ||
811 | .id = V4L2_CID_GAIN, | ||
812 | .name = "Gain", | ||
813 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
814 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
815 | .min = OV9281_MIN_GAIN, | ||
816 | .max = OV9281_MAX_GAIN, | ||
817 | .def = OV9281_DEFAULT_GAIN, | ||
818 | .step = 1, | ||
819 | }, | ||
820 | { | ||
821 | .ops = &ov9281_ctrl_ops, | ||
822 | .id = V4L2_CID_FRAME_LENGTH, | ||
823 | .name = "Frame Length", | ||
824 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
825 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
826 | .min = OV9281_MIN_FRAME_LENGTH, | ||
827 | .max = OV9281_MAX_FRAME_LENGTH, | ||
828 | .def = OV9281_DEFAULT_FRAME_LENGTH, | ||
829 | .step = 1, | ||
830 | }, | ||
831 | { | ||
832 | .ops = &ov9281_ctrl_ops, | ||
833 | .id = V4L2_CID_COARSE_TIME, | ||
834 | .name = "Coarse Time", | ||
835 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
836 | .flags = V4L2_CTRL_FLAG_SLIDER, | ||
837 | .min = OV9281_MIN_EXPOSURE_COARSE, | ||
838 | .max = OV9281_MAX_EXPOSURE_COARSE, | ||
839 | .def = OV9281_DEFAULT_EXPOSURE_COARSE, | ||
840 | .step = 1, | ||
841 | }, | ||
842 | { | ||
843 | .ops = &ov9281_ctrl_ops, | ||
844 | .id = V4L2_CID_GROUP_HOLD, | ||
845 | .name = "Group Hold", | ||
846 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, | ||
847 | .min = 0, | ||
848 | .max = ARRAY_SIZE(switch_ctrl_qmenu) - 1, | ||
849 | .menu_skip_mask = 0, | ||
850 | .def = 0, | ||
851 | .qmenu_int = switch_ctrl_qmenu, | ||
852 | }, | ||
853 | { | ||
854 | .ops = &ov9281_ctrl_ops, | ||
855 | .id = V4L2_CID_HDR_EN, | ||
856 | .name = "HDR enable", | ||
857 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, | ||
858 | .min = 0, | ||
859 | .max = ARRAY_SIZE(switch_ctrl_qmenu) - 1, | ||
860 | .menu_skip_mask = 0, | ||
861 | .def = 0, | ||
862 | .qmenu_int = switch_ctrl_qmenu, | ||
863 | }, | ||
864 | { | ||
865 | .ops = &ov9281_ctrl_ops, | ||
866 | .id = V4L2_CID_OTP_DATA, | ||
867 | .name = "OTP Data", | ||
868 | .type = V4L2_CTRL_TYPE_STRING, | ||
869 | .flags = V4L2_CTRL_FLAG_READ_ONLY, | ||
870 | .min = 0, | ||
871 | .max = OV9281_OTP_STR_SIZE, | ||
872 | .step = 2, | ||
873 | }, | ||
874 | { | ||
875 | .ops = &ov9281_ctrl_ops, | ||
876 | .id = V4L2_CID_FUSE_ID, | ||
877 | .name = "Fuse ID", | ||
878 | .type = V4L2_CTRL_TYPE_STRING, | ||
879 | .flags = V4L2_CTRL_FLAG_READ_ONLY, | ||
880 | .min = 0, | ||
881 | .max = OV9281_FUSE_ID_STR_SIZE, | ||
882 | .step = 2, | ||
883 | }, | ||
884 | }; | ||
885 | |||
886 | static int ov9281_ctrls_init(struct ov9281 *priv) | ||
887 | { | ||
888 | struct i2c_client *client = priv->i2c_client; | ||
889 | struct v4l2_ctrl *ctrl; | ||
890 | int num_ctrls; | ||
891 | int i; | ||
892 | int err; | ||
893 | |||
894 | dev_dbg(&client->dev, "%s++\n", __func__); | ||
895 | |||
896 | num_ctrls = ARRAY_SIZE(ctrl_config_list); | ||
897 | v4l2_ctrl_handler_init(&priv->ctrl_handler, num_ctrls); | ||
898 | |||
899 | for (i = 0; i < num_ctrls; i++) { | ||
900 | ctrl = v4l2_ctrl_new_custom(&priv->ctrl_handler, | ||
901 | &ctrl_config_list[i], NULL); | ||
902 | if (ctrl == NULL) { | ||
903 | dev_err(&client->dev, "Failed to init %s ctrl\n", | ||
904 | ctrl_config_list[i].name); | ||
905 | continue; | ||
906 | } | ||
907 | |||
908 | if (ctrl_config_list[i].type == V4L2_CTRL_TYPE_STRING && | ||
909 | ctrl_config_list[i].flags & V4L2_CTRL_FLAG_READ_ONLY) { | ||
910 | ctrl->p_new.p_char = devm_kzalloc(&client->dev, | ||
911 | ctrl_config_list[i].max + 1, GFP_KERNEL); | ||
912 | } | ||
913 | priv->ctrls[i] = ctrl; | ||
914 | } | ||
915 | |||
916 | priv->num_ctrls = num_ctrls; | ||
917 | priv->subdev->ctrl_handler = &priv->ctrl_handler; | ||
918 | if (priv->ctrl_handler.error) { | ||
919 | dev_err(&client->dev, "Error %d adding controls\n", | ||
920 | priv->ctrl_handler.error); | ||
921 | err = priv->ctrl_handler.error; | ||
922 | goto error; | ||
923 | } | ||
924 | |||
925 | err = v4l2_ctrl_handler_setup(&priv->ctrl_handler); | ||
926 | if (err) { | ||
927 | dev_err(&client->dev, | ||
928 | "Error %d setting default controls\n", err); | ||
929 | goto error; | ||
930 | } | ||
931 | |||
932 | return 0; | ||
933 | |||
934 | error: | ||
935 | v4l2_ctrl_handler_free(&priv->ctrl_handler); | ||
936 | return err; | ||
937 | } | ||
938 | |||
939 | static const struct media_entity_operations ov9281_media_ops = { | ||
940 | .link_validate = v4l2_subdev_link_validate, | ||
941 | }; | ||
942 | |||
943 | /* Driver probe helper stuff */ | ||
944 | static int ov9281_parse_dt(struct i2c_client *client, struct ov9281 *priv) | ||
945 | { | ||
946 | struct device_node *np = client->dev.of_node; | ||
947 | const char *fsync_str; | ||
948 | int gpio; | ||
949 | int err; | ||
950 | |||
951 | err = of_property_read_string(np, "mclk", &priv->pdata->mclk_name); | ||
952 | if (err) { | ||
953 | dev_err(&client->dev, "mclk not in DT\n"); | ||
954 | return -EINVAL; | ||
955 | } | ||
956 | |||
957 | err = of_property_read_string(np, "fsync", &fsync_str); | ||
958 | if (!err && fsync_str && (strcmp(fsync_str, "master") == 0)) | ||
959 | priv->fsync = OV9281_FSYNC_MASTER; | ||
960 | else if (!err && fsync_str && (strcmp(fsync_str, "slave") == 0)) | ||
961 | priv->fsync = OV9281_FSYNC_SLAVE; | ||
962 | else | ||
963 | priv->fsync = OV9281_FSYNC_NONE; | ||
964 | |||
965 | gpio = of_get_named_gpio(np, "pwdn-gpios", 0); | ||
966 | if (!gpio_is_valid(gpio)) { | ||
967 | dev_dbg(&client->dev, "pwdn gpios not in DT\n"); | ||
968 | gpio = 0; | ||
969 | } | ||
970 | priv->pdata->pwdn_gpio = (unsigned int)gpio; | ||
971 | |||
972 | gpio = of_get_named_gpio(np, "reset-gpios", 0); | ||
973 | if (!gpio_is_valid(gpio)) { | ||
974 | dev_dbg(&client->dev, "reset gpios not in DT\n"); | ||
975 | gpio = 0; | ||
976 | } | ||
977 | priv->pdata->reset_gpio = (unsigned int)gpio; | ||
978 | |||
979 | priv->mcu_boot_gpio = | ||
980 | of_get_named_gpio(np, "mcu-boot-gpios", 0); | ||
981 | priv->mcu_reset_gpio = | ||
982 | of_get_named_gpio(np, "mcu-reset-gpios", 0); | ||
983 | |||
984 | priv->cam_sid_gpio = of_get_named_gpio(np, "cam-sid-gpios", 0); | ||
985 | |||
986 | return 0; | ||
987 | } | ||
988 | |||
989 | static int ov9281_verify_chip_id(struct ov9281 *priv) | ||
990 | { | ||
991 | struct i2c_client *client = priv->i2c_client; | ||
992 | struct camera_common_data *s_data = priv->s_data; | ||
993 | u8 chip_id_hi, chip_id_lo; | ||
994 | u16 chip_id; | ||
995 | int err; | ||
996 | |||
997 | err = camera_common_s_power(priv->subdev, true); | ||
998 | if (err) | ||
999 | return -ENODEV; | ||
1000 | |||
1001 | err = ov9281_read_reg(s_data, OV9281_SC_CHIP_ID_HIGH_ADDR, &chip_id_hi); | ||
1002 | if (err) { | ||
1003 | dev_err(&client->dev, "Failed to read chip ID\n"); | ||
1004 | return err; | ||
1005 | } | ||
1006 | err = ov9281_read_reg(s_data, OV9281_SC_CHIP_ID_LOW_ADDR, &chip_id_lo); | ||
1007 | if (err) { | ||
1008 | dev_err(&client->dev, "Failed to read chip ID\n"); | ||
1009 | return err; | ||
1010 | } | ||
1011 | |||
1012 | chip_id = (chip_id_hi << 8) | chip_id_lo; | ||
1013 | if (chip_id != 0x9281) { | ||
1014 | dev_err(&client->dev, "Read unknown chip ID 0x%04x\n", chip_id); | ||
1015 | return -EINVAL; | ||
1016 | } | ||
1017 | |||
1018 | err = camera_common_s_power(priv->subdev, false); | ||
1019 | if (err) | ||
1020 | return -ENODEV; | ||
1021 | |||
1022 | return 0; | ||
1023 | } | ||
1024 | |||
1025 | static const struct of_device_id ov9281_of_match[] = { | ||
1026 | { .compatible = "nvidia,ov9281", }, | ||
1027 | { }, | ||
1028 | }; | ||
1029 | |||
1030 | MODULE_DEVICE_TABLE(of, ov9281_of_match); | ||
1031 | |||
1032 | static int ov9281_probe(struct i2c_client *client, | ||
1033 | const struct i2c_device_id *id) | ||
1034 | { | ||
1035 | struct camera_common_data *common_data; | ||
1036 | struct ov9281 *priv; | ||
1037 | char dev_name[10]; | ||
1038 | int err; | ||
1039 | |||
1040 | dev_info(&client->dev, "Probing v4l2 sensor.\n"); | ||
1041 | |||
1042 | common_data = devm_kzalloc(&client->dev, | ||
1043 | sizeof(struct camera_common_data), | ||
1044 | GFP_KERNEL); | ||
1045 | |||
1046 | priv = devm_kzalloc(&client->dev, | ||
1047 | sizeof(struct ov9281) + | ||
1048 | (sizeof(struct v4l2_ctrl *) * | ||
1049 | ARRAY_SIZE(ctrl_config_list)), | ||
1050 | GFP_KERNEL); | ||
1051 | if (!priv) { | ||
1052 | dev_err(&client->dev, | ||
1053 | "unable to allocate camera_common_data\n"); | ||
1054 | return -ENOMEM; | ||
1055 | } | ||
1056 | |||
1057 | priv->regmap = devm_regmap_init_i2c(client, &ov9281_regmap_config); | ||
1058 | if (IS_ERR(priv->regmap)) { | ||
1059 | dev_err(&client->dev, | ||
1060 | "regmap init failed: %ld\n", PTR_ERR(priv->regmap)); | ||
1061 | return -ENODEV; | ||
1062 | } | ||
1063 | |||
1064 | priv->pdata = devm_kzalloc(&client->dev, | ||
1065 | sizeof(struct camera_common_pdata), | ||
1066 | GFP_KERNEL); | ||
1067 | if (!priv->pdata) { | ||
1068 | dev_err(&client->dev, | ||
1069 | "unable to allocate camera_common_pdata\n"); | ||
1070 | return -ENOMEM; | ||
1071 | } | ||
1072 | |||
1073 | err = ov9281_parse_dt(client, priv); | ||
1074 | if (err) | ||
1075 | return err; | ||
1076 | |||
1077 | common_data->ops = &ov9281_common_ops; | ||
1078 | common_data->ctrl_handler = &priv->ctrl_handler; | ||
1079 | common_data->i2c_client = client; | ||
1080 | common_data->frmfmt = ov9281_frmfmt; | ||
1081 | common_data->colorfmt = | ||
1082 | camera_common_find_datafmt(OV9281_DEFAULT_DATAFMT); | ||
1083 | common_data->power = &priv->power; | ||
1084 | common_data->ctrls = priv->ctrls; | ||
1085 | common_data->priv = (void *)priv; | ||
1086 | common_data->numctrls = ARRAY_SIZE(ctrl_config_list); | ||
1087 | common_data->numfmts = ARRAY_SIZE(ov9281_frmfmt); | ||
1088 | common_data->def_mode = OV9281_DEFAULT_MODE; | ||
1089 | common_data->def_width = OV9281_DEFAULT_WIDTH; | ||
1090 | common_data->def_height = OV9281_DEFAULT_HEIGHT; | ||
1091 | common_data->def_clk_freq = OV9281_DEFAULT_CLK_FREQ; | ||
1092 | common_data->fmt_width = common_data->def_width; | ||
1093 | common_data->fmt_height = common_data->def_height; | ||
1094 | |||
1095 | priv->i2c_client = client; | ||
1096 | priv->s_data = common_data; | ||
1097 | priv->subdev = &common_data->subdev; | ||
1098 | priv->subdev->dev = &client->dev; | ||
1099 | priv->group_hold_prev = 0; | ||
1100 | |||
1101 | err = ov9281_power_get(priv); | ||
1102 | if (err) | ||
1103 | return err; | ||
1104 | |||
1105 | /* | ||
1106 | * If our device tree node is given MCU GPIOs, then we are expected to | ||
1107 | * reset the MCU. | ||
1108 | */ | ||
1109 | if (gpio_is_valid(priv->mcu_boot_gpio) && | ||
1110 | gpio_is_valid(priv->mcu_reset_gpio)) { | ||
1111 | dev_info(&client->dev, "Resetting MCU\n"); | ||
1112 | gpio_set_value(priv->mcu_boot_gpio, 0); | ||
1113 | gpio_set_value(priv->mcu_reset_gpio, 0); | ||
1114 | msleep_range(1); | ||
1115 | gpio_set_value(priv->mcu_reset_gpio, 1); | ||
1116 | } | ||
1117 | |||
1118 | err = camera_common_parse_ports(client, common_data); | ||
1119 | if (err) { | ||
1120 | dev_err(&client->dev, "Failed to find port info\n"); | ||
1121 | return err; | ||
1122 | } | ||
1123 | sprintf(dev_name, "ov9281_%c", common_data->csi_port + 'a'); | ||
1124 | dev_dbg(&client->dev, "%s: name %s\n", __func__, dev_name); | ||
1125 | camera_common_create_debugfs(common_data, dev_name); | ||
1126 | |||
1127 | v4l2_i2c_subdev_init(&common_data->subdev, client, | ||
1128 | &ov9281_subdev_ops); | ||
1129 | |||
1130 | err = ov9281_ctrls_init(priv); | ||
1131 | if (err) | ||
1132 | return err; | ||
1133 | |||
1134 | err = ov9281_i2c_addr_assign(priv, client->addr); | ||
1135 | if (err) | ||
1136 | return err; | ||
1137 | |||
1138 | err = ov9281_verify_chip_id(priv); | ||
1139 | if (err) | ||
1140 | return err; | ||
1141 | |||
1142 | err = ov9281_otp_setup(priv); | ||
1143 | if (err) { | ||
1144 | dev_err(&client->dev, "Error %d reading otp data\n", err); | ||
1145 | return err; | ||
1146 | } | ||
1147 | |||
1148 | err = ov9281_fuse_id_setup(priv); | ||
1149 | if (err) { | ||
1150 | dev_err(&client->dev, "Error %d reading fuse id data\n", err); | ||
1151 | return err; | ||
1152 | } | ||
1153 | |||
1154 | priv->subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | | ||
1155 | V4L2_SUBDEV_FL_HAS_EVENTS; | ||
1156 | |||
1157 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
1158 | priv->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
1159 | priv->subdev->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; | ||
1160 | priv->subdev->entity.ops = &ov9281_media_ops; | ||
1161 | err = media_entity_init(&priv->subdev->entity, 1, &priv->pad, 0); | ||
1162 | if (err < 0) { | ||
1163 | dev_err(&client->dev, "unable to init media entity\n"); | ||
1164 | return err; | ||
1165 | } | ||
1166 | #endif | ||
1167 | |||
1168 | err = v4l2_async_register_subdev(priv->subdev); | ||
1169 | if (err) | ||
1170 | return err; | ||
1171 | |||
1172 | dev_info(&client->dev, "Probed v4l2 sensor.\n"); | ||
1173 | |||
1174 | return 0; | ||
1175 | } | ||
1176 | |||
1177 | static int | ||
1178 | ov9281_remove(struct i2c_client *client) | ||
1179 | { | ||
1180 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
1181 | struct ov9281 *priv = (struct ov9281 *)s_data->priv; | ||
1182 | |||
1183 | v4l2_async_unregister_subdev(priv->subdev); | ||
1184 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
1185 | media_entity_cleanup(&priv->subdev->entity); | ||
1186 | #endif | ||
1187 | v4l2_ctrl_handler_free(&priv->ctrl_handler); | ||
1188 | ov9281_power_put(priv); | ||
1189 | camera_common_remove_debugfs(s_data); | ||
1190 | |||
1191 | return 0; | ||
1192 | } | ||
1193 | |||
1194 | static const struct i2c_device_id ov9281_id[] = { | ||
1195 | { "ov9281", 0 }, | ||
1196 | { } | ||
1197 | }; | ||
1198 | |||
1199 | MODULE_DEVICE_TABLE(i2c, ov9281_id); | ||
1200 | |||
1201 | static struct i2c_driver ov9281_i2c_driver = { | ||
1202 | .driver = { | ||
1203 | .name = "ov9281", | ||
1204 | .owner = THIS_MODULE, | ||
1205 | .of_match_table = of_match_ptr(ov9281_of_match), | ||
1206 | }, | ||
1207 | .probe = ov9281_probe, | ||
1208 | .remove = ov9281_remove, | ||
1209 | .id_table = ov9281_id, | ||
1210 | }; | ||
1211 | |||
1212 | module_i2c_driver(ov9281_i2c_driver); | ||
1213 | |||
1214 | MODULE_DESCRIPTION("SoC Camera driver for Omnivison OV9281"); | ||
1215 | MODULE_AUTHOR("NVIDIA Corporation"); | ||
1216 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/i2c/ov9281_mode_tbls.h b/drivers/media/i2c/ov9281_mode_tbls.h new file mode 100644 index 000000000..65a86794e --- /dev/null +++ b/drivers/media/i2c/ov9281_mode_tbls.h | |||
@@ -0,0 +1,425 @@ | |||
1 | /* | ||
2 | * ov9281.c - ov9281 sensor driver | ||
3 | * | ||
4 | * Copyright (c) 2016-2017, NVIDIA CORPORATION, All Rights Reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <media/camera_common.h> | ||
20 | |||
21 | #ifndef __OV9281_I2C_TABLES__ | ||
22 | #define __OV9281_I2C_TABLES__ | ||
23 | |||
24 | #define OV9281_TABLE_WAIT_MS 0 | ||
25 | #define OV9281_TABLE_END 1 | ||
26 | |||
27 | #define ov9281_reg struct reg_8 | ||
28 | |||
29 | enum { | ||
30 | OV9281_MODE_1280X800, | ||
31 | OV9281_MODE_1280X720, | ||
32 | OV9281_MODE_640X400, | ||
33 | OV9281_MODE_START_STREAM, | ||
34 | OV9281_MODE_STOP_STREAM, | ||
35 | }; | ||
36 | |||
37 | enum { | ||
38 | OV9281_FSYNC_NONE, | ||
39 | OV9281_FSYNC_MASTER, | ||
40 | OV9281_FSYNC_SLAVE, | ||
41 | }; | ||
42 | |||
43 | static const ov9281_reg ov9281_start[] = { | ||
44 | { 0x0100, 0x01 }, | ||
45 | { OV9281_TABLE_END, 0x00 } | ||
46 | }; | ||
47 | |||
48 | static const ov9281_reg ov9281_stop[] = { | ||
49 | { 0x0100, 0x00 }, | ||
50 | { OV9281_TABLE_END, 0x00 } | ||
51 | }; | ||
52 | |||
53 | static const ov9281_reg ov9281_fsync_master[] = { | ||
54 | {0x3006, 0x02}, /* fsin pin out */ | ||
55 | {0x3823, 0x00}, | ||
56 | {OV9281_TABLE_WAIT_MS, 66}, | ||
57 | {OV9281_TABLE_END, 0x00} | ||
58 | }; | ||
59 | |||
60 | static const ov9281_reg ov9281_fsync_slave[] = { | ||
61 | {0x3006, 0x00}, /* fsin pin in */ | ||
62 | {0x3823, 0x30}, /* ext_vs_en, r_init_man */ | ||
63 | {OV9281_TABLE_WAIT_MS, 66}, | ||
64 | {OV9281_TABLE_END, 0x00} | ||
65 | }; | ||
66 | |||
67 | static const ov9281_reg ov9281_mode_1280x800_26MhzMCLK[] = { | ||
68 | /* PLL control */ | ||
69 | { 0x0302, 0x32 }, | ||
70 | { 0x030d, 0x50 }, | ||
71 | { 0x030e, 0x02 }, | ||
72 | |||
73 | /* system control */ | ||
74 | { 0x3001, 0x00 }, | ||
75 | { 0x3004, 0x00 }, | ||
76 | { 0x3005, 0x00 }, | ||
77 | { 0x3006, 0x04 }, | ||
78 | { 0x3011, 0x0a }, | ||
79 | { 0x3013, 0x18 }, | ||
80 | { 0x3022, 0x01 }, | ||
81 | { 0x3030, 0x10 }, | ||
82 | { 0x3039, 0x32 }, | ||
83 | { 0x303a, 0x00 }, | ||
84 | |||
85 | /* manual AEC/AGC */ | ||
86 | { 0x3500, 0x00 }, | ||
87 | { 0x3501, 0x2a }, | ||
88 | { 0x3502, 0x90 }, | ||
89 | { 0x3503, 0x08 }, | ||
90 | { 0x3505, 0x8c }, | ||
91 | { 0x3507, 0x03 }, | ||
92 | { 0x3508, 0x00 }, | ||
93 | { 0x3509, 0x10 }, | ||
94 | |||
95 | /* analog control */ | ||
96 | { 0x3610, 0x80 }, | ||
97 | { 0x3611, 0xa0 }, | ||
98 | { 0x3620, 0x6e }, | ||
99 | { 0x3632, 0x56 }, | ||
100 | { 0x3633, 0x78 }, | ||
101 | { 0x3662, 0x05 }, | ||
102 | { 0x3666, 0x00 }, | ||
103 | { 0x366f, 0x5a }, | ||
104 | { 0x3680, 0x84 }, | ||
105 | |||
106 | /* sensor control */ | ||
107 | { 0x3712, 0x80 }, | ||
108 | { 0x372d, 0x22 }, | ||
109 | { 0x3731, 0x80 }, | ||
110 | { 0x3732, 0x30 }, | ||
111 | { 0x3778, 0x00 }, | ||
112 | { 0x377d, 0x22 }, | ||
113 | { 0x3788, 0x02 }, | ||
114 | { 0x3789, 0xa4 }, | ||
115 | { 0x378a, 0x00 }, | ||
116 | { 0x378b, 0x4a }, | ||
117 | { 0x3799, 0x20 }, | ||
118 | |||
119 | /* timing control */ | ||
120 | { 0x3800, 0x00 }, | ||
121 | { 0x3801, 0x00 }, | ||
122 | { 0x3802, 0x00 }, | ||
123 | { 0x3803, 0x00 }, | ||
124 | { 0x3804, 0x05 }, | ||
125 | { 0x3805, 0x0f }, | ||
126 | { 0x3806, 0x03 }, | ||
127 | { 0x3807, 0x2f }, | ||
128 | { 0x3808, 0x05 }, | ||
129 | { 0x3809, 0x00 }, | ||
130 | { 0x380a, 0x03 }, | ||
131 | { 0x380b, 0x20 }, | ||
132 | { 0x380c, 0x02 }, | ||
133 | { 0x380d, 0xd8 }, | ||
134 | { 0x380e, 0x03 }, | ||
135 | { 0x380f, 0x8e }, | ||
136 | { 0x3810, 0x00 }, | ||
137 | { 0x3811, 0x08 }, | ||
138 | { 0x3812, 0x00 }, | ||
139 | { 0x3813, 0x08 }, | ||
140 | { 0x3814, 0x11 }, | ||
141 | { 0x3815, 0x11 }, | ||
142 | { 0x3820, 0x40 }, | ||
143 | { 0x3821, 0x00 }, | ||
144 | { 0x3881, 0x42 }, | ||
145 | { 0x38a8, 0x02 }, | ||
146 | { 0x38a9, 0x80 }, | ||
147 | { 0x38b1, 0x00 }, | ||
148 | { 0x38c4, 0x00 }, | ||
149 | { 0x38c5, 0xc0 }, | ||
150 | { 0x38c6, 0x04 }, | ||
151 | { 0x38c7, 0x80 }, | ||
152 | |||
153 | /* PWM and strobe control */ | ||
154 | { 0x3920, 0xff }, | ||
155 | |||
156 | /* BLC control */ | ||
157 | { 0x4003, 0x40 }, | ||
158 | { 0x4008, 0x04 }, | ||
159 | { 0x4009, 0x0b }, | ||
160 | { 0x400c, 0x00 }, | ||
161 | { 0x400d, 0x07 }, | ||
162 | { 0x4010, 0x40 }, | ||
163 | { 0x4043, 0x40 }, | ||
164 | |||
165 | /* format control */ | ||
166 | { 0x4307, 0x30 }, | ||
167 | { 0x4317, 0x00 }, | ||
168 | |||
169 | /* ???? */ | ||
170 | { 0x4501, 0x00 }, | ||
171 | { 0x4507, 0x00 }, | ||
172 | { 0x4509, 0x00 }, | ||
173 | { 0x450a, 0x08 }, | ||
174 | |||
175 | /* VFIFO control */ | ||
176 | { 0x4601, 0x04 }, | ||
177 | |||
178 | /* DVP control */ | ||
179 | { 0x470f, 0x00 }, | ||
180 | |||
181 | /* low power mode control */ | ||
182 | { 0x4f07, 0x00 }, | ||
183 | |||
184 | /* MIPI top control */ | ||
185 | { 0x4800, 0x00 }, /* bit 5: discontinuous clk */ | ||
186 | |||
187 | /* ISP top control */ | ||
188 | { 0x5000, 0x9f }, | ||
189 | { 0x5001, 0x00 }, | ||
190 | { 0x5e00, 0x00 }, | ||
191 | |||
192 | /* ???? */ | ||
193 | { 0x5d00, 0x07 }, | ||
194 | { 0x5d01, 0x00 }, | ||
195 | { OV9281_TABLE_END, 0x00} | ||
196 | }; | ||
197 | |||
198 | static const ov9281_reg ov9281_mode_1280x720_26MhzMCLK[] = { | ||
199 | { 0x0302, 0x32 }, | ||
200 | { 0x030d, 0x50 }, | ||
201 | { 0x030e, 0x02 }, | ||
202 | { 0x3001, 0x00 }, | ||
203 | { 0x3004, 0x00 }, | ||
204 | { 0x3005, 0x00 }, | ||
205 | { 0x3006, 0x04 }, | ||
206 | { 0x3011, 0x0a }, | ||
207 | { 0x3013, 0x18 }, | ||
208 | { 0x3022, 0x01 }, | ||
209 | { 0x3030, 0x10 }, | ||
210 | { 0x3039, 0x32 }, | ||
211 | { 0x303a, 0x00 }, | ||
212 | { 0x3500, 0x00 }, | ||
213 | { 0x3501, 0x2a }, | ||
214 | { 0x3502, 0x90 }, | ||
215 | { 0x3503, 0x08 }, | ||
216 | { 0x3505, 0x8c }, | ||
217 | { 0x3507, 0x03 }, | ||
218 | { 0x3508, 0x00 }, | ||
219 | { 0x3509, 0x10 }, | ||
220 | { 0x3610, 0x80 }, | ||
221 | { 0x3611, 0xa0 }, | ||
222 | { 0x3620, 0x6e }, | ||
223 | { 0x3632, 0x56 }, | ||
224 | { 0x3633, 0x78 }, | ||
225 | { 0x3662, 0x05 }, | ||
226 | { 0x3666, 0x00 }, | ||
227 | { 0x366f, 0x5a }, | ||
228 | { 0x3680, 0x84 }, | ||
229 | { 0x3712, 0x80 }, | ||
230 | { 0x372d, 0x22 }, | ||
231 | { 0x3731, 0x80 }, | ||
232 | { 0x3732, 0x30 }, | ||
233 | { 0x3778, 0x00 }, | ||
234 | { 0x377d, 0x22 }, | ||
235 | { 0x3788, 0x02 }, | ||
236 | { 0x3789, 0xa4 }, | ||
237 | { 0x378a, 0x00 }, | ||
238 | { 0x378b, 0x4a }, | ||
239 | { 0x3799, 0x20 }, | ||
240 | { 0x3800, 0x00 }, | ||
241 | { 0x3801, 0x00 }, | ||
242 | { 0x3802, 0x00 }, | ||
243 | { 0x3803, 0x28 }, | ||
244 | { 0x3804, 0x05 }, | ||
245 | { 0x3805, 0x0f }, | ||
246 | { 0x3806, 0x03 }, | ||
247 | { 0x3807, 0x07 }, | ||
248 | { 0x3808, 0x05 }, | ||
249 | { 0x3809, 0x00 }, | ||
250 | { 0x380a, 0x02 }, | ||
251 | { 0x380b, 0xd0 }, | ||
252 | { 0x380c, 0x02 }, | ||
253 | { 0x380d, 0xd8 }, | ||
254 | { 0x380e, 0x03 }, | ||
255 | { 0x380f, 0x8e }, | ||
256 | { 0x3810, 0x00 }, | ||
257 | { 0x3811, 0x08 }, | ||
258 | { 0x3812, 0x00 }, | ||
259 | { 0x3813, 0x08 }, | ||
260 | { 0x3814, 0x11 }, | ||
261 | { 0x3815, 0x11 }, | ||
262 | { 0x3820, 0x40 }, | ||
263 | { 0x3821, 0x00 }, | ||
264 | { 0x3881, 0x42 }, | ||
265 | { 0x38a8, 0x02 }, | ||
266 | { 0x38a9, 0x80 }, | ||
267 | { 0x38b1, 0x00 }, | ||
268 | { 0x38c4, 0x00 }, | ||
269 | { 0x38c5, 0xc0 }, | ||
270 | { 0x38c6, 0x04 }, | ||
271 | { 0x38c7, 0x80 }, | ||
272 | { 0x3920, 0xff }, | ||
273 | { 0x4003, 0x40 }, | ||
274 | { 0x4008, 0x04 }, | ||
275 | { 0x4009, 0x0b }, | ||
276 | { 0x400c, 0x00 }, | ||
277 | { 0x400d, 0x07 }, | ||
278 | { 0x4010, 0x40 }, | ||
279 | { 0x4043, 0x40 }, | ||
280 | { 0x4307, 0x30 }, | ||
281 | { 0x4317, 0x00 }, | ||
282 | { 0x4501, 0x00 }, | ||
283 | { 0x4507, 0x00 }, | ||
284 | { 0x4509, 0x00 }, | ||
285 | { 0x450a, 0x08 }, | ||
286 | { 0x4601, 0x04 }, | ||
287 | { 0x470f, 0x00 }, | ||
288 | { 0x4f07, 0x00 }, | ||
289 | { 0x4800, 0x00 }, | ||
290 | { 0x5000, 0x9f }, | ||
291 | { 0x5001, 0x00 }, | ||
292 | { 0x5e00, 0x00 }, | ||
293 | { 0x5d00, 0x07 }, | ||
294 | { 0x5d01, 0x00 }, | ||
295 | { OV9281_TABLE_END, 0x00} | ||
296 | }; | ||
297 | |||
298 | static const ov9281_reg ov9281_mode_640x400_26MhzMCLK[] = { | ||
299 | { 0x0302, 0x32 }, | ||
300 | { 0x030d, 0x50 }, | ||
301 | { 0x030e, 0x02 }, | ||
302 | { 0x3001, 0x00 }, | ||
303 | { 0x3004, 0x00 }, | ||
304 | { 0x3005, 0x00 }, | ||
305 | { 0x3006, 0x04 }, | ||
306 | { 0x3011, 0x0a }, | ||
307 | { 0x3013, 0x18 }, | ||
308 | { 0x3022, 0x01 }, | ||
309 | { 0x3030, 0x10 }, | ||
310 | { 0x3039, 0x32 }, | ||
311 | { 0x303a, 0x00 }, | ||
312 | { 0x3500, 0x00 }, | ||
313 | { 0x3501, 0x01 }, | ||
314 | { 0x3502, 0xf4 }, | ||
315 | { 0x3503, 0x08 }, | ||
316 | { 0x3505, 0x8c }, | ||
317 | { 0x3507, 0x03 }, | ||
318 | { 0x3508, 0x00 }, | ||
319 | { 0x3509, 0x10 }, | ||
320 | { 0x3610, 0x80 }, | ||
321 | { 0x3611, 0xa0 }, | ||
322 | { 0x3620, 0x6e }, | ||
323 | { 0x3632, 0x56 }, | ||
324 | { 0x3633, 0x78 }, | ||
325 | { 0x3662, 0x05 }, | ||
326 | { 0x3666, 0x00 }, | ||
327 | { 0x366f, 0x5a }, | ||
328 | { 0x3680, 0x84 }, | ||
329 | { 0x3712, 0x80 }, | ||
330 | { 0x372d, 0x22 }, | ||
331 | { 0x3731, 0x80 }, | ||
332 | { 0x3732, 0x30 }, | ||
333 | { 0x3778, 0x10 }, | ||
334 | { 0x377d, 0x22 }, | ||
335 | { 0x3788, 0x02 }, | ||
336 | { 0x3789, 0xa4 }, | ||
337 | { 0x378a, 0x00 }, | ||
338 | { 0x378b, 0x4a }, | ||
339 | { 0x3799, 0x20 }, | ||
340 | { 0x3800, 0x00 }, | ||
341 | { 0x3801, 0x00 }, | ||
342 | { 0x3802, 0x00 }, | ||
343 | { 0x3803, 0x00 }, | ||
344 | { 0x3804, 0x05 }, | ||
345 | { 0x3805, 0x0f }, | ||
346 | { 0x3806, 0x03 }, | ||
347 | { 0x3807, 0x2f }, | ||
348 | { 0x3808, 0x02 }, | ||
349 | { 0x3809, 0x80 }, | ||
350 | { 0x380a, 0x01 }, | ||
351 | { 0x380b, 0x90 }, | ||
352 | { 0x380c, 0x02 }, | ||
353 | { 0x380d, 0xd8 }, | ||
354 | { 0x380e, 0x02 }, | ||
355 | { 0x380f, 0x08 }, | ||
356 | { 0x3810, 0x00 }, | ||
357 | { 0x3811, 0x04 }, | ||
358 | { 0x3812, 0x00 }, | ||
359 | { 0x3813, 0x04 }, | ||
360 | { 0x3814, 0x31 }, | ||
361 | { 0x3815, 0x22 }, | ||
362 | { 0x3820, 0x60 }, | ||
363 | { 0x3821, 0x01 }, | ||
364 | { 0x3881, 0x42 }, | ||
365 | { 0x38a8, 0x02 }, | ||
366 | { 0x38a9, 0x80 }, | ||
367 | { 0x38b1, 0x00 }, | ||
368 | { 0x38c4, 0x00 }, | ||
369 | { 0x38c5, 0xc0 }, | ||
370 | { 0x38c6, 0x04 }, | ||
371 | { 0x38c7, 0x80 }, | ||
372 | { 0x3920, 0xff }, | ||
373 | { 0x4003, 0x40 }, | ||
374 | { 0x4008, 0x02 }, | ||
375 | { 0x4009, 0x05 }, | ||
376 | { 0x400c, 0x00 }, | ||
377 | { 0x400d, 0x03 }, | ||
378 | { 0x4010, 0x40 }, | ||
379 | { 0x4043, 0x40 }, | ||
380 | { 0x4307, 0x30 }, | ||
381 | { 0x4317, 0x00 }, | ||
382 | { 0x4501, 0x00 }, | ||
383 | { 0x4507, 0x03 }, | ||
384 | { 0x4509, 0x80 }, | ||
385 | { 0x450a, 0x08 }, | ||
386 | { 0x4601, 0x04 }, | ||
387 | { 0x470f, 0x00 }, | ||
388 | { 0x4f07, 0x00 }, | ||
389 | { 0x4800, 0x00 }, | ||
390 | { 0x5000, 0x9f }, | ||
391 | { 0x5001, 0x00 }, | ||
392 | { 0x5e00, 0x00 }, | ||
393 | { 0x5d00, 0x07 }, | ||
394 | { 0x5d01, 0x00 }, | ||
395 | { OV9281_TABLE_END, 0x00 } | ||
396 | }; | ||
397 | |||
398 | static const ov9281_reg *ov9281_mode_table[] = { | ||
399 | [OV9281_MODE_1280X800] = ov9281_mode_1280x800_26MhzMCLK, | ||
400 | [OV9281_MODE_1280X720] = ov9281_mode_1280x720_26MhzMCLK, | ||
401 | [OV9281_MODE_640X400] = ov9281_mode_640x400_26MhzMCLK, | ||
402 | [OV9281_MODE_START_STREAM] = ov9281_start, | ||
403 | [OV9281_MODE_STOP_STREAM] = ov9281_stop, | ||
404 | }; | ||
405 | |||
406 | static const ov9281_reg *ov9281_fsync_table[] = { | ||
407 | [OV9281_FSYNC_NONE] = NULL, | ||
408 | [OV9281_FSYNC_MASTER] = ov9281_fsync_master, | ||
409 | [OV9281_FSYNC_SLAVE] = ov9281_fsync_slave, | ||
410 | }; | ||
411 | |||
412 | static const int ov9281_120fps[] = { | ||
413 | 120, | ||
414 | }; | ||
415 | |||
416 | static const struct camera_common_frmfmt ov9281_frmfmt[] = { | ||
417 | { { 1280, 800 }, ov9281_120fps, ARRAY_SIZE(ov9281_120fps), 0, | ||
418 | OV9281_MODE_1280X800 }, | ||
419 | { { 1280, 720 }, ov9281_120fps, ARRAY_SIZE(ov9281_120fps), 0, | ||
420 | OV9281_MODE_1280X720 }, | ||
421 | { { 640, 400 }, ov9281_120fps, ARRAY_SIZE(ov9281_120fps), 0, | ||
422 | OV9281_MODE_640X400 }, | ||
423 | }; | ||
424 | |||
425 | #endif /* __OV9281_I2C_TABLES__ */ | ||
diff --git a/drivers/media/i2c/pca9570.c b/drivers/media/i2c/pca9570.c new file mode 100644 index 000000000..e937f191c --- /dev/null +++ b/drivers/media/i2c/pca9570.c | |||
@@ -0,0 +1,367 @@ | |||
1 | /* | ||
2 | * pca9570.c - pca9570 IO Expander driver | ||
3 | * | ||
4 | * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <linux/seq_file.h> | ||
20 | #include <linux/debugfs.h> | ||
21 | #include <media/camera_common.h> | ||
22 | #include <linux/module.h> | ||
23 | |||
24 | |||
25 | #define IMX185_PCA9570_I2C_ADDR (0x24) | ||
26 | #define PCA9570_MODE_STEPS 5 | ||
27 | #define PCA9570_FORWARD 0 | ||
28 | #define PCA9570_REVERSE 1 | ||
29 | |||
30 | #define BA6208_FORWARD 0x02 | ||
31 | #define BA6208_BACKWARD 0x01 | ||
32 | #define BA6208_BREAK 0x03 | ||
33 | #define DRV8838_FORWARD 0x03 | ||
34 | #define DRV8838_BACKWARD 0x02 | ||
35 | #define DRV8838_BREAK 0x00 | ||
36 | |||
37 | enum drive_ic { | ||
38 | BA6208 = 0, | ||
39 | DRV8838, | ||
40 | }; | ||
41 | |||
42 | struct pca9570 { | ||
43 | struct i2c_client *i2c_client; | ||
44 | struct regmap *regmap; | ||
45 | const char *channel; | ||
46 | const char *drive_ic_name; | ||
47 | int drive_ic; | ||
48 | }; | ||
49 | |||
50 | static int pca9570_write_reg(struct pca9570 *priv, | ||
51 | u8 addr, u8 val) | ||
52 | { | ||
53 | struct i2c_client *i2c_client = priv->i2c_client; | ||
54 | int err; | ||
55 | |||
56 | err = regmap_write(priv->regmap, addr, val); | ||
57 | if (err) | ||
58 | dev_err(&i2c_client->dev, "%s:i2c write failed, 0x%x = %x\n", | ||
59 | __func__, addr, val); | ||
60 | |||
61 | return err; | ||
62 | } | ||
63 | |||
64 | static int pca9570_icr_move(struct pca9570 *priv, u32 direction, u32 val) | ||
65 | { | ||
66 | struct i2c_client *i2c_client = priv->i2c_client; | ||
67 | int i; | ||
68 | int steps = 0; | ||
69 | int err = 0; | ||
70 | u8 reg = 0; | ||
71 | u8 reg_forward, reg_revert, reg_brake; | ||
72 | |||
73 | switch (priv->drive_ic) { | ||
74 | case DRV8838: | ||
75 | reg_forward = DRV8838_FORWARD; | ||
76 | reg_revert = DRV8838_BACKWARD; | ||
77 | reg_brake = DRV8838_BREAK; | ||
78 | break; | ||
79 | case BA6208: | ||
80 | default: | ||
81 | reg_forward = BA6208_FORWARD; | ||
82 | reg_revert = BA6208_BACKWARD; | ||
83 | reg_brake = BA6208_BREAK; | ||
84 | break; | ||
85 | } | ||
86 | |||
87 | steps = val; | ||
88 | if (steps < 1) | ||
89 | steps = PCA9570_MODE_STEPS; | ||
90 | |||
91 | if (direction == PCA9570_FORWARD) { | ||
92 | dev_info(&i2c_client->dev, "%s, forward val=%d\n", | ||
93 | __func__, steps); | ||
94 | reg = reg_forward; | ||
95 | } else if (direction == PCA9570_REVERSE) { | ||
96 | dev_info(&i2c_client->dev, "%s, reverse val=%d\n", | ||
97 | __func__, steps); | ||
98 | reg = reg_revert; | ||
99 | } else | ||
100 | return -ENOMEM; | ||
101 | |||
102 | for (i = 0; i < steps; i++) { | ||
103 | usleep_range(1000*100, 1000*110); | ||
104 | err |= pca9570_write_reg(priv, IMX185_PCA9570_I2C_ADDR, 0x48); | ||
105 | err |= pca9570_write_reg(priv, IMX185_PCA9570_I2C_ADDR, reg); | ||
106 | usleep_range(1000*100, 1000*110); | ||
107 | err |= pca9570_write_reg(priv, IMX185_PCA9570_I2C_ADDR, 0x48); | ||
108 | err |= pca9570_write_reg(priv, IMX185_PCA9570_I2C_ADDR, | ||
109 | reg_brake); | ||
110 | } | ||
111 | if (err) | ||
112 | dev_err(&i2c_client->dev, "%s:i2c write failed\n", __func__); | ||
113 | |||
114 | return err; | ||
115 | } | ||
116 | |||
117 | |||
118 | static int pca9570_icr_daymode(struct pca9570 *priv) | ||
119 | { | ||
120 | int err = 0; | ||
121 | |||
122 | err = pca9570_icr_move(priv, PCA9570_FORWARD, PCA9570_MODE_STEPS); | ||
123 | return err; | ||
124 | } | ||
125 | |||
126 | |||
127 | static int pca9570_icr_nightmode(struct pca9570 *priv) | ||
128 | { | ||
129 | int err = 0; | ||
130 | |||
131 | err = pca9570_icr_move(priv, PCA9570_REVERSE, PCA9570_MODE_STEPS); | ||
132 | return err; | ||
133 | } | ||
134 | |||
135 | static int pca9570_stats_show(struct seq_file *s, void *data) | ||
136 | { | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int pca9570_debugfs_open(struct inode *inode, struct file *file) | ||
141 | { | ||
142 | return single_open(file, pca9570_stats_show, inode->i_private); | ||
143 | } | ||
144 | |||
145 | static ssize_t pca9570_debugfs_write(struct file *s, | ||
146 | const char __user *user_buf, | ||
147 | size_t count, loff_t *ppos) | ||
148 | { | ||
149 | struct pca9570 *priv = | ||
150 | ((struct seq_file *)s->private_data)->private; | ||
151 | struct i2c_client *i2c_client = priv->i2c_client; | ||
152 | |||
153 | char buf[255]; | ||
154 | int buf_size; | ||
155 | u32 val = 0; | ||
156 | int err = 0; | ||
157 | |||
158 | if (!user_buf || count <= 1) | ||
159 | return -EFAULT; | ||
160 | |||
161 | memset(buf, 0, sizeof(buf)); | ||
162 | buf_size = min(count, sizeof(buf) - 1); | ||
163 | if (copy_from_user(buf, user_buf, buf_size)) | ||
164 | return -EFAULT; | ||
165 | |||
166 | if (buf[0] == 'd') { | ||
167 | dev_info(&i2c_client->dev, "%s, set daymode\n", __func__); | ||
168 | err = pca9570_icr_daymode(priv); | ||
169 | if (err) | ||
170 | dev_info(&i2c_client->dev, "%s, set daymode fail\n", | ||
171 | __func__); | ||
172 | return count; | ||
173 | } | ||
174 | |||
175 | if (buf[0] == 'n') { | ||
176 | dev_info(&i2c_client->dev, "%s, set nightmode\n", __func__); | ||
177 | err = pca9570_icr_nightmode(priv); | ||
178 | if (err) | ||
179 | dev_info(&i2c_client->dev, "%s, set nightmode fail\n", | ||
180 | __func__); | ||
181 | return count; | ||
182 | } | ||
183 | |||
184 | if (sscanf(buf + 1, "0x%x", &val) == 1) | ||
185 | goto set_attr; | ||
186 | if (sscanf(buf + 1, "0X%x", &val) == 1) | ||
187 | goto set_attr; | ||
188 | if (sscanf(buf + 1, "%d", &val) == 1) | ||
189 | goto set_attr; | ||
190 | |||
191 | dev_err(&i2c_client->dev, "SYNTAX ERROR: %s\n", buf); | ||
192 | return -EFAULT; | ||
193 | |||
194 | set_attr: | ||
195 | dev_info(&i2c_client->dev, "%s, val=%c%d\n", __func__, buf[0], val); | ||
196 | switch (buf[0]) { | ||
197 | case 'f': | ||
198 | err = pca9570_icr_move(priv, PCA9570_FORWARD, val); | ||
199 | if (err) | ||
200 | dev_info(&i2c_client->dev, "%s, move forward fail\n", | ||
201 | __func__); | ||
202 | break; | ||
203 | case 'r': | ||
204 | err = pca9570_icr_move(priv, PCA9570_REVERSE, val); | ||
205 | if (err) | ||
206 | dev_info(&i2c_client->dev, "%s, move reverse fail\n", | ||
207 | __func__); | ||
208 | break; | ||
209 | } | ||
210 | |||
211 | return count; | ||
212 | } | ||
213 | |||
214 | |||
215 | static const struct file_operations pca9570_debugfs_fops = { | ||
216 | .open = pca9570_debugfs_open, | ||
217 | .read = seq_read, | ||
218 | .write = pca9570_debugfs_write, | ||
219 | .llseek = seq_lseek, | ||
220 | .release = single_release, | ||
221 | }; | ||
222 | |||
223 | static int pca9570_debugfs_init(const char *dir_name, | ||
224 | struct dentry **d_entry, | ||
225 | struct dentry **f_entry, | ||
226 | struct pca9570 *priv) | ||
227 | { | ||
228 | struct dentry *dp, *fp; | ||
229 | char dev_name[20]; | ||
230 | struct i2c_client *i2c_client = priv->i2c_client; | ||
231 | struct device_node *np = i2c_client->dev.of_node; | ||
232 | int err = 0; | ||
233 | |||
234 | if (np) { | ||
235 | err = of_property_read_string(np, "channel", &priv->channel); | ||
236 | if (err) | ||
237 | dev_err(&i2c_client->dev, "channel not found\n"); | ||
238 | snprintf(dev_name, sizeof(dev_name), "pca9570_%s", | ||
239 | priv->channel); | ||
240 | } | ||
241 | |||
242 | dp = debugfs_create_dir(dev_name, NULL); | ||
243 | if (dp == NULL) { | ||
244 | dev_err(&i2c_client->dev, "%s: debugfs create dir failed\n", | ||
245 | __func__); | ||
246 | return -ENOMEM; | ||
247 | } | ||
248 | |||
249 | fp = debugfs_create_file("pca9570", S_IRUGO|S_IWUSR, | ||
250 | dp, priv, &pca9570_debugfs_fops); | ||
251 | if (!fp) { | ||
252 | dev_err(&i2c_client->dev, "%s: debugfs create file failed\n", | ||
253 | __func__); | ||
254 | debugfs_remove_recursive(dp); | ||
255 | return -ENOMEM; | ||
256 | } | ||
257 | |||
258 | if (d_entry) | ||
259 | *d_entry = dp; | ||
260 | if (f_entry) | ||
261 | *f_entry = fp; | ||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | static struct regmap_config pca9570_regmap_config = { | ||
266 | .reg_bits = 8, | ||
267 | .val_bits = 8, | ||
268 | .cache_type = REGCACHE_RBTREE, | ||
269 | }; | ||
270 | |||
271 | static int pca9570_probe(struct i2c_client *client, | ||
272 | const struct i2c_device_id *id) | ||
273 | { | ||
274 | struct pca9570 *priv; | ||
275 | struct device_node *np = client->dev.of_node; | ||
276 | int err = 0; | ||
277 | |||
278 | priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); | ||
279 | priv->i2c_client = client; | ||
280 | priv->regmap = devm_regmap_init_i2c(priv->i2c_client, | ||
281 | &pca9570_regmap_config); | ||
282 | if (IS_ERR(priv->regmap)) { | ||
283 | dev_err(&client->dev, | ||
284 | "regmap init failed: %ld\n", PTR_ERR(priv->regmap)); | ||
285 | return -ENODEV; | ||
286 | } | ||
287 | |||
288 | err = of_property_read_string(np, "drive_ic", &priv->drive_ic_name); | ||
289 | if (!err && !IS_ERR(priv->drive_ic_name)) { | ||
290 | if (!strcmp(priv->drive_ic_name, "BA6208")) | ||
291 | priv->drive_ic = BA6208; | ||
292 | else if (!strcmp(priv->drive_ic_name, "DRV8838")) | ||
293 | priv->drive_ic = DRV8838; | ||
294 | else { | ||
295 | priv->drive_ic = BA6208; | ||
296 | dev_info(&client->dev, | ||
297 | "%s, unsupport driver ic found\n", __func__); | ||
298 | } | ||
299 | } else { | ||
300 | priv->drive_ic = BA6208; | ||
301 | dev_info(&client->dev, | ||
302 | "%s, drive_ic not found\n", __func__); | ||
303 | } | ||
304 | |||
305 | err = pca9570_debugfs_init(NULL, NULL, NULL, priv); | ||
306 | if (err) | ||
307 | return err; | ||
308 | /*set daymode by fault*/ | ||
309 | err = pca9570_icr_daymode(priv); | ||
310 | if (err) | ||
311 | return err; | ||
312 | dev_info(&client->dev, "%s: success\n", __func__); | ||
313 | |||
314 | return err; | ||
315 | } | ||
316 | |||
317 | |||
318 | static int | ||
319 | pca9570_remove(struct i2c_client *client) | ||
320 | { | ||
321 | |||
322 | if (client != NULL) { | ||
323 | i2c_unregister_device(client); | ||
324 | client = NULL; | ||
325 | } | ||
326 | |||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | static const struct i2c_device_id pca9570_id[] = { | ||
331 | { "pca9570", 0 }, | ||
332 | { }, | ||
333 | }; | ||
334 | |||
335 | const struct of_device_id pca9570_of_match[] = { | ||
336 | { .compatible = "nvidia,pca9570", }, | ||
337 | { }, | ||
338 | }; | ||
339 | MODULE_DEVICE_TABLE(of, imx185_of_match); | ||
340 | MODULE_DEVICE_TABLE(i2c, pca9570_id); | ||
341 | |||
342 | static struct i2c_driver pca9570_i2c_driver = { | ||
343 | .driver = { | ||
344 | .name = "pca9570", | ||
345 | .owner = THIS_MODULE, | ||
346 | }, | ||
347 | .probe = pca9570_probe, | ||
348 | .remove = pca9570_remove, | ||
349 | .id_table = pca9570_id, | ||
350 | }; | ||
351 | |||
352 | static int __init pca9570_init(void) | ||
353 | { | ||
354 | return i2c_add_driver(&pca9570_i2c_driver); | ||
355 | } | ||
356 | |||
357 | static void __exit pca9570_exit(void) | ||
358 | { | ||
359 | i2c_del_driver(&pca9570_i2c_driver); | ||
360 | } | ||
361 | |||
362 | module_init(pca9570_init); | ||
363 | module_exit(pca9570_exit); | ||
364 | |||
365 | MODULE_DESCRIPTION("IO Expander driver pca9570"); | ||
366 | MODULE_AUTHOR("NVIDIA Corporation"); | ||
367 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/i2c/tc358840.c b/drivers/media/i2c/tc358840.c new file mode 100644 index 000000000..a545d4571 --- /dev/null +++ b/drivers/media/i2c/tc358840.c | |||
@@ -0,0 +1,2465 @@ | |||
1 | /* | ||
2 | * tc358840.c - Toshiba UH2C/D HDMI-CSI bridge driver | ||
3 | * | ||
4 | * Copyright (c) 2015, Armin Weiss <weii@zhaw.ch> | ||
5 | * Copyright (c) 2016 - 2017, NVIDIA CORPORATION. All rights reserved. | ||
6 | * | ||
7 | * This program is based on the tc358840 - Toshiba HDMI to CSI-2 bridge driver | ||
8 | * from Cisco Systems, Inc. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms and conditions of the GNU General Public License, | ||
12 | * version 2, as published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
17 | * more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
21 | */ | ||
22 | |||
23 | |||
24 | #include <linux/module.h> | ||
25 | |||
26 | #include <linux/i2c.h> | ||
27 | #include <linux/regmap.h> | ||
28 | #include <linux/regulator/consumer.h> | ||
29 | #include <linux/of_gpio.h> | ||
30 | #include <linux/of_irq.h> | ||
31 | #include <linux/interrupt.h> | ||
32 | #include <linux/videodev2.h> | ||
33 | #include <linux/workqueue.h> | ||
34 | #include <linux/delay.h> | ||
35 | #include <linux/hdmi.h> | ||
36 | #include <linux/v4l2-dv-timings.h> | ||
37 | |||
38 | #include <media/v4l2-dv-timings.h> | ||
39 | #include <media/v4l2-ctrls.h> | ||
40 | #include <media/v4l2-event.h> | ||
41 | #include <media/v4l2-device.h> | ||
42 | #include <media/v4l2-subdev.h> | ||
43 | #include <media/v4l2-of.h> | ||
44 | #include <media/camera_common.h> | ||
45 | |||
46 | #include <media/i2c/tc358840.h> | ||
47 | #include "tc358840_regs.h" | ||
48 | |||
49 | |||
50 | static int debug; | ||
51 | module_param(debug, int, 0644); | ||
52 | MODULE_PARM_DESC(debug, "debug level (0-3)"); | ||
53 | |||
54 | /* TODO: Implement Colorbar TPG */ | ||
55 | |||
56 | #define EDID_NUM_BLOCKS_MAX 8 | ||
57 | #define EDID_BLOCK_SIZE 128 | ||
58 | #define DELAY_ENABLE_INTERRUPT_MS 10000 | ||
59 | |||
60 | static u8 edid[] = { | ||
61 | 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, | ||
62 | 0x52, 0x62, 0x88, 0x88, 0x00, 0x88, 0x88, 0x88, | ||
63 | 0x1C, 0x15, 0x01, 0x03, 0x80, 0x00, 0x00, 0x78, | ||
64 | 0x0A, 0x0D, 0xC9, 0xA0, 0x57, 0x47, 0x98, 0x27, | ||
65 | 0x12, 0x48, 0x4C, 0x00, 0x00, 0x00, 0x01, 0x01, | ||
66 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | ||
67 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xEC, 0x68, | ||
68 | 0x00, 0xA0, 0xF0, 0x70, 0x37, 0x80, 0x30, 0x20, | ||
69 | 0x3A, 0x00, 0x00, 0x70, 0xF8, 0x00, 0x00, 0x1C, | ||
70 | 0x02, 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, | ||
71 | 0x58, 0x2C, 0x45, 0x00, 0xC4, 0x8E, 0x21, 0x00, | ||
72 | 0x00, 0x1E, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x54, | ||
73 | 0x6F, 0x73, 0x68, 0x69, 0x62, 0x61, 0x2D, 0x55, | ||
74 | 0x48, 0x32, 0x44, 0x0A, 0x00, 0x00, 0x00, 0xFD, | ||
75 | 0x00, 0x17, 0x3D, 0x0F, 0x8C, 0x17, 0x00, 0x0A, | ||
76 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xAF, | ||
77 | 0x02, 0x03, 0x1A, 0x74, 0x47, 0x32, 0x10, 0x04, | ||
78 | 0x32, 0x32, 0x32, 0x32, 0x23, 0x09, 0x07, 0x01, | ||
79 | 0x83, 0x01, 0x00, 0x00, 0x65, 0x03, 0x0C, 0x00, | ||
80 | 0x10, 0x00, 0x01, 0x1D, 0x00, 0x72, 0x51, 0xD0, | ||
81 | 0x1E, 0x20, 0x6E, 0x28, 0x55, 0x00, 0xC4, 0x8E, | ||
82 | 0x21, 0x00, 0x00, 0x1E, 0xEC, 0x68, 0x00, 0xA0, | ||
83 | 0xF0, 0x70, 0x37, 0x80, 0x30, 0x20, 0x3A, 0x00, | ||
84 | 0x00, 0x70, 0xF8, 0x00, 0x00, 0x1C, 0xEC, 0x68, | ||
85 | 0x00, 0xA0, 0xF0, 0x70, 0x37, 0x80, 0x30, 0x20, | ||
86 | 0x3A, 0x00, 0x00, 0x70, 0xF8, 0x00, 0x00, 0x1C, | ||
87 | 0xEC, 0x68, 0x00, 0xA0, 0xF0, 0x70, 0x37, 0x80, | ||
88 | 0x30, 0x20, 0x3A, 0x00, 0x00, 0x70, 0xF8, 0x00, | ||
89 | 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
90 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
91 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
92 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, | ||
93 | }; | ||
94 | |||
95 | static const struct v4l2_dv_timings_cap tc358840_timings_cap = { | ||
96 | .type = V4L2_DV_BT_656_1120, | ||
97 | /* keep this initialization for compatibility with GCC < 4.4.6 */ | ||
98 | .reserved = { 0 }, | ||
99 | /* Pixel clock from REF_01 p. 20. Min/max height/width are unknown */ | ||
100 | V4L2_INIT_BT_TIMINGS( | ||
101 | 1, 10000, 1, 10000, 0, 297000000, | ||
102 | V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | | ||
103 | V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, | ||
104 | V4L2_DV_BT_CAP_PROGRESSIVE | | ||
105 | V4L2_DV_BT_CAP_REDUCED_BLANKING | | ||
106 | V4L2_DV_BT_CAP_CUSTOM) | ||
107 | }; | ||
108 | |||
109 | struct tc358840_state { | ||
110 | struct tc358840_platform_data pdata; | ||
111 | struct v4l2_subdev sd; | ||
112 | struct media_pad pad[2]; | ||
113 | struct v4l2_ctrl_handler hdl; | ||
114 | struct i2c_client *i2c_client; | ||
115 | bool enabled; | ||
116 | bool format_changed; | ||
117 | |||
118 | /* controls */ | ||
119 | struct v4l2_ctrl *detect_tx_5v_ctrl; | ||
120 | struct v4l2_ctrl *audio_sampling_rate_ctrl; | ||
121 | struct v4l2_ctrl *audio_present_ctrl; | ||
122 | struct v4l2_ctrl *splitter_width_ctrl; | ||
123 | |||
124 | /* work queues */ | ||
125 | struct workqueue_struct *work_queues; | ||
126 | struct delayed_work delayed_work_enable_hotplug; | ||
127 | struct delayed_work delayed_work_enable_interrupt; | ||
128 | struct work_struct process_isr; | ||
129 | struct mutex isr_lock; | ||
130 | |||
131 | /* edid */ | ||
132 | u8 edid_blocks_written; | ||
133 | |||
134 | /* timing / mbus */ | ||
135 | struct v4l2_dv_timings timings; | ||
136 | u32 mbus_fmt_code; | ||
137 | }; | ||
138 | |||
139 | static inline struct tc358840_state *to_state(struct v4l2_subdev *sd) | ||
140 | { | ||
141 | return container_of(sd, struct tc358840_state, sd); | ||
142 | } | ||
143 | |||
144 | |||
145 | static void tc358840_enable_interrupts( | ||
146 | struct v4l2_subdev *sd, bool cable_connected); | ||
147 | static int tc358840_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd); | ||
148 | static void tc358840_init_interrupts(struct v4l2_subdev *sd); | ||
149 | static int tc358840_s_dv_timings( | ||
150 | struct v4l2_subdev *sd, struct v4l2_dv_timings *timings); | ||
151 | static void tc358840_set_csi(struct v4l2_subdev *sd); | ||
152 | static void tc358840_set_splitter(struct v4l2_subdev *sd); | ||
153 | static int tc358840_s_edid(struct v4l2_subdev *sd, | ||
154 | struct v4l2_subdev_edid *edid); | ||
155 | |||
156 | /* --------------- I2C --------------- */ | ||
157 | |||
158 | static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) | ||
159 | { | ||
160 | struct tc358840_state *state = to_state(sd); | ||
161 | struct i2c_client *client = state->i2c_client; | ||
162 | int err; | ||
163 | u8 buf[2] = { reg >> 8, reg & 0xff }; | ||
164 | struct i2c_msg msgs[] = { | ||
165 | { | ||
166 | .addr = client->addr, | ||
167 | .flags = 0, | ||
168 | .len = 2, | ||
169 | .buf = buf, | ||
170 | }, | ||
171 | { | ||
172 | .addr = client->addr, | ||
173 | .flags = I2C_M_RD, | ||
174 | .len = n, | ||
175 | .buf = values, | ||
176 | }, | ||
177 | }; | ||
178 | |||
179 | err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | ||
180 | if (err != ARRAY_SIZE(msgs)) { | ||
181 | v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed\n", | ||
182 | __func__, reg, client->addr); | ||
183 | } | ||
184 | |||
185 | if (debug < 3) | ||
186 | return; | ||
187 | |||
188 | switch (n) { | ||
189 | case 1: | ||
190 | v4l2_info(sd, "I2C read 0x%04X = 0x%02X\n", reg, values[0]); | ||
191 | break; | ||
192 | case 2: | ||
193 | v4l2_info(sd, "I2C read 0x%04X = 0x%02X%02X\n", | ||
194 | reg, values[1], values[0]); | ||
195 | break; | ||
196 | case 4: | ||
197 | v4l2_info(sd, "I2C read 0x%04X = 0x%02X%02X%02X%02X\n", | ||
198 | reg, values[3], values[2], values[1], values[0]); | ||
199 | break; | ||
200 | default: | ||
201 | v4l2_info(sd, "I2C read %d bytes from address 0x%04X\n", | ||
202 | n, reg); | ||
203 | } | ||
204 | |||
205 | } | ||
206 | |||
207 | static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) | ||
208 | { | ||
209 | struct tc358840_state *state = to_state(sd); | ||
210 | struct i2c_client *client = state->i2c_client; | ||
211 | int err, i; | ||
212 | struct i2c_msg msg; | ||
213 | u8 data[2 + n]; | ||
214 | |||
215 | msg.addr = client->addr; | ||
216 | msg.buf = data; | ||
217 | msg.len = 2 + n; | ||
218 | msg.flags = 0; | ||
219 | |||
220 | data[0] = reg >> 8; | ||
221 | data[1] = reg & 0xff; | ||
222 | |||
223 | for (i = 0; i < n; i++) | ||
224 | data[2 + i] = values[i]; | ||
225 | |||
226 | err = i2c_transfer(client->adapter, &msg, 1); | ||
227 | if (err != 1) { | ||
228 | v4l2_err(sd, "%s: writing register 0x%x from 0x%x failed\n", | ||
229 | __func__, reg, client->addr); | ||
230 | return; | ||
231 | } | ||
232 | |||
233 | if (debug < 3) | ||
234 | return; | ||
235 | |||
236 | switch (n) { | ||
237 | case 1: | ||
238 | v4l2_info(sd, "I2C write 0x%04X = 0x%02X\n", reg, data[2]); | ||
239 | break; | ||
240 | case 2: | ||
241 | v4l2_info(sd, "I2C write 0x%04X = 0x%02X%02X\n", | ||
242 | reg, data[3], data[2]); | ||
243 | break; | ||
244 | case 4: | ||
245 | v4l2_info(sd, "I2C write 0x%04X = 0x%02X%02X%02X%02X\n", | ||
246 | reg, data[5], data[4], data[3], data[2]); | ||
247 | break; | ||
248 | default: | ||
249 | v4l2_info(sd, "I2C write %d bytes from address 0x%04X\n", | ||
250 | n, reg); | ||
251 | } | ||
252 | } | ||
253 | |||
254 | static u8 i2c_rd8(struct v4l2_subdev *sd, u16 reg) | ||
255 | { | ||
256 | u8 val; | ||
257 | |||
258 | i2c_rd(sd, reg, &val, 1); | ||
259 | |||
260 | return val; | ||
261 | } | ||
262 | |||
263 | static void i2c_wr8(struct v4l2_subdev *sd, u16 reg, u8 val) | ||
264 | { | ||
265 | i2c_wr(sd, reg, &val, 1); | ||
266 | } | ||
267 | |||
268 | static void i2c_wr8_and_or(struct v4l2_subdev *sd, u16 reg, | ||
269 | u8 mask, u8 val) | ||
270 | { | ||
271 | i2c_wr8(sd, reg, (i2c_rd8(sd, reg) & mask) | val); | ||
272 | } | ||
273 | |||
274 | static u16 i2c_rd16(struct v4l2_subdev *sd, u16 reg) | ||
275 | { | ||
276 | u16 val; | ||
277 | |||
278 | i2c_rd(sd, reg, (u8 *)&val, 2); | ||
279 | |||
280 | return val; | ||
281 | } | ||
282 | |||
283 | static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val) | ||
284 | { | ||
285 | i2c_wr(sd, reg, (u8 *)&val, 2); | ||
286 | } | ||
287 | |||
288 | static void i2c_wr16_and_or(struct v4l2_subdev *sd, u16 reg, u16 mask, u16 val) | ||
289 | { | ||
290 | i2c_wr16(sd, reg, (i2c_rd16(sd, reg) & mask) | val); | ||
291 | } | ||
292 | |||
293 | static u32 i2c_rd32(struct v4l2_subdev *sd, u16 reg) | ||
294 | { | ||
295 | u32 val; | ||
296 | |||
297 | i2c_rd(sd, reg, (u8 *)&val, 4); | ||
298 | |||
299 | return val; | ||
300 | } | ||
301 | |||
302 | static void i2c_wr32(struct v4l2_subdev *sd, u16 reg, u32 val) | ||
303 | { | ||
304 | i2c_wr(sd, reg, (u8 *)&val, 4); | ||
305 | } | ||
306 | |||
307 | static void i2c_wr32_and_or(struct v4l2_subdev *sd, u32 reg, u32 mask, u32 val) | ||
308 | { | ||
309 | i2c_wr32(sd, reg, (i2c_rd32(sd, reg) & mask) | val); | ||
310 | } | ||
311 | |||
312 | /* --------------- STATUS --------------- */ | ||
313 | |||
314 | static inline bool is_hdmi(struct v4l2_subdev *sd) | ||
315 | { | ||
316 | return i2c_rd8(sd, SYS_STATUS) & MASK_S_HDMI; | ||
317 | } | ||
318 | |||
319 | static inline bool tx_5v_power_present(struct v4l2_subdev *sd) | ||
320 | { | ||
321 | return i2c_rd8(sd, SYS_STATUS) & MASK_S_DDC5V; | ||
322 | } | ||
323 | |||
324 | static inline bool no_signal(struct v4l2_subdev *sd) | ||
325 | { | ||
326 | return !(i2c_rd8(sd, SYS_STATUS) & MASK_S_TMDS); | ||
327 | } | ||
328 | |||
329 | static inline bool no_sync(struct v4l2_subdev *sd) | ||
330 | { | ||
331 | return !(i2c_rd8(sd, SYS_STATUS) & MASK_S_SYNC); | ||
332 | } | ||
333 | |||
334 | static inline bool audio_present(struct v4l2_subdev *sd) | ||
335 | { | ||
336 | return i2c_rd8(sd, AU_STATUS0) & MASK_S_A_SAMPLE; | ||
337 | } | ||
338 | |||
339 | static int get_audio_sampling_rate(struct v4l2_subdev *sd) | ||
340 | { | ||
341 | static const int code_to_rate[] = { | ||
342 | 44100, 0, 48000, 32000, 22050, 384000, 24000, 352800, | ||
343 | 88200, 768000, 96000, 705600, 176400, 0, 192000, 0 | ||
344 | }; | ||
345 | |||
346 | /* Register FS_SET is not cleared when the cable is disconnected */ | ||
347 | if (no_signal(sd)) | ||
348 | return 0; | ||
349 | |||
350 | return code_to_rate[i2c_rd8(sd, FS_SET) & MASK_FS]; | ||
351 | } | ||
352 | |||
353 | static unsigned tc358840_num_csi_lanes_in_use(struct v4l2_subdev *sd) | ||
354 | { | ||
355 | /* FIXME: Read # of lanes from both, TX0 and TX1 */ | ||
356 | return i2c_rd32(sd, CSITX0_BASE_ADDR+LANEEN) & MASK_LANES; | ||
357 | } | ||
358 | |||
359 | /* --------------- TIMINGS --------------- */ | ||
360 | |||
361 | static inline unsigned fps(const struct v4l2_bt_timings *t) | ||
362 | { | ||
363 | if (!V4L2_DV_BT_FRAME_HEIGHT(t) || !V4L2_DV_BT_FRAME_WIDTH(t)) | ||
364 | return 0; | ||
365 | |||
366 | return DIV_ROUND_CLOSEST((unsigned)t->pixelclock, | ||
367 | V4L2_DV_BT_FRAME_HEIGHT(t) * V4L2_DV_BT_FRAME_WIDTH(t)); | ||
368 | } | ||
369 | |||
370 | static int tc358840_get_detected_timings(struct v4l2_subdev *sd, | ||
371 | struct v4l2_dv_timings *timings) | ||
372 | { | ||
373 | struct v4l2_bt_timings *bt = &timings->bt; | ||
374 | unsigned width, height, frame_width, frame_height, frame_interval, fps; | ||
375 | |||
376 | memset(timings, 0, sizeof(struct v4l2_dv_timings)); | ||
377 | |||
378 | if (no_signal(sd)) { | ||
379 | v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__); | ||
380 | return -ENOLINK; | ||
381 | } | ||
382 | if (no_sync(sd)) { | ||
383 | v4l2_dbg(1, debug, sd, "%s: no sync on signal\n", __func__); | ||
384 | return -ENOLCK; | ||
385 | } | ||
386 | |||
387 | timings->type = V4L2_DV_BT_656_1120; | ||
388 | |||
389 | bt->interlaced = i2c_rd8(sd, VI_STATUS1) & | ||
390 | MASK_S_V_INTERLACE ? V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; | ||
391 | |||
392 | width = ((i2c_rd8(sd, DE_HSIZE_HI) & 0x1f) << 8) + | ||
393 | i2c_rd8(sd, DE_HSIZE_LO); | ||
394 | height = ((i2c_rd8(sd, DE_VSIZE_HI) & 0x1f) << 8) + | ||
395 | i2c_rd8(sd, DE_VSIZE_LO); | ||
396 | frame_width = ((i2c_rd8(sd, IN_HSIZE_HI) & 0x1f) << 8) + | ||
397 | i2c_rd8(sd, IN_HSIZE_LO); | ||
398 | frame_height = (((i2c_rd8(sd, IN_VSIZE_HI) & 0x3f) << 8) + | ||
399 | i2c_rd8(sd, IN_VSIZE_LO)) / 2; | ||
400 | |||
401 | /* TODO: Check if frame_interval is correct | ||
402 | * since the register is not in the datasheet rev. 1.5 */ | ||
403 | |||
404 | /* frame interval in milliseconds * 10 | ||
405 | * Require SYS_FREQ0 and SYS_FREQ1 are precisely set */ | ||
406 | frame_interval = ((i2c_rd8(sd, FV_CNT_HI) & 0x3) << 8) + | ||
407 | i2c_rd8(sd, FV_CNT_LO); | ||
408 | fps = (frame_interval > 0) ? | ||
409 | DIV_ROUND_CLOSEST(10000, frame_interval) : 0; | ||
410 | |||
411 | bt->width = width; | ||
412 | bt->height = height; | ||
413 | bt->vsync = frame_height - height; | ||
414 | bt->hsync = frame_width - width; | ||
415 | bt->pixelclock = frame_width * frame_height * fps; | ||
416 | if (bt->interlaced == V4L2_DV_INTERLACED) { | ||
417 | bt->height *= 2; | ||
418 | bt->il_vsync = bt->vsync + 1; | ||
419 | bt->pixelclock /= 2; | ||
420 | } | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | /* --------------- HOTPLUG / HDCP / EDID --------------- */ | ||
426 | |||
427 | static void tc358840_delayed_work_enable_hotplug(struct work_struct *work) | ||
428 | { | ||
429 | struct delayed_work *dwork = to_delayed_work(work); | ||
430 | struct tc358840_state *state = container_of(dwork, | ||
431 | struct tc358840_state, delayed_work_enable_hotplug); | ||
432 | struct v4l2_subdev *sd = &state->sd; | ||
433 | |||
434 | v4l2_dbg(2, debug, sd, "%s:\n", __func__); | ||
435 | |||
436 | i2c_wr8_and_or(sd, HPD_CTL, ~MASK_HPD_OUT0, MASK_HPD_OUT0); | ||
437 | } | ||
438 | |||
439 | static void tc358840_set_hdmi_hdcp(struct v4l2_subdev *sd, bool enable) | ||
440 | { | ||
441 | v4l2_dbg(2, debug, sd, "%s: %s\n", __func__, enable ? | ||
442 | "enable" : "disable"); | ||
443 | |||
444 | i2c_wr8_and_or(sd, HDCP_REG1, | ||
445 | ~(MASK_AUTH_UNAUTH_SEL | MASK_AUTH_UNAUTH), | ||
446 | MASK_AUTH_UNAUTH_SEL_16_FRAMES | MASK_AUTH_UNAUTH_AUTO); | ||
447 | |||
448 | i2c_wr8_and_or(sd, HDCP_REG2, ~MASK_AUTO_P3_RESET, | ||
449 | SET_AUTO_P3_RESET_FRAMES(0x0f)); | ||
450 | |||
451 | /* HDCP is disabled by configuring the receiver as HDCP repeater. The | ||
452 | * repeater mode require software support to work, so HDCP | ||
453 | * authentication will fail. | ||
454 | */ | ||
455 | i2c_wr8_and_or(sd, HDCP_REG3, ~KEY_RD_CMD, enable ? KEY_RD_CMD : 0); | ||
456 | i2c_wr8_and_or(sd, HDCP_MODE, ~(MASK_AUTO_CLR | MASK_MODE_RST_TN), | ||
457 | enable ? (MASK_AUTO_CLR | MASK_MODE_RST_TN) : 0); | ||
458 | |||
459 | /* Apple MacBook Pro gen.8 has a bug that makes it freeze every fifth | ||
460 | * second when HDCP is disabled, but the MAX_EXCED bit is handled | ||
461 | * correctly and HDCP is disabled on the HDMI output. | ||
462 | */ | ||
463 | i2c_wr8_and_or(sd, BSTATUS1, ~MASK_MAX_EXCED, | ||
464 | enable ? 0 : MASK_MAX_EXCED); | ||
465 | i2c_wr8_and_or(sd, BCAPS, ~(MASK_REPEATER | MASK_READY), | ||
466 | enable ? 0 : MASK_REPEATER | MASK_READY); | ||
467 | } | ||
468 | |||
469 | static void tc358840_disable_edid(struct v4l2_subdev *sd) | ||
470 | { | ||
471 | struct tc358840_state *state = to_state(sd); | ||
472 | |||
473 | v4l2_dbg(2, debug, sd, "%s:\n", __func__); | ||
474 | |||
475 | cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); | ||
476 | |||
477 | /* DDC access to EDID is also disabled when hotplug is disabled. See | ||
478 | * register DDC_CTL */ | ||
479 | i2c_wr8_and_or(sd, HPD_CTL, ~MASK_HPD_OUT0, 0x0); | ||
480 | } | ||
481 | |||
482 | static void tc358840_enable_edid(struct v4l2_subdev *sd) | ||
483 | { | ||
484 | struct tc358840_state *state = to_state(sd); | ||
485 | |||
486 | if (state->edid_blocks_written == 0) { | ||
487 | v4l2_dbg(2, debug, sd, "%s: no EDID -> no hotplug\n", __func__); | ||
488 | return; | ||
489 | } | ||
490 | |||
491 | v4l2_dbg(2, debug, sd, "%s:\n", __func__); | ||
492 | |||
493 | /* Enable hotplug after 100 ms. DDC access to EDID is also enabled when | ||
494 | * hotplug is enabled. See register DDC_CTL */ | ||
495 | queue_delayed_work(state->work_queues, | ||
496 | &state->delayed_work_enable_hotplug, HZ / 10); | ||
497 | |||
498 | tc358840_enable_interrupts(sd, true); | ||
499 | tc358840_s_ctrl_detect_tx_5v(sd); | ||
500 | } | ||
501 | |||
502 | static void tc358840_delayed_work_enable_interrupt(struct work_struct *work) | ||
503 | { | ||
504 | struct delayed_work *dwork = to_delayed_work(work); | ||
505 | struct tc358840_state *state = container_of(dwork, | ||
506 | struct tc358840_state, delayed_work_enable_interrupt); | ||
507 | struct v4l2_subdev *sd = &state->sd; | ||
508 | |||
509 | struct v4l2_subdev_edid sd_edid = { | ||
510 | .blocks = 2, | ||
511 | .edid = edid, | ||
512 | }; | ||
513 | |||
514 | v4l2_dbg(2, debug, sd, "%s:\n", __func__); | ||
515 | |||
516 | tc358840_enable_interrupts(sd, tx_5v_power_present(sd)); | ||
517 | |||
518 | /* Temporary EDID. Should be set by userspace */ | ||
519 | tc358840_s_edid(sd, &sd_edid); | ||
520 | } | ||
521 | |||
522 | static void tc358840_erase_bksv(struct v4l2_subdev *sd) | ||
523 | { | ||
524 | int i; | ||
525 | |||
526 | for (i = 0; i < 5; i++) | ||
527 | i2c_wr8(sd, BKSV + i, 0); | ||
528 | } | ||
529 | |||
530 | /* --------------- AVI infoframe --------------- */ | ||
531 | |||
532 | static void print_avi_infoframe(struct v4l2_subdev *sd) | ||
533 | { | ||
534 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
535 | struct device *dev = &client->dev; | ||
536 | union hdmi_infoframe frame; | ||
537 | u8 buffer[HDMI_INFOFRAME_SIZE(MAX)]; | ||
538 | |||
539 | if (!is_hdmi(sd)) { | ||
540 | v4l2_info(sd, "DVI-D signal - AVI infoframe not supported\n"); | ||
541 | return; | ||
542 | } | ||
543 | |||
544 | i2c_rd(sd, PK_AVI_0HEAD, buffer, HDMI_INFOFRAME_SIZE(AVI)); | ||
545 | |||
546 | if (hdmi_infoframe_unpack(&frame, buffer) < 0) { | ||
547 | v4l2_err(sd, "%s: unpack of AVI infoframe failed\n", __func__); | ||
548 | return; | ||
549 | } | ||
550 | |||
551 | hdmi_infoframe_log(KERN_INFO, dev, &frame); | ||
552 | } | ||
553 | |||
554 | /* --------------- CTRLS --------------- */ | ||
555 | |||
556 | static int tc358840_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd) | ||
557 | { | ||
558 | struct tc358840_state *state = to_state(sd); | ||
559 | |||
560 | return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, | ||
561 | tx_5v_power_present(sd)); | ||
562 | } | ||
563 | |||
564 | static int tc358840_s_ctrl_audio_sampling_rate(struct v4l2_subdev *sd) | ||
565 | { | ||
566 | struct tc358840_state *state = to_state(sd); | ||
567 | |||
568 | return v4l2_ctrl_s_ctrl(state->audio_sampling_rate_ctrl, | ||
569 | get_audio_sampling_rate(sd)); | ||
570 | } | ||
571 | |||
572 | static int tc358840_s_ctrl_audio_present(struct v4l2_subdev *sd) | ||
573 | { | ||
574 | struct tc358840_state *state = to_state(sd); | ||
575 | |||
576 | return v4l2_ctrl_s_ctrl(state->audio_present_ctrl, | ||
577 | audio_present(sd)); | ||
578 | } | ||
579 | |||
580 | static int tc358840_update_controls(struct v4l2_subdev *sd) | ||
581 | { | ||
582 | int ret = 0; | ||
583 | |||
584 | ret |= tc358840_s_ctrl_detect_tx_5v(sd); | ||
585 | ret |= tc358840_s_ctrl_audio_sampling_rate(sd); | ||
586 | ret |= tc358840_s_ctrl_audio_present(sd); | ||
587 | |||
588 | return ret; | ||
589 | } | ||
590 | |||
591 | /* --------------- INIT --------------- */ | ||
592 | |||
593 | static void tc358840_reset_phy(struct v4l2_subdev *sd) | ||
594 | { | ||
595 | v4l2_dbg(1, debug, sd, "%s:\n", __func__); | ||
596 | |||
597 | i2c_wr8_and_or(sd, PHY_RST, ~MASK_RESET_CTRL, 0); | ||
598 | i2c_wr8_and_or(sd, PHY_RST, ~MASK_RESET_CTRL, MASK_RESET_CTRL); | ||
599 | } | ||
600 | |||
601 | static void tc358840_reset(struct v4l2_subdev *sd, u16 mask) | ||
602 | { | ||
603 | u16 sysctl = i2c_rd16(sd, SYSCTL); | ||
604 | |||
605 | i2c_wr16(sd, SYSCTL, sysctl | mask); | ||
606 | i2c_wr16(sd, SYSCTL, sysctl & ~mask); | ||
607 | } | ||
608 | |||
609 | static inline void tc358840_sleep_mode(struct v4l2_subdev *sd, bool enable) | ||
610 | { | ||
611 | v4l2_dbg(1, debug, sd, "%s(): %s\n", __func__, | ||
612 | enable ? "enable" : "disable"); | ||
613 | |||
614 | i2c_wr16_and_or(sd, SYSCTL, ~MASK_SLEEP, enable ? MASK_SLEEP : 0); | ||
615 | } | ||
616 | |||
617 | static int enable_stream(struct v4l2_subdev *sd, bool enable) | ||
618 | { | ||
619 | struct tc358840_state *state = to_state(sd); | ||
620 | struct tc358840_platform_data *pdata = &state->pdata; | ||
621 | |||
622 | u32 sync_timeout_ctr; | ||
623 | |||
624 | v4l2_dbg(2, debug, sd, "%s: %sable\n", __func__, enable ? "en" : "dis"); | ||
625 | |||
626 | if (enable == state->enabled) | ||
627 | return 0; | ||
628 | |||
629 | if (enable) { | ||
630 | #if 0 /* Wait until we can use the clock-noncontinuous property */ | ||
631 | if (pdata->endpoint.bus.mipi_csi2.flags & | ||
632 | V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK) { | ||
633 | i2c_wr32_and_or(sd, FUNCMODE, ~(MASK_CONTCLKMODE), | ||
634 | MASK_FORCESTOP); | ||
635 | } else { | ||
636 | /* It is critical for CSI receiver to see lane transition | ||
637 | * LP11->HS. Set to non-continuous mode to enable clock lane | ||
638 | * LP11 state. */ | ||
639 | i2c_wr32_and_or(sd, FUNCMODE, ~(MASK_CONTCLKMODE), 0); | ||
640 | /* Set to continuous mode to trigger LP11->HS transition */ | ||
641 | i2c_wr32_and_or(sd, FUNCMODE, 0, MASK_CONTCLKMODE); | ||
642 | } | ||
643 | #else | ||
644 | i2c_wr32_and_or(sd, FUNCMODE, ~(MASK_CONTCLKMODE), | ||
645 | MASK_FORCESTOP); | ||
646 | #endif | ||
647 | /* Unmute video */ | ||
648 | i2c_wr8(sd, VI_MUTE, MASK_AUTO_MUTE); | ||
649 | /* Signal end of initialization */ | ||
650 | i2c_wr8(sd, INIT_END, MASK_INIT_END); | ||
651 | } else { | ||
652 | /* Enable Registers to be initialized */ | ||
653 | i2c_wr8_and_or(sd, INIT_END, ~(MASK_INIT_END), 0x00); | ||
654 | |||
655 | /* Mute video so that all data lanes go to LSP11 state. | ||
656 | * No data is output to CSI Tx block. */ | ||
657 | |||
658 | i2c_wr8(sd, VI_MUTE, MASK_AUTO_MUTE | MASK_VI_MUTE); | ||
659 | tc358840_set_csi(sd); | ||
660 | tc358840_set_splitter(sd); | ||
661 | } | ||
662 | |||
663 | /* Wait for HDMI input to become stable */ | ||
664 | if (enable) { | ||
665 | sync_timeout_ctr = 100; | ||
666 | while (no_sync(sd) && sync_timeout_ctr) | ||
667 | sync_timeout_ctr--; | ||
668 | |||
669 | if (sync_timeout_ctr == 0) { | ||
670 | /* Disable stream again. Probably no cable inserted.. */ | ||
671 | v4l2_err(sd, "%s: Timeout: HDMI input sync failed.\n", | ||
672 | __func__); | ||
673 | enable_stream(sd, false); | ||
674 | return -EIO; | ||
675 | } | ||
676 | |||
677 | v4l2_dbg(2, debug, sd, | ||
678 | "%s: Stream enabled! Remaining timeout attempts: %d\n", | ||
679 | __func__, sync_timeout_ctr); | ||
680 | } | ||
681 | |||
682 | i2c_wr16_and_or(sd, CONFCTL0, | ||
683 | ~(MASK_VTX0EN | MASK_VTX1EN | MASK_ABUFEN), | ||
684 | enable ? ((pdata->csi_port & (MASK_VTX0EN | MASK_VTX1EN)) | | ||
685 | MASK_ABUFEN | MASK_TX_MSEL | MASK_AUTOINDEX) : | ||
686 | (MASK_TX_MSEL | MASK_AUTOINDEX)); | ||
687 | state->enabled = enable; | ||
688 | |||
689 | return 0; | ||
690 | } | ||
691 | |||
692 | static void tc358840_set_splitter(struct v4l2_subdev *sd) | ||
693 | { | ||
694 | struct tc358840_state *state = to_state(sd); | ||
695 | |||
696 | v4l2_dbg(3, debug, sd, "%s():\n", __func__); | ||
697 | |||
698 | if (state->timings.bt.width <= 1920) { | ||
699 | i2c_wr16_and_or(sd, SPLITTX0_CTRL, ~(MASK_IFEN | MASK_LCD_CSEL), | ||
700 | MASK_SPBP); | ||
701 | i2c_wr16_and_or(sd, SPLITTX1_CTRL, ~(MASK_IFEN | MASK_LCD_CSEL), | ||
702 | MASK_SPBP); | ||
703 | |||
704 | i2c_wr16_and_or(sd, SPLITTX0_SPLIT, (u16)~(MASK_TX1SEL | MASK_EHW), 0); | ||
705 | } else { | ||
706 | i2c_wr16_and_or(sd, SPLITTX0_CTRL, ~(MASK_IFEN | MASK_LCD_CSEL | MASK_SPBP), 0); | ||
707 | i2c_wr16_and_or(sd, SPLITTX1_CTRL, ~(MASK_IFEN | MASK_LCD_CSEL | MASK_SPBP), 0); | ||
708 | |||
709 | i2c_wr16_and_or(sd, SPLITTX0_SPLIT, ~(MASK_TX1SEL), MASK_EHW); | ||
710 | } | ||
711 | } | ||
712 | |||
713 | static void tc358840_set_pll(struct v4l2_subdev *sd, | ||
714 | enum tc358840_csi_port port) | ||
715 | { | ||
716 | struct tc358840_state *state = to_state(sd); | ||
717 | struct tc358840_platform_data *pdata = &state->pdata; | ||
718 | u16 base_addr; | ||
719 | u16 pll_frs; | ||
720 | u32 pllconf; | ||
721 | u32 pllconf_new; | ||
722 | u32 hsck; | ||
723 | |||
724 | v4l2_dbg(2, debug, sd, "%s:\n", __func__); | ||
725 | |||
726 | BUG_ON((pdata->csi_port <= CSI_TX_NONE) || | ||
727 | (pdata->csi_port > CSI_TX_BOTH)); | ||
728 | |||
729 | if (pdata->csi_port == CSI_TX_NONE) { | ||
730 | v4l2_err(sd, "%s: No CSI port defined!\n", __func__); | ||
731 | return; | ||
732 | } | ||
733 | |||
734 | base_addr = (port == CSI_TX_0) ? CSITX0_BASE_ADDR : | ||
735 | CSITX1_BASE_ADDR; | ||
736 | pllconf = i2c_rd32(sd, base_addr+PLLCONF); | ||
737 | pllconf_new = SET_PLL_PRD(pdata->pll_prd) | | ||
738 | SET_PLL_FBD(pdata->pll_fbd); | ||
739 | |||
740 | hsck = (pdata->refclk_hz / pdata->pll_prd) * | ||
741 | pdata->pll_fbd; | ||
742 | |||
743 | if (hsck > 500000000) | ||
744 | pll_frs = 0x0; | ||
745 | else if (hsck > 250000000) | ||
746 | pll_frs = 0x1; | ||
747 | else if (hsck > 125000000) | ||
748 | pll_frs = 0x2; | ||
749 | else | ||
750 | pll_frs = 0x3; | ||
751 | |||
752 | v4l2_dbg(1, debug, sd, "%s: Updating PLL clock of CSI TX%d\n", | ||
753 | __func__, port-1); | ||
754 | |||
755 | i2c_wr32(sd, base_addr+PLLCONF, | ||
756 | pllconf_new | SET_PLL_FRS(pll_frs)); | ||
757 | } | ||
758 | |||
759 | static void tc358840_set_ref_clk(struct v4l2_subdev *sd) | ||
760 | { | ||
761 | struct tc358840_state *state = to_state(sd); | ||
762 | struct tc358840_platform_data *pdata = &state->pdata; | ||
763 | |||
764 | u32 sys_freq; | ||
765 | u32 lock_ref_freq; | ||
766 | u32 nco; | ||
767 | u16 csc; | ||
768 | |||
769 | v4l2_dbg(3, debug, sd, "%s():\n", __func__); | ||
770 | |||
771 | BUG_ON((pdata->refclk_hz < 40000000) || (pdata->refclk_hz > 50000000)); | ||
772 | |||
773 | /* System Frequency */ | ||
774 | sys_freq = pdata->refclk_hz / 10000; | ||
775 | i2c_wr8(sd, SYS_FREQ0, sys_freq & 0x00FF); | ||
776 | i2c_wr8(sd, SYS_FREQ1, (sys_freq & 0xFF00) >> 8); | ||
777 | |||
778 | /* Audio System Frequency */ | ||
779 | lock_ref_freq = pdata->refclk_hz / 100; | ||
780 | i2c_wr8(sd, LOCK_REF_FREQA, lock_ref_freq & 0xFF); | ||
781 | i2c_wr8(sd, LOCK_REF_FREQB, (lock_ref_freq >> 8) & 0xFF); | ||
782 | i2c_wr8(sd, LOCK_REF_FREQC, (lock_ref_freq >> 16) & 0x0F); | ||
783 | |||
784 | /* Audio PLL */ | ||
785 | i2c_wr8(sd, NCO_F0_MOD, MASK_NCO_F0_MOD_REG); | ||
786 | /* 6.144 * 2^28 = 1649267442 */ | ||
787 | nco = (1649267442 / (pdata->refclk_hz / 1000000)); | ||
788 | i2c_wr8(sd, NCO_48F0A, nco & 0xFF); | ||
789 | i2c_wr8(sd, NCO_48F0B, (nco >> 8) & 0xFF); | ||
790 | i2c_wr8(sd, NCO_48F0C, (nco >> 16) & 0xFF); | ||
791 | i2c_wr8(sd, NCO_48F0D, (nco >> 24) & 0xFF); | ||
792 | |||
793 | /* Color Space Conversion */ | ||
794 | csc = pdata->refclk_hz / 10000; | ||
795 | i2c_wr8(sd, SCLK_CSC0, csc & 0xFF); | ||
796 | i2c_wr8(sd, SCLK_CSC1, (csc >> 8) & 0xFF); | ||
797 | } | ||
798 | |||
799 | static void tc358840_set_csi_mbus_config(struct v4l2_subdev *sd) | ||
800 | { | ||
801 | struct tc358840_state *state = to_state(sd); | ||
802 | |||
803 | v4l2_dbg(3, debug, sd, "%s():\n", __func__); | ||
804 | |||
805 | switch (state->mbus_fmt_code) { | ||
806 | case MEDIA_BUS_FMT_UYVY8_1X16: | ||
807 | v4l2_dbg(2, debug, sd, "%s: YCbCr 422 16-bit\n", __func__); | ||
808 | |||
809 | i2c_wr8(sd, VOUT_FMT, MASK_OUTFMT_422 | MASK_422FMT_NORMAL); | ||
810 | i2c_wr8(sd, VOUT_FIL, MASK_422FIL_3_TAP_444 | | ||
811 | MASK_444FIL_2_TAP); | ||
812 | i2c_wr8(sd, VOUT_SYNC0, MASK_MODE_2); | ||
813 | i2c_wr8(sd, VOUT_CSC, MASK_CSC_MODE_BUILTIN | | ||
814 | MASK_COLOR_601_YCBCR_LIMITED); | ||
815 | i2c_wr16_and_or(sd, CONFCTL0, ~(MASK_YCBCRFMT), | ||
816 | MASK_YCBCRFMT_YCBCR422_8); | ||
817 | i2c_wr16(sd, CONFCTL1, 0x0); | ||
818 | break; | ||
819 | |||
820 | case MEDIA_BUS_FMT_RGB888_1X24: | ||
821 | v4l2_dbg(2, debug, sd, "%s: RGB 888 24-bit\n", __func__); | ||
822 | |||
823 | i2c_wr8(sd, VOUT_FMT, MASK_OUTFMT_444_RGB); | ||
824 | i2c_wr8(sd, VOUT_FIL, MASK_422FIL_3_TAP_444 | | ||
825 | MASK_444FIL_2_TAP); | ||
826 | i2c_wr8(sd, VOUT_SYNC0, MASK_MODE_2); | ||
827 | i2c_wr8(sd, VOUT_CSC, MASK_CSC_MODE_BUILTIN | | ||
828 | MASK_COLOR_RGB_LIMITED); | ||
829 | i2c_wr16_and_or(sd, CONFCTL0, ~(MASK_YCBCRFMT), 0x0); | ||
830 | i2c_wr16_and_or(sd, CONFCTL1, 0x0, MASK_TX_OUT_FMT_RGB888); | ||
831 | break; | ||
832 | |||
833 | default: | ||
834 | v4l2_dbg(2, debug, sd, "%s: Unsupported format code 0x%x\n", | ||
835 | __func__, state->mbus_fmt_code); | ||
836 | break; | ||
837 | } | ||
838 | } | ||
839 | |||
840 | static unsigned tc358840_num_csi_lanes_needed(struct v4l2_subdev *sd) | ||
841 | { | ||
842 | |||
843 | /* TODO: Check if this can be useful */ | ||
844 | #if 0 | ||
845 | struct tc358840_state *state = to_state(sd); | ||
846 | struct v4l2_bt_timings *bt = &state->timings.bt; | ||
847 | struct tc358840_platform_data *pdata = &state->pdata; | ||
848 | u32 bits_pr_pixel = | ||
849 | (state->mbus_fmt_code == MEDIA_BUS_FMT_UYVY8_1X16) ? 16 : 24; | ||
850 | u32 bps = bt->width * bt->height * fps(bt) * bits_pr_pixel; | ||
851 | u32 bps_pr_lane = (pdata->refclk_hz / pdata->pll_prd) * pdata->pll_fbd; | ||
852 | |||
853 | return DIV_ROUND_UP(bps, bps_pr_lane); | ||
854 | #endif | ||
855 | |||
856 | /* Always use 4 lanes for one CSI */ | ||
857 | return 4; | ||
858 | } | ||
859 | |||
860 | static void tc358840_set_csi(struct v4l2_subdev *sd) | ||
861 | { | ||
862 | struct tc358840_state *state = to_state(sd); | ||
863 | struct tc358840_platform_data *pdata = &state->pdata; | ||
864 | #if 0 | ||
865 | struct v4l2_bt_timings *bt = &state->timings.bt; | ||
866 | #endif | ||
867 | unsigned lanes = tc358840_num_csi_lanes_needed(sd); | ||
868 | |||
869 | enum tc358840_csi_port port; | ||
870 | u16 base_addr; | ||
871 | |||
872 | v4l2_dbg(3, debug, sd, "%s:\n", __func__); | ||
873 | |||
874 | tc358840_reset(sd, MASK_CTXRST); | ||
875 | |||
876 | for (port = CSI_TX_0; port <= CSI_TX_1; port++) { | ||
877 | base_addr = (port == CSI_TX_0) ? CSITX0_BASE_ADDR : | ||
878 | CSITX1_BASE_ADDR; | ||
879 | |||
880 | if (pdata->csi_port != CSI_TX_BOTH && | ||
881 | pdata->csi_port != port) { | ||
882 | v4l2_dbg(1, debug, sd, | ||
883 | "%s: Disabling CSI TX%d\n", __func__, port-1); | ||
884 | |||
885 | /* Disable CSI lanes (High Z)*/ | ||
886 | i2c_wr32_and_or(sd, base_addr+LANEEN, | ||
887 | ~(MASK_CLANEEN), 0); | ||
888 | continue; | ||
889 | } | ||
890 | |||
891 | v4l2_dbg(1, debug, sd, | ||
892 | "%s: Enabling CSI TX%d\n", __func__, port-1); | ||
893 | |||
894 | /* (0x0108) */ | ||
895 | i2c_wr32(sd, base_addr+CSITX_CLKEN, MASK_CSITX_EN); | ||
896 | /* | ||
897 | * PLL has to be enabled between CSITX_CLKEN and | ||
898 | * LANEEN (0x02AC) | ||
899 | */ | ||
900 | tc358840_set_pll(sd, port); | ||
901 | /* (0x02A0) */ | ||
902 | i2c_wr32_and_or(sd, base_addr+MIPICLKEN, | ||
903 | ~(MASK_MP_CKEN), MASK_MP_ENABLE); | ||
904 | usleep_range(10000, 11000); | ||
905 | /* (0x02A0) */ | ||
906 | i2c_wr32(sd, base_addr+MIPICLKEN, | ||
907 | MASK_MP_CKEN | MASK_MP_ENABLE); | ||
908 | /* (0x010C) */ | ||
909 | i2c_wr32(sd, base_addr+PPICLKEN, MASK_HSTXCLKEN); | ||
910 | /* (0x0118) */ | ||
911 | i2c_wr32(sd, base_addr+LANEEN, | ||
912 | (lanes & MASK_LANES) | MASK_CLANEEN); | ||
913 | |||
914 | /* (0x0120) */ | ||
915 | i2c_wr32(sd, base_addr+LINEINITCNT, pdata->lineinitcnt); | ||
916 | |||
917 | /* | ||
918 | * TODO: Check if this is the correct register | ||
919 | * (0x0150) | ||
920 | */ | ||
921 | i2c_rd32(sd, base_addr+FUNCMODE); | ||
922 | /* (0x0254) */ | ||
923 | i2c_wr32(sd, base_addr+LPTXTIMECNT, pdata->lptxtimecnt); | ||
924 | /* (0x0258) */ | ||
925 | i2c_wr32(sd, base_addr+TCLK_HEADERCNT, | ||
926 | pdata->tclk_headercnt); | ||
927 | /* (0x025C) */ | ||
928 | i2c_wr32(sd, base_addr+TCLK_TRAILCNT, | ||
929 | pdata->tclk_trailcnt); | ||
930 | /* (0x0260) */ | ||
931 | i2c_wr32(sd, base_addr+THS_HEADERCNT, | ||
932 | pdata->ths_headercnt); | ||
933 | /* (0x0264) */ | ||
934 | i2c_wr32(sd, base_addr+TWAKEUP, pdata->twakeup); | ||
935 | /* (0x0268) */ | ||
936 | i2c_wr32(sd, base_addr+TCLK_POSTCNT, | ||
937 | pdata->tclk_postcnt); | ||
938 | /* (0x026C) */ | ||
939 | i2c_wr32(sd, base_addr+THS_TRAILCNT, | ||
940 | pdata->ths_trailcnt); | ||
941 | |||
942 | /* (0x0270) */ | ||
943 | i2c_wr32(sd, base_addr+HSTXVREGCNT, pdata->hstxvregcnt); | ||
944 | |||
945 | /* (0x0274) */ | ||
946 | i2c_wr32(sd, base_addr+HSTXVREGEN, | ||
947 | ((lanes > 0) ? MASK_CLM_HSTXVREGEN : 0x0) | | ||
948 | ((lanes > 0) ? MASK_D0M_HSTXVREGEN : 0x0) | | ||
949 | ((lanes > 1) ? MASK_D1M_HSTXVREGEN : 0x0) | | ||
950 | ((lanes > 2) ? MASK_D2M_HSTXVREGEN : 0x0) | | ||
951 | ((lanes > 3) ? MASK_D3M_HSTXVREGEN : 0x0)); | ||
952 | |||
953 | /* | ||
954 | * Finishing configuration by setting CSITX to start | ||
955 | * (0X011C) | ||
956 | */ | ||
957 | i2c_wr32(sd, base_addr+CSITX_START, 0x00000001); | ||
958 | |||
959 | i2c_rd32(sd, base_addr+CSITX_INTERNAL_STAT); | ||
960 | } | ||
961 | } | ||
962 | |||
963 | static void tc358840_set_hdmi_phy(struct v4l2_subdev *sd) | ||
964 | { | ||
965 | v4l2_dbg(3, debug, sd, "%s():\n", __func__); | ||
966 | |||
967 | /* Reset PHY */ | ||
968 | tc358840_reset_phy(sd); | ||
969 | |||
970 | /* Set PHY to manual */ | ||
971 | i2c_wr8(sd, PHY_CTL, MASK_48_MHZ); | ||
972 | |||
973 | /* Enable PHY */ | ||
974 | i2c_wr8_and_or(sd, PHY_ENB, ~MASK_ENABLE_PHY, 0x0); | ||
975 | i2c_wr8_and_or(sd, PHY_ENB, ~MASK_ENABLE_PHY, MASK_ENABLE_PHY); | ||
976 | |||
977 | /* Enable Audio PLL */ | ||
978 | i2c_wr8(sd, APPL_CTL, MASK_APLL_CPCTL_NORMAL | MASK_APLL_ON); | ||
979 | |||
980 | /* Enable DDC IO */ | ||
981 | i2c_wr8(sd, DDCIO_CTL, MASK_DDC_PWR_ON); | ||
982 | } | ||
983 | |||
984 | static void tc358840_set_hdmi_audio(struct v4l2_subdev *sd) | ||
985 | { | ||
986 | v4l2_dbg(3, debug, sd, "%s():\n", __func__); | ||
987 | |||
988 | i2c_wr8(sd, FORCE_MUTE, 0x00); | ||
989 | i2c_wr8(sd, AUTO_CMD0, MASK_AUTO_MUTE7 | MASK_AUTO_MUTE6 | | ||
990 | MASK_AUTO_MUTE5 | MASK_AUTO_MUTE4 | | ||
991 | MASK_AUTO_MUTE1 | MASK_AUTO_MUTE0); | ||
992 | i2c_wr8(sd, AUTO_CMD1, MASK_AUTO_MUTE9); | ||
993 | i2c_wr8(sd, AUTO_CMD2, MASK_AUTO_PLAY3 | MASK_AUTO_PLAY2); | ||
994 | i2c_wr8(sd, BUFINIT_START, SET_BUFINIT_START_MS(500)); | ||
995 | i2c_wr8(sd, FS_MUTE, 0x00); | ||
996 | i2c_wr8(sd, FS_IMODE, MASK_NLPCM_SMODE | MASK_FS_SMODE); | ||
997 | i2c_wr8(sd, ACR_MODE, MASK_CTS_MODE); | ||
998 | i2c_wr8(sd, ACR_MDF0, MASK_ACR_L2MDF_1976_PPM | MASK_ACR_L1MDF_976_PPM); | ||
999 | i2c_wr8(sd, ACR_MDF1, MASK_ACR_L3MDF_3906_PPM); | ||
1000 | /* | ||
1001 | * TODO: Set output data bit length (currently 16 bit, 8 bit discarded) | ||
1002 | */ | ||
1003 | i2c_wr8(sd, SDO_MODE1, MASK_SDO_FMT_I2S); | ||
1004 | i2c_wr8(sd, DIV_MODE, SET_DIV_DLY_MS(100)); | ||
1005 | i2c_wr16_and_or(sd, CONFCTL0, 0xFFFF, MASK_AUDCHNUM_2 | | ||
1006 | MASK_AUDOUTSEL_I2S | MASK_AUTOINDEX); | ||
1007 | } | ||
1008 | |||
1009 | static void tc358840_set_hdmi_info_frame_mode(struct v4l2_subdev *sd) | ||
1010 | { | ||
1011 | v4l2_dbg(3, debug, sd, "%s(): DUMMY\n", __func__); | ||
1012 | |||
1013 | /* TODO: Check which registers are needed/available */ | ||
1014 | #if 0 | ||
1015 | i2c_wr8(sd, PK_INT_MODE, MASK_ISRC2_INT_MODE | MASK_ISRC_INT_MODE | | ||
1016 | MASK_ACP_INT_MODE | MASK_VS_INT_MODE | | ||
1017 | MASK_SPD_INT_MODE | MASK_MS_INT_MODE | | ||
1018 | MASK_AUD_INT_MODE | MASK_AVI_INT_MODE); | ||
1019 | i2c_wr8(sd, NO_PKT_LIMIT, 0x2c); | ||
1020 | i2c_wr8(sd, NO_PKT_CLR, 0x53); | ||
1021 | i2c_wr8(sd, ERR_PK_LIMIT, 0x01); | ||
1022 | i2c_wr8(sd, NO_PKT_LIMIT2, 0x30); | ||
1023 | i2c_wr8(sd, NO_GDB_LIMIT, 0x10); | ||
1024 | #endif | ||
1025 | } | ||
1026 | |||
1027 | static void tc358840_initial_setup(struct v4l2_subdev *sd) | ||
1028 | { | ||
1029 | static struct v4l2_dv_timings default_timing = V4L2_DV_BT_CEA_1920X1080P60; | ||
1030 | struct tc358840_state *state = to_state(sd); | ||
1031 | struct tc358840_platform_data *pdata = &state->pdata; | ||
1032 | |||
1033 | v4l2_dbg(3, debug, sd, "%s():\n", __func__); | ||
1034 | |||
1035 | /* *** Reset *** */ | ||
1036 | enable_stream(sd, false); | ||
1037 | |||
1038 | tc358840_sleep_mode(sd, false); | ||
1039 | tc358840_reset(sd, MASK_RESET_ALL); | ||
1040 | |||
1041 | tc358840_init_interrupts(sd); | ||
1042 | |||
1043 | /* *** Init CSI *** */ | ||
1044 | tc358840_s_dv_timings(sd, &default_timing); | ||
1045 | |||
1046 | tc358840_set_ref_clk(sd); | ||
1047 | |||
1048 | i2c_wr8_and_or(sd, DDC_CTL, ~MASK_DDC5V_MODE, | ||
1049 | pdata->ddc5v_delay & MASK_DDC5V_MODE); | ||
1050 | |||
1051 | i2c_wr8_and_or(sd, EDID_MODE, ~MASK_EDID_MODE_ALL, MASK_RAM_EDDC); | ||
1052 | |||
1053 | i2c_wr8_and_or(sd, HPD_CTL, ~MASK_HPD_CTL0, 0); | ||
1054 | |||
1055 | tc358840_set_hdmi_phy(sd); | ||
1056 | |||
1057 | tc358840_set_hdmi_hdcp(sd, pdata->enable_hdcp); | ||
1058 | tc358840_set_hdmi_audio(sd); | ||
1059 | tc358840_set_hdmi_info_frame_mode(sd); | ||
1060 | |||
1061 | /* All CE and IT formats are detected as RGB full range in DVI mode */ | ||
1062 | i2c_wr8_and_or(sd, VI_MODE, ~MASK_RGB_DVI, 0); | ||
1063 | } | ||
1064 | |||
1065 | /* --------------- IRQ --------------- */ | ||
1066 | |||
1067 | static void tc358840_format_change(struct v4l2_subdev *sd) | ||
1068 | { | ||
1069 | struct tc358840_state *state = to_state(sd); | ||
1070 | struct v4l2_dv_timings timings; | ||
1071 | static const struct v4l2_event tc358840_ev_fmt = { | ||
1072 | .type = V4L2_EVENT_SOURCE_CHANGE, | ||
1073 | .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, | ||
1074 | }; | ||
1075 | |||
1076 | if (tc358840_get_detected_timings(sd, &timings)) { | ||
1077 | enable_stream(sd, false); | ||
1078 | |||
1079 | v4l2_info(sd, "%s: No Signal\n", __func__); | ||
1080 | } else { | ||
1081 | if (!v4l2_match_dv_timings(&state->timings, &timings, 0)) | ||
1082 | enable_stream(sd, false); | ||
1083 | |||
1084 | v4l2_print_dv_timings(sd->name, | ||
1085 | "tc358840_format_change: New format: ", | ||
1086 | &timings, false); | ||
1087 | } | ||
1088 | |||
1089 | /* Application gets notified after CSI Tx's are reset */ | ||
1090 | if (sd->devnode) | ||
1091 | v4l2_subdev_notify_event(sd, &tc358840_ev_fmt); | ||
1092 | } | ||
1093 | |||
1094 | static void tc358840_init_interrupts(struct v4l2_subdev *sd) | ||
1095 | { | ||
1096 | u16 i; | ||
1097 | |||
1098 | v4l2_dbg(3, debug, sd, "%s():\n", __func__); | ||
1099 | |||
1100 | /* clear interrupt status registers */ | ||
1101 | for (i = SYS_INT; i <= MISC_INT; i++) { | ||
1102 | /* No interrupt register at Address 0x850A */ | ||
1103 | if (i != 0x850A) | ||
1104 | i2c_wr8(sd, i, 0xFF); | ||
1105 | } | ||
1106 | |||
1107 | /* Clear and disable all interrupts */ | ||
1108 | i2c_wr16(sd, INTSTATUS, MASK_INT_STATUS_MASK_ALL); | ||
1109 | i2c_wr16(sd, INTSTATUS, 0x0); | ||
1110 | |||
1111 | i2c_wr16(sd, INTMASK, MASK_INT_STATUS_MASK_ALL); | ||
1112 | } | ||
1113 | |||
1114 | static void tc358840_enable_interrupts(struct v4l2_subdev *sd, | ||
1115 | bool cable_connected) | ||
1116 | { | ||
1117 | v4l2_dbg(2, debug, sd, "%s: cable connected = %d\n", __func__, | ||
1118 | cable_connected); | ||
1119 | |||
1120 | if (cable_connected) { | ||
1121 | i2c_wr8(sd, SYS_INTM, ~(MASK_DDC | MASK_DVI | | ||
1122 | MASK_HDMI) & 0xFF); | ||
1123 | i2c_wr8(sd, SYS_INTM, ~(MASK_DDC) & 0xFF); | ||
1124 | i2c_wr8(sd, CLK_INTM, ~MASK_IN_DE_CHG); | ||
1125 | i2c_wr8(sd, CBIT_INTM, ~(MASK_CBIT_FS | MASK_AF_LOCK | | ||
1126 | MASK_AF_UNLOCK) & 0xFF); | ||
1127 | i2c_wr8(sd, AUDIO_INTM, ~MASK_BUFINIT_END); | ||
1128 | i2c_wr8(sd, MISC_INTM, ~MASK_SYNC_CHG); | ||
1129 | } else { | ||
1130 | i2c_wr8(sd, SYS_INTM, ~MASK_DDC & 0xFF); | ||
1131 | i2c_wr8(sd, CLK_INTM, 0xFF); | ||
1132 | i2c_wr8(sd, CBIT_INTM, 0xFF); | ||
1133 | i2c_wr8(sd, AUDIO_INTM, 0xFF); | ||
1134 | i2c_wr8(sd, MISC_INTM, 0xFF); | ||
1135 | } | ||
1136 | } | ||
1137 | |||
1138 | static void tc358840_hdmi_audio_int_handler(struct v4l2_subdev *sd, | ||
1139 | bool *handled) | ||
1140 | { | ||
1141 | u8 audio_int_mask = i2c_rd8(sd, AUDIO_INTM); | ||
1142 | u8 audio_int = i2c_rd8(sd, AUDIO_INT) & ~audio_int_mask; | ||
1143 | |||
1144 | i2c_wr8(sd, AUDIO_INT, audio_int); | ||
1145 | |||
1146 | v4l2_dbg(3, debug, sd, "%s: AUDIO_INT = 0x%02x\n", __func__, audio_int); | ||
1147 | |||
1148 | tc358840_s_ctrl_audio_sampling_rate(sd); | ||
1149 | tc358840_s_ctrl_audio_present(sd); | ||
1150 | } | ||
1151 | |||
1152 | static void tc358840_hdmi_misc_int_handler(struct v4l2_subdev *sd, | ||
1153 | bool *handled) | ||
1154 | { | ||
1155 | struct tc358840_state *state = to_state(sd); | ||
1156 | u8 misc_int_mask = i2c_rd8(sd, MISC_INTM); | ||
1157 | u8 misc_int = i2c_rd8(sd, MISC_INT) & ~misc_int_mask; | ||
1158 | |||
1159 | i2c_wr8(sd, MISC_INT, misc_int); | ||
1160 | |||
1161 | v4l2_dbg(3, debug, sd, "%s: MISC_INT = 0x%02x\n", __func__, misc_int); | ||
1162 | |||
1163 | if (misc_int & MASK_SYNC_CHG) { | ||
1164 | /* Reset the HDMI PHY to try to trigger proper lock on the | ||
1165 | * incoming video format. Erase BKSV to prevent that old keys | ||
1166 | * are used when a new source is connected. */ | ||
1167 | |||
1168 | state->format_changed = true; | ||
1169 | |||
1170 | misc_int &= ~MASK_SYNC_CHG; | ||
1171 | if (handled) | ||
1172 | *handled = true; | ||
1173 | } | ||
1174 | |||
1175 | if (misc_int) { | ||
1176 | v4l2_err(sd, "%s: Unhandled MISC_INT interrupts: 0x%02x\n", | ||
1177 | __func__, misc_int); | ||
1178 | } | ||
1179 | } | ||
1180 | |||
1181 | static void tc358840_hdmi_cbit_int_handler(struct v4l2_subdev *sd, | ||
1182 | bool *handled) | ||
1183 | { | ||
1184 | u8 cbit_int_mask = i2c_rd8(sd, CBIT_INTM); | ||
1185 | u8 cbit_int = i2c_rd8(sd, CBIT_INT) & ~cbit_int_mask; | ||
1186 | |||
1187 | i2c_wr8(sd, CBIT_INT, cbit_int); | ||
1188 | |||
1189 | v4l2_dbg(3, debug, sd, "%s: CBIT_INT = 0x%02x\n", __func__, cbit_int); | ||
1190 | |||
1191 | if (cbit_int & MASK_CBIT_FS) { | ||
1192 | |||
1193 | v4l2_dbg(1, debug, sd, "%s: Audio sample rate changed\n", | ||
1194 | __func__); | ||
1195 | tc358840_s_ctrl_audio_sampling_rate(sd); | ||
1196 | |||
1197 | cbit_int &= ~MASK_CBIT_FS; | ||
1198 | if (handled) | ||
1199 | *handled = true; | ||
1200 | } | ||
1201 | |||
1202 | if (cbit_int & (MASK_AF_LOCK | MASK_AF_UNLOCK)) { | ||
1203 | |||
1204 | v4l2_dbg(1, debug, sd, "%s: Audio present changed\n", | ||
1205 | __func__); | ||
1206 | tc358840_s_ctrl_audio_present(sd); | ||
1207 | |||
1208 | cbit_int &= ~(MASK_AF_LOCK | MASK_AF_UNLOCK); | ||
1209 | if (handled) | ||
1210 | *handled = true; | ||
1211 | } | ||
1212 | |||
1213 | if (cbit_int) { | ||
1214 | v4l2_err(sd, "%s: Unhandled CBIT_INT interrupts: 0x%02x\n", | ||
1215 | __func__, cbit_int); | ||
1216 | } | ||
1217 | } | ||
1218 | |||
1219 | static void tc358840_hdmi_clk_int_handler(struct v4l2_subdev *sd, bool *handled) | ||
1220 | { | ||
1221 | struct tc358840_state *state = to_state(sd); | ||
1222 | u8 clk_int_mask = i2c_rd8(sd, CLK_INTM); | ||
1223 | u8 clk_int = i2c_rd8(sd, CLK_INT) & ~clk_int_mask; | ||
1224 | |||
1225 | /* Bit 7 and bit 6 are set even when they are masked */ | ||
1226 | i2c_wr8(sd, CLK_INT, clk_int | 0x80 | MASK_OUT_H_CHG); | ||
1227 | |||
1228 | v4l2_dbg(3, debug, sd, "%s: CLK_INT = 0x%02x\n", __func__, clk_int); | ||
1229 | |||
1230 | if (clk_int & (MASK_IN_DE_CHG)) { | ||
1231 | |||
1232 | v4l2_dbg(1, debug, sd, "%s: DE size or position has changed\n", | ||
1233 | __func__); | ||
1234 | |||
1235 | /* TODO: Check if also true for tc358840 */ | ||
1236 | /* If the source switch to a new resolution with the same pixel | ||
1237 | * frequency as the existing (e.g. 1080p25 -> 720p50), the | ||
1238 | * I_SYNC_CHG interrupt is not always triggered, while the | ||
1239 | * I_IN_DE_CHG interrupt seems to work fine. FMT_CHANGE | ||
1240 | * notifications are only sent when the signal is stable to | ||
1241 | * reduce the number of notifications. */ | ||
1242 | if (!no_signal(sd) && !no_sync(sd)) | ||
1243 | state->format_changed = true; | ||
1244 | |||
1245 | clk_int &= ~MASK_IN_DE_CHG; | ||
1246 | if (handled) | ||
1247 | *handled = true; | ||
1248 | } | ||
1249 | |||
1250 | if (clk_int) { | ||
1251 | v4l2_err(sd, "%s: Unhandled CLK_INT interrupts: 0x%02x\n", | ||
1252 | __func__, clk_int); | ||
1253 | } | ||
1254 | } | ||
1255 | |||
1256 | static void tc358840_hdmi_sys_int_handler(struct v4l2_subdev *sd, bool *handled) | ||
1257 | { | ||
1258 | struct tc358840_state *state = to_state(sd); | ||
1259 | u8 sys_int_mask = i2c_rd8(sd, SYS_INTM); | ||
1260 | u8 sys_int = i2c_rd8(sd, SYS_INT) & ~sys_int_mask; | ||
1261 | |||
1262 | i2c_wr8(sd, SYS_INT, sys_int); | ||
1263 | |||
1264 | v4l2_dbg(3, debug, sd, "%s: SYS_INT = 0x%02x\n", __func__, sys_int); | ||
1265 | |||
1266 | if (sys_int & MASK_DDC) { | ||
1267 | bool tx_5v = tx_5v_power_present(sd); | ||
1268 | |||
1269 | v4l2_dbg(1, debug, sd, "%s: Tx 5V power present: %s\n", | ||
1270 | __func__, tx_5v ? "yes" : "no"); | ||
1271 | |||
1272 | if (tx_5v) { | ||
1273 | tc358840_enable_edid(sd); | ||
1274 | } else { | ||
1275 | tc358840_enable_interrupts(sd, false); | ||
1276 | tc358840_disable_edid(sd); | ||
1277 | memset(&state->timings, 0, sizeof(state->timings)); | ||
1278 | tc358840_erase_bksv(sd); | ||
1279 | tc358840_update_controls(sd); | ||
1280 | } | ||
1281 | |||
1282 | sys_int &= ~MASK_DDC; | ||
1283 | if (handled) | ||
1284 | *handled = true; | ||
1285 | } | ||
1286 | |||
1287 | if (sys_int & MASK_DVI) { | ||
1288 | v4l2_dbg(1, debug, sd, "%s: HDMI->DVI change detected\n", | ||
1289 | __func__); | ||
1290 | |||
1291 | /* Reset the HDMI PHY to try to trigger proper lock on the | ||
1292 | * incoming video format. Erase BKSV to prevent that old keys | ||
1293 | * are used when a new source is connected. */ | ||
1294 | if (no_sync(sd) || no_signal(sd)) | ||
1295 | state->format_changed = true; | ||
1296 | |||
1297 | sys_int &= ~MASK_DVI; | ||
1298 | if (handled) | ||
1299 | *handled = true; | ||
1300 | } | ||
1301 | |||
1302 | if (sys_int & MASK_HDMI) { | ||
1303 | v4l2_dbg(1, debug, sd, "%s: DVI->HDMI change detected\n", | ||
1304 | __func__); | ||
1305 | |||
1306 | /* TODO: Check if reg is required. Reg not found in Rev. 1.5 */ | ||
1307 | #if 0 | ||
1308 | i2c_wr8(sd, ANA_CTL, MASK_APPL_PCSX_NORMAL | MASK_ANALOG_ON); | ||
1309 | #endif | ||
1310 | sys_int &= ~MASK_HDMI; | ||
1311 | if (handled) | ||
1312 | *handled = true; | ||
1313 | } | ||
1314 | |||
1315 | if (sys_int) { | ||
1316 | v4l2_err(sd, "%s: Unhandled SYS_INT interrupts: 0x%02x\n", | ||
1317 | __func__, sys_int); | ||
1318 | } | ||
1319 | } | ||
1320 | |||
1321 | /* --------------- CORE OPS --------------- */ | ||
1322 | |||
1323 | static int tc358840_isr(struct v4l2_subdev *sd, u32 status, bool *handled) | ||
1324 | { | ||
1325 | struct tc358840_state *state = to_state(sd); | ||
1326 | u16 intstatus; | ||
1327 | unsigned retry = 10; | ||
1328 | |||
1329 | //disable_irq_nosync(state->pdata.interrupt); | ||
1330 | intstatus = i2c_rd16(sd, INTSTATUS); | ||
1331 | |||
1332 | v4l2_dbg(1, debug, sd, "%s: IntStatus = 0x%04X\n", __func__, intstatus); | ||
1333 | |||
1334 | /* | ||
1335 | * Need to figure out why these msleeps are needed, and which of these | ||
1336 | * are needed. Without msleeps the interrupts just stop. | ||
1337 | */ | ||
1338 | usleep_range(500, 1000); | ||
1339 | state->format_changed = false; | ||
1340 | if (intstatus & MASK_HDMI_INT) { | ||
1341 | u8 hdmi_int0; | ||
1342 | u8 hdmi_int1; | ||
1343 | retry: | ||
1344 | retry--; | ||
1345 | hdmi_int0 = i2c_rd8(sd, HDMI_INT0); | ||
1346 | usleep_range(500, 1000); | ||
1347 | hdmi_int1 = i2c_rd8(sd, HDMI_INT1); | ||
1348 | usleep_range(500, 1000); | ||
1349 | |||
1350 | if (hdmi_int0 & MASK_MISC) | ||
1351 | tc358840_hdmi_misc_int_handler(sd, handled); | ||
1352 | if (hdmi_int1 & MASK_ACBIT) | ||
1353 | tc358840_hdmi_cbit_int_handler(sd, handled); | ||
1354 | if (hdmi_int1 & MASK_CLK) | ||
1355 | tc358840_hdmi_clk_int_handler(sd, handled); | ||
1356 | if (hdmi_int1 & MASK_SYS) | ||
1357 | tc358840_hdmi_sys_int_handler(sd, handled); | ||
1358 | if (hdmi_int1 & MASK_AUD) | ||
1359 | tc358840_hdmi_audio_int_handler(sd, handled); | ||
1360 | |||
1361 | usleep_range(500, 1000); | ||
1362 | i2c_wr16(sd, INTSTATUS, MASK_HDMI_INT); | ||
1363 | intstatus &= ~MASK_HDMI_INT; | ||
1364 | usleep_range(500, 1000); | ||
1365 | |||
1366 | /* Display unhandled HDMI interrupts */ | ||
1367 | hdmi_int0 = i2c_rd8(sd, HDMI_INT0); | ||
1368 | if (hdmi_int0) { | ||
1369 | v4l2_dbg(1, debug, sd, | ||
1370 | "%s: Unhandled HDMI_INT0 interrupts: 0x%02X\n", | ||
1371 | __func__, hdmi_int0); | ||
1372 | if (retry) | ||
1373 | goto retry; | ||
1374 | } | ||
1375 | usleep_range(500, 1000); | ||
1376 | hdmi_int1 = i2c_rd8(sd, HDMI_INT1); | ||
1377 | if (hdmi_int1) { | ||
1378 | v4l2_dbg(1, debug, sd, | ||
1379 | "%s: Unhandled HDMI_INT1 interrupts: 0x%02X\n", | ||
1380 | __func__, hdmi_int1); | ||
1381 | if (retry) | ||
1382 | goto retry; | ||
1383 | } | ||
1384 | } | ||
1385 | |||
1386 | if (handled && state->format_changed) { | ||
1387 | tc358840_format_change(sd); | ||
1388 | if (no_sync(sd) || no_signal(sd)) { | ||
1389 | tc358840_reset_phy(sd); | ||
1390 | tc358840_erase_bksv(sd); | ||
1391 | } | ||
1392 | } | ||
1393 | |||
1394 | if (intstatus & MASK_CSITX0_INT) { | ||
1395 | v4l2_dbg(3, debug, sd, "%s: MASK_CSITX0_INT\n", __func__); | ||
1396 | |||
1397 | i2c_wr16(sd, INTSTATUS, MASK_CSITX0_INT); | ||
1398 | intstatus &= ~MASK_CSITX0_INT; | ||
1399 | } | ||
1400 | |||
1401 | if (intstatus & MASK_CSITX1_INT) { | ||
1402 | v4l2_dbg(3, debug, sd, "%s: MASK_CSITX1_INT\n", __func__); | ||
1403 | |||
1404 | i2c_wr16(sd, INTSTATUS, MASK_CSITX1_INT); | ||
1405 | intstatus &= ~MASK_CSITX1_INT; | ||
1406 | } | ||
1407 | |||
1408 | if (intstatus) { | ||
1409 | v4l2_dbg(1, debug, sd, | ||
1410 | "%s: Unhandled IntStatus interrupts: 0x%04x\n", | ||
1411 | __func__, intstatus); | ||
1412 | } | ||
1413 | //enable_irq(state->pdata.interrupt); | ||
1414 | return 0; | ||
1415 | } | ||
1416 | |||
1417 | static void tc358840_process_isr(struct work_struct *work) | ||
1418 | { | ||
1419 | struct tc358840_state *state = container_of(work, | ||
1420 | struct tc358840_state, process_isr); | ||
1421 | struct v4l2_subdev *sd = &state->sd; | ||
1422 | bool handled; | ||
1423 | |||
1424 | v4l2_dbg(2, debug, sd, "%s:\n", __func__); | ||
1425 | |||
1426 | mutex_lock(&state->isr_lock); | ||
1427 | tc358840_isr(sd, 0, &handled); | ||
1428 | mutex_unlock(&state->isr_lock); | ||
1429 | } | ||
1430 | |||
1431 | static irqreturn_t tc358840_irq_handler(int irq, void *dev_id) | ||
1432 | { | ||
1433 | struct v4l2_subdev *sd = dev_id; | ||
1434 | struct tc358840_state *state = to_state(sd); | ||
1435 | |||
1436 | queue_work(state->work_queues, &state->process_isr); | ||
1437 | |||
1438 | return IRQ_HANDLED; | ||
1439 | } | ||
1440 | |||
1441 | /* --------------- PAD OPS --------------- */ | ||
1442 | |||
1443 | static int tc358840_get_fmt(struct v4l2_subdev *sd, | ||
1444 | struct v4l2_subdev_pad_config *cfg, | ||
1445 | struct v4l2_subdev_format *format) | ||
1446 | { | ||
1447 | struct tc358840_state *state = to_state(sd); | ||
1448 | u8 vout_csc = i2c_rd8(sd, VOUT_CSC); | ||
1449 | struct v4l2_mbus_framefmt *fmt; | ||
1450 | |||
1451 | v4l2_dbg(3, debug, sd, "%s():\n", __func__); | ||
1452 | |||
1453 | if (format->pad != 0) | ||
1454 | return -EINVAL; | ||
1455 | |||
1456 | format->format.code = state->mbus_fmt_code; | ||
1457 | format->format.width = state->timings.bt.width; | ||
1458 | format->format.height = state->timings.bt.height; | ||
1459 | format->format.field = V4L2_FIELD_NONE; | ||
1460 | |||
1461 | switch (vout_csc & MASK_COLOR) { | ||
1462 | case MASK_COLOR_RGB_FULL: | ||
1463 | case MASK_COLOR_RGB_LIMITED: | ||
1464 | format->format.colorspace = V4L2_COLORSPACE_SRGB; | ||
1465 | break; | ||
1466 | case MASK_COLOR_601_YCBCR_FULL: | ||
1467 | case MASK_COLOR_601_YCBCR_LIMITED: | ||
1468 | format->format.colorspace = V4L2_COLORSPACE_SMPTE170M; | ||
1469 | break; | ||
1470 | case MASK_COLOR_709_YCBCR_FULL: | ||
1471 | case MASK_COLOR_709_YCBCR_LIMITED: | ||
1472 | format->format.colorspace = V4L2_COLORSPACE_REC709; | ||
1473 | break; | ||
1474 | default: | ||
1475 | format->format.colorspace = 0; | ||
1476 | break; | ||
1477 | } | ||
1478 | |||
1479 | fmt = &format->format; | ||
1480 | v4l2_dbg(3, debug, sd, | ||
1481 | "%s(): width=%d, height=%d, code=0x%08X, field=%d\n", | ||
1482 | __func__, fmt->width, fmt->height, fmt->code, fmt->field); | ||
1483 | |||
1484 | return 0; | ||
1485 | } | ||
1486 | |||
1487 | static int tc358840_set_fmt(struct v4l2_subdev *sd, | ||
1488 | struct v4l2_subdev_pad_config *cfg, | ||
1489 | struct v4l2_subdev_format *format) | ||
1490 | { | ||
1491 | struct tc358840_state *state = to_state(sd); | ||
1492 | u32 code = format->format.code; /* is overwritten by get_fmt */ | ||
1493 | int ret = tc358840_get_fmt(sd, cfg, format); | ||
1494 | |||
1495 | v4l2_dbg(3, debug, sd, "%s():\n", __func__); | ||
1496 | |||
1497 | format->format.code = code; | ||
1498 | |||
1499 | if (ret) | ||
1500 | return ret; | ||
1501 | |||
1502 | switch (code) { | ||
1503 | case MEDIA_BUS_FMT_RGB888_1X24: | ||
1504 | case MEDIA_BUS_FMT_UYVY8_1X16: | ||
1505 | break; | ||
1506 | default: | ||
1507 | return -EINVAL; | ||
1508 | } | ||
1509 | |||
1510 | if (format->which == V4L2_SUBDEV_FORMAT_TRY) | ||
1511 | return 0; | ||
1512 | |||
1513 | v4l2_dbg(3, debug, sd, "%s(): format->which=%d\n", | ||
1514 | __func__, format->which); | ||
1515 | |||
1516 | state->mbus_fmt_code = format->format.code; | ||
1517 | enable_stream(sd, false); | ||
1518 | tc358840_set_csi(sd); | ||
1519 | tc358840_set_csi_mbus_config(sd); | ||
1520 | |||
1521 | return 0; | ||
1522 | } | ||
1523 | |||
1524 | static int tc358840_g_edid(struct v4l2_subdev *sd, | ||
1525 | struct v4l2_subdev_edid *edid) | ||
1526 | { | ||
1527 | struct tc358840_state *state = to_state(sd); | ||
1528 | |||
1529 | v4l2_dbg(3, debug, sd, "%s():\n", __func__); | ||
1530 | |||
1531 | memset(edid->reserved, 0, sizeof(edid->reserved)); | ||
1532 | |||
1533 | if (edid->pad != 0) | ||
1534 | return -EINVAL; | ||
1535 | |||
1536 | if (edid->start_block == 0 && edid->blocks == 0) { | ||
1537 | edid->blocks = state->edid_blocks_written; | ||
1538 | return 0; | ||
1539 | } | ||
1540 | |||
1541 | if (state->edid_blocks_written == 0) | ||
1542 | return -ENODATA; | ||
1543 | |||
1544 | if (edid->start_block >= state->edid_blocks_written || | ||
1545 | edid->blocks == 0) | ||
1546 | return -EINVAL; | ||
1547 | |||
1548 | if (edid->start_block + edid->blocks > state->edid_blocks_written) | ||
1549 | edid->blocks = state->edid_blocks_written - edid->start_block; | ||
1550 | |||
1551 | i2c_rd(sd, EDID_RAM + (edid->start_block * EDID_BLOCK_SIZE), edid->edid, | ||
1552 | edid->blocks * EDID_BLOCK_SIZE); | ||
1553 | |||
1554 | return 0; | ||
1555 | } | ||
1556 | |||
1557 | static int tc358840_s_edid(struct v4l2_subdev *sd, | ||
1558 | struct v4l2_subdev_edid *edid) | ||
1559 | { | ||
1560 | struct tc358840_state *state = to_state(sd); | ||
1561 | u16 edid_len = edid->blocks * EDID_BLOCK_SIZE; | ||
1562 | int i; | ||
1563 | |||
1564 | v4l2_dbg(2, debug, sd, "%s, pad %d, start block %d, blocks %d\n", | ||
1565 | __func__, edid->pad, edid->start_block, edid->blocks); | ||
1566 | |||
1567 | memset(edid->reserved, 0, sizeof(edid->reserved)); | ||
1568 | |||
1569 | if (edid->pad != 0) | ||
1570 | return -EINVAL; | ||
1571 | |||
1572 | if (edid->start_block != 0) | ||
1573 | return -EINVAL; | ||
1574 | |||
1575 | if (edid->blocks > EDID_NUM_BLOCKS_MAX) { | ||
1576 | edid->blocks = EDID_NUM_BLOCKS_MAX; | ||
1577 | return -E2BIG; | ||
1578 | } | ||
1579 | |||
1580 | tc358840_disable_edid(sd); | ||
1581 | |||
1582 | i2c_wr8(sd, EDID_LEN1, edid_len & 0xFF); | ||
1583 | i2c_wr8(sd, EDID_LEN2, edid_len >> 8); | ||
1584 | |||
1585 | if (edid->blocks == 0) { | ||
1586 | state->edid_blocks_written = 0; | ||
1587 | return 0; | ||
1588 | } | ||
1589 | |||
1590 | for (i = 0; i < 256; i++) { | ||
1591 | unsigned int val; | ||
1592 | val = edid->edid[i]; | ||
1593 | i2c_wr8(sd, EDID_RAM + i, val); | ||
1594 | } | ||
1595 | |||
1596 | state->edid_blocks_written = edid->blocks; | ||
1597 | |||
1598 | if (tx_5v_power_present(sd)) | ||
1599 | tc358840_enable_edid(sd); | ||
1600 | |||
1601 | return 0; | ||
1602 | } | ||
1603 | |||
1604 | static int tc358840_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, | ||
1605 | struct v4l2_event_subscription *sub) | ||
1606 | { | ||
1607 | switch (sub->type) { | ||
1608 | case V4L2_EVENT_SOURCE_CHANGE: | ||
1609 | return v4l2_src_change_event_subdev_subscribe(sd, fh, sub); | ||
1610 | case V4L2_EVENT_CTRL: | ||
1611 | return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); | ||
1612 | default: | ||
1613 | return -EINVAL; | ||
1614 | } | ||
1615 | } | ||
1616 | |||
1617 | /* --------------- VIDEO OPS --------------- */ | ||
1618 | |||
1619 | static int tc358840_g_input_status(struct v4l2_subdev *sd, u32 *status) | ||
1620 | { | ||
1621 | v4l2_dbg(3, debug, sd, "%s():\n", __func__); | ||
1622 | |||
1623 | *status = 0; | ||
1624 | *status |= no_signal(sd) ? V4L2_IN_ST_NO_SIGNAL : 0; | ||
1625 | *status |= no_sync(sd) ? V4L2_IN_ST_NO_SYNC : 0; | ||
1626 | |||
1627 | v4l2_dbg(1, debug, sd, "%s: status = 0x%x\n", __func__, *status); | ||
1628 | |||
1629 | return 0; | ||
1630 | } | ||
1631 | |||
1632 | static int tc358840_s_dv_timings(struct v4l2_subdev *sd, | ||
1633 | struct v4l2_dv_timings *timings) | ||
1634 | { | ||
1635 | struct tc358840_state *state = to_state(sd); | ||
1636 | |||
1637 | v4l2_dbg(3, debug, sd, "%s():\n", __func__); | ||
1638 | |||
1639 | if (!timings) | ||
1640 | return -EINVAL; | ||
1641 | |||
1642 | if (debug) | ||
1643 | v4l2_print_dv_timings(sd->name, "tc358840_s_dv_timings: ", | ||
1644 | timings, false); | ||
1645 | |||
1646 | if (v4l2_match_dv_timings(&state->timings, timings, 0)) { | ||
1647 | v4l2_dbg(1, debug, sd, "%s: no change\n", __func__); | ||
1648 | return 0; | ||
1649 | } | ||
1650 | |||
1651 | if (!v4l2_valid_dv_timings(timings, &tc358840_timings_cap, NULL, NULL)) { | ||
1652 | v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__); | ||
1653 | return -ERANGE; | ||
1654 | } | ||
1655 | |||
1656 | state->timings = *timings; | ||
1657 | |||
1658 | enable_stream(sd, false); | ||
1659 | tc358840_set_csi(sd); | ||
1660 | tc358840_set_splitter(sd); | ||
1661 | |||
1662 | return 0; | ||
1663 | } | ||
1664 | |||
1665 | static int tc358840_g_dv_timings(struct v4l2_subdev *sd, | ||
1666 | struct v4l2_dv_timings *timings) | ||
1667 | { | ||
1668 | struct tc358840_state *state = to_state(sd); | ||
1669 | |||
1670 | v4l2_dbg(3, debug, sd, "%s():\n", __func__); | ||
1671 | |||
1672 | *timings = state->timings; | ||
1673 | |||
1674 | return 0; | ||
1675 | } | ||
1676 | |||
1677 | static int tc358840_enum_dv_timings(struct v4l2_subdev *sd, | ||
1678 | struct v4l2_enum_dv_timings *timings) | ||
1679 | { | ||
1680 | v4l2_dbg(3, debug, sd, "%s(): DUMMY\n", __func__); | ||
1681 | |||
1682 | if (timings->pad != 0) | ||
1683 | return -EINVAL; | ||
1684 | |||
1685 | return v4l2_enum_dv_timings_cap(timings, | ||
1686 | &tc358840_timings_cap, NULL, NULL); | ||
1687 | } | ||
1688 | |||
1689 | static int tc358840_query_dv_timings(struct v4l2_subdev *sd, | ||
1690 | struct v4l2_dv_timings *timings) | ||
1691 | { | ||
1692 | int ret; | ||
1693 | |||
1694 | v4l2_dbg(3, debug, sd, "%s():\n", __func__); | ||
1695 | |||
1696 | ret = tc358840_get_detected_timings(sd, timings); | ||
1697 | if (ret) | ||
1698 | return ret; | ||
1699 | |||
1700 | if (debug) | ||
1701 | v4l2_print_dv_timings(sd->name, "tc358840_query_dv_timings: ", | ||
1702 | timings, false); | ||
1703 | if (!v4l2_valid_dv_timings(timings, &tc358840_timings_cap, NULL, NULL)) { | ||
1704 | v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__); | ||
1705 | return -ERANGE; | ||
1706 | } | ||
1707 | |||
1708 | return 0; | ||
1709 | } | ||
1710 | |||
1711 | static int tc358840_dv_timings_cap(struct v4l2_subdev *sd, | ||
1712 | struct v4l2_dv_timings_cap *cap) | ||
1713 | { | ||
1714 | v4l2_dbg(3, debug, sd, "%s():\n", __func__); | ||
1715 | |||
1716 | if (cap->pad != 0) | ||
1717 | return -EINVAL; | ||
1718 | |||
1719 | *cap = tc358840_timings_cap; | ||
1720 | |||
1721 | return 0; | ||
1722 | } | ||
1723 | |||
1724 | static int tc358840_g_mbus_config(struct v4l2_subdev *sd, | ||
1725 | struct v4l2_mbus_config *cfg) | ||
1726 | { | ||
1727 | v4l2_dbg(3, debug, sd, "%s():\n", __func__); | ||
1728 | |||
1729 | cfg->type = V4L2_MBUS_CSI2; | ||
1730 | |||
1731 | /* Support for non-continuous CSI-2 clock is missing in the driver */ | ||
1732 | cfg->flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK | V4L2_MBUS_CSI2_CHANNEL_0; | ||
1733 | |||
1734 | switch (tc358840_num_csi_lanes_in_use(sd)) { | ||
1735 | case 1: | ||
1736 | cfg->flags |= V4L2_MBUS_CSI2_1_LANE; | ||
1737 | break; | ||
1738 | case 2: | ||
1739 | cfg->flags |= V4L2_MBUS_CSI2_2_LANE; | ||
1740 | break; | ||
1741 | case 3: | ||
1742 | cfg->flags |= V4L2_MBUS_CSI2_3_LANE; | ||
1743 | break; | ||
1744 | case 4: | ||
1745 | cfg->flags |= V4L2_MBUS_CSI2_4_LANE; | ||
1746 | break; | ||
1747 | default: | ||
1748 | return -EINVAL; | ||
1749 | } | ||
1750 | |||
1751 | v4l2_dbg(2, debug, sd, "%s: Lanes: 0x%02X\n", | ||
1752 | __func__, cfg->flags & 0x0F); | ||
1753 | |||
1754 | return 0; | ||
1755 | } | ||
1756 | |||
1757 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1758 | static int tc358840_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) | ||
1759 | { | ||
1760 | switch (reg->size) { | ||
1761 | case 1: | ||
1762 | reg->val = i2c_rd8(sd, reg->reg); | ||
1763 | break; | ||
1764 | case 2: | ||
1765 | reg->val = i2c_rd16(sd, reg->reg); | ||
1766 | break; | ||
1767 | case 4: | ||
1768 | default: | ||
1769 | reg->val = i2c_rd32(sd, reg->reg); | ||
1770 | break; | ||
1771 | } | ||
1772 | return 0; | ||
1773 | } | ||
1774 | |||
1775 | static int tc358840_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) | ||
1776 | { | ||
1777 | switch (reg->size) { | ||
1778 | case 1: | ||
1779 | i2c_wr8(sd, reg->reg, reg->val); | ||
1780 | break; | ||
1781 | case 2: | ||
1782 | i2c_wr16(sd, reg->reg, reg->val); | ||
1783 | break; | ||
1784 | case 4: | ||
1785 | default: | ||
1786 | i2c_wr32(sd, reg->reg, reg->val); | ||
1787 | break; | ||
1788 | } | ||
1789 | return 0; | ||
1790 | } | ||
1791 | #endif | ||
1792 | |||
1793 | static int tc358840_log_status(struct v4l2_subdev *sd) | ||
1794 | { | ||
1795 | struct tc358840_state *state = to_state(sd); | ||
1796 | struct v4l2_dv_timings timings; | ||
1797 | u8 hdmi_sys_status = i2c_rd8(sd, SYS_STATUS); | ||
1798 | u16 sysctl = i2c_rd16(sd, SYSCTL); | ||
1799 | u8 vi_status3 = i2c_rd8(sd, VI_STATUS3); | ||
1800 | const int deep_color_mode[4] = { 8, 10, 12, 16 }; | ||
1801 | static const char * const input_color_space[] = { | ||
1802 | "RGB", "YCbCr 601", "Adobe RGB", "YCbCr 709", "NA (4)", | ||
1803 | "xvYCC 601", "NA(6)", "xvYCC 709", "NA(8)", "sYCC601", | ||
1804 | "NA(10)", "NA(11)", "NA(12)", "Adobe YCC 601"}; | ||
1805 | |||
1806 | v4l2_ctrl_subdev_log_status(sd); | ||
1807 | v4l2_info(sd, "-----Chip status-----\n"); | ||
1808 | v4l2_info(sd, "Chip ID: 0x%02x\n", | ||
1809 | (i2c_rd16(sd, CHIPID_ADDR) & MASK_CHIPID) >> 8); | ||
1810 | v4l2_info(sd, "Chip revision: 0x%02x\n", | ||
1811 | i2c_rd16(sd, CHIPID_ADDR) & MASK_REVID); | ||
1812 | v4l2_info(sd, "Reset: IR: %d, CEC: %d, CSI TX: %d, HDMI: %d\n", | ||
1813 | !!(sysctl & MASK_IRRST), | ||
1814 | !!(sysctl & MASK_CECRST), | ||
1815 | !!(sysctl & MASK_CTXRST), | ||
1816 | !!(sysctl & MASK_HDMIRST)); | ||
1817 | v4l2_info(sd, "Sleep mode: %s\n", sysctl & MASK_SLEEP ? "on" : "off"); | ||
1818 | v4l2_info(sd, "Cable detected (+5V power): %s\n", | ||
1819 | hdmi_sys_status & MASK_S_DDC5V ? "yes" : "no"); | ||
1820 | v4l2_info(sd, "DDC lines enabled: %s\n", | ||
1821 | (i2c_rd8(sd, EDID_MODE) & MASK_EDID_MODE_ALL) ? | ||
1822 | "yes" : "no"); | ||
1823 | v4l2_info(sd, "Hotplug enabled: %s\n", | ||
1824 | (i2c_rd8(sd, HPD_CTL) & MASK_HPD_OUT0) ? | ||
1825 | "yes" : "no"); | ||
1826 | v4l2_info(sd, "CEC enabled: %s\n", | ||
1827 | (i2c_rd16(sd, CECEN) & MASK_CECEN) ? "yes" : "no"); | ||
1828 | v4l2_info(sd, "-----Signal status-----\n"); | ||
1829 | v4l2_info(sd, "TMDS signal detected: %s\n", | ||
1830 | hdmi_sys_status & MASK_S_TMDS ? "yes" : "no"); | ||
1831 | v4l2_info(sd, "Stable sync signal: %s\n", | ||
1832 | hdmi_sys_status & MASK_S_SYNC ? "yes" : "no"); | ||
1833 | v4l2_info(sd, "PHY PLL locked: %s\n", | ||
1834 | hdmi_sys_status & MASK_S_PHY_PLL ? "yes" : "no"); | ||
1835 | v4l2_info(sd, "PHY DE detected: %s\n", | ||
1836 | hdmi_sys_status & MASK_S_PHY_SCDT ? "yes" : "no"); | ||
1837 | |||
1838 | if (tc358840_get_detected_timings(sd, &timings)) { | ||
1839 | v4l2_info(sd, "No video detected\n"); | ||
1840 | } else { | ||
1841 | v4l2_print_dv_timings(sd->name, "Detected format: ", &timings, | ||
1842 | true); | ||
1843 | } | ||
1844 | v4l2_print_dv_timings(sd->name, "Configured format: ", &state->timings, | ||
1845 | true); | ||
1846 | |||
1847 | v4l2_info(sd, "-----CSI-TX status-----\n"); | ||
1848 | v4l2_info(sd, "Lanes needed: %d\n", | ||
1849 | tc358840_num_csi_lanes_needed(sd)); | ||
1850 | v4l2_info(sd, "Lanes in use: %d\n", | ||
1851 | tc358840_num_csi_lanes_in_use(sd)); | ||
1852 | v4l2_info(sd, "Splitter %sabled\n", | ||
1853 | (i2c_rd16(sd, SPLITTX0_CTRL) & MASK_SPBP) ? "dis" : "en"); | ||
1854 | /* | ||
1855 | v4l2_info(sd, "Waiting for particular sync signal: %s\n", | ||
1856 | (i2c_rd16(sd, CSI_STATUS) & MASK_S_WSYNC) ? | ||
1857 | "yes" : "no"); | ||
1858 | v4l2_info(sd, "Transmit mode: %s\n", | ||
1859 | (i2c_rd16(sd, CSI_STATUS) & MASK_S_TXACT) ? | ||
1860 | "yes" : "no"); | ||
1861 | v4l2_info(sd, "Receive mode: %s\n", | ||
1862 | (i2c_rd16(sd, CSI_STATUS) & MASK_S_RXACT) ? | ||
1863 | "yes" : "no"); | ||
1864 | v4l2_info(sd, "Stopped: %s\n", | ||
1865 | (i2c_rd16(sd, CSI_STATUS) & MASK_S_HLT) ? | ||
1866 | "yes" : "no");*/ | ||
1867 | v4l2_info(sd, "Color space: %s\n", | ||
1868 | state->mbus_fmt_code == MEDIA_BUS_FMT_UYVY8_1X16 ? | ||
1869 | "YCbCr 422 16-bit" : | ||
1870 | state->mbus_fmt_code == MEDIA_BUS_FMT_RGB888_1X24 ? | ||
1871 | "RGB 888 24-bit" : "Unsupported"); | ||
1872 | |||
1873 | v4l2_info(sd, "-----%s status-----\n", is_hdmi(sd) ? "HDMI" : "DVI-D"); | ||
1874 | v4l2_info(sd, "HDCP encrypted content: %s\n", | ||
1875 | hdmi_sys_status & MASK_S_HDCP ? "yes" : "no"); | ||
1876 | v4l2_info(sd, "Input color space: %s %s range\n", | ||
1877 | input_color_space[(vi_status3 & MASK_S_V_COLOR) >> 1], | ||
1878 | (vi_status3 & MASK_LIMITED) ? "limited" : "full"); | ||
1879 | if (!is_hdmi(sd)) | ||
1880 | return 0; | ||
1881 | v4l2_info(sd, "AV Mute: %s\n", hdmi_sys_status & MASK_S_AVMUTE ? "on" : | ||
1882 | "off"); | ||
1883 | v4l2_info(sd, "Deep color mode: %d-bits per channel\n", | ||
1884 | deep_color_mode[(i2c_rd8(sd, VI_STATUS1) & | ||
1885 | MASK_S_DEEPCOLOR) >> 2]); | ||
1886 | print_avi_infoframe(sd); | ||
1887 | |||
1888 | return 0; | ||
1889 | } | ||
1890 | |||
1891 | static int tc358840_s_stream(struct v4l2_subdev *sd, int enable) | ||
1892 | { | ||
1893 | v4l2_dbg(3, debug, sd, "%s():\n", __func__); | ||
1894 | |||
1895 | return enable_stream(sd, enable); | ||
1896 | } | ||
1897 | |||
1898 | static int tc358840_enum_mbus_code(struct v4l2_subdev *sd, | ||
1899 | struct v4l2_subdev_pad_config *cfg, | ||
1900 | struct v4l2_subdev_mbus_code_enum *code) | ||
1901 | { | ||
1902 | v4l2_dbg(2, debug, sd, "%s()\n", __func__); | ||
1903 | |||
1904 | if (code->index >= 2) | ||
1905 | return -EINVAL; | ||
1906 | |||
1907 | switch (code->index) { | ||
1908 | case 0: | ||
1909 | code->code = MEDIA_BUS_FMT_UYVY8_1X16; | ||
1910 | break; | ||
1911 | case 1: | ||
1912 | code->code = MEDIA_BUS_FMT_RGB888_1X24; | ||
1913 | break; | ||
1914 | } | ||
1915 | return 0; | ||
1916 | } | ||
1917 | |||
1918 | static int tc358840_enum_framesizes(struct v4l2_subdev *sd, | ||
1919 | struct v4l2_subdev_pad_config *cfg, | ||
1920 | struct v4l2_subdev_frame_size_enum *fse) | ||
1921 | { | ||
1922 | const struct camera_common_frmfmt *frmfmt = tc358840_frmfmt; | ||
1923 | int num_frmfmt = ARRAY_SIZE(tc358840_frmfmt); | ||
1924 | |||
1925 | v4l2_dbg(2, debug, sd, "%s()\n", __func__); | ||
1926 | |||
1927 | if (fse->code != V4L2_PIX_FMT_UYVY && | ||
1928 | fse->code != V4L2_PIX_FMT_ABGR32) | ||
1929 | return -EINVAL; | ||
1930 | |||
1931 | if (fse->index >= num_frmfmt) | ||
1932 | return -EINVAL; | ||
1933 | |||
1934 | fse->min_width = fse->max_width = frmfmt[fse->index].size.width; | ||
1935 | fse->min_height = fse->max_height = frmfmt[fse->index].size.height; | ||
1936 | |||
1937 | return 0; | ||
1938 | } | ||
1939 | |||
1940 | static int tc358840_enum_frameintervals(struct v4l2_subdev *sd, | ||
1941 | struct v4l2_subdev_pad_config *cfg, | ||
1942 | struct v4l2_subdev_frame_interval_enum *fie) | ||
1943 | { | ||
1944 | const struct camera_common_frmfmt *frmfmt = tc358840_frmfmt; | ||
1945 | int num_frmfmt = ARRAY_SIZE(tc358840_frmfmt); | ||
1946 | int i; | ||
1947 | |||
1948 | v4l2_dbg(2, debug, sd, "%s()\n", __func__); | ||
1949 | |||
1950 | if (fie->code != V4L2_PIX_FMT_UYVY && | ||
1951 | fie->code != V4L2_PIX_FMT_ABGR32) | ||
1952 | return -EINVAL; | ||
1953 | |||
1954 | for (i = 0; i < num_frmfmt; i++) { | ||
1955 | if (frmfmt[i].size.width == fie->width && | ||
1956 | frmfmt[i].size.height == fie->height) | ||
1957 | break; | ||
1958 | } | ||
1959 | if (i >= num_frmfmt) | ||
1960 | return -EINVAL; | ||
1961 | |||
1962 | if (fie->index >= frmfmt[i].num_framerates) | ||
1963 | return -EINVAL; | ||
1964 | |||
1965 | fie->interval.numerator = 1; | ||
1966 | fie->interval.denominator = frmfmt[i].framerates[fie->index]; | ||
1967 | |||
1968 | return 0; | ||
1969 | } | ||
1970 | |||
1971 | static int tc358840_s_power(struct v4l2_subdev *sd, int on) | ||
1972 | { | ||
1973 | return 0; | ||
1974 | } | ||
1975 | |||
1976 | static struct v4l2_subdev_video_ops tc358840_subdev_video_ops = { | ||
1977 | .g_input_status = tc358840_g_input_status, | ||
1978 | .s_dv_timings = tc358840_s_dv_timings, | ||
1979 | .g_dv_timings = tc358840_g_dv_timings, | ||
1980 | .query_dv_timings = tc358840_query_dv_timings, | ||
1981 | .g_mbus_config = tc358840_g_mbus_config, | ||
1982 | .s_stream = tc358840_s_stream, | ||
1983 | }; | ||
1984 | |||
1985 | static struct v4l2_subdev_core_ops tc358840_subdev_core_ops = { | ||
1986 | .s_power = tc358840_s_power, | ||
1987 | .log_status = tc358840_log_status, | ||
1988 | .interrupt_service_routine = tc358840_isr, | ||
1989 | .subscribe_event = tc358840_subscribe_event, | ||
1990 | .unsubscribe_event = v4l2_event_subdev_unsubscribe, | ||
1991 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1992 | .g_register = tc358840_g_register, | ||
1993 | .s_register = tc358840_s_register, | ||
1994 | #endif | ||
1995 | }; | ||
1996 | |||
1997 | static const struct v4l2_subdev_pad_ops tc358840_pad_ops = { | ||
1998 | .set_fmt = tc358840_set_fmt, | ||
1999 | .get_fmt = tc358840_get_fmt, | ||
2000 | .enum_mbus_code = tc358840_enum_mbus_code, | ||
2001 | .get_edid = tc358840_g_edid, | ||
2002 | .set_edid = tc358840_s_edid, | ||
2003 | .dv_timings_cap = tc358840_dv_timings_cap, | ||
2004 | .enum_dv_timings = tc358840_enum_dv_timings, | ||
2005 | .enum_frame_size = tc358840_enum_framesizes, | ||
2006 | .enum_frame_interval = tc358840_enum_frameintervals, | ||
2007 | }; | ||
2008 | |||
2009 | static struct v4l2_subdev_ops tc358840_ops = { | ||
2010 | .core = &tc358840_subdev_core_ops, | ||
2011 | .video = &tc358840_subdev_video_ops, | ||
2012 | .pad = &tc358840_pad_ops, | ||
2013 | }; | ||
2014 | |||
2015 | |||
2016 | /* --------------- CUSTOM CTRLS --------------- */ | ||
2017 | |||
2018 | static const struct v4l2_ctrl_config tc358840_ctrl_audio_sampling_rate = { | ||
2019 | .id = TC358840_CID_AUDIO_SAMPLING_RATE, | ||
2020 | .name = "Audio sampling rate", | ||
2021 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
2022 | .min = 0, | ||
2023 | .max = 768000, | ||
2024 | .step = 1, | ||
2025 | .def = 0, | ||
2026 | .flags = V4L2_CTRL_FLAG_READ_ONLY, | ||
2027 | }; | ||
2028 | |||
2029 | static const struct v4l2_ctrl_config tc358840_ctrl_audio_present = { | ||
2030 | .id = TC358840_CID_AUDIO_PRESENT, | ||
2031 | .name = "Audio present", | ||
2032 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
2033 | .min = 0, | ||
2034 | .max = 1, | ||
2035 | .step = 1, | ||
2036 | .def = 0, | ||
2037 | .flags = V4L2_CTRL_FLAG_READ_ONLY, | ||
2038 | }; | ||
2039 | |||
2040 | static const struct v4l2_ctrl_config tc358840_ctrl_splitter_width = { | ||
2041 | .id = TC358840_CID_SPLITTER_WIDTH, | ||
2042 | .name = "Splitter Width", | ||
2043 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
2044 | .min = 320, | ||
2045 | .max = 1920, | ||
2046 | .step = 16, | ||
2047 | .def = 1920, | ||
2048 | .flags = V4L2_CTRL_FLAG_READ_ONLY, | ||
2049 | }; | ||
2050 | |||
2051 | /* --------------- PROBE / REMOVE --------------- */ | ||
2052 | |||
2053 | #ifdef CONFIG_OF | ||
2054 | |||
2055 | static bool tc358840_parse_dt(struct tc358840_platform_data *pdata, | ||
2056 | struct i2c_client *client) | ||
2057 | { | ||
2058 | struct device_node *node = client->dev.of_node; | ||
2059 | const u32 *property; | ||
2060 | |||
2061 | v4l_dbg(1, debug, client, "Device Tree Parameters:\n"); | ||
2062 | |||
2063 | pdata->reset_gpio = of_get_named_gpio(node, "reset-gpios", 0); | ||
2064 | if (pdata->reset_gpio == 0) | ||
2065 | return false; | ||
2066 | v4l_dbg(1, debug, client, "reset_gpio = %d\n", pdata->reset_gpio); | ||
2067 | |||
2068 | // if (v4l2_of_parse_endpoint(node, &pdata->endpoint)) | ||
2069 | // return false; | ||
2070 | |||
2071 | property = of_get_property(node, "refclk_hz", NULL); | ||
2072 | if (property == NULL) | ||
2073 | return false; | ||
2074 | pdata->refclk_hz = be32_to_cpup(property); | ||
2075 | v4l_dbg(1, debug, client, "refclk_hz = %d\n", be32_to_cpup(property)); | ||
2076 | |||
2077 | property = of_get_property(node, "ddc5v_delay", NULL); | ||
2078 | if (property == NULL) | ||
2079 | return false; | ||
2080 | pdata->ddc5v_delay = be32_to_cpup(property); | ||
2081 | if (pdata->ddc5v_delay > DDC5V_DELAY_MAX) | ||
2082 | pdata->ddc5v_delay = DDC5V_DELAY_MAX; | ||
2083 | v4l_dbg(1, debug, client, "ddc5v_delay = %d ms\n", | ||
2084 | 50 * pdata->ddc5v_delay); | ||
2085 | |||
2086 | property = of_get_property(node, "enable_hdcp", NULL); | ||
2087 | if (property == NULL) | ||
2088 | return false; | ||
2089 | pdata->enable_hdcp = be32_to_cpup(property); | ||
2090 | v4l_dbg(1, debug, client, "enable_hdcp = %d\n", be32_to_cpup(property)); | ||
2091 | |||
2092 | property = of_get_property(node, "csi_port", NULL); | ||
2093 | if (property == NULL) | ||
2094 | return false; | ||
2095 | pdata->csi_port = be32_to_cpup(property); | ||
2096 | v4l_dbg(1, debug, client, "csi_port = %d\n", be32_to_cpup(property)); | ||
2097 | |||
2098 | property = of_get_property(node, "lineinitcnt", NULL); | ||
2099 | if (property == NULL) | ||
2100 | return false; | ||
2101 | pdata->lineinitcnt = be32_to_cpup(property); | ||
2102 | v4l_dbg(1, debug, client, "lineinitcnt = %d\n", be32_to_cpup(property)); | ||
2103 | |||
2104 | property = of_get_property(node, "lptxtimecnt", NULL); | ||
2105 | if (property == NULL) | ||
2106 | return false; | ||
2107 | pdata->lptxtimecnt = be32_to_cpup(property); | ||
2108 | v4l_dbg(1, debug, client, "lptxtimecnt = %d\n", be32_to_cpup(property)); | ||
2109 | |||
2110 | property = of_get_property(node, "tclk_headercnt", NULL); | ||
2111 | if (property == NULL) | ||
2112 | return false; | ||
2113 | pdata->tclk_headercnt = be32_to_cpup(property); | ||
2114 | v4l_dbg(1, debug, client, "tclk_headercnt = %d\n", | ||
2115 | be32_to_cpup(property)); | ||
2116 | |||
2117 | property = of_get_property(node, "tclk_trailcnt", NULL); | ||
2118 | if (property == NULL) | ||
2119 | return false; | ||
2120 | pdata->tclk_trailcnt = be32_to_cpup(property); | ||
2121 | v4l_dbg(1, debug, client, "tclk_trailcnt = %d\n", | ||
2122 | be32_to_cpup(property)); | ||
2123 | |||
2124 | property = of_get_property(node, "ths_headercnt", NULL); | ||
2125 | if (property == NULL) | ||
2126 | return false; | ||
2127 | pdata->ths_headercnt = be32_to_cpup(property); | ||
2128 | v4l_dbg(1, debug, client, "ths_headercnt = %d\n", | ||
2129 | be32_to_cpup(property)); | ||
2130 | |||
2131 | property = of_get_property(node, "twakeup", NULL); | ||
2132 | if (property == NULL) | ||
2133 | return false; | ||
2134 | pdata->twakeup = be32_to_cpup(property); | ||
2135 | v4l_dbg(1, debug, client, "twakeup = %d\n", be32_to_cpup(property)); | ||
2136 | |||
2137 | property = of_get_property(node, "tclk_postcnt", NULL); | ||
2138 | if (property == NULL) | ||
2139 | return false; | ||
2140 | pdata->tclk_postcnt = be32_to_cpup(property); | ||
2141 | v4l_dbg(1, debug, client, "tclk_postcnt = %d\n", | ||
2142 | be32_to_cpup(property)); | ||
2143 | |||
2144 | property = of_get_property(node, "ths_trailcnt", NULL); | ||
2145 | if (property == NULL) | ||
2146 | return false; | ||
2147 | pdata->ths_trailcnt = be32_to_cpup(property); | ||
2148 | v4l_dbg(1, debug, client, "ths_trailcnt = %d\n", | ||
2149 | be32_to_cpup(property)); | ||
2150 | |||
2151 | property = of_get_property(node, "hstxvregcnt", NULL); | ||
2152 | if (property == NULL) | ||
2153 | return false; | ||
2154 | pdata->hstxvregcnt = be32_to_cpup(property); | ||
2155 | v4l_dbg(1, debug, client, "hstxvregcnt = %d\n", be32_to_cpup(property)); | ||
2156 | |||
2157 | property = of_get_property(node, "pll_prd", NULL); | ||
2158 | if (property == NULL) | ||
2159 | return false; | ||
2160 | pdata->pll_prd = be32_to_cpup(property); | ||
2161 | v4l_dbg(1, debug, client, "pll_prd = %d\n", be32_to_cpup(property)); | ||
2162 | |||
2163 | property = of_get_property(node, "pll_fbd", NULL); | ||
2164 | if (property == NULL) | ||
2165 | return false; | ||
2166 | pdata->pll_fbd = be32_to_cpup(property); | ||
2167 | v4l_dbg(1, debug, client, "pll_fbd = %d\n", be32_to_cpup(property)); | ||
2168 | |||
2169 | return true; | ||
2170 | } | ||
2171 | #endif | ||
2172 | |||
2173 | static int tc358840_pwr_init(struct tc358840_platform_data *pdata, | ||
2174 | struct i2c_client *client) | ||
2175 | { | ||
2176 | struct device_node *node = client->dev.of_node; | ||
2177 | int cam2_rst; | ||
2178 | int err; | ||
2179 | struct regulator *dvdd; | ||
2180 | struct regulator *iovdd; | ||
2181 | |||
2182 | err = camera_common_regulator_get(client, &iovdd, "vif"); | ||
2183 | if (err < 0) { | ||
2184 | dev_err(&client->dev, "cannot get regulator vif %d\n", err); | ||
2185 | return -EINVAL; | ||
2186 | } | ||
2187 | |||
2188 | err = camera_common_regulator_get(client, &dvdd, "vdig"); | ||
2189 | if (err < 0) { | ||
2190 | dev_err(&client->dev, "cannot get regulator vdig %d\n", err); | ||
2191 | return -EINVAL; | ||
2192 | } | ||
2193 | |||
2194 | /* cam2 rst */ | ||
2195 | cam2_rst = of_get_named_gpio(node, "cam2_rst", 0); | ||
2196 | if (cam2_rst == 0) | ||
2197 | return false; | ||
2198 | err = gpio_request(cam2_rst, "cam2-rst"); | ||
2199 | if (err < 0) | ||
2200 | dev_err(&client->dev, | ||
2201 | "cam2 rst gpio request failed %d\n", err); | ||
2202 | |||
2203 | gpio_direction_output(cam2_rst, 1); | ||
2204 | |||
2205 | if (dvdd) { | ||
2206 | err = regulator_enable(dvdd); | ||
2207 | if (err < 0) { | ||
2208 | dev_err(&client->dev, "cannot enable regulator vif %d\n", err); | ||
2209 | return -EINVAL; | ||
2210 | } | ||
2211 | } | ||
2212 | if (iovdd) { | ||
2213 | err = regulator_enable(iovdd); | ||
2214 | if (err < 0) { | ||
2215 | dev_err(&client->dev, "cannot enable regulator vdig %d\n", err); | ||
2216 | return -EINVAL; | ||
2217 | } | ||
2218 | } | ||
2219 | gpio_direction_output(cam2_rst, 1); | ||
2220 | |||
2221 | return true; | ||
2222 | } | ||
2223 | |||
2224 | static int tc358840_verify_chipid(struct v4l2_subdev *sd) | ||
2225 | { | ||
2226 | u16 cid = 0; | ||
2227 | |||
2228 | cid = i2c_rd16(sd, CHIPID_ADDR); | ||
2229 | if (cid != TC358840_CHIPID) { | ||
2230 | v4l2_err(sd, "Invalid chip ID 0x%04X\n", cid); | ||
2231 | return -ENODEV; | ||
2232 | } | ||
2233 | |||
2234 | v4l2_dbg(1, debug, sd, "TC358840 ChipID 0x%02x, Revision 0x%02x\n", | ||
2235 | (cid & MASK_CHIPID) >> 8, cid & MASK_REVID); | ||
2236 | |||
2237 | return 0; | ||
2238 | } | ||
2239 | |||
2240 | static int tc358840_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
2241 | { | ||
2242 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
2243 | |||
2244 | dev_dbg(&client->dev, "%s:\n", __func__); | ||
2245 | return 0; | ||
2246 | } | ||
2247 | |||
2248 | static const struct v4l2_subdev_internal_ops tc358840_subdev_internal_ops = { | ||
2249 | .open = tc358840_open, | ||
2250 | }; | ||
2251 | |||
2252 | static const struct media_entity_operations tc358840_media_ops = { | ||
2253 | #ifdef CONFIG_MEDIA_CONTROLLER | ||
2254 | .link_validate = v4l2_subdev_link_validate, | ||
2255 | #endif | ||
2256 | }; | ||
2257 | |||
2258 | static int tc358840_probe(struct i2c_client *client, const struct i2c_device_id *id) | ||
2259 | { | ||
2260 | struct tc358840_state *state; | ||
2261 | struct v4l2_subdev *sd; | ||
2262 | int err; | ||
2263 | |||
2264 | state = devm_kzalloc(&client->dev, sizeof(struct tc358840_state), GFP_KERNEL); | ||
2265 | if (!state) | ||
2266 | return -ENOMEM; | ||
2267 | |||
2268 | if (client->dev.of_node) { | ||
2269 | if (!tc358840_parse_dt(&state->pdata, client)) { | ||
2270 | v4l_err(client, "Couldn't parse device tree\n"); | ||
2271 | return -ENODEV; | ||
2272 | } | ||
2273 | if (!tc358840_pwr_init(&state->pdata, client)) { | ||
2274 | v4l_err(client, "Couldn't power init\n"); | ||
2275 | return -ENODEV; | ||
2276 | } | ||
2277 | } else { | ||
2278 | if (!client->dev.platform_data) { | ||
2279 | v4l_err(client, "No platform data!\n"); | ||
2280 | return -ENODEV; | ||
2281 | } | ||
2282 | state->pdata = *(struct tc358840_platform_data *)client->dev.platform_data; | ||
2283 | } | ||
2284 | |||
2285 | state->i2c_client = client; | ||
2286 | sd = &state->sd; | ||
2287 | |||
2288 | i2c_set_clientdata(client, state); | ||
2289 | |||
2290 | v4l2_i2c_subdev_init(sd, client, &tc358840_ops); | ||
2291 | |||
2292 | /* Release System Reset (pin K8) */ | ||
2293 | v4l2_info(sd, "Releasing System Reset (gpio 0x%04X)\n", | ||
2294 | state->pdata.reset_gpio); | ||
2295 | if (!gpio_is_valid(state->pdata.reset_gpio)) { | ||
2296 | v4l_err(client, "Reset GPIO is invalid!\n"); | ||
2297 | return state->pdata.reset_gpio; | ||
2298 | } | ||
2299 | err = devm_gpio_request_one(&client->dev, state->pdata.reset_gpio, | ||
2300 | GPIOF_OUT_INIT_HIGH, "tc358840-reset"); | ||
2301 | if (err) { | ||
2302 | dev_err(&client->dev, | ||
2303 | "Failed to request Reset GPIO 0x%04X: %d\n", | ||
2304 | state->pdata.reset_gpio, err); | ||
2305 | return err; | ||
2306 | } | ||
2307 | |||
2308 | /* */ | ||
2309 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
2310 | return -EIO; | ||
2311 | v4l_info(client, "Chip found @ 7h%02X (%s)\n", | ||
2312 | client->addr, client->adapter->name); | ||
2313 | |||
2314 | |||
2315 | /* Verify chip ID */ | ||
2316 | err = tc358840_verify_chipid(sd); | ||
2317 | if (err) | ||
2318 | return err; | ||
2319 | |||
2320 | /* Control Handlers */ | ||
2321 | v4l2_ctrl_handler_init(&state->hdl, 4); | ||
2322 | |||
2323 | /* Custom controls */ | ||
2324 | state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(&state->hdl, NULL, | ||
2325 | V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0); | ||
2326 | |||
2327 | state->audio_sampling_rate_ctrl = v4l2_ctrl_new_custom(&state->hdl, | ||
2328 | &tc358840_ctrl_audio_sampling_rate, NULL); | ||
2329 | |||
2330 | state->audio_present_ctrl = v4l2_ctrl_new_custom(&state->hdl, | ||
2331 | &tc358840_ctrl_audio_present, NULL); | ||
2332 | |||
2333 | state->splitter_width_ctrl = v4l2_ctrl_new_custom(&state->hdl, | ||
2334 | &tc358840_ctrl_splitter_width, NULL); | ||
2335 | |||
2336 | if (state->hdl.error) { | ||
2337 | err = state->hdl.error; | ||
2338 | goto err_hdl; | ||
2339 | } | ||
2340 | |||
2341 | sd->ctrl_handler = &state->hdl; | ||
2342 | |||
2343 | if (tc358840_update_controls(sd)) { | ||
2344 | err = -ENODEV; | ||
2345 | goto err_hdl; | ||
2346 | } | ||
2347 | |||
2348 | /* Work Queues */ | ||
2349 | state->work_queues = create_singlethread_workqueue(client->name); | ||
2350 | if (!state->work_queues) { | ||
2351 | v4l2_err(sd, "Could not create work queue!\n"); | ||
2352 | err = -ENOMEM; | ||
2353 | goto err_hdl; | ||
2354 | } | ||
2355 | INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, | ||
2356 | tc358840_delayed_work_enable_hotplug); | ||
2357 | INIT_DELAYED_WORK(&state->delayed_work_enable_interrupt, | ||
2358 | tc358840_delayed_work_enable_interrupt); | ||
2359 | INIT_WORK(&state->process_isr, tc358840_process_isr); | ||
2360 | mutex_init(&state->isr_lock); | ||
2361 | |||
2362 | /* Initial Setup */ | ||
2363 | state->mbus_fmt_code = MEDIA_BUS_FMT_UYVY8_1X16; | ||
2364 | tc358840_initial_setup(sd); | ||
2365 | |||
2366 | tc358840_set_csi_mbus_config(sd); | ||
2367 | |||
2368 | /* Get interrupt */ | ||
2369 | if (client->irq) { | ||
2370 | err = devm_request_threaded_irq(&state->i2c_client->dev, | ||
2371 | client->irq, NULL, tc358840_irq_handler, | ||
2372 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, | ||
2373 | sd->name, (void *)sd); | ||
2374 | if (err) { | ||
2375 | v4l2_err(sd, "Could not request interrupt %d!\n", | ||
2376 | client->irq); | ||
2377 | goto err_hdl; | ||
2378 | } | ||
2379 | } | ||
2380 | |||
2381 | queue_delayed_work(state->work_queues, | ||
2382 | &state->delayed_work_enable_interrupt, | ||
2383 | msecs_to_jiffies(DELAY_ENABLE_INTERRUPT_MS)); | ||
2384 | |||
2385 | /* | ||
2386 | * FIXME: Don't know what MASK_CSITX0_INT and MASK_CSITX1_INT do. | ||
2387 | * Thus, disable them for now... | ||
2388 | */ | ||
2389 | #if 0 | ||
2390 | i2c_wr16(sd, INTMASK, ~(MASK_HDMI_INT | MASK_CSITX0_INT | | ||
2391 | MASK_CSITX1_INT) & 0xFFFF); | ||
2392 | #endif | ||
2393 | i2c_wr16(sd, INTMASK, ~(MASK_HDMI_INT) & 0xFFFF); | ||
2394 | |||
2395 | v4l2_ctrl_handler_setup(sd->ctrl_handler); | ||
2396 | |||
2397 | v4l2_info(sd, "%s found @ 7h%02X (%s)\n", client->name, | ||
2398 | client->addr, client->adapter->name); | ||
2399 | |||
2400 | sd->dev = &client->dev; | ||
2401 | sd->internal_ops = &tc358840_subdev_internal_ops; | ||
2402 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; | ||
2403 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
2404 | state->pad[0].flags = MEDIA_PAD_FL_SOURCE; | ||
2405 | state->pad[1].flags = MEDIA_PAD_FL_SOURCE; | ||
2406 | sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; | ||
2407 | sd->entity.ops = &tc358840_media_ops; | ||
2408 | err = media_entity_init(&sd->entity, 2, state->pad, 0); | ||
2409 | if (err < 0) { | ||
2410 | dev_err(&client->dev, "unable to init media entity\n"); | ||
2411 | return err; | ||
2412 | } | ||
2413 | #endif | ||
2414 | |||
2415 | err = v4l2_async_register_subdev(sd); | ||
2416 | if (err == 0) | ||
2417 | return 0; | ||
2418 | |||
2419 | err_hdl: | ||
2420 | v4l2_ctrl_handler_free(&state->hdl); | ||
2421 | return err; | ||
2422 | } | ||
2423 | |||
2424 | static int tc358840_remove(struct i2c_client *client) | ||
2425 | { | ||
2426 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
2427 | |||
2428 | v4l_dbg(1, debug, client, "%s()\n", __func__); | ||
2429 | |||
2430 | #if defined(CONFIG_MEDIA_CONTROLLER) | ||
2431 | media_entity_cleanup(&sd->entity); | ||
2432 | #endif | ||
2433 | return 0; | ||
2434 | } | ||
2435 | |||
2436 | static const struct i2c_device_id tc358840_id[] = { | ||
2437 | { "tc358840", 0 }, | ||
2438 | { } | ||
2439 | }; | ||
2440 | |||
2441 | MODULE_DEVICE_TABLE(i2c, tc358840_id); | ||
2442 | |||
2443 | #ifdef CONFIG_OF | ||
2444 | static const struct of_device_id tc358840_of_table[] = { | ||
2445 | { .compatible = "toshiba,tc358840" }, | ||
2446 | { } | ||
2447 | }; | ||
2448 | MODULE_DEVICE_TABLE(of, tc358840_of_table); | ||
2449 | #endif | ||
2450 | |||
2451 | static struct i2c_driver tc358840_driver = { | ||
2452 | .driver = { | ||
2453 | .of_match_table = of_match_ptr(tc358840_of_table), | ||
2454 | .name = "tc358840", | ||
2455 | .owner = THIS_MODULE, | ||
2456 | }, | ||
2457 | .probe = tc358840_probe, | ||
2458 | .remove = tc358840_remove, | ||
2459 | .id_table = tc358840_id, | ||
2460 | }; | ||
2461 | module_i2c_driver(tc358840_driver); | ||
2462 | |||
2463 | MODULE_DESCRIPTION("Driver for Toshiba TC358840 HDMI to CSI-2 Bridge"); | ||
2464 | MODULE_AUTHOR("Armin Weiss (weii@zhaw.ch)"); | ||
2465 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/i2c/tc358840_regs.h b/drivers/media/i2c/tc358840_regs.h new file mode 100644 index 000000000..1cc41628b --- /dev/null +++ b/drivers/media/i2c/tc358840_regs.h | |||
@@ -0,0 +1,730 @@ | |||
1 | /* | ||
2 | * tc358840_regs.h - Toshiba UH2C/D HDMI-CSI bridge registers | ||
3 | * | ||
4 | * Copyright (c) 2015, Armin Weiss <weii@zhaw.ch> | ||
5 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms and conditions of the GNU General Public License, | ||
9 | * version 2, as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #ifndef __TC358840_TABLES__ | ||
21 | #define __TC358840_TABLES__ | ||
22 | |||
23 | #include <media/camera_common.h> | ||
24 | |||
25 | /************************************************** | ||
26 | * Register Addresses | ||
27 | *************************************************/ | ||
28 | |||
29 | /* *** General (16 bit) *** */ | ||
30 | #define CHIPID_ADDR 0x0000 | ||
31 | #define MASK_CHIPID 0xFF00 | ||
32 | #define MASK_REVID 0x00FF | ||
33 | #define TC358840_CHIPID 0x4700 | ||
34 | |||
35 | #define SYSCTL 0x0002 | ||
36 | #define MASK_SLEEP (1 << 0) | ||
37 | #define MASK_I2SDIS (1 << 7) | ||
38 | #define MASK_HDMIRST (1 << 8) | ||
39 | #define MASK_CTXRST (1 << 9) | ||
40 | #define MASK_CECRST (1 << 10) | ||
41 | #define MASK_IRRST (1 << 11) | ||
42 | #define MASK_SPLRST (1 << 12) | ||
43 | #define MASK_ABRST (1 << 14) | ||
44 | #define MASK_RESET_ALL 0x5F80 | ||
45 | |||
46 | #define CONFCTL0 0x0004 | ||
47 | #define MASK_VTX0EN (1 << 0) | ||
48 | #define MASK_VTX1EN (1 << 1) | ||
49 | #define MASK_AUTOINDEX (1 << 2) | ||
50 | #define MASK_AUDOUTSEL_CSITX0 (0 << 3) | ||
51 | #define MASK_AUDOUTSEL_CSITX1 (1 << 3) | ||
52 | #define MASK_AUDOUTSEL_I2S (2 << 3) | ||
53 | #define MASK_AUDOUTSEL_TDM (3 << 3) | ||
54 | #define MASK_ABUFEN (1 << 5) | ||
55 | #define MASK_YCBCRFMT (3 << 6) | ||
56 | #define MASK_YCBCRFMT_YCBCR444 (0 << 6) | ||
57 | #define MASK_YCBCRFMT_YCBCR422_12 (1 << 6) | ||
58 | #define MASK_YCBCRFMT_VPID2 (2 << 6) | ||
59 | #define MASK_YCBCRFMT_YCBCR422_8 (3 << 6) | ||
60 | #define MASK_I2SDLYOPT (1 << 8) | ||
61 | #define MASK_AUDCHSEL (1 << 9) | ||
62 | #define MASK_AUDCHNUM_8 (0 << 10) | ||
63 | #define MASK_AUDCHNUM_6 (1 << 10) | ||
64 | #define MASK_AUDCHNUM_4 (2 << 10) | ||
65 | #define MASK_AUDCHNUM_2 (3 << 10) | ||
66 | #define MASK_ACLKOPT (1 << 12) | ||
67 | #define MASK_IECEN (1 << 13) | ||
68 | #define MASK_SLMBEN (1 << 14) | ||
69 | #define MASK_TX_MSEL (1 << 15) | ||
70 | |||
71 | #define CONFCTL1 0x0006 | ||
72 | #define MASK_TX_OUT_FMT 0x0003 | ||
73 | #define MASK_TX_OUT_FMT_RGB888 (0 << 0) | ||
74 | #define MASK_TX_OUT_FMT_RGB666 (2 << 0) | ||
75 | #define MASK_TX_MS_EN (1 << 2) | ||
76 | |||
77 | /* *** Interrupt (16 bit) *** */ | ||
78 | #define INTSTATUS 0x0014 | ||
79 | #define INTMASK 0x0016 | ||
80 | #define MASK_IR_DINT (1 << 0) | ||
81 | #define MASK_IR_EINT (1 << 1) | ||
82 | #define MASK_CEC_RINT (1 << 2) | ||
83 | #define MASK_CEC_TINT (1 << 3) | ||
84 | #define MASK_CEC_EINT (1 << 4) | ||
85 | #define MASK_SYS_INT (1 << 5) | ||
86 | #define MASK_CSITX0_INT (1 << 8) | ||
87 | #define MASK_HDMI_INT (1 << 9) | ||
88 | #define MASK_AMUTE_INT (1 << 10) | ||
89 | #define MASK_CSITX1_INT (1 << 11) | ||
90 | #define MASK_INT_STATUS_MASK_ALL 0x0F3F | ||
91 | |||
92 | /* *** Interrupt and MASKs (8 bit) *** */ | ||
93 | #define HDMI_INT0 0x8500 | ||
94 | #define MASK_KEY 0x01 | ||
95 | #define MASK_MISC 0x0002 | ||
96 | |||
97 | #define HDMI_INT1 0x8501 | ||
98 | #define MASK_SYS 0x01 | ||
99 | #define MASK_CLK 0x02 | ||
100 | #define MASK_PACKET 0x04 | ||
101 | #define MASK_ACBIT 0x08 | ||
102 | #define MASK_AUD 0x10 | ||
103 | #define MASK_ERR 0x20 | ||
104 | #define MASK_HDCP 0x40 | ||
105 | #define MASK_GBD 0x80 | ||
106 | |||
107 | #define SYS_INT 0x8502 | ||
108 | #define SYS_INTM 0x8512 | ||
109 | #define MASK_DDC 0x01 | ||
110 | #define MASK_TMDS 0x02 | ||
111 | #define MASK_DPMBDET 0x04 | ||
112 | #define MASK_NOPMBDET 0x08 | ||
113 | #define MASK_HDMI 0x10 | ||
114 | #define MASK_DVI 0x20 | ||
115 | #define MASK_ACRN 0x40 | ||
116 | #define MASK_ACR_CTS 0x80 | ||
117 | |||
118 | #define CLK_INT 0x8503 | ||
119 | #define CLK_INTM 0x8513 | ||
120 | #define MASK_TMDSCLK_CHG 0x01 | ||
121 | #define MASK_PHYCLK_CHG 0x02 | ||
122 | #define MASK_PXCLK_CHG 0x04 | ||
123 | #define MASK_DC_CHG 0x08 | ||
124 | #define MASK_IN_HV_CHG 0x10 | ||
125 | #define MASK_IN_DE_CHG 0x20 | ||
126 | #define MASK_OUT_H_CHG 0x40 | ||
127 | #define MASK_OUT_DE_CHG 0x80 | ||
128 | |||
129 | #define PACKET_INT 0x8504 | ||
130 | #define PACKET_INTM 0x8514 | ||
131 | #define MASK_PK_AVI 0x01 | ||
132 | #define MASK_PK_AUD 0x02 | ||
133 | #define MASK_PK_MS 0x04 | ||
134 | #define MASK_PK_SPD 0x08 | ||
135 | #define MASK_PK_VS 0x10 | ||
136 | #define MASK_PK_ACP 0x20 | ||
137 | #define MASK_PK_ISRC 0x40 | ||
138 | #define MASK_PK_ISRC2 0x80 | ||
139 | |||
140 | #define CBIT_INT 0x8505 | ||
141 | #define CBIT_INTM 0x8515 | ||
142 | #define MASK_CBIT 0x01 | ||
143 | #define MASK_CBIT_FS 0x02 | ||
144 | #define MASK_CBIT_NLPCM 0x04 | ||
145 | #define MASK_AU_HBR 0x08 | ||
146 | #define MASK_AU_DSD 0x10 | ||
147 | #define MASK_AF_UNLOCK 0x40 | ||
148 | #define MASK_AF_LOCK 0x80 | ||
149 | |||
150 | #define AUDIO_INT 0x8506 | ||
151 | #define AUDIO_INTM 0x8516 | ||
152 | #define MASK_BUFINIT_END 0x01 | ||
153 | #define MASK_BUF_UNDER 0x02 | ||
154 | #define MASK_BUF_NU2 0x04 | ||
155 | #define MASK_BUF_NU1 0x08 | ||
156 | #define MASK_BUF_CENTER 0x10 | ||
157 | #define MASK_BUF_NO1 0x20 | ||
158 | #define MASK_BUF_NO2 0x40 | ||
159 | #define MASK_BUF_OVER 0x80 | ||
160 | |||
161 | #define ERR_INT 0x8507 | ||
162 | #define ERR_INTM 0x8517 | ||
163 | #define MASK_DC_PPERR 0x01 | ||
164 | #define MASK_DC_BUFERR 0x02 | ||
165 | #define MASK_DC_DEERR 0x04 | ||
166 | #define MASK_DC_NOCD 0x08 | ||
167 | #define MASK_NO_AVI 0x10 | ||
168 | #define MASK_NO_ACP 0x20 | ||
169 | #define MASK_AU_FRAME 0x40 | ||
170 | #define MASK_EESS_ERR 0x80 | ||
171 | |||
172 | #define HDCP_INT 0x8508 | ||
173 | #define HDCP_INTM 0x8518 | ||
174 | #define MASK_AN_END 0x01 | ||
175 | #define MASK_AKSV_END 0x02 | ||
176 | #define MASK_KM_END 0x04 | ||
177 | #define MASK_R0_END 0x08 | ||
178 | #define MASK_SHA_END 0x10 | ||
179 | #define MASK_LINKERR 0x20 | ||
180 | #define MASK_AVM_CLR 0x40 | ||
181 | #define MASK_AVM_SET 0x80 | ||
182 | |||
183 | #define GBD_INT 0x8509 | ||
184 | #define GBD_INTM 0x8519 | ||
185 | #define MASK_GBD_ON 0x01 | ||
186 | #define MASK_GBD_OFF 0x02 | ||
187 | #define MASK_P1GBD_DET 0x04 | ||
188 | #define MASK_P0GBD_CHG 0x10 | ||
189 | #define MASK_P1GBD_CHG 0x20 | ||
190 | #define MASK_GBD_ACLR 0x40 | ||
191 | #define MASK_GBD_PKERR 0x80 | ||
192 | |||
193 | #define MISC_INT 0x850B | ||
194 | #define MISC_INTM 0x851B | ||
195 | #define MASK_AUDIO_MUTE 0x01 | ||
196 | #define MASK_SYNC_CHG 0x02 | ||
197 | #define MASK_NO_VS 0x04 | ||
198 | #define MASK_NO_SPD 0x08 | ||
199 | #define MASK_AS_LAYOUT 0x10 | ||
200 | #define MASK_VIDEO_COLOR 0x20 | ||
201 | #define MASK_AU_HBR_OFF 0x40 | ||
202 | #define MASK_AU_DSD_OFF 0x80 | ||
203 | |||
204 | /* *** STATUS *** */ | ||
205 | #define SYS_STATUS 0x8520 | ||
206 | #define MASK_S_SYNC 0x80 | ||
207 | #define MASK_S_AVMUTE 0x40 | ||
208 | #define MASK_S_HDCP 0x20 | ||
209 | #define MASK_S_HDMI 0x10 | ||
210 | #define MASK_S_PHY_SCDT 0x08 | ||
211 | #define MASK_S_PHY_PLL 0x04 | ||
212 | #define MASK_S_TMDS 0x02 | ||
213 | #define MASK_S_DDC5V 0x01 | ||
214 | |||
215 | #define VI_STATUS1 0x8522 | ||
216 | #define MASK_S_V_GBD 0x08 | ||
217 | #define MASK_S_DEEPCOLOR 0x0c | ||
218 | #define MASK_S_V_422 0x02 | ||
219 | #define MASK_S_V_INTERLACE 0x01 | ||
220 | |||
221 | #define VI_STATUS3 0x8528 | ||
222 | #define MASK_S_V_COLOR 0x1F | ||
223 | #define MASK_RGB_FULL 0x00 | ||
224 | #define MASK_RGB_LIMITED 0x01 | ||
225 | #define MASK_YCBCR601_FULL 0x02 | ||
226 | #define MASK_YCBCR601_LIMITED 0x03 | ||
227 | #define MASK_ADOBE_RGB_FULL 0x04 | ||
228 | #define MASK_ADOBE_RGB_LIMITED 0x05 | ||
229 | #define MASK_YCBCR709_FULL 0x06 | ||
230 | #define MASK_YCBCR709_LIMITED 0x07 | ||
231 | #define MASK_XVYCC601_FULL 0x0A | ||
232 | #define MASK_XVYCC601_LIMITED 0x0B | ||
233 | #define MASK_XVYCC709_FULL 0x0E | ||
234 | #define MASK_XVYCC709_LIMITED 0x0F | ||
235 | #define MASK_SYCC601_FULL 0x12 | ||
236 | #define MASK_SYCC601_LIMITED 0x13 | ||
237 | #define MASK_ADOBE_YCC601_FULL 0x1A | ||
238 | #define MASK_ADOBE_YCC601_LIMITED 0x1B | ||
239 | #define MASK_LIMITED 0x01 | ||
240 | |||
241 | |||
242 | /* *** CSI TX (32 bit) *** */ | ||
243 | #define CSITX0_BASE_ADDR 0x0000 | ||
244 | #define CSITX1_BASE_ADDR 0x0200 | ||
245 | |||
246 | #define CSITX_CLKEN 0x0108 | ||
247 | #define MASK_CSITX_EN (1 << 0) | ||
248 | |||
249 | #define PPICLKEN 0x010C | ||
250 | #define MASK_HSTXCLKEN 0x00000001 | ||
251 | |||
252 | #define MODECONF 0x0110 /* Not in Ref. v1.5 */ | ||
253 | #define MASK_CSI2MODE (1 << 0) | ||
254 | #define MASK_VSYNC_POL_SW (1 << 1) | ||
255 | #define MASK_HSYNC_POL_SW (1 << 2) | ||
256 | #define MASK_DTVALID_POL_SW (1 << 3) | ||
257 | #define MASK_INDMODE (1 << 4) | ||
258 | |||
259 | #define LANEEN 0x0118 | ||
260 | #define MASK_LANES 0x00000007 | ||
261 | #define MASK_LANE_0_EN (1 << 0) | ||
262 | #define MASK_LANE_0_1_EN (2 << 0) | ||
263 | #define MASK_LANE_0_1_2_EN (3 << 0) | ||
264 | #define MASK_LANE_0_1_2_3_EN (4 << 0) | ||
265 | #define MASK_LANES 0x00000007 | ||
266 | #define MASK_CLANEEN (1 << 4) | ||
267 | |||
268 | #define CSITX_START 0x011C | ||
269 | #define LINEINITCNT 0x0120 | ||
270 | #define HSTOCNT 0x0124 | ||
271 | |||
272 | #define INTEN 0x0128 /* Not in Ref. v1.5 */ | ||
273 | #define MASK_VH_DLY_EN (1 << 0) | ||
274 | #define MASK_VFHSYNCMASK_EN (1 << 7) | ||
275 | #define MASK_IND_MODE_SEL_PORT (0 << 8) | ||
276 | #define MASK_IND_MODE_SEL_REG (1 << 8) | ||
277 | #define MASK_IND_TO_EN (1 << 9) | ||
278 | #define MASK_HSTX_TO_EN (1 << 10) | ||
279 | #define MASK_LRX_H_TO_EN (1 << 11) | ||
280 | #define MASK_TA_TO_EN (1 << 12) | ||
281 | #define MASK_PR_TO_EN (1 << 13) | ||
282 | #define MASK_PRESP_TO_EN (1 << 14) | ||
283 | #define MASK_DSI_RX_STATE_INT_EN (1 << 16) | ||
284 | #define MASK_DSI_RX_TRIG_INT_EN (1 << 17) | ||
285 | #define MASK_DSI_LP_TX_INT_EN (1 << 18) | ||
286 | #define MASK_DSI_RX_ERR_INT_EN (1 << 19) | ||
287 | #define MASK_DSI_RP_TO_INT_EN (1 << 20) | ||
288 | #define MASK_APP_SIDE_ERR_INT_EN (1 << 21) | ||
289 | #define MASK_INIT_INT_EN (1 << 22) | ||
290 | #define MASK_DEBUG_MODE_EN (1 << 31) | ||
291 | |||
292 | #define FUNCMODE 0x0150 | ||
293 | #define MASK_CONTCLKMODE (1 << 5) | ||
294 | #define MASK_FORCESTOP (1 << 10) | ||
295 | |||
296 | #define CSITX_INTERNAL_STAT 0x01B0 | ||
297 | |||
298 | #define LPTXTIMECNT 0x0254 | ||
299 | #define TCLK_HEADERCNT 0x0258 | ||
300 | #define TCLK_TRAILCNT 0x025C | ||
301 | #define THS_HEADERCNT 0x0260 | ||
302 | #define TWAKEUP 0x0264 | ||
303 | #define TCLK_POSTCNT 0x0268 | ||
304 | #define THS_TRAILCNT 0x026C | ||
305 | #define HSTXVREGCNT 0x0270 | ||
306 | |||
307 | #define HSTXVREGEN 0x0274 | ||
308 | #define MASK_D3M_HSTXVREGEN 0x0010 | ||
309 | #define MASK_D2M_HSTXVREGEN 0x0008 | ||
310 | #define MASK_D1M_HSTXVREGEN 0x0004 | ||
311 | #define MASK_D0M_HSTXVREGEN 0x0002 | ||
312 | #define MASK_CLM_HSTXVREGEN 0x0001 | ||
313 | |||
314 | #define MIPICLKEN 0x02A0 | ||
315 | #define MASK_MP_ENABLE 0x00000001 | ||
316 | #define MASK_MP_CKEN 0x00000002 | ||
317 | |||
318 | #define PLLCONF 0x02AC | ||
319 | #define MASK_LFBREN (1 << 9) | ||
320 | #define MASK_MPLBW 0x00030000 | ||
321 | #define MASK_MPLBW_25 (0 << 16) | ||
322 | #define MASK_MPLBW_33 (1 << 16) | ||
323 | #define MASK_MPLBW_50 (2 << 16) | ||
324 | #define MASK_MPLBW_MAX (3 << 16) | ||
325 | #define MASK_PLL_FBD 0x000000FF | ||
326 | #define SET_PLL_FBD(fbd) ((fbd) & MASK_PLL_FBD) | ||
327 | #define MASK_PLL_FRS 0x00000C00 | ||
328 | #define SET_PLL_FRS(frs) (((frs) << 10) & MASK_PLL_FRS) | ||
329 | #define MASK_PLL_PRD 0x0000F000 | ||
330 | #define SET_PLL_PRD(prd) (((prd) << 12) & \ | ||
331 | MASK_PLL_PRD) | ||
332 | #define MASK_PLL_LBW 0x00030000 | ||
333 | #define SET_PLL_LBW(lbw) ((((lbw) - 1) << 16) & \ | ||
334 | MASK_PLL_LBW) | ||
335 | |||
336 | #define CECEN 0x0600 | ||
337 | #define MASK_CECEN 0x0001 | ||
338 | |||
339 | /* *** Split Control (16 bit) *** */ | ||
340 | #define SPLITTX0_CTRL 0x5000 | ||
341 | #define SPLITTX1_CTRL 0x5080 | ||
342 | #define MASK_LCD_CSEL 0x0001 | ||
343 | #define MASK_IFEN 0x0002 | ||
344 | #define MASK_SPBP 0x0100 | ||
345 | |||
346 | #define SPLITTX0_WC 0x5008 /*Removed in rev. 1.1*/ | ||
347 | #define SPLITTX1_WC 0x5088 /*Removed in rev. 1.1*/ | ||
348 | |||
349 | #define SPLITTX0_SPLIT 0x500C | ||
350 | #define SPLITTX1_SPLIT 0x508C | ||
351 | #define MASK_FPXV 0x0FFF | ||
352 | /* NOTE: Only available for TX0 */ | ||
353 | #define MASK_TX1SEL 0x4000 | ||
354 | /* NOTE: Only available for TX0 */ | ||
355 | #define MASK_EHW 0x8000 | ||
356 | |||
357 | /* *** HDMI PHY (8 bit) *** */ | ||
358 | #define PHY_CTL 0x8410 | ||
359 | /* TODO: Check name of mask */ | ||
360 | #define MASK_POWERCTL (1 << 0) | ||
361 | /* TODO: Check name of mask */ | ||
362 | #define MASK_48_MHZ (1 << 1) | ||
363 | |||
364 | #define PHY_CTL2 0x8412 | ||
365 | #define MASK_PHY_FREE_RUN (1 << 5) | ||
366 | |||
367 | #define PHY_ENB 0x8413 | ||
368 | #define MASK_ENABLE_PHY 0x01 | ||
369 | |||
370 | #define PHY_RST 0x8414 | ||
371 | #define MASK_RESET_CTRL 0x01 /* Reset active low */ | ||
372 | |||
373 | #define APPL_CTL 0x84F0 | ||
374 | #define MASK_APLL_ON 0x01 | ||
375 | #define MASK_APLL_CPCTL 0x30 | ||
376 | #define MASK_APLL_CPCTL_HIZ 0x00 | ||
377 | #define MASK_APLL_CPCTL_LFIX 0x10 | ||
378 | #define MASK_APLL_CPCTL_HFIX 0x20 | ||
379 | #define MASK_APLL_CPCTL_NORMAL 0x30 | ||
380 | |||
381 | #define DDCIO_CTL 0x84F4 | ||
382 | #define MASK_DDC_PWR_ON (1 << 0) | ||
383 | |||
384 | /** *** HDMI Clock (8 bit) *** */ | ||
385 | #define AU_STATUS0 0x8523 | ||
386 | #define MASK_S_A_SAMPLE 0x01 | ||
387 | |||
388 | #define SYS_FREQ0 0x8540 | ||
389 | #define SYS_FREQ1 0x8541 | ||
390 | #define LOCK_REF_FREQA 0x8630 | ||
391 | #define LOCK_REF_FREQB 0x8631 | ||
392 | #define LOCK_REF_FREQC 0x8632 | ||
393 | |||
394 | #define FS_SET 0x8621 | ||
395 | #define MASK_FS 0x0F | ||
396 | |||
397 | #define NCO_F0_MOD 0x8670 | ||
398 | #define MASK_NCO_F0_MOD_42MHZ 0x00 | ||
399 | #define MASK_NCO_F0_MOD_REG 0x02 | ||
400 | |||
401 | #define NCO_48F0A 0x8671 | ||
402 | #define NCO_48F0B 0x8672 | ||
403 | #define NCO_48F0C 0x8673 | ||
404 | #define NCO_48F0D 0x8674 | ||
405 | |||
406 | #define NCO_44F0A 0x8675 | ||
407 | #define NCO_44F0B 0x8676 | ||
408 | #define NCO_44F0C 0x8677 | ||
409 | #define NCO_44F0D 0x8678 | ||
410 | |||
411 | #define SCLK_CSC0 0x8A0C | ||
412 | #define SCLK_CSC1 0x8A0D | ||
413 | |||
414 | #define HDCP_MODE 0x8560 | ||
415 | #define MASK_MODE_RST_TN 0x20 | ||
416 | #define MASK_LINE_REKEY 0x10 | ||
417 | #define MASK_AUTO_CLR 0x04 | ||
418 | |||
419 | #define HDCP_REG1 0x8563 /* Not in REF_01 */ | ||
420 | #define MASK_AUTH_UNAUTH_SEL 0x70 | ||
421 | #define MASK_AUTH_UNAUTH_SEL_12_FRAMES 0x70 | ||
422 | #define MASK_AUTH_UNAUTH_SEL_8_FRAMES 0x60 | ||
423 | #define MASK_AUTH_UNAUTH_SEL_4_FRAMES 0x50 | ||
424 | #define MASK_AUTH_UNAUTH_SEL_2_FRAMES 0x40 | ||
425 | #define MASK_AUTH_UNAUTH_SEL_64_FRAMES 0x30 | ||
426 | #define MASK_AUTH_UNAUTH_SEL_32_FRAMES 0x20 | ||
427 | #define MASK_AUTH_UNAUTH_SEL_16_FRAMES 0x10 | ||
428 | #define MASK_AUTH_UNAUTH_SEL_ONCE 0x00 | ||
429 | #define MASK_AUTH_UNAUTH 0x01 | ||
430 | #define MASK_AUTH_UNAUTH_AUTO 0x01 | ||
431 | |||
432 | #define HDCP_REG2 0x8564 /* Not in REF_01 */ | ||
433 | #define MASK_AUTO_P3_RESET 0x0F | ||
434 | #define SET_AUTO_P3_RESET_FRAMES(n) (n & MASK_AUTO_P3_RESET) | ||
435 | #define MASK_AUTO_P3_RESET_OFF 0x00 | ||
436 | |||
437 | |||
438 | /* *** VI *** */ | ||
439 | #define VI_MODE 0x8570 | ||
440 | /* TODO: Probably wrong bit (see p. 292 rev. 0.93) */ | ||
441 | #define MASK_RGB_DVI 0x08 | ||
442 | |||
443 | #define DE_HSIZE_LO 0x8582 | ||
444 | #define DE_HSIZE_HI 0x8583 | ||
445 | #define DE_VSIZE_LO 0x858C | ||
446 | #define DE_VSIZE_HI 0x858D | ||
447 | |||
448 | #define IN_HSIZE_LO 0x858E | ||
449 | #define IN_HSIZE_HI 0x858F | ||
450 | |||
451 | #define IN_VSIZE_LO 0x8590 | ||
452 | #define IN_VSIZE_HI 0x8591 | ||
453 | |||
454 | #define FV_CNT_LO 0x85C1 /* Not in Ref. v1.5 */ | ||
455 | #define FV_CNT_HI 0x85C2 /* Not in Ref. v1.5 */ | ||
456 | |||
457 | #define HDCP_REG3 0x85D1 /* Not in REF_01 */ | ||
458 | #define KEY_RD_CMD 0x01 | ||
459 | |||
460 | /* *** EDID (8 bit) *** */ | ||
461 | #define EDID_MODE 0x85E0 | ||
462 | #define MASK_DIRECT 0x00 | ||
463 | #define MASK_RAM_DDC2B (1 << 0) | ||
464 | #define MASK_RAM_EDDC (1 << 1) | ||
465 | #define MASK_EDID_MODE_ALL 0x03 | ||
466 | |||
467 | #define EDID_LEN1 0x85E3 | ||
468 | #define EDID_LEN2 0x85E4 | ||
469 | |||
470 | #define EDID_RAM 0x8C00 | ||
471 | |||
472 | /* *** HDCP *** */ | ||
473 | #define BKSV 0x8800 | ||
474 | |||
475 | #define BCAPS 0x8840 | ||
476 | #define MASK_HDMI_RSVD 0x80 | ||
477 | #define MASK_REPEATER 0x40 | ||
478 | #define MASK_READY 0x20 | ||
479 | #define MASK_FASTI2C 0x10 | ||
480 | #define MASK_1_1_FEA 0x02 | ||
481 | #define MASK_FAST_REAU 0x01 | ||
482 | |||
483 | #define BSTATUS0 0x8841 | ||
484 | #define BSTATUS1 0x8842 | ||
485 | #define MASK_HDMI_MODE 0x10 | ||
486 | #define MASK_MAX_EXCED 0x08 | ||
487 | |||
488 | /* *** Video Output Format (8 bit) *** */ | ||
489 | #define VOUT_FMT 0x8A00 | ||
490 | #define MASK_OUTFMT_444_RGB (0 << 0) | ||
491 | #define MASK_OUTFMT_422 (1 << 0) | ||
492 | #define MASK_OUTFMT_THROUGH (2 << 0) | ||
493 | #define MASK_422FMT_NORMAL (0 << 4) | ||
494 | #define MASK_422FMT_HDMITHROUGH (1 << 4) | ||
495 | |||
496 | #define VOUT_FIL 0x8A01 | ||
497 | #define MASK_422FIL 0x07 | ||
498 | #define MASK_422FIL_2_TAP (0 << 0) | ||
499 | #define MASK_422FIL_3_TAP (1 << 0) | ||
500 | #define MASK_422FIL_NO_FILTER (2 << 0) | ||
501 | #define MASK_422FIL_2_TAP_444 (3 << 0) | ||
502 | #define MASK_422FIL_3_TAP_444 (4 << 0) | ||
503 | #define MASK_422FIL_2_TAP_444_CSC (5 << 0) | ||
504 | #define MASK_422FIL_3_TAP_444_CSC (6 << 0) | ||
505 | #define MASK_444FIL 0x10 | ||
506 | #define MASK_444FIL_REPEAT (0 << 4) | ||
507 | #define MASK_444FIL_2_TAP (1 << 4) | ||
508 | |||
509 | #define VOUT_SYNC0 0x8A02 | ||
510 | #define MASK_MODE_2 (2 << 0) | ||
511 | #define MASK_MODE_3 (3 << 0) | ||
512 | #define MASK_M3_HSIZE 0x30 | ||
513 | #define MASK_M3_VSIZE 0xC0 | ||
514 | |||
515 | #define VOUT_CSC 0x8A08 | ||
516 | #define MASK_CSC_MODE 0x03 | ||
517 | #define MASK_CSC_MODE_OFF (0 << 0) | ||
518 | #define MASK_CSC_MODE_BUILTIN (1 << 0) | ||
519 | #define MASK_CSC_MODE_AUTO (2 << 0) | ||
520 | #define MASK_CSC_MODE_HOST (3 << 0) | ||
521 | #define MASK_COLOR 0x70 | ||
522 | #define MASK_COLOR_RGB_FULL (0 << 4) | ||
523 | #define MASK_COLOR_RGB_LIMITED (1 << 4) | ||
524 | #define MASK_COLOR_601_YCBCR_FULL (2 << 4) | ||
525 | #define MASK_COLOR_601_YCBCR_LIMITED (3 << 4) | ||
526 | #define MASK_COLOR_709_YCBCR_FULL (4 << 4) | ||
527 | #define MASK_COLOR_709_YCBCR_LIMITED (5 << 4) | ||
528 | #define MASK_COLOR_FULL_TO_LIMITED (6 << 4) | ||
529 | #define MASK_COLOR_LIMITED_TO_FULL (7 << 4) | ||
530 | |||
531 | |||
532 | /* *** HDMI Audio RefClk (8 bit) *** */ | ||
533 | #define FORCE_MUTE 0x8600 | ||
534 | #define MASK_FORCE_DMUTE (1 << 0) | ||
535 | #define MASK_FORCE_AMUTE (1 << 4) | ||
536 | |||
537 | #define AUTO_CMD0 0x8602 | ||
538 | #define MASK_AUTO_MUTE7 0x80 | ||
539 | #define MASK_AUTO_MUTE6 0x40 | ||
540 | #define MASK_AUTO_MUTE5 0x20 | ||
541 | #define MASK_AUTO_MUTE4 0x10 | ||
542 | #define MASK_AUTO_MUTE3 0x08 | ||
543 | #define MASK_AUTO_MUTE2 0x04 | ||
544 | #define MASK_AUTO_MUTE1 0x02 | ||
545 | #define MASK_AUTO_MUTE0 0x01 | ||
546 | |||
547 | #define AUTO_CMD1 0x8603 | ||
548 | #define MASK_AUTO_MUTE10 0x04 | ||
549 | #define MASK_AUTO_MUTE9 0x02 | ||
550 | #define MASK_AUTO_MUTE8 0x01 | ||
551 | |||
552 | #define AUTO_CMD2 0x8604 | ||
553 | #define MASK_AUTO_PLAY3 0x08 | ||
554 | #define MASK_AUTO_PLAY2 0x04 | ||
555 | |||
556 | #define BUFINIT_START 0x8606 | ||
557 | #define SET_BUFINIT_START_MS(milliseconds) ((milliseconds) / 100) | ||
558 | |||
559 | #define FS_MUTE 0x8607 | ||
560 | #define MASK_FS_ELSE_MUTE 0x80 | ||
561 | #define MASK_FS22_MUTE 0x40 | ||
562 | #define MASK_FS24_MUTE 0x20 | ||
563 | #define MASK_FS88_MUTE 0x10 | ||
564 | #define MASK_FS96_MUTE 0x08 | ||
565 | #define MASK_FS176_MUTE 0x04 | ||
566 | #define MASK_FS192_MUTE 0x02 | ||
567 | #define MASK_FS_NO_MUTE 0x01 | ||
568 | |||
569 | #define FS_IMODE 0x8620 | ||
570 | #define MASK_NLPCM_HMODE 0x40 | ||
571 | #define MASK_NLPCM_SMODE 0x20 | ||
572 | #define MASK_NLPCM_IMODE 0x10 | ||
573 | #define MASK_FS_HMODE 0x08 | ||
574 | #define MASK_FS_AMODE 0x04 | ||
575 | #define MASK_FS_SMODE 0x02 | ||
576 | #define MASK_FS_IMODE 0x01 | ||
577 | |||
578 | #define ACR_MODE 0x8640 | ||
579 | #define MASK_ACR_LOAD 0x10 | ||
580 | #define MASK_N_MODE 0x04 | ||
581 | #define MASK_CTS_MODE 0x01 | ||
582 | |||
583 | #define ACR_MDF0 0x8641 | ||
584 | #define MASK_ACR_L2MDF 0x70 | ||
585 | #define MASK_ACR_L2MDF_0_PPM 0x00 | ||
586 | #define MASK_ACR_L2MDF_61_PPM 0x10 | ||
587 | #define MASK_ACR_L2MDF_122_PPM 0x20 | ||
588 | #define MASK_ACR_L2MDF_244_PPM 0x30 | ||
589 | #define MASK_ACR_L2MDF_488_PPM 0x40 | ||
590 | #define MASK_ACR_L2MDF_976_PPM 0x50 | ||
591 | #define MASK_ACR_L2MDF_1976_PPM 0x60 | ||
592 | #define MASK_ACR_L2MDF_3906_PPM 0x70 | ||
593 | #define MASK_ACR_L1MDF 0x07 | ||
594 | #define MASK_ACR_L1MDF_0_PPM 0x00 | ||
595 | #define MASK_ACR_L1MDF_61_PPM 0x01 | ||
596 | #define MASK_ACR_L1MDF_122_PPM 0x02 | ||
597 | #define MASK_ACR_L1MDF_244_PPM 0x03 | ||
598 | #define MASK_ACR_L1MDF_488_PPM 0x04 | ||
599 | #define MASK_ACR_L1MDF_976_PPM 0x05 | ||
600 | #define MASK_ACR_L1MDF_1976_PPM 0x06 | ||
601 | #define MASK_ACR_L1MDF_3906_PPM 0x07 | ||
602 | |||
603 | #define ACR_MDF1 0x8642 | ||
604 | #define MASK_ACR_L3MDF 0x07 | ||
605 | #define MASK_ACR_L3MDF_0_PPM 0x00 | ||
606 | #define MASK_ACR_L3MDF_61_PPM 0x01 | ||
607 | #define MASK_ACR_L3MDF_122_PPM 0x02 | ||
608 | #define MASK_ACR_L3MDF_244_PPM 0x03 | ||
609 | #define MASK_ACR_L3MDF_488_PPM 0x04 | ||
610 | #define MASK_ACR_L3MDF_976_PPM 0x05 | ||
611 | #define MASK_ACR_L3MDF_1976_PPM 0x06 | ||
612 | #define MASK_ACR_L3MDF_3906_PPM 0x07 | ||
613 | |||
614 | #define SDO_MODE1 0x8652 | ||
615 | #define MASK_SDO_BIT_LENG 0x70 | ||
616 | #define MASK_SDO_FMT 0x03 | ||
617 | #define MASK_SDO_FMT_RIGHT 0x00 | ||
618 | #define MASK_SDO_FMT_LEFT 0x01 | ||
619 | #define MASK_SDO_FMT_I2S 0x02 | ||
620 | |||
621 | #define DIV_MODE 0x8665 /* Not in REF_01 */ | ||
622 | #define MASK_DIV_DLY 0xf0 | ||
623 | #define SET_DIV_DLY_MS(milliseconds) ((((milliseconds)/100) << 4) & \ | ||
624 | MASK_DIV_DLY) | ||
625 | #define MASK_DIV_MODE 0x01 | ||
626 | |||
627 | #define HDMIAUDIO_MODE 0x8680 | ||
628 | |||
629 | /* *** HDMI General (16 bit) *** */ | ||
630 | #define DDC_CTL 0x8543 | ||
631 | #define MASK_DDC_ACTION 0x04 | ||
632 | #define MASK_DDC5V_MODE 0x03 | ||
633 | #define MASK_DDC5V_MODE_0MS 0x00 | ||
634 | #define MASK_DDC5V_MODE_50MS 0x01 | ||
635 | #define MASK_DDC5V_MODE_100MS 0x02 | ||
636 | #define MASK_DDC5V_MODE_200MS 0x03 | ||
637 | |||
638 | #define HPD_CTL 0x8544 | ||
639 | #define MASK_HPD_OUT0 (1 << 0) | ||
640 | #define MASK_HPD_CTL0 (1 << 4) | ||
641 | |||
642 | #define INIT_END 0x854A | ||
643 | #define MASK_INIT_END 0x01 | ||
644 | |||
645 | /* *** Video Mute *** */ | ||
646 | #define VI_MUTE 0x857F | ||
647 | #define MASK_AUTO_MUTE 0xC0 | ||
648 | #define MASK_VI_MUTE 0x10 | ||
649 | #define MASK_VI_BLACK 0x01 | ||
650 | |||
651 | /* *** Info Frame *** */ | ||
652 | #define PK_INT_MODE 0x8709 | ||
653 | #define MASK_ISRC2_INT_MODE 0x80 | ||
654 | #define MASK_ISRC_INT_MODE 0x40 | ||
655 | #define MASK_ACP_INT_MODE 0x20 | ||
656 | #define MASK_VS_INT_MODE 0x10 | ||
657 | #define MASK_SPD_INT_MODE 0x08 | ||
658 | #define MASK_MS_INT_MODE 0x04 | ||
659 | #define MASK_AUD_INT_MODE 0x02 | ||
660 | #define MASK_AVI_INT_MODE 0x01 | ||
661 | |||
662 | #define NO_PKT_LIMIT 0x870B | ||
663 | #define MASK_NO_ACP_LIMIT 0xF0 | ||
664 | #define SET_NO_ACP_LIMIT_MS(milliseconds) ((((milliseconds)/80) << 4) & \ | ||
665 | MASK_NO_ACP_LIMIT) | ||
666 | |||
667 | #define NO_PKT_CLR 0x870C | ||
668 | #define MASK_NO_VS_CLR 0x40 | ||
669 | #define MASK_NO_SPD_CLR 0x20 | ||
670 | #define MASK_NO_ACP_CLR 0x10 | ||
671 | #define MASK_NO_AVI_CLR1 0x02 | ||
672 | #define MASK_NO_AVI_CLR0 0x01 | ||
673 | |||
674 | #define ERR_PK_LIMIT 0x870D | ||
675 | #define NO_PKT_LIMIT2 0x870E | ||
676 | #define PK_AVI_0HEAD 0x8710 | ||
677 | #define PK_AVI_1HEAD 0x8711 | ||
678 | #define PK_AVI_2HEAD 0x8712 | ||
679 | #define PK_AVI_0BYTE 0x8713 | ||
680 | #define PK_AVI_1BYTE 0x8714 | ||
681 | #define PK_AVI_2BYTE 0x8715 | ||
682 | #define PK_AVI_3BYTE 0x8716 | ||
683 | #define PK_AVI_4BYTE 0x8717 | ||
684 | #define PK_AVI_5BYTE 0x8718 | ||
685 | #define PK_AVI_6BYTE 0x8719 | ||
686 | #define PK_AVI_7BYTE 0x871A | ||
687 | #define PK_AVI_8BYTE 0x871B | ||
688 | #define PK_AVI_9BYTE 0x871C | ||
689 | #define PK_AVI_10BYTE 0x871D | ||
690 | #define PK_AVI_11BYTE 0x871E | ||
691 | #define PK_AVI_12BYTE 0x871F | ||
692 | #define PK_AVI_13BYTE 0x8720 | ||
693 | #define PK_AVI_14BYTE 0x8721 | ||
694 | #define PK_AVI_15BYTE 0x8722 | ||
695 | #define PK_AVI_16BYTE 0x8723 | ||
696 | |||
697 | #define NO_GDB_LIMIT 0x9007 | ||
698 | |||
699 | /* *** Color Bar (16 bit) *** */ | ||
700 | #define CB_CTL 0x7000 | ||
701 | #define CB_HSW 0x7008 | ||
702 | #define CB_VSW 0x700A | ||
703 | #define CB_HTOTOAL 0x700C | ||
704 | #define CB_VTOTOAL 0x700E | ||
705 | #define CB_HACT 0x7010 | ||
706 | #define CB_VACT 0x7012 | ||
707 | #define CB_HSTART 0x7014 | ||
708 | #define CB_VSTART 0x7016 | ||
709 | |||
710 | enum { | ||
711 | TC358840_MODE_3840X2160, | ||
712 | TC358840_MODE_1920X1080, | ||
713 | TC358840_MODE_1280X720, | ||
714 | }; | ||
715 | |||
716 | static const int tc358840_30fps[] = { | ||
717 | 30, | ||
718 | }; | ||
719 | |||
720 | static const int tc358840_30_60fps[] = { | ||
721 | 30, | ||
722 | 60, | ||
723 | }; | ||
724 | |||
725 | static const struct camera_common_frmfmt tc358840_frmfmt[] = { | ||
726 | {{3840, 2160}, tc358840_30fps, 1, 1, TC358840_MODE_3840X2160}, | ||
727 | {{1920, 1080}, tc358840_30_60fps, 2, 1, TC358840_MODE_1920X1080}, | ||
728 | {{1280, 720}, tc358840_30_60fps, 2, 1, TC358840_MODE_1280X720}, | ||
729 | }; | ||
730 | #endif /* __TC358840_TABLES__ */ | ||
diff --git a/drivers/media/platform/tegra/Makefile b/drivers/media/platform/tegra/Makefile new file mode 100644 index 000000000..414f22f69 --- /dev/null +++ b/drivers/media/platform/tegra/Makefile | |||
@@ -0,0 +1,12 @@ | |||
1 | GCOV_PROFILE := y | ||
2 | |||
3 | #subdir-ccflags-y := -Werror | ||
4 | # | ||
5 | # Makefile for the video capture/playback device drivers. | ||
6 | # | ||
7 | obj-y += camera/ | ||
8 | obj-y += vi/ | ||
9 | obj-$(CONFIG_VIDEO_CAMERA) += regmap_util.o | ||
10 | obj-$(CONFIG_VIDEO_TEGRA_VI_TPG) += tpg/ | ||
11 | |||
12 | obj-$(CONFIG_TEGRA_MIPI_CAL) += mipical/ | ||
diff --git a/drivers/media/platform/tegra/camera/Makefile b/drivers/media/platform/tegra/camera/Makefile new file mode 100644 index 000000000..8474f451a --- /dev/null +++ b/drivers/media/platform/tegra/camera/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | GCOV_PROFILE := y | ||
2 | obj-y += vi/ | ||
3 | obj-y += csi/ | ||
4 | ccflags-y += -I../nvhost/drivers/video/tegra/host | ||
5 | ccflags-y += -Idrivers/video/tegra/host | ||
6 | ccflags-y += -Idrivers/video/tegra/camera | ||
7 | ccflags-y += -Idrivers/media/platform/tegra | ||
8 | ccflags-y += -Werror | ||
9 | |||
10 | obj-y += camera_common.o camera_gpio.o sensor_common.o | ||
diff --git a/drivers/media/platform/tegra/camera/camera_common.c b/drivers/media/platform/tegra/camera/camera_common.c new file mode 100644 index 000000000..17a253640 --- /dev/null +++ b/drivers/media/platform/tegra/camera/camera_common.c | |||
@@ -0,0 +1,858 @@ | |||
1 | /* | ||
2 | * camera_common.c - utilities for tegra camera driver | ||
3 | * | ||
4 | * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <media/camera_common.h> | ||
19 | #include <linux/of_graph.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <soc/tegra/pmc.h> | ||
22 | #include "camera/vi/mc_common.h" | ||
23 | |||
24 | #define has_s_op(master, op) \ | ||
25 | (master->ops && master->ops->op) | ||
26 | #define call_s_op(master, op) \ | ||
27 | (has_s_op(master, op) ? \ | ||
28 | master->ops->op(master) : 0) | ||
29 | #define call_s_ops(master, op, ...) \ | ||
30 | (has_s_op(master, op) ? \ | ||
31 | master->ops->op(master, __VA_ARGS__) : 0) | ||
32 | |||
33 | static const struct camera_common_colorfmt camera_common_color_fmts[] = { | ||
34 | { | ||
35 | MEDIA_BUS_FMT_SRGGB12_1X12, | ||
36 | V4L2_COLORSPACE_SRGB, | ||
37 | V4L2_PIX_FMT_SRGGB12, | ||
38 | }, | ||
39 | { | ||
40 | MEDIA_BUS_FMT_SRGGB10_1X10, | ||
41 | V4L2_COLORSPACE_SRGB, | ||
42 | V4L2_PIX_FMT_SRGGB10, | ||
43 | }, | ||
44 | { | ||
45 | MEDIA_BUS_FMT_SBGGR10_1X10, | ||
46 | V4L2_COLORSPACE_SRGB, | ||
47 | V4L2_PIX_FMT_SBGGR10, | ||
48 | }, | ||
49 | { | ||
50 | MEDIA_BUS_FMT_SRGGB8_1X8, | ||
51 | V4L2_COLORSPACE_SRGB, | ||
52 | V4L2_PIX_FMT_SRGGB8, | ||
53 | }, | ||
54 | /* | ||
55 | * The below two formats are not supported by VI4, | ||
56 | * keep them at the last to ensure they get discarded | ||
57 | */ | ||
58 | { | ||
59 | MEDIA_BUS_FMT_XRGGB10P_3X10, | ||
60 | V4L2_COLORSPACE_SRGB, | ||
61 | V4L2_PIX_FMT_XRGGB10P, | ||
62 | }, | ||
63 | { | ||
64 | MEDIA_BUS_FMT_XBGGR10P_3X10, | ||
65 | V4L2_COLORSPACE_SRGB, | ||
66 | V4L2_PIX_FMT_XRGGB10P, | ||
67 | }, | ||
68 | }; | ||
69 | |||
70 | static const char *camera_common_csi_io_pads[] = { | ||
71 | "csia", | ||
72 | "csib", | ||
73 | "csic", | ||
74 | "csid", | ||
75 | "csie", | ||
76 | "csif", | ||
77 | }; | ||
78 | |||
79 | bool camera_common_verify_code(struct tegra_channel *chan, unsigned int code) | ||
80 | { | ||
81 | int i; | ||
82 | |||
83 | for (i = 0; i < chan->num_video_formats; i++) { | ||
84 | if (chan->video_formats[i]->code == code) | ||
85 | return true; | ||
86 | } | ||
87 | |||
88 | return false; | ||
89 | } | ||
90 | |||
91 | int camera_common_g_ctrl(struct camera_common_data *s_data, | ||
92 | struct v4l2_control *control) | ||
93 | { | ||
94 | int i; | ||
95 | |||
96 | for (i = 0; i < s_data->numctrls; i++) { | ||
97 | if (s_data->ctrls[i]->id == control->id) { | ||
98 | control->value = s_data->ctrls[i]->val; | ||
99 | dev_dbg(&s_data->i2c_client->dev, | ||
100 | "%s: found control %s\n", __func__, | ||
101 | s_data->ctrls[i]->name); | ||
102 | return 0; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | return -EFAULT; | ||
107 | } | ||
108 | |||
109 | int camera_common_regulator_get(struct i2c_client *client, | ||
110 | struct regulator **vreg, const char *vreg_name) | ||
111 | { | ||
112 | struct regulator *reg = NULL; | ||
113 | int err = 0; | ||
114 | |||
115 | reg = devm_regulator_get(&client->dev, vreg_name); | ||
116 | if (unlikely(IS_ERR(reg))) { | ||
117 | dev_err(&client->dev, "%s %s ERR: %p\n", | ||
118 | __func__, vreg_name, reg); | ||
119 | err = PTR_ERR(reg); | ||
120 | reg = NULL; | ||
121 | } else | ||
122 | dev_dbg(&client->dev, "%s: %s\n", | ||
123 | __func__, vreg_name); | ||
124 | |||
125 | *vreg = reg; | ||
126 | return err; | ||
127 | } | ||
128 | |||
129 | int camera_common_parse_clocks(struct i2c_client *client, | ||
130 | struct camera_common_pdata *pdata) | ||
131 | { | ||
132 | struct device_node *np = client->dev.of_node; | ||
133 | const char *prop; | ||
134 | int proplen = 0; | ||
135 | int i = 0; | ||
136 | int numclocks = 0; | ||
137 | int mclk_index = 0; | ||
138 | int parentclk_index = -1; | ||
139 | int err = 0; | ||
140 | |||
141 | |||
142 | pdata->mclk_name = NULL; | ||
143 | pdata->parentclk_name = NULL; | ||
144 | err = of_property_read_string(np, "mclk", &pdata->mclk_name); | ||
145 | if (!err) { | ||
146 | dev_dbg(&client->dev, "mclk in DT %s\n", pdata->mclk_name); | ||
147 | of_property_read_string(np, "parent-clk", | ||
148 | &pdata->parentclk_name); | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | prop = (const char *)of_get_property(np, "clock-names", &proplen); | ||
153 | if (!prop) | ||
154 | return -ENODATA; | ||
155 | |||
156 | /* find length of clock-names string array */ | ||
157 | for (i = 0; i < proplen; i++) { | ||
158 | if (prop[i] == '\0') | ||
159 | numclocks++; | ||
160 | } | ||
161 | |||
162 | if (numclocks > 1) { | ||
163 | err = of_property_read_u32(np, "mclk-index", &mclk_index); | ||
164 | if (err) { | ||
165 | dev_err(&client->dev, "Failed to find mclk index\n"); | ||
166 | return err; | ||
167 | } | ||
168 | err = of_property_read_u32(np, "parent-clk-index", | ||
169 | &parentclk_index); | ||
170 | } | ||
171 | |||
172 | for (i = 0; i < numclocks; i++) { | ||
173 | if (i == mclk_index) { | ||
174 | pdata->mclk_name = prop; | ||
175 | dev_dbg(&client->dev, "%s: mclk_name is %s\n", | ||
176 | __func__, pdata->mclk_name); | ||
177 | } else if (i == parentclk_index) { | ||
178 | pdata->parentclk_name = prop; | ||
179 | dev_dbg(&client->dev, "%s: parentclk_name is %s\n", | ||
180 | __func__, pdata->parentclk_name); | ||
181 | } else | ||
182 | dev_dbg(&client->dev, "%s: %s\n", __func__, prop); | ||
183 | prop += strlen(prop) + 1; | ||
184 | } | ||
185 | |||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | int camera_common_parse_ports(struct i2c_client *client, | ||
190 | struct camera_common_data *s_data) | ||
191 | { | ||
192 | struct device_node *node = client->dev.of_node; | ||
193 | struct device_node *ep = NULL; | ||
194 | struct device_node *next; | ||
195 | int bus_width = 0; | ||
196 | int err = 0; | ||
197 | int port = 0; | ||
198 | |||
199 | /* Parse all the remote entities and put them into the list */ | ||
200 | next = of_graph_get_next_endpoint(node, ep); | ||
201 | if (!next) | ||
202 | return -ENODATA; | ||
203 | |||
204 | of_node_put(ep); | ||
205 | ep = next; | ||
206 | |||
207 | err = of_property_read_u32(ep, "bus-width", &bus_width); | ||
208 | if (err) { | ||
209 | dev_err(&client->dev, | ||
210 | "Failed to find num of lanes\n"); | ||
211 | return err; | ||
212 | } | ||
213 | s_data->numlanes = bus_width; | ||
214 | |||
215 | err = of_property_read_u32(ep, "csi-port", &port); | ||
216 | if (err) { | ||
217 | dev_err(&client->dev, | ||
218 | "Failed to find CSI port\n"); | ||
219 | return err; | ||
220 | } | ||
221 | s_data->csi_port = port; | ||
222 | |||
223 | dev_dbg(&client->dev, "%s: csi port %d num of lanes %d\n", | ||
224 | __func__, s_data->csi_port, s_data->numlanes); | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | int camera_common_debugfs_show(struct seq_file *s, void *unused) | ||
230 | { | ||
231 | struct camera_common_data *s_data = s->private; | ||
232 | |||
233 | dev_dbg(&s_data->i2c_client->dev, "%s: ++\n", __func__); | ||
234 | |||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | ssize_t camera_common_debugfs_write( | ||
239 | struct file *file, | ||
240 | char const __user *buf, | ||
241 | size_t count, | ||
242 | loff_t *offset) | ||
243 | { | ||
244 | struct camera_common_data *s_data = | ||
245 | ((struct seq_file *)file->private_data)->private; | ||
246 | struct i2c_client *client = s_data->i2c_client; | ||
247 | int err = 0; | ||
248 | char buffer[MAX_BUFFER_SIZE]; | ||
249 | u32 address; | ||
250 | u32 data; | ||
251 | u8 readback = 0; | ||
252 | |||
253 | dev_dbg(&client->dev, "%s: ++\n", __func__); | ||
254 | |||
255 | if (copy_from_user(&buffer, buf, sizeof(buffer))) | ||
256 | goto debugfs_write_fail; | ||
257 | |||
258 | if (sscanf(buf, "0x%x 0x%x", &address, &data) == 2) | ||
259 | goto set_attr; | ||
260 | if (sscanf(buf, "0X%x 0X%x", &address, &data) == 2) | ||
261 | goto set_attr; | ||
262 | if (sscanf(buf, "%d %d", &address, &data) == 2) | ||
263 | goto set_attr; | ||
264 | |||
265 | if (sscanf(buf, "0x%x 0x%x", &address, &data) == 1) | ||
266 | goto read; | ||
267 | if (sscanf(buf, "0X%x 0X%x", &address, &data) == 1) | ||
268 | goto read; | ||
269 | if (sscanf(buf, "%d %d", &address, &data) == 1) | ||
270 | goto read; | ||
271 | |||
272 | dev_err(&client->dev, "SYNTAX ERROR: %s\n", buf); | ||
273 | return -EFAULT; | ||
274 | |||
275 | set_attr: | ||
276 | dev_dbg(&client->dev, | ||
277 | "new address = %x, data = %x\n", address, data); | ||
278 | err |= call_s_ops(s_data, write_reg, address, data); | ||
279 | read: | ||
280 | err |= call_s_ops(s_data, read_reg, address, &readback); | ||
281 | dev_dbg(&client->dev, | ||
282 | "wrote to address 0x%x with value 0x%x\n", | ||
283 | address, readback); | ||
284 | |||
285 | if (err) | ||
286 | goto debugfs_write_fail; | ||
287 | |||
288 | return count; | ||
289 | |||
290 | debugfs_write_fail: | ||
291 | dev_err(&client->dev, | ||
292 | "%s: test pattern write failed\n", __func__); | ||
293 | return -EFAULT; | ||
294 | } | ||
295 | |||
296 | int camera_common_debugfs_open(struct inode *inode, struct file *file) | ||
297 | { | ||
298 | struct camera_common_data *s_data = inode->i_private; | ||
299 | struct i2c_client *client = s_data->i2c_client; | ||
300 | |||
301 | dev_dbg(&client->dev, "%s: ++\n", __func__); | ||
302 | |||
303 | return single_open(file, camera_common_debugfs_show, inode->i_private); | ||
304 | } | ||
305 | |||
306 | static const struct file_operations camera_common_debugfs_fops = { | ||
307 | .open = camera_common_debugfs_open, | ||
308 | .read = seq_read, | ||
309 | .write = camera_common_debugfs_write, | ||
310 | .llseek = seq_lseek, | ||
311 | .release = single_release, | ||
312 | }; | ||
313 | |||
314 | void camera_common_remove_debugfs( | ||
315 | struct camera_common_data *s_data) | ||
316 | { | ||
317 | struct i2c_client *client = s_data->i2c_client; | ||
318 | |||
319 | dev_dbg(&client->dev, "%s: ++\n", __func__); | ||
320 | |||
321 | debugfs_remove_recursive(s_data->debugdir); | ||
322 | s_data->debugdir = NULL; | ||
323 | } | ||
324 | |||
325 | void camera_common_create_debugfs( | ||
326 | struct camera_common_data *s_data, | ||
327 | const char *name) | ||
328 | { | ||
329 | struct dentry *err; | ||
330 | struct i2c_client *client = s_data->i2c_client; | ||
331 | |||
332 | dev_dbg(&client->dev, "%s %s\n", __func__, name); | ||
333 | |||
334 | s_data->debugdir = | ||
335 | debugfs_create_dir(name, NULL); | ||
336 | if (!s_data->debugdir) | ||
337 | goto remove_debugfs; | ||
338 | |||
339 | err = debugfs_create_file("d", | ||
340 | S_IWUSR | S_IRUGO, | ||
341 | s_data->debugdir, s_data, | ||
342 | &camera_common_debugfs_fops); | ||
343 | if (!err) | ||
344 | goto remove_debugfs; | ||
345 | |||
346 | return; | ||
347 | remove_debugfs: | ||
348 | dev_err(&client->dev, "couldn't create debugfs\n"); | ||
349 | camera_common_remove_debugfs(s_data); | ||
350 | } | ||
351 | |||
352 | /* Find a data format by a pixel code in an array */ | ||
353 | const struct camera_common_colorfmt *camera_common_find_datafmt( | ||
354 | unsigned int code) | ||
355 | { | ||
356 | int i; | ||
357 | |||
358 | for (i = 0; i < ARRAY_SIZE(camera_common_color_fmts); i++) | ||
359 | if (camera_common_color_fmts[i].code == code) | ||
360 | return camera_common_color_fmts + i; | ||
361 | |||
362 | return NULL; | ||
363 | } | ||
364 | EXPORT_SYMBOL(camera_common_find_datafmt); | ||
365 | |||
366 | int camera_common_enum_mbus_code(struct v4l2_subdev *sd, | ||
367 | struct v4l2_subdev_pad_config *cfg, | ||
368 | struct v4l2_subdev_mbus_code_enum *code) | ||
369 | { | ||
370 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
371 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
372 | struct tegra_channel *chan = v4l2_get_subdev_hostdata(sd); | ||
373 | unsigned int mbus_code; | ||
374 | |||
375 | if (s_data->num_color_fmts < 1 || !s_data->color_fmts) { | ||
376 | s_data->color_fmts = camera_common_color_fmts; | ||
377 | s_data->num_color_fmts = ARRAY_SIZE(camera_common_color_fmts); | ||
378 | } | ||
379 | |||
380 | if ((unsigned int)code->index >= s_data->num_color_fmts) | ||
381 | return -EINVAL; | ||
382 | |||
383 | mbus_code = s_data->color_fmts[code->index].code; | ||
384 | if (!camera_common_verify_code(chan, mbus_code)) | ||
385 | return -EINVAL; | ||
386 | |||
387 | code->code = mbus_code; | ||
388 | return 0; | ||
389 | } | ||
390 | EXPORT_SYMBOL(camera_common_enum_mbus_code); | ||
391 | |||
392 | int camera_common_enum_fmt(struct v4l2_subdev *sd, unsigned int index, | ||
393 | unsigned int *code) | ||
394 | { | ||
395 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
396 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
397 | |||
398 | if (s_data->num_color_fmts < 1 || !s_data->color_fmts) { | ||
399 | s_data->color_fmts = camera_common_color_fmts; | ||
400 | s_data->num_color_fmts = ARRAY_SIZE(camera_common_color_fmts); | ||
401 | } | ||
402 | |||
403 | if ((unsigned int)index >= s_data->num_color_fmts) | ||
404 | return -EINVAL; | ||
405 | *code = s_data->color_fmts[index].code; | ||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | int camera_common_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) | ||
410 | { | ||
411 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
412 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
413 | struct tegra_channel *chan = v4l2_get_subdev_hostdata(sd); | ||
414 | struct v4l2_control hdr_control; | ||
415 | const struct camera_common_frmfmt *frmfmt = s_data->frmfmt; | ||
416 | int hdr_en; | ||
417 | int err = 0; | ||
418 | int i; | ||
419 | |||
420 | dev_dbg(&client->dev, "%s: size %i x %i\n", __func__, | ||
421 | mf->width, mf->height); | ||
422 | |||
423 | /* check hdr enable ctrl */ | ||
424 | hdr_control.id = V4L2_CID_HDR_EN; | ||
425 | |||
426 | err = v4l2_g_ctrl(s_data->ctrl_handler, &hdr_control); | ||
427 | if (err < 0) { | ||
428 | dev_err(&client->dev, "could not find device ctrl.\n"); | ||
429 | return err; | ||
430 | } | ||
431 | |||
432 | hdr_en = switch_ctrl_qmenu[hdr_control.value]; | ||
433 | |||
434 | s_data->mode = s_data->def_mode; | ||
435 | s_data->fmt_width = s_data->def_width; | ||
436 | s_data->fmt_height = s_data->def_height; | ||
437 | |||
438 | if (s_data->use_sensor_mode_id && | ||
439 | s_data->sensor_mode_id >= 0 && | ||
440 | s_data->sensor_mode_id < s_data->numfmts) { | ||
441 | dev_dbg(&client->dev, "%s: use_sensor_mode_id %d\n", | ||
442 | __func__, s_data->sensor_mode_id); | ||
443 | s_data->mode = frmfmt[s_data->sensor_mode_id].mode; | ||
444 | s_data->fmt_width = mf->width; | ||
445 | s_data->fmt_height = mf->height; | ||
446 | } else { | ||
447 | for (i = 0; i < s_data->numfmts; i++) { | ||
448 | if (mf->width == frmfmt[i].size.width && | ||
449 | mf->height == frmfmt[i].size.height && | ||
450 | hdr_en == frmfmt[i].hdr_en) { | ||
451 | s_data->mode = frmfmt[i].mode; | ||
452 | s_data->fmt_width = mf->width; | ||
453 | s_data->fmt_height = mf->height; | ||
454 | break; | ||
455 | } | ||
456 | } | ||
457 | |||
458 | if (i == s_data->numfmts) { | ||
459 | mf->width = s_data->fmt_width; | ||
460 | mf->height = s_data->fmt_height; | ||
461 | dev_dbg(&client->dev, | ||
462 | "%s: invalid resolution supplied to set mode %d %d\n", | ||
463 | __func__, mf->width, mf->height); | ||
464 | } | ||
465 | } | ||
466 | |||
467 | if (!camera_common_verify_code(chan, mf->code)) | ||
468 | err = -EINVAL; | ||
469 | |||
470 | mf->field = V4L2_FIELD_NONE; | ||
471 | mf->colorspace = V4L2_COLORSPACE_SRGB; | ||
472 | |||
473 | return err; | ||
474 | } | ||
475 | |||
476 | int camera_common_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) | ||
477 | { | ||
478 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
479 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
480 | int ret; | ||
481 | |||
482 | dev_dbg(&client->dev, "%s(%u) size %i x %i\n", __func__, | ||
483 | mf->code, mf->width, mf->height); | ||
484 | |||
485 | /* MIPI CSI could have changed the format, double-check */ | ||
486 | if (!camera_common_find_datafmt(mf->code)) | ||
487 | return -EINVAL; | ||
488 | |||
489 | ret = camera_common_try_fmt(sd, mf); | ||
490 | |||
491 | s_data->colorfmt = camera_common_find_datafmt(mf->code); | ||
492 | |||
493 | return ret; | ||
494 | } | ||
495 | |||
496 | int camera_common_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) | ||
497 | { | ||
498 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
499 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
500 | const struct camera_common_colorfmt *fmt = s_data->colorfmt; | ||
501 | |||
502 | dev_dbg(&client->dev, "%s++\n", __func__); | ||
503 | |||
504 | mf->code = fmt->code; | ||
505 | mf->colorspace = fmt->colorspace; | ||
506 | mf->width = s_data->fmt_width; | ||
507 | mf->height = s_data->fmt_height; | ||
508 | mf->field = V4L2_FIELD_NONE; | ||
509 | |||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | static int camera_common_evaluate_color_format(struct v4l2_subdev *sd, | ||
514 | int pixelformat) | ||
515 | { | ||
516 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
517 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
518 | int i; | ||
519 | |||
520 | if (!s_data) | ||
521 | return -EINVAL; | ||
522 | |||
523 | if (s_data->num_color_fmts < 1 || !s_data->color_fmts) { | ||
524 | s_data->color_fmts = camera_common_color_fmts; | ||
525 | s_data->num_color_fmts = ARRAY_SIZE(camera_common_color_fmts); | ||
526 | } | ||
527 | |||
528 | for (i = 0; i < s_data->num_color_fmts; i++) { | ||
529 | if (s_data->color_fmts[i].pix_fmt == pixelformat) | ||
530 | break; | ||
531 | } | ||
532 | |||
533 | if (i >= s_data->num_color_fmts) | ||
534 | return -EINVAL; | ||
535 | |||
536 | return 0; | ||
537 | } | ||
538 | |||
539 | int camera_common_enum_framesizes(struct v4l2_subdev *sd, | ||
540 | struct v4l2_subdev_pad_config *cfg, | ||
541 | struct v4l2_subdev_frame_size_enum *fse) | ||
542 | { | ||
543 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
544 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
545 | int ret; | ||
546 | |||
547 | if (!s_data || !s_data->frmfmt) | ||
548 | return -EINVAL; | ||
549 | |||
550 | if (fse->index >= s_data->numfmts) | ||
551 | return -EINVAL; | ||
552 | |||
553 | ret = camera_common_evaluate_color_format(sd, fse->code); | ||
554 | if (ret) | ||
555 | return ret; | ||
556 | |||
557 | fse->min_width = fse->max_width = | ||
558 | s_data->frmfmt[fse->index].size.width; | ||
559 | fse->min_height = fse->max_height = | ||
560 | s_data->frmfmt[fse->index].size.height; | ||
561 | return 0; | ||
562 | } | ||
563 | EXPORT_SYMBOL(camera_common_enum_framesizes); | ||
564 | |||
565 | int camera_common_enum_frameintervals(struct v4l2_subdev *sd, | ||
566 | struct v4l2_subdev_pad_config *cfg, | ||
567 | struct v4l2_subdev_frame_interval_enum *fie) | ||
568 | { | ||
569 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
570 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
571 | int i, ret; | ||
572 | |||
573 | if (!s_data || !s_data->frmfmt) | ||
574 | return -EINVAL; | ||
575 | |||
576 | /* Check color format */ | ||
577 | ret = camera_common_evaluate_color_format(sd, fie->code); | ||
578 | if (ret) | ||
579 | return ret; | ||
580 | |||
581 | /* Check resolution sizes */ | ||
582 | for (i = 0; i < s_data->numfmts; i++) { | ||
583 | if (s_data->frmfmt[i].size.width == fie->width && | ||
584 | s_data->frmfmt[i].size.height == fie->height) | ||
585 | break; | ||
586 | } | ||
587 | if (i >= s_data->numfmts) | ||
588 | return -EINVAL; | ||
589 | |||
590 | /* Check index is in the rage of framerates array index */ | ||
591 | if (fie->index >= s_data->frmfmt[i].num_framerates) | ||
592 | return -EINVAL; | ||
593 | |||
594 | fie->interval.numerator = 1; | ||
595 | fie->interval.denominator = | ||
596 | s_data->frmfmt[i].framerates[fie->index]; | ||
597 | |||
598 | return 0; | ||
599 | } | ||
600 | EXPORT_SYMBOL(camera_common_enum_frameintervals); | ||
601 | |||
602 | static void camera_common_mclk_disable(struct camera_common_data *s_data) | ||
603 | { | ||
604 | struct camera_common_power_rail *pw = s_data->power; | ||
605 | |||
606 | if (!pw) { | ||
607 | dev_err(&s_data->i2c_client->dev, "%s: no device power rail\n", | ||
608 | __func__); | ||
609 | return; | ||
610 | } | ||
611 | |||
612 | dev_dbg(&s_data->i2c_client->dev, "%s: disable MCLK\n", __func__); | ||
613 | clk_disable_unprepare(pw->mclk); | ||
614 | } | ||
615 | |||
616 | static int camera_common_mclk_enable(struct camera_common_data *s_data) | ||
617 | { | ||
618 | int err; | ||
619 | struct camera_common_power_rail *pw = s_data->power; | ||
620 | unsigned long mclk_init_rate = s_data->def_clk_freq; | ||
621 | |||
622 | if (!pw) { | ||
623 | dev_err(s_data->dev, "%s: no device power rail\n", | ||
624 | __func__); | ||
625 | return -ENODEV; | ||
626 | } | ||
627 | |||
628 | dev_dbg(s_data->dev, "%s: enable MCLK with %lu Hz\n", | ||
629 | __func__, mclk_init_rate); | ||
630 | |||
631 | err = clk_set_rate(pw->mclk, mclk_init_rate); | ||
632 | if (!err) | ||
633 | err = clk_prepare_enable(pw->mclk); | ||
634 | |||
635 | return err; | ||
636 | } | ||
637 | |||
638 | void camera_common_dpd_disable(struct camera_common_data *s_data) | ||
639 | { | ||
640 | int i; | ||
641 | int io_idx; | ||
642 | /* 2 lanes per port, divide by two to get numports */ | ||
643 | int numports = (s_data->numlanes + 1) >> 1; | ||
644 | |||
645 | /* disable CSI IOs DPD mode to turn on camera */ | ||
646 | for (i = 0; i < numports; i++) { | ||
647 | io_idx = s_data->csi_port + i; | ||
648 | tegra_pmc_io_pad_low_power_disable( | ||
649 | camera_common_csi_io_pads[io_idx]); | ||
650 | dev_dbg(s_data->dev, | ||
651 | "%s: csi %d\n", __func__, io_idx); | ||
652 | } | ||
653 | } | ||
654 | |||
655 | void camera_common_dpd_enable(struct camera_common_data *s_data) | ||
656 | { | ||
657 | int i; | ||
658 | int io_idx; | ||
659 | /* 2 lanes per port, divide by two to get numports */ | ||
660 | int numports = (s_data->numlanes + 1) >> 1; | ||
661 | |||
662 | /* disable CSI IOs DPD mode to turn on camera */ | ||
663 | for (i = 0; i < numports; i++) { | ||
664 | io_idx = s_data->csi_port + i; | ||
665 | tegra_pmc_io_pad_low_power_enable( | ||
666 | camera_common_csi_io_pads[io_idx]); | ||
667 | dev_dbg(s_data->dev, | ||
668 | "%s: csi %d\n", __func__, io_idx); | ||
669 | } | ||
670 | } | ||
671 | |||
672 | int camera_common_s_power(struct v4l2_subdev *sd, int on) | ||
673 | { | ||
674 | int err = 0; | ||
675 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
676 | struct camera_common_data *s_data = to_camera_common_data(client); | ||
677 | |||
678 | if (on) { | ||
679 | err = camera_common_mclk_enable(s_data); | ||
680 | if (err) | ||
681 | return err; | ||
682 | |||
683 | camera_common_dpd_disable(s_data); | ||
684 | |||
685 | err = call_s_op(s_data, power_on); | ||
686 | if (err) { | ||
687 | dev_err(s_data->dev, | ||
688 | "%s: error power on\n", __func__); | ||
689 | camera_common_dpd_enable(s_data); | ||
690 | camera_common_mclk_disable(s_data); | ||
691 | } | ||
692 | } else { | ||
693 | call_s_op(s_data, power_off); | ||
694 | camera_common_dpd_enable(s_data); | ||
695 | camera_common_mclk_disable(s_data); | ||
696 | } | ||
697 | |||
698 | return err; | ||
699 | } | ||
700 | |||
701 | int camera_common_g_mbus_config(struct v4l2_subdev *sd, | ||
702 | struct v4l2_mbus_config *cfg) | ||
703 | { | ||
704 | cfg->type = V4L2_MBUS_CSI2; | ||
705 | cfg->flags = V4L2_MBUS_CSI2_4_LANE | | ||
706 | V4L2_MBUS_CSI2_CHANNEL_0 | | ||
707 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; | ||
708 | |||
709 | return 0; | ||
710 | } | ||
711 | |||
712 | int camera_common_focuser_s_power(struct v4l2_subdev *sd, int on) | ||
713 | { | ||
714 | int err = 0; | ||
715 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
716 | struct camera_common_focuser_data *s_data = | ||
717 | to_camera_common_focuser_data(client); | ||
718 | |||
719 | if (on) { | ||
720 | err = call_s_op(s_data, power_on); | ||
721 | if (err) | ||
722 | dev_err(&s_data->i2c_client->dev, | ||
723 | "%s: error power on\n", __func__); | ||
724 | } else | ||
725 | err = call_s_op(s_data, power_off); | ||
726 | |||
727 | return err; | ||
728 | } | ||
729 | |||
730 | int camera_common_focuser_init(struct camera_common_focuser_data *s_data) | ||
731 | { | ||
732 | int err = 0; | ||
733 | |||
734 | /* power on */ | ||
735 | err = call_s_op(s_data, power_on); | ||
736 | if (err) { | ||
737 | dev_err(&s_data->i2c_client->dev, | ||
738 | "%s: error power on\n", __func__); | ||
739 | return err; | ||
740 | } | ||
741 | |||
742 | /* load default configuration */ | ||
743 | err = call_s_op(s_data, load_config); | ||
744 | if (err) { | ||
745 | dev_err(&s_data->i2c_client->dev, | ||
746 | "%s: error loading config\n", __func__); | ||
747 | goto fail; | ||
748 | } | ||
749 | |||
750 | /* set controls */ | ||
751 | err = call_s_op(s_data, ctrls_init); | ||
752 | if (err) | ||
753 | dev_err(&s_data->i2c_client->dev, | ||
754 | "%s: error initializing controls\n", __func__); | ||
755 | |||
756 | fail: | ||
757 | /* power off */ | ||
758 | err |= call_s_op(s_data, power_off); | ||
759 | |||
760 | return err; | ||
761 | } | ||
762 | |||
763 | int camera_common_parse_sensor_mode(struct i2c_client *client, | ||
764 | struct camera_common_pdata *pdata) | ||
765 | { | ||
766 | struct device_node *np = client->dev.of_node; | ||
767 | char temp_str[OF_MAX_STR_LEN]; | ||
768 | const char *str; | ||
769 | struct device_node *node; | ||
770 | int num_modes = 0; | ||
771 | int err, i; | ||
772 | |||
773 | /* get number of modes */ | ||
774 | for (i = 0; num_modes < MAX_NUM_SENSOR_MODES; i++) { | ||
775 | snprintf(temp_str, sizeof(temp_str), "%s%d", | ||
776 | OF_SENSORMODE_PREFIX, i); | ||
777 | of_node_get(np); | ||
778 | node = of_find_node_by_name(np, temp_str); | ||
779 | if (node == NULL) | ||
780 | break; | ||
781 | num_modes++; | ||
782 | } | ||
783 | |||
784 | pdata->mode_info = devm_kzalloc(&client->dev, | ||
785 | num_modes * sizeof(struct camera_common_mode_info), | ||
786 | GFP_KERNEL); | ||
787 | if (!pdata->mode_info) { | ||
788 | dev_err(&client->dev, "Failed to allocate memory for mode info\n"); | ||
789 | return -ENOMEM; | ||
790 | } | ||
791 | memset(pdata->mode_info, 0, num_modes * | ||
792 | sizeof(struct camera_common_mode_info)); | ||
793 | |||
794 | /* parse mode info */ | ||
795 | for (i = 0; i < num_modes; i++) { | ||
796 | snprintf(temp_str, sizeof(temp_str), "%s%d", | ||
797 | OF_SENSORMODE_PREFIX, i); | ||
798 | of_node_get(np); | ||
799 | node = of_find_node_by_name(np, temp_str); | ||
800 | if (node == NULL) { | ||
801 | dev_err(&client->dev, "Failed to find mode\n"); | ||
802 | return -ENODATA; | ||
803 | }; | ||
804 | |||
805 | /* read mode width */ | ||
806 | of_property_read_string(node, "active_w", &str); | ||
807 | if (str == NULL) { | ||
808 | dev_err(&client->dev, "Failed to read mode width\n"); | ||
809 | return -ENODATA; | ||
810 | }; | ||
811 | err = kstrtoint(str, 10, &pdata->mode_info[i].width); | ||
812 | if (err) { | ||
813 | dev_err(&client->dev, "Failed to convert mode width\n"); | ||
814 | return -EFAULT; | ||
815 | } | ||
816 | /* read mode height */ | ||
817 | of_property_read_string(node, "active_h", &str); | ||
818 | if (str == NULL) { | ||
819 | dev_err(&client->dev, "Failed to read mode height\n"); | ||
820 | return -ENODATA; | ||
821 | }; | ||
822 | err = kstrtoint(str, 10, &pdata->mode_info[i].height); | ||
823 | if (err) { | ||
824 | dev_err(&client->dev, "Failed to convert mode height\n"); | ||
825 | return -EFAULT; | ||
826 | } | ||
827 | dev_info(&client->dev, "%s: mode %d x %d:\n", __func__, | ||
828 | pdata->mode_info[i].width, pdata->mode_info[i].height); | ||
829 | |||
830 | of_property_read_string(node, "line_length", &str); | ||
831 | if (str == NULL) { | ||
832 | dev_err(&client->dev, "Failed to read mode line_length\n"); | ||
833 | return -ENODATA; | ||
834 | }; | ||
835 | err = kstrtoint(str, 10, &pdata->mode_info[i].line_length); | ||
836 | if (err) { | ||
837 | dev_err(&client->dev, "Failed to convert mode line_length\n"); | ||
838 | return -EFAULT; | ||
839 | } | ||
840 | |||
841 | of_property_read_string(node, "pix_clk_hz", &str); | ||
842 | if (str == NULL) { | ||
843 | dev_err(&client->dev, "Failed to read mode pix_clk_hz\n"); | ||
844 | return -ENODATA; | ||
845 | }; | ||
846 | err = kstrtoll(str, 10, &pdata->mode_info[i].pixel_clock); | ||
847 | if (err) { | ||
848 | dev_err(&client->dev, "Failed to convert mode pix_clk_hz\n"); | ||
849 | return -EFAULT; | ||
850 | } | ||
851 | dev_info(&client->dev, "%s: line_length = %d, pixel_clock = %llu\n", | ||
852 | __func__, pdata->mode_info[i].line_length, | ||
853 | pdata->mode_info[i].pixel_clock); | ||
854 | } | ||
855 | |||
856 | return 0; | ||
857 | } | ||
858 | EXPORT_SYMBOL(camera_common_parse_sensor_mode); | ||
diff --git a/drivers/media/platform/tegra/camera/camera_gpio.c b/drivers/media/platform/tegra/camera/camera_gpio.c new file mode 100644 index 000000000..fcd53e3be --- /dev/null +++ b/drivers/media/platform/tegra/camera/camera_gpio.c | |||
@@ -0,0 +1,160 @@ | |||
1 | /* | ||
2 | * virtual.c - Camera GPIO driver | ||
3 | * | ||
4 | * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. | ||
5 | |||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | |||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | |||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <linux/list.h> | ||
20 | #include <linux/debugfs.h> | ||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/gpio.h> | ||
24 | |||
25 | #include "camera_gpio.h" | ||
26 | |||
27 | struct camera_gpio { | ||
28 | struct list_head list; | ||
29 | unsigned gpio_num; | ||
30 | struct mutex mutex; | ||
31 | atomic_t state_cnt; | ||
32 | atomic_t use_cnt; | ||
33 | }; | ||
34 | |||
35 | static DEFINE_MUTEX(g_mutex); | ||
36 | static LIST_HEAD(cam_gpio_list); | ||
37 | |||
38 | int cam_gpio_register(struct i2c_client *client, | ||
39 | unsigned pin_num) { | ||
40 | struct camera_gpio *new_gpio; | ||
41 | struct camera_gpio *next_gpio; | ||
42 | |||
43 | mutex_lock(&g_mutex); | ||
44 | |||
45 | |||
46 | list_for_each_entry(next_gpio, &cam_gpio_list, list) { | ||
47 | if (next_gpio->gpio_num == pin_num) { | ||
48 | dev_dbg(&client->dev, | ||
49 | "%s: gpio pin %u already registered.\n", | ||
50 | __func__, pin_num); | ||
51 | |||
52 | atomic_inc(&next_gpio->use_cnt); | ||
53 | |||
54 | mutex_unlock(&g_mutex); | ||
55 | return 0; | ||
56 | } | ||
57 | } | ||
58 | |||
59 | /* gpio is not present in the cam_gpio_list, add it */ | ||
60 | new_gpio = kzalloc(sizeof(*new_gpio), GFP_KERNEL); | ||
61 | if (!new_gpio) { | ||
62 | dev_err(&client->dev, "%s: memory low!\n", __func__); | ||
63 | mutex_unlock(&g_mutex); | ||
64 | return -EFAULT; | ||
65 | } | ||
66 | |||
67 | dev_dbg(&client->dev, "%s: adding cam gpio %u\n", | ||
68 | __func__, pin_num); | ||
69 | |||
70 | new_gpio->gpio_num = pin_num; | ||
71 | mutex_init(&new_gpio->mutex); | ||
72 | atomic_inc(&new_gpio->use_cnt); | ||
73 | |||
74 | list_add(&new_gpio->list, &cam_gpio_list); | ||
75 | |||
76 | mutex_unlock(&g_mutex); | ||
77 | return 0; | ||
78 | } | ||
79 | EXPORT_SYMBOL(cam_gpio_register); | ||
80 | |||
81 | void cam_gpio_deregister(struct i2c_client *client, | ||
82 | unsigned pin_num) { | ||
83 | struct camera_gpio *next_gpio; | ||
84 | |||
85 | mutex_lock(&g_mutex); | ||
86 | |||
87 | |||
88 | list_for_each_entry(next_gpio, &cam_gpio_list, list) { | ||
89 | if (next_gpio->gpio_num == pin_num) { | ||
90 | atomic_dec(&next_gpio->use_cnt); | ||
91 | |||
92 | if (atomic_read(&next_gpio->use_cnt) == 0) { | ||
93 | list_del(&next_gpio->list); | ||
94 | kfree(next_gpio); | ||
95 | |||
96 | dev_dbg(&client->dev, | ||
97 | "%s: removing cam gpio %u\n", | ||
98 | __func__, pin_num); | ||
99 | } | ||
100 | |||
101 | break; | ||
102 | } | ||
103 | } | ||
104 | |||
105 | mutex_unlock(&g_mutex); | ||
106 | return; | ||
107 | } | ||
108 | EXPORT_SYMBOL(cam_gpio_deregister); | ||
109 | |||
110 | int cam_gpio_ctrl(struct i2c_client *client, | ||
111 | unsigned pin_num, int val, | ||
112 | bool active_high) /* val: 0=deassert, 1=assert */ | ||
113 | { | ||
114 | struct camera_gpio *next_gpio; | ||
115 | int err = -EINVAL; | ||
116 | int pin_val; | ||
117 | bool found = false; | ||
118 | |||
119 | list_for_each_entry(next_gpio, &cam_gpio_list, list) { | ||
120 | mutex_lock(&next_gpio->mutex); | ||
121 | if (next_gpio->gpio_num == pin_num) { | ||
122 | found = true; | ||
123 | |||
124 | if (!atomic_read(&next_gpio->state_cnt) && | ||
125 | !val) { | ||
126 | dev_err(&client->dev, | ||
127 | "%s: state cnt can't be < 0\n", | ||
128 | __func__); | ||
129 | mutex_unlock(&next_gpio->mutex); | ||
130 | return err; | ||
131 | } | ||
132 | |||
133 | if (val) | ||
134 | atomic_inc(&next_gpio->state_cnt); | ||
135 | else | ||
136 | atomic_dec(&next_gpio->state_cnt); | ||
137 | |||
138 | pin_val = active_high ? val : !val; | ||
139 | pin_val &= 1; | ||
140 | err = pin_val; | ||
141 | |||
142 | /* subtract val allows a 0 check to be | ||
143 | * used to indicate that gpio can be written to*/ | ||
144 | if (atomic_read(&next_gpio->state_cnt) - val == 0) { | ||
145 | gpio_set_value_cansleep(pin_num, pin_val); | ||
146 | dev_dbg(&client->dev, "%s %u %d\n", | ||
147 | __func__, pin_num, pin_val); | ||
148 | } | ||
149 | } | ||
150 | mutex_unlock(&next_gpio->mutex); | ||
151 | } | ||
152 | |||
153 | if (!found) | ||
154 | dev_dbg(&client->dev, | ||
155 | "WARNING %s: gpio %u not in list\n", | ||
156 | __func__, pin_num); | ||
157 | |||
158 | return err; /* return value written or error */ | ||
159 | } | ||
160 | EXPORT_SYMBOL(cam_gpio_ctrl); | ||
diff --git a/drivers/media/platform/tegra/camera/camera_gpio.h b/drivers/media/platform/tegra/camera/camera_gpio.h new file mode 100644 index 000000000..b388e178d --- /dev/null +++ b/drivers/media/platform/tegra/camera/camera_gpio.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. | ||
3 | |||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | |||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | |||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #ifndef __CAMERA_GPIO_H__ | ||
18 | #define __CAMERA_GPIO_H__ | ||
19 | |||
20 | int cam_gpio_register(struct i2c_client *client, | ||
21 | unsigned pin_num); | ||
22 | |||
23 | void cam_gpio_deregister(struct i2c_client *client, | ||
24 | unsigned pin_num); | ||
25 | |||
26 | int cam_gpio_ctrl(struct i2c_client *client, | ||
27 | unsigned pin_num, int ref_inc, bool active_high); | ||
28 | |||
29 | #endif | ||
30 | /* __CAMERA_GPIO_H__ */ | ||
diff --git a/drivers/media/platform/tegra/camera/csi/Makefile b/drivers/media/platform/tegra/camera/csi/Makefile new file mode 100644 index 000000000..3d307cb83 --- /dev/null +++ b/drivers/media/platform/tegra/camera/csi/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | GCOV_PROFILE := y | ||
2 | ccflags-y += -I../nvhost/drivers/video/tegra/host | ||
3 | ccflags-y += -I../nvhost/include | ||
4 | ccflags-y += -Idrivers/video/tegra/camera | ||
5 | ccflags-y += -Idrivers/media/platform/tegra | ||
6 | ccflags-y += -Werror | ||
7 | |||
8 | obj-y += csi.o csi2_fops.o csi4_fops.o | ||
diff --git a/drivers/media/platform/tegra/camera/csi/csi.c b/drivers/media/platform/tegra/camera/csi/csi.c new file mode 100644 index 000000000..f6c838ff2 --- /dev/null +++ b/drivers/media/platform/tegra/camera/csi/csi.c | |||
@@ -0,0 +1,784 @@ | |||
1 | /* | ||
2 | * NVIDIA Tegra CSI Device | ||
3 | * | ||
4 | * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * Author: Bryan Wu <pengw@nvidia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/clk.h> | ||
14 | #include <linux/device.h> | ||
15 | #include <linux/gpio/consumer.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/of_graph.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/of_platform.h> | ||
21 | |||
22 | #include <media/media-entity.h> | ||
23 | #include <media/v4l2-async.h> | ||
24 | #include <media/v4l2-ctrls.h> | ||
25 | #include <media/camera_common.h> | ||
26 | |||
27 | #include "dev.h" | ||
28 | #include "vi/vi.h" | ||
29 | #include "camera/csi/csi.h" | ||
30 | #include "camera/vi/mc_common.h" | ||
31 | #include "mipical/mipi_cal.h" | ||
32 | #include "linux/nvhost.h" | ||
33 | |||
34 | static int set_csi_properties(struct tegra_csi_device *csi, | ||
35 | struct platform_device *pdev) | ||
36 | { | ||
37 | struct camera_common_data *s_data = &csi->s_data[0]; | ||
38 | |||
39 | /* | ||
40 | * These values are only used for tpg mode | ||
41 | * With sensor, CSI power and clock info are provided | ||
42 | * by the sensor sub device | ||
43 | */ | ||
44 | s_data->csi_port = 0; | ||
45 | s_data->numlanes = 12; | ||
46 | csi->clk_freq = TEGRA_CLOCK_CSI_PORT_MAX; | ||
47 | |||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | static void update_blank_intervals(struct tegra_csi_channel *chan, | ||
52 | int portnum, int fmtindex) | ||
53 | { | ||
54 | struct tegra_csi_port *port = &chan->ports[portnum]; | ||
55 | const struct tpg_frmfmt *tegra_csi_tpg_frmfmt = | ||
56 | chan->csi->tpg_frmfmt_table; | ||
57 | |||
58 | port->framerate = tegra_csi_tpg_frmfmt[fmtindex].framerate; | ||
59 | port->h_blank = tegra_csi_tpg_frmfmt[fmtindex].h_blank; | ||
60 | port->v_blank = tegra_csi_tpg_frmfmt[fmtindex].v_blank; | ||
61 | } | ||
62 | |||
63 | void set_csi_portinfo(struct tegra_csi_device *csi, | ||
64 | unsigned int port, unsigned int numlanes) | ||
65 | { | ||
66 | struct camera_common_data *s_data = &csi->s_data[port]; | ||
67 | |||
68 | s_data->csi_port = port; | ||
69 | s_data->numlanes = numlanes; | ||
70 | s_data->def_clk_freq = TEGRA_CLOCK_CSI_PORT_MAX; | ||
71 | } | ||
72 | EXPORT_SYMBOL(set_csi_portinfo); | ||
73 | |||
74 | int tegra_csi_power(struct tegra_csi_device *csi, int enable) | ||
75 | { | ||
76 | int err = 0; | ||
77 | |||
78 | if (enable) { | ||
79 | err = csi->fops->csi_power_on(csi); | ||
80 | if (!err) | ||
81 | atomic_inc(&csi->power_ref); | ||
82 | } else { | ||
83 | err = csi->fops->csi_power_off(csi); | ||
84 | if (!err) | ||
85 | atomic_dec(&csi->power_ref); | ||
86 | } | ||
87 | return err; | ||
88 | } | ||
89 | EXPORT_SYMBOL(tegra_csi_power); | ||
90 | |||
91 | int tegra_csi_s_power(struct v4l2_subdev *subdev, int enable) | ||
92 | { | ||
93 | int err = 0; | ||
94 | struct tegra_csi_device *csi = to_csi(subdev); | ||
95 | |||
96 | err = tegra_csi_power(csi, enable); | ||
97 | |||
98 | return err; | ||
99 | } | ||
100 | |||
101 | /* | ||
102 | * ----------------------------------------------------------------------------- | ||
103 | * CSI Subdevice Video Operations | ||
104 | * ----------------------------------------------------------------------------- | ||
105 | */ | ||
106 | |||
107 | int tegra_csi_start_streaming(struct tegra_csi_channel *chan, | ||
108 | enum tegra_csi_port_num port_num) | ||
109 | { | ||
110 | struct tegra_csi_device *csi = chan->csi; | ||
111 | |||
112 | return csi->fops->csi_start_streaming(chan, port_num); | ||
113 | } | ||
114 | EXPORT_SYMBOL(tegra_csi_start_streaming); | ||
115 | |||
116 | void tegra_csi_stop_streaming(struct tegra_csi_channel *chan, | ||
117 | enum tegra_csi_port_num port_num) | ||
118 | { | ||
119 | struct tegra_csi_device *csi = chan->csi; | ||
120 | |||
121 | csi->fops->csi_stop_streaming(chan, port_num); | ||
122 | } | ||
123 | EXPORT_SYMBOL(tegra_csi_stop_streaming); | ||
124 | |||
125 | static int tegra_csi_s_stream(struct v4l2_subdev *subdev, int enable) | ||
126 | { | ||
127 | struct tegra_csi_device *csi; | ||
128 | struct tegra_csi_channel *chan = to_csi_chan(subdev); | ||
129 | struct tegra_channel *tegra_chan = v4l2_get_subdev_hostdata(subdev); | ||
130 | int i, ret = 0; | ||
131 | |||
132 | csi = to_csi(subdev); | ||
133 | if (!csi) | ||
134 | return -EINVAL; | ||
135 | if (!chan->pg_mode) { | ||
136 | if (enable) { | ||
137 | tegra_mipi_bias_pad_enable(); | ||
138 | csi->fops->mipical(chan); | ||
139 | } else | ||
140 | tegra_mipi_bias_pad_disable(); | ||
141 | } | ||
142 | if (tegra_chan->bypass) | ||
143 | return 0; | ||
144 | |||
145 | for (i = 0; i < tegra_chan->valid_ports; i++) { | ||
146 | if (enable) { | ||
147 | ret = tegra_csi_start_streaming(chan, i); | ||
148 | if (ret) | ||
149 | tegra_csi_stop_streaming(chan, i); | ||
150 | } else | ||
151 | tegra_csi_stop_streaming(chan, i); | ||
152 | } | ||
153 | return ret; | ||
154 | } | ||
155 | |||
156 | /* | ||
157 | * Only use this subdevice media bus ops for test pattern generator, | ||
158 | * because CSI device is an separated subdevice which has 6 source | ||
159 | * pads to generate test pattern. | ||
160 | */ | ||
161 | static struct v4l2_mbus_framefmt tegra_csi_tpg_fmts[] = { | ||
162 | { | ||
163 | TEGRA_DEF_WIDTH, | ||
164 | TEGRA_DEF_HEIGHT, | ||
165 | MEDIA_BUS_FMT_SRGGB10_1X10, | ||
166 | V4L2_FIELD_NONE, | ||
167 | V4L2_COLORSPACE_SRGB | ||
168 | }, | ||
169 | { | ||
170 | TEGRA_DEF_WIDTH, | ||
171 | TEGRA_DEF_HEIGHT, | ||
172 | MEDIA_BUS_FMT_RGB888_1X32_PADHI, | ||
173 | V4L2_FIELD_NONE, | ||
174 | V4L2_COLORSPACE_SRGB | ||
175 | } | ||
176 | |||
177 | }; | ||
178 | |||
179 | static struct v4l2_frmsize_discrete tegra_csi_tpg_sizes[] = { | ||
180 | {1280, 720}, | ||
181 | {1920, 1080}, | ||
182 | {3840, 2160} | ||
183 | }; | ||
184 | |||
185 | static int tegra_csi_enum_framesizes(struct v4l2_subdev *sd, | ||
186 | struct v4l2_subdev_pad_config *cfg, | ||
187 | struct v4l2_subdev_frame_size_enum *fse) | ||
188 | { | ||
189 | int i; | ||
190 | struct tegra_csi_channel *chan = to_csi_chan(sd); | ||
191 | struct tegra_channel *vi_chan = v4l2_get_subdev_hostdata(sd); | ||
192 | |||
193 | if (!chan->pg_mode) | ||
194 | return -ENOIOCTLCMD; | ||
195 | |||
196 | if (fse->index >= ARRAY_SIZE(tegra_csi_tpg_sizes)) | ||
197 | return -EINVAL; | ||
198 | |||
199 | for (i = 0; i < ARRAY_SIZE(tegra_csi_tpg_fmts); i++) { | ||
200 | const struct tegra_video_format *format = | ||
201 | tegra_core_get_format_by_code(vi_chan, | ||
202 | tegra_csi_tpg_fmts[i].code, 0); | ||
203 | if (format && format->fourcc == fse->code) | ||
204 | break; | ||
205 | } | ||
206 | if (i == ARRAY_SIZE(tegra_csi_tpg_fmts)) | ||
207 | return -EINVAL; | ||
208 | |||
209 | fse->min_width = fse->max_width = | ||
210 | tegra_csi_tpg_sizes[fse->index].width; | ||
211 | fse->min_height = fse->max_height = | ||
212 | tegra_csi_tpg_sizes[fse->index].height; | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static int tegra_csi_get_fmtindex(struct tegra_csi_channel *chan, | ||
217 | int width, int height, int pixel_format) | ||
218 | { | ||
219 | int i; | ||
220 | const struct tpg_frmfmt *tegra_csi_tpg_frmfmt = | ||
221 | chan->csi->tpg_frmfmt_table; | ||
222 | |||
223 | for (i = 0; i < chan->csi->tpg_frmfmt_table_size; i++) { | ||
224 | if (tegra_csi_tpg_frmfmt[i].frmsize.width == width && | ||
225 | tegra_csi_tpg_frmfmt[i].frmsize.height == height && | ||
226 | tegra_csi_tpg_frmfmt[i].pixel_format == pixel_format) | ||
227 | break; | ||
228 | } | ||
229 | |||
230 | if (i == chan->csi->tpg_frmfmt_table_size) | ||
231 | return -EINVAL; | ||
232 | |||
233 | return i; | ||
234 | } | ||
235 | |||
236 | static int tegra_csi_enum_frameintervals(struct v4l2_subdev *sd, | ||
237 | struct v4l2_subdev_pad_config *cfg, | ||
238 | struct v4l2_subdev_frame_interval_enum *fie) | ||
239 | { | ||
240 | int index; | ||
241 | struct tegra_csi_channel *chan = to_csi_chan(sd); | ||
242 | const struct tegra_video_format *format; | ||
243 | const struct tpg_frmfmt *tegra_csi_tpg_frmfmt = | ||
244 | chan->csi->tpg_frmfmt_table; | ||
245 | struct tegra_channel *vi_chan = v4l2_get_subdev_hostdata(sd); | ||
246 | |||
247 | if (!chan->pg_mode) | ||
248 | return -ENOIOCTLCMD; | ||
249 | |||
250 | /* One resolution just one framerate */ | ||
251 | if (fie->index > 0) | ||
252 | return -EINVAL; | ||
253 | format = tegra_core_get_format_by_fourcc(vi_chan, fie->code); | ||
254 | if (!format) | ||
255 | return -EINVAL; | ||
256 | index = tegra_csi_get_fmtindex(chan, fie->width, fie->height, | ||
257 | format->fourcc); | ||
258 | if (index < 0) | ||
259 | return -EINVAL; | ||
260 | |||
261 | fie->interval.numerator = 1; | ||
262 | fie->interval.denominator = tegra_csi_tpg_frmfmt[index].framerate; | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | static int tegra_csi_try_mbus_fmt(struct v4l2_subdev *sd, | ||
268 | struct v4l2_mbus_framefmt *mf) | ||
269 | { | ||
270 | int i, j; | ||
271 | struct tegra_csi_channel *chan = to_csi_chan(sd); | ||
272 | static struct v4l2_frmsize_discrete *sizes; | ||
273 | |||
274 | if (!chan->pg_mode) | ||
275 | return -ENOIOCTLCMD; | ||
276 | |||
277 | for (i = 0; i < ARRAY_SIZE(tegra_csi_tpg_fmts); i++) { | ||
278 | struct v4l2_mbus_framefmt *fmt = &tegra_csi_tpg_fmts[i]; | ||
279 | |||
280 | if (mf->code == fmt->code && mf->field == fmt->field && | ||
281 | mf->colorspace == fmt->colorspace) { | ||
282 | for (j = 0; j < ARRAY_SIZE(tegra_csi_tpg_sizes); j++) { | ||
283 | sizes = &tegra_csi_tpg_sizes[j]; | ||
284 | if (mf->width == sizes->width && | ||
285 | mf->height == sizes->height) | ||
286 | return 0; | ||
287 | } | ||
288 | } | ||
289 | } | ||
290 | |||
291 | memcpy(mf, tegra_csi_tpg_fmts, sizeof(struct v4l2_mbus_framefmt)); | ||
292 | |||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | static int tegra_csi_g_mbus_fmt(struct v4l2_subdev *sd, | ||
297 | struct v4l2_mbus_framefmt *fmt) | ||
298 | { | ||
299 | struct tegra_csi_channel *chan = to_csi_chan(sd); | ||
300 | struct v4l2_mbus_framefmt *format = &chan->ports[0].format; | ||
301 | |||
302 | if (!chan->pg_mode) { | ||
303 | dev_err(chan->csi->dev, "CSI is not in TPG mode\n"); | ||
304 | return -EINVAL; | ||
305 | } | ||
306 | |||
307 | mutex_lock(&chan->format_lock); | ||
308 | memcpy(fmt, format, sizeof(struct v4l2_mbus_framefmt)); | ||
309 | mutex_unlock(&chan->format_lock); | ||
310 | |||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static int csi_is_power_on(struct tegra_csi_device *csi) | ||
315 | { | ||
316 | return atomic_read(&csi->power_ref); | ||
317 | } | ||
318 | static int tegra_csi_g_input_status(struct v4l2_subdev *sd, u32 *status) | ||
319 | { | ||
320 | struct tegra_csi_device *csi = to_csi(sd); | ||
321 | |||
322 | /* Set status to 0 if power is on | ||
323 | * Set status to 1 if power is off | ||
324 | */ | ||
325 | *status = !csi_is_power_on(csi); | ||
326 | |||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | /* ----------------------------------------------------------------------------- | ||
331 | * V4L2 Subdevice Pad Operations | ||
332 | */ | ||
333 | |||
334 | static int tegra_csi_get_format(struct v4l2_subdev *subdev, | ||
335 | struct v4l2_subdev_pad_config *cfg, | ||
336 | struct v4l2_subdev_format *fmt) | ||
337 | { | ||
338 | struct tegra_csi_channel *chan = to_csi_chan(subdev); | ||
339 | struct v4l2_mbus_framefmt *mbus_fmt = &fmt->format; | ||
340 | int ret; | ||
341 | |||
342 | if (!chan->pg_mode) | ||
343 | return -ENOIOCTLCMD; | ||
344 | ret = tegra_csi_g_mbus_fmt(subdev, mbus_fmt); | ||
345 | if (ret) | ||
346 | return ret; | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static int tegra_csi_set_format(struct v4l2_subdev *subdev, | ||
352 | struct v4l2_subdev_pad_config *cfg, | ||
353 | struct v4l2_subdev_format *fmt) | ||
354 | { | ||
355 | int ret; | ||
356 | struct tegra_csi_channel *chan = to_csi_chan(subdev); | ||
357 | struct v4l2_mbus_framefmt *format = &fmt->format; | ||
358 | const struct tegra_video_format *vf; | ||
359 | struct tegra_channel *vi_chan = v4l2_get_subdev_hostdata(subdev); | ||
360 | int index, i; | ||
361 | |||
362 | if (!chan->pg_mode) | ||
363 | return -ENOIOCTLCMD; | ||
364 | |||
365 | ret = tegra_csi_try_mbus_fmt(subdev, format); | ||
366 | if (ret) | ||
367 | return ret; | ||
368 | |||
369 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) | ||
370 | return 0; | ||
371 | |||
372 | vf = tegra_core_get_format_by_code(vi_chan, format->code, 0); | ||
373 | if (!vf) { | ||
374 | dev_err(chan->csi->dev, "Fail to find tegra video fmt"); | ||
375 | mutex_unlock(&chan->format_lock); | ||
376 | return -EINVAL; | ||
377 | } | ||
378 | index = tegra_csi_get_fmtindex(chan, format->width, | ||
379 | format->height, vf->fourcc); | ||
380 | if (index < 0) { | ||
381 | dev_err(chan->csi->dev, "Fail to find matching fmt"); | ||
382 | return -EINVAL; | ||
383 | } | ||
384 | |||
385 | mutex_lock(&chan->format_lock); | ||
386 | for (i = 0; i < vi_chan->valid_ports; i++) { | ||
387 | memcpy(&chan->ports[i].format, | ||
388 | &fmt->format, sizeof(struct v4l2_mbus_framefmt)); | ||
389 | chan->ports[i].core_format = vf; | ||
390 | update_blank_intervals(chan, i, index); | ||
391 | } | ||
392 | mutex_unlock(&chan->format_lock); | ||
393 | |||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | static int tegra_csi_g_frame_interval(struct v4l2_subdev *sd, | ||
398 | struct v4l2_subdev_frame_interval *vfi) | ||
399 | { | ||
400 | struct tegra_csi_channel *chan = to_csi_chan(sd); | ||
401 | struct tegra_csi_port *port = &chan->ports[0]; | ||
402 | |||
403 | if (!port->framerate) | ||
404 | return -EINVAL; | ||
405 | |||
406 | vfi->interval.numerator = 1; | ||
407 | vfi->interval.denominator = port->framerate; | ||
408 | |||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | /* ----------------------------------------------------------------------------- | ||
413 | * V4L2 Subdevice Operations | ||
414 | */ | ||
415 | static struct v4l2_subdev_video_ops tegra_csi_video_ops = { | ||
416 | .s_stream = tegra_csi_s_stream, | ||
417 | .g_input_status = tegra_csi_g_input_status, | ||
418 | .g_frame_interval = tegra_csi_g_frame_interval, | ||
419 | }; | ||
420 | |||
421 | static struct v4l2_subdev_pad_ops tegra_csi_pad_ops = { | ||
422 | .get_fmt = tegra_csi_get_format, | ||
423 | .set_fmt = tegra_csi_set_format, | ||
424 | .enum_frame_size = tegra_csi_enum_framesizes, | ||
425 | .enum_frame_interval = tegra_csi_enum_frameintervals, | ||
426 | }; | ||
427 | |||
428 | static struct v4l2_subdev_core_ops tegra_csi_core_ops = { | ||
429 | .s_power = tegra_csi_s_power, | ||
430 | }; | ||
431 | |||
432 | static struct v4l2_subdev_ops tegra_csi_ops = { | ||
433 | .core = &tegra_csi_core_ops, | ||
434 | .video = &tegra_csi_video_ops, | ||
435 | .pad = &tegra_csi_pad_ops, | ||
436 | }; | ||
437 | |||
438 | /* ----------------------------------------------------------------------------- | ||
439 | * Media Operations | ||
440 | */ | ||
441 | |||
442 | static const struct media_entity_operations tegra_csi_media_ops = { | ||
443 | .link_validate = v4l2_subdev_link_validate, | ||
444 | }; | ||
445 | |||
446 | /* ----------------------------------------------------------------------------- | ||
447 | * Platform Device Driver | ||
448 | */ | ||
449 | |||
450 | static int tegra_csi_get_port_info(struct tegra_csi_channel *chan, | ||
451 | struct device_node *node, unsigned int index) | ||
452 | { | ||
453 | struct device_node *ep = NULL; | ||
454 | struct device_node *ports; | ||
455 | struct device_node *port; | ||
456 | struct device_node *chan_dt; | ||
457 | |||
458 | int value = 0xFFFF; | ||
459 | int ret = 0, i; | ||
460 | |||
461 | memset(&chan->port[0], INVALID_CSI_PORT, TEGRA_CSI_BLOCKS); | ||
462 | for_each_child_of_node(node, chan_dt) { | ||
463 | if (!chan_dt->name || of_node_cmp(chan_dt->name, "channel")) | ||
464 | continue; | ||
465 | ret = of_property_read_u32(chan_dt, "reg", &value); | ||
466 | if (ret < 0) | ||
467 | return -EINVAL; | ||
468 | if (value == index) | ||
469 | break; | ||
470 | } | ||
471 | |||
472 | chan->subdev.of_node = chan_dt; | ||
473 | ports = of_get_child_by_name(chan_dt, "ports"); | ||
474 | if (ports == NULL) | ||
475 | return -EINVAL; | ||
476 | |||
477 | for_each_child_of_node(ports, port) { | ||
478 | if (!port->name || of_node_cmp(port->name, "port")) | ||
479 | continue; | ||
480 | ret = of_property_read_u32(port, "reg", &value); | ||
481 | if (ret < 0) | ||
482 | continue; | ||
483 | if (value != 0) | ||
484 | continue; | ||
485 | for_each_child_of_node(port, ep) { | ||
486 | if (!ep->name || of_node_cmp(ep->name, "endpoint")) | ||
487 | continue; | ||
488 | ret = of_property_read_u32(ep, "csi-port", &value); | ||
489 | if (ret < 0) | ||
490 | dev_err(chan->csi->dev, "No csi port info\n"); | ||
491 | chan->port[0] = value; | ||
492 | |||
493 | ret = of_property_read_u32(ep, "bus-width", &value); | ||
494 | if (ret < 0) | ||
495 | dev_err(chan->csi->dev, "No bus width info\n"); | ||
496 | chan->numlanes = value; | ||
497 | if (value > 12) { | ||
498 | dev_err(chan->csi->dev, "Invalid num lanes\n"); | ||
499 | return -EINVAL; | ||
500 | } | ||
501 | /* | ||
502 | * for numlanes greater than 4 multiple CSI bricks | ||
503 | * are needed to capture the image, the logic below | ||
504 | * checks for numlanes > 4 and add a new CSI brick | ||
505 | * as a valid port. Loops around the three CSI | ||
506 | * bricks to add as many ports necessary. | ||
507 | */ | ||
508 | value -= 4; | ||
509 | for (i = 1; value > 0; i++, value -= 4) { | ||
510 | int next_port = chan->port[i-1] + 2; | ||
511 | |||
512 | next_port = (next_port % (PORT_F + 1)); | ||
513 | chan->port[i] = next_port; | ||
514 | } | ||
515 | } | ||
516 | } | ||
517 | |||
518 | for (i = 0; csi_port_is_valid(chan->port[i]); i++) | ||
519 | chan->numports++; | ||
520 | |||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | int tegra_csi_init(struct tegra_csi_device *csi, | ||
525 | struct platform_device *pdev) | ||
526 | { | ||
527 | int err = 0; | ||
528 | struct nvhost_device_data *pdata = platform_get_drvdata(pdev); | ||
529 | |||
530 | csi->dev = &pdev->dev; | ||
531 | err = set_csi_properties(csi, pdev); | ||
532 | if (err) | ||
533 | return err; | ||
534 | |||
535 | csi->iomem_base = pdata->aperture[0]; | ||
536 | csi->fops->hw_init(csi); | ||
537 | return err; | ||
538 | } | ||
539 | |||
540 | static int tegra_csi_channel_init_one(struct tegra_csi_channel *chan) | ||
541 | { | ||
542 | struct v4l2_subdev *sd; | ||
543 | int numlanes = 0; | ||
544 | struct tegra_csi_device *csi = chan->csi; | ||
545 | int i, ret; | ||
546 | const struct tegra_video_format *vf; | ||
547 | |||
548 | mutex_init(&chan->format_lock); | ||
549 | |||
550 | vf = tegra_core_get_default_format(); | ||
551 | if (vf == NULL) { | ||
552 | dev_err(csi->dev, "Fail to find tegra video fmt"); | ||
553 | return -EINVAL; | ||
554 | } | ||
555 | |||
556 | sd = &chan->subdev; | ||
557 | /* Initialize V4L2 subdevice and media entity */ | ||
558 | v4l2_subdev_init(sd, &tegra_csi_ops); | ||
559 | sd->dev = chan->csi->dev; | ||
560 | v4l2_set_subdevdata(sd, csi); | ||
561 | sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
562 | sd->entity.ops = &tegra_csi_media_ops; | ||
563 | chan->ports = devm_kzalloc(csi->dev, | ||
564 | chan->numports * sizeof(struct tegra_csi_port), | ||
565 | GFP_KERNEL); | ||
566 | if (!chan->ports) | ||
567 | return -ENOMEM; | ||
568 | |||
569 | /* Initialize the default format */ | ||
570 | for (i = 0; i < chan->numports; i++) { | ||
571 | chan->ports[i].format.code = vf->vf_code; | ||
572 | chan->ports[i].format.field = V4L2_FIELD_NONE; | ||
573 | chan->ports[i].format.colorspace = V4L2_COLORSPACE_SRGB; | ||
574 | chan->ports[i].format.width = TEGRA_DEF_WIDTH; | ||
575 | chan->ports[i].format.height = TEGRA_DEF_HEIGHT; | ||
576 | chan->ports[i].core_format = vf; | ||
577 | } | ||
578 | if (chan->pg_mode) { | ||
579 | /* If CSI has 2 existing channels, chan->id will start | ||
580 | * from 2 for the first TPG channel, which uses PORT_A(0). | ||
581 | * To get the correct PORT number, subtract existing number of | ||
582 | * channels from chan->id. | ||
583 | */ | ||
584 | chan->port[0] = chan->id - csi->num_channels; | ||
585 | WARN_ON(chan->port[0] > TPG_CHANNELS); | ||
586 | chan->ports[0].num = chan->id - csi->num_channels; | ||
587 | chan->ports->lanes = 2; | ||
588 | chan->pads = devm_kzalloc(csi->dev, sizeof(*chan->pads), | ||
589 | GFP_KERNEL); | ||
590 | if (!chan->pads) | ||
591 | return -ENOMEM; | ||
592 | chan->pads[0].flags = MEDIA_PAD_FL_SOURCE; | ||
593 | } else { | ||
594 | chan->pads = devm_kzalloc(csi->dev, 2 * sizeof(*chan->pads), | ||
595 | GFP_KERNEL); | ||
596 | if (!chan->pads) | ||
597 | return -ENOMEM; | ||
598 | chan->pads[0].flags = MEDIA_PAD_FL_SINK; | ||
599 | chan->pads[1].flags = MEDIA_PAD_FL_SOURCE; | ||
600 | } | ||
601 | snprintf(sd->name, sizeof(sd->name), "%s-%d", | ||
602 | chan->pg_mode ? "tpg" : | ||
603 | (strlen(csi->devname) == 0 ? | ||
604 | dev_name(csi->dev) : csi->devname), | ||
605 | chan->port[0]); | ||
606 | /* Initialize media entity */ | ||
607 | ret = media_entity_init(&sd->entity, | ||
608 | chan->pg_mode ? 1 : 2, | ||
609 | chan->pads, 0); | ||
610 | if (ret < 0) | ||
611 | return ret; | ||
612 | |||
613 | for (i = 0; i < chan->numports; i++) { | ||
614 | numlanes = chan->numlanes - (i * MAX_CSI_BLOCK_LANES); | ||
615 | WARN_ON(numlanes < 0); | ||
616 | numlanes = numlanes > MAX_CSI_BLOCK_LANES ? | ||
617 | MAX_CSI_BLOCK_LANES : numlanes; | ||
618 | chan->ports[i].lanes = numlanes; | ||
619 | chan->ports[i].num = chan->port[i]; | ||
620 | } | ||
621 | |||
622 | if (!chan->pg_mode) { | ||
623 | ret = v4l2_async_register_subdev(sd); | ||
624 | if (ret < 0) { | ||
625 | dev_err(csi->dev, "failed to register subdev\n"); | ||
626 | media_entity_cleanup(&sd->entity); | ||
627 | } | ||
628 | } | ||
629 | return ret; | ||
630 | } | ||
631 | |||
632 | static int tegra_csi_channels_init(struct tegra_csi_device *csi) | ||
633 | { | ||
634 | int ret; | ||
635 | struct tegra_csi_channel *it; | ||
636 | |||
637 | list_for_each_entry(it, &csi->csi_chans, list) { | ||
638 | ret = tegra_csi_channel_init_one(it); | ||
639 | if (ret) | ||
640 | return ret; | ||
641 | } | ||
642 | |||
643 | return 0; | ||
644 | } | ||
645 | |||
646 | static int csi_parse_dt(struct tegra_csi_device *csi, | ||
647 | struct platform_device *pdev) | ||
648 | { | ||
649 | int err = 0, i; | ||
650 | int num_channels = 0; | ||
651 | struct device_node *node = pdev->dev.of_node; | ||
652 | struct tegra_csi_channel *item; | ||
653 | |||
654 | if (strncmp(node->name, "nvcsi", 5)) { | ||
655 | node = of_find_node_by_name(node, "nvcsi"); | ||
656 | strncpy(csi->devname, "nvcsi", 6); | ||
657 | } | ||
658 | if (!node) | ||
659 | return -EINVAL; | ||
660 | err = of_property_read_u32(node, "num-channels", &num_channels); | ||
661 | if (err) { | ||
662 | dev_dbg(csi->dev, " Failed to find num of channels, set to 0\n"); | ||
663 | num_channels = 0; | ||
664 | } | ||
665 | |||
666 | csi->num_channels = num_channels; | ||
667 | for (i = 0; i < num_channels; i++) { | ||
668 | item = devm_kzalloc(csi->dev, sizeof(*item), GFP_KERNEL); | ||
669 | if (!item) | ||
670 | return -ENOMEM; | ||
671 | list_add_tail(&item->list, &csi->csi_chans); | ||
672 | item->csi = csi; | ||
673 | item->id = i; | ||
674 | err = tegra_csi_get_port_info(item, node, item->id); | ||
675 | if (err) | ||
676 | return err; | ||
677 | } | ||
678 | |||
679 | return 0; | ||
680 | } | ||
681 | |||
682 | int tpg_csi_media_controller_init(struct tegra_csi_device *csi, int pg_mode) | ||
683 | { | ||
684 | int i, err; | ||
685 | struct tegra_csi_channel *item; | ||
686 | |||
687 | if (!csi) | ||
688 | return -EINVAL; | ||
689 | for (i = 0; i < TPG_CHANNELS; i++) { | ||
690 | item = devm_kzalloc(csi->dev, sizeof(*item), GFP_KERNEL); | ||
691 | if (!item) { | ||
692 | err = -ENOMEM; | ||
693 | goto channel_init_error; | ||
694 | } | ||
695 | if (i == 0) | ||
696 | csi->tpg_start = item; | ||
697 | list_add_tail(&item->list, &csi->csi_chans); | ||
698 | item->numlanes = 2; | ||
699 | item->numports = 1; | ||
700 | item->csi = csi; | ||
701 | item->pg_mode = pg_mode; | ||
702 | item->id = csi->num_channels + i; | ||
703 | err = tegra_csi_channel_init_one(item); | ||
704 | if (err) | ||
705 | goto channel_init_error; | ||
706 | } | ||
707 | csi->fops->hw_init(csi); | ||
708 | csi->num_channels += TPG_CHANNELS; | ||
709 | |||
710 | return err; | ||
711 | |||
712 | channel_init_error: | ||
713 | if (csi->tpg_start) | ||
714 | tpg_csi_media_controller_cleanup(csi); | ||
715 | dev_err(csi->dev, "%s: Error\n", __func__); | ||
716 | return err; | ||
717 | } | ||
718 | EXPORT_SYMBOL(tpg_csi_media_controller_init); | ||
719 | |||
720 | void tpg_csi_media_controller_cleanup(struct tegra_csi_device *csi) | ||
721 | { | ||
722 | struct tegra_csi_channel *item; | ||
723 | struct tegra_csi_channel *itemn; | ||
724 | struct v4l2_subdev *sd; | ||
725 | |||
726 | list_for_each_entry_safe(item, itemn, &csi->csi_chans, list) { | ||
727 | if (!item->pg_mode) | ||
728 | continue; | ||
729 | sd = &item->subdev; | ||
730 | /* decrement media device entity count */ | ||
731 | if (sd->entity.parent) | ||
732 | sd->entity.parent->entity_id--; | ||
733 | v4l2_device_unregister_subdev(sd); | ||
734 | media_entity_cleanup(&sd->entity); | ||
735 | list_del(&item->list); | ||
736 | devm_kfree(csi->dev, item); | ||
737 | } | ||
738 | csi->num_channels -= TPG_CHANNELS; | ||
739 | csi->tpg_start = NULL; | ||
740 | } | ||
741 | EXPORT_SYMBOL(tpg_csi_media_controller_cleanup); | ||
742 | int tegra_csi_media_controller_init(struct tegra_csi_device *csi, | ||
743 | struct platform_device *pdev) | ||
744 | { | ||
745 | int ret; | ||
746 | |||
747 | csi->dev = &pdev->dev; | ||
748 | csi->pdev = pdev; | ||
749 | atomic_set(&csi->power_ref, 0); | ||
750 | atomic_set(&csi->tpg_enabled, 0); | ||
751 | INIT_LIST_HEAD(&csi->csi_chans); | ||
752 | ret = csi_parse_dt(csi, pdev); | ||
753 | if (ret < 0) | ||
754 | return ret; | ||
755 | |||
756 | /* | ||
757 | * if there is no csi channels listed in DT, | ||
758 | * no need to init the channel and graph | ||
759 | */ | ||
760 | if (csi->num_channels == 0) | ||
761 | return 0; | ||
762 | |||
763 | ret = tegra_csi_channels_init(csi); | ||
764 | ret = tegra_csi_init(csi, pdev); | ||
765 | if (ret < 0) | ||
766 | dev_err(&pdev->dev, "Failed to init csi property,clks\n"); | ||
767 | |||
768 | return 0; | ||
769 | } | ||
770 | EXPORT_SYMBOL(tegra_csi_media_controller_init); | ||
771 | |||
772 | int tegra_csi_media_controller_remove(struct tegra_csi_device *csi) | ||
773 | { | ||
774 | struct tegra_csi_channel *chan; | ||
775 | struct v4l2_subdev *sd; | ||
776 | |||
777 | list_for_each_entry(chan, &csi->csi_chans, list) { | ||
778 | sd = &chan->subdev; | ||
779 | v4l2_async_unregister_subdev(sd); | ||
780 | media_entity_cleanup(&sd->entity); | ||
781 | } | ||
782 | return 0; | ||
783 | } | ||
784 | EXPORT_SYMBOL(tegra_csi_media_controller_remove); | ||
diff --git a/drivers/media/platform/tegra/camera/csi/csi.h b/drivers/media/platform/tegra/camera/csi/csi.h new file mode 100644 index 000000000..208e15e42 --- /dev/null +++ b/drivers/media/platform/tegra/camera/csi/csi.h | |||
@@ -0,0 +1,158 @@ | |||
1 | /* | ||
2 | * NVIDIA Tegra CSI Device Header | ||
3 | * | ||
4 | * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * Author: Bryan Wu <pengw@nvidia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef __CSI_H_ | ||
14 | #define __CSI_H_ | ||
15 | |||
16 | #include <media/media-entity.h> | ||
17 | #include <media/v4l2-async.h> | ||
18 | #include <media/v4l2-ctrls.h> | ||
19 | #include <media/v4l2-subdev.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | |||
22 | #include <media/camera_common.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | |||
25 | #include "camera/vi/registers.h" | ||
26 | #include "camera/csi/csi4_registers.h" | ||
27 | |||
28 | #define MAX_CSI_BLOCK_LANES 4 | ||
29 | |||
30 | enum tegra_csi_port_num { | ||
31 | PORT_A = 0, | ||
32 | PORT_B = 1, | ||
33 | PORT_C = 2, | ||
34 | PORT_D = 3, | ||
35 | PORT_E = 4, | ||
36 | PORT_F = 5, | ||
37 | }; | ||
38 | |||
39 | #define csi_port_is_valid(port) (port > PORT_F ? 0 : 1) | ||
40 | |||
41 | enum camera_gang_mode { | ||
42 | CAMERA_NO_GANG_MODE = 0, | ||
43 | CAMERA_GANG_L_R = 1, | ||
44 | CAMERA_GANG_T_B, | ||
45 | CAMERA_GANG_R_L, | ||
46 | CAMERA_GANG_B_T | ||
47 | }; | ||
48 | |||
49 | struct tegra_channel; | ||
50 | |||
51 | struct tpg_frmfmt { | ||
52 | struct v4l2_frmsize_discrete frmsize; | ||
53 | int pixel_format; | ||
54 | int framerate; | ||
55 | int h_blank; | ||
56 | int v_blank; | ||
57 | }; | ||
58 | |||
59 | struct tegra_csi_port { | ||
60 | void __iomem *pixel_parser; | ||
61 | void __iomem *cil; | ||
62 | void __iomem *tpg; | ||
63 | |||
64 | /* One pair of sink/source pad has one format */ | ||
65 | struct v4l2_mbus_framefmt format; | ||
66 | const struct tegra_video_format *core_format; | ||
67 | unsigned int lanes; | ||
68 | unsigned int framerate; | ||
69 | unsigned int h_blank; | ||
70 | unsigned int v_blank; | ||
71 | |||
72 | enum tegra_csi_port_num num; | ||
73 | }; | ||
74 | |||
75 | struct tegra_csi_device { | ||
76 | struct device *dev; | ||
77 | struct platform_device *pdev; | ||
78 | char devname[32]; | ||
79 | void __iomem *iomem_base; | ||
80 | void __iomem *iomem[3]; | ||
81 | struct clk *plld_dsi; | ||
82 | struct clk *plld; | ||
83 | |||
84 | struct camera_common_data s_data[6]; | ||
85 | struct tegra_csi_port *ports; | ||
86 | struct media_pad *pads; | ||
87 | |||
88 | unsigned int clk_freq; | ||
89 | int num_ports; | ||
90 | int num_channels; | ||
91 | struct list_head csi_chans; | ||
92 | struct tegra_csi_channel *tpg_start; | ||
93 | struct tegra_csi_fops *fops; | ||
94 | const struct tpg_frmfmt *tpg_frmfmt_table; | ||
95 | unsigned int tpg_frmfmt_table_size; | ||
96 | atomic_t power_ref; | ||
97 | |||
98 | struct dentry *debugdir; | ||
99 | atomic_t tpg_enabled; | ||
100 | }; | ||
101 | |||
102 | /* | ||
103 | * subdev: channel subdev | ||
104 | * numports: Number of CSI ports in use for this channel | ||
105 | * numlanes: Number of CIL lanes in use | ||
106 | */ | ||
107 | struct tegra_csi_channel { | ||
108 | struct list_head list; | ||
109 | struct v4l2_subdev subdev; | ||
110 | struct media_pad *pads; | ||
111 | struct media_pipeline pipe; | ||
112 | |||
113 | struct tegra_csi_device *csi; | ||
114 | struct tegra_csi_port *ports; | ||
115 | unsigned char port[TEGRA_CSI_BLOCKS]; | ||
116 | struct mutex format_lock; | ||
117 | unsigned int numports; | ||
118 | unsigned int numlanes; | ||
119 | unsigned int pg_mode; | ||
120 | struct camera_common_data *s_data; | ||
121 | unsigned int id; | ||
122 | }; | ||
123 | |||
124 | static inline struct tegra_csi_channel *to_csi_chan(struct v4l2_subdev *subdev) | ||
125 | { | ||
126 | return container_of(subdev, struct tegra_csi_channel, subdev); | ||
127 | } | ||
128 | |||
129 | static inline struct tegra_csi_device *to_csi(struct v4l2_subdev *subdev) | ||
130 | { | ||
131 | struct tegra_csi_channel *chan = to_csi_chan(subdev); | ||
132 | |||
133 | return chan->csi; | ||
134 | } | ||
135 | |||
136 | void set_csi_portinfo(struct tegra_csi_device *csi, | ||
137 | unsigned int port, unsigned int numlanes); | ||
138 | void tegra_csi_status(struct tegra_csi_channel *chan, | ||
139 | enum tegra_csi_port_num port_num); | ||
140 | int tegra_csi_error(struct tegra_csi_channel *chan, | ||
141 | enum tegra_csi_port_num port_num); | ||
142 | int tegra_csi_start_streaming(struct tegra_csi_channel *chan, | ||
143 | enum tegra_csi_port_num port_num); | ||
144 | void tegra_csi_stop_streaming(struct tegra_csi_channel *chan, | ||
145 | enum tegra_csi_port_num port_num); | ||
146 | void tegra_csi_error_recover(struct tegra_csi_channel *chan, | ||
147 | enum tegra_csi_port_num port_num); | ||
148 | int tegra_csi_power(struct tegra_csi_device *csi, int enable); | ||
149 | #define tegra_csi_power_on(csi) tegra_csi_power(csi, 1) | ||
150 | #define tegra_csi_power_off(csi) tegra_csi_power(csi, 0) | ||
151 | int tegra_csi_init(struct tegra_csi_device *csi, | ||
152 | struct platform_device *pdev); | ||
153 | int tegra_csi_media_controller_init(struct tegra_csi_device *csi, | ||
154 | struct platform_device *pdev); | ||
155 | int tegra_csi_media_controller_remove(struct tegra_csi_device *csi); | ||
156 | int tpg_csi_media_controller_init(struct tegra_csi_device *csi, int pg_mode); | ||
157 | void tpg_csi_media_controller_cleanup(struct tegra_csi_device *csi); | ||
158 | #endif | ||
diff --git a/drivers/media/platform/tegra/camera/csi/csi2_fops.c b/drivers/media/platform/tegra/camera/csi/csi2_fops.c new file mode 100644 index 000000000..d633a6205 --- /dev/null +++ b/drivers/media/platform/tegra/camera/csi/csi2_fops.c | |||
@@ -0,0 +1,455 @@ | |||
1 | /* | ||
2 | * Tegra CSI2 device common APIs | ||
3 | * | ||
4 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * Author: Bryan Wu <pengw@nvidia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/device.h> | ||
14 | #include <linux/clk/tegra.h> | ||
15 | #include "camera/csi/csi.h" | ||
16 | #include "camera/vi/mc_common.h" | ||
17 | #include "mipical/mipi_cal.h" | ||
18 | #include "nvhost_acm.h" | ||
19 | #include <linux/clk/tegra.h> | ||
20 | |||
21 | static void csi_write(struct tegra_csi_channel *chan, unsigned int addr, | ||
22 | u32 val, u8 port) | ||
23 | { | ||
24 | struct tegra_csi_device *csi = chan->csi; | ||
25 | |||
26 | writel(val, (csi->iomem[port] + addr)); | ||
27 | } | ||
28 | |||
29 | static u32 csi_read(struct tegra_csi_channel *chan, unsigned int addr, | ||
30 | u8 port) | ||
31 | { | ||
32 | struct tegra_csi_device *csi = chan->csi; | ||
33 | |||
34 | return readl((csi->iomem[port] + addr)); | ||
35 | } | ||
36 | |||
37 | /* Pixel parser registers accessors */ | ||
38 | static void pp_write(struct tegra_csi_port *port, u32 addr, u32 val) | ||
39 | { | ||
40 | writel(val, port->pixel_parser + addr); | ||
41 | } | ||
42 | |||
43 | static u32 pp_read(struct tegra_csi_port *port, u32 addr) | ||
44 | { | ||
45 | return readl(port->pixel_parser + addr); | ||
46 | } | ||
47 | |||
48 | /* CSI CIL registers accessors */ | ||
49 | static void cil_write(struct tegra_csi_port *port, u32 addr, u32 val) | ||
50 | { | ||
51 | writel(val, port->cil + addr); | ||
52 | } | ||
53 | |||
54 | static u32 cil_read(struct tegra_csi_port *port, u32 addr) | ||
55 | { | ||
56 | return readl(port->cil + addr); | ||
57 | } | ||
58 | |||
59 | /* Test pattern generator registers accessor */ | ||
60 | static void tpg_write(struct tegra_csi_port *port, | ||
61 | unsigned int addr, u32 val) | ||
62 | { | ||
63 | writel(val, port->tpg + addr); | ||
64 | } | ||
65 | |||
66 | int tegra_csi_error(struct tegra_csi_channel *chan, | ||
67 | enum tegra_csi_port_num port_num) | ||
68 | { | ||
69 | struct tegra_csi_port *port; | ||
70 | u32 val; | ||
71 | int err = 0; | ||
72 | |||
73 | port = &chan->ports[port_num]; | ||
74 | /* | ||
75 | * only uncorrectable header error and multi-bit | ||
76 | * transmission errors are checked as they cannot be | ||
77 | * corrected automatically | ||
78 | */ | ||
79 | val = pp_read(port, TEGRA_CSI_PIXEL_PARSER_STATUS); | ||
80 | err |= val & 0x4000; | ||
81 | pp_write(port, TEGRA_CSI_PIXEL_PARSER_STATUS, val); | ||
82 | |||
83 | val = cil_read(port, TEGRA_CSI_CIL_STATUS); | ||
84 | err |= val & 0x02; | ||
85 | cil_write(port, TEGRA_CSI_CIL_STATUS, val); | ||
86 | |||
87 | val = cil_read(port, TEGRA_CSI_CILX_STATUS); | ||
88 | err |= val & 0x00020020; | ||
89 | cil_write(port, TEGRA_CSI_CILX_STATUS, val); | ||
90 | |||
91 | return err; | ||
92 | } | ||
93 | |||
94 | void tegra_csi_status(struct tegra_csi_channel *chan, | ||
95 | enum tegra_csi_port_num port_num) | ||
96 | { | ||
97 | int i; | ||
98 | u32 val; | ||
99 | struct tegra_csi_port *port; | ||
100 | |||
101 | for (i = 0; i < chan->numports; i++) { | ||
102 | port = &chan->ports[i]; | ||
103 | val = pp_read(port, TEGRA_CSI_PIXEL_PARSER_STATUS); | ||
104 | |||
105 | dev_dbg(chan->csi->dev, | ||
106 | "TEGRA_CSI_PIXEL_PARSER_STATUS 0x%08x\n", | ||
107 | val); | ||
108 | |||
109 | val = cil_read(port, TEGRA_CSI_CIL_STATUS); | ||
110 | dev_dbg(chan->csi->dev, | ||
111 | "TEGRA_CSI_CIL_STATUS 0x%08x\n", val); | ||
112 | |||
113 | val = cil_read(port, TEGRA_CSI_CILX_STATUS); | ||
114 | dev_dbg(chan->csi->dev, | ||
115 | "TEGRA_CSI_CILX_STATUS 0x%08x\n", val); | ||
116 | } | ||
117 | } | ||
118 | EXPORT_SYMBOL(tegra_csi_status); | ||
119 | |||
120 | void tegra_csi_error_recover(struct tegra_csi_channel *chan, | ||
121 | enum tegra_csi_port_num port_num) | ||
122 | { | ||
123 | struct tegra_csi_port *port; | ||
124 | struct tegra_csi_device *csi; | ||
125 | int i; | ||
126 | |||
127 | csi = chan->csi; | ||
128 | |||
129 | for (i = 0; i < chan->numports; i++) { | ||
130 | port = &chan->ports[i]; | ||
131 | |||
132 | if (port->lanes == 4) { | ||
133 | int port_val = ((port_num >> 1) << 1); | ||
134 | struct tegra_csi_port *port_a = | ||
135 | &chan->ports[port_val]; | ||
136 | struct tegra_csi_port *port_b = | ||
137 | &chan->ports[port_val+1]; | ||
138 | |||
139 | tpg_write(port_a, | ||
140 | TEGRA_CSI_PATTERN_GENERATOR_CTRL, PG_ENABLE); | ||
141 | tpg_write(port_b, | ||
142 | TEGRA_CSI_PATTERN_GENERATOR_CTRL, PG_ENABLE); | ||
143 | cil_write(port_a, | ||
144 | TEGRA_CSI_CIL_SW_SENSOR_RESET, 0x1); | ||
145 | cil_write(port_b, | ||
146 | TEGRA_CSI_CIL_SW_SENSOR_RESET, 0x1); | ||
147 | csi_write(chan, TEGRA_CSI_CSI_SW_STATUS_RESET, 0x1, | ||
148 | port_num >> 1); | ||
149 | /* sleep for clock cycles to drain the Rx FIFO */ | ||
150 | usleep_range(10, 20); | ||
151 | cil_write(port_a, | ||
152 | TEGRA_CSI_CIL_SW_SENSOR_RESET, 0x0); | ||
153 | cil_write(port_b, | ||
154 | TEGRA_CSI_CIL_SW_SENSOR_RESET, 0x0); | ||
155 | csi_write(chan, | ||
156 | TEGRA_CSI_CSI_SW_STATUS_RESET, | ||
157 | 0x0, port_num >> 1); | ||
158 | tpg_write(port_a, | ||
159 | TEGRA_CSI_PATTERN_GENERATOR_CTRL, PG_DISABLE); | ||
160 | tpg_write(port_b, | ||
161 | TEGRA_CSI_PATTERN_GENERATOR_CTRL, PG_DISABLE); | ||
162 | } else { | ||
163 | tpg_write(port, | ||
164 | TEGRA_CSI_PATTERN_GENERATOR_CTRL, PG_ENABLE); | ||
165 | cil_write(port, | ||
166 | TEGRA_CSI_CIL_SW_SENSOR_RESET, 0x1); | ||
167 | csi_write(chan, | ||
168 | TEGRA_CSI_CSI_SW_STATUS_RESET, | ||
169 | 0x1, port_num >> 1); | ||
170 | /* sleep for clock cycles to drain the Rx FIFO */ | ||
171 | usleep_range(10, 20); | ||
172 | cil_write(port, | ||
173 | TEGRA_CSI_CIL_SW_SENSOR_RESET, 0x0); | ||
174 | csi_write(chan, | ||
175 | TEGRA_CSI_CSI_SW_STATUS_RESET, | ||
176 | 0x0, port_num >> 1); | ||
177 | tpg_write(port, | ||
178 | TEGRA_CSI_PATTERN_GENERATOR_CTRL, PG_DISABLE); | ||
179 | } | ||
180 | } | ||
181 | } | ||
182 | |||
183 | |||
184 | static int tpg_clk_enable(struct tegra_csi_device *csi) | ||
185 | { | ||
186 | int err = 0; | ||
187 | |||
188 | if (atomic_inc_return(&csi->tpg_enabled) != 1) | ||
189 | return 0; | ||
190 | |||
191 | clk_set_rate(csi->plld, TEGRA_CLOCK_TPG); | ||
192 | err = clk_prepare_enable(csi->plld); | ||
193 | if (err) { | ||
194 | dev_err(csi->dev, "pll_d enable failed"); | ||
195 | return err; | ||
196 | } | ||
197 | |||
198 | err = clk_prepare_enable(csi->plld_dsi); | ||
199 | if (err) { | ||
200 | dev_err(csi->dev, "pll_d enable failed"); | ||
201 | goto plld_dsi_err; | ||
202 | } | ||
203 | tegra210_csi_source_from_plld(); | ||
204 | return err; | ||
205 | plld_dsi_err: | ||
206 | clk_disable_unprepare(csi->plld); | ||
207 | return err; | ||
208 | } | ||
209 | |||
210 | static int tpg_clk_disable(struct tegra_csi_device *csi) | ||
211 | { | ||
212 | int err = 0; | ||
213 | |||
214 | if (!atomic_dec_and_test(&csi->tpg_enabled)) | ||
215 | return 0; | ||
216 | tegra210_csi_source_from_brick(); | ||
217 | clk_disable_unprepare(csi->plld_dsi); | ||
218 | clk_disable_unprepare(csi->plld); | ||
219 | |||
220 | return err; | ||
221 | } | ||
222 | |||
223 | static int csi2_tpg_start_streaming(struct tegra_csi_channel *chan, | ||
224 | enum tegra_csi_port_num port_num) | ||
225 | { | ||
226 | struct tegra_csi_port *port = &chan->ports[port_num]; | ||
227 | |||
228 | tpg_write(port, TEGRA_CSI_PATTERN_GENERATOR_CTRL, | ||
229 | ((chan->pg_mode - 1) << PG_MODE_OFFSET) | | ||
230 | PG_ENABLE); | ||
231 | tpg_write(port, TEGRA_CSI_PG_BLANK, | ||
232 | port->v_blank << PG_VBLANK_OFFSET | | ||
233 | port->h_blank); | ||
234 | tpg_write(port, TEGRA_CSI_PG_PHASE, 0x0); | ||
235 | tpg_write(port, TEGRA_CSI_PG_RED_FREQ, | ||
236 | (0x10 << PG_RED_VERT_INIT_FREQ_OFFSET) | | ||
237 | (0x10 << PG_RED_HOR_INIT_FREQ_OFFSET)); | ||
238 | tpg_write(port, TEGRA_CSI_PG_RED_FREQ_RATE, 0x0); | ||
239 | tpg_write(port, TEGRA_CSI_PG_GREEN_FREQ, | ||
240 | (0x10 << PG_GREEN_VERT_INIT_FREQ_OFFSET) | | ||
241 | (0x10 << PG_GREEN_HOR_INIT_FREQ_OFFSET)); | ||
242 | tpg_write(port, TEGRA_CSI_PG_GREEN_FREQ_RATE, 0x0); | ||
243 | tpg_write(port, TEGRA_CSI_PG_BLUE_FREQ, | ||
244 | (0x10 << PG_BLUE_VERT_INIT_FREQ_OFFSET) | | ||
245 | (0x10 << PG_BLUE_HOR_INIT_FREQ_OFFSET)); | ||
246 | tpg_write(port, TEGRA_CSI_PG_BLUE_FREQ_RATE, 0x0); | ||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | int csi2_start_streaming(struct tegra_csi_channel *chan, | ||
251 | enum tegra_csi_port_num port_num) | ||
252 | { | ||
253 | struct tegra_csi_port *port = &chan->ports[port_num]; | ||
254 | int csi_port, csi_lanes; | ||
255 | |||
256 | csi_port = chan->ports[port_num].num; | ||
257 | csi_lanes = chan->ports[port_num].lanes; | ||
258 | |||
259 | csi_write(chan, TEGRA_CSI_CLKEN_OVERRIDE, 0, csi_port >> 1); | ||
260 | |||
261 | /* Clean up status */ | ||
262 | pp_write(port, TEGRA_CSI_PIXEL_PARSER_STATUS, 0xFFFFFFFF); | ||
263 | cil_write(port, TEGRA_CSI_CIL_STATUS, 0xFFFFFFFF); | ||
264 | cil_write(port, TEGRA_CSI_CILX_STATUS, 0xFFFFFFFF); | ||
265 | |||
266 | cil_write(port, TEGRA_CSI_CIL_INTERRUPT_MASK, 0x0); | ||
267 | |||
268 | /* CIL PHY registers setup */ | ||
269 | cil_write(port, TEGRA_CSI_CIL_PAD_CONFIG0, 0x0); | ||
270 | cil_write(port, TEGRA_CSI_CIL_PHY_CONTROL, | ||
271 | BYPASS_LP_SEQ | 0xA); | ||
272 | |||
273 | /* | ||
274 | * The CSI unit provides for connection of up to six cameras in | ||
275 | * the system and is organized as three identical instances of | ||
276 | * two MIPI support blocks, each with a separate 4-lane | ||
277 | * interface that can be configured as a single camera with 4 | ||
278 | * lanes or as a dual camera with 2 lanes available for each | ||
279 | * camera. | ||
280 | */ | ||
281 | if (csi_lanes == 4) { | ||
282 | unsigned int cilb_offset; | ||
283 | |||
284 | cilb_offset = TEGRA_CSI_CIL_OFFSET + TEGRA_CSI_PORT_OFFSET; | ||
285 | |||
286 | cil_write(port, TEGRA_CSI_CIL_PAD_CONFIG0, | ||
287 | BRICK_CLOCK_A_4X); | ||
288 | csi_write(chan, cilb_offset + TEGRA_CSI_CIL_PAD_CONFIG0, 0x0, | ||
289 | csi_port >> 1); | ||
290 | csi_write(chan, cilb_offset + TEGRA_CSI_CIL_INTERRUPT_MASK, 0x0, | ||
291 | csi_port >> 1); | ||
292 | cil_write(port, TEGRA_CSI_CIL_PHY_CONTROL, | ||
293 | BYPASS_LP_SEQ | 0xA); | ||
294 | csi_write(chan, cilb_offset + TEGRA_CSI_CIL_PHY_CONTROL, | ||
295 | BYPASS_LP_SEQ | 0xA, csi_port >> 1); | ||
296 | csi_write(chan, TEGRA_CSI_PHY_CIL_COMMAND, | ||
297 | CSI_A_PHY_CIL_ENABLE | CSI_B_PHY_CIL_ENABLE, | ||
298 | csi_port >> 1); | ||
299 | } else { | ||
300 | u32 val = csi_read(chan, TEGRA_CSI_PHY_CIL_COMMAND, | ||
301 | csi_port >> 1); | ||
302 | |||
303 | csi_write(chan, | ||
304 | TEGRA_CSI_CIL_OFFSET + TEGRA_CSI_CIL_PAD_CONFIG0, 0x0, | ||
305 | csi_port >> 1); | ||
306 | val |= ((csi_port & 0x1) == PORT_A) ? CSI_A_PHY_CIL_ENABLE : | ||
307 | CSI_B_PHY_CIL_ENABLE; | ||
308 | csi_write(chan, TEGRA_CSI_PHY_CIL_COMMAND, val, | ||
309 | csi_port >> 1); | ||
310 | } | ||
311 | /* CSI pixel parser registers setup */ | ||
312 | pp_write(port, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND, | ||
313 | (0xF << CSI_PP_START_MARKER_FRAME_MAX_OFFSET) | | ||
314 | CSI_PP_SINGLE_SHOT_ENABLE | CSI_PP_RST); | ||
315 | pp_write(port, TEGRA_CSI_PIXEL_PARSER_INTERRUPT_MASK, 0x0); | ||
316 | pp_write(port, TEGRA_CSI_PIXEL_STREAM_CONTROL0, | ||
317 | CSI_PP_PACKET_HEADER_SENT | | ||
318 | CSI_PP_DATA_IDENTIFIER_ENABLE | | ||
319 | CSI_PP_WORD_COUNT_SELECT_HEADER | | ||
320 | CSI_PP_CRC_CHECK_ENABLE | CSI_PP_WC_CHECK | | ||
321 | CSI_PP_OUTPUT_FORMAT_STORE | CSI_PPA_PAD_LINE_NOPAD | | ||
322 | CSI_PP_HEADER_EC_DISABLE | CSI_PPA_PAD_FRAME_NOPAD | | ||
323 | (csi_port & 1)); | ||
324 | pp_write(port, TEGRA_CSI_PIXEL_STREAM_CONTROL1, | ||
325 | (0x1 << CSI_PP_TOP_FIELD_FRAME_OFFSET) | | ||
326 | (0x1 << CSI_PP_TOP_FIELD_FRAME_MASK_OFFSET)); | ||
327 | pp_write(port, TEGRA_CSI_PIXEL_STREAM_GAP, | ||
328 | 0x14 << PP_FRAME_MIN_GAP_OFFSET); | ||
329 | pp_write(port, TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME, 0x0); | ||
330 | pp_write(port, TEGRA_CSI_INPUT_STREAM_CONTROL, | ||
331 | (0x3f << CSI_SKIP_PACKET_THRESHOLD_OFFSET) | | ||
332 | (csi_lanes - 1)); | ||
333 | |||
334 | if (chan->pg_mode) { | ||
335 | tpg_clk_enable(chan->csi); | ||
336 | csi2_tpg_start_streaming(chan, port_num); | ||
337 | } | ||
338 | |||
339 | pp_write(port, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND, | ||
340 | (0xF << CSI_PP_START_MARKER_FRAME_MAX_OFFSET) | | ||
341 | CSI_PP_SINGLE_SHOT_ENABLE | CSI_PP_ENABLE); | ||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | void csi2_stop_streaming(struct tegra_csi_channel *chan, | ||
346 | enum tegra_csi_port_num port_num) | ||
347 | { | ||
348 | struct tegra_csi_port *port = &chan->ports[port_num]; | ||
349 | |||
350 | |||
351 | if (chan->pg_mode) { | ||
352 | tpg_write(port, TEGRA_CSI_PATTERN_GENERATOR_CTRL, PG_DISABLE); | ||
353 | tpg_clk_disable(chan->csi); | ||
354 | } | ||
355 | if (!port) { | ||
356 | pr_err("%s:no port\n", __func__); | ||
357 | return; | ||
358 | } | ||
359 | pp_write(port, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND, | ||
360 | (0xF << CSI_PP_START_MARKER_FRAME_MAX_OFFSET) | | ||
361 | CSI_PP_DISABLE); | ||
362 | } | ||
363 | |||
364 | int csi2_hw_init(struct tegra_csi_device *csi) | ||
365 | { | ||
366 | int i, csi_port; | ||
367 | struct tegra_csi_channel *it; | ||
368 | struct tegra_csi_port *port; | ||
369 | |||
370 | csi->iomem[0] = (csi->iomem_base + TEGRA_CSI_PIXEL_PARSER_0_BASE); | ||
371 | csi->iomem[1] = (csi->iomem_base + TEGRA_CSI_PIXEL_PARSER_2_BASE); | ||
372 | csi->iomem[2] = (csi->iomem_base + TEGRA_CSI_PIXEL_PARSER_4_BASE); | ||
373 | list_for_each_entry(it, &csi->csi_chans, list) { | ||
374 | for (i = 0; i < it->numports; i++) { | ||
375 | port = &it->ports[i]; | ||
376 | csi_port = it->ports[i].num; | ||
377 | port->pixel_parser = csi->iomem[csi_port >> 1] + | ||
378 | (csi_port % 2) * TEGRA_CSI_PORT_OFFSET; | ||
379 | port->cil = port->pixel_parser + TEGRA_CSI_CIL_OFFSET; | ||
380 | port->tpg = port->pixel_parser + TEGRA_CSI_TPG_OFFSET; | ||
381 | } | ||
382 | } | ||
383 | csi->plld = devm_clk_get(csi->dev, "pll_d"); | ||
384 | if (IS_ERR(csi->plld)) { | ||
385 | dev_err(csi->dev, "Fail to get pll_d\n"); | ||
386 | return PTR_ERR(csi->plld); | ||
387 | } | ||
388 | csi->plld_dsi = devm_clk_get(csi->dev, "pll_d_dsi_out"); | ||
389 | if (IS_ERR(csi->plld_dsi)) { | ||
390 | dev_err(csi->dev, "Fail to get pll_d_dsi_out\n"); | ||
391 | return PTR_ERR(csi->plld_dsi); | ||
392 | } | ||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | int csi2_mipi_cal(struct tegra_csi_channel *chan) | ||
397 | { | ||
398 | unsigned int lanes, num_ports, val, csi_port; | ||
399 | struct tegra_csi_port *port; | ||
400 | struct tegra_csi_device *csi = chan->csi; | ||
401 | |||
402 | lanes = 0; | ||
403 | num_ports = 0; | ||
404 | |||
405 | nvhost_module_enable_clk(csi->dev); | ||
406 | while (num_ports < chan->numports) { | ||
407 | port = &chan->ports[num_ports]; | ||
408 | csi_port = port->num; | ||
409 | dev_dbg(csi->dev, "Calibrate csi port %d\n", port->num); | ||
410 | |||
411 | if (chan->numlanes == 2) { | ||
412 | lanes |= CSIA << csi_port; | ||
413 | val = csi_read(chan, TEGRA_CSI_PHY_CIL_COMMAND, | ||
414 | csi_port >> 1); | ||
415 | csi_write(chan, | ||
416 | TEGRA_CSI_CIL_OFFSET + | ||
417 | TEGRA_CSI_CIL_PAD_CONFIG0, 0x0, csi_port >> 1); | ||
418 | val |= ((csi_port & 0x1) == PORT_A) ? | ||
419 | CSI_A_PHY_CIL_ENABLE : CSI_B_PHY_CIL_ENABLE; | ||
420 | csi_write(chan, TEGRA_CSI_PHY_CIL_COMMAND, val, | ||
421 | csi_port >> 1); | ||
422 | } else { | ||
423 | lanes |= (CSIA | CSIB) << port->num; | ||
424 | csi_write(chan, TEGRA_CSI_PHY_CIL_COMMAND, | ||
425 | CSI_A_PHY_CIL_ENABLE | CSI_B_PHY_CIL_ENABLE, | ||
426 | csi_port >> 1); | ||
427 | } | ||
428 | num_ports++; | ||
429 | } | ||
430 | if (!lanes) { | ||
431 | dev_err(csi->dev, | ||
432 | "Selected no CSI lane, cannot do calibration"); | ||
433 | return -EINVAL; | ||
434 | } | ||
435 | nvhost_module_disable_clk(csi->dev); | ||
436 | return tegra_mipi_calibration(lanes); | ||
437 | } | ||
438 | |||
439 | int csi2_power_on(struct tegra_csi_device *csi) | ||
440 | { | ||
441 | return 0; | ||
442 | } | ||
443 | int csi2_power_off(struct tegra_csi_device *csi) | ||
444 | { | ||
445 | return 0; | ||
446 | } | ||
447 | const struct tegra_csi_fops csi2_fops = { | ||
448 | .csi_power_on = csi2_power_on, | ||
449 | .csi_power_off = csi2_power_off, | ||
450 | .csi_start_streaming = csi2_start_streaming, | ||
451 | .csi_stop_streaming = csi2_stop_streaming, | ||
452 | .mipical = csi2_mipi_cal, | ||
453 | .hw_init = csi2_hw_init, | ||
454 | }; | ||
455 | EXPORT_SYMBOL(csi2_fops); | ||
diff --git a/drivers/media/platform/tegra/camera/csi/csi2_fops.h b/drivers/media/platform/tegra/camera/csi/csi2_fops.h new file mode 100644 index 000000000..7b801e777 --- /dev/null +++ b/drivers/media/platform/tegra/camera/csi/csi2_fops.h | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * Tegra CSI2 device common APIs | ||
3 | * | ||
4 | * Tegra Graphics Host VI | ||
5 | * | ||
6 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. | ||
7 | * | ||
8 | * Author: Bryan Wu <pengw@nvidia.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #ifndef __CSI2_H__ | ||
16 | #define __CSI2_H__ | ||
17 | |||
18 | #include "csi.h" | ||
19 | |||
20 | int csi2_start_streaming(struct tegra_csi_channel *chan, | ||
21 | enum tegra_csi_port_num port_num); | ||
22 | void csi2_stop_streaming(struct tegra_csi_channel *chan, | ||
23 | enum tegra_csi_port_num port_num); | ||
24 | |||
25 | extern struct tegra_csi_fops csi2_fops; | ||
26 | |||
27 | #endif | ||
diff --git a/drivers/media/platform/tegra/camera/csi/csi4_fops.c b/drivers/media/platform/tegra/camera/csi/csi4_fops.c new file mode 100644 index 000000000..6fd28156e --- /dev/null +++ b/drivers/media/platform/tegra/camera/csi/csi4_fops.c | |||
@@ -0,0 +1,506 @@ | |||
1 | /* | ||
2 | * Tegra CSI4 device common APIs | ||
3 | * | ||
4 | * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * Author: Frank Chen <frankc@nvidia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #include <linux/clk/tegra.h> | ||
13 | #include "nvhost_acm.h" | ||
14 | #include "camera/csi/csi.h" | ||
15 | #include "camera/csi/csi4_registers.h" | ||
16 | #include "camera/vi/core.h" | ||
17 | #include "mipical/mipi_cal.h" | ||
18 | #include "nvcsi/nvcsi.h" | ||
19 | |||
20 | static void csi4_stream_write(struct tegra_csi_channel *chan, | ||
21 | unsigned int index, unsigned int addr, u32 val) | ||
22 | { | ||
23 | struct tegra_csi_device *csi = chan->csi; | ||
24 | u32 cilb_offset = (index & 0x1) ? CSI4_STREAM_OFFSET : 0x0; | ||
25 | |||
26 | writel(val, csi->iomem[index >> 1] + cilb_offset + addr); | ||
27 | } | ||
28 | |||
29 | static u32 csi4_stream_read(struct tegra_csi_channel *chan, | ||
30 | unsigned int index, unsigned int addr) | ||
31 | { | ||
32 | struct tegra_csi_device *csi = chan->csi; | ||
33 | u32 cilb_offset = (index & 0x1) ? CSI4_STREAM_OFFSET : 0x0; | ||
34 | |||
35 | return readl(csi->iomem[index >> 1] + cilb_offset + addr); | ||
36 | } | ||
37 | |||
38 | static void csi4_phy_write(struct tegra_csi_channel *chan, | ||
39 | unsigned int index, unsigned int addr, u32 val) | ||
40 | { | ||
41 | struct tegra_csi_device *csi = chan->csi; | ||
42 | |||
43 | writel(val, csi->iomem_base + | ||
44 | CSI4_BASE_ADDRESS + (CSI4_PHY_OFFSET * index) + addr); | ||
45 | } | ||
46 | |||
47 | static u32 csi4_phy_read(struct tegra_csi_channel *chan, | ||
48 | unsigned int index, unsigned int addr) | ||
49 | { | ||
50 | struct tegra_csi_device *csi = chan->csi; | ||
51 | |||
52 | return readl(csi->iomem_base + | ||
53 | CSI4_BASE_ADDRESS + (CSI4_PHY_OFFSET * index) + addr); | ||
54 | } | ||
55 | |||
56 | static void csi4_stream_init(struct tegra_csi_channel *chan, int port_num) | ||
57 | { | ||
58 | struct tegra_csi_device *csi = chan->csi; | ||
59 | |||
60 | dev_dbg(csi->dev, "%s\n", __func__); | ||
61 | |||
62 | csi4_stream_write(chan, port_num, CIL_INTR_STATUS, 0xffffffff); | ||
63 | csi4_stream_write(chan, port_num, CIL_ERR_INTR_STATUS, 0xffffffff); | ||
64 | csi4_stream_write(chan, port_num, CIL_INTR_MASK, 0xffffffff); | ||
65 | csi4_stream_write(chan, port_num, CIL_ERR_INTR_MASK, 0xffffffff); | ||
66 | csi4_stream_write(chan, port_num, INTR_STATUS, 0x3ffff); | ||
67 | csi4_stream_write(chan, port_num, ERR_INTR_STATUS, 0x7ffff); | ||
68 | csi4_stream_write(chan, port_num, ERROR_STATUS2VI_MASK, 0x0); | ||
69 | csi4_stream_write(chan, port_num, INTR_MASK, 0x0); | ||
70 | csi4_stream_write(chan, port_num, ERR_INTR_MASK, 0x0); | ||
71 | } | ||
72 | |||
73 | static void csi4_stream_config(struct tegra_csi_channel *chan, int port_num) | ||
74 | { | ||
75 | struct tegra_csi_device *csi = chan->csi; | ||
76 | int val; | ||
77 | |||
78 | dev_dbg(csi->dev, "%s\n", __func__); | ||
79 | |||
80 | csi4_stream_write(chan, port_num, PPFSM_TIMEOUT_CTRL, 0); | ||
81 | csi4_stream_write(chan, port_num, PH_CHK_CTRL, | ||
82 | CFG_PH_CRC_CHK_EN | CFG_PH_ECC_CHK_EN); | ||
83 | csi4_stream_write(chan, port_num, VC0_DPCM_CTRL, 0); | ||
84 | csi4_stream_write(chan, port_num, VC0_DT_OVERRIDE, 0); | ||
85 | |||
86 | val = csi4_stream_read(chan, port_num, VC0_DPCM_CTRL); | ||
87 | dev_dbg(csi->dev, "%s (%d) read VC0_DPCM_CTRL = %08x\n", | ||
88 | __func__, port_num, val); | ||
89 | } | ||
90 | |||
91 | |||
92 | static void csi4_phy_config( | ||
93 | struct tegra_csi_channel *chan, int csi_port, | ||
94 | int csi_lanes, bool enable) | ||
95 | { | ||
96 | struct tegra_csi_device *csi = chan->csi; | ||
97 | int phy_num = (csi_port & 0x6) >> 1; | ||
98 | bool cil_a = (csi_port & 0x1) ? false : true; | ||
99 | int cil_config; | ||
100 | |||
101 | dev_dbg(csi->dev, "%s\n", __func__); | ||
102 | |||
103 | /* set to DPHY */ | ||
104 | csi4_phy_write(chan, phy_num, NVCSI_CIL_PHY_CTRL, DPHY); | ||
105 | |||
106 | /* read current NVCSI_CIL_CONFIG setting */ | ||
107 | cil_config = csi4_phy_read(chan, phy_num, NVCSI_CIL_CONFIG); | ||
108 | dev_dbg(csi->dev, "NVCSI_CIL_CONFIG = %08x\n", cil_config); | ||
109 | |||
110 | if (cil_a) { | ||
111 | /* soft reset for data lane */ | ||
112 | csi4_phy_write(chan, phy_num, NVCSI_CIL_A_SW_RESET, | ||
113 | SW_RESET1_EN | SW_RESET0_EN); | ||
114 | /* reset CSI lane number */ | ||
115 | csi4_phy_write(chan, phy_num, NVCSI_CIL_CONFIG, | ||
116 | cil_config & ~DATA_LANE_A); | ||
117 | /* disable clock lane*/ | ||
118 | csi4_phy_write(chan, phy_num, | ||
119 | NVCSI_CIL_A_PAD_CONFIG, | ||
120 | PD_CLK | PD_IO0 | PD_IO1 | SPARE_IO0 | SPARE_IO1); | ||
121 | |||
122 | /* setting up CIL B for 4 lane */ | ||
123 | if (csi_lanes > 2) { | ||
124 | /* soft reset for data lane */ | ||
125 | csi4_phy_write(chan, phy_num, NVCSI_CIL_B_SW_RESET, | ||
126 | SW_RESET1_EN | SW_RESET0_EN); | ||
127 | /* reset CSI lane number */ | ||
128 | csi4_phy_write(chan, phy_num, NVCSI_CIL_CONFIG, | ||
129 | cil_config & ~DATA_LANE_B); | ||
130 | /* disable clock lane*/ | ||
131 | csi4_phy_write(chan, phy_num, | ||
132 | NVCSI_CIL_B_PAD_CONFIG, | ||
133 | PD_CLK | PD_IO0 | PD_IO1 | | ||
134 | SPARE_IO0 | SPARE_IO1); | ||
135 | } | ||
136 | |||
137 | /* power down de-serializer is CIL B is not in use*/ | ||
138 | if ((cil_config & DATA_LANE_B) == 0) | ||
139 | csi4_phy_write(chan, phy_num, | ||
140 | NVCSI_CIL_PAD_CONFIG, PDVCLAMP); | ||
141 | } else { | ||
142 | /* soft reset for data lane */ | ||
143 | csi4_phy_write(chan, phy_num, NVCSI_CIL_B_SW_RESET, | ||
144 | SW_RESET1_EN | SW_RESET0_EN); | ||
145 | /* reset CSI lane number */ | ||
146 | csi4_phy_write(chan, phy_num, NVCSI_CIL_CONFIG, | ||
147 | cil_config & ~DATA_LANE_B); | ||
148 | /* disable clock lane*/ | ||
149 | csi4_phy_write(chan, phy_num, | ||
150 | NVCSI_CIL_B_PAD_CONFIG, | ||
151 | PD_CLK | PD_IO0 | PD_IO1 | SPARE_IO0 | SPARE_IO1); | ||
152 | |||
153 | /* power down de-serializer if CIL A is not in use*/ | ||
154 | if ((cil_config & DATA_LANE_A) == 0) | ||
155 | csi4_phy_write(chan, phy_num, | ||
156 | NVCSI_CIL_PAD_CONFIG, PDVCLAMP); | ||
157 | } | ||
158 | |||
159 | if (!enable) | ||
160 | return; | ||
161 | |||
162 | /* power on de-serializer */ | ||
163 | csi4_phy_write(chan, phy_num, NVCSI_CIL_PAD_CONFIG, 0); | ||
164 | |||
165 | if (cil_a) { | ||
166 | /* set CSI lane number */ | ||
167 | csi4_phy_write(chan, phy_num, NVCSI_CIL_CONFIG, | ||
168 | (cil_config & ~DATA_LANE_A) | | ||
169 | (csi_lanes << DATA_LANE_A_OFFSET)); | ||
170 | /* enable clock lane*/ | ||
171 | csi4_phy_write(chan, phy_num, | ||
172 | NVCSI_CIL_A_PAD_CONFIG, | ||
173 | E_INPUT_LP_CLK | E_INPUT_LP_IO0 | E_INPUT_LP_IO1); | ||
174 | /* setup settle time */ | ||
175 | csi4_phy_write(chan, phy_num, | ||
176 | NVCSI_CIL_A_CONTROL, | ||
177 | DEFAULT_DESKEW_COMPARE | DEFAULT_DESKEW_SETTLE | | ||
178 | DEFAULT_CLK_SETTLE | | ||
179 | T18X_BYPASS_LP_SEQ | DEFAULT_THS_SETTLE); | ||
180 | /* release soft reset */ | ||
181 | csi4_phy_write(chan, phy_num, NVCSI_CIL_A_SW_RESET, 0x0); | ||
182 | |||
183 | /* setting up CIL B for 4 lane */ | ||
184 | if (csi_lanes > 2) { | ||
185 | /* set CSI lane number */ | ||
186 | csi4_phy_write(chan, phy_num, NVCSI_CIL_CONFIG, | ||
187 | csi_lanes << DATA_LANE_A_OFFSET); | ||
188 | /* enable clock lane*/ | ||
189 | csi4_phy_write(chan, phy_num, | ||
190 | NVCSI_CIL_B_PAD_CONFIG, | ||
191 | E_INPUT_LP_IO0 | E_INPUT_LP_IO1 | PD_CLK); | ||
192 | /* setup settle time */ | ||
193 | csi4_phy_write(chan, phy_num, | ||
194 | NVCSI_CIL_B_CONTROL, | ||
195 | DEFAULT_DESKEW_COMPARE | DEFAULT_DESKEW_SETTLE | ||
196 | | DEFAULT_CLK_SETTLE | | ||
197 | T18X_BYPASS_LP_SEQ | DEFAULT_THS_SETTLE); | ||
198 | /* release soft reset */ | ||
199 | csi4_phy_write(chan, phy_num, | ||
200 | NVCSI_CIL_B_SW_RESET, 0x0); | ||
201 | } | ||
202 | } else { | ||
203 | /* set CSI lane number */ | ||
204 | csi4_phy_write(chan, phy_num, NVCSI_CIL_CONFIG, | ||
205 | (cil_config & ~DATA_LANE_B) | | ||
206 | (csi_lanes << DATA_LANE_B_OFFSET)); | ||
207 | /* enable clock lane*/ | ||
208 | csi4_phy_write(chan, phy_num, | ||
209 | NVCSI_CIL_B_PAD_CONFIG, | ||
210 | E_INPUT_LP_CLK | E_INPUT_LP_IO0 | E_INPUT_LP_IO1); | ||
211 | /* setup settle time */ | ||
212 | csi4_phy_write(chan, phy_num, | ||
213 | NVCSI_CIL_B_CONTROL, | ||
214 | DEFAULT_DESKEW_COMPARE | DEFAULT_DESKEW_SETTLE | | ||
215 | DEFAULT_CLK_SETTLE | | ||
216 | T18X_BYPASS_LP_SEQ | DEFAULT_THS_SETTLE); | ||
217 | /* release soft reset */ | ||
218 | csi4_phy_write(chan, phy_num, NVCSI_CIL_B_SW_RESET, 0x0); | ||
219 | } | ||
220 | } | ||
221 | |||
222 | static void csi4_stream_check_status( | ||
223 | struct tegra_csi_channel *chan, int port_num) | ||
224 | { | ||
225 | struct tegra_csi_device *csi = chan->csi; | ||
226 | int status = 0; | ||
227 | |||
228 | dev_dbg(csi->dev, "%s\n", __func__); | ||
229 | if (!chan->pg_mode) { | ||
230 | status = csi4_stream_read(chan, port_num, ERROR_STATUS2VI_VC0); | ||
231 | if (status) | ||
232 | dev_err(csi->dev, | ||
233 | "%s (%d) ERROR_STATUS2VI_VC0 = 0x%08x\n", | ||
234 | __func__, port_num, status); | ||
235 | |||
236 | status = csi4_stream_read(chan, port_num, ERROR_STATUS2VI_VC1); | ||
237 | if (status) | ||
238 | dev_err(csi->dev, | ||
239 | "%s (%d) ERROR_STATUS2VI_VC1 = 0x%08x\n", | ||
240 | __func__, port_num, status); | ||
241 | |||
242 | status = csi4_stream_read(chan, port_num, ERROR_STATUS2VI_VC2); | ||
243 | if (status) | ||
244 | dev_err(csi->dev, | ||
245 | "%s (%d) ERROR_STATUS2VI_VC2 = 0x%08x\n", | ||
246 | __func__, port_num, status); | ||
247 | |||
248 | status = csi4_stream_read(chan, port_num, ERROR_STATUS2VI_VC3); | ||
249 | if (status) | ||
250 | dev_err(csi->dev, | ||
251 | "%s (%d) ERROR_STATUS2VI_VC2 = 0x%08x\n", | ||
252 | __func__, port_num, status); | ||
253 | } | ||
254 | status = csi4_stream_read(chan, port_num, INTR_STATUS); | ||
255 | if (status) | ||
256 | dev_err(csi->dev, | ||
257 | "%s (%d) INTR_STATUS 0x%08x\n", | ||
258 | __func__, port_num, status); | ||
259 | |||
260 | status = csi4_stream_read(chan, port_num, ERR_INTR_STATUS); | ||
261 | if (status) | ||
262 | dev_err(csi->dev, | ||
263 | "%s (%d) ERR_INTR_STATUS 0x%08x\n", | ||
264 | __func__, port_num, status); | ||
265 | } | ||
266 | |||
267 | static void csi4_cil_check_status(struct tegra_csi_channel *chan, int port_num) | ||
268 | { | ||
269 | struct tegra_csi_device *csi = chan->csi; | ||
270 | int status = 0; | ||
271 | |||
272 | dev_dbg(csi->dev, "%s %d\n", __func__, __LINE__); | ||
273 | |||
274 | status = csi4_stream_read(chan, port_num, CIL_INTR_STATUS); | ||
275 | if (status) | ||
276 | dev_err(csi->dev, | ||
277 | "%s (%d) CIL_INTR_STATUS 0x%08x\n", | ||
278 | __func__, port_num, status); | ||
279 | |||
280 | status = csi4_stream_read(chan, port_num, CIL_ERR_INTR_STATUS); | ||
281 | if (status) | ||
282 | dev_err(csi->dev, | ||
283 | "%s (%d) CIL_ERR_INTR_STATUS 0x%08x\n", | ||
284 | __func__, port_num, status); | ||
285 | } | ||
286 | |||
287 | |||
288 | int csi4_power_on(struct tegra_csi_device *csi) | ||
289 | { | ||
290 | int err = 0; | ||
291 | |||
292 | err = nvhost_module_busy(csi->pdev); | ||
293 | if (err) | ||
294 | dev_err(csi->dev, "%s:cannot enable csi\n", __func__); | ||
295 | |||
296 | return err; | ||
297 | } | ||
298 | |||
299 | int csi4_power_off(struct tegra_csi_device *csi) | ||
300 | { | ||
301 | nvhost_module_idle(csi->pdev); | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static void csi4_tpg_stop_streaming(struct tegra_csi_channel *chan, | ||
307 | int ports_index) | ||
308 | { | ||
309 | unsigned int csi_port = chan->ports[ports_index].num; | ||
310 | struct tegra_csi_device *csi = chan->csi; | ||
311 | |||
312 | dev_dbg(csi->dev, "%s\n", __func__); | ||
313 | csi4_stream_check_status(chan, csi_port); | ||
314 | csi4_cil_check_status(chan, csi_port); | ||
315 | csi4_stream_write(chan, csi_port, PP_EN_CTRL, 0); | ||
316 | csi4_stream_write(chan, csi_port, TPG_EN_0, 0); | ||
317 | csi4_stream_write(chan, csi_port, PG_CTRL, PG_DISABLE); | ||
318 | } | ||
319 | static int csi4_tpg_start_streaming(struct tegra_csi_channel *chan, | ||
320 | enum tegra_csi_port_num port_num) | ||
321 | { | ||
322 | struct tegra_csi_port *port = &chan->ports[port_num]; | ||
323 | struct tegra_csi_device *csi = chan->csi; | ||
324 | unsigned int val, csi_port, csi_lanes; | ||
325 | |||
326 | if (!port->core_format) { | ||
327 | dev_err(csi->dev, "Fail to find tegra video fmt"); | ||
328 | return -EINVAL; | ||
329 | } | ||
330 | |||
331 | csi_port = port->num; | ||
332 | csi_lanes = port->lanes; | ||
333 | dev_dbg(csi->dev, "%s CSI port=%d, # lanes=%d\n", | ||
334 | __func__, csi_port, csi_lanes); | ||
335 | |||
336 | csi4_stream_write(chan, csi_port, PH_CHK_CTRL, 0); | ||
337 | csi4_stream_write(chan, csi_port, INTR_MASK, PH_ECC_MULTI_BIT_ERR | | ||
338 | PD_CRC_ERR_VC0 | PH_ECC_SINGLE_BIT_ERR_VC0); | ||
339 | csi4_stream_write(chan, csi_port, ERR_INTR_MASK, PH_ECC_MULTI_BIT_ERR | | ||
340 | PD_CRC_ERR_VC0 | PH_ECC_SINGLE_BIT_ERR_VC0); | ||
341 | csi4_stream_write(chan, csi_port, ERROR_STATUS2VI_MASK, | ||
342 | CFG_ERR_STATUS2VI_MASK_VC0 | | ||
343 | CFG_ERR_STATUS2VI_MASK_VC1 | | ||
344 | CFG_ERR_STATUS2VI_MASK_VC2 | | ||
345 | CFG_ERR_STATUS2VI_MASK_VC3); | ||
346 | /* calculate PG blank */ | ||
347 | csi4_stream_write(chan, csi_port, PG_BLANK, | ||
348 | ((port->v_blank & PG_VBLANK_MASK) << PG_VBLANK_OFFSET) | | ||
349 | ((port->h_blank & PG_HBLANK_MASK) << PG_HBLANK_OFFSET)); | ||
350 | csi4_stream_write(chan, csi_port, PG_PHASE, 0x0); | ||
351 | csi4_stream_write(chan, csi_port, PG_RED_FREQ, | ||
352 | (0x10 << PG_VERT_INIT_FREQ_OFFSET)| | ||
353 | (0x10 << PG_HOR_INIT_FREQ_OFFSET)); | ||
354 | csi4_stream_write(chan, csi_port, PG_RED_FREQ_RATE, 0x0); | ||
355 | csi4_stream_write(chan, csi_port, PG_GREEN_FREQ, | ||
356 | (0x10 << PG_VERT_INIT_FREQ_OFFSET)| | ||
357 | (0x10 << PG_HOR_INIT_FREQ_OFFSET)); | ||
358 | csi4_stream_write(chan, csi_port, PG_GREEN_FREQ_RATE, 0x0); | ||
359 | csi4_stream_write(chan, csi_port, PG_BLUE_FREQ, | ||
360 | (0x10 << PG_VERT_INIT_FREQ_OFFSET)| | ||
361 | (0x10 << PG_HOR_INIT_FREQ_OFFSET)); | ||
362 | csi4_stream_write(chan, csi_port, PG_BLUE_FREQ_RATE, 0x0); | ||
363 | /* calculate PG IMAGE SIZE and DT */ | ||
364 | mutex_lock(&chan->format_lock); | ||
365 | val = port->format.height << HEIGHT_OFFSET | | ||
366 | (port->format.width * | ||
367 | (port->core_format->vf_code == TEGRA_VF_RAW10 ? 10 : 24) / 8); | ||
368 | mutex_unlock(&chan->format_lock); | ||
369 | csi4_stream_write(chan, csi_port, PG_IMAGE_SIZE, val); | ||
370 | csi4_stream_write(chan, csi_port, PG_IMAGE_DT, | ||
371 | port->core_format->img_dt); | ||
372 | csi4_stream_write(chan, csi_port, PP_EN_CTRL, CFG_PP_EN); | ||
373 | csi4_stream_write(chan, csi_port, TPG_EN_0, cfg_tpg_en); | ||
374 | |||
375 | csi4_stream_write(chan, csi_port, PG_CTRL, | ||
376 | ((chan->pg_mode - 1) << PG_MODE_OFFSET) | PG_ENABLE); | ||
377 | return 0; | ||
378 | } | ||
379 | int csi4_hw_init(struct tegra_csi_device *csi) | ||
380 | { | ||
381 | csi->iomem[0] = csi->iomem_base + TEGRA_CSI_STREAM_0_BASE; | ||
382 | csi->iomem[1] = csi->iomem_base + TEGRA_CSI_STREAM_2_BASE; | ||
383 | csi->iomem[2] = csi->iomem_base + TEGRA_CSI_STREAM_4_BASE; | ||
384 | |||
385 | return 0; | ||
386 | } | ||
387 | int csi4_start_streaming(struct tegra_csi_channel *chan, | ||
388 | enum tegra_csi_port_num port_num) | ||
389 | { | ||
390 | struct tegra_csi_device *csi = chan->csi; | ||
391 | int csi_port, csi_lanes, ret = 0; | ||
392 | |||
393 | csi_port = chan->ports[port_num].num; | ||
394 | csi_lanes = chan->ports[port_num].lanes; | ||
395 | dev_dbg(csi->dev, "%s ports index=%d, lanes=%d\n", | ||
396 | __func__, csi_port, csi_lanes); | ||
397 | |||
398 | if (chan->pg_mode) | ||
399 | ret = csi4_tpg_start_streaming(chan, port_num); | ||
400 | else { | ||
401 | csi4_stream_init(chan, csi_port); | ||
402 | csi4_stream_config(chan, csi_port); | ||
403 | /* enable DPHY */ | ||
404 | csi4_phy_config(chan, csi_port, csi_lanes, true); | ||
405 | csi4_stream_write(chan, csi_port, PP_EN_CTRL, CFG_PP_EN); | ||
406 | } | ||
407 | return ret; | ||
408 | } | ||
409 | |||
410 | void csi4_stop_streaming(struct tegra_csi_channel *chan, | ||
411 | enum tegra_csi_port_num port_num) | ||
412 | { | ||
413 | struct tegra_csi_device *csi = chan->csi; | ||
414 | int csi_port, csi_lanes; | ||
415 | |||
416 | dev_dbg(csi->dev, "%s ports index=%d, lanes=%d\n", | ||
417 | __func__, port_num, chan->numlanes); | ||
418 | |||
419 | csi_port = chan->ports[port_num].num; | ||
420 | csi_lanes = chan->ports[port_num].lanes; | ||
421 | |||
422 | if (chan->pg_mode) | ||
423 | csi4_tpg_stop_streaming(chan, port_num); | ||
424 | else { | ||
425 | /* disable DPHY */ | ||
426 | csi4_phy_config(chan, csi_port, csi_lanes, false); | ||
427 | csi4_stream_check_status(chan, csi_port); | ||
428 | csi4_cil_check_status(chan, csi_port); | ||
429 | } | ||
430 | } | ||
431 | |||
432 | void csi4_override_format(struct tegra_csi_channel *chan, | ||
433 | enum tegra_csi_port_num port_num) | ||
434 | { | ||
435 | struct tegra_csi_port *port = &chan->ports[port_num]; | ||
436 | unsigned int val; | ||
437 | int csi_port; | ||
438 | |||
439 | if (!chan->pg_mode) { | ||
440 | dev_err(chan->csi->dev, "%s non PG format update failed\n", | ||
441 | __func__); | ||
442 | return; | ||
443 | } | ||
444 | |||
445 | /* calculate PG IMAGE SIZE and DT */ | ||
446 | mutex_lock(&chan->format_lock); | ||
447 | val = port->format.height << HEIGHT_OFFSET | | ||
448 | (port->format.width * | ||
449 | (port->core_format->vf_code == TEGRA_VF_RAW10 ? 10 : 24) / 8); | ||
450 | mutex_unlock(&chan->format_lock); | ||
451 | |||
452 | csi_port = chan->ports[port_num].num; | ||
453 | csi4_stream_write(chan, csi_port, PG_IMAGE_SIZE, val); | ||
454 | } | ||
455 | |||
456 | int csi4_mipi_cal(struct tegra_csi_channel *chan) | ||
457 | { | ||
458 | unsigned int lanes, num_ports, port, addr; | ||
459 | unsigned int cila, cilb; | ||
460 | struct tegra_csi_device *csi = chan->csi; | ||
461 | |||
462 | lanes = 0; | ||
463 | num_ports = 0; | ||
464 | port = 0; | ||
465 | while (num_ports < chan->numports) { | ||
466 | port = chan->ports[num_ports].num; | ||
467 | dev_dbg(csi->dev, "csi port:%d\n", port); | ||
468 | |||
469 | if (chan->numlanes == 2) { | ||
470 | lanes |= CSIA << port; | ||
471 | cila = (0x01 << E_INPUT_LP_IO0_SHIFT) | | ||
472 | (0x01 << E_INPUT_LP_IO1_SHIFT) | | ||
473 | (0x01 << E_INPUT_LP_CLK_SHIFT) | | ||
474 | (0x00 << PD_CLK_SHIFT) | | ||
475 | (0x00 << PD_IO0_SHIFT) | | ||
476 | (0x00 << PD_IO1_SHIFT); | ||
477 | addr = (port % 2 == 0 ? | ||
478 | NVCSI_CIL_A_BASE : NVCSI_CIL_B_BASE) | ||
479 | + PAD_CONFIG_0; | ||
480 | csi4_phy_write(chan, port >> 1, addr, cila); | ||
481 | } else { | ||
482 | lanes |= (CSIA | CSIB) << port; | ||
483 | cila = (0x01 << E_INPUT_LP_IO0_SHIFT) | | ||
484 | (0x01 << E_INPUT_LP_IO1_SHIFT) | | ||
485 | (0x01 << E_INPUT_LP_CLK_SHIFT) | | ||
486 | (0x00 << PD_CLK_SHIFT) | | ||
487 | (0x00 << PD_IO0_SHIFT) | | ||
488 | (0x00 << PD_IO1_SHIFT); | ||
489 | cilb = (0x01 << E_INPUT_LP_IO0_SHIFT) | | ||
490 | (0x01 << E_INPUT_LP_IO1_SHIFT) | | ||
491 | (0x01 << PD_CLK_SHIFT) | | ||
492 | (0x00 << PD_IO0_SHIFT) | | ||
493 | (0x00 << PD_IO1_SHIFT); | ||
494 | csi4_phy_write(chan, port >> 1, | ||
495 | NVCSI_CIL_A_BASE + PAD_CONFIG_0, cila); | ||
496 | csi4_phy_write(chan, port >> 1, | ||
497 | NVCSI_CIL_B_BASE + PAD_CONFIG_0, cilb); | ||
498 | } | ||
499 | num_ports++; | ||
500 | } | ||
501 | if (!lanes) { | ||
502 | dev_err(csi->dev, "Selected no CSI lane, cannot do calibration"); | ||
503 | return -EINVAL; | ||
504 | } | ||
505 | return tegra_mipi_calibration(lanes); | ||
506 | } | ||
diff --git a/drivers/media/platform/tegra/camera/csi/csi4_fops.h b/drivers/media/platform/tegra/camera/csi/csi4_fops.h new file mode 100644 index 000000000..49f0aa8ad --- /dev/null +++ b/drivers/media/platform/tegra/camera/csi/csi4_fops.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /* | ||
2 | * Tegra CSI4 device common APIs | ||
3 | * | ||
4 | * Tegra Graphics Host VI | ||
5 | * | ||
6 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. | ||
7 | * | ||
8 | * Author: Frank Chen <frankc@nvidia.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #ifndef __CSI4_H__ | ||
16 | #define __CSI4_H__ | ||
17 | |||
18 | #include "csi.h" | ||
19 | |||
20 | int csi4_power_on(struct tegra_csi_device *csi); | ||
21 | int csi4_power_off(struct tegra_csi_device *csi); | ||
22 | int csi4_start_streaming(struct tegra_csi_channel *chacsin, | ||
23 | enum tegra_csi_port_num port_num); | ||
24 | void csi4_stop_streaming(struct tegra_csi_channel *chan, | ||
25 | enum tegra_csi_port_num port_num); | ||
26 | void csi4_override_format(struct tegra_csi_channel *chan, | ||
27 | enum tegra_csi_port_num port_num); | ||
28 | int csi4_mipi_cal(struct tegra_csi_channel *chan); | ||
29 | int csi4_hw_init(struct tegra_csi_device *csi); | ||
30 | |||
31 | struct tegra_csi_fops csi4_fops = { | ||
32 | .csi_power_on = csi4_power_on, | ||
33 | .csi_power_off = csi4_power_off, | ||
34 | .csi_start_streaming = csi4_start_streaming, | ||
35 | .csi_stop_streaming = csi4_stop_streaming, | ||
36 | .csi_override_format = csi4_override_format, | ||
37 | .mipical = csi4_mipi_cal, | ||
38 | .hw_init = csi4_hw_init, | ||
39 | }; | ||
40 | |||
41 | #endif | ||
diff --git a/drivers/media/platform/tegra/camera/csi/csi4_registers.h b/drivers/media/platform/tegra/camera/csi/csi4_registers.h new file mode 100644 index 000000000..ed4ef936c --- /dev/null +++ b/drivers/media/platform/tegra/camera/csi/csi4_registers.h | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * drivers/media/platform/tegra/camera/csi/csi4_registers.h | ||
3 | * | ||
4 | * Tegra 18x CSI register offsets | ||
5 | * | ||
6 | * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms and conditions of the GNU General Public License, | ||
10 | * version 2, as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | #ifndef __CSI4_REGISTERS_H__ | ||
22 | #define __CSI4_REGISTERS_H__ | ||
23 | |||
24 | #define CSI4_BASE_ADDRESS 0x18000 | ||
25 | #define CSI4_PHY_OFFSET 0x10000 | ||
26 | #define CSI4_STREAM_OFFSET 0x800 | ||
27 | |||
28 | #define CSI_PORTS (6) | ||
29 | #define PHY_BRICKS (3) | ||
30 | |||
31 | /* NVCSI registers. Starts from 0x0 */ | ||
32 | #define CFG_NVCSI_INCR_SYNCPT_CNTRL 0x04 | ||
33 | |||
34 | /* NVCSI_STREAM registers */ | ||
35 | #define TEGRA_CSI_STREAM_0_BASE 0x010000 | ||
36 | #define TEGRA_CSI_STREAM_1_BASE 0x010800 | ||
37 | #define TEGRA_CSI_STREAM_2_BASE 0x020000 | ||
38 | #define TEGRA_CSI_STREAM_3_BASE 0x020800 | ||
39 | #define TEGRA_CSI_STREAM_4_BASE 0x030000 | ||
40 | #define TEGRA_CSI_STREAM_5_BASE 0x030800 | ||
41 | |||
42 | #define PP_EN_CTRL 0x08 | ||
43 | #define CFG_PP_EN (0x1 << 0) | ||
44 | |||
45 | #define PPFSM_TIMEOUT_CTRL 0x6c | ||
46 | #define CFG_TIMEOUT_EN (0x1 << 31) | ||
47 | #define CFG_TIMEOUT_PERIOD (0x7fffffff << 0) | ||
48 | |||
49 | #define VC0_DT_OVERRIDE 0x20 | ||
50 | #define CFG_VC0_DT_OVERRIDE_EN (0x1 << 31) | ||
51 | #define CFG_VC0_DT_OVERRIDE (0x3f << 0) | ||
52 | |||
53 | #define PH_CHK_CTRL 0x70 | ||
54 | #define CFG_PH_CRC_CHK_EN (0x1 << 1) | ||
55 | #define CFG_PH_ECC_CHK_EN (0x1 << 0) | ||
56 | |||
57 | #define VC0_DPCM_CTRL 0x74 | ||
58 | #define CFG_VC0_DPCM_COMPRESSION_RATIO (0xf << 0) | ||
59 | |||
60 | #define ERROR_STATUS2VI_MASK 0x90 | ||
61 | |||
62 | /* T186 TPG */ | ||
63 | #define TPG_EN_0 0x0b8 | ||
64 | #define cfg_tpg_en 0x1 | ||
65 | /* NVCSI_STREAM Legacy T210 PG*/ | ||
66 | #define PG_CTRL 0x194 | ||
67 | #define PG_MODE_OFFSET 2 | ||
68 | #define PG_ENABLE 0x1 | ||
69 | #define PG_DISABLE 0x0 | ||
70 | #define PG_BLANK 0x198 | ||
71 | #define PG_VBLANK_MASK 0xffff | ||
72 | #define PG_HBLANK_MASK 0xffff | ||
73 | #define PG_VBLANK_OFFSET 16 | ||
74 | #define PG_HBLANK_OFFSET 0 | ||
75 | #define PG_PHASE 0x19c | ||
76 | #define PG_RED_FREQ 0x1a0 | ||
77 | #define PG_VERT_INIT_FREQ_OFFSET 16 | ||
78 | #define PG_HOR_INIT_FREQ_OFFSET 0 | ||
79 | #define PG_RED_FREQ_RATE 0x1a4 | ||
80 | #define PG_GREEN_FREQ 0x1a8 | ||
81 | #define PG_GREEN_FREQ_RATE 0x1ac | ||
82 | #define PG_BLUE_FREQ 0x1b0 | ||
83 | #define PG_BLUE_FREQ_RATE 0X1b4 | ||
84 | #define PG_AOHDR 0x1b8 | ||
85 | #define PG_IMAGE_SIZE 0x1bc | ||
86 | #define HEIGHT_OFFSET 16 | ||
87 | #define PG_IMAGE_DT 0x1c0 | ||
88 | |||
89 | /* TODO - double check if rr_status2vi_vc0:[0] means bit or value */ | ||
90 | #define ERROR_STATUS2VI_VC0 0x94 | ||
91 | #define ERROR_STATUS2VI_VC1 0x98 | ||
92 | #define ERROR_STATUS2VI_VC2 0x9c | ||
93 | #define ERROR_STATUS2VI_VC3 0xa0 | ||
94 | #define ERR_STATUS2VI_VC (0xf << 0) | ||
95 | #define ERR_PP_FSM_TIMEOUT (0) | ||
96 | #define ERR_PH_ECC_SINGLE_BIT (1) | ||
97 | #define ERR_PACKET_PAYLOAD_CRC (2) | ||
98 | #define ERR_PACKET_PAYLOAD_LESS (3) | ||
99 | |||
100 | #define INTR_STATUS 0xa4 | ||
101 | #define INTR_MASK 0xa8 | ||
102 | #define PD_CRC_ERR_VC0 (0x1 << 2) | ||
103 | #define PH_ECC_SINGLE_BIT_ERR_VC0 (0x1 << 1) | ||
104 | #define PH_ECC_MULTI_BIT_ERR (0x1 << 16) | ||
105 | #define ERR_INTR_STATUS 0xac | ||
106 | #define ERR_INTR_MASK 0xb0 | ||
107 | #define MASK_PH_CRC_ERR (0x1 << 17) | ||
108 | #define MASK_PH_ECC_MULTI_BIT_ERR (0x1 << 16) | ||
109 | #define MASK_PD_WC_SHORT_ERR_VC3 (0x1 << 15) | ||
110 | #define MASK_PD_CRC_ERR_VC3 (0x1 << 14) | ||
111 | #define MASK_PH_ECC_SINGLE_BIT_ERR_VC3 (0x1 << 13) | ||
112 | #define MASK_PPFSM_TIMEOUT_VC3 (0x1 << 12) | ||
113 | #define MASK_PD_WC_SHORT_ERR_VC2 (0x1 << 11) | ||
114 | #define MASK_PD_CRC_ERR_VC2 (0x1 << 10) | ||
115 | #define MASK_PH_ECC_SINGLE_BIT_ERR_VC2 (0x1 << 9) | ||
116 | #define MASK_PPFSM_TIMEOUT_VC2 (0x1 << 8) | ||
117 | #define MASK_PD_WC_SHORT_ERR_VC1 (0x1 << 7) | ||
118 | #define MASK_PD_CRC_ERR_VC1 (0x1 << 6) | ||
119 | #define MASK_PH_ECC_SINGLE_BIT_ERR_VC1 (0x1 << 5) | ||
120 | #define MASK_PPFSM_TIMEOUT_VC1 (0x1 << 4) | ||
121 | #define MASK_PD_WC_SHORT_ERR_VC0 (0x1 << 3) | ||
122 | #define MASK_PD_CRC_ERR_VC0 (0x1 << 2) | ||
123 | #define MASK_PH_ECC_SINGLE_BIT_ERR_VC0 (0x1 << 1) | ||
124 | #define MASK_PPFSM_TIMEOUT_VC0 (0x1 << 0) | ||
125 | /* For ERR_INTR_MASK and ERR_INTR_MASK */ | ||
126 | #define MASK_HSM_INTR_SW_TRIGGER (0x1 << 18) | ||
127 | |||
128 | /* NVCSI_PHY CIL registers */ | ||
129 | #define NVCSI_PHY_0_CILA_BASE 0x010400 | ||
130 | #define NVCSI_PHY_0_CILB_BASE 0x010C00 | ||
131 | #define NVCSI_PHY_1_CILA_BASE 0x020400 | ||
132 | #define NVCSI_PHY_1_CILB_BASE 0x020C00 | ||
133 | #define NVCSI_PHY_2_CILA_BASE 0x030400 | ||
134 | #define NVCSI_PHY_2_CILB_BASE 0x030C00 | ||
135 | |||
136 | #define CIL_INTR_STATUS 0x400 | ||
137 | #define CIL_INTR_MASK 0x404 | ||
138 | #define CIL_ERR_INTR_STATUS 0x408 | ||
139 | #define CIL_ERR_INTR_MASK 0x40c | ||
140 | |||
141 | /* NVCSI_PHY registers */ | ||
142 | #define NVCSI_CIL_PHY_CTRL 0x00 | ||
143 | #define CFG_PHY_MODE (0x1 << 0) | ||
144 | #define DPHY (0) | ||
145 | #define CPHY (1) | ||
146 | |||
147 | #define NVCSI_CIL_CONFIG 0x04 | ||
148 | #define DATA_LANE_B_OFFSET 0x8 | ||
149 | #define DATA_LANE_A_OFFSET 0x0 | ||
150 | #define DATA_LANE_B (0x7 << DATA_LANE_B_OFFSET) | ||
151 | #define DATA_LANE_A (0x7 << DATA_LANE_A_OFFSET) | ||
152 | |||
153 | #define NVCSI_CIL_PAD_CONFIG 0x0c | ||
154 | #define LOADADJ (0xf << 12) | ||
155 | #define PDVCLAMP (0x1 << 9) | ||
156 | #define E_VCLAMP (0x1 << 8) | ||
157 | #define SPARE_TOP (0xff << 0) | ||
158 | |||
159 | #define NVCSI_CIL_A_SW_RESET 0x18 | ||
160 | #define NVCSI_CIL_B_SW_RESET 0x7c | ||
161 | #define SW_RESET1_EN (0x1 << 1) | ||
162 | #define SW_RESET0_EN (0x1 << 0) | ||
163 | |||
164 | #define NVCSI_CIL_A_PAD_CONFIG 0x20 | ||
165 | #define NVCSI_CIL_B_PAD_CONFIG 0x84 | ||
166 | #define E_INPUT_LP_IO1_SHIFT 22 | ||
167 | #define E_INPUT_LP_IO0_SHIFT 21 | ||
168 | #define E_INPUT_LP_CLK_SHIFT 20 | ||
169 | #define E_INPUT_LP_IO1 (0x1 << 22) | ||
170 | #define E_INPUT_LP_IO0 (0x1 << 21) | ||
171 | #define E_INPUT_LP_CLK (0x1 << 20) | ||
172 | #define BANDWD_IN (0x1 << 19) | ||
173 | #define PD_CLK (0x1 << 18) | ||
174 | #define PD_IO1 (0x1 << 17) | ||
175 | #define PD_IO0 (0x1 << 16) | ||
176 | #define PD_CLK_SHIFT 18 | ||
177 | #define PD_IO1_SHIFT 17 | ||
178 | #define PD_IO0_SHIFT 16 | ||
179 | #define SPARE_CLK (0x1 << 8) | ||
180 | #define SPARE_IO1 (0x1 << 4) | ||
181 | #define SPARE_IO0 (0x1 << 0) | ||
182 | |||
183 | #define NVCSI_CIL_A_CONTROL 0x5c | ||
184 | #define NVCSI_CIL_B_CONTROL 0xc0 | ||
185 | #define DEFAULT_DESKEW_COMPARE (0x4 << 20) | ||
186 | #define DEFAULT_DESKEW_SETTLE (0x6 << 16) | ||
187 | #define DEFAULT_CLK_SETTLE (0x21 << 8) | ||
188 | #define T18X_BYPASS_LP_SEQ (0x1 << 7) | ||
189 | #define DEFAULT_THS_SETTLE (0x14 << 0) | ||
190 | |||
191 | /* MIPICAL */ | ||
192 | #define NVCSI_CIL_A_BASE 0x18 | ||
193 | #define NVCSI_CIL_B_BASE 0x7c | ||
194 | #define PAD_CONFIG_0 0x8 | ||
195 | |||
196 | #endif /* __CSI4_REGISTERS_H__ */ | ||
diff --git a/drivers/media/platform/tegra/camera/sensor_common.c b/drivers/media/platform/tegra/camera/sensor_common.c new file mode 100644 index 000000000..b1504e61d --- /dev/null +++ b/drivers/media/platform/tegra/camera/sensor_common.c | |||
@@ -0,0 +1,329 @@ | |||
1 | /* | ||
2 | * sensor_common.c - utilities for tegra sensor drivers | ||
3 | * | ||
4 | * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <media/sensor_common.h> | ||
20 | #include <linux/of_graph.h> | ||
21 | #include <linux/string.h> | ||
22 | |||
23 | static int read_property_u32( | ||
24 | struct device_node *node, const char *name, u32 *value) | ||
25 | { | ||
26 | const char *str; | ||
27 | int err = 0; | ||
28 | |||
29 | err = of_property_read_string(node, name, &str); | ||
30 | if (err) | ||
31 | return -ENODATA; | ||
32 | |||
33 | err = kstrtou32(str, 10, value); | ||
34 | if (err) | ||
35 | return -EFAULT; | ||
36 | |||
37 | return 0; | ||
38 | } | ||
39 | |||
40 | static int read_property_u64( | ||
41 | struct device_node *node, const char *name, u64 *value) | ||
42 | { | ||
43 | const char *str; | ||
44 | int err = 0; | ||
45 | |||
46 | err = of_property_read_string(node, name, &str); | ||
47 | if (err) | ||
48 | return -ENODATA; | ||
49 | |||
50 | err = kstrtou64(str, 10, value); | ||
51 | if (err) | ||
52 | return -EFAULT; | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static int sensor_common_parse_signal_props( | ||
58 | struct device *dev, struct device_node *node, | ||
59 | struct sensor_signal_properties *signal) | ||
60 | { | ||
61 | const char *temp_str; | ||
62 | int err = 0; | ||
63 | |||
64 | /* Do not report error for these properties yet */ | ||
65 | read_property_u32(node, "readout_orientation", | ||
66 | &signal->readout_orientation); | ||
67 | read_property_u32(node, "num_lanes", | ||
68 | &signal->num_lanes); | ||
69 | read_property_u32(node, "mclk_khz", | ||
70 | &signal->mclk_freq); | ||
71 | read_property_u64(node, "pix_clk_hz", | ||
72 | &signal->pixel_clock.val); | ||
73 | read_property_u32(node, "cil_settletime", | ||
74 | &signal->cil_settletime); | ||
75 | /* initialize default if this prop not available */ | ||
76 | err = of_property_read_string(node, "discontinuous_clk", | ||
77 | &temp_str); | ||
78 | if (!err) | ||
79 | signal->discontinuous_clk = | ||
80 | !strncmp(temp_str, "yes", sizeof("yes")); | ||
81 | else | ||
82 | signal->discontinuous_clk = 1; | ||
83 | /* initialize default if this prop not available */ | ||
84 | err = of_property_read_string(node, "dpcm_enable", | ||
85 | &temp_str); | ||
86 | if (!err) | ||
87 | signal->dpcm_enable = | ||
88 | !strncmp(temp_str, "true", sizeof("true")); | ||
89 | else | ||
90 | signal->dpcm_enable = 0; | ||
91 | |||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static int extract_pixel_format( | ||
96 | const char *pixel_t, u32 *format) | ||
97 | { | ||
98 | size_t size = strnlen(pixel_t, OF_MAX_STR_LEN); | ||
99 | |||
100 | if (strncmp(pixel_t, "bayer_bggr10", size) == 0) | ||
101 | *format = V4L2_PIX_FMT_SBGGR10; | ||
102 | else if (strncmp(pixel_t, "bayer_rggb10", size) == 0) | ||
103 | *format = V4L2_PIX_FMT_SRGGB10; | ||
104 | else if (strncmp(pixel_t, "bayer_bggr12", size) == 0) | ||
105 | *format = V4L2_PIX_FMT_SBGGR12; | ||
106 | else if (strncmp(pixel_t, "bayer_rggb12", size) == 0) | ||
107 | *format = V4L2_PIX_FMT_SRGGB12; | ||
108 | else if (strncmp(pixel_t, "bayer_xbggr10p", size) == 0) | ||
109 | *format = V4L2_PIX_FMT_XBGGR10P; | ||
110 | else if (strncmp(pixel_t, "bayer_xrggb10p", size) == 0) | ||
111 | *format = V4L2_PIX_FMT_XRGGB10P; | ||
112 | else { | ||
113 | pr_err("%s: Need to extend format%s\n", __func__, pixel_t); | ||
114 | return -EINVAL; | ||
115 | } | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static int sensor_common_parse_image_props( | ||
121 | struct device *dev, struct device_node *node, | ||
122 | struct sensor_image_properties *image) | ||
123 | { | ||
124 | const char *temp_str; | ||
125 | int err = 0; | ||
126 | |||
127 | err = read_property_u32(node, "active_w", | ||
128 | &image->width); | ||
129 | if (err) { | ||
130 | dev_err(dev, "%s:active_w property missing\n", __func__); | ||
131 | goto fail; | ||
132 | } | ||
133 | |||
134 | err = read_property_u32(node, "active_h", | ||
135 | &image->height); | ||
136 | if (err) { | ||
137 | dev_err(dev, "%s:active_h property missing\n", __func__); | ||
138 | goto fail; | ||
139 | } | ||
140 | |||
141 | err = read_property_u32(node, "line_length", | ||
142 | &image->line_length); | ||
143 | if (err) { | ||
144 | dev_err(dev, "%s:Line length property missing\n", __func__); | ||
145 | goto fail; | ||
146 | } | ||
147 | |||
148 | err = of_property_read_string(node, "pixel_t", | ||
149 | &temp_str); | ||
150 | if (err) { | ||
151 | dev_err(dev, "%s:pixel_t property missing\n", __func__); | ||
152 | goto fail; | ||
153 | } | ||
154 | |||
155 | err = extract_pixel_format(temp_str, &image->pixel_format); | ||
156 | if (err) { | ||
157 | dev_err(dev, "Unsupported pixel format\n"); | ||
158 | goto fail; | ||
159 | } | ||
160 | |||
161 | /* ignore err for this prop */ | ||
162 | read_property_u32(node, "embedded_metadata_height", | ||
163 | &image->embedded_metadata_height); | ||
164 | |||
165 | fail: | ||
166 | return err; | ||
167 | } | ||
168 | |||
169 | static int sensor_common_parse_dv_timings( | ||
170 | struct device *dev, struct device_node *node, | ||
171 | struct sensor_dv_timings *timings) | ||
172 | { | ||
173 | /* Do not report error for these properties yet */ | ||
174 | read_property_u32(node, "horz_front_porch", | ||
175 | &timings->hfrontporch); | ||
176 | read_property_u32(node, "horz_sync", | ||
177 | &timings->hsync); | ||
178 | read_property_u32(node, "horz_back_porch", | ||
179 | &timings->hbackporch); | ||
180 | read_property_u32(node, "vert_front_porch", | ||
181 | &timings->vfrontporch); | ||
182 | read_property_u32(node, "vert_sync", | ||
183 | &timings->vsync); | ||
184 | read_property_u32(node, "vert_back_porch", | ||
185 | &timings->vbackporch); | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static int sensor_common_parse_control_props( | ||
191 | struct device *dev, struct device_node *node, | ||
192 | struct sensor_control_properties *control) | ||
193 | { | ||
194 | int err = 0; | ||
195 | |||
196 | err = read_property_u32(node, "gain_factor", | ||
197 | &control->gain_factor); | ||
198 | if (err) | ||
199 | dev_err(dev, "%s:%s:property missing\n", | ||
200 | __func__, "gain_factor"); | ||
201 | |||
202 | err = read_property_u32(node, "framerate_factor", | ||
203 | &control->framerate_factor); | ||
204 | if (err) | ||
205 | dev_err(dev, "%s:%s:property missing\n", | ||
206 | __func__, "framerate_factor"); | ||
207 | |||
208 | /* ignore err for this prop */ | ||
209 | err = read_property_u32(node, "inherent_gain", | ||
210 | &control->inherent_gain); | ||
211 | |||
212 | err = read_property_u32(node, "min_gain_val", | ||
213 | &control->min_gain_val); | ||
214 | if (err) | ||
215 | dev_err(dev, "%s:%s:property missing\n", | ||
216 | __func__, "min_gain_val"); | ||
217 | |||
218 | err = read_property_u32(node, "max_gain_val", | ||
219 | &control->max_gain_val); | ||
220 | if (err) | ||
221 | dev_err(dev, "%s:%s:property missing\n", | ||
222 | __func__, "max_gain_val"); | ||
223 | |||
224 | /* ignore err for this prop */ | ||
225 | err = read_property_u32(node, "min_hdr_ratio", | ||
226 | &control->min_hdr_ratio); | ||
227 | err = read_property_u32(node, "max_hdr_ratio", | ||
228 | &control->max_hdr_ratio); | ||
229 | |||
230 | err = read_property_u32(node, "min_framerate", | ||
231 | &control->min_framerate); | ||
232 | if (err) | ||
233 | dev_err(dev, "%s:%s:property missing\n", | ||
234 | __func__, "min_framerate"); | ||
235 | |||
236 | err = read_property_u32(node, "max_framerate", | ||
237 | &control->max_framerate); | ||
238 | if (err) | ||
239 | dev_err(dev, "%s:%s:property missing\n", | ||
240 | __func__, "max_framerate"); | ||
241 | |||
242 | err = read_property_u64(node, "min_exp_time", | ||
243 | &control->min_exp_time.val); | ||
244 | if (err) | ||
245 | dev_err(dev, "%s:%s:property missing\n", | ||
246 | __func__, "min_exp_time"); | ||
247 | |||
248 | err = read_property_u64(node, "max_exp_time", | ||
249 | &control->max_exp_time.val); | ||
250 | if (err) | ||
251 | dev_err(dev, "%s:%s:property missing\n", | ||
252 | __func__, "max_exp_time"); | ||
253 | |||
254 | |||
255 | return err; | ||
256 | } | ||
257 | |||
258 | int sensor_common_init_sensor_properties( | ||
259 | struct device *dev, struct device_node *node, | ||
260 | struct sensor_properties *sensor) | ||
261 | { | ||
262 | char temp_str[OF_MAX_STR_LEN]; | ||
263 | struct device_node *temp_node; | ||
264 | int num_modes = 0; | ||
265 | int err, i; | ||
266 | |||
267 | /* get number of modes */ | ||
268 | for (i = 0; num_modes < MAX_NUM_SENSOR_MODES; i++) { | ||
269 | snprintf(temp_str, sizeof(temp_str), "%s%d", | ||
270 | OF_SENSORMODE_PREFIX, i); | ||
271 | temp_node = of_find_node_by_name(node, temp_str); | ||
272 | if (temp_node == NULL) | ||
273 | break; | ||
274 | num_modes++; | ||
275 | } | ||
276 | sensor->num_modes = num_modes; | ||
277 | |||
278 | sensor->sensor_modes = devm_kzalloc(dev, | ||
279 | num_modes * sizeof(struct sensor_mode_properties), | ||
280 | GFP_KERNEL); | ||
281 | if (!sensor->sensor_modes) { | ||
282 | dev_err(dev, "Failed to allocate memory for sensor modes\n"); | ||
283 | return -ENOMEM; | ||
284 | } | ||
285 | memset(sensor->sensor_modes, 0, num_modes * | ||
286 | sizeof(struct sensor_mode_properties)); | ||
287 | |||
288 | for (i = 0; i < num_modes; i++) { | ||
289 | snprintf(temp_str, sizeof(temp_str), "%s%d", | ||
290 | OF_SENSORMODE_PREFIX, i); | ||
291 | |||
292 | temp_node = of_find_node_by_name(node, temp_str); | ||
293 | if (temp_node == NULL) { | ||
294 | dev_err(dev, "Failed to find mode\n"); | ||
295 | return -ENODATA; | ||
296 | }; | ||
297 | |||
298 | err = sensor_common_parse_signal_props(dev, temp_node, | ||
299 | &sensor->sensor_modes[i].signal_properties); | ||
300 | if (err) { | ||
301 | dev_err(dev, "Failed to read signal properties\n"); | ||
302 | return err; | ||
303 | } | ||
304 | |||
305 | err = sensor_common_parse_image_props(dev, temp_node, | ||
306 | &sensor->sensor_modes[i].image_properties); | ||
307 | if (err) { | ||
308 | dev_err(dev, "Failed to read image properties\n"); | ||
309 | return err; | ||
310 | } | ||
311 | |||
312 | err = sensor_common_parse_dv_timings(dev, temp_node, | ||
313 | &sensor->sensor_modes[i].dv_timings); | ||
314 | if (err) { | ||
315 | dev_err(dev, "Failed to read DV timings\n"); | ||
316 | return err; | ||
317 | } | ||
318 | |||
319 | err = sensor_common_parse_control_props(dev, temp_node, | ||
320 | &sensor->sensor_modes[i].control_properties); | ||
321 | if (err) { | ||
322 | dev_err(dev, "Failed to read control properties\n"); | ||
323 | return err; | ||
324 | } | ||
325 | } | ||
326 | |||
327 | return 0; | ||
328 | } | ||
329 | EXPORT_SYMBOL(sensor_common_init_sensor_properties); | ||
diff --git a/drivers/media/platform/tegra/camera/vi/Makefile b/drivers/media/platform/tegra/camera/vi/Makefile new file mode 100644 index 000000000..11bce8f3b --- /dev/null +++ b/drivers/media/platform/tegra/camera/vi/Makefile | |||
@@ -0,0 +1,21 @@ | |||
1 | GCOV_PROFILE := y | ||
2 | ccflags-y += -I../nvhost/drivers/video/tegra/host | ||
3 | ccflags-y += -Idrivers/video/tegra/host | ||
4 | ccflags-y += -Idrivers/video/tegra/camera | ||
5 | ccflags-y += -Idrivers/media/platform/tegra | ||
6 | ccflags-y += -Werror | ||
7 | |||
8 | ifeq ($(CONFIG_ARCH_TEGRA_18x_SOC),y) | ||
9 | ccflags-y += -I../t18x/drivers/video/tegra/host/ | ||
10 | ccflags-y += -I../t18x/include | ||
11 | ccflags-y += -I../nvhost/include | ||
12 | obj-y += mc_common.o core.o channel.o graph.o vi2_fops.o vi4_fops.o | ||
13 | endif | ||
14 | |||
15 | obj-$(CONFIG_TEGRA_CAMERA_RTCPU) += capture.o | ||
16 | |||
17 | ifeq ($(CONFIG_ARCH_TEGRA_210_SOC),y) | ||
18 | ccflags-y += -I../nvhost/include | ||
19 | ccflags-y += -I../t18x/drivers/video/tegra/host/ | ||
20 | obj-y += mc_common.o core.o channel.o graph.o vi2_fops.o | ||
21 | endif | ||
diff --git a/drivers/media/platform/tegra/camera/vi/capture.c b/drivers/media/platform/tegra/camera/vi/capture.c new file mode 100644 index 000000000..7a8083098 --- /dev/null +++ b/drivers/media/platform/tegra/camera/vi/capture.c | |||
@@ -0,0 +1,880 @@ | |||
1 | /* | ||
2 | * Tegra Video Input capture operations | ||
3 | * | ||
4 | * Tegra Graphics Host VI | ||
5 | * | ||
6 | * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. | ||
7 | * | ||
8 | * Author: David Wang <davidw@nvidia.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/completion.h> | ||
16 | #include <linux/dma-buf.h> | ||
17 | #include <linux/nvhost.h> | ||
18 | #include <linux/of_platform.h> | ||
19 | #include <linux/printk.h> | ||
20 | #include <linux/scatterlist.h> | ||
21 | #include <linux/tegra-capture-ivc.h> | ||
22 | #include <media/capture.h> | ||
23 | |||
24 | #include "soc/tegra/camrtc-capture.h" | ||
25 | #include "soc/tegra/camrtc-capture-messages.h" | ||
26 | #include "mc_common.h" | ||
27 | |||
28 | |||
29 | #define CAPTURE_CHANNEL_UNKNOWN_RESP 0xFFFFFFFF | ||
30 | #define CAPTURE_CHANNEL_INVALID_ID 0xFFFF | ||
31 | #define CAPTURE_CHANNEL_INVALID_MASK 0llu | ||
32 | #define PROGRESS_SP_IDX 0 | ||
33 | #define EMBDATA_SP_IDX 1 | ||
34 | #define LINETIMER_SP_IDX 2 | ||
35 | #define CAPTURE_CHANNEL_MAX_NUM_SPS 3 | ||
36 | |||
37 | struct vi_capture_buf { | ||
38 | struct dma_buf *buf; | ||
39 | struct dma_buf_attachment *attach; | ||
40 | struct sg_table *sgt; | ||
41 | dma_addr_t iova; | ||
42 | }; | ||
43 | |||
44 | struct vi_capture_unpins { | ||
45 | uint32_t num_unpins; | ||
46 | struct vi_capture_buf data[]; | ||
47 | }; | ||
48 | |||
49 | struct vi_capture { | ||
50 | uint16_t channel_id; | ||
51 | struct device *rtcpu_dev; | ||
52 | struct tegra_channel *vi_channel; | ||
53 | struct vi_capture_buf requests; | ||
54 | uint32_t request_size; | ||
55 | |||
56 | uint32_t syncpts[CAPTURE_CHANNEL_MAX_NUM_SPS]; | ||
57 | |||
58 | struct completion control_resp; | ||
59 | struct completion capture_resp; | ||
60 | struct mutex control_msg_lock; | ||
61 | struct CAPTURE_CONTROL_MSG control_resp_msg; | ||
62 | |||
63 | struct mutex unpins_list_lock; | ||
64 | struct vi_capture_unpins *unpins_list; | ||
65 | }; | ||
66 | |||
67 | static void vi_capture_ivc_control_callback(const void *ivc_resp, | ||
68 | const void *pcontext) | ||
69 | { | ||
70 | const struct CAPTURE_CONTROL_MSG *control_msg = ivc_resp; | ||
71 | struct vi_capture *capture = (struct vi_capture *)pcontext; | ||
72 | struct tegra_channel *chan = capture->vi_channel; | ||
73 | |||
74 | if (unlikely(capture == NULL)) { | ||
75 | dev_err(chan->vi->dev, "%s: invalid context", __func__); | ||
76 | return; | ||
77 | } | ||
78 | |||
79 | if (unlikely(control_msg == NULL)) { | ||
80 | dev_err(chan->vi->dev, "%s: invalid response", __func__); | ||
81 | return; | ||
82 | } | ||
83 | |||
84 | switch (control_msg->header.msg_id) { | ||
85 | case CAPTURE_CHANNEL_SETUP_RESP: | ||
86 | case CAPTURE_CHANNEL_RESET_RESP: | ||
87 | case CAPTURE_CHANNEL_RELEASE_RESP: | ||
88 | case CAPTURE_COMPAND_CONFIG_RESP: | ||
89 | case CAPTURE_PDAF_CONFIG_RESP: | ||
90 | case CAPTURE_SYNCGEN_ENABLE_RESP: | ||
91 | case CAPTURE_SYNCGEN_DISABLE_RESP: | ||
92 | memcpy(&capture->control_resp_msg, control_msg, | ||
93 | sizeof(*control_msg)); | ||
94 | complete(&capture->control_resp); | ||
95 | break; | ||
96 | default: | ||
97 | dev_err(chan->vi->dev, | ||
98 | "%s: unknown capture control resp", __func__); | ||
99 | break; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | static void vi_capture_request_unpin(struct tegra_channel *chan, | ||
104 | uint32_t buffer_index); | ||
105 | static void vi_capture_ivc_status_callback(const void *ivc_resp, | ||
106 | const void *pcontext) | ||
107 | { | ||
108 | struct CAPTURE_MSG *status_msg = (struct CAPTURE_MSG *)ivc_resp; | ||
109 | struct vi_capture *capture = (struct vi_capture *)pcontext; | ||
110 | struct tegra_channel *chan = capture->vi_channel; | ||
111 | |||
112 | if (unlikely(capture == NULL)) { | ||
113 | dev_err(chan->vi->dev, "%s: invalid context", __func__); | ||
114 | return; | ||
115 | } | ||
116 | |||
117 | if (unlikely(status_msg == NULL)) { | ||
118 | dev_err(chan->vi->dev, "%s: invalid response", __func__); | ||
119 | return; | ||
120 | } | ||
121 | |||
122 | switch (status_msg->header.msg_id) { | ||
123 | case CAPTURE_STATUS_IND: | ||
124 | vi_capture_request_unpin(chan, | ||
125 | status_msg->capture_status_ind.buffer_index); | ||
126 | complete(&capture->capture_resp); | ||
127 | dev_dbg(chan->vi->dev, "%s: status chan_id %u msg_id %u\n", | ||
128 | __func__, status_msg->header.channel_id, | ||
129 | status_msg->header.msg_id); | ||
130 | break; | ||
131 | default: | ||
132 | dev_err(chan->vi->dev, | ||
133 | "%s: unknown capture resp", __func__); | ||
134 | break; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | int vi_capture_init(struct tegra_channel *chan) | ||
139 | { | ||
140 | struct vi_capture *capture; | ||
141 | struct device_node *dn; | ||
142 | struct platform_device *rtc_pdev; | ||
143 | |||
144 | dev_dbg(chan->vi->dev, "%s++\n", __func__); | ||
145 | dn = of_find_node_by_path("tegra-camera-rtcpu"); | ||
146 | if (of_device_is_available(dn) == 0) { | ||
147 | dev_err(chan->vi->dev, "failed to find rtcpu device node\n"); | ||
148 | return -ENODEV; | ||
149 | } | ||
150 | rtc_pdev = of_find_device_by_node(dn); | ||
151 | if (rtc_pdev == NULL) { | ||
152 | dev_err(chan->vi->dev, "failed to find rtcpu platform\n"); | ||
153 | return -ENODEV; | ||
154 | } | ||
155 | |||
156 | capture = devm_kzalloc(chan->vi->dev, | ||
157 | sizeof(*capture), GFP_KERNEL); | ||
158 | if (unlikely(capture == NULL)) { | ||
159 | dev_err(chan->vi->dev, "failed to allocate capture channel\n"); | ||
160 | return -ENOMEM; | ||
161 | } | ||
162 | |||
163 | capture->rtcpu_dev = &rtc_pdev->dev; | ||
164 | |||
165 | init_completion(&capture->control_resp); | ||
166 | init_completion(&capture->capture_resp); | ||
167 | |||
168 | mutex_init(&capture->control_msg_lock); | ||
169 | mutex_init(&capture->unpins_list_lock); | ||
170 | |||
171 | capture->vi_channel = chan; | ||
172 | chan->capture_data = capture; | ||
173 | |||
174 | capture->channel_id = CAPTURE_CHANNEL_INVALID_ID; | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | void vi_capture_shutdown(struct tegra_channel *chan) | ||
180 | { | ||
181 | struct vi_capture *capture = chan->capture_data; | ||
182 | |||
183 | dev_dbg(chan->vi->dev, "%s--\n", __func__); | ||
184 | if (capture == NULL) | ||
185 | return; | ||
186 | |||
187 | if (capture->channel_id != CAPTURE_CHANNEL_INVALID_ID) | ||
188 | vi_capture_release(chan, 0); | ||
189 | |||
190 | devm_kfree(chan->vi->dev, capture); | ||
191 | chan->capture_data = NULL; | ||
192 | } | ||
193 | |||
194 | static int vi_capture_ivc_send_control(struct tegra_channel *chan, | ||
195 | const struct CAPTURE_CONTROL_MSG *msg, size_t size, | ||
196 | uint32_t resp_id) | ||
197 | { | ||
198 | struct vi_capture *capture = chan->capture_data; | ||
199 | struct CAPTURE_MSG_HEADER resp_header = msg->header; | ||
200 | uint32_t timeout = HZ; | ||
201 | int err = 0; | ||
202 | |||
203 | dev_dbg(chan->vi->dev, "%s: sending chan_id %u msg_id %u\n", | ||
204 | __func__, resp_header.channel_id, resp_header.msg_id); | ||
205 | resp_header.msg_id = resp_id; | ||
206 | /* Send capture control IVC message */ | ||
207 | mutex_lock(&capture->control_msg_lock); | ||
208 | err = tegra_capture_ivc_control_submit(msg, size); | ||
209 | if (err < 0) { | ||
210 | dev_err(chan->vi->dev, "IVC control submit failed\n"); | ||
211 | goto fail; | ||
212 | } | ||
213 | |||
214 | timeout = wait_for_completion_killable_timeout( | ||
215 | &capture->control_resp, timeout); | ||
216 | if (timeout <= 0) { | ||
217 | dev_err(chan->vi->dev, | ||
218 | "no reply from camera processor\n"); | ||
219 | err = -ETIMEDOUT; | ||
220 | goto fail; | ||
221 | } | ||
222 | |||
223 | if (memcmp(&resp_header, &capture->control_resp_msg.header, | ||
224 | sizeof(resp_header)) != 0) { | ||
225 | dev_err(chan->vi->dev, | ||
226 | "unexpected response from camera processor\n"); | ||
227 | err = -EINVAL; | ||
228 | goto fail; | ||
229 | } | ||
230 | |||
231 | mutex_unlock(&capture->control_msg_lock); | ||
232 | dev_dbg(chan->vi->dev, "%s: response chan_id %u msg_id %u\n", | ||
233 | __func__, capture->control_resp_msg.header.channel_id, | ||
234 | capture->control_resp_msg.header.msg_id); | ||
235 | return 0; | ||
236 | |||
237 | fail: | ||
238 | mutex_unlock(&capture->control_msg_lock); | ||
239 | return err; | ||
240 | } | ||
241 | |||
242 | static int pin_memory(struct device *dev, | ||
243 | uint32_t mem, struct vi_capture_buf *unpin_data); | ||
244 | static void unpin_memory(struct vi_capture_buf *unpin_data); | ||
245 | |||
246 | static int pin_memory(struct device *dev, | ||
247 | uint32_t mem, struct vi_capture_buf *unpin_data) | ||
248 | { | ||
249 | struct dma_buf *buf; | ||
250 | struct dma_buf_attachment *attach; | ||
251 | struct sg_table *sgt; | ||
252 | int err = 0; | ||
253 | |||
254 | buf = dma_buf_get(mem); | ||
255 | if (IS_ERR(buf)) { | ||
256 | err = PTR_ERR(buf); | ||
257 | goto fail; | ||
258 | } | ||
259 | |||
260 | attach = dma_buf_attach(buf, dev); | ||
261 | if (IS_ERR(attach)) { | ||
262 | err = PTR_ERR(attach); | ||
263 | goto fail; | ||
264 | } | ||
265 | |||
266 | sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); | ||
267 | if (IS_ERR(sgt)) { | ||
268 | err = PTR_ERR(sgt); | ||
269 | goto fail; | ||
270 | } | ||
271 | |||
272 | if (sg_dma_address(sgt->sgl) == 0) | ||
273 | sg_dma_address(sgt->sgl) = sg_phys(sgt->sgl); | ||
274 | |||
275 | unpin_data->iova = sg_dma_address(sgt->sgl); | ||
276 | unpin_data->buf = buf; | ||
277 | unpin_data->attach = attach; | ||
278 | unpin_data->sgt = sgt; | ||
279 | |||
280 | return 0; | ||
281 | |||
282 | fail: | ||
283 | unpin_memory(unpin_data); | ||
284 | return err; | ||
285 | } | ||
286 | |||
287 | static void unpin_memory(struct vi_capture_buf *unpin_data) | ||
288 | { | ||
289 | if (unpin_data->sgt != NULL) | ||
290 | dma_buf_unmap_attachment(unpin_data->attach, unpin_data->sgt, | ||
291 | DMA_BIDIRECTIONAL); | ||
292 | if (unpin_data->attach != NULL) | ||
293 | dma_buf_detach(unpin_data->buf, unpin_data->attach); | ||
294 | if (unpin_data->buf != NULL) | ||
295 | dma_buf_put(unpin_data->buf); | ||
296 | |||
297 | unpin_data->sgt = NULL; | ||
298 | unpin_data->attach = NULL; | ||
299 | unpin_data->buf = NULL; | ||
300 | unpin_data->iova = 0; | ||
301 | } | ||
302 | |||
303 | static int vi_capture_setup_syncpts(struct tegra_channel *chan); | ||
304 | static void vi_capture_release_syncpts(struct tegra_channel *chan); | ||
305 | |||
306 | static int vi_capture_setup_syncpts(struct tegra_channel *chan) | ||
307 | { | ||
308 | struct vi_capture *capture = chan->capture_data; | ||
309 | int i; | ||
310 | int err = 0; | ||
311 | |||
312 | for (i = 0; i < CAPTURE_CHANNEL_MAX_NUM_SPS; i++) { | ||
313 | capture->syncpts[i] = nvhost_get_syncpt_client_managed( | ||
314 | chan->vi->ndev, "vi-capture"); | ||
315 | if (capture->syncpts[i] == 0) { | ||
316 | dev_err(chan->vi->dev, "failed to get syncpt %i!\n", i); | ||
317 | err = -ENODEV; | ||
318 | goto fail; | ||
319 | } | ||
320 | } | ||
321 | |||
322 | return 0; | ||
323 | |||
324 | fail: | ||
325 | vi_capture_release_syncpts(chan); | ||
326 | return err; | ||
327 | } | ||
328 | |||
329 | static void vi_capture_release_syncpts(struct tegra_channel *chan) | ||
330 | { | ||
331 | struct vi_capture *capture = chan->capture_data; | ||
332 | int i; | ||
333 | |||
334 | for (i = 0; i < CAPTURE_CHANNEL_MAX_NUM_SPS; i++) { | ||
335 | if (capture->syncpts[i] != 0) | ||
336 | nvhost_syncpt_put_ref_ext(chan->vi->ndev, | ||
337 | capture->syncpts[i]); | ||
338 | capture->syncpts[i] = 0; | ||
339 | } | ||
340 | } | ||
341 | |||
342 | int vi_capture_setup(struct tegra_channel *chan, | ||
343 | struct vi_capture_setup *setup) | ||
344 | { | ||
345 | struct vi_capture *capture = chan->capture_data; | ||
346 | uint32_t transaction; | ||
347 | struct CAPTURE_CONTROL_MSG control_desc; | ||
348 | struct CAPTURE_CONTROL_MSG *resp_msg = &capture->control_resp_msg; | ||
349 | struct capture_channel_config *config = | ||
350 | &control_desc.channel_setup_req.channel_config; | ||
351 | int err = 0; | ||
352 | |||
353 | if (capture == NULL) { | ||
354 | dev_err(chan->vi->dev, | ||
355 | "%s: vi capture uninitialized\n", __func__); | ||
356 | return -ENODEV; | ||
357 | } | ||
358 | |||
359 | if (capture->channel_id != CAPTURE_CHANNEL_INVALID_ID) { | ||
360 | dev_err(chan->vi->dev, | ||
361 | "%s: already setup, release first\n", __func__); | ||
362 | return -EEXIST; | ||
363 | } | ||
364 | |||
365 | dev_dbg(chan->vi->dev, "chan flags %u\n", setup->channel_flags); | ||
366 | dev_dbg(chan->vi->dev, "chan mask %llx\n", setup->vi_channel_mask); | ||
367 | dev_dbg(chan->vi->dev, "queue depth %u\n", setup->queue_depth); | ||
368 | dev_dbg(chan->vi->dev, "request size %u\n", setup->request_size); | ||
369 | |||
370 | if (setup->vi_channel_mask == CAPTURE_CHANNEL_INVALID_MASK || | ||
371 | setup->channel_flags == 0 || | ||
372 | setup->queue_depth == 0 || | ||
373 | setup->request_size == 0) | ||
374 | return -EINVAL; | ||
375 | |||
376 | /* pin the capture descriptor ring buffer */ | ||
377 | dev_dbg(chan->vi->dev, "%s: descr buffer handle %u\n", | ||
378 | __func__, setup->mem); | ||
379 | err = pin_memory(capture->rtcpu_dev, setup->mem, &capture->requests); | ||
380 | if (err < 0) { | ||
381 | dev_err(chan->vi->dev, "%s: memory setup failed\n", __func__); | ||
382 | return -EFAULT; | ||
383 | } | ||
384 | capture->request_size = setup->request_size; | ||
385 | |||
386 | /* allocate for unpin list based on queue depth */ | ||
387 | capture->unpins_list = devm_kzalloc(chan->vi->dev, | ||
388 | sizeof(struct vi_capture_unpins) * setup->queue_depth, | ||
389 | GFP_KERNEL); | ||
390 | if (unlikely(capture->unpins_list == NULL)) { | ||
391 | dev_err(chan->vi->dev, "failed to allocate unpins array\n"); | ||
392 | goto unpins_list_fail; | ||
393 | } | ||
394 | |||
395 | err = vi_capture_setup_syncpts(chan); | ||
396 | if (err < 0) { | ||
397 | dev_err(chan->vi->dev, "%s: syncpt setup failed\n", __func__); | ||
398 | goto syncpt_fail; | ||
399 | } | ||
400 | |||
401 | err = tegra_capture_ivc_register_control_cb( | ||
402 | &vi_capture_ivc_control_callback, | ||
403 | &transaction, capture); | ||
404 | if (err < 0) { | ||
405 | dev_err(chan->vi->dev, "failed to register control callback\n"); | ||
406 | goto control_cb_fail; | ||
407 | } | ||
408 | |||
409 | memset(&control_desc, 0, sizeof(control_desc)); | ||
410 | control_desc.header.msg_id = CAPTURE_CHANNEL_SETUP_REQ; | ||
411 | control_desc.header.transaction = transaction; | ||
412 | |||
413 | config->channel_flags = setup->channel_flags; | ||
414 | config->vi_channel_mask = setup->vi_channel_mask; | ||
415 | |||
416 | config->queue_depth = setup->queue_depth; | ||
417 | config->request_size = setup->request_size; | ||
418 | config->requests = capture->requests.iova; | ||
419 | |||
420 | config->progress_sp.id = capture->syncpts[PROGRESS_SP_IDX]; | ||
421 | config->embdata_sp.id = capture->syncpts[EMBDATA_SP_IDX]; | ||
422 | config->linetimer_sp.id = capture->syncpts[LINETIMER_SP_IDX]; | ||
423 | |||
424 | err = vi_capture_ivc_send_control(chan, &control_desc, | ||
425 | sizeof(control_desc), CAPTURE_CHANNEL_SETUP_RESP); | ||
426 | if (err < 0) | ||
427 | goto submit_fail; | ||
428 | |||
429 | if (resp_msg->channel_setup_resp.result != CAPTURE_OK) { | ||
430 | dev_err(chan->vi->dev, "%s: control failed, errno %d", __func__, | ||
431 | resp_msg->channel_setup_resp.result); | ||
432 | err = -EINVAL; | ||
433 | goto resp_fail; | ||
434 | } | ||
435 | |||
436 | capture->channel_id = resp_msg->channel_setup_resp.channel_id; | ||
437 | |||
438 | err = tegra_capture_ivc_notify_chan_id(capture->channel_id, | ||
439 | transaction); | ||
440 | if (err < 0) { | ||
441 | dev_err(chan->vi->dev, "failed to update control callback\n"); | ||
442 | goto cb_fail; | ||
443 | } | ||
444 | |||
445 | err = tegra_capture_ivc_register_capture_cb( | ||
446 | &vi_capture_ivc_status_callback, | ||
447 | capture->channel_id, capture); | ||
448 | if (err < 0) { | ||
449 | dev_err(chan->vi->dev, "failed to register capture callback\n"); | ||
450 | goto cb_fail; | ||
451 | } | ||
452 | |||
453 | return 0; | ||
454 | |||
455 | cb_fail: | ||
456 | vi_capture_release(chan, CAPTURE_CHANNEL_RESET_FLAG_IMMEDIATE); | ||
457 | resp_fail: | ||
458 | submit_fail: | ||
459 | tegra_capture_ivc_unregister_control_cb(transaction); | ||
460 | control_cb_fail: | ||
461 | vi_capture_release_syncpts(chan); | ||
462 | syncpt_fail: | ||
463 | devm_kfree(chan->vi->dev, capture->unpins_list); | ||
464 | unpins_list_fail: | ||
465 | unpin_memory(&capture->requests); | ||
466 | return err; | ||
467 | } | ||
468 | |||
469 | int vi_capture_reset(struct tegra_channel *chan, | ||
470 | uint32_t reset_flags) | ||
471 | { | ||
472 | struct vi_capture *capture = chan->capture_data; | ||
473 | struct CAPTURE_CONTROL_MSG control_desc; | ||
474 | struct CAPTURE_CONTROL_MSG *resp_msg = &capture->control_resp_msg; | ||
475 | int err = 0; | ||
476 | |||
477 | if (capture == NULL) { | ||
478 | dev_err(chan->vi->dev, | ||
479 | "%s: vi capture uninitialized\n", __func__); | ||
480 | return -ENODEV; | ||
481 | } | ||
482 | |||
483 | if (capture->channel_id == CAPTURE_CHANNEL_INVALID_ID) { | ||
484 | dev_err(chan->vi->dev, | ||
485 | "%s: setup channel first\n", __func__); | ||
486 | return -ENODEV; | ||
487 | } | ||
488 | |||
489 | memset(&control_desc, 0, sizeof(control_desc)); | ||
490 | control_desc.header.msg_id = CAPTURE_CHANNEL_RESET_REQ; | ||
491 | control_desc.header.channel_id = capture->channel_id; | ||
492 | control_desc.channel_reset_req.reset_flags = reset_flags; | ||
493 | |||
494 | err = vi_capture_ivc_send_control(chan, &control_desc, | ||
495 | sizeof(control_desc), CAPTURE_CHANNEL_RESET_RESP); | ||
496 | if (err < 0) | ||
497 | goto submit_fail; | ||
498 | |||
499 | if (resp_msg->channel_reset_resp.result != CAPTURE_OK) { | ||
500 | dev_err(chan->vi->dev, "%s: control failed, errno %d", __func__, | ||
501 | resp_msg->channel_reset_resp.result); | ||
502 | err = -EINVAL; | ||
503 | } | ||
504 | |||
505 | return 0; | ||
506 | |||
507 | submit_fail: | ||
508 | return err; | ||
509 | } | ||
510 | |||
511 | int vi_capture_release(struct tegra_channel *chan, | ||
512 | uint32_t reset_flags) | ||
513 | { | ||
514 | struct vi_capture *capture = chan->capture_data; | ||
515 | struct CAPTURE_CONTROL_MSG control_desc; | ||
516 | struct CAPTURE_CONTROL_MSG *resp_msg = &capture->control_resp_msg; | ||
517 | int err = 0; | ||
518 | int ret = 0; | ||
519 | |||
520 | if (capture == NULL) { | ||
521 | dev_err(chan->vi->dev, | ||
522 | "%s: vi capture uninitialized\n", __func__); | ||
523 | return -ENODEV; | ||
524 | } | ||
525 | |||
526 | if (capture->channel_id == CAPTURE_CHANNEL_INVALID_ID) { | ||
527 | dev_err(chan->vi->dev, | ||
528 | "%s: setup channel first\n", __func__); | ||
529 | return -ENODEV; | ||
530 | } | ||
531 | |||
532 | memset(&control_desc, 0, sizeof(control_desc)); | ||
533 | control_desc.header.msg_id = CAPTURE_CHANNEL_RELEASE_REQ; | ||
534 | control_desc.header.channel_id = capture->channel_id; | ||
535 | control_desc.channel_release_req.reset_flags = reset_flags; | ||
536 | |||
537 | err = vi_capture_ivc_send_control(chan, &control_desc, | ||
538 | sizeof(control_desc), CAPTURE_CHANNEL_RELEASE_RESP); | ||
539 | if (err < 0) | ||
540 | goto submit_fail; | ||
541 | |||
542 | if (resp_msg->channel_release_resp.result != CAPTURE_OK) { | ||
543 | dev_err(chan->vi->dev, "%s: control failed, errno %d", __func__, | ||
544 | resp_msg->channel_release_resp.result); | ||
545 | err = -EINVAL; | ||
546 | } | ||
547 | |||
548 | vi_capture_release_syncpts(chan); | ||
549 | unpin_memory(&capture->requests); | ||
550 | |||
551 | ret = tegra_capture_ivc_unregister_capture_cb(capture->channel_id); | ||
552 | if (ret < 0 && err == 0) { | ||
553 | dev_err(chan->vi->dev, | ||
554 | "failed to unregister capture callback\n"); | ||
555 | err = ret; | ||
556 | } | ||
557 | |||
558 | ret = tegra_capture_ivc_unregister_control_cb(capture->channel_id); | ||
559 | if (ret < 0 && err == 0) { | ||
560 | dev_err(chan->vi->dev, | ||
561 | "failed to unregister control callback\n"); | ||
562 | err = ret; | ||
563 | } | ||
564 | |||
565 | capture->channel_id = CAPTURE_CHANNEL_INVALID_ID; | ||
566 | |||
567 | return 0; | ||
568 | |||
569 | submit_fail: | ||
570 | return err; | ||
571 | } | ||
572 | |||
573 | int vi_capture_get_info(struct tegra_channel *chan, | ||
574 | struct vi_capture_info *info) | ||
575 | { | ||
576 | struct vi_capture *capture = chan->capture_data; | ||
577 | |||
578 | if (capture == NULL) { | ||
579 | dev_err(chan->vi->dev, | ||
580 | "%s: vi capture uninitialized\n", __func__); | ||
581 | return -ENODEV; | ||
582 | } | ||
583 | |||
584 | if (capture->channel_id == CAPTURE_CHANNEL_INVALID_ID) { | ||
585 | dev_err(chan->vi->dev, | ||
586 | "%s: setup channel first\n", __func__); | ||
587 | return -ENODEV; | ||
588 | } | ||
589 | |||
590 | if (info == NULL) | ||
591 | return -EINVAL; | ||
592 | |||
593 | info->syncpts.progress_syncpt = capture->syncpts[PROGRESS_SP_IDX]; | ||
594 | info->syncpts.emb_data_syncpt = capture->syncpts[EMBDATA_SP_IDX]; | ||
595 | info->syncpts.line_timer_syncpt = capture->syncpts[LINETIMER_SP_IDX]; | ||
596 | |||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | int vi_capture_control_message(struct tegra_channel *chan, | ||
601 | struct vi_capture_control_msg *msg) | ||
602 | { | ||
603 | struct vi_capture *capture = chan->capture_data; | ||
604 | const void __user *msg_ptr = | ||
605 | (const void __user *)(uintptr_t)msg->ptr; | ||
606 | void __user *response = | ||
607 | (void __user *)(uintptr_t)msg->response; | ||
608 | void *msg_cpy; | ||
609 | struct CAPTURE_MSG_HEADER *header; | ||
610 | uint32_t resp_id; | ||
611 | struct CAPTURE_CONTROL_MSG *resp_msg = &capture->control_resp_msg; | ||
612 | int err = 0; | ||
613 | |||
614 | if (capture == NULL) { | ||
615 | dev_err(chan->vi->dev, | ||
616 | "%s: vi capture uninitialized\n", __func__); | ||
617 | return -ENODEV; | ||
618 | } | ||
619 | |||
620 | if (msg->ptr == 0ull || msg->response == 0ull || msg->size == 0) | ||
621 | return -EINVAL; | ||
622 | |||
623 | msg_cpy = devm_kzalloc(chan->vi->dev, msg->size, GFP_KERNEL); | ||
624 | if (unlikely(msg_cpy == NULL)) | ||
625 | return -ENOMEM; | ||
626 | |||
627 | err = copy_from_user(msg_cpy, msg_ptr, msg->size) ? -EFAULT : 0; | ||
628 | if (err < 0) | ||
629 | goto fail; | ||
630 | header = (struct CAPTURE_MSG_HEADER *)msg_cpy; | ||
631 | header->channel_id = capture->channel_id; | ||
632 | |||
633 | switch (header->msg_id) { | ||
634 | case CAPTURE_COMPAND_CONFIG_REQ: | ||
635 | resp_id = CAPTURE_COMPAND_CONFIG_RESP; | ||
636 | break; | ||
637 | case CAPTURE_PDAF_CONFIG_REQ: | ||
638 | resp_id = CAPTURE_PDAF_CONFIG_RESP; | ||
639 | break; | ||
640 | case CAPTURE_SYNCGEN_ENABLE_REQ: | ||
641 | resp_id = CAPTURE_SYNCGEN_ENABLE_RESP; | ||
642 | break; | ||
643 | case CAPTURE_SYNCGEN_DISABLE_REQ: | ||
644 | resp_id = CAPTURE_SYNCGEN_DISABLE_RESP; | ||
645 | break; | ||
646 | default: | ||
647 | dev_err(chan->vi->dev, | ||
648 | "%s: unknown capture control resp", __func__); | ||
649 | err = -EINVAL; | ||
650 | goto fail; | ||
651 | } | ||
652 | |||
653 | err = vi_capture_ivc_send_control(chan, msg_cpy, msg->size, resp_id); | ||
654 | if (err < 0) | ||
655 | goto fail; | ||
656 | |||
657 | err = copy_to_user(response, resp_msg, | ||
658 | sizeof(*resp_msg)) ? -EFAULT : 0; | ||
659 | |||
660 | fail: | ||
661 | devm_kfree(chan->vi->dev, msg_cpy); | ||
662 | return err; | ||
663 | } | ||
664 | |||
665 | struct surface_t { | ||
666 | uint32_t offset; | ||
667 | uint32_t offset_hi; | ||
668 | }; | ||
669 | |||
670 | static int vi_capture_request_pin_and_reloc(struct tegra_channel *chan, | ||
671 | struct vi_capture_req *req) | ||
672 | { | ||
673 | struct vi_capture *capture = chan->capture_data; | ||
674 | uint32_t num_relocs = req->num_relocs; | ||
675 | uint32_t __user *reloc_relatives = | ||
676 | (uint32_t __user *)(uintptr_t)req->reloc_relatives; | ||
677 | uint32_t local_reloc_relatives[num_relocs]; | ||
678 | struct vi_capture_unpins *unpins; | ||
679 | uint32_t request_offset = req->buffer_index * capture->request_size; | ||
680 | void *reloc_page_addr = NULL; | ||
681 | uint32_t prev_mem = 0; | ||
682 | int last_page = -1; | ||
683 | dma_addr_t surface_phys_addr = 0; | ||
684 | dma_addr_t surface_prev_addr = 0; | ||
685 | int i, pin_count = 0; | ||
686 | int err = 0; | ||
687 | |||
688 | err = copy_from_user(local_reloc_relatives, reloc_relatives, | ||
689 | num_relocs * sizeof(uint32_t)) ? -EFAULT : 0; | ||
690 | if (err < 0) | ||
691 | return err; | ||
692 | |||
693 | unpins = devm_kzalloc(chan->vi->dev, | ||
694 | sizeof(struct vi_capture_unpins) + | ||
695 | sizeof(struct vi_capture_buf) * num_relocs, | ||
696 | GFP_KERNEL); | ||
697 | if (unpins == NULL) | ||
698 | return -ENOMEM; | ||
699 | |||
700 | dev_dbg(chan->vi->dev, "%s: relocating %u surfaces\n", | ||
701 | __func__, num_relocs); | ||
702 | for (i = 0; i < num_relocs; i++) { | ||
703 | uint32_t reloc_offset = | ||
704 | request_offset + local_reloc_relatives[i]; | ||
705 | uint64_t surface_raw; | ||
706 | struct surface_t *surface; | ||
707 | uint32_t mem; | ||
708 | uint32_t target_offset; | ||
709 | dma_addr_t target_phys_addr; | ||
710 | |||
711 | dev_dbg(chan->vi->dev, | ||
712 | "%s: idx:%i reloc:%u reloc_offset:%u", __func__, | ||
713 | i, local_reloc_relatives[i], reloc_offset); | ||
714 | |||
715 | /* locate page of the request descr buffer relocation is on */ | ||
716 | if (last_page != reloc_offset >> PAGE_SHIFT) { | ||
717 | if (reloc_page_addr != NULL) | ||
718 | dma_buf_kunmap(capture->requests.buf, last_page, | ||
719 | reloc_page_addr); | ||
720 | |||
721 | reloc_page_addr = dma_buf_kmap(capture->requests.buf, | ||
722 | reloc_offset >> PAGE_SHIFT); | ||
723 | last_page = reloc_offset >> PAGE_SHIFT; | ||
724 | |||
725 | if (unlikely(reloc_page_addr == NULL)) { | ||
726 | dev_err(chan->vi->dev, | ||
727 | "%s: couldn't map request\n", __func__); | ||
728 | goto fail; | ||
729 | } | ||
730 | } | ||
731 | |||
732 | /* read surface offset and memory handle from request descr */ | ||
733 | surface_raw = __raw_readq( | ||
734 | (void __iomem *)(reloc_page_addr + | ||
735 | (reloc_offset & ~PAGE_MASK))); | ||
736 | surface = (struct surface_t *)&surface_raw; | ||
737 | target_offset = surface->offset; | ||
738 | mem = surface->offset_hi; | ||
739 | dev_dbg(chan->vi->dev, "%s: hmem:%u offset:%u\n", __func__, | ||
740 | target_offset, mem); | ||
741 | |||
742 | if (mem != prev_mem) { | ||
743 | err = pin_memory(capture->rtcpu_dev, | ||
744 | mem, &unpins->data[pin_count]); | ||
745 | if (err < 0) { | ||
746 | unpins->num_unpins = pin_count; | ||
747 | goto fail; | ||
748 | } | ||
749 | surface_prev_addr = unpins->data[i].iova; | ||
750 | surface_phys_addr = unpins->data[i].iova; | ||
751 | |||
752 | mutex_lock(&capture->unpins_list_lock); | ||
753 | memcpy(&capture->unpins_list[req->buffer_index], | ||
754 | unpins, sizeof(*unpins)); | ||
755 | mutex_unlock(&capture->unpins_list_lock); | ||
756 | |||
757 | pin_count++; | ||
758 | } else | ||
759 | surface_phys_addr = surface_prev_addr; | ||
760 | |||
761 | target_phys_addr = surface_phys_addr + target_offset; | ||
762 | /* write relocated physical address to request descr */ | ||
763 | __raw_writeq( | ||
764 | target_phys_addr, | ||
765 | (void __iomem *)(reloc_page_addr + | ||
766 | (reloc_offset & ~PAGE_MASK))); | ||
767 | } | ||
768 | |||
769 | unpins->num_unpins = pin_count; | ||
770 | |||
771 | return 0; | ||
772 | |||
773 | fail: | ||
774 | if (reloc_page_addr != NULL) | ||
775 | dma_buf_kunmap(capture->requests.buf, last_page, | ||
776 | reloc_page_addr); | ||
777 | |||
778 | for (i = 0; i < unpins->num_unpins; i++) | ||
779 | unpin_memory(&unpins->data[i]); | ||
780 | devm_kfree(chan->vi->dev, unpins); | ||
781 | |||
782 | return err; | ||
783 | } | ||
784 | |||
785 | static void vi_capture_request_unpin(struct tegra_channel *chan, | ||
786 | uint32_t buffer_index) | ||
787 | { | ||
788 | struct vi_capture *capture = chan->capture_data; | ||
789 | struct vi_capture_unpins *unpins; | ||
790 | int i = 0; | ||
791 | |||
792 | mutex_lock(&capture->unpins_list_lock); | ||
793 | unpins = &capture->unpins_list[buffer_index]; | ||
794 | for (i = 0; i < unpins->num_unpins; i++) | ||
795 | unpin_memory(&unpins->data[i]); | ||
796 | unpins->num_unpins = 0u; | ||
797 | mutex_unlock(&capture->unpins_list_lock); | ||
798 | } | ||
799 | |||
800 | int vi_capture_request(struct tegra_channel *chan, | ||
801 | struct vi_capture_req *req) | ||
802 | { | ||
803 | struct vi_capture *capture = chan->capture_data; | ||
804 | struct CAPTURE_MSG capture_desc; | ||
805 | int err = 0; | ||
806 | |||
807 | if (capture == NULL) { | ||
808 | dev_err(chan->vi->dev, | ||
809 | "%s: vi capture uninitialized\n", __func__); | ||
810 | return -ENODEV; | ||
811 | } | ||
812 | |||
813 | if (capture->channel_id == CAPTURE_CHANNEL_INVALID_ID) { | ||
814 | dev_err(chan->vi->dev, | ||
815 | "%s: setup channel first\n", __func__); | ||
816 | return -ENODEV; | ||
817 | } | ||
818 | |||
819 | memset(&capture_desc, 0, sizeof(capture_desc)); | ||
820 | capture_desc.header.msg_id = CAPTURE_REQUEST_REQ; | ||
821 | capture_desc.header.channel_id = capture->channel_id; | ||
822 | capture_desc.capture_request_req.buffer_index = req->buffer_index; | ||
823 | |||
824 | /* perform surface pinning and relocation */ | ||
825 | err = vi_capture_request_pin_and_reloc(chan, req); | ||
826 | if (err < 0) { | ||
827 | dev_err(chan->vi->dev, "relocation failed\n"); | ||
828 | return err; | ||
829 | } | ||
830 | |||
831 | dev_dbg(chan->vi->dev, "%s: sending chan_id %u msg_id %u buf:%u\n", | ||
832 | __func__, capture_desc.header.channel_id, | ||
833 | capture_desc.header.msg_id, req->buffer_index); | ||
834 | err = tegra_capture_ivc_capture_submit(&capture_desc, | ||
835 | sizeof(capture_desc)); | ||
836 | if (err < 0) { | ||
837 | dev_err(chan->vi->dev, "IVC capture submit failed\n"); | ||
838 | goto fail; | ||
839 | } | ||
840 | |||
841 | return 0; | ||
842 | |||
843 | fail: | ||
844 | vi_capture_request_unpin(chan, req->buffer_index); | ||
845 | return err; | ||
846 | } | ||
847 | |||
848 | int vi_capture_status(struct tegra_channel *chan, | ||
849 | int32_t timeout_ms) | ||
850 | { | ||
851 | struct vi_capture *capture = chan->capture_data; | ||
852 | int ret = 0; | ||
853 | int err = 0; | ||
854 | |||
855 | if (capture == NULL) { | ||
856 | dev_err(chan->vi->dev, | ||
857 | "%s: vi capture uninitialized\n", __func__); | ||
858 | return -ENODEV; | ||
859 | } | ||
860 | |||
861 | if (capture->channel_id == CAPTURE_CHANNEL_INVALID_ID) { | ||
862 | dev_err(chan->vi->dev, | ||
863 | "%s: setup channel first\n", __func__); | ||
864 | return -ENODEV; | ||
865 | } | ||
866 | |||
867 | dev_dbg(chan->vi->dev, "%s: waiting for status, timeout:%d ms\n", | ||
868 | __func__, timeout_ms); | ||
869 | |||
870 | ret = wait_for_completion_killable_timeout( | ||
871 | &capture->capture_resp, | ||
872 | (unsigned long)(timeout_ms/1000*HZ)); | ||
873 | if (ret <= 0) { | ||
874 | dev_err(chan->vi->dev, | ||
875 | "no reply from camera processor\n"); | ||
876 | return -ETIMEDOUT; | ||
877 | } | ||
878 | |||
879 | return err; | ||
880 | } | ||
diff --git a/drivers/media/platform/tegra/camera/vi/channel.c b/drivers/media/platform/tegra/camera/vi/channel.c new file mode 100644 index 000000000..5c8e066be --- /dev/null +++ b/drivers/media/platform/tegra/camera/vi/channel.c | |||
@@ -0,0 +1,1650 @@ | |||
1 | /* | ||
2 | * NVIDIA Tegra Video Input Device | ||
3 | * | ||
4 | * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * Author: Bryan Wu <pengw@nvidia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/atomic.h> | ||
14 | #include <linux/bitmap.h> | ||
15 | #include <linux/clk.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/nvhost.h> | ||
18 | #include <linux/lcm.h> | ||
19 | #include <linux/list.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/of.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/slab.h> | ||
24 | |||
25 | #include <media/v4l2-ctrls.h> | ||
26 | #include <media/v4l2-event.h> | ||
27 | #include <media/v4l2-dev.h> | ||
28 | #include <media/v4l2-fh.h> | ||
29 | #include <media/v4l2-ioctl.h> | ||
30 | #include <media/videobuf2-core.h> | ||
31 | #include <media/videobuf2-dma-contig.h> | ||
32 | #include <media/camera_common.h> | ||
33 | #include <media/tegra_camera_platform.h> | ||
34 | #include <media/v4l2-dv-timings.h> | ||
35 | |||
36 | #include <linux/clk/tegra.h> | ||
37 | |||
38 | #include "mc_common.h" | ||
39 | #include "vi/vi.h" | ||
40 | #include "mipical/mipi_cal.h" | ||
41 | |||
42 | #define TPG_CSI_GROUP_ID 10 | ||
43 | |||
44 | static void gang_buffer_offsets(struct tegra_channel *chan) | ||
45 | { | ||
46 | int i; | ||
47 | u32 offset = 0; | ||
48 | |||
49 | for (i = 0; i < chan->total_ports; i++) { | ||
50 | switch (chan->gang_mode) { | ||
51 | case CAMERA_NO_GANG_MODE: | ||
52 | case CAMERA_GANG_L_R: | ||
53 | case CAMERA_GANG_R_L: | ||
54 | offset = chan->gang_bytesperline; | ||
55 | break; | ||
56 | case CAMERA_GANG_T_B: | ||
57 | case CAMERA_GANG_B_T: | ||
58 | offset = chan->gang_sizeimage; | ||
59 | break; | ||
60 | default: | ||
61 | offset = 0; | ||
62 | } | ||
63 | offset = ((offset + TEGRA_SURFACE_ALIGNMENT - 1) & | ||
64 | ~(TEGRA_SURFACE_ALIGNMENT - 1)); | ||
65 | chan->buffer_offset[i] = i * offset; | ||
66 | } | ||
67 | } | ||
68 | |||
69 | static u32 gang_mode_width(enum camera_gang_mode gang_mode, | ||
70 | unsigned int width) | ||
71 | { | ||
72 | if ((gang_mode == CAMERA_GANG_L_R) || | ||
73 | (gang_mode == CAMERA_GANG_R_L)) | ||
74 | return width >> 1; | ||
75 | else | ||
76 | return width; | ||
77 | } | ||
78 | |||
79 | static u32 gang_mode_height(enum camera_gang_mode gang_mode, | ||
80 | unsigned int height) | ||
81 | { | ||
82 | if ((gang_mode == CAMERA_GANG_T_B) || | ||
83 | (gang_mode == CAMERA_GANG_B_T)) | ||
84 | return height >> 1; | ||
85 | else | ||
86 | return height; | ||
87 | } | ||
88 | |||
89 | static void update_gang_mode_params(struct tegra_channel *chan) | ||
90 | { | ||
91 | chan->gang_width = gang_mode_width(chan->gang_mode, | ||
92 | chan->format.width); | ||
93 | chan->gang_height = gang_mode_height(chan->gang_mode, | ||
94 | chan->format.height); | ||
95 | chan->gang_bytesperline = ((chan->gang_width * | ||
96 | chan->fmtinfo->bpp.numerator) / | ||
97 | chan->fmtinfo->bpp.denominator); | ||
98 | chan->gang_sizeimage = chan->gang_bytesperline * | ||
99 | chan->format.height; | ||
100 | gang_buffer_offsets(chan); | ||
101 | } | ||
102 | |||
103 | static void update_gang_mode(struct tegra_channel *chan) | ||
104 | { | ||
105 | int width = chan->format.width; | ||
106 | int height = chan->format.height; | ||
107 | |||
108 | /* | ||
109 | * At present only 720p, 1080p and 4k resolutions | ||
110 | * are supported and only 4K requires gang mode | ||
111 | * Update this code with CID for future extensions | ||
112 | * Also, validate width and height of images based | ||
113 | * on gang mode and surface stride alignment | ||
114 | */ | ||
115 | if ((width > 1920) && (height > 1080)) { | ||
116 | chan->gang_mode = CAMERA_GANG_L_R; | ||
117 | chan->valid_ports = chan->total_ports; | ||
118 | } else { | ||
119 | chan->gang_mode = CAMERA_NO_GANG_MODE; | ||
120 | chan->valid_ports = 1; | ||
121 | } | ||
122 | |||
123 | update_gang_mode_params(chan); | ||
124 | } | ||
125 | |||
126 | static u32 get_aligned_buffer_size(struct tegra_channel *chan, | ||
127 | u32 bytesperline, u32 height) | ||
128 | { | ||
129 | u32 height_aligned; | ||
130 | u32 temp_size, size; | ||
131 | |||
132 | height_aligned = roundup(height, chan->height_align); | ||
133 | temp_size = bytesperline * height_aligned; | ||
134 | size = roundup(temp_size, chan->size_align); | ||
135 | |||
136 | return size; | ||
137 | } | ||
138 | |||
139 | static void tegra_channel_fmt_align(struct tegra_channel *chan, | ||
140 | const struct tegra_video_format *vfmt, | ||
141 | u32 *width, u32 *height, u32 *bytesperline) | ||
142 | { | ||
143 | unsigned int min_width; | ||
144 | unsigned int max_width; | ||
145 | unsigned int min_bpl; | ||
146 | unsigned int max_bpl; | ||
147 | unsigned int temp_width; | ||
148 | unsigned int align, fmt_align; | ||
149 | unsigned int temp_bpl; | ||
150 | unsigned int bpl; | ||
151 | unsigned int numerator, denominator; | ||
152 | const struct tegra_frac *bpp = &vfmt->bpp; | ||
153 | |||
154 | /* Init, if un-init */ | ||
155 | if (!*width || !*height) { | ||
156 | *width = chan->format.width; | ||
157 | *height = chan->format.height; | ||
158 | } | ||
159 | |||
160 | denominator = (!bpp->denominator) ? 1 : bpp->denominator; | ||
161 | numerator = (!bpp->numerator) ? 1 : bpp->numerator; | ||
162 | |||
163 | bpl = (*width * numerator) / denominator; | ||
164 | if (!*bytesperline) | ||
165 | *bytesperline = bpl; | ||
166 | |||
167 | /* The transfer alignment requirements are expressed in bytes. Compute | ||
168 | * the minimum and maximum values, clamp the requested width and convert | ||
169 | * it back to pixels. | ||
170 | * use denominator for base width alignment when >1. | ||
171 | * use bytesperline to adjust width for applicaton related requriements. | ||
172 | */ | ||
173 | fmt_align = (denominator == 1) ? numerator : 1; | ||
174 | align = lcm(chan->width_align, fmt_align); | ||
175 | min_width = roundup(TEGRA_MIN_WIDTH, align); | ||
176 | max_width = rounddown(TEGRA_MAX_WIDTH, align); | ||
177 | temp_width = roundup(bpl, align); | ||
178 | |||
179 | *width = (clamp(temp_width, min_width, max_width) * denominator) / | ||
180 | numerator; | ||
181 | *height = clamp(*height, TEGRA_MIN_HEIGHT, TEGRA_MAX_HEIGHT); | ||
182 | |||
183 | /* Clamp the requested bytes per line value. If the maximum bytes per | ||
184 | * line value is zero, the module doesn't support user configurable line | ||
185 | * sizes. Override the requested value with the minimum in that case. | ||
186 | */ | ||
187 | min_bpl = bpl; | ||
188 | max_bpl = rounddown(TEGRA_MAX_WIDTH, chan->stride_align); | ||
189 | temp_bpl = roundup(*bytesperline, chan->stride_align); | ||
190 | |||
191 | *bytesperline = clamp(temp_bpl, min_bpl, max_bpl); | ||
192 | } | ||
193 | |||
194 | static void tegra_channel_update_format(struct tegra_channel *chan, | ||
195 | u32 width, u32 height, u32 fourcc, | ||
196 | const struct tegra_frac *bpp, | ||
197 | u32 preferred_stride) | ||
198 | { | ||
199 | u32 denominator = (!bpp->denominator) ? 1 : bpp->denominator; | ||
200 | u32 numerator = (!bpp->numerator) ? 1 : bpp->numerator; | ||
201 | u32 bytesperline = (width * numerator / denominator); | ||
202 | |||
203 | chan->format.width = width; | ||
204 | chan->format.height = height; | ||
205 | chan->format.pixelformat = fourcc; | ||
206 | chan->format.bytesperline = preferred_stride ?: bytesperline; | ||
207 | |||
208 | tegra_channel_fmt_align(chan, chan->fmtinfo, | ||
209 | &chan->format.width, | ||
210 | &chan->format.height, | ||
211 | &chan->format.bytesperline); | ||
212 | |||
213 | /* Calculate the sizeimage per plane */ | ||
214 | chan->format.sizeimage = get_aligned_buffer_size(chan, | ||
215 | chan->format.bytesperline, chan->format.height); | ||
216 | |||
217 | if (fourcc == V4L2_PIX_FMT_NV16) | ||
218 | chan->format.sizeimage *= 2; | ||
219 | } | ||
220 | |||
221 | static void tegra_channel_fmts_bitmap_init(struct tegra_channel *chan) | ||
222 | { | ||
223 | int ret, pixel_format_index = 0, init_code = 0; | ||
224 | struct v4l2_subdev *subdev = chan->subdev_on_csi; | ||
225 | struct v4l2_subdev_format fmt = {}; | ||
226 | struct v4l2_subdev_mbus_code_enum code = { | ||
227 | .which = V4L2_SUBDEV_FORMAT_ACTIVE, | ||
228 | }; | ||
229 | |||
230 | bitmap_zero(chan->fmts_bitmap, MAX_FORMAT_NUM); | ||
231 | |||
232 | /* | ||
233 | * Initialize all the formats available from | ||
234 | * the sub-device and extract the corresponding | ||
235 | * index from the pre-defined video formats and initialize | ||
236 | * the channel default format with the active code | ||
237 | * Index zero as the only sub-device is sensor | ||
238 | */ | ||
239 | while (1) { | ||
240 | ret = v4l2_subdev_call(subdev, pad, enum_mbus_code, | ||
241 | NULL, &code); | ||
242 | if (ret < 0) | ||
243 | /* no more formats */ | ||
244 | break; | ||
245 | |||
246 | pixel_format_index = | ||
247 | tegra_core_get_idx_by_code(chan, code.code, 0); | ||
248 | while (pixel_format_index >= 0) { | ||
249 | bitmap_set(chan->fmts_bitmap, pixel_format_index, 1); | ||
250 | /* Set init_code to the first matched format */ | ||
251 | if (!init_code) | ||
252 | init_code = code.code; | ||
253 | /* Look for other formats with the same mbus code */ | ||
254 | pixel_format_index = tegra_core_get_idx_by_code(chan, | ||
255 | code.code, pixel_format_index + 1); | ||
256 | } | ||
257 | |||
258 | code.index++; | ||
259 | } | ||
260 | |||
261 | if (!init_code) { | ||
262 | pixel_format_index = | ||
263 | tegra_core_get_idx_by_code(chan, TEGRA_VF_DEF, 0); | ||
264 | if (pixel_format_index >= 0) { | ||
265 | bitmap_set(chan->fmts_bitmap, pixel_format_index, 1); | ||
266 | init_code = TEGRA_VF_DEF; | ||
267 | } | ||
268 | } | ||
269 | /* Get the format based on active code of the sub-device */ | ||
270 | ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); | ||
271 | if (ret) | ||
272 | return; | ||
273 | |||
274 | /* Initiate the channel format to the first matched format */ | ||
275 | chan->fmtinfo = | ||
276 | tegra_core_get_format_by_code(chan, fmt.format.code, 0); | ||
277 | v4l2_fill_pix_format(&chan->format, &fmt.format); | ||
278 | tegra_channel_update_format(chan, chan->format.width, | ||
279 | chan->format.height, | ||
280 | chan->fmtinfo->fourcc, | ||
281 | &chan->fmtinfo->bpp, 0); | ||
282 | |||
283 | if (chan->total_ports > 1) | ||
284 | update_gang_mode(chan); | ||
285 | } | ||
286 | |||
287 | /* | ||
288 | * ----------------------------------------------------------------------------- | ||
289 | * Tegra channel frame setup and capture operations | ||
290 | * ----------------------------------------------------------------------------- | ||
291 | */ | ||
292 | |||
293 | void tegra_channel_init_ring_buffer(struct tegra_channel *chan) | ||
294 | { | ||
295 | chan->released_bufs = 0; | ||
296 | chan->num_buffers = 0; | ||
297 | chan->save_index = 0; | ||
298 | chan->free_index = 0; | ||
299 | chan->bfirst_fstart = false; | ||
300 | } | ||
301 | |||
302 | void free_ring_buffers(struct tegra_channel *chan, int frames) | ||
303 | { | ||
304 | struct vb2_v4l2_buffer *vbuf; | ||
305 | |||
306 | while (frames) { | ||
307 | vbuf = chan->buffers[chan->free_index]; | ||
308 | |||
309 | /* release one frame */ | ||
310 | vbuf->sequence = chan->sequence++; | ||
311 | vbuf->field = V4L2_FIELD_NONE; | ||
312 | vb2_set_plane_payload(&vbuf->vb2_buf, | ||
313 | 0, chan->format.sizeimage); | ||
314 | |||
315 | /* | ||
316 | * WAR to force buffer state if capture state is not good | ||
317 | * WAR - After sync point timeout or error frame capture | ||
318 | * the second buffer is intermittently frame of zeros | ||
319 | * with no error status or padding. | ||
320 | */ | ||
321 | #if 0 | ||
322 | /* This will drop the first two frames. Disable for now. */ | ||
323 | if (chan->capture_state != CAPTURE_GOOD || | ||
324 | chan->released_bufs < 2) | ||
325 | chan->buffer_state[chan->free_index] = | ||
326 | VB2_BUF_STATE_ERROR; | ||
327 | #endif | ||
328 | vb2_buffer_done(&vbuf->vb2_buf, | ||
329 | chan->buffer_state[chan->free_index++]); | ||
330 | |||
331 | if (chan->free_index >= QUEUED_BUFFERS) | ||
332 | chan->free_index = 0; | ||
333 | chan->num_buffers--; | ||
334 | chan->released_bufs++; | ||
335 | frames--; | ||
336 | } | ||
337 | } | ||
338 | |||
339 | static void add_buffer_to_ring(struct tegra_channel *chan, | ||
340 | struct vb2_v4l2_buffer *vb) | ||
341 | { | ||
342 | /* save the buffer to the ring first */ | ||
343 | /* Mark buffer state as error before start */ | ||
344 | chan->buffer_state[chan->save_index] = VB2_BUF_STATE_ERROR; | ||
345 | chan->buffers[chan->save_index++] = vb; | ||
346 | if (chan->save_index >= QUEUED_BUFFERS) | ||
347 | chan->save_index = 0; | ||
348 | chan->num_buffers++; | ||
349 | } | ||
350 | |||
351 | static void update_state_to_buffer(struct tegra_channel *chan, int state) | ||
352 | { | ||
353 | int save_index = (chan->save_index - PREVIOUS_BUFFER_DEC_INDEX); | ||
354 | |||
355 | /* save index decrements by 2 as 3 bufs are added in ring buffer */ | ||
356 | if (save_index < 0) | ||
357 | save_index += QUEUED_BUFFERS; | ||
358 | /* update state for the previous buffer */ | ||
359 | chan->buffer_state[save_index] = state; | ||
360 | |||
361 | /* for timeout/error case update the current buffer state as well */ | ||
362 | if (chan->capture_state != CAPTURE_GOOD) | ||
363 | chan->buffer_state[chan->save_index] = state; | ||
364 | } | ||
365 | |||
366 | void tegra_channel_ring_buffer(struct tegra_channel *chan, | ||
367 | struct vb2_v4l2_buffer *vb, | ||
368 | struct timespec *ts, int state) | ||
369 | |||
370 | { | ||
371 | if (!chan->bfirst_fstart) | ||
372 | chan->bfirst_fstart = true; | ||
373 | else | ||
374 | update_state_to_buffer(chan, state); | ||
375 | |||
376 | /* Capture state is not GOOD, release all buffers and re-init state */ | ||
377 | if (chan->capture_state != CAPTURE_GOOD) { | ||
378 | free_ring_buffers(chan, chan->num_buffers); | ||
379 | tegra_channel_init_ring_buffer(chan); | ||
380 | return; | ||
381 | } else { | ||
382 | /* update time stamp of the buffer */ | ||
383 | vb->timestamp.tv_sec = ts->tv_sec; | ||
384 | vb->timestamp.tv_usec = ts->tv_nsec / NSEC_PER_USEC; | ||
385 | } | ||
386 | |||
387 | /* release buffer N at N+2 frame start event */ | ||
388 | if (chan->num_buffers >= (QUEUED_BUFFERS - 1)) | ||
389 | free_ring_buffers(chan, 1); | ||
390 | } | ||
391 | |||
392 | void tegra_channel_ec_close(struct tegra_mc_vi *vi) | ||
393 | { | ||
394 | struct tegra_channel *chan; | ||
395 | |||
396 | /* clear all channles sync point fifo context */ | ||
397 | list_for_each_entry(chan, &vi->vi_chans, list) { | ||
398 | memset(&chan->syncpoint_fifo[0], 0, TEGRA_CSI_BLOCKS); | ||
399 | } | ||
400 | } | ||
401 | |||
402 | struct tegra_channel_buffer *dequeue_buffer(struct tegra_channel *chan) | ||
403 | { | ||
404 | struct tegra_channel_buffer *buf = NULL; | ||
405 | |||
406 | spin_lock(&chan->start_lock); | ||
407 | if (list_empty(&chan->capture)) | ||
408 | goto done; | ||
409 | |||
410 | buf = list_entry(chan->capture.next, | ||
411 | struct tegra_channel_buffer, queue); | ||
412 | list_del_init(&buf->queue); | ||
413 | |||
414 | /* add dequeued buffer to the ring buffer */ | ||
415 | add_buffer_to_ring(chan, &buf->buf); | ||
416 | done: | ||
417 | spin_unlock(&chan->start_lock); | ||
418 | return buf; | ||
419 | } | ||
420 | |||
421 | /* | ||
422 | * ----------------------------------------------------------------------------- | ||
423 | * videobuf2 queue operations | ||
424 | * ----------------------------------------------------------------------------- | ||
425 | */ | ||
426 | static int | ||
427 | tegra_channel_queue_setup(struct vb2_queue *vq, const void *parg, | ||
428 | unsigned int *nbuffers, unsigned int *nplanes, | ||
429 | unsigned int sizes[], void *alloc_ctxs[]) | ||
430 | { | ||
431 | const struct v4l2_format *fmt = parg; | ||
432 | struct tegra_channel *chan = vb2_get_drv_priv(vq); | ||
433 | /* Make sure the image size is large enough. */ | ||
434 | if (fmt && fmt->fmt.pix.sizeimage < chan->format.sizeimage) | ||
435 | return -EINVAL; | ||
436 | |||
437 | *nplanes = 1; | ||
438 | |||
439 | sizes[0] = fmt ? fmt->fmt.pix.sizeimage : chan->format.sizeimage; | ||
440 | alloc_ctxs[0] = chan->alloc_ctx; | ||
441 | |||
442 | /* Make sure minimum number of buffers are passed */ | ||
443 | if (*nbuffers < (QUEUED_BUFFERS - 1)) | ||
444 | *nbuffers = QUEUED_BUFFERS - 1; | ||
445 | |||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | static int tegra_channel_buffer_prepare(struct vb2_buffer *vb) | ||
450 | { | ||
451 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
452 | struct tegra_channel *chan = vb2_get_drv_priv(vb->vb2_queue); | ||
453 | struct tegra_channel_buffer *buf = to_tegra_channel_buffer(vbuf); | ||
454 | |||
455 | buf->chan = chan; | ||
456 | vb2_set_plane_payload(&vbuf->vb2_buf, 0, chan->format.sizeimage); | ||
457 | #if defined(CONFIG_VIDEOBUF2_DMA_CONTIG) | ||
458 | buf->addr = vb2_dma_contig_plane_dma_addr(vb, 0); | ||
459 | #endif | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | static void tegra_channel_buffer_queue(struct vb2_buffer *vb) | ||
465 | { | ||
466 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | ||
467 | struct tegra_channel *chan = vb2_get_drv_priv(vb->vb2_queue); | ||
468 | struct tegra_channel_buffer *buf = to_tegra_channel_buffer(vbuf); | ||
469 | |||
470 | /* for bypass mode - do nothing */ | ||
471 | if (chan->bypass) | ||
472 | return; | ||
473 | |||
474 | /* Put buffer into the capture queue */ | ||
475 | spin_lock(&chan->start_lock); | ||
476 | list_add_tail(&buf->queue, &chan->capture); | ||
477 | spin_unlock(&chan->start_lock); | ||
478 | |||
479 | /* Wait up kthread for capture */ | ||
480 | wake_up_interruptible(&chan->start_wait); | ||
481 | } | ||
482 | |||
483 | /* Return all queued buffers back to videobuf2 */ | ||
484 | void tegra_channel_queued_buf_done(struct tegra_channel *chan, | ||
485 | enum vb2_buffer_state state) | ||
486 | { | ||
487 | struct tegra_channel_buffer *buf, *nbuf; | ||
488 | spinlock_t *lock = &chan->start_lock; | ||
489 | struct list_head *q = &chan->capture; | ||
490 | |||
491 | spin_lock(lock); | ||
492 | list_for_each_entry_safe(buf, nbuf, q, queue) { | ||
493 | vb2_buffer_done(&buf->buf.vb2_buf, state); | ||
494 | list_del(&buf->queue); | ||
495 | } | ||
496 | spin_unlock(lock); | ||
497 | } | ||
498 | |||
499 | #define __tegra_channel_device_call_subdevs_all_p(v4l2_dev, sd, cond, o,\ | ||
500 | f, args...) \ | ||
501 | ({ \ | ||
502 | long __err = 0; \ | ||
503 | long e = 0; \ | ||
504 | \ | ||
505 | list_for_each_entry((sd), &(v4l2_dev)->subdevs, list) { \ | ||
506 | if ((cond) && (sd)->ops->o && (sd)->ops->o->f) \ | ||
507 | e = (sd)->ops->o->f((sd), ##args); \ | ||
508 | if (!__err && e && e != -ENOIOCTLCMD) \ | ||
509 | __err = e; \ | ||
510 | e = 0; \ | ||
511 | } \ | ||
512 | __err; \ | ||
513 | }) | ||
514 | |||
515 | /* | ||
516 | * Call the specified callback for all subdevs matching grp_id (if 0, then | ||
517 | * match them all), errors are ignored until the end, and the first error | ||
518 | * encountered is returned. If the callback returns an error other than 0 or | ||
519 | * -ENOIOCTLCMD, then return with that error code. Note that you cannot | ||
520 | * add or delete a subdev while walking the subdevs list. | ||
521 | */ | ||
522 | #define tegra_channel_device_call_all(v4l2_dev, grpid, o, f, args...) \ | ||
523 | ({ \ | ||
524 | struct v4l2_subdev *__sd; \ | ||
525 | __tegra_channel_device_call_subdevs_all_p(v4l2_dev, __sd, \ | ||
526 | !(grpid) || __sd->grp_id == (grpid), o, f, \ | ||
527 | ##args); \ | ||
528 | }) | ||
529 | |||
530 | /* | ||
531 | * ----------------------------------------------------------------------------- | ||
532 | * subdevice set/unset operations | ||
533 | * ----------------------------------------------------------------------------- | ||
534 | */ | ||
535 | int tegra_channel_set_stream(struct tegra_channel *chan, bool on) | ||
536 | { | ||
537 | int num_sd; | ||
538 | int ret = 0; | ||
539 | |||
540 | if (atomic_read(&chan->is_streaming) == on) | ||
541 | return 0; | ||
542 | |||
543 | for (num_sd = chan->num_subdevs - 1; num_sd >= 0; num_sd--) { | ||
544 | struct v4l2_subdev *sd = chan->subdev[num_sd]; | ||
545 | int err = 0; | ||
546 | |||
547 | err = v4l2_subdev_call(sd, video, s_stream, on); | ||
548 | if (!ret && err < 0 && err != -ENOIOCTLCMD) | ||
549 | ret = err; | ||
550 | } | ||
551 | |||
552 | atomic_set(&chan->is_streaming, on); | ||
553 | |||
554 | return ret; | ||
555 | } | ||
556 | |||
557 | int tegra_channel_set_power(struct tegra_channel *chan, bool on) | ||
558 | { | ||
559 | int num_sd; | ||
560 | int ret = 0; | ||
561 | |||
562 | for (num_sd = 0; num_sd < chan->num_subdevs; num_sd++) { | ||
563 | struct v4l2_subdev *sd = chan->subdev[num_sd]; | ||
564 | int err = 0; | ||
565 | |||
566 | err = v4l2_subdev_call(sd, core, s_power, on); | ||
567 | if (!ret && err < 0 && err != -ENOIOCTLCMD) | ||
568 | ret = err; | ||
569 | } | ||
570 | |||
571 | return ret; | ||
572 | } | ||
573 | |||
574 | static int tegra_channel_start_streaming(struct vb2_queue *vq, u32 count) | ||
575 | { | ||
576 | struct tegra_channel *chan = vb2_get_drv_priv(vq); | ||
577 | struct tegra_mc_vi *vi = chan->vi; | ||
578 | |||
579 | if (vi->fops) | ||
580 | return vi->fops->vi_start_streaming(vq, count); | ||
581 | return 0; | ||
582 | } | ||
583 | |||
584 | static void tegra_channel_stop_streaming(struct vb2_queue *vq) | ||
585 | { | ||
586 | struct tegra_channel *chan = vb2_get_drv_priv(vq); | ||
587 | struct tegra_mc_vi *vi = chan->vi; | ||
588 | |||
589 | if (vi->fops) | ||
590 | vi->fops->vi_stop_streaming(vq); | ||
591 | } | ||
592 | |||
593 | static const struct vb2_ops tegra_channel_queue_qops = { | ||
594 | .queue_setup = tegra_channel_queue_setup, | ||
595 | .buf_prepare = tegra_channel_buffer_prepare, | ||
596 | .buf_queue = tegra_channel_buffer_queue, | ||
597 | .wait_prepare = vb2_ops_wait_prepare, | ||
598 | .wait_finish = vb2_ops_wait_finish, | ||
599 | .start_streaming = tegra_channel_start_streaming, | ||
600 | .stop_streaming = tegra_channel_stop_streaming, | ||
601 | }; | ||
602 | |||
603 | /* ----------------------------------------------------------------------------- | ||
604 | * V4L2 ioctls | ||
605 | */ | ||
606 | |||
607 | static int | ||
608 | tegra_channel_querycap(struct file *file, void *fh, struct v4l2_capability *cap) | ||
609 | { | ||
610 | struct v4l2_fh *vfh = file->private_data; | ||
611 | struct tegra_channel *chan = to_tegra_channel(vfh->vdev); | ||
612 | |||
613 | cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; | ||
614 | cap->device_caps |= V4L2_CAP_EXT_PIX_FORMAT; | ||
615 | cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
616 | |||
617 | strlcpy(cap->driver, "tegra-video", sizeof(cap->driver)); | ||
618 | strlcpy(cap->card, chan->video.name, sizeof(cap->card)); | ||
619 | snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s:%u", | ||
620 | dev_name(chan->vi->dev), chan->port[0]); | ||
621 | |||
622 | return 0; | ||
623 | } | ||
624 | |||
625 | static int | ||
626 | tegra_channel_enum_framesizes(struct file *file, void *fh, | ||
627 | struct v4l2_frmsizeenum *sizes) | ||
628 | { | ||
629 | struct v4l2_fh *vfh = file->private_data; | ||
630 | struct tegra_channel *chan = to_tegra_channel(vfh->vdev); | ||
631 | struct v4l2_subdev_frame_size_enum fse = { | ||
632 | .index = sizes->index, | ||
633 | .code = sizes->pixel_format, | ||
634 | }; | ||
635 | int ret = 0; | ||
636 | |||
637 | ret = v4l2_device_call_until_err(chan->video.v4l2_dev, | ||
638 | chan->grp_id, pad, enum_frame_size, NULL, &fse); | ||
639 | if (!ret) { | ||
640 | sizes->type = V4L2_FRMSIZE_TYPE_DISCRETE; | ||
641 | sizes->discrete.width = fse.max_width; | ||
642 | sizes->discrete.height = fse.max_height; | ||
643 | } | ||
644 | |||
645 | return ret; | ||
646 | } | ||
647 | |||
648 | static int | ||
649 | tegra_channel_enum_frameintervals(struct file *file, void *fh, | ||
650 | struct v4l2_frmivalenum *intervals) | ||
651 | { | ||
652 | struct v4l2_fh *vfh = file->private_data; | ||
653 | struct tegra_channel *chan = to_tegra_channel(vfh->vdev); | ||
654 | struct v4l2_subdev_frame_interval_enum fie = { | ||
655 | .index = intervals->index, | ||
656 | .code = intervals->pixel_format, | ||
657 | .width = intervals->width, | ||
658 | .height = intervals->height, | ||
659 | }; | ||
660 | int ret = 0; | ||
661 | |||
662 | ret = v4l2_device_call_until_err(chan->video.v4l2_dev, | ||
663 | chan->grp_id, pad, enum_frame_interval, NULL, &fie); | ||
664 | |||
665 | if (!ret) { | ||
666 | intervals->type = V4L2_FRMIVAL_TYPE_DISCRETE; | ||
667 | intervals->discrete.numerator = fie.interval.numerator; | ||
668 | intervals->discrete.denominator = fie.interval.denominator; | ||
669 | } | ||
670 | |||
671 | return ret; | ||
672 | } | ||
673 | |||
674 | static int | ||
675 | tegra_channel_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) | ||
676 | { | ||
677 | struct v4l2_fh *vfh = file->private_data; | ||
678 | struct tegra_channel *chan = to_tegra_channel(vfh->vdev); | ||
679 | unsigned int index = 0, i; | ||
680 | unsigned long *fmts_bitmap = chan->fmts_bitmap; | ||
681 | |||
682 | if (f->index >= bitmap_weight(fmts_bitmap, MAX_FORMAT_NUM)) | ||
683 | return -EINVAL; | ||
684 | |||
685 | for (i = 0; i < f->index + 1; i++, index++) | ||
686 | index = find_next_bit(fmts_bitmap, MAX_FORMAT_NUM, index); | ||
687 | |||
688 | index -= 1; | ||
689 | f->pixelformat = tegra_core_get_fourcc_by_idx(chan, index); | ||
690 | tegra_core_get_description_by_idx(chan, index, f->description); | ||
691 | |||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | static int | ||
696 | tegra_channel_g_edid(struct file *file, void *fh, struct v4l2_edid *edid) | ||
697 | { | ||
698 | struct v4l2_fh *vfh = file->private_data; | ||
699 | struct tegra_channel *chan = to_tegra_channel(vfh->vdev); | ||
700 | struct v4l2_subdev *sd = chan->subdev_on_csi; | ||
701 | |||
702 | if (!v4l2_subdev_has_op(sd, pad, get_edid)) | ||
703 | return -ENOTTY; | ||
704 | |||
705 | return v4l2_subdev_call(sd, pad, get_edid, edid); | ||
706 | } | ||
707 | |||
708 | static int | ||
709 | tegra_channel_s_edid(struct file *file, void *fh, struct v4l2_edid *edid) | ||
710 | { | ||
711 | struct v4l2_fh *vfh = file->private_data; | ||
712 | struct tegra_channel *chan = to_tegra_channel(vfh->vdev); | ||
713 | struct v4l2_subdev *sd = chan->subdev_on_csi; | ||
714 | |||
715 | if (!v4l2_subdev_has_op(sd, pad, set_edid)) | ||
716 | return -ENOTTY; | ||
717 | |||
718 | return v4l2_subdev_call(sd, pad, set_edid, edid); | ||
719 | } | ||
720 | |||
721 | static int | ||
722 | tegra_channel_g_dv_timings(struct file *file, void *fh, | ||
723 | struct v4l2_dv_timings *timings) | ||
724 | { | ||
725 | struct v4l2_fh *vfh = file->private_data; | ||
726 | struct tegra_channel *chan = to_tegra_channel(vfh->vdev); | ||
727 | |||
728 | if (!v4l2_subdev_has_op(chan->subdev_on_csi, video, g_dv_timings)) | ||
729 | return -ENOTTY; | ||
730 | |||
731 | return v4l2_device_call_until_err(chan->video.v4l2_dev, | ||
732 | chan->grp_id, video, g_dv_timings, timings); | ||
733 | } | ||
734 | |||
735 | static int | ||
736 | tegra_channel_s_dv_timings(struct file *file, void *fh, | ||
737 | struct v4l2_dv_timings *timings) | ||
738 | { | ||
739 | struct v4l2_fh *vfh = file->private_data; | ||
740 | struct tegra_channel *chan = to_tegra_channel(vfh->vdev); | ||
741 | struct v4l2_bt_timings *bt = &timings->bt; | ||
742 | struct v4l2_dv_timings curr_timings; | ||
743 | int ret; | ||
744 | |||
745 | if (!v4l2_subdev_has_op(chan->subdev_on_csi, video, s_dv_timings)) | ||
746 | return -ENOTTY; | ||
747 | |||
748 | ret = tegra_channel_g_dv_timings(file, fh, &curr_timings); | ||
749 | if (ret) | ||
750 | return ret; | ||
751 | |||
752 | if (v4l2_match_dv_timings(timings, &curr_timings, 0)) | ||
753 | return 0; | ||
754 | |||
755 | if (vb2_is_busy(&chan->queue)) | ||
756 | return -EBUSY; | ||
757 | |||
758 | ret = v4l2_device_call_until_err(chan->video.v4l2_dev, | ||
759 | chan->grp_id, video, s_dv_timings, timings); | ||
760 | |||
761 | if (!ret) | ||
762 | tegra_channel_update_format(chan, bt->width, bt->height, | ||
763 | chan->fmtinfo->fourcc, &chan->fmtinfo->bpp, 0); | ||
764 | |||
765 | if (chan->total_ports > 1) | ||
766 | update_gang_mode(chan); | ||
767 | |||
768 | return ret; | ||
769 | } | ||
770 | |||
771 | static int | ||
772 | tegra_channel_query_dv_timings(struct file *file, void *fh, | ||
773 | struct v4l2_dv_timings *timings) | ||
774 | { | ||
775 | struct v4l2_fh *vfh = file->private_data; | ||
776 | struct tegra_channel *chan = to_tegra_channel(vfh->vdev); | ||
777 | |||
778 | if (!v4l2_subdev_has_op(chan->subdev_on_csi, video, query_dv_timings)) | ||
779 | return -ENOTTY; | ||
780 | |||
781 | return v4l2_device_call_until_err(chan->video.v4l2_dev, | ||
782 | chan->grp_id, video, query_dv_timings, timings); | ||
783 | } | ||
784 | |||
785 | static int | ||
786 | tegra_channel_enum_dv_timings(struct file *file, void *fh, | ||
787 | struct v4l2_enum_dv_timings *timings) | ||
788 | { | ||
789 | struct v4l2_fh *vfh = file->private_data; | ||
790 | struct tegra_channel *chan = to_tegra_channel(vfh->vdev); | ||
791 | struct v4l2_subdev *sd = chan->subdev_on_csi; | ||
792 | |||
793 | if (!v4l2_subdev_has_op(sd, pad, enum_dv_timings)) | ||
794 | return -ENOTTY; | ||
795 | |||
796 | return v4l2_subdev_call(sd, pad, enum_dv_timings, timings); | ||
797 | } | ||
798 | |||
799 | static int | ||
800 | tegra_channel_dv_timings_cap(struct file *file, void *fh, | ||
801 | struct v4l2_dv_timings_cap *cap) | ||
802 | { | ||
803 | struct v4l2_fh *vfh = file->private_data; | ||
804 | struct tegra_channel *chan = to_tegra_channel(vfh->vdev); | ||
805 | struct v4l2_subdev *sd = chan->subdev_on_csi; | ||
806 | |||
807 | if (!v4l2_subdev_has_op(sd, pad, dv_timings_cap)) | ||
808 | return -ENOTTY; | ||
809 | |||
810 | return v4l2_subdev_call(sd, pad, dv_timings_cap, cap); | ||
811 | } | ||
812 | |||
813 | int tegra_channel_s_ctrl(struct v4l2_ctrl *ctrl) | ||
814 | { | ||
815 | struct tegra_channel *chan = container_of(ctrl->handler, | ||
816 | struct tegra_channel, ctrl_handler); | ||
817 | |||
818 | switch (ctrl->id) { | ||
819 | case V4L2_CID_VI_BYPASS_MODE: | ||
820 | if (switch_ctrl_qmenu[ctrl->val] == SWITCH_ON) | ||
821 | chan->bypass = true; | ||
822 | else if (chan->vi->bypass) { | ||
823 | dev_dbg(&chan->video.dev, | ||
824 | "can't disable bypass mode\n"); | ||
825 | dev_dbg(&chan->video.dev, | ||
826 | "because the VI/CSI is in bypass mode\n"); | ||
827 | chan->bypass = true; | ||
828 | } else | ||
829 | chan->bypass = false; | ||
830 | break; | ||
831 | case V4L2_CID_OVERRIDE_ENABLE: | ||
832 | { | ||
833 | struct v4l2_subdev *sd = chan->subdev_on_csi; | ||
834 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
835 | struct camera_common_data *s_data = | ||
836 | to_camera_common_data(client); | ||
837 | |||
838 | if (!i2c_get_clientdata(client)) { | ||
839 | dev_info(&chan->video.dev, | ||
840 | "i2c_client drvdata is NULL\n"); | ||
841 | break; | ||
842 | } | ||
843 | if (!s_data) | ||
844 | break; | ||
845 | if (switch_ctrl_qmenu[ctrl->val] == SWITCH_ON) { | ||
846 | s_data->override_enable = true; | ||
847 | dev_dbg(&chan->video.dev, | ||
848 | "enable override control\n"); | ||
849 | } else { | ||
850 | s_data->override_enable = false; | ||
851 | dev_dbg(&chan->video.dev, | ||
852 | "disable override control\n"); | ||
853 | } | ||
854 | } | ||
855 | break; | ||
856 | case V4L2_CID_VI_HEIGHT_ALIGN: | ||
857 | chan->height_align = ctrl->val; | ||
858 | tegra_channel_update_format(chan, chan->format.width, | ||
859 | chan->format.height, | ||
860 | chan->format.pixelformat, | ||
861 | &chan->fmtinfo->bpp, 0); | ||
862 | break; | ||
863 | case V4L2_CID_VI_SIZE_ALIGN: | ||
864 | chan->size_align = size_align_ctrl_qmenu[ctrl->val]; | ||
865 | tegra_channel_update_format(chan, chan->format.width, | ||
866 | chan->format.height, | ||
867 | chan->format.pixelformat, | ||
868 | &chan->fmtinfo->bpp, 0); | ||
869 | break; | ||
870 | default: | ||
871 | dev_err(&chan->video.dev, "%s:Not valid ctrl\n", __func__); | ||
872 | return -EINVAL; | ||
873 | } | ||
874 | |||
875 | return 0; | ||
876 | } | ||
877 | |||
878 | static const struct v4l2_ctrl_ops channel_ctrl_ops = { | ||
879 | .s_ctrl = tegra_channel_s_ctrl, | ||
880 | }; | ||
881 | |||
882 | static const struct v4l2_ctrl_config common_custom_ctrls[] = { | ||
883 | { | ||
884 | .ops = &channel_ctrl_ops, | ||
885 | .id = V4L2_CID_VI_BYPASS_MODE, | ||
886 | .name = "Bypass Mode", | ||
887 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, | ||
888 | .def = 0, | ||
889 | .min = 0, | ||
890 | .max = ARRAY_SIZE(switch_ctrl_qmenu) - 1, | ||
891 | .menu_skip_mask = 0, | ||
892 | .qmenu_int = switch_ctrl_qmenu, | ||
893 | }, | ||
894 | { | ||
895 | .ops = &channel_ctrl_ops, | ||
896 | .id = V4L2_CID_OVERRIDE_ENABLE, | ||
897 | .name = "Override Enable", | ||
898 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, | ||
899 | .def = 0, | ||
900 | .min = 0, | ||
901 | .max = ARRAY_SIZE(switch_ctrl_qmenu) - 1, | ||
902 | .menu_skip_mask = 0, | ||
903 | .qmenu_int = switch_ctrl_qmenu, | ||
904 | }, | ||
905 | { | ||
906 | .ops = &channel_ctrl_ops, | ||
907 | .id = V4L2_CID_VI_HEIGHT_ALIGN, | ||
908 | .name = "Height Align", | ||
909 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
910 | .min = 1, | ||
911 | .max = 16, | ||
912 | .step = 1, | ||
913 | .def = 1, | ||
914 | }, | ||
915 | { | ||
916 | .ops = &channel_ctrl_ops, | ||
917 | .id = V4L2_CID_VI_SIZE_ALIGN, | ||
918 | .name = "Size Align", | ||
919 | .type = V4L2_CTRL_TYPE_INTEGER_MENU, | ||
920 | .def = 0, | ||
921 | .min = 0, | ||
922 | .max = ARRAY_SIZE(size_align_ctrl_qmenu) - 1, | ||
923 | .menu_skip_mask = 0, | ||
924 | .qmenu_int = size_align_ctrl_qmenu, | ||
925 | }, | ||
926 | }; | ||
927 | |||
928 | static int tegra_channel_setup_controls(struct tegra_channel *chan) | ||
929 | { | ||
930 | int num_sd = 0; | ||
931 | struct v4l2_subdev *sd = NULL; | ||
932 | struct tegra_mc_vi *vi = chan->vi; | ||
933 | int i; | ||
934 | |||
935 | /* Initialize the subdev and controls here at first open */ | ||
936 | sd = chan->subdev[num_sd]; | ||
937 | while ((sd = chan->subdev[num_sd++]) && | ||
938 | (num_sd <= chan->num_subdevs)) { | ||
939 | /* Add control handler for the subdevice */ | ||
940 | v4l2_ctrl_add_handler(&chan->ctrl_handler, | ||
941 | sd->ctrl_handler, NULL); | ||
942 | if (chan->ctrl_handler.error) | ||
943 | dev_err(chan->vi->dev, | ||
944 | "Failed to add sub-device controls\n"); | ||
945 | } | ||
946 | |||
947 | /* Add new custom controls */ | ||
948 | for (i = 0; i < ARRAY_SIZE(common_custom_ctrls); i++) { | ||
949 | /* don't create override control for pg mode */ | ||
950 | if (common_custom_ctrls[i].id == V4L2_CID_OVERRIDE_ENABLE && | ||
951 | chan->pg_mode) | ||
952 | continue; | ||
953 | v4l2_ctrl_new_custom(&chan->ctrl_handler, | ||
954 | &common_custom_ctrls[i], NULL); | ||
955 | if (chan->ctrl_handler.error) { | ||
956 | dev_err(chan->vi->dev, | ||
957 | "Failed to add %s ctrl\n", | ||
958 | common_custom_ctrls[i].name); | ||
959 | return chan->ctrl_handler.error; | ||
960 | } | ||
961 | } | ||
962 | |||
963 | vi->fops->vi_add_ctrls(chan); | ||
964 | |||
965 | if (chan->pg_mode) { | ||
966 | v4l2_ctrl_add_handler(&chan->ctrl_handler, | ||
967 | &chan->vi->ctrl_handler, NULL); | ||
968 | if (chan->ctrl_handler.error) | ||
969 | dev_err(chan->vi->dev, | ||
970 | "Failed to add VI controls\n"); | ||
971 | } | ||
972 | |||
973 | /* setup the controls */ | ||
974 | return v4l2_ctrl_handler_setup(&chan->ctrl_handler); | ||
975 | } | ||
976 | |||
977 | int tegra_channel_init_subdevices(struct tegra_channel *chan) | ||
978 | { | ||
979 | struct media_entity *entity; | ||
980 | struct media_pad *pad; | ||
981 | struct v4l2_subdev *sd; | ||
982 | int index = 0; | ||
983 | int num_sd = 0; | ||
984 | int grp_id = chan->pg_mode ? (TPG_CSI_GROUP_ID + chan->port[0] + 1) | ||
985 | : chan->port[0] + 1; | ||
986 | |||
987 | /* set_stream of CSI */ | ||
988 | pad = media_entity_remote_pad(&chan->pad); | ||
989 | if (!pad) | ||
990 | return -ENODEV; | ||
991 | |||
992 | entity = pad->entity; | ||
993 | sd = media_entity_to_v4l2_subdev(entity); | ||
994 | v4l2_set_subdev_hostdata(sd, chan); | ||
995 | chan->subdev[num_sd++] = sd; | ||
996 | /* Add subdev name to this video dev name with vi-output tag*/ | ||
997 | snprintf(chan->video.name, sizeof(chan->video.name), "%s, %s", | ||
998 | "vi-output", sd->name); | ||
999 | sd->grp_id = grp_id; | ||
1000 | chan->grp_id = grp_id; | ||
1001 | index = pad->index - 1; | ||
1002 | while (index >= 0) { | ||
1003 | pad = &entity->pads[index]; | ||
1004 | if (!(pad->flags & MEDIA_PAD_FL_SINK)) | ||
1005 | break; | ||
1006 | |||
1007 | pad = media_entity_remote_pad(pad); | ||
1008 | if (pad == NULL || | ||
1009 | media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) | ||
1010 | break; | ||
1011 | |||
1012 | if (num_sd >= MAX_SUBDEVICES) | ||
1013 | break; | ||
1014 | |||
1015 | entity = pad->entity; | ||
1016 | sd = media_entity_to_v4l2_subdev(entity); | ||
1017 | v4l2_set_subdev_hostdata(sd, chan); | ||
1018 | sd->grp_id = grp_id; | ||
1019 | chan->subdev[num_sd++] = sd; | ||
1020 | /* Add subdev name to this video dev name with vi-output tag*/ | ||
1021 | snprintf(chan->video.name, sizeof(chan->video.name), "%s, %s", | ||
1022 | "vi-output", sd->name); | ||
1023 | |||
1024 | index = pad->index - 1; | ||
1025 | } | ||
1026 | chan->num_subdevs = num_sd; | ||
1027 | /* | ||
1028 | * Each CSI channel has only one final remote source, | ||
1029 | * Mark that subdev as subdev_on_csi | ||
1030 | */ | ||
1031 | chan->subdev_on_csi = sd; | ||
1032 | |||
1033 | /* initialize the available formats */ | ||
1034 | if (chan->num_subdevs) | ||
1035 | tegra_channel_fmts_bitmap_init(chan); | ||
1036 | |||
1037 | return tegra_channel_setup_controls(chan); | ||
1038 | } | ||
1039 | |||
1040 | static int | ||
1041 | tegra_channel_get_format(struct file *file, void *fh, | ||
1042 | struct v4l2_format *format) | ||
1043 | { | ||
1044 | struct v4l2_fh *vfh = file->private_data; | ||
1045 | struct tegra_channel *chan = to_tegra_channel(vfh->vdev); | ||
1046 | struct v4l2_pix_format *pix = &format->fmt.pix; | ||
1047 | |||
1048 | *pix = chan->format; | ||
1049 | |||
1050 | return 0; | ||
1051 | } | ||
1052 | |||
1053 | static int | ||
1054 | __tegra_channel_try_format(struct tegra_channel *chan, | ||
1055 | struct v4l2_pix_format *pix) | ||
1056 | { | ||
1057 | const struct tegra_video_format *vfmt; | ||
1058 | struct v4l2_subdev_format fmt; | ||
1059 | struct v4l2_subdev *sd = chan->subdev_on_csi; | ||
1060 | int ret = 0; | ||
1061 | |||
1062 | /* Use the channel format if pixformat is not supported */ | ||
1063 | vfmt = tegra_core_get_format_by_fourcc(chan, pix->pixelformat); | ||
1064 | if (!vfmt) { | ||
1065 | pix->pixelformat = chan->format.pixelformat; | ||
1066 | vfmt = tegra_core_get_format_by_fourcc(chan, pix->pixelformat); | ||
1067 | } | ||
1068 | |||
1069 | fmt.which = V4L2_SUBDEV_FORMAT_TRY; | ||
1070 | fmt.pad = 0; | ||
1071 | v4l2_fill_mbus_format(&fmt.format, pix, vfmt->code); | ||
1072 | |||
1073 | ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &fmt); | ||
1074 | if (ret == -ENOIOCTLCMD) | ||
1075 | return -ENOTTY; | ||
1076 | |||
1077 | v4l2_fill_pix_format(pix, &fmt.format); | ||
1078 | |||
1079 | tegra_channel_fmt_align(chan, vfmt, | ||
1080 | &pix->width, &pix->height, &pix->bytesperline); | ||
1081 | pix->sizeimage = get_aligned_buffer_size(chan, | ||
1082 | pix->bytesperline, pix->height); | ||
1083 | if (chan->fmtinfo->fourcc == V4L2_PIX_FMT_NV16) | ||
1084 | pix->sizeimage *= 2; | ||
1085 | |||
1086 | return ret; | ||
1087 | } | ||
1088 | |||
1089 | static int | ||
1090 | tegra_channel_try_format(struct file *file, void *fh, | ||
1091 | struct v4l2_format *format) | ||
1092 | { | ||
1093 | struct v4l2_fh *vfh = file->private_data; | ||
1094 | struct tegra_channel *chan = to_tegra_channel(vfh->vdev); | ||
1095 | |||
1096 | return __tegra_channel_try_format(chan, &format->fmt.pix); | ||
1097 | } | ||
1098 | |||
1099 | static int | ||
1100 | __tegra_channel_set_format(struct tegra_channel *chan, | ||
1101 | struct v4l2_pix_format *pix) | ||
1102 | { | ||
1103 | const struct tegra_video_format *vfmt; | ||
1104 | struct v4l2_subdev_format fmt; | ||
1105 | struct v4l2_subdev *sd = chan->subdev_on_csi; | ||
1106 | int ret = 0; | ||
1107 | |||
1108 | vfmt = tegra_core_get_format_by_fourcc(chan, pix->pixelformat); | ||
1109 | |||
1110 | fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; | ||
1111 | fmt.pad = 0; | ||
1112 | v4l2_fill_mbus_format(&fmt.format, pix, vfmt->code); | ||
1113 | |||
1114 | ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &fmt); | ||
1115 | if (ret == -ENOIOCTLCMD) | ||
1116 | return -ENOTTY; | ||
1117 | |||
1118 | v4l2_fill_pix_format(pix, &fmt.format); | ||
1119 | |||
1120 | if (!ret) { | ||
1121 | chan->format = *pix; | ||
1122 | chan->fmtinfo = vfmt; | ||
1123 | tegra_channel_update_format(chan, pix->width, | ||
1124 | pix->height, vfmt->fourcc, &vfmt->bpp, | ||
1125 | pix->bytesperline); | ||
1126 | |||
1127 | *pix = chan->format; | ||
1128 | |||
1129 | if (chan->total_ports > 1) | ||
1130 | update_gang_mode(chan); | ||
1131 | } | ||
1132 | |||
1133 | return ret; | ||
1134 | } | ||
1135 | |||
1136 | static int | ||
1137 | tegra_channel_set_format(struct file *file, void *fh, | ||
1138 | struct v4l2_format *format) | ||
1139 | { | ||
1140 | struct v4l2_fh *vfh = file->private_data; | ||
1141 | struct tegra_channel *chan = to_tegra_channel(vfh->vdev); | ||
1142 | int ret = 0; | ||
1143 | |||
1144 | /* get the suppod format by try_fmt */ | ||
1145 | ret = __tegra_channel_try_format(chan, &format->fmt.pix); | ||
1146 | if (ret) | ||
1147 | return ret; | ||
1148 | |||
1149 | if (vb2_is_busy(&chan->queue)) | ||
1150 | return -EBUSY; | ||
1151 | |||
1152 | return __tegra_channel_set_format(chan, &format->fmt.pix); | ||
1153 | } | ||
1154 | |||
1155 | static int tegra_channel_subscribe_event(struct v4l2_fh *fh, | ||
1156 | const struct v4l2_event_subscription *sub) | ||
1157 | { | ||
1158 | switch (sub->type) { | ||
1159 | case V4L2_EVENT_SOURCE_CHANGE: | ||
1160 | return v4l2_event_subscribe(fh, sub, 4, NULL); | ||
1161 | } | ||
1162 | return v4l2_ctrl_subscribe_event(fh, sub); | ||
1163 | } | ||
1164 | |||
1165 | static int | ||
1166 | tegra_channel_enum_input(struct file *file, void *fh, struct v4l2_input *inp) | ||
1167 | { | ||
1168 | struct v4l2_fh *vfh = file->private_data; | ||
1169 | struct tegra_channel *chan = to_tegra_channel(vfh->vdev); | ||
1170 | struct v4l2_subdev *sd_on_csi = chan->subdev_on_csi; | ||
1171 | int ret; | ||
1172 | |||
1173 | if (inp->index) | ||
1174 | return -EINVAL; | ||
1175 | |||
1176 | ret = v4l2_device_call_until_err(chan->video.v4l2_dev, | ||
1177 | chan->grp_id, video, g_input_status, &inp->status); | ||
1178 | |||
1179 | if (ret == -ENODEV || sd_on_csi == NULL) | ||
1180 | return -ENODEV; | ||
1181 | |||
1182 | inp->type = V4L2_INPUT_TYPE_CAMERA; | ||
1183 | if (v4l2_subdev_has_op(sd_on_csi, video, s_dv_timings)) { | ||
1184 | inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; | ||
1185 | snprintf(inp->name, | ||
1186 | sizeof(inp->name), "HDMI %u", | ||
1187 | chan->port[0]); | ||
1188 | } else | ||
1189 | snprintf(inp->name, | ||
1190 | sizeof(inp->name), "Camera %u", | ||
1191 | chan->port[0]); | ||
1192 | |||
1193 | return ret; | ||
1194 | } | ||
1195 | |||
1196 | static int tegra_channel_g_input(struct file *file, void *priv, unsigned int *i) | ||
1197 | { | ||
1198 | *i = 0; | ||
1199 | return 0; | ||
1200 | } | ||
1201 | |||
1202 | static int tegra_channel_s_input(struct file *file, void *priv, unsigned int i) | ||
1203 | { | ||
1204 | if (i > 0) | ||
1205 | return -EINVAL; | ||
1206 | return 0; | ||
1207 | } | ||
1208 | |||
1209 | static int tegra_channel_log_status(struct file *file, void *priv) | ||
1210 | { | ||
1211 | struct v4l2_fh *vfh = file->private_data; | ||
1212 | struct tegra_channel *chan = to_tegra_channel(vfh->vdev); | ||
1213 | |||
1214 | v4l2_device_call_all(chan->video.v4l2_dev, | ||
1215 | chan->grp_id, core, log_status); | ||
1216 | return 0; | ||
1217 | } | ||
1218 | |||
1219 | static long tegra_channel_default_ioctl(struct file *file, void *fh, | ||
1220 | bool use_prio, unsigned int cmd, void *arg) | ||
1221 | { | ||
1222 | struct v4l2_fh *vfh = file->private_data; | ||
1223 | struct tegra_channel *chan = to_tegra_channel(vfh->vdev); | ||
1224 | struct tegra_mc_vi *vi = chan->vi; | ||
1225 | long ret = 0; | ||
1226 | |||
1227 | if (vi->fops && vi->fops->vi_default_ioctl) | ||
1228 | ret = vi->fops->vi_default_ioctl(file, fh, use_prio, cmd, arg); | ||
1229 | |||
1230 | return ret; | ||
1231 | } | ||
1232 | |||
1233 | #ifdef CONFIG_COMPAT | ||
1234 | static long tegra_channel_compat_ioctl(struct file *filp, | ||
1235 | unsigned int cmd, unsigned long arg) | ||
1236 | { | ||
1237 | struct video_device *vdev = video_devdata(filp); | ||
1238 | int ret = -ENODEV; | ||
1239 | |||
1240 | if (vdev->fops->unlocked_ioctl) { | ||
1241 | struct mutex *lock = v4l2_ioctl_get_lock(vdev, cmd); | ||
1242 | |||
1243 | if (lock && mutex_lock_interruptible(lock)) | ||
1244 | return -ERESTARTSYS; | ||
1245 | if (video_is_registered(vdev)) | ||
1246 | ret = vdev->fops->unlocked_ioctl(filp, cmd, arg); | ||
1247 | if (lock) | ||
1248 | mutex_unlock(lock); | ||
1249 | } else | ||
1250 | ret = -ENOTTY; | ||
1251 | |||
1252 | return ret; | ||
1253 | } | ||
1254 | #endif | ||
1255 | |||
1256 | static const struct v4l2_ioctl_ops tegra_channel_ioctl_ops = { | ||
1257 | .vidioc_querycap = tegra_channel_querycap, | ||
1258 | .vidioc_enum_framesizes = tegra_channel_enum_framesizes, | ||
1259 | .vidioc_enum_frameintervals = tegra_channel_enum_frameintervals, | ||
1260 | .vidioc_enum_fmt_vid_cap = tegra_channel_enum_format, | ||
1261 | .vidioc_g_fmt_vid_cap = tegra_channel_get_format, | ||
1262 | .vidioc_s_fmt_vid_cap = tegra_channel_set_format, | ||
1263 | .vidioc_try_fmt_vid_cap = tegra_channel_try_format, | ||
1264 | .vidioc_reqbufs = vb2_ioctl_reqbufs, | ||
1265 | .vidioc_querybuf = vb2_ioctl_querybuf, | ||
1266 | .vidioc_qbuf = vb2_ioctl_qbuf, | ||
1267 | .vidioc_dqbuf = vb2_ioctl_dqbuf, | ||
1268 | .vidioc_create_bufs = vb2_ioctl_create_bufs, | ||
1269 | .vidioc_expbuf = vb2_ioctl_expbuf, | ||
1270 | .vidioc_streamon = vb2_ioctl_streamon, | ||
1271 | .vidioc_streamoff = vb2_ioctl_streamoff, | ||
1272 | .vidioc_g_edid = tegra_channel_g_edid, | ||
1273 | .vidioc_s_edid = tegra_channel_s_edid, | ||
1274 | .vidioc_s_dv_timings = tegra_channel_s_dv_timings, | ||
1275 | .vidioc_g_dv_timings = tegra_channel_g_dv_timings, | ||
1276 | .vidioc_query_dv_timings = tegra_channel_query_dv_timings, | ||
1277 | .vidioc_enum_dv_timings = tegra_channel_enum_dv_timings, | ||
1278 | .vidioc_dv_timings_cap = tegra_channel_dv_timings_cap, | ||
1279 | .vidioc_subscribe_event = tegra_channel_subscribe_event, | ||
1280 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | ||
1281 | .vidioc_enum_input = tegra_channel_enum_input, | ||
1282 | .vidioc_g_input = tegra_channel_g_input, | ||
1283 | .vidioc_s_input = tegra_channel_s_input, | ||
1284 | .vidioc_log_status = tegra_channel_log_status, | ||
1285 | .vidioc_default = tegra_channel_default_ioctl, | ||
1286 | }; | ||
1287 | |||
1288 | static int tegra_channel_close(struct file *fp); | ||
1289 | static int tegra_channel_open(struct file *fp) | ||
1290 | { | ||
1291 | int ret; | ||
1292 | struct video_device *vdev = video_devdata(fp); | ||
1293 | struct tegra_channel *chan = video_get_drvdata(vdev); | ||
1294 | #ifdef T210 | ||
1295 | struct vi *tegra_vi; | ||
1296 | #endif | ||
1297 | struct tegra_mc_vi *vi; | ||
1298 | struct tegra_csi_device *csi; | ||
1299 | |||
1300 | mutex_lock(&chan->video_lock); | ||
1301 | ret = v4l2_fh_open(fp); | ||
1302 | if (ret || !v4l2_fh_is_singular_file(fp)) { | ||
1303 | mutex_unlock(&chan->video_lock); | ||
1304 | return ret; | ||
1305 | } | ||
1306 | |||
1307 | if (chan->subdev[0] == NULL) { | ||
1308 | ret = -ENODEV; | ||
1309 | goto fail; | ||
1310 | } | ||
1311 | |||
1312 | vi = chan->vi; | ||
1313 | #ifdef T210 | ||
1314 | tegra_vi = vi->vi; | ||
1315 | #endif | ||
1316 | csi = vi->csi; | ||
1317 | |||
1318 | /* The first open then turn on power */ | ||
1319 | if (vi->fops) | ||
1320 | ret = vi->fops->vi_power_on(chan); | ||
1321 | if (ret < 0) | ||
1322 | goto fail; | ||
1323 | |||
1324 | chan->fh = (struct v4l2_fh *)fp->private_data; | ||
1325 | |||
1326 | mutex_unlock(&chan->video_lock); | ||
1327 | return 0; | ||
1328 | |||
1329 | fail: | ||
1330 | tegra_channel_close(fp); | ||
1331 | mutex_unlock(&chan->video_lock); | ||
1332 | return ret; | ||
1333 | } | ||
1334 | |||
1335 | static int tegra_channel_close(struct file *fp) | ||
1336 | { | ||
1337 | int ret = 0; | ||
1338 | struct video_device *vdev = video_devdata(fp); | ||
1339 | struct tegra_channel *chan = video_get_drvdata(vdev); | ||
1340 | struct tegra_mc_vi *vi = chan->vi; | ||
1341 | bool is_singular; | ||
1342 | |||
1343 | mutex_lock(&chan->video_lock); | ||
1344 | is_singular = v4l2_fh_is_singular_file(fp); | ||
1345 | ret = _vb2_fop_release(fp, NULL); | ||
1346 | |||
1347 | if (!is_singular) { | ||
1348 | mutex_unlock(&chan->video_lock); | ||
1349 | return ret; | ||
1350 | } | ||
1351 | vi->fops->vi_power_off(chan); | ||
1352 | |||
1353 | mutex_unlock(&chan->video_lock); | ||
1354 | return ret; | ||
1355 | } | ||
1356 | |||
1357 | /* ----------------------------------------------------------------------------- | ||
1358 | * V4L2 file operations | ||
1359 | */ | ||
1360 | static const struct v4l2_file_operations tegra_channel_fops = { | ||
1361 | .owner = THIS_MODULE, | ||
1362 | .unlocked_ioctl = video_ioctl2, | ||
1363 | #ifdef CONFIG_COMPAT | ||
1364 | .compat_ioctl32 = tegra_channel_compat_ioctl, | ||
1365 | #endif | ||
1366 | .open = tegra_channel_open, | ||
1367 | .release = tegra_channel_close, | ||
1368 | .read = vb2_fop_read, | ||
1369 | .poll = vb2_fop_poll, | ||
1370 | .mmap = vb2_fop_mmap, | ||
1371 | }; | ||
1372 | |||
1373 | static int tegra_channel_csi_init(struct tegra_channel *chan) | ||
1374 | { | ||
1375 | int numlanes = 0; | ||
1376 | int idx = 0; | ||
1377 | struct tegra_mc_vi *vi = chan->vi; | ||
1378 | int ret = 0; | ||
1379 | |||
1380 | chan->gang_mode = CAMERA_NO_GANG_MODE; | ||
1381 | chan->total_ports = 0; | ||
1382 | memset(&chan->port[0], INVALID_CSI_PORT, TEGRA_CSI_BLOCKS); | ||
1383 | memset(&chan->syncpoint_fifo[0], 0, TEGRA_CSI_BLOCKS); | ||
1384 | if (chan->pg_mode) { | ||
1385 | /* If VI has 4 existing channels, chan->id will start | ||
1386 | * from 4 for the first TPG channel, which uses PORT_A(0). | ||
1387 | * To get the correct PORT number, subtract existing number of | ||
1388 | * channels from chan->id. | ||
1389 | */ | ||
1390 | chan->port[0] = chan->id - vi->num_channels; | ||
1391 | WARN_ON(chan->port[0] > TPG_CHANNELS); | ||
1392 | chan->numlanes = 2; | ||
1393 | } else { | ||
1394 | ret = tegra_vi_get_port_info(chan, vi->dev->of_node, chan->id); | ||
1395 | if (ret) { | ||
1396 | dev_err(vi->dev, "%s:Fail to parse port info\n", | ||
1397 | __func__); | ||
1398 | return ret; | ||
1399 | } | ||
1400 | } | ||
1401 | |||
1402 | for (idx = 0; csi_port_is_valid(chan->port[idx]); idx++) { | ||
1403 | chan->total_ports++; | ||
1404 | numlanes = chan->numlanes - (idx * MAX_CSI_BLOCK_LANES); | ||
1405 | numlanes = numlanes > MAX_CSI_BLOCK_LANES ? | ||
1406 | MAX_CSI_BLOCK_LANES : numlanes; | ||
1407 | /* maximum of 4 lanes are present per CSI block */ | ||
1408 | chan->csibase[idx] = vi->iomem + | ||
1409 | TEGRA_VI_CSI_BASE(chan->port[idx]); | ||
1410 | #ifdef T210 | ||
1411 | set_csi_portinfo(vi->csi, chan->port[idx], numlanes); | ||
1412 | #endif | ||
1413 | } | ||
1414 | /* based on gang mode valid ports will be updated - set default to 1 */ | ||
1415 | chan->valid_ports = chan->total_ports ? 1 : 0; | ||
1416 | return ret; | ||
1417 | } | ||
1418 | |||
1419 | int tegra_channel_init(struct tegra_channel *chan) | ||
1420 | { | ||
1421 | int ret; | ||
1422 | struct tegra_mc_vi *vi = chan->vi; | ||
1423 | |||
1424 | #ifdef T210 | ||
1425 | chan->fops = vi->vi->data->channel_fops; | ||
1426 | #endif | ||
1427 | ret = tegra_channel_csi_init(chan); | ||
1428 | if (ret) | ||
1429 | return ret; | ||
1430 | |||
1431 | chan->width_align = TEGRA_WIDTH_ALIGNMENT; | ||
1432 | chan->stride_align = TEGRA_STRIDE_ALIGNMENT; | ||
1433 | chan->num_subdevs = 0; | ||
1434 | mutex_init(&chan->video_lock); | ||
1435 | INIT_LIST_HEAD(&chan->capture); | ||
1436 | init_waitqueue_head(&chan->start_wait); | ||
1437 | spin_lock_init(&chan->start_lock); | ||
1438 | mutex_init(&chan->stop_kthread_lock); | ||
1439 | atomic_set(&chan->is_streaming, DISABLE); | ||
1440 | spin_lock_init(&chan->capture_state_lock); | ||
1441 | |||
1442 | /* Init video format */ | ||
1443 | vi->fops->vi_init_video_formats(chan); | ||
1444 | chan->fmtinfo = tegra_core_get_default_format(); | ||
1445 | tegra_channel_update_format(chan, TEGRA_DEF_WIDTH, | ||
1446 | TEGRA_DEF_HEIGHT, | ||
1447 | chan->fmtinfo->fourcc, | ||
1448 | &chan->fmtinfo->bpp, 0); | ||
1449 | |||
1450 | chan->buffer_offset[0] = 0; | ||
1451 | |||
1452 | /* Initialize the media entity... */ | ||
1453 | chan->pad.flags = MEDIA_PAD_FL_SINK; | ||
1454 | |||
1455 | ret = media_entity_init(&chan->video.entity, 1, &chan->pad, 0); | ||
1456 | if (ret < 0) { | ||
1457 | dev_err(&chan->video.dev, "failed to init video entity\n"); | ||
1458 | return ret; | ||
1459 | } | ||
1460 | |||
1461 | /* init control handler */ | ||
1462 | ret = v4l2_ctrl_handler_init(&chan->ctrl_handler, MAX_CID_CONTROLS); | ||
1463 | if (chan->ctrl_handler.error) { | ||
1464 | dev_err(&chan->video.dev, "failed to init control handler\n"); | ||
1465 | goto ctrl_init_error; | ||
1466 | } | ||
1467 | |||
1468 | /* init video node... */ | ||
1469 | chan->video.fops = &tegra_channel_fops; | ||
1470 | chan->video.v4l2_dev = &vi->v4l2_dev; | ||
1471 | chan->video.queue = &chan->queue; | ||
1472 | snprintf(chan->video.name, sizeof(chan->video.name), "%s-%s-%u", | ||
1473 | dev_name(vi->dev), chan->pg_mode ? "tpg" : "output", | ||
1474 | chan->port[0]); | ||
1475 | chan->video.vfl_type = VFL_TYPE_GRABBER; | ||
1476 | chan->video.vfl_dir = VFL_DIR_RX; | ||
1477 | chan->video.release = video_device_release_empty; | ||
1478 | chan->video.ioctl_ops = &tegra_channel_ioctl_ops; | ||
1479 | chan->video.ctrl_handler = &chan->ctrl_handler; | ||
1480 | chan->video.lock = &chan->video_lock; | ||
1481 | |||
1482 | set_bit(_IOC_NR(VIDIOC_G_PRIORITY), chan->video.valid_ioctls); | ||
1483 | set_bit(_IOC_NR(VIDIOC_S_PRIORITY), chan->video.valid_ioctls); | ||
1484 | |||
1485 | video_set_drvdata(&chan->video, chan); | ||
1486 | |||
1487 | #if defined(CONFIG_VIDEOBUF2_DMA_CONTIG) | ||
1488 | /* get the buffers queue... */ | ||
1489 | chan->alloc_ctx = vb2_dma_contig_init_ctx(chan->vi->dev); | ||
1490 | if (IS_ERR(chan->alloc_ctx)) { | ||
1491 | dev_err(chan->vi->dev, "failed to init vb2 buffer\n"); | ||
1492 | ret = -ENOMEM; | ||
1493 | goto vb2_init_error; | ||
1494 | } | ||
1495 | #endif | ||
1496 | |||
1497 | chan->queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1498 | chan->queue.io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ | VB2_USERPTR; | ||
1499 | chan->queue.lock = &chan->video_lock; | ||
1500 | chan->queue.drv_priv = chan; | ||
1501 | chan->queue.buf_struct_size = sizeof(struct tegra_channel_buffer); | ||
1502 | chan->queue.ops = &tegra_channel_queue_qops; | ||
1503 | #if defined(CONFIG_VIDEOBUF2_DMA_CONTIG) | ||
1504 | chan->queue.mem_ops = &vb2_dma_contig_memops; | ||
1505 | #endif | ||
1506 | chan->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC | ||
1507 | | V4L2_BUF_FLAG_TSTAMP_SRC_EOF; | ||
1508 | ret = vb2_queue_init(&chan->queue); | ||
1509 | if (ret < 0) { | ||
1510 | dev_err(chan->vi->dev, "failed to initialize VB2 queue\n"); | ||
1511 | goto vb2_queue_error; | ||
1512 | } | ||
1513 | |||
1514 | chan->init_done = true; | ||
1515 | return 0; | ||
1516 | |||
1517 | vb2_queue_error: | ||
1518 | #if defined(CONFIG_VIDEOBUF2_DMA_CONTIG) | ||
1519 | vb2_dma_contig_cleanup_ctx(chan->alloc_ctx); | ||
1520 | vb2_init_error: | ||
1521 | #endif | ||
1522 | v4l2_ctrl_handler_free(&chan->ctrl_handler); | ||
1523 | ctrl_init_error: | ||
1524 | media_entity_cleanup(&chan->video.entity); | ||
1525 | return ret; | ||
1526 | } | ||
1527 | |||
1528 | int tegra_channel_cleanup(struct tegra_channel *chan) | ||
1529 | { | ||
1530 | v4l2_ctrl_handler_free(&chan->ctrl_handler); | ||
1531 | vb2_queue_release(&chan->queue); | ||
1532 | #if defined(CONFIG_VIDEOBUF2_DMA_CONTIG) | ||
1533 | vb2_dma_contig_cleanup_ctx(chan->alloc_ctx); | ||
1534 | #endif | ||
1535 | |||
1536 | media_entity_cleanup(&chan->video.entity); | ||
1537 | |||
1538 | return 0; | ||
1539 | } | ||
1540 | |||
1541 | int tegra_vi_channels_register(struct tegra_mc_vi *vi) | ||
1542 | { | ||
1543 | int ret = 0; | ||
1544 | struct tegra_channel *it; | ||
1545 | int count = 0; | ||
1546 | |||
1547 | list_for_each_entry(it, &vi->vi_chans, list) { | ||
1548 | if (!it->init_done) | ||
1549 | continue; | ||
1550 | ret = video_register_device(&it->video, VFL_TYPE_GRABBER, -1); | ||
1551 | if (ret < 0) { | ||
1552 | dev_err(&it->video.dev, "failed to register %s\n", | ||
1553 | it->video.name); | ||
1554 | continue; | ||
1555 | } | ||
1556 | count++; | ||
1557 | } | ||
1558 | |||
1559 | if (count == 0) { | ||
1560 | dev_err(vi->dev, "all channel register failed\n"); | ||
1561 | return ret; | ||
1562 | } | ||
1563 | |||
1564 | return 0; | ||
1565 | } | ||
1566 | |||
1567 | void tegra_vi_channels_unregister(struct tegra_mc_vi *vi) | ||
1568 | { | ||
1569 | struct tegra_channel *it; | ||
1570 | |||
1571 | list_for_each_entry(it, &vi->vi_chans, list) { | ||
1572 | if (it->video.cdev != NULL) | ||
1573 | video_unregister_device(&it->video); | ||
1574 | } | ||
1575 | } | ||
1576 | |||
1577 | int tegra_vi_channels_init(struct tegra_mc_vi *vi) | ||
1578 | { | ||
1579 | int ret = 0; | ||
1580 | struct tegra_channel *it; | ||
1581 | int count = 0; | ||
1582 | |||
1583 | list_for_each_entry(it, &vi->vi_chans, list) { | ||
1584 | it->vi = vi; | ||
1585 | ret = tegra_channel_init(it); | ||
1586 | if (ret < 0) { | ||
1587 | dev_err(vi->dev, "channel init failed\n"); | ||
1588 | continue; | ||
1589 | } | ||
1590 | count++; | ||
1591 | } | ||
1592 | |||
1593 | if (count == 0) { | ||
1594 | dev_err(vi->dev, "all channel init failed\n"); | ||
1595 | return ret; | ||
1596 | } | ||
1597 | |||
1598 | return 0; | ||
1599 | } | ||
1600 | EXPORT_SYMBOL(tegra_vi_channels_init); | ||
1601 | |||
1602 | int tegra_vi_channels_cleanup(struct tegra_mc_vi *vi) | ||
1603 | { | ||
1604 | int ret = 0, err = 0; | ||
1605 | struct tegra_channel *it; | ||
1606 | |||
1607 | list_for_each_entry(it, &vi->vi_chans, list) { | ||
1608 | if (!it->init_done) | ||
1609 | continue; | ||
1610 | err = tegra_channel_cleanup(it); | ||
1611 | if (err < 0) { | ||
1612 | ret = err; | ||
1613 | dev_err(vi->dev, "channel cleanup failed, err %d\n", | ||
1614 | err); | ||
1615 | } | ||
1616 | } | ||
1617 | return ret; | ||
1618 | } | ||
1619 | EXPORT_SYMBOL(tegra_vi_channels_cleanup); | ||
1620 | |||
1621 | int tegra_clean_unlinked_channels(struct tegra_mc_vi *vi) | ||
1622 | { | ||
1623 | int ret, err = 0; | ||
1624 | struct tegra_channel *chan; | ||
1625 | |||
1626 | list_for_each_entry(chan, &vi->vi_chans, list) { | ||
1627 | struct v4l2_subdev *sd = chan->subdev_on_csi; | ||
1628 | bool is_csi = false; | ||
1629 | |||
1630 | /* | ||
1631 | * If subdevice on csi is csi itself, | ||
1632 | * then sensor subdevice is not connected | ||
1633 | */ | ||
1634 | if (sd) | ||
1635 | is_csi = strstr(sd->name, "nvcsi") != NULL; | ||
1636 | |||
1637 | if (chan->num_subdevs && !is_csi) | ||
1638 | continue; | ||
1639 | |||
1640 | ret = tegra_channel_cleanup(chan); | ||
1641 | if (ret < 0) { | ||
1642 | err = ret; | ||
1643 | dev_err(vi->dev, "channel cleanup failed, err %d\n", | ||
1644 | err); | ||
1645 | } | ||
1646 | } | ||
1647 | |||
1648 | return err; | ||
1649 | } | ||
1650 | EXPORT_SYMBOL(tegra_clean_unlinked_channels); | ||
diff --git a/drivers/media/platform/tegra/camera/vi/core.c b/drivers/media/platform/tegra/camera/vi/core.c new file mode 100644 index 000000000..97de67085 --- /dev/null +++ b/drivers/media/platform/tegra/camera/vi/core.c | |||
@@ -0,0 +1,173 @@ | |||
1 | /* | ||
2 | * NVIDIA Tegra Video Input Device Driver Core Helpers | ||
3 | * | ||
4 | * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * Author: Bryan Wu <pengw@nvidia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/export.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/of.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | |||
18 | #include "camera/vi/mc_common.h" | ||
19 | |||
20 | static const struct tegra_video_format tegra_default_format[] = { | ||
21 | { | ||
22 | TEGRA_VF_DEF, | ||
23 | 10, | ||
24 | MEDIA_BUS_FMT_SRGGB10_1X10, | ||
25 | {2, 1}, | ||
26 | TEGRA_IMAGE_FORMAT_DEF, | ||
27 | TEGRA_IMAGE_DT_RAW10, | ||
28 | V4L2_PIX_FMT_SRGGB10, | ||
29 | "RGRG.. GBGB..", | ||
30 | }, | ||
31 | }; | ||
32 | |||
33 | /* ----------------------------------------------------------------------------- | ||
34 | * Helper functions | ||
35 | */ | ||
36 | |||
37 | /** | ||
38 | * tegra_core_get_fourcc_by_idx - get fourcc of a tegra_video format | ||
39 | * @index: array index of the tegra_video_formats | ||
40 | * | ||
41 | * Return: fourcc code | ||
42 | */ | ||
43 | u32 tegra_core_get_fourcc_by_idx(struct tegra_channel *chan, | ||
44 | unsigned int index) | ||
45 | { | ||
46 | /* return default fourcc format if the index out of bounds */ | ||
47 | if (index > (chan->num_video_formats - 1)) | ||
48 | return V4L2_PIX_FMT_SGRBG10; | ||
49 | |||
50 | return chan->video_formats[index]->fourcc; | ||
51 | } | ||
52 | |||
53 | /** | ||
54 | * tegra_core_get_description_by_idx - get description of a tegra_video format | ||
55 | * @index: array index of the tegra_video_formats | ||
56 | */ | ||
57 | void tegra_core_get_description_by_idx(struct tegra_channel *chan, | ||
58 | unsigned int index, __u8 *description) | ||
59 | { | ||
60 | if (index > (chan->num_video_formats - 1)) | ||
61 | return; | ||
62 | |||
63 | if (description) | ||
64 | strlcpy(description, | ||
65 | chan->video_formats[index]->description, | ||
66 | sizeof(chan->video_formats[index]->description)); | ||
67 | } | ||
68 | |||
69 | /** | ||
70 | * tegra_core_get_word_count - Calculate word count | ||
71 | * @frame_width: number of pixels per line | ||
72 | * @fmt: Tegra Video format struct which has BPP information | ||
73 | * | ||
74 | * Return: word count number | ||
75 | */ | ||
76 | u32 tegra_core_get_word_count(unsigned int frame_width, | ||
77 | const struct tegra_video_format *fmt) | ||
78 | { | ||
79 | return frame_width * fmt->width / 8; | ||
80 | } | ||
81 | |||
82 | /** | ||
83 | * tegra_core_get_idx_by_code - Retrieve index for a media bus code | ||
84 | * @code: the format media bus code | ||
85 | * | ||
86 | * Return: a index to the format information structure corresponding to the | ||
87 | * given V4L2 media bus format @code, or -1 if no corresponding format can | ||
88 | * be found. | ||
89 | */ | ||
90 | int tegra_core_get_idx_by_code(struct tegra_channel *chan, | ||
91 | unsigned int code, unsigned offset) | ||
92 | { | ||
93 | unsigned int i; | ||
94 | |||
95 | for (i = offset; i < chan->num_video_formats; ++i) { | ||
96 | if (chan->video_formats[i]->code == code) | ||
97 | return i; | ||
98 | } | ||
99 | |||
100 | return -1; | ||
101 | } | ||
102 | |||
103 | /** | ||
104 | * tegra_core_get_default_format - Get default format | ||
105 | * | ||
106 | * Return: pointer to the format where the default format needs | ||
107 | * to be filled in. | ||
108 | */ | ||
109 | const struct tegra_video_format *tegra_core_get_default_format(void) | ||
110 | { | ||
111 | return &tegra_default_format[0]; | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * tegra_core_get_format_by_code - Retrieve format information for a media | ||
116 | * bus code | ||
117 | * @code: the format media bus code | ||
118 | * | ||
119 | * Return: a pointer to the format information structure corresponding to the | ||
120 | * given V4L2 media bus format @code, or NULL if no corresponding format can | ||
121 | * be found. | ||
122 | */ | ||
123 | const struct tegra_video_format * | ||
124 | tegra_core_get_format_by_code(struct tegra_channel *chan, | ||
125 | unsigned int code, unsigned offset) | ||
126 | { | ||
127 | unsigned int i; | ||
128 | |||
129 | for (i = offset; i < chan->num_video_formats; ++i) { | ||
130 | if (chan->video_formats[i]->code == code) | ||
131 | return chan->video_formats[i]; | ||
132 | } | ||
133 | |||
134 | return NULL; | ||
135 | } | ||
136 | |||
137 | /** | ||
138 | * tegra_core_get_format_by_fourcc - Retrieve format information for a 4CC | ||
139 | * @fourcc: the format 4CC | ||
140 | * | ||
141 | * Return: a pointer to the format information structure corresponding to the | ||
142 | * given V4L2 format @fourcc, or NULL if no corresponding format can be | ||
143 | * found. | ||
144 | */ | ||
145 | const struct tegra_video_format * | ||
146 | tegra_core_get_format_by_fourcc(struct tegra_channel *chan, u32 fourcc) | ||
147 | { | ||
148 | unsigned int i; | ||
149 | |||
150 | for (i = 0; i < chan->num_video_formats; ++i) { | ||
151 | if (chan->video_formats[i]->fourcc == fourcc) | ||
152 | return chan->video_formats[i]; | ||
153 | } | ||
154 | |||
155 | return NULL; | ||
156 | } | ||
157 | |||
158 | /** | ||
159 | * tegra_core_bytes_per_line - Calculate bytes per line in one frame | ||
160 | * @width: frame width | ||
161 | * @align: number of alignment bytes | ||
162 | * @fmt: Tegra Video format | ||
163 | * | ||
164 | * Simply calcualte the bytes_per_line and if it's not aligned it | ||
165 | * will be padded to alignment boundary. | ||
166 | */ | ||
167 | u32 tegra_core_bytes_per_line(unsigned int width, unsigned int align, | ||
168 | const struct tegra_video_format *fmt) | ||
169 | { | ||
170 | u32 value = ((width * fmt->bpp.numerator) / fmt->bpp.denominator); | ||
171 | |||
172 | return roundup(value, align); | ||
173 | } | ||
diff --git a/drivers/media/platform/tegra/camera/vi/core.h b/drivers/media/platform/tegra/camera/vi/core.h new file mode 100644 index 000000000..56b24fd59 --- /dev/null +++ b/drivers/media/platform/tegra/camera/vi/core.h | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | * NVIDIA Tegra Video Input Device Driver Core Helpers | ||
3 | * | ||
4 | * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * Author: Bryan Wu <pengw@nvidia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef __TEGRA_CORE_H__ | ||
14 | #define __TEGRA_CORE_H__ | ||
15 | |||
16 | #include <media/v4l2-subdev.h> | ||
17 | |||
18 | /* Minimum and maximum width and height common to Tegra video input device. */ | ||
19 | #define TEGRA_MIN_WIDTH 32U | ||
20 | #define TEGRA_MAX_WIDTH 32768U | ||
21 | #define TEGRA_MIN_HEIGHT 32U | ||
22 | #define TEGRA_MAX_HEIGHT 32768U | ||
23 | /* Width alignment */ | ||
24 | #define TEGRA_WIDTH_ALIGNMENT 1 | ||
25 | /* Stride alignment is 256, for VIC worse case */ | ||
26 | #define TEGRA_STRIDE_ALIGNMENT 256 | ||
27 | |||
28 | /* 1080p resolution as default resolution for test pattern generator */ | ||
29 | #define TEGRA_DEF_WIDTH 1920 | ||
30 | #define TEGRA_DEF_HEIGHT 1080 | ||
31 | |||
32 | #define TEGRA_VF_DEF MEDIA_BUS_FMT_SRGGB10_1X10 | ||
33 | #define TEGRA_IMAGE_FORMAT_DEF 32 | ||
34 | |||
35 | enum tegra_image_dt { | ||
36 | TEGRA_IMAGE_DT_YUV420_8 = 24, | ||
37 | TEGRA_IMAGE_DT_YUV420_10, | ||
38 | |||
39 | TEGRA_IMAGE_DT_YUV420CSPS_8 = 28, | ||
40 | TEGRA_IMAGE_DT_YUV420CSPS_10, | ||
41 | TEGRA_IMAGE_DT_YUV422_8, | ||
42 | TEGRA_IMAGE_DT_YUV422_10, | ||
43 | TEGRA_IMAGE_DT_RGB444, | ||
44 | TEGRA_IMAGE_DT_RGB555, | ||
45 | TEGRA_IMAGE_DT_RGB565, | ||
46 | TEGRA_IMAGE_DT_RGB666, | ||
47 | TEGRA_IMAGE_DT_RGB888, | ||
48 | |||
49 | TEGRA_IMAGE_DT_RAW6 = 40, | ||
50 | TEGRA_IMAGE_DT_RAW7, | ||
51 | TEGRA_IMAGE_DT_RAW8, | ||
52 | TEGRA_IMAGE_DT_RAW10, | ||
53 | TEGRA_IMAGE_DT_RAW12, | ||
54 | TEGRA_IMAGE_DT_RAW14, | ||
55 | }; | ||
56 | |||
57 | /* Supported CSI to VI Data Formats */ | ||
58 | enum tegra_vf_code { | ||
59 | TEGRA_VF_RAW6 = 0, | ||
60 | TEGRA_VF_RAW7, | ||
61 | TEGRA_VF_RAW8, | ||
62 | TEGRA_VF_RAW10, | ||
63 | TEGRA_VF_RAW12, | ||
64 | TEGRA_VF_RAW14, | ||
65 | TEGRA_VF_EMBEDDED8, | ||
66 | TEGRA_VF_RGB565, | ||
67 | TEGRA_VF_RGB555, | ||
68 | TEGRA_VF_RGB888, | ||
69 | TEGRA_VF_RGB444, | ||
70 | TEGRA_VF_RGB666, | ||
71 | TEGRA_VF_YUV422, | ||
72 | TEGRA_VF_YUV420, | ||
73 | TEGRA_VF_YUV420_CSPS, | ||
74 | }; | ||
75 | |||
76 | /** | ||
77 | * struct tegra_frac | ||
78 | * @numerator: numerator of the fraction | ||
79 | * @denominator: denominator of the fraction | ||
80 | */ | ||
81 | struct tegra_frac { | ||
82 | unsigned int numerator; | ||
83 | unsigned int denominator; | ||
84 | }; | ||
85 | |||
86 | /** | ||
87 | * struct tegra_video_format - Tegra video format description | ||
88 | * @vf_code: video format code | ||
89 | * @width: format width in bits per component | ||
90 | * @code: media bus format code | ||
91 | * @bpp: bytes per pixel fraction (when stored in memory) | ||
92 | * @img_fmt: image format | ||
93 | * @img_dt: image data type | ||
94 | * @fourcc: V4L2 pixel format FCC identifier | ||
95 | * @description: format description, suitable for userspace | ||
96 | */ | ||
97 | struct tegra_video_format { | ||
98 | enum tegra_vf_code vf_code; | ||
99 | unsigned int width; | ||
100 | unsigned int code; | ||
101 | struct tegra_frac bpp; | ||
102 | u32 img_fmt; | ||
103 | enum tegra_image_dt img_dt; | ||
104 | u32 fourcc; | ||
105 | __u8 description[32]; | ||
106 | }; | ||
107 | |||
108 | #define TEGRA_VIDEO_FORMAT(VF_CODE, BPP, MBUS_CODE, FRAC_BPP_NUM, \ | ||
109 | FRAC_BPP_DEN, FORMAT, DATA_TYPE, FOURCC, DESCRIPTION) \ | ||
110 | { \ | ||
111 | TEGRA_VF_##VF_CODE, \ | ||
112 | BPP, \ | ||
113 | MEDIA_BUS_FMT_##MBUS_CODE, \ | ||
114 | {FRAC_BPP_NUM, FRAC_BPP_DEN}, \ | ||
115 | TEGRA_IMAGE_FORMAT_##FORMAT, \ | ||
116 | TEGRA_IMAGE_DT_##DATA_TYPE, \ | ||
117 | V4L2_PIX_FMT_##FOURCC, \ | ||
118 | DESCRIPTION, \ | ||
119 | } | ||
120 | |||
121 | u32 tegra_core_get_word_count(unsigned int frame_width, | ||
122 | const struct tegra_video_format *fmt); | ||
123 | u32 tegra_core_bytes_per_line(unsigned int width, unsigned int align, | ||
124 | const struct tegra_video_format *fmt); | ||
125 | const struct tegra_video_format *tegra_core_get_default_format(void); | ||
126 | |||
127 | #endif | ||
diff --git a/drivers/media/platform/tegra/camera/vi/graph.c b/drivers/media/platform/tegra/camera/vi/graph.c new file mode 100644 index 000000000..c2dd058a1 --- /dev/null +++ b/drivers/media/platform/tegra/camera/vi/graph.c | |||
@@ -0,0 +1,602 @@ | |||
1 | /* | ||
2 | * NVIDIA Media controller graph management | ||
3 | * | ||
4 | * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * Author: Bryan Wu <pengw@nvidia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #include <linux/clk.h> | ||
13 | #include <linux/list.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/of.h> | ||
16 | #include <linux/of_graph.h> | ||
17 | #include <linux/of_device.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/regulator/consumer.h> | ||
20 | #include <linux/reset.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/tegra-soc.h> | ||
23 | #include <linux/tegra_pm_domains.h> | ||
24 | |||
25 | #include <media/media-device.h> | ||
26 | #include <media/v4l2-async.h> | ||
27 | #include <media/v4l2-common.h> | ||
28 | #include <media/v4l2-device.h> | ||
29 | #include <media/v4l2-of.h> | ||
30 | #include <media/tegra_v4l2_camera.h> | ||
31 | |||
32 | #include "camera/vi/mc_common.h" | ||
33 | #include "camera/csi/csi.h" | ||
34 | #include "vi/vi4.h" | ||
35 | #include "nvcsi/nvcsi.h" | ||
36 | |||
37 | /* ----------------------------------------------------------------------------- | ||
38 | * Graph Management | ||
39 | */ | ||
40 | |||
41 | static struct tegra_vi_graph_entity * | ||
42 | tegra_vi_graph_find_entity(struct tegra_mc_vi *vi, | ||
43 | const struct device_node *node) | ||
44 | { | ||
45 | struct tegra_vi_graph_entity *entity; | ||
46 | |||
47 | list_for_each_entry(entity, &vi->entities, list) { | ||
48 | if (entity->node == node) | ||
49 | return entity; | ||
50 | } | ||
51 | |||
52 | return NULL; | ||
53 | } | ||
54 | |||
55 | static int tegra_vi_graph_build_one(struct tegra_mc_vi *vi, | ||
56 | struct tegra_vi_graph_entity *entity) | ||
57 | { | ||
58 | u32 link_flags = MEDIA_LNK_FL_ENABLED; | ||
59 | struct media_entity *local; | ||
60 | struct media_entity *remote; | ||
61 | struct media_pad *local_pad; | ||
62 | struct media_pad *remote_pad; | ||
63 | struct tegra_vi_graph_entity *ent; | ||
64 | struct v4l2_of_link link; | ||
65 | struct device_node *ep = NULL; | ||
66 | struct device_node *next; | ||
67 | int ret = 0; | ||
68 | |||
69 | if (!entity->subdev) { | ||
70 | dev_err(vi->dev, "%s:No subdev under entity, skip linking\n", | ||
71 | __func__); | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | local = entity->entity; | ||
76 | dev_dbg(vi->dev, "creating links for entity %s\n", local->name); | ||
77 | |||
78 | do { | ||
79 | /* Get the next endpoint and parse its link. */ | ||
80 | next = of_graph_get_next_endpoint(entity->node, ep); | ||
81 | if (next == NULL) | ||
82 | break; | ||
83 | |||
84 | ep = next; | ||
85 | |||
86 | dev_dbg(vi->dev, "processing endpoint %s\n", ep->full_name); | ||
87 | |||
88 | ret = v4l2_of_parse_link(ep, &link); | ||
89 | if (ret < 0) { | ||
90 | dev_err(vi->dev, "failed to parse link for %s\n", | ||
91 | ep->full_name); | ||
92 | continue; | ||
93 | } | ||
94 | |||
95 | /* Skip sink ports, they will be processed from the other end of | ||
96 | * the link. | ||
97 | */ | ||
98 | if (link.local_port >= local->num_pads) { | ||
99 | dev_err(vi->dev, "invalid port number %u on %s\n", | ||
100 | link.local_port, link.local_node->full_name); | ||
101 | v4l2_of_put_link(&link); | ||
102 | ret = -EINVAL; | ||
103 | break; | ||
104 | } | ||
105 | |||
106 | local_pad = &local->pads[link.local_port]; | ||
107 | |||
108 | if (local_pad->flags & MEDIA_PAD_FL_SINK) { | ||
109 | dev_dbg(vi->dev, "skipping sink port %s:%u\n", | ||
110 | link.local_node->full_name, link.local_port); | ||
111 | v4l2_of_put_link(&link); | ||
112 | continue; | ||
113 | } | ||
114 | |||
115 | /* Skip channel entity , they will be processed separately. */ | ||
116 | if (link.remote_node == vi->dev->of_node) { | ||
117 | dev_dbg(vi->dev, "skipping channel port %s:%u\n", | ||
118 | link.local_node->full_name, link.local_port); | ||
119 | v4l2_of_put_link(&link); | ||
120 | continue; | ||
121 | } | ||
122 | |||
123 | /* Find the remote entity. */ | ||
124 | ent = tegra_vi_graph_find_entity(vi, link.remote_node); | ||
125 | if (ent == NULL) { | ||
126 | dev_err(vi->dev, "no entity found for %s\n", | ||
127 | link.remote_node->full_name); | ||
128 | v4l2_of_put_link(&link); | ||
129 | ret = -EINVAL; | ||
130 | break; | ||
131 | } | ||
132 | |||
133 | remote = ent->entity; | ||
134 | |||
135 | if (link.remote_port >= remote->num_pads) { | ||
136 | dev_err(vi->dev, "invalid port number %u on %s\n", | ||
137 | link.remote_port, link.remote_node->full_name); | ||
138 | v4l2_of_put_link(&link); | ||
139 | ret = -EINVAL; | ||
140 | break; | ||
141 | } | ||
142 | |||
143 | remote_pad = &remote->pads[link.remote_port]; | ||
144 | |||
145 | v4l2_of_put_link(&link); | ||
146 | |||
147 | /* Create the media link. */ | ||
148 | dev_dbg(vi->dev, "creating %s:%u -> %s:%u link\n", | ||
149 | local->name, local_pad->index, | ||
150 | remote->name, remote_pad->index); | ||
151 | |||
152 | ret = media_entity_create_link(local, local_pad->index, | ||
153 | remote, remote_pad->index, | ||
154 | link_flags); | ||
155 | if (ret < 0) { | ||
156 | dev_err(vi->dev, | ||
157 | "failed to create %s:%u -> %s:%u link\n", | ||
158 | local->name, local_pad->index, | ||
159 | remote->name, remote_pad->index); | ||
160 | break; | ||
161 | } | ||
162 | } while (next); | ||
163 | |||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | static int tegra_vi_graph_build_links(struct tegra_mc_vi *vi) | ||
168 | { | ||
169 | u32 link_flags = MEDIA_LNK_FL_ENABLED; | ||
170 | struct device_node *node = vi->dev->of_node; | ||
171 | struct media_entity *source; | ||
172 | struct media_entity *sink; | ||
173 | struct media_pad *source_pad; | ||
174 | struct media_pad *sink_pad; | ||
175 | struct tegra_vi_graph_entity *ent; | ||
176 | struct v4l2_of_link link; | ||
177 | struct device_node *ep = NULL; | ||
178 | struct device_node *next; | ||
179 | struct tegra_channel *chan; | ||
180 | int ret = 0; | ||
181 | |||
182 | dev_dbg(vi->dev, "creating links for channels\n"); | ||
183 | |||
184 | chan = list_first_entry(&vi->vi_chans, struct tegra_channel, list); | ||
185 | do { | ||
186 | /* Get the next endpoint and parse its link. */ | ||
187 | next = of_graph_get_next_endpoint(node, ep); | ||
188 | if (next == NULL || !of_device_is_available(next)) | ||
189 | break; | ||
190 | |||
191 | /* Device not registered */ | ||
192 | if (!chan->init_done) { | ||
193 | chan = list_next_entry(chan, list); | ||
194 | continue; | ||
195 | } | ||
196 | |||
197 | ep = next; | ||
198 | |||
199 | dev_dbg(vi->dev, "processing endpoint %s\n", ep->full_name); | ||
200 | |||
201 | ret = v4l2_of_parse_link(ep, &link); | ||
202 | if (ret < 0) { | ||
203 | dev_err(vi->dev, "failed to parse link for %s\n", | ||
204 | ep->full_name); | ||
205 | continue; | ||
206 | } | ||
207 | |||
208 | if (link.local_port >= vi->num_channels) { | ||
209 | dev_err(vi->dev, "wrong channel number for port %u\n", | ||
210 | link.local_port); | ||
211 | v4l2_of_put_link(&link); | ||
212 | ret = -EINVAL; | ||
213 | break; | ||
214 | } | ||
215 | |||
216 | dev_dbg(vi->dev, "creating link for channel %s\n", | ||
217 | chan->video.name); | ||
218 | |||
219 | /* Find the remote entity. */ | ||
220 | ent = tegra_vi_graph_find_entity(vi, link.remote_node); | ||
221 | if (ent == NULL) { | ||
222 | dev_err(vi->dev, "no entity found for %s\n", | ||
223 | link.remote_node->full_name); | ||
224 | v4l2_of_put_link(&link); | ||
225 | ret = -EINVAL; | ||
226 | break; | ||
227 | } | ||
228 | |||
229 | if (ent->entity == NULL) { | ||
230 | dev_err(vi->dev, "entity not bounded %s\n", | ||
231 | link.remote_node->full_name); | ||
232 | continue; | ||
233 | } | ||
234 | |||
235 | source = ent->entity; | ||
236 | source_pad = &source->pads[link.remote_port]; | ||
237 | sink = &chan->video.entity; | ||
238 | sink_pad = &chan->pad; | ||
239 | |||
240 | v4l2_of_put_link(&link); | ||
241 | |||
242 | /* Create the media link. */ | ||
243 | dev_dbg(vi->dev, "creating %s:%u -> %s:%u link\n", | ||
244 | source->name, source_pad->index, | ||
245 | sink->name, sink_pad->index); | ||
246 | |||
247 | ret = media_entity_create_link(source, source_pad->index, | ||
248 | sink, sink_pad->index, | ||
249 | link_flags); | ||
250 | if (ret < 0) { | ||
251 | dev_err(vi->dev, | ||
252 | "failed to create %s:%u -> %s:%u link\n", | ||
253 | source->name, source_pad->index, | ||
254 | sink->name, sink_pad->index); | ||
255 | break; | ||
256 | } | ||
257 | |||
258 | tegra_channel_init_subdevices(chan); | ||
259 | chan = list_next_entry(chan, list); | ||
260 | } while (next != NULL); | ||
261 | |||
262 | return ret; | ||
263 | } | ||
264 | |||
265 | static int tegra_vi_graph_notify_complete(struct v4l2_async_notifier *notifier) | ||
266 | { | ||
267 | struct tegra_mc_vi *vi = | ||
268 | container_of(notifier, struct tegra_mc_vi, notifier); | ||
269 | struct tegra_vi_graph_entity *entity; | ||
270 | int ret; | ||
271 | |||
272 | dev_dbg(vi->dev, "notify complete, all subdevs registered\n"); | ||
273 | |||
274 | /* Create links for every entity. */ | ||
275 | list_for_each_entry(entity, &vi->entities, list) { | ||
276 | if (entity->entity != NULL) { | ||
277 | ret = tegra_vi_graph_build_one(vi, entity); | ||
278 | if (ret < 0) | ||
279 | return ret; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | /* Create links for channels */ | ||
284 | ret = tegra_vi_graph_build_links(vi); | ||
285 | if (ret < 0) | ||
286 | return ret; | ||
287 | |||
288 | ret = v4l2_device_register_subdev_nodes(&vi->v4l2_dev); | ||
289 | if (ret < 0) | ||
290 | dev_err(vi->dev, "failed to register subdev nodes\n"); | ||
291 | |||
292 | vi->link_status++; | ||
293 | |||
294 | return ret; | ||
295 | } | ||
296 | |||
297 | static int tegra_vi_graph_notify_bound(struct v4l2_async_notifier *notifier, | ||
298 | struct v4l2_subdev *subdev, | ||
299 | struct v4l2_async_subdev *asd) | ||
300 | { | ||
301 | struct tegra_mc_vi *vi = | ||
302 | container_of(notifier, struct tegra_mc_vi, notifier); | ||
303 | struct tegra_vi_graph_entity *entity; | ||
304 | |||
305 | /* Locate the entity corresponding to the bound subdev and store the | ||
306 | * subdev pointer. | ||
307 | */ | ||
308 | list_for_each_entry(entity, &vi->entities, list) { | ||
309 | if (entity->node != subdev->dev->of_node && | ||
310 | entity->node != subdev->of_node) | ||
311 | continue; | ||
312 | |||
313 | if (entity->subdev) { | ||
314 | dev_err(vi->dev, "duplicate subdev for node %s\n", | ||
315 | entity->node->full_name); | ||
316 | return -EINVAL; | ||
317 | } | ||
318 | |||
319 | dev_dbg(vi->dev, "subdev %s bound\n", subdev->name); | ||
320 | entity->entity = &subdev->entity; | ||
321 | entity->subdev = subdev; | ||
322 | vi->subdevs_bound++; | ||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | dev_err(vi->dev, "no entity for subdev %s\n", subdev->name); | ||
327 | return -EINVAL; | ||
328 | } | ||
329 | |||
330 | void tegra_vi_graph_cleanup(struct tegra_mc_vi *vi) | ||
331 | { | ||
332 | struct tegra_vi_graph_entity *entityp; | ||
333 | struct tegra_vi_graph_entity *entity; | ||
334 | |||
335 | v4l2_async_notifier_unregister(&vi->notifier); | ||
336 | |||
337 | list_for_each_entry_safe(entity, entityp, &vi->entities, list) { | ||
338 | of_node_put(entity->node); | ||
339 | list_del(&entity->list); | ||
340 | } | ||
341 | } | ||
342 | |||
343 | int tegra_vi_get_port_info(struct tegra_channel *chan, | ||
344 | struct device_node *node, unsigned int index) | ||
345 | { | ||
346 | struct device_node *ep = NULL; | ||
347 | struct device_node *ports; | ||
348 | struct device_node *port; | ||
349 | int value = 0xFFFF; | ||
350 | int ret = 0, i; | ||
351 | |||
352 | ports = of_get_child_by_name(node, "ports"); | ||
353 | if (ports == NULL) | ||
354 | ports = node; | ||
355 | |||
356 | for_each_child_of_node(ports, port) { | ||
357 | if (!port->name || of_node_cmp(port->name, "port")) | ||
358 | continue; | ||
359 | |||
360 | ret = of_property_read_u32(port, "reg", &value); | ||
361 | if (ret < 0) | ||
362 | continue; | ||
363 | |||
364 | if (value != index) | ||
365 | continue; | ||
366 | |||
367 | for_each_child_of_node(port, ep) { | ||
368 | if (!ep->name || of_node_cmp(ep->name, "endpoint")) | ||
369 | continue; | ||
370 | |||
371 | /* Get CSI port */ | ||
372 | ret = of_property_read_u32(ep, "csi-port", &value); | ||
373 | if (ret < 0) | ||
374 | dev_err(&chan->video.dev, "csi port error\n"); | ||
375 | chan->port[0] = value; | ||
376 | |||
377 | /* Get number of data lanes for the endpoint */ | ||
378 | ret = of_property_read_u32(ep, "bus-width", &value); | ||
379 | if (ret < 0) | ||
380 | dev_err(&chan->video.dev, "num lanes error\n"); | ||
381 | chan->numlanes = value; | ||
382 | |||
383 | if (value > 12) { | ||
384 | dev_err(&chan->video.dev, "num lanes >12!\n"); | ||
385 | return -EINVAL; | ||
386 | } | ||
387 | /* | ||
388 | * for numlanes greater than 4 multiple CSI bricks | ||
389 | * are needed to capture the image, the logic below | ||
390 | * checks for numlanes > 4 and add a new CSI brick | ||
391 | * as a valid port. Loops around the three CSI | ||
392 | * bricks to add as many ports necessary. | ||
393 | */ | ||
394 | value -= 4; | ||
395 | for (i = 1; value > 0; i++, value -= 4) { | ||
396 | int next_port = chan->port[i-1] + 2; | ||
397 | |||
398 | next_port = (next_port % (PORT_F + 1)); | ||
399 | chan->port[i] = next_port; | ||
400 | } | ||
401 | } | ||
402 | } | ||
403 | |||
404 | return ret; | ||
405 | } | ||
406 | |||
407 | static int tegra_vi_graph_parse_one(struct tegra_mc_vi *vi, | ||
408 | struct device_node *node) | ||
409 | { | ||
410 | struct device_node *ep = NULL; | ||
411 | struct device_node *next; | ||
412 | struct device_node *remote = NULL; | ||
413 | struct tegra_vi_graph_entity *entity; | ||
414 | int ret = 0; | ||
415 | |||
416 | dev_dbg(vi->dev, "parsing node %s\n", node->full_name); | ||
417 | |||
418 | do { | ||
419 | /* Parse all the remote entities and put them into the list */ | ||
420 | next = of_graph_get_next_endpoint(node, ep); | ||
421 | if (next == NULL || !of_device_is_available(next)) | ||
422 | break; | ||
423 | ep = next; | ||
424 | |||
425 | dev_dbg(vi->dev, "handling endpoint %s\n", ep->full_name); | ||
426 | |||
427 | remote = of_graph_get_remote_port_parent(ep); | ||
428 | if (!remote) { | ||
429 | ret = -EINVAL; | ||
430 | break; | ||
431 | } | ||
432 | |||
433 | /* Skip entities that we have already processed. */ | ||
434 | if (remote == vi->dev->of_node || | ||
435 | tegra_vi_graph_find_entity(vi, remote) || | ||
436 | !of_device_is_available(remote)) | ||
437 | continue; | ||
438 | |||
439 | entity = devm_kzalloc(vi->dev, sizeof(*entity), | ||
440 | GFP_KERNEL); | ||
441 | if (entity == NULL) { | ||
442 | ret = -ENOMEM; | ||
443 | break; | ||
444 | } | ||
445 | |||
446 | entity->node = remote; | ||
447 | entity->asd.match_type = V4L2_ASYNC_MATCH_OF; | ||
448 | entity->asd.match.of.node = remote; | ||
449 | list_add_tail(&entity->list, &vi->entities); | ||
450 | vi->num_subdevs++; | ||
451 | } while (next); | ||
452 | |||
453 | return ret; | ||
454 | } | ||
455 | |||
456 | int tegra_vi_tpg_graph_init(struct tegra_mc_vi *mc_vi) | ||
457 | { | ||
458 | int err = 0; | ||
459 | u32 link_flags = MEDIA_LNK_FL_ENABLED; | ||
460 | struct tegra_csi_device *csi = mc_vi->csi; | ||
461 | struct tegra_channel *vi_it; | ||
462 | struct tegra_csi_channel *csi_it; | ||
463 | |||
464 | if (!csi) { | ||
465 | dev_err(mc_vi->dev, "CSI is NULL\n"); | ||
466 | return -EINVAL; | ||
467 | } | ||
468 | mc_vi->num_subdevs = mc_vi->num_channels; | ||
469 | vi_it = mc_vi->tpg_start; | ||
470 | csi_it = csi->tpg_start; | ||
471 | |||
472 | list_for_each_entry_from(vi_it, &mc_vi->vi_chans, list) { | ||
473 | /* Device not registered */ | ||
474 | if (!vi_it->init_done) | ||
475 | continue; | ||
476 | |||
477 | list_for_each_entry_from(csi_it, &csi->csi_chans, list) { | ||
478 | struct media_entity *source = &csi_it->subdev.entity; | ||
479 | struct media_entity *sink = &vi_it->video.entity; | ||
480 | struct media_pad *source_pad = csi_it->pads; | ||
481 | struct media_pad *sink_pad = &vi_it->pad; | ||
482 | |||
483 | vi_it->bypass = 0; | ||
484 | err = v4l2_device_register_subdev(&mc_vi->v4l2_dev, | ||
485 | &csi_it->subdev); | ||
486 | if (err) { | ||
487 | dev_err(mc_vi->dev, | ||
488 | "%s:Fail to register subdev\n", | ||
489 | __func__); | ||
490 | goto register_fail; | ||
491 | } | ||
492 | dev_dbg(mc_vi->dev, "creating %s:%u -> %s:%u link\n", | ||
493 | source->name, source_pad->index, | ||
494 | sink->name, sink_pad->index); | ||
495 | |||
496 | err = media_entity_create_link(source, | ||
497 | source_pad->index, | ||
498 | sink, sink_pad->index, | ||
499 | link_flags); | ||
500 | if (err < 0) { | ||
501 | dev_err(mc_vi->dev, | ||
502 | "failed to create %s:%u -> %s:%u link\n", | ||
503 | source->name, source_pad->index, | ||
504 | sink->name, sink_pad->index); | ||
505 | goto register_fail; | ||
506 | } | ||
507 | err = tegra_channel_init_subdevices(vi_it); | ||
508 | if (err) { | ||
509 | dev_err(mc_vi->dev, | ||
510 | "%s:Init subdevice error\n", __func__); | ||
511 | goto register_fail; | ||
512 | } | ||
513 | csi_it = list_next_entry(csi_it, list); | ||
514 | break; | ||
515 | } | ||
516 | } | ||
517 | |||
518 | return 0; | ||
519 | register_fail: | ||
520 | csi_it = csi->tpg_start; | ||
521 | list_for_each_entry_from(csi_it, &csi->csi_chans, list) | ||
522 | v4l2_device_unregister_subdev(&csi_it->subdev); | ||
523 | return err; | ||
524 | } | ||
525 | |||
526 | int tegra_vi_graph_init(struct tegra_mc_vi *vi) | ||
527 | { | ||
528 | struct tegra_vi_graph_entity *entity; | ||
529 | struct v4l2_async_subdev **subdevs = NULL; | ||
530 | unsigned int num_subdevs = 0; | ||
531 | int ret = 0, i; | ||
532 | |||
533 | /* | ||
534 | * Walk the links to parse the full graph. Start by parsing the | ||
535 | * composite node and then parse entities in turn. The list_for_each | ||
536 | * loop will handle entities added at the end of the list while walking | ||
537 | * the links. | ||
538 | */ | ||
539 | ret = tegra_vi_graph_parse_one(vi, vi->dev->of_node); | ||
540 | if (ret < 0) | ||
541 | return 0; | ||
542 | |||
543 | list_for_each_entry(entity, &vi->entities, list) { | ||
544 | ret = tegra_vi_graph_parse_one(vi, entity->node); | ||
545 | if (ret < 0) | ||
546 | break; | ||
547 | } | ||
548 | |||
549 | if (!vi->num_subdevs) { | ||
550 | dev_dbg(vi->dev, "warning: no subdev found in graph\n"); | ||
551 | goto done; | ||
552 | } | ||
553 | |||
554 | /* Register the subdevices notifier. */ | ||
555 | num_subdevs = vi->num_subdevs; | ||
556 | subdevs = devm_kzalloc(vi->dev, sizeof(*subdevs) * num_subdevs, | ||
557 | GFP_KERNEL); | ||
558 | if (subdevs == NULL) { | ||
559 | ret = -ENOMEM; | ||
560 | goto done; | ||
561 | } | ||
562 | |||
563 | /* | ||
564 | * Add code to check for sensors and | ||
565 | * set TPG mode for VI if no sensors found | ||
566 | * logic varies for different platforms | ||
567 | */ | ||
568 | i = 0; | ||
569 | list_for_each_entry(entity, &vi->entities, list) | ||
570 | subdevs[i++] = &entity->asd; | ||
571 | |||
572 | vi->notifier.subdevs = subdevs; | ||
573 | vi->notifier.num_subdevs = num_subdevs; | ||
574 | vi->notifier.bound = tegra_vi_graph_notify_bound; | ||
575 | vi->notifier.complete = tegra_vi_graph_notify_complete; | ||
576 | vi->link_status = 0; | ||
577 | vi->subdevs_bound = 0; | ||
578 | |||
579 | ret = v4l2_async_notifier_register(&vi->v4l2_dev, &vi->notifier); | ||
580 | if (ret < 0) { | ||
581 | dev_err(vi->dev, "notifier registration failed\n"); | ||
582 | goto done; | ||
583 | } | ||
584 | |||
585 | if (!vi->link_status) { | ||
586 | if (vi->subdevs_bound) { | ||
587 | ret = tegra_vi_graph_notify_complete(&vi->notifier); | ||
588 | if (ret < 0) | ||
589 | goto done; | ||
590 | } | ||
591 | tegra_clean_unlinked_channels(vi); | ||
592 | } | ||
593 | |||
594 | return 0; | ||
595 | |||
596 | done: | ||
597 | tegra_clean_unlinked_channels(vi); | ||
598 | if (ret < 0) | ||
599 | tegra_vi_graph_cleanup(vi); | ||
600 | |||
601 | return ret; | ||
602 | } | ||
diff --git a/drivers/media/platform/tegra/camera/vi/mc_common.c b/drivers/media/platform/tegra/camera/vi/mc_common.c new file mode 100644 index 000000000..11acb7cfe --- /dev/null +++ b/drivers/media/platform/tegra/camera/vi/mc_common.c | |||
@@ -0,0 +1,346 @@ | |||
1 | /* | ||
2 | * Tegra Video Input device common APIs | ||
3 | * | ||
4 | * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * Author: Bryan Wu <pengw@nvidia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | #include <linux/export.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/of.h> | ||
17 | #include <linux/of_device.h> | ||
18 | #include <linux/of_platform.h> | ||
19 | |||
20 | #include <media/tegra_v4l2_camera.h> | ||
21 | #include <media/camera_common.h> | ||
22 | #include <media/v4l2-event.h> | ||
23 | #include <media/tegra_camera_platform.h> | ||
24 | |||
25 | #include "dev.h" | ||
26 | #include "camera/vi/mc_common.h" | ||
27 | #include "vi/vi.h" | ||
28 | #include "vi/vi4.h" | ||
29 | #include "host1x/host1x.h" | ||
30 | #include "camera/vi/registers.h" | ||
31 | |||
32 | /* In TPG mode, VI only support 2 formats */ | ||
33 | static void vi_tpg_fmts_bitmap_init(struct tegra_channel *chan) | ||
34 | { | ||
35 | int index; | ||
36 | |||
37 | bitmap_zero(chan->fmts_bitmap, MAX_FORMAT_NUM); | ||
38 | |||
39 | index = tegra_core_get_idx_by_code(chan, | ||
40 | MEDIA_BUS_FMT_SRGGB10_1X10, 0); | ||
41 | bitmap_set(chan->fmts_bitmap, index, 1); | ||
42 | |||
43 | index = tegra_core_get_idx_by_code(chan, | ||
44 | MEDIA_BUS_FMT_RGB888_1X32_PADHI, 0); | ||
45 | bitmap_set(chan->fmts_bitmap, index, 1); | ||
46 | } | ||
47 | |||
48 | /* ----------------------------------------------------------------------------- | ||
49 | * Media Controller and V4L2 | ||
50 | */ | ||
51 | |||
52 | static const char *const vi_pattern_strings[] = { | ||
53 | "Disabled", | ||
54 | "Black/White Direct Mode", | ||
55 | "Color Patch Mode", | ||
56 | }; | ||
57 | |||
58 | static int vi_s_ctrl(struct v4l2_ctrl *ctrl) | ||
59 | { | ||
60 | struct tegra_mc_vi *vi = container_of(ctrl->handler, struct tegra_mc_vi, | ||
61 | ctrl_handler); | ||
62 | |||
63 | switch (ctrl->id) { | ||
64 | case V4L2_CID_TEST_PATTERN: | ||
65 | /* | ||
66 | * TPG control is only avaiable to TPG driver, | ||
67 | * it can't be changed to 0 to disable TPG mode. | ||
68 | */ | ||
69 | if (ctrl->val) { | ||
70 | dev_info(&vi->ndev->dev, "Set TPG mode to %d\n", | ||
71 | ctrl->val); | ||
72 | vi->pg_mode = ctrl->val; | ||
73 | } | ||
74 | break; | ||
75 | default: | ||
76 | dev_err(vi->dev, "%s:Not valid ctrl\n", __func__); | ||
77 | return -EINVAL; | ||
78 | } | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static const struct v4l2_ctrl_ops vi_ctrl_ops = { | ||
84 | .s_ctrl = vi_s_ctrl, | ||
85 | }; | ||
86 | |||
87 | void tegra_vi_v4l2_cleanup(struct tegra_mc_vi *vi) | ||
88 | { | ||
89 | v4l2_ctrl_handler_free(&vi->ctrl_handler); | ||
90 | v4l2_device_unregister(&vi->v4l2_dev); | ||
91 | if (!vi->pg_mode) | ||
92 | media_device_unregister(&vi->media_dev); | ||
93 | } | ||
94 | EXPORT_SYMBOL(tegra_vi_v4l2_cleanup); | ||
95 | |||
96 | static void tegra_vi_notify(struct v4l2_subdev *sd, | ||
97 | unsigned int notification, void *arg) | ||
98 | { | ||
99 | struct tegra_mc_vi *vi = container_of(sd->v4l2_dev, | ||
100 | struct tegra_mc_vi, v4l2_dev); | ||
101 | unsigned i; | ||
102 | struct tegra_channel *chan; | ||
103 | |||
104 | if (notification != V4L2_DEVICE_NOTIFY_EVENT) | ||
105 | return; | ||
106 | |||
107 | list_for_each_entry(chan, &vi->vi_chans, list) { | ||
108 | for (i = 0; i < chan->num_subdevs; i++) | ||
109 | if (sd == chan->subdev[i]) | ||
110 | v4l2_event_queue(&chan->video, arg); | ||
111 | } | ||
112 | } | ||
113 | |||
114 | int tegra_vi_v4l2_init(struct tegra_mc_vi *vi) | ||
115 | { | ||
116 | int ret; | ||
117 | |||
118 | vi->media_dev.dev = vi->dev; | ||
119 | strlcpy(vi->media_dev.model, "NVIDIA Tegra Video Input Device", | ||
120 | sizeof(vi->media_dev.model)); | ||
121 | vi->media_dev.hw_revision = 3; | ||
122 | |||
123 | ret = media_device_register(&vi->media_dev); | ||
124 | if (ret < 0) { | ||
125 | dev_err(vi->dev, | ||
126 | "media device registration failed (%d)\n", | ||
127 | ret); | ||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | mutex_init(&vi->bw_update_lock); | ||
132 | vi->v4l2_dev.mdev = &vi->media_dev; | ||
133 | vi->v4l2_dev.notify = tegra_vi_notify; | ||
134 | ret = v4l2_device_register(vi->dev, &vi->v4l2_dev); | ||
135 | if (ret < 0) { | ||
136 | dev_err(vi->dev, "V4L2 device registration failed (%d)\n", | ||
137 | ret); | ||
138 | goto register_error; | ||
139 | } | ||
140 | |||
141 | return 0; | ||
142 | |||
143 | register_error: | ||
144 | media_device_unregister(&vi->media_dev); | ||
145 | return ret; | ||
146 | } | ||
147 | |||
148 | static int vi_parse_dt(struct tegra_mc_vi *vi, struct platform_device *dev) | ||
149 | { | ||
150 | int err = 0; | ||
151 | int num_channels = 0; | ||
152 | int i; | ||
153 | struct tegra_channel *item; | ||
154 | struct device_node *node = dev->dev.of_node; | ||
155 | |||
156 | err = of_property_read_u32(node, "num-channels", &num_channels); | ||
157 | if (err) { | ||
158 | dev_dbg(&dev->dev, | ||
159 | "Failed to find num of channels, set to 0\n"); | ||
160 | num_channels = 0; | ||
161 | } | ||
162 | vi->num_channels = num_channels; | ||
163 | for (i = 0; i < num_channels; i++) { | ||
164 | item = devm_kzalloc(vi->dev, sizeof(*item), GFP_KERNEL); | ||
165 | if (!item) | ||
166 | return -ENOMEM; | ||
167 | item->id = i; | ||
168 | list_add_tail(&item->list, &vi->vi_chans); | ||
169 | } | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static void set_vi_register_base(struct tegra_mc_vi *mc_vi, | ||
175 | void __iomem *regbase) | ||
176 | { | ||
177 | mc_vi->iomem = regbase; | ||
178 | } | ||
179 | int tpg_vi_media_controller_init(struct tegra_mc_vi *mc_vi, int pg_mode) | ||
180 | { | ||
181 | int err = 0, i; | ||
182 | struct tegra_channel *item; | ||
183 | int count = 0; | ||
184 | |||
185 | /* Allocate TPG channel */ | ||
186 | v4l2_ctrl_handler_init(&mc_vi->ctrl_handler, 1); | ||
187 | mc_vi->pattern = v4l2_ctrl_new_std_menu_items(&mc_vi->ctrl_handler, | ||
188 | &vi_ctrl_ops, V4L2_CID_TEST_PATTERN, | ||
189 | ARRAY_SIZE(vi_pattern_strings) - 1, | ||
190 | 0, mc_vi->pg_mode, vi_pattern_strings); | ||
191 | |||
192 | if (mc_vi->ctrl_handler.error) { | ||
193 | dev_err(mc_vi->dev, "failed to add controls\n"); | ||
194 | err = mc_vi->ctrl_handler.error; | ||
195 | goto ctrl_error; | ||
196 | } | ||
197 | |||
198 | mc_vi->tpg_start = NULL; | ||
199 | for (i = 0; i < TPG_CHANNELS; i++) { | ||
200 | item = devm_kzalloc(mc_vi->dev, sizeof(*item), GFP_KERNEL); | ||
201 | if (!item) | ||
202 | continue; | ||
203 | item->id = mc_vi->num_channels + i; | ||
204 | item->pg_mode = pg_mode; | ||
205 | item->vi = mc_vi; | ||
206 | |||
207 | err = tegra_channel_init(item); | ||
208 | if (err) { | ||
209 | devm_kfree(mc_vi->dev, item); | ||
210 | continue; | ||
211 | } | ||
212 | vi_tpg_fmts_bitmap_init(item); | ||
213 | /* only inited tpg channels are added */ | ||
214 | list_add_tail(&item->list, &mc_vi->vi_chans); | ||
215 | mc_vi->num_channels++; | ||
216 | if (mc_vi->tpg_start == NULL) | ||
217 | mc_vi->tpg_start = item; | ||
218 | } | ||
219 | |||
220 | err = tegra_vi_tpg_graph_init(mc_vi); | ||
221 | if (err) | ||
222 | goto channel_init_error; | ||
223 | |||
224 | list_for_each_entry(item, &mc_vi->vi_chans, list) { | ||
225 | if (!item->pg_mode) | ||
226 | continue; | ||
227 | err = video_register_device(&item->video, VFL_TYPE_GRABBER, -1); | ||
228 | if (err < 0) { | ||
229 | dev_err(&item->video.dev, "failed to register %s\n", | ||
230 | item->video.name); | ||
231 | continue; | ||
232 | } | ||
233 | count++; | ||
234 | } | ||
235 | |||
236 | if (count == 0) { | ||
237 | dev_err(mc_vi->dev, "all tpg register failed\n"); | ||
238 | goto channel_init_error; | ||
239 | } | ||
240 | |||
241 | return err; | ||
242 | |||
243 | channel_init_error: | ||
244 | dev_err(mc_vi->dev, "%s: channel init failed\n", __func__); | ||
245 | if (!mc_vi->tpg_start) | ||
246 | tpg_vi_media_controller_cleanup(mc_vi); | ||
247 | return err; | ||
248 | ctrl_error: | ||
249 | v4l2_ctrl_handler_free(&mc_vi->ctrl_handler); | ||
250 | dev_err(mc_vi->dev, "%s: v2l4_ctl error\n", __func__); | ||
251 | return err; | ||
252 | } | ||
253 | EXPORT_SYMBOL(tpg_vi_media_controller_init); | ||
254 | |||
255 | void tpg_vi_media_controller_cleanup(struct tegra_mc_vi *mc_vi) | ||
256 | { | ||
257 | struct tegra_channel *item; | ||
258 | struct tegra_channel *itemn; | ||
259 | |||
260 | list_for_each_entry_safe(item, itemn, &mc_vi->vi_chans, list) { | ||
261 | if (!item->pg_mode) | ||
262 | continue; | ||
263 | if (item->video.cdev != NULL) | ||
264 | video_unregister_device(&item->video); | ||
265 | tegra_channel_cleanup(item); | ||
266 | list_del(&item->list); | ||
267 | devm_kfree(mc_vi->dev, item); | ||
268 | /* decrement media device entity count */ | ||
269 | mc_vi->media_dev.entity_id--; | ||
270 | mc_vi->num_channels--; | ||
271 | } | ||
272 | mc_vi->tpg_start = NULL; | ||
273 | v4l2_ctrl_handler_free(&mc_vi->ctrl_handler); | ||
274 | } | ||
275 | EXPORT_SYMBOL(tpg_vi_media_controller_cleanup); | ||
276 | |||
277 | int tegra_vi_media_controller_init(struct tegra_mc_vi *mc_vi, | ||
278 | struct platform_device *pdev) | ||
279 | { | ||
280 | int err = 0; | ||
281 | struct nvhost_device_data *pdata = (struct nvhost_device_data *) | ||
282 | platform_get_drvdata(pdev); | ||
283 | |||
284 | if (!pdata) | ||
285 | return -EINVAL; | ||
286 | set_vi_register_base(mc_vi, pdata->aperture[0]); | ||
287 | |||
288 | mc_vi->ndev = pdev; | ||
289 | mc_vi->dev = &pdev->dev; | ||
290 | INIT_LIST_HEAD(&mc_vi->vi_chans); | ||
291 | INIT_LIST_HEAD(&mc_vi->entities); | ||
292 | mutex_init(&mc_vi->mipical_lock); | ||
293 | |||
294 | err = vi_parse_dt(mc_vi, pdev); | ||
295 | if (err) | ||
296 | goto mc_init_fail; | ||
297 | |||
298 | /* | ||
299 | * if there is no vi channels listed in DT, | ||
300 | * no need to init the channel and graph | ||
301 | */ | ||
302 | if (mc_vi->num_channels == 0) | ||
303 | return 0; | ||
304 | |||
305 | err = tegra_vi_v4l2_init(mc_vi); | ||
306 | if (err < 0) | ||
307 | goto mc_init_fail; | ||
308 | |||
309 | /* Init Tegra VI channels */ | ||
310 | err = tegra_vi_channels_init(mc_vi); | ||
311 | if (err < 0) { | ||
312 | dev_err(&pdev->dev, "Init channel failed\n"); | ||
313 | goto channels_error; | ||
314 | } | ||
315 | |||
316 | /* Setup media links between VI and external sensor subdev. */ | ||
317 | err = tegra_vi_graph_init(mc_vi); | ||
318 | if (err < 0) | ||
319 | goto graph_error; | ||
320 | |||
321 | err = tegra_vi_channels_register(mc_vi); | ||
322 | if (err < 0) | ||
323 | goto register_error; | ||
324 | |||
325 | return 0; | ||
326 | |||
327 | register_error: | ||
328 | tegra_vi_graph_cleanup(mc_vi); | ||
329 | graph_error: | ||
330 | tegra_vi_channels_cleanup(mc_vi); | ||
331 | channels_error: | ||
332 | tegra_vi_v4l2_cleanup(mc_vi); | ||
333 | mc_init_fail: | ||
334 | dev_err(&pdev->dev, "%s: failed\n", __func__); | ||
335 | return err; | ||
336 | } | ||
337 | EXPORT_SYMBOL(tegra_vi_media_controller_init); | ||
338 | |||
339 | void tegra_vi_media_controller_cleanup(struct tegra_mc_vi *mc_vi) | ||
340 | { | ||
341 | tegra_vi_channels_unregister(mc_vi); | ||
342 | tegra_vi_graph_cleanup(mc_vi); | ||
343 | tegra_vi_channels_cleanup(mc_vi); | ||
344 | tegra_vi_v4l2_cleanup(mc_vi); | ||
345 | } | ||
346 | EXPORT_SYMBOL(tegra_vi_media_controller_cleanup); | ||
diff --git a/drivers/media/platform/tegra/camera/vi/mc_common.h b/drivers/media/platform/tegra/camera/vi/mc_common.h new file mode 100644 index 000000000..42982bef8 --- /dev/null +++ b/drivers/media/platform/tegra/camera/vi/mc_common.h | |||
@@ -0,0 +1,352 @@ | |||
1 | /* | ||
2 | * drivers/media/platform/tegra/camera/mc_common.h | ||
3 | * | ||
4 | * Tegra Media controller common APIs | ||
5 | * | ||
6 | * Copyright (c) 2012-2017, NVIDIA CORPORATION. All rights reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms and conditions of the GNU General Public License, | ||
10 | * version 2, as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | #ifndef __CAMERA_MC_COMMON_H__ | ||
22 | #define __CAMERA_MC_COMMON_H__ | ||
23 | |||
24 | #include <media/media-device.h> | ||
25 | #include <media/media-entity.h> | ||
26 | #include <media/v4l2-async.h> | ||
27 | #include <media/v4l2-ctrls.h> | ||
28 | #include <media/v4l2-device.h> | ||
29 | #include <media/v4l2-dev.h> | ||
30 | #include <media/videobuf2-core.h> | ||
31 | #include <linux/workqueue.h> | ||
32 | |||
33 | #include "core.h" | ||
34 | #include "../csi/csi.h" | ||
35 | |||
36 | #define MAX_FORMAT_NUM 64 | ||
37 | #define MAX_SUBDEVICES 4 | ||
38 | #define QUEUED_BUFFERS 4 | ||
39 | #define ENABLE 1 | ||
40 | #define DISABLE 0 | ||
41 | #define MAX_SYNCPT_PER_CHANNEL 3 | ||
42 | #define TPG_CHANNELS 6 | ||
43 | |||
44 | #define TEGRA_MEM_FORMAT 0 | ||
45 | #define TEGRA_ISP_FORMAT 1 | ||
46 | |||
47 | enum channel_capture_state { | ||
48 | CAPTURE_IDLE = 0, | ||
49 | CAPTURE_GOOD, | ||
50 | CAPTURE_TIMEOUT, | ||
51 | CAPTURE_ERROR, | ||
52 | }; | ||
53 | |||
54 | enum tegra_vi_pg_mode { | ||
55 | TEGRA_VI_PG_DISABLED = 0, | ||
56 | TEGRA_VI_PG_DIRECT, | ||
57 | TEGRA_VI_PG_PATCH, | ||
58 | }; | ||
59 | |||
60 | /** | ||
61 | * struct tegra_channel_buffer - video channel buffer | ||
62 | * @buf: vb2 buffer base object | ||
63 | * @queue: buffer list entry in the channel queued buffers list | ||
64 | * @chan: channel that uses the buffer | ||
65 | * @addr: Tegra IOVA buffer address for VI output | ||
66 | */ | ||
67 | struct tegra_channel_buffer { | ||
68 | struct vb2_v4l2_buffer buf; | ||
69 | struct list_head queue; | ||
70 | struct tegra_channel *chan; | ||
71 | |||
72 | dma_addr_t addr; | ||
73 | }; | ||
74 | |||
75 | #define to_tegra_channel_buffer(vb) \ | ||
76 | container_of(vb, struct tegra_channel_buffer, buf) | ||
77 | |||
78 | /** | ||
79 | * struct tegra_vi_graph_entity - Entity in the video graph | ||
80 | * @list: list entry in a graph entities list | ||
81 | * @node: the entity's DT node | ||
82 | * @entity: media entity, from the corresponding V4L2 subdev | ||
83 | * @asd: subdev asynchronous registration information | ||
84 | * @subdev: V4L2 subdev | ||
85 | */ | ||
86 | struct tegra_vi_graph_entity { | ||
87 | struct list_head list; | ||
88 | struct device_node *node; | ||
89 | struct media_entity *entity; | ||
90 | |||
91 | struct v4l2_async_subdev asd; | ||
92 | struct v4l2_subdev *subdev; | ||
93 | }; | ||
94 | |||
95 | /** | ||
96 | * struct tegra_channel - Tegra video channel | ||
97 | * @list: list entry in a composite device dmas list | ||
98 | * @video: V4L2 video device associated with the video channel | ||
99 | * @video_lock: | ||
100 | * @pad: media pad for the video device entity | ||
101 | * @pipe: pipeline belonging to the channel | ||
102 | * | ||
103 | * @vi: composite device DT node port number for the channel | ||
104 | * | ||
105 | * @kthread_capture: kernel thread task structure of this video channel | ||
106 | * @wait: wait queue structure for kernel thread | ||
107 | * | ||
108 | * @format: active V4L2 pixel format | ||
109 | * @fmtinfo: format information corresponding to the active @format | ||
110 | * | ||
111 | * @queue: vb2 buffers queue | ||
112 | * @alloc_ctx: allocation context for the vb2 @queue | ||
113 | * @sequence: V4L2 buffers sequence number | ||
114 | * | ||
115 | * @capture: list of queued buffers for capture | ||
116 | * @queued_lock: protects the buf_queued list | ||
117 | * | ||
118 | * @csi: CSI register bases | ||
119 | * @stride_align: channel buffer stride alignment, default is 64 | ||
120 | * @width_align: image width alignment, default is 4 | ||
121 | * @height_align: channel buffer height alignment, default is 1 | ||
122 | * @size_align: channel buffer size alignment, default is 128K bytes | ||
123 | * @port: CSI port of this video channel | ||
124 | * @io_id: Tegra IO rail ID of this video channel | ||
125 | * | ||
126 | * @fmts_bitmap: a bitmap for formats supported | ||
127 | * @bypass: bypass flag for VI bypass mode | ||
128 | */ | ||
129 | struct tegra_channel { | ||
130 | int id; | ||
131 | struct list_head list; | ||
132 | struct video_device video; | ||
133 | struct media_pad pad; | ||
134 | struct media_pipeline pipe; | ||
135 | struct mutex video_lock; | ||
136 | |||
137 | struct tegra_mc_vi *vi; | ||
138 | struct v4l2_subdev *subdev[MAX_SUBDEVICES]; | ||
139 | struct v4l2_subdev *subdev_on_csi; | ||
140 | |||
141 | struct v4l2_ctrl_handler ctrl_handler; | ||
142 | struct v4l2_pix_format format; | ||
143 | const struct tegra_video_format *fmtinfo; | ||
144 | const struct tegra_video_format *video_formats[MAX_FORMAT_NUM]; | ||
145 | unsigned int num_video_formats; | ||
146 | struct mutex stop_kthread_lock; | ||
147 | |||
148 | unsigned char port[TEGRA_CSI_BLOCKS]; | ||
149 | unsigned int syncpt[TEGRA_CSI_BLOCKS][MAX_SYNCPT_PER_CHANNEL]; | ||
150 | unsigned int syncpoint_fifo[TEGRA_CSI_BLOCKS]; | ||
151 | unsigned int buffer_offset[TEGRA_CSI_BLOCKS]; | ||
152 | unsigned int buffer_state[QUEUED_BUFFERS]; | ||
153 | struct vb2_v4l2_buffer *buffers[QUEUED_BUFFERS]; | ||
154 | unsigned int timeout; | ||
155 | unsigned int save_index; | ||
156 | unsigned int free_index; | ||
157 | unsigned int num_buffers; | ||
158 | unsigned int released_bufs; | ||
159 | |||
160 | struct task_struct *kthread_capture_start; | ||
161 | wait_queue_head_t start_wait; | ||
162 | struct vb2_queue queue; | ||
163 | void *alloc_ctx; | ||
164 | bool init_done; | ||
165 | struct list_head capture; | ||
166 | spinlock_t start_lock; | ||
167 | struct work_struct status_work; | ||
168 | struct work_struct error_work; | ||
169 | |||
170 | void __iomem *csibase[TEGRA_CSI_BLOCKS]; | ||
171 | unsigned int stride_align; | ||
172 | unsigned int width_align; | ||
173 | unsigned int height_align; | ||
174 | unsigned int size_align; | ||
175 | unsigned int valid_ports; | ||
176 | unsigned int total_ports; | ||
177 | unsigned int numlanes; | ||
178 | unsigned int io_id; | ||
179 | unsigned int num_subdevs; | ||
180 | unsigned int sequence; | ||
181 | unsigned int saved_ctx_bypass; | ||
182 | unsigned int saved_ctx_pgmode; | ||
183 | unsigned int gang_mode; | ||
184 | unsigned int gang_width; | ||
185 | unsigned int gang_height; | ||
186 | unsigned int gang_bytesperline; | ||
187 | unsigned int gang_sizeimage; | ||
188 | |||
189 | DECLARE_BITMAP(fmts_bitmap, MAX_FORMAT_NUM); | ||
190 | atomic_t power_on_refcnt; | ||
191 | struct v4l2_fh *fh; | ||
192 | bool bypass; | ||
193 | bool write_ispformat; | ||
194 | enum tegra_vi_pg_mode pg_mode; | ||
195 | bool bfirst_fstart; | ||
196 | enum channel_capture_state capture_state; | ||
197 | spinlock_t capture_state_lock; | ||
198 | atomic_t is_streaming; | ||
199 | int requested_kbyteps; | ||
200 | unsigned long requested_hz; | ||
201 | |||
202 | struct vi_notify_channel *vnc[TEGRA_CSI_BLOCKS]; | ||
203 | int vnc_id[TEGRA_CSI_BLOCKS]; | ||
204 | int grp_id; | ||
205 | |||
206 | struct vi_capture *capture_data; | ||
207 | }; | ||
208 | |||
209 | #define to_tegra_channel(vdev) \ | ||
210 | container_of(vdev, struct tegra_channel, video) | ||
211 | |||
212 | /** | ||
213 | * struct tegra_mc_vi - NVIDIA Tegra Media controller structure | ||
214 | * @v4l2_dev: V4L2 device | ||
215 | * @media_dev: media device | ||
216 | * @dev: device struct | ||
217 | * @tegra_camera: tegra camera structure | ||
218 | * @nvhost_device_data: NvHost VI device information | ||
219 | * | ||
220 | * @notifier: V4L2 asynchronous subdevs notifier | ||
221 | * @entities: entities in the graph as a list of tegra_vi_graph_entity | ||
222 | * @num_subdevs: number of subdevs in the pipeline | ||
223 | * | ||
224 | * @channels: list of channels at the pipeline output and input | ||
225 | * | ||
226 | * @ctrl_handler: V4L2 control handler | ||
227 | * @pattern: test pattern generator V4L2 control | ||
228 | * @pg_mode: test pattern generator mode (disabled/direct/patch) | ||
229 | * | ||
230 | * @has_sensors: a flag to indicate whether is a real sensor connecting | ||
231 | */ | ||
232 | struct tegra_mc_vi { | ||
233 | struct vi *vi; | ||
234 | struct platform_device *ndev; | ||
235 | struct v4l2_device v4l2_dev; | ||
236 | struct media_device media_dev; | ||
237 | struct device *dev; | ||
238 | struct nvhost_device_data *ndata; | ||
239 | |||
240 | struct regulator *reg; | ||
241 | struct clk *clk; | ||
242 | struct clk *parent_clk; | ||
243 | |||
244 | struct v4l2_async_notifier notifier; | ||
245 | struct list_head entities; | ||
246 | unsigned int num_channels; | ||
247 | unsigned int num_subdevs; | ||
248 | |||
249 | struct tegra_csi_device *csi; | ||
250 | struct list_head vi_chans; | ||
251 | struct tegra_channel *tpg_start; | ||
252 | void __iomem *iomem; | ||
253 | |||
254 | struct v4l2_ctrl_handler ctrl_handler; | ||
255 | struct v4l2_ctrl *pattern; | ||
256 | enum tegra_vi_pg_mode pg_mode; | ||
257 | |||
258 | bool has_sensors; | ||
259 | atomic_t power_on_refcnt; | ||
260 | unsigned int link_status; | ||
261 | unsigned int subdevs_bound; | ||
262 | struct mutex bw_update_lock; | ||
263 | unsigned long aggregated_kbyteps; | ||
264 | unsigned long max_requested_hz; | ||
265 | struct mutex mipical_lock; | ||
266 | |||
267 | bool bypass; | ||
268 | |||
269 | struct tegra_vi_fops *fops; | ||
270 | }; | ||
271 | |||
272 | int tegra_vi_get_port_info(struct tegra_channel *chan, | ||
273 | struct device_node *node, unsigned int index); | ||
274 | void tegra_vi_v4l2_cleanup(struct tegra_mc_vi *vi); | ||
275 | int tegra_vi_v4l2_init(struct tegra_mc_vi *vi); | ||
276 | int tegra_vi_tpg_graph_init(struct tegra_mc_vi *vi); | ||
277 | int tegra_vi_graph_init(struct tegra_mc_vi *vi); | ||
278 | void tegra_vi_graph_cleanup(struct tegra_mc_vi *vi); | ||
279 | int tegra_channel_init(struct tegra_channel *chan); | ||
280 | int tegra_vi_channels_register(struct tegra_mc_vi *vi); | ||
281 | void tegra_vi_channels_unregister(struct tegra_mc_vi *vi); | ||
282 | int tegra_vi_channels_init(struct tegra_mc_vi *vi); | ||
283 | int tegra_channel_cleanup(struct tegra_channel *chan); | ||
284 | int tegra_vi_channels_cleanup(struct tegra_mc_vi *vi); | ||
285 | int tegra_channel_init_subdevices(struct tegra_channel *chan); | ||
286 | int tegra_vi2_power_on(struct tegra_mc_vi *vi); | ||
287 | void tegra_vi2_power_off(struct tegra_mc_vi *vi); | ||
288 | int tegra_vi4_power_on(struct tegra_mc_vi *vi); | ||
289 | void tegra_vi4_power_off(struct tegra_mc_vi *vi); | ||
290 | int tegra_clean_unlinked_channels(struct tegra_mc_vi *vi); | ||
291 | int tegra_channel_s_ctrl(struct v4l2_ctrl *ctrl); | ||
292 | int tegra_vi_media_controller_init(struct tegra_mc_vi *mc_vi, | ||
293 | struct platform_device *pdev); | ||
294 | void tegra_vi_media_controller_cleanup(struct tegra_mc_vi *mc_vi); | ||
295 | void tegra_channel_ec_close(struct tegra_mc_vi *mc_vi); | ||
296 | void tegra_channel_query_hdmiin_unplug(struct tegra_channel *chan, | ||
297 | struct v4l2_event *event); | ||
298 | int tpg_vi_media_controller_init(struct tegra_mc_vi *mc_vi, int pg_mode); | ||
299 | void tpg_vi_media_controller_cleanup(struct tegra_mc_vi *mc_vi); | ||
300 | |||
301 | u32 tegra_core_get_fourcc_by_idx(struct tegra_channel *chan, | ||
302 | unsigned int index); | ||
303 | int tegra_core_get_idx_by_code(struct tegra_channel *chan, | ||
304 | unsigned int code, unsigned offset); | ||
305 | const struct tegra_video_format *tegra_core_get_format_by_code( | ||
306 | struct tegra_channel *chan, | ||
307 | unsigned int code, unsigned offset); | ||
308 | const struct tegra_video_format *tegra_core_get_format_by_fourcc( | ||
309 | struct tegra_channel *chan, u32 fourcc); | ||
310 | void tegra_core_get_description_by_idx(struct tegra_channel *chan, | ||
311 | unsigned int index, __u8 *description); | ||
312 | |||
313 | struct tegra_vi_fops { | ||
314 | int (*vi_power_on)(struct tegra_channel *chan); | ||
315 | void (*vi_power_off)(struct tegra_channel *chan); | ||
316 | int (*vi_start_streaming)(struct vb2_queue *vq, u32 count); | ||
317 | int (*vi_stop_streaming)(struct vb2_queue *vq); | ||
318 | int (*vi_add_ctrls)(struct tegra_channel *chan); | ||
319 | void (*vi_init_video_formats)(struct tegra_channel *chan); | ||
320 | long (*vi_default_ioctl)(struct file *file, void *fh, | ||
321 | bool use_prio, unsigned int cmd, void *arg); | ||
322 | }; | ||
323 | |||
324 | struct tegra_csi_fops { | ||
325 | int (*csi_power_on)(struct tegra_csi_device *csi); | ||
326 | int (*csi_power_off)(struct tegra_csi_device *csi); | ||
327 | int (*csi_start_streaming)(struct tegra_csi_channel *chan, | ||
328 | enum tegra_csi_port_num port_num); | ||
329 | void (*csi_stop_streaming)(struct tegra_csi_channel *chan, | ||
330 | enum tegra_csi_port_num port_num); | ||
331 | void (*csi_override_format)(struct tegra_csi_channel *chan, | ||
332 | enum tegra_csi_port_num port_num); | ||
333 | int (*mipical)(struct tegra_csi_channel *chan); | ||
334 | int (*hw_init)(struct tegra_csi_device *csi); | ||
335 | }; | ||
336 | |||
337 | struct tegra_t210_vi_data { | ||
338 | struct nvhost_device_data *info; | ||
339 | struct tegra_vi_fops *vi_fops; | ||
340 | struct tegra_csi_fops *csi_fops; | ||
341 | }; | ||
342 | |||
343 | struct tegra_vi_data { | ||
344 | struct nvhost_device_data *info; | ||
345 | struct tegra_vi_fops *vi_fops; | ||
346 | }; | ||
347 | |||
348 | struct tegra_csi_data { | ||
349 | struct nvhost_device_data *info; | ||
350 | struct tegra_csi_fops *csi_fops; | ||
351 | }; | ||
352 | #endif | ||
diff --git a/drivers/media/platform/tegra/camera/vi/registers.h b/drivers/media/platform/tegra/camera/vi/registers.h new file mode 100644 index 000000000..176575dff --- /dev/null +++ b/drivers/media/platform/tegra/camera/vi/registers.h | |||
@@ -0,0 +1,223 @@ | |||
1 | /* | ||
2 | * drivers/media/platform/tegra/camera/registers.h | ||
3 | * | ||
4 | * Tegra VI/CSI register offsets | ||
5 | * | ||
6 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms and conditions of the GNU General Public License, | ||
10 | * version 2, as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | #ifndef __REGISTERS_H__ | ||
22 | #define __REGISTERS_H__ | ||
23 | |||
24 | /* VI registers */ | ||
25 | #define TEGRA_VI_SYNCPT_WAIT_TIMEOUT 200 | ||
26 | #define TEGRA_VI_CFG_VI_INCR_SYNCPT 0x000 | ||
27 | #define VI_CFG_VI_INCR_SYNCPT_COND(x) (x << 8) | ||
28 | #define VI_CSI_PP_LINE_START(port) (4 + (port) * 4) | ||
29 | #define VI_CSI_PP_FRAME_START(port) (5 + (port) * 4) | ||
30 | #define VI_CSI_MW_REQ_DONE(port) (6 + (port) * 4) | ||
31 | #define VI_CSI_MW_ACK_DONE(port) (7 + (port) * 4) | ||
32 | |||
33 | #define TEGRA_VI_CFG_VI_INCR_SYNCPT_CNTRL 0x004 | ||
34 | #define TEGRA_VI_CFG_VI_INCR_SYNCPT_ERROR 0x008 | ||
35 | #define TEGRA_VI_CFG_CTXSW 0x020 | ||
36 | #define TEGRA_VI_CFG_INTSTATUS 0x024 | ||
37 | #define TEGRA_VI_CFG_PWM_CONTROL 0x038 | ||
38 | #define TEGRA_VI_CFG_PWM_HIGH_PULSE 0x03c | ||
39 | #define TEGRA_VI_CFG_PWM_LOW_PULSE 0x040 | ||
40 | #define TEGRA_VI_CFG_PWM_SELECT_PULSE_A 0x044 | ||
41 | #define TEGRA_VI_CFG_PWM_SELECT_PULSE_B 0x048 | ||
42 | #define TEGRA_VI_CFG_PWM_SELECT_PULSE_C 0x04c | ||
43 | #define TEGRA_VI_CFG_PWM_SELECT_PULSE_D 0x050 | ||
44 | #define TEGRA_VI_CFG_VGP1 0x064 | ||
45 | #define TEGRA_VI_CFG_VGP2 0x068 | ||
46 | #define TEGRA_VI_CFG_VGP3 0x06c | ||
47 | #define TEGRA_VI_CFG_VGP4 0x070 | ||
48 | #define TEGRA_VI_CFG_VGP5 0x074 | ||
49 | #define TEGRA_VI_CFG_VGP6 0x078 | ||
50 | #define TEGRA_VI_CFG_INTERRUPT_MASK 0x08c | ||
51 | #define TEGRA_VI_CFG_INTERRUPT_TYPE_SELECT 0x090 | ||
52 | #define TEGRA_VI_CFG_INTERRUPT_POLARITY_SELECT 0x094 | ||
53 | #define TEGRA_VI_CFG_INTERRUPT_STATUS 0x098 | ||
54 | #define TEGRA_VI_CFG_VGP_SYNCPT_CONFIG 0x0ac | ||
55 | #define TEGRA_VI_CFG_VI_SW_RESET 0x0b4 | ||
56 | #define TEGRA_VI_CFG_CG_CTRL 0x0b8 | ||
57 | #define VI_CG_2ND_LEVEL_EN 0x1 | ||
58 | #define TEGRA_VI_CFG_VI_MCCIF_FIFOCTRL 0x0e4 | ||
59 | #define TEGRA_VI_CFG_TIMEOUT_WCOAL_VI 0x0e8 | ||
60 | #define TEGRA_VI_CFG_DVFS 0x0f0 | ||
61 | #define TEGRA_VI_CFG_RESERVE 0x0f4 | ||
62 | #define TEGRA_VI_CFG_RESERVE_1 0x0f8 | ||
63 | |||
64 | /* CSI registers */ | ||
65 | #define TEGRA_VI_CSI_BASE(x) (0x100 + (x) * 0x100) | ||
66 | |||
67 | #define TEGRA_VI_CSI_SW_RESET 0x000 | ||
68 | #define TEGRA_VI_CSI_SINGLE_SHOT 0x004 | ||
69 | #define SINGLE_SHOT_CAPTURE 0x1 | ||
70 | #define CAPTURE_GOOD_FRAME 0x1 | ||
71 | #define TEGRA_VI_CSI_SINGLE_SHOT_STATE_UPDATE 0x008 | ||
72 | #define TEGRA_VI_CSI_IMAGE_DEF 0x00c | ||
73 | #define BYPASS_PXL_TRANSFORM_OFFSET 24 | ||
74 | #define IMAGE_DEF_FORMAT_OFFSET 16 | ||
75 | #define IMAGE_DEF_DEST_MEM 0x1 | ||
76 | #define TEGRA_VI_CSI_RGB2Y_CTRL 0x010 | ||
77 | #define TEGRA_VI_CSI_MEM_TILING 0x014 | ||
78 | #define TEGRA_VI_CSI_IMAGE_SIZE 0x018 | ||
79 | #define IMAGE_SIZE_HEIGHT_OFFSET 16 | ||
80 | #define TEGRA_VI_CSI_IMAGE_SIZE_WC 0x01c | ||
81 | #define TEGRA_VI_CSI_IMAGE_DT 0x020 | ||
82 | #define TEGRA_VI_CSI_SURFACE0_OFFSET_MSB 0x024 | ||
83 | #define TEGRA_VI_CSI_SURFACE0_OFFSET_LSB 0x028 | ||
84 | #define TEGRA_VI_CSI_SURFACE1_OFFSET_MSB 0x02c | ||
85 | #define TEGRA_VI_CSI_SURFACE1_OFFSET_LSB 0x030 | ||
86 | #define TEGRA_VI_CSI_SURFACE2_OFFSET_MSB 0x034 | ||
87 | #define TEGRA_VI_CSI_SURFACE2_OFFSET_LSB 0x038 | ||
88 | #define TEGRA_VI_CSI_SURFACE0_BF_OFFSET_MSB 0x03c | ||
89 | #define TEGRA_VI_CSI_SURFACE0_BF_OFFSET_LSB 0x040 | ||
90 | #define TEGRA_VI_CSI_SURFACE1_BF_OFFSET_MSB 0x044 | ||
91 | #define TEGRA_VI_CSI_SURFACE1_BF_OFFSET_LSB 0x048 | ||
92 | #define TEGRA_VI_CSI_SURFACE2_BF_OFFSET_MSB 0x04c | ||
93 | #define TEGRA_VI_CSI_SURFACE2_BF_OFFSET_LSB 0x050 | ||
94 | #define TEGRA_VI_CSI_SURFACE0_STRIDE 0x054 | ||
95 | #define TEGRA_VI_CSI_SURFACE1_STRIDE 0x058 | ||
96 | #define TEGRA_VI_CSI_SURFACE2_STRIDE 0x05c | ||
97 | #define TEGRA_VI_CSI_SURFACE_HEIGHT0 0x060 | ||
98 | #define TEGRA_VI_CSI_ISPINTF_CONFIG 0x064 | ||
99 | #define TEGRA_VI_CSI_ERROR_STATUS 0x084 | ||
100 | #define TEGRA_VI_CSI_ERROR_INT_MASK 0x088 | ||
101 | #define TEGRA_VI_CSI_WD_CTRL 0x08c | ||
102 | #define TEGRA_VI_CSI_WD_PERIOD 0x090 | ||
103 | |||
104 | /* CSI Pixel Parser registers: Starts from 0x838, offset 0x0 */ | ||
105 | #define TEGRA_CSI_INPUT_STREAM_CONTROL 0x000 | ||
106 | #define CSI_SKIP_PACKET_THRESHOLD_OFFSET 16 | ||
107 | |||
108 | #define TEGRA_CSI_PIXEL_STREAM_CONTROL0 0x004 | ||
109 | #define CSI_PP_PACKET_HEADER_SENT (0x1 << 4) | ||
110 | #define CSI_PP_DATA_IDENTIFIER_ENABLE (0x1 << 5) | ||
111 | #define CSI_PP_WORD_COUNT_SELECT_HEADER (0x1 << 6) | ||
112 | #define CSI_PP_CRC_CHECK_ENABLE (0x1 << 7) | ||
113 | #define CSI_PP_WC_CHECK (0x1 << 8) | ||
114 | #define CSI_PP_OUTPUT_FORMAT_STORE (0x3 << 16) | ||
115 | #define CSI_PPA_PAD_LINE_NOPAD (0x2 << 24) | ||
116 | #define CSI_PP_HEADER_EC_DISABLE (0x1 << 27) | ||
117 | #define CSI_PPA_PAD_FRAME_NOPAD (0x2 << 28) | ||
118 | |||
119 | #define TEGRA_CSI_PIXEL_STREAM_CONTROL1 0x008 | ||
120 | #define CSI_PP_TOP_FIELD_FRAME_OFFSET 0 | ||
121 | #define CSI_PP_TOP_FIELD_FRAME_MASK_OFFSET 4 | ||
122 | |||
123 | #define TEGRA_CSI_PIXEL_STREAM_GAP 0x00c | ||
124 | #define PP_FRAME_MIN_GAP_OFFSET 16 | ||
125 | |||
126 | #define TEGRA_CSI_PIXEL_STREAM_PP_COMMAND 0x010 | ||
127 | #define CSI_PP_ENABLE 0x1 | ||
128 | #define CSI_PP_DISABLE 0x2 | ||
129 | #define CSI_PP_RST 0x3 | ||
130 | #define CSI_PP_SINGLE_SHOT_ENABLE (0x1 << 2) | ||
131 | #define CSI_PP_START_MARKER_FRAME_MAX_OFFSET 12 | ||
132 | |||
133 | #define TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME 0x014 | ||
134 | #define TEGRA_CSI_PIXEL_PARSER_INTERRUPT_MASK 0x018 | ||
135 | #define TEGRA_CSI_PIXEL_PARSER_STATUS 0x01c | ||
136 | #define TEGRA_CSI_CSI_SW_SENSOR_RESET 0x020 | ||
137 | |||
138 | /* CSI PHY registers */ | ||
139 | /* CSI_PHY_CIL_COMMAND_0 offset 0x0d0 from TEGRA_CSI_PIXEL_PARSER_0_BASE */ | ||
140 | #define TEGRA_CSI_PHY_CIL_COMMAND 0x0d0 | ||
141 | #define CSI_A_PHY_CIL_ENABLE 0x1 | ||
142 | #define CSI_B_PHY_CIL_ENABLE (0x1 << 8) | ||
143 | |||
144 | /* CSI CIL registers: Starts from 0x92c, offset 0xF4 */ | ||
145 | #define TEGRA_CSI_CIL_OFFSET 0x0f4 | ||
146 | |||
147 | #define TEGRA_CSI_CIL_PAD_CONFIG0 0x000 | ||
148 | #define BRICK_CLOCK_A_4X (0x1 << 16) | ||
149 | #define BRICK_CLOCK_B_4X (0x2 << 16) | ||
150 | #define TEGRA_CSI_CIL_PAD_CONFIG1 0x004 | ||
151 | #define TEGRA_CSI_CIL_PHY_CONTROL 0x008 | ||
152 | #define BYPASS_LP_SEQ (0x1 << 6) | ||
153 | #define TEGRA_CSI_CIL_INTERRUPT_MASK 0x00c | ||
154 | #define TEGRA_CSI_CIL_STATUS 0x010 | ||
155 | #define TEGRA_CSI_CILX_STATUS 0x014 | ||
156 | #define TEGRA_CSI_CIL_ESCAPE_MODE_COMMAND 0x018 | ||
157 | #define TEGRA_CSI_CIL_ESCAPE_MODE_DATA 0x01c | ||
158 | #define TEGRA_CSI_CIL_SW_SENSOR_RESET 0x020 | ||
159 | |||
160 | /* CSI Pattern Generator registers: Starts from 0x9c4, offset 0x18c */ | ||
161 | #define TEGRA_CSI_TPG_OFFSET 0x18c | ||
162 | |||
163 | #define TEGRA_CSI_PATTERN_GENERATOR_CTRL 0x000 | ||
164 | #define PG_MODE_OFFSET 2 | ||
165 | #define PG_ENABLE 0x1 | ||
166 | #define PG_DISABLE 0x0 | ||
167 | |||
168 | #define PG_VBLANK_OFFSET 16 | ||
169 | #define TEGRA_CSI_PG_BLANK 0x004 | ||
170 | #define TEGRA_CSI_PG_PHASE 0x008 | ||
171 | #define TEGRA_CSI_PG_RED_FREQ 0x00c | ||
172 | #define PG_RED_VERT_INIT_FREQ_OFFSET 16 | ||
173 | #define PG_RED_HOR_INIT_FREQ_OFFSET 0 | ||
174 | |||
175 | #define TEGRA_CSI_PG_RED_FREQ_RATE 0x010 | ||
176 | #define TEGRA_CSI_PG_GREEN_FREQ 0x014 | ||
177 | #define PG_GREEN_VERT_INIT_FREQ_OFFSET 16 | ||
178 | #define PG_GREEN_HOR_INIT_FREQ_OFFSET 0 | ||
179 | |||
180 | #define TEGRA_CSI_PG_GREEN_FREQ_RATE 0x018 | ||
181 | #define TEGRA_CSI_PG_BLUE_FREQ 0x01c | ||
182 | #define PG_BLUE_VERT_INIT_FREQ_OFFSET 16 | ||
183 | #define PG_BLUE_HOR_INIT_FREQ_OFFSET 0 | ||
184 | |||
185 | #define TEGRA_CSI_PG_BLUE_FREQ_RATE 0x020 | ||
186 | #define TEGRA_CSI_PG_AOHDR 0x024 | ||
187 | |||
188 | #define TEGRA_CSI_DPCM_CTRL_A 0xa2c | ||
189 | #define TEGRA_CSI_DPCM_CTRL_B 0xa30 | ||
190 | |||
191 | /* Other CSI registers: Starts from 0xa44, offset 0x20c */ | ||
192 | #define TEGRA_CSI_STALL_COUNTER 0x20c | ||
193 | #define TEGRA_CSI_CSI_READONLY_STATUS 0x210 | ||
194 | #define TEGRA_CSI_CSI_SW_STATUS_RESET 0x214 | ||
195 | #define TEGRA_CSI_CLKEN_OVERRIDE 0x218 | ||
196 | #define TEGRA_CSI_DEBUG_CONTROL 0x21c | ||
197 | #define TEGRA_CSI_DEBUG_COUNTER_0 0x220 | ||
198 | #define TEGRA_CSI_DEBUG_COUNTER_1 0x224 | ||
199 | #define TEGRA_CSI_DEBUG_COUNTER_2 0x228 | ||
200 | |||
201 | |||
202 | /* CSI Pixel Parser registers */ | ||
203 | #define TEGRA_CSI_PIXEL_PARSER_0_BASE 0x0838 | ||
204 | #define TEGRA_CSI_PIXEL_PARSER_1_BASE 0x086c | ||
205 | #define TEGRA_CSI_PIXEL_PARSER_2_BASE 0x1038 | ||
206 | #define TEGRA_CSI_PIXEL_PARSER_3_BASE 0x106c | ||
207 | #define TEGRA_CSI_PIXEL_PARSER_4_BASE 0x1838 | ||
208 | #define TEGRA_CSI_PIXEL_PARSER_5_BASE 0x186c | ||
209 | |||
210 | /* CSIA to CSIB register offset */ | ||
211 | #define TEGRA_CSI_PORT_OFFSET 0x34 | ||
212 | |||
213 | #define INVALID_CSI_PORT 0xFF | ||
214 | #define TEGRA_CSI_BLOCKS 3 | ||
215 | #define SYNCPT_FIFO_DEPTH 2 | ||
216 | #define PREVIOUS_BUFFER_DEC_INDEX 2 | ||
217 | |||
218 | #define TEGRA_CLOCK_VI_MAX 793600000 | ||
219 | #define TEGRA_CLOCK_TPG 927000000 | ||
220 | #define TEGRA_CLOCK_CSI_PORT_MAX 102000000 | ||
221 | |||
222 | #define TEGRA_SURFACE_ALIGNMENT 64 | ||
223 | #endif | ||
diff --git a/drivers/media/platform/tegra/camera/vi/vi2_fops.c b/drivers/media/platform/tegra/camera/vi/vi2_fops.c new file mode 100644 index 000000000..fa081b9e0 --- /dev/null +++ b/drivers/media/platform/tegra/camera/vi/vi2_fops.c | |||
@@ -0,0 +1,825 @@ | |||
1 | /* | ||
2 | * Tegra Video Input 2 device common APIs | ||
3 | * | ||
4 | * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * Author: Bryan Wu <pengw@nvidia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #include <linux/device.h> | ||
13 | #include <linux/nvhost.h> | ||
14 | #include <linux/tegra-powergate.h> | ||
15 | #include <linux/kthread.h> | ||
16 | #include <linux/freezer.h> | ||
17 | #include <media/tegra_camera_platform.h> | ||
18 | #include "nvhost_acm.h" | ||
19 | #include "camera/vi/mc_common.h" | ||
20 | #include "camera/csi/csi2_fops.h" | ||
21 | #include "vi2_formats.h" | ||
22 | #include "vi/vi.h" | ||
23 | |||
24 | #define DEFAULT_FRAMERATE 30 | ||
25 | #define DEFAULT_CSI_FREQ 204000000 | ||
26 | #define BPP_MEM 2 | ||
27 | #define NUM_PPC 2 | ||
28 | #define VI_CSI_CLK_SCALE 110 | ||
29 | |||
30 | extern void tegra_channel_queued_buf_done(struct tegra_channel *chan, | ||
31 | enum vb2_buffer_state state); | ||
32 | static void tegra_channel_stop_kthreads(struct tegra_channel *chan); | ||
33 | extern int tegra_channel_set_stream(struct tegra_channel *chan, bool on); | ||
34 | extern void tegra_channel_ring_buffer(struct tegra_channel *chan, | ||
35 | struct vb2_v4l2_buffer *vb, | ||
36 | struct timespec *ts, int state); | ||
37 | extern struct tegra_channel_buffer *dequeue_buffer(struct tegra_channel *chan); | ||
38 | extern void tegra_channel_init_ring_buffer(struct tegra_channel *chan); | ||
39 | extern void free_ring_buffers(struct tegra_channel *chan, int frames); | ||
40 | extern int tegra_channel_set_power(struct tegra_channel *chan, bool on); | ||
41 | |||
42 | static void vi_write(struct tegra_mc_vi *vi, unsigned int addr, u32 val) | ||
43 | { | ||
44 | writel(val, vi->iomem + addr); | ||
45 | } | ||
46 | |||
47 | static u32 tegra_channel_read(struct tegra_channel *chan, | ||
48 | unsigned int addr) | ||
49 | { | ||
50 | return readl(chan->vi->iomem + addr); | ||
51 | } | ||
52 | |||
53 | static void tegra_channel_write(struct tegra_channel *chan, | ||
54 | unsigned int addr, u32 val) | ||
55 | { | ||
56 | writel(val, chan->vi->iomem + addr); | ||
57 | } | ||
58 | |||
59 | /* CSI registers */ | ||
60 | static void csi_write(struct tegra_channel *chan, unsigned int index, | ||
61 | unsigned int addr, u32 val) | ||
62 | { | ||
63 | writel(val, chan->csibase[index] + addr); | ||
64 | } | ||
65 | |||
66 | static u32 csi_read(struct tegra_channel *chan, unsigned int index, | ||
67 | unsigned int addr) | ||
68 | { | ||
69 | return readl(chan->csibase[index] + addr); | ||
70 | } | ||
71 | |||
72 | static void vi_channel_syncpt_init(struct tegra_channel *chan) | ||
73 | { | ||
74 | int i; | ||
75 | |||
76 | for (i = 0; i < chan->total_ports; i++) | ||
77 | chan->syncpt[i][0] = | ||
78 | nvhost_get_syncpt_client_managed(chan->vi->ndev, "vi"); | ||
79 | } | ||
80 | |||
81 | static void vi_channel_syncpt_free(struct tegra_channel *chan) | ||
82 | { | ||
83 | int i; | ||
84 | |||
85 | for (i = 0; i < chan->total_ports; i++) | ||
86 | nvhost_syncpt_put_ref_ext(chan->vi->ndev, chan->syncpt[i][0]); | ||
87 | } | ||
88 | |||
89 | void vi2_init_video_formats(struct tegra_channel *chan) | ||
90 | { | ||
91 | int i; | ||
92 | |||
93 | chan->num_video_formats = ARRAY_SIZE(vi2_video_formats); | ||
94 | for (i = 0; i < chan->num_video_formats; i++) | ||
95 | chan->video_formats[i] = &vi2_video_formats[i]; | ||
96 | } | ||
97 | |||
98 | int tegra_vi2_s_ctrl(struct v4l2_ctrl *ctrl) | ||
99 | { | ||
100 | struct tegra_channel *chan = container_of(ctrl->handler, | ||
101 | struct tegra_channel, ctrl_handler); | ||
102 | int err = 0; | ||
103 | |||
104 | switch (ctrl->id) { | ||
105 | case V4L2_CID_WRITE_ISPFORMAT: | ||
106 | chan->write_ispformat = ctrl->val; | ||
107 | break; | ||
108 | default: | ||
109 | dev_err(&chan->video.dev, "%s:Not valid ctrl\n", __func__); | ||
110 | return -EINVAL; | ||
111 | } | ||
112 | |||
113 | return err; | ||
114 | } | ||
115 | |||
116 | static const struct v4l2_ctrl_ops vi2_ctrl_ops = { | ||
117 | .s_ctrl = tegra_vi2_s_ctrl, | ||
118 | }; | ||
119 | |||
120 | static const struct v4l2_ctrl_config vi2_custom_ctrls[] = { | ||
121 | { | ||
122 | .ops = &vi2_ctrl_ops, | ||
123 | .id = V4L2_CID_WRITE_ISPFORMAT, | ||
124 | .name = "Write ISP format", | ||
125 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
126 | .def = 0, | ||
127 | .min = 0, | ||
128 | .step = 1, | ||
129 | .max = 1, | ||
130 | }, | ||
131 | }; | ||
132 | |||
133 | int vi2_add_ctrls(struct tegra_channel *chan) | ||
134 | { | ||
135 | int i; | ||
136 | |||
137 | /* Add vi2 custom controls */ | ||
138 | for (i = 0; i < ARRAY_SIZE(vi2_custom_ctrls); i++) { | ||
139 | v4l2_ctrl_new_custom(&chan->ctrl_handler, | ||
140 | &vi2_custom_ctrls[i], NULL); | ||
141 | if (chan->ctrl_handler.error) { | ||
142 | dev_err(chan->vi->dev, | ||
143 | "Failed to add %s ctrl\n", | ||
144 | vi2_custom_ctrls[i].name); | ||
145 | return chan->ctrl_handler.error; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static struct tegra_csi_channel *find_linked_csi_channel( | ||
153 | struct tegra_channel *chan, struct tegra_csi_device *csi) | ||
154 | { | ||
155 | struct tegra_csi_channel *csi_it; | ||
156 | struct tegra_csi_channel *csi_chan = NULL; | ||
157 | int i; | ||
158 | /* Find connected csi_channel */ | ||
159 | list_for_each_entry(csi_it, &csi->csi_chans, list) { | ||
160 | for (i = 0; i < chan->num_subdevs; i++) { | ||
161 | if (chan->subdev[i] == &csi_it->subdev) { | ||
162 | csi_chan = csi_it; | ||
163 | break; | ||
164 | } | ||
165 | } | ||
166 | } | ||
167 | return csi_chan; | ||
168 | } | ||
169 | static int tegra_channel_capture_setup(struct tegra_channel *chan) | ||
170 | { | ||
171 | u32 height = chan->format.height; | ||
172 | u32 width = chan->format.width; | ||
173 | u32 format = chan->fmtinfo->img_fmt; | ||
174 | u32 data_type = chan->fmtinfo->img_dt; | ||
175 | u32 word_count = tegra_core_get_word_count(width, chan->fmtinfo); | ||
176 | u32 bypass_pixel_transform = 1; | ||
177 | int index; | ||
178 | |||
179 | if (chan->valid_ports > 1) { | ||
180 | height = chan->gang_height; | ||
181 | width = chan->gang_width; | ||
182 | word_count = tegra_core_get_word_count(width, chan->fmtinfo); | ||
183 | } | ||
184 | |||
185 | if (chan->pg_mode || | ||
186 | (chan->write_ispformat == TEGRA_ISP_FORMAT) || | ||
187 | (chan->fmtinfo->vf_code == TEGRA_VF_YUV422) || | ||
188 | (chan->fmtinfo->vf_code == TEGRA_VF_RGB888)) | ||
189 | bypass_pixel_transform = 0; | ||
190 | |||
191 | for (index = 0; index < chan->valid_ports; index++) { | ||
192 | csi_write(chan, index, TEGRA_VI_CSI_ERROR_STATUS, 0xFFFFFFFF); | ||
193 | csi_write(chan, index, TEGRA_VI_CSI_IMAGE_DEF, | ||
194 | (bypass_pixel_transform << BYPASS_PXL_TRANSFORM_OFFSET) | | ||
195 | (format << IMAGE_DEF_FORMAT_OFFSET)); | ||
196 | csi_write(chan, index, TEGRA_VI_CSI_IMAGE_DT, data_type); | ||
197 | csi_write(chan, index, TEGRA_VI_CSI_IMAGE_SIZE_WC, word_count); | ||
198 | csi_write(chan, index, TEGRA_VI_CSI_IMAGE_SIZE, | ||
199 | (height << IMAGE_SIZE_HEIGHT_OFFSET) | width); | ||
200 | } | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static int tegra_channel_enable_stream(struct tegra_channel *chan) | ||
206 | { | ||
207 | int ret = 0; | ||
208 | struct tegra_csi_channel *csi_chan = NULL; | ||
209 | struct tegra_csi_device *csi = chan->vi->csi; | ||
210 | /* | ||
211 | * enable pad power and perform calibration before arming | ||
212 | * single shot for first frame after the HW setup is complete | ||
213 | */ | ||
214 | /* Find connected csi_channel */ | ||
215 | csi_chan = find_linked_csi_channel(chan, csi); | ||
216 | |||
217 | /* start streaming */ | ||
218 | ret = tegra_channel_set_stream(chan, true); | ||
219 | return ret; | ||
220 | } | ||
221 | |||
222 | static void tegra_channel_ec_init(struct tegra_channel *chan) | ||
223 | { | ||
224 | /* | ||
225 | * error recover initialization sequence | ||
226 | * set timeout as 200 ms, use default if fps not available | ||
227 | * Time limit allow CSI to capture good frames and drop error frames | ||
228 | * Timeout units is jiffies, 1 jiffy = 10ms | ||
229 | * TODO: Get frame rate from sub-device and adopt timeout | ||
230 | */ | ||
231 | chan->timeout = 20; | ||
232 | |||
233 | /* | ||
234 | * Sync point FIFO full blocks host interface | ||
235 | * Below setting enables SW to process error recovery | ||
236 | */ | ||
237 | tegra_channel_write(chan, TEGRA_VI_CFG_VI_INCR_SYNCPT_CNTRL, 0x100); | ||
238 | } | ||
239 | |||
240 | |||
241 | static void tegra_channel_clear_singleshot(struct tegra_channel *chan, | ||
242 | int index) | ||
243 | { | ||
244 | /* clear single shot */ | ||
245 | csi_write(chan, index, TEGRA_VI_CSI_SW_RESET, 0xF); | ||
246 | csi_write(chan, index, TEGRA_VI_CSI_SW_RESET, 0x0); | ||
247 | } | ||
248 | |||
249 | static void tegra_channel_vi_csi_recover(struct tegra_channel *chan) | ||
250 | { | ||
251 | u32 error_val = tegra_channel_read(chan, | ||
252 | TEGRA_VI_CFG_VI_INCR_SYNCPT_ERROR); | ||
253 | u32 frame_start; | ||
254 | int index, valid_ports = chan->valid_ports; | ||
255 | struct tegra_csi_channel *csi_chan; | ||
256 | struct tegra_csi_device *csi = chan->vi->csi; | ||
257 | |||
258 | /* Disable clock gating to enable continuous clock */ | ||
259 | tegra_channel_write(chan, TEGRA_VI_CFG_CG_CTRL, DISABLE); | ||
260 | /* Find connected csi_channel */ | ||
261 | csi_chan = find_linked_csi_channel(chan, csi); | ||
262 | |||
263 | /* clear CSI state */ | ||
264 | for (index = 0; index < valid_ports; index++) { | ||
265 | tegra_csi_error_recover(csi_chan, index); | ||
266 | csi_write(chan, index, | ||
267 | TEGRA_VI_CSI_IMAGE_DEF, 0); | ||
268 | tegra_channel_clear_singleshot(chan, index); | ||
269 | } | ||
270 | |||
271 | /* clear VI errors */ | ||
272 | for (index = 0; index < valid_ports; index++) { | ||
273 | frame_start = VI_CSI_PP_FRAME_START(chan->port[index]); | ||
274 | if (error_val & frame_start) | ||
275 | chan->syncpoint_fifo[index] = SYNCPT_FIFO_DEPTH; | ||
276 | } | ||
277 | /* clear FIFO error status */ | ||
278 | tegra_channel_write(chan, | ||
279 | TEGRA_VI_CFG_VI_INCR_SYNCPT_ERROR, error_val); | ||
280 | |||
281 | /* Enable clock gating so VI can be clock gated if necessary */ | ||
282 | tegra_channel_write(chan, TEGRA_VI_CFG_CG_CTRL, ENABLE); | ||
283 | |||
284 | /* re-init VI and CSI */ | ||
285 | tegra_channel_capture_setup(chan); | ||
286 | for (index = 0; index < valid_ports; index++) { | ||
287 | csi2_stop_streaming(csi_chan, index); | ||
288 | csi2_start_streaming(csi_chan, index); | ||
289 | nvhost_syncpt_set_min_eq_max_ext(chan->vi->ndev, | ||
290 | chan->syncpt[index][0]); | ||
291 | } | ||
292 | } | ||
293 | |||
294 | static void tegra_channel_capture_error(struct tegra_channel *chan) | ||
295 | { | ||
296 | u32 val; | ||
297 | int index = 0; | ||
298 | struct tegra_csi_channel *csi_chan; | ||
299 | struct tegra_csi_device *csi = chan->vi->csi; | ||
300 | |||
301 | /* Find connected csi_channel */ | ||
302 | csi_chan = find_linked_csi_channel(chan, csi); | ||
303 | |||
304 | for (index = 0; index < chan->valid_ports; index++) { | ||
305 | val = csi_read(chan, index, TEGRA_VI_CSI_ERROR_STATUS); | ||
306 | dev_dbg(&chan->video.dev, | ||
307 | "TEGRA_VI_CSI_ERROR_STATUS 0x%08x\n", val); | ||
308 | tegra_csi_status(csi_chan, index); | ||
309 | } | ||
310 | } | ||
311 | |||
312 | static void tegra_channel_ec_recover(struct tegra_channel *chan) | ||
313 | { | ||
314 | tegra_channel_capture_error(chan); | ||
315 | tegra_channel_vi_csi_recover(chan); | ||
316 | } | ||
317 | |||
318 | static int tegra_channel_error_status(struct tegra_channel *chan) | ||
319 | { | ||
320 | u32 val; | ||
321 | int err = 0; | ||
322 | int index = 0; | ||
323 | struct tegra_csi_channel *csi_chan; | ||
324 | struct tegra_csi_device *csi = chan->vi->csi; | ||
325 | |||
326 | /* Find connected csi_channel */ | ||
327 | csi_chan = find_linked_csi_channel(chan, csi); | ||
328 | |||
329 | for (index = 0; index < chan->valid_ports; index++) { | ||
330 | /* Ignore error based on resolution but reset status */ | ||
331 | val = csi_read(chan, index, TEGRA_VI_CSI_ERROR_STATUS); | ||
332 | csi_write(chan, index, TEGRA_VI_CSI_ERROR_STATUS, val); | ||
333 | err = tegra_csi_error(csi_chan, index); | ||
334 | } | ||
335 | |||
336 | if (err) | ||
337 | dev_err(chan->vi->dev, "%s:error %x frame %d\n", | ||
338 | __func__, err, chan->sequence); | ||
339 | return err; | ||
340 | } | ||
341 | |||
342 | static int tegra_channel_capture_frame(struct tegra_channel *chan, | ||
343 | struct tegra_channel_buffer *buf) | ||
344 | { | ||
345 | struct vb2_v4l2_buffer *vb = &buf->buf; | ||
346 | struct timespec ts; | ||
347 | int err = 0; | ||
348 | u32 val, frame_start; | ||
349 | int bytes_per_line = chan->format.bytesperline; | ||
350 | int index = 0; | ||
351 | u32 thresh[TEGRA_CSI_BLOCKS] = { 0 }; | ||
352 | int valid_ports = chan->valid_ports; | ||
353 | int state = VB2_BUF_STATE_DONE; | ||
354 | |||
355 | /* Init registers related to each frames */ | ||
356 | for (index = 0; index < valid_ports; index++) { | ||
357 | /* Program buffer address by using surface 0 */ | ||
358 | csi_write(chan, index, TEGRA_VI_CSI_SURFACE0_OFFSET_MSB, 0x0); | ||
359 | csi_write(chan, index, TEGRA_VI_CSI_SURFACE0_OFFSET_LSB, | ||
360 | (buf->addr + chan->buffer_offset[index])); | ||
361 | csi_write(chan, index, | ||
362 | TEGRA_VI_CSI_SURFACE0_STRIDE, bytes_per_line); | ||
363 | |||
364 | /* Program syncpoints */ | ||
365 | thresh[index] = nvhost_syncpt_incr_max_ext(chan->vi->ndev, | ||
366 | chan->syncpt[index][0], 1); | ||
367 | /* Do not arm sync points if FIFO had entries before */ | ||
368 | if (!chan->syncpoint_fifo[index]) { | ||
369 | frame_start = VI_CSI_PP_FRAME_START(chan->port[index]); | ||
370 | val = VI_CFG_VI_INCR_SYNCPT_COND(frame_start) | | ||
371 | chan->syncpt[index][0]; | ||
372 | tegra_channel_write(chan, | ||
373 | TEGRA_VI_CFG_VI_INCR_SYNCPT, val); | ||
374 | } else | ||
375 | chan->syncpoint_fifo[index]--; | ||
376 | } | ||
377 | |||
378 | /* enable input stream once the VI registers are configured */ | ||
379 | if (!chan->bfirst_fstart) { | ||
380 | err = tegra_channel_enable_stream(chan); | ||
381 | if (err) { | ||
382 | state = VB2_BUF_STATE_ERROR; | ||
383 | chan->capture_state = CAPTURE_ERROR; | ||
384 | tegra_channel_ring_buffer(chan, vb, &ts, state); | ||
385 | return err; | ||
386 | } | ||
387 | /* Bit controls VI memory write, enable after all regs */ | ||
388 | for (index = 0; index < valid_ports; index++) { | ||
389 | val = csi_read(chan, index, | ||
390 | TEGRA_VI_CSI_IMAGE_DEF); | ||
391 | csi_write(chan, index, TEGRA_VI_CSI_IMAGE_DEF, | ||
392 | val | IMAGE_DEF_DEST_MEM); | ||
393 | } | ||
394 | } | ||
395 | |||
396 | /* Ensure all CSI ports are ready with setup to avoid timing issue */ | ||
397 | for (index = 0; index < valid_ports; index++) | ||
398 | csi_write(chan, index, | ||
399 | TEGRA_VI_CSI_SINGLE_SHOT, SINGLE_SHOT_CAPTURE); | ||
400 | |||
401 | chan->capture_state = CAPTURE_GOOD; | ||
402 | for (index = 0; index < valid_ports; index++) { | ||
403 | err = nvhost_syncpt_wait_timeout_ext(chan->vi->ndev, | ||
404 | chan->syncpt[index][0], thresh[index], | ||
405 | chan->timeout, NULL, &ts); | ||
406 | if (err) { | ||
407 | dev_err(&chan->video.dev, | ||
408 | "frame start syncpt timeout!%d\n", index); | ||
409 | state = VB2_BUF_STATE_ERROR; | ||
410 | /* perform error recovery for timeout */ | ||
411 | tegra_channel_ec_recover(chan); | ||
412 | chan->capture_state = CAPTURE_TIMEOUT; | ||
413 | break; | ||
414 | } | ||
415 | } | ||
416 | |||
417 | if (!err && !chan->pg_mode) { | ||
418 | /* Marking error frames and resume capture */ | ||
419 | /* TODO: TPG has frame height short error always set */ | ||
420 | err = tegra_channel_error_status(chan); | ||
421 | if (err) { | ||
422 | state = VB2_BUF_STATE_ERROR; | ||
423 | chan->capture_state = CAPTURE_ERROR; | ||
424 | /* do we have to run recover here ?? */ | ||
425 | /* tegra_channel_ec_recover(chan); */ | ||
426 | } | ||
427 | } | ||
428 | |||
429 | tegra_channel_ring_buffer(chan, vb, &ts, state); | ||
430 | |||
431 | return 0; | ||
432 | } | ||
433 | |||
434 | static void tegra_channel_capture_done(struct tegra_channel *chan) | ||
435 | { | ||
436 | struct timespec ts; | ||
437 | int index, err; | ||
438 | int bytes_per_line = chan->format.bytesperline; | ||
439 | u32 val, mw_ack_done; | ||
440 | u32 thresh[TEGRA_CSI_BLOCKS] = { 0 }; | ||
441 | struct tegra_channel_buffer *buf; | ||
442 | int state = VB2_BUF_STATE_DONE; | ||
443 | |||
444 | /* dequeue buffer and return if no buffer exists */ | ||
445 | buf = dequeue_buffer(chan); | ||
446 | if (!buf) | ||
447 | return; | ||
448 | |||
449 | for (index = 0; index < chan->valid_ports; index++) { | ||
450 | /* Program buffer address by using surface 0 */ | ||
451 | csi_write(chan, index, TEGRA_VI_CSI_SURFACE0_OFFSET_MSB, 0x0); | ||
452 | csi_write(chan, index, TEGRA_VI_CSI_SURFACE0_OFFSET_LSB, | ||
453 | (buf->addr + chan->buffer_offset[index])); | ||
454 | csi_write(chan, index, | ||
455 | TEGRA_VI_CSI_SURFACE0_STRIDE, bytes_per_line); | ||
456 | |||
457 | /* Program syncpoints */ | ||
458 | thresh[index] = nvhost_syncpt_incr_max_ext(chan->vi->ndev, | ||
459 | chan->syncpt[index][0], 1); | ||
460 | mw_ack_done = VI_CSI_MW_ACK_DONE(chan->port[index]); | ||
461 | val = VI_CFG_VI_INCR_SYNCPT_COND(mw_ack_done) | | ||
462 | chan->syncpt[index][0]; | ||
463 | tegra_channel_write(chan, TEGRA_VI_CFG_VI_INCR_SYNCPT, val); | ||
464 | csi_write(chan, index, | ||
465 | TEGRA_VI_CSI_SINGLE_SHOT, SINGLE_SHOT_CAPTURE); | ||
466 | } | ||
467 | |||
468 | for (index = 0; index < chan->valid_ports; index++) { | ||
469 | err = nvhost_syncpt_wait_timeout_ext(chan->vi->ndev, | ||
470 | chan->syncpt[index][0], thresh[index], | ||
471 | chan->timeout, NULL, &ts); | ||
472 | if (err) { | ||
473 | dev_err(&chan->video.dev, | ||
474 | "MW_ACK_DONE syncpoint time out!%d\n", index); | ||
475 | state = VB2_BUF_STATE_ERROR; | ||
476 | /* perform error recovery for timeout */ | ||
477 | tegra_channel_ec_recover(chan); | ||
478 | chan->capture_state = CAPTURE_TIMEOUT; | ||
479 | break; | ||
480 | } | ||
481 | } | ||
482 | |||
483 | /* Mark capture state to IDLE as capture is finished */ | ||
484 | chan->capture_state = CAPTURE_IDLE; | ||
485 | |||
486 | tegra_channel_ring_buffer(chan, &buf->buf, &ts, state); | ||
487 | } | ||
488 | |||
489 | static int tegra_channel_kthread_capture_start(void *data) | ||
490 | { | ||
491 | struct tegra_channel *chan = data; | ||
492 | struct tegra_channel_buffer *buf; | ||
493 | int err = 0; | ||
494 | |||
495 | set_freezable(); | ||
496 | |||
497 | while (1) { | ||
498 | |||
499 | try_to_freeze(); | ||
500 | |||
501 | wait_event_interruptible(chan->start_wait, | ||
502 | !list_empty(&chan->capture) || | ||
503 | kthread_should_stop()); | ||
504 | |||
505 | if (kthread_should_stop()) | ||
506 | break; | ||
507 | |||
508 | /* source is not streaming if error is non-zero */ | ||
509 | /* wait till kthread stop and dont DeQ buffers */ | ||
510 | if (err) | ||
511 | continue; | ||
512 | |||
513 | buf = dequeue_buffer(chan); | ||
514 | if (!buf) | ||
515 | continue; | ||
516 | |||
517 | err = tegra_channel_capture_frame(chan, buf); | ||
518 | } | ||
519 | |||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | static void tegra_channel_stop_kthreads(struct tegra_channel *chan) | ||
524 | { | ||
525 | mutex_lock(&chan->stop_kthread_lock); | ||
526 | /* Stop the kthread for capture */ | ||
527 | if (chan->kthread_capture_start) { | ||
528 | kthread_stop(chan->kthread_capture_start); | ||
529 | chan->kthread_capture_start = NULL; | ||
530 | } | ||
531 | mutex_unlock(&chan->stop_kthread_lock); | ||
532 | } | ||
533 | |||
534 | static int tegra_channel_update_clknbw( | ||
535 | struct tegra_channel *chan, u8 on) __maybe_unused; | ||
536 | static int tegra_channel_update_clknbw(struct tegra_channel *chan, u8 on) | ||
537 | { | ||
538 | int ret = 0; | ||
539 | unsigned long request_pixelrate; | ||
540 | struct v4l2_subdev_frame_interval fie; | ||
541 | unsigned long csi_freq = 0; | ||
542 | |||
543 | fie.interval.denominator = DEFAULT_FRAMERATE; | ||
544 | fie.interval.numerator = 1; | ||
545 | |||
546 | if (v4l2_subdev_has_op(chan->subdev_on_csi, | ||
547 | video, g_frame_interval)) | ||
548 | v4l2_subdev_call(chan->subdev_on_csi, video, | ||
549 | g_frame_interval, &fie); | ||
550 | if (on) { | ||
551 | /** | ||
552 | * TODO: use real sensor pixelrate | ||
553 | * See PowerService code | ||
554 | */ | ||
555 | request_pixelrate = (long long)(chan->format.width | ||
556 | * chan->format.height | ||
557 | * fie.interval.denominator / 100) | ||
558 | * VI_CSI_CLK_SCALE; | ||
559 | /* for PG, get csi frequency from nvhost */ | ||
560 | if (chan->pg_mode) { | ||
561 | ret = nvhost_module_get_rate( | ||
562 | chan->vi->csi->pdev, &csi_freq, 0); | ||
563 | csi_freq = ret ? DEFAULT_CSI_FREQ : csi_freq; | ||
564 | } else | ||
565 | /* Use default csi4 frequency for t186 for now | ||
566 | * We can't get the frequency from nvhost because | ||
567 | * vi4 does not has access to csi4 | ||
568 | */ | ||
569 | csi_freq = DEFAULT_CSI_FREQ; | ||
570 | |||
571 | /* VI clk should be slightly faster than CSI clk*/ | ||
572 | ret = nvhost_module_set_rate(chan->vi->ndev, &chan->video, | ||
573 | max(request_pixelrate, | ||
574 | csi_freq * VI_CSI_CLK_SCALE * NUM_PPC / 100), | ||
575 | 0, NVHOST_PIXELRATE); | ||
576 | if (ret) { | ||
577 | dev_err(chan->vi->dev, "Fail to update vi clk\n"); | ||
578 | return ret; | ||
579 | } | ||
580 | } else { | ||
581 | ret = nvhost_module_set_rate(chan->vi->ndev, &chan->video, 0, 0, | ||
582 | NVHOST_PIXELRATE); | ||
583 | if (ret) { | ||
584 | dev_err(chan->vi->dev, "Fail to update vi clk\n"); | ||
585 | return ret; | ||
586 | } | ||
587 | } | ||
588 | |||
589 | chan->requested_kbyteps = (on > 0 ? 1 : -1) * | ||
590 | ((long long)(chan->format.width * chan->format.height | ||
591 | * fie.interval.denominator * BPP_MEM) * 115 / 100) / 1000; | ||
592 | |||
593 | mutex_lock(&chan->vi->bw_update_lock); | ||
594 | chan->vi->aggregated_kbyteps += chan->requested_kbyteps; | ||
595 | ret = vi_v4l2_update_isobw(chan->vi->aggregated_kbyteps, 0); | ||
596 | mutex_unlock(&chan->vi->bw_update_lock); | ||
597 | if (ret) | ||
598 | dev_info(chan->vi->dev, | ||
599 | "WAR:Calculation not precise.Ignore BW request failure\n"); | ||
600 | #if 0 | ||
601 | ret = vi4_v4l2_set_la(chan->vi->ndev, 0, 0); | ||
602 | if (ret) | ||
603 | dev_info(chan->vi->dev, | ||
604 | "WAR:Calculation not precise.Ignore LA failure\n"); | ||
605 | #endif | ||
606 | return 0; | ||
607 | } | ||
608 | |||
609 | int vi2_channel_start_streaming(struct vb2_queue *vq, u32 count) | ||
610 | { | ||
611 | struct tegra_channel *chan = vb2_get_drv_priv(vq); | ||
612 | struct media_pipeline *pipe = chan->video.entity.pipe; | ||
613 | int ret = 0, i; | ||
614 | struct tegra_csi_channel *csi_chan = NULL; | ||
615 | struct tegra_csi_device *csi = chan->vi->csi; | ||
616 | struct v4l2_ctrl *override_ctrl; | ||
617 | |||
618 | vi_channel_syncpt_init(chan); | ||
619 | |||
620 | tegra_channel_ec_init(chan); | ||
621 | |||
622 | /* Start the pipeline. */ | ||
623 | ret = media_entity_pipeline_start(&chan->video.entity, pipe); | ||
624 | if (ret < 0) | ||
625 | goto error_pipeline_start; | ||
626 | |||
627 | if (chan->bypass) { | ||
628 | ret = tegra_channel_set_stream(chan, true); | ||
629 | if (ret < 0) | ||
630 | goto error_set_stream; | ||
631 | return ret; | ||
632 | } | ||
633 | chan->capture_state = CAPTURE_IDLE; | ||
634 | /* Find connected csi_channel */ | ||
635 | csi_chan = find_linked_csi_channel(chan, csi); | ||
636 | |||
637 | if (!csi_chan) | ||
638 | goto error_set_stream; | ||
639 | for (i = 0; i < chan->valid_ports; i++) { | ||
640 | /* csi2_start_streaming(csi_chan, i); */ | ||
641 | /* ensure sync point state is clean */ | ||
642 | nvhost_syncpt_set_min_eq_max_ext(chan->vi->ndev, | ||
643 | chan->syncpt[i][0]); | ||
644 | } | ||
645 | |||
646 | /* Note: Program VI registers after TPG, sensors and CSI streaming */ | ||
647 | ret = tegra_channel_capture_setup(chan); | ||
648 | if (ret < 0) | ||
649 | goto error_capture_setup; | ||
650 | |||
651 | chan->sequence = 0; | ||
652 | tegra_channel_init_ring_buffer(chan); | ||
653 | |||
654 | /* disable override for vi mode */ | ||
655 | override_ctrl = v4l2_ctrl_find( | ||
656 | &chan->ctrl_handler, V4L2_CID_OVERRIDE_ENABLE); | ||
657 | if (!chan->pg_mode) { | ||
658 | if (override_ctrl) { | ||
659 | ret = v4l2_ctrl_s_ctrl(override_ctrl, false); | ||
660 | if (ret < 0) | ||
661 | dev_err(&chan->video.dev, | ||
662 | "failed to disable override control\n"); | ||
663 | } else | ||
664 | dev_err(&chan->video.dev, | ||
665 | "No override control\n"); | ||
666 | } | ||
667 | /* Update clock and bandwidth based on the format */ | ||
668 | tegra_channel_update_clknbw(chan, 1); | ||
669 | |||
670 | /* Start kthread to capture data to buffer */ | ||
671 | chan->kthread_capture_start = kthread_run( | ||
672 | tegra_channel_kthread_capture_start, | ||
673 | chan, chan->video.name); | ||
674 | if (IS_ERR(chan->kthread_capture_start)) { | ||
675 | dev_err(&chan->video.dev, | ||
676 | "failed to run kthread for capture start\n"); | ||
677 | ret = PTR_ERR(chan->kthread_capture_start); | ||
678 | goto error_capture_setup; | ||
679 | } | ||
680 | |||
681 | return 0; | ||
682 | |||
683 | error_capture_setup: | ||
684 | if (!chan->pg_mode) | ||
685 | tegra_channel_set_stream(chan, false); | ||
686 | error_set_stream: | ||
687 | if (!chan->pg_mode) | ||
688 | media_entity_pipeline_stop(&chan->video.entity); | ||
689 | error_pipeline_start: | ||
690 | vq->start_streaming_called = 0; | ||
691 | tegra_channel_queued_buf_done(chan, VB2_BUF_STATE_QUEUED); | ||
692 | |||
693 | return ret; | ||
694 | } | ||
695 | |||
696 | void vi2_channel_stop_streaming(struct vb2_queue *vq) | ||
697 | { | ||
698 | struct tegra_channel *chan = vb2_get_drv_priv(vq); | ||
699 | int index; | ||
700 | bool is_streaming = atomic_read(&chan->is_streaming); | ||
701 | struct tegra_csi_channel *csi_chan = NULL; | ||
702 | struct tegra_csi_device *csi = chan->vi->csi; | ||
703 | |||
704 | if (!chan->bypass) { | ||
705 | tegra_channel_stop_kthreads(chan); | ||
706 | /* wait for last frame memory write ack */ | ||
707 | if (is_streaming && chan->capture_state == CAPTURE_GOOD) | ||
708 | tegra_channel_capture_done(chan); | ||
709 | /* free all the ring buffers */ | ||
710 | free_ring_buffers(chan, chan->num_buffers); | ||
711 | /* dequeue buffers back to app which are in capture queue */ | ||
712 | tegra_channel_queued_buf_done(chan, VB2_BUF_STATE_ERROR); | ||
713 | |||
714 | /* Disable clock gating to enable continuous clock */ | ||
715 | tegra_channel_write(chan, TEGRA_VI_CFG_CG_CTRL, DISABLE); | ||
716 | /* Find connected csi_channel */ | ||
717 | csi_chan = find_linked_csi_channel(chan, csi); | ||
718 | if (!csi_chan) | ||
719 | pr_err("%s, no csi_chan found\n", __func__); | ||
720 | for (index = 0; index < chan->valid_ports; index++) { | ||
721 | /* csi2_stop_streaming(csi_chan, index); */ | ||
722 | /* Always clear single shot if armed at close */ | ||
723 | if (csi_read(chan, index, TEGRA_VI_CSI_SINGLE_SHOT)) | ||
724 | tegra_channel_clear_singleshot(chan, index); | ||
725 | } | ||
726 | /* Enable clock gating so VI can be clock gated if necessary */ | ||
727 | tegra_channel_write(chan, TEGRA_VI_CFG_CG_CTRL, ENABLE); | ||
728 | } | ||
729 | |||
730 | tegra_channel_set_stream(chan, false); | ||
731 | media_entity_pipeline_stop(&chan->video.entity); | ||
732 | |||
733 | if (!chan->bypass) | ||
734 | tegra_channel_update_clknbw(chan, 0); | ||
735 | |||
736 | vi_channel_syncpt_free(chan); | ||
737 | } | ||
738 | |||
739 | int tegra_vi2_power_on(struct tegra_mc_vi *vi) | ||
740 | { | ||
741 | int ret; | ||
742 | |||
743 | ret = nvhost_module_busy(vi->ndev); | ||
744 | if (ret) { | ||
745 | dev_err(vi->dev, "%s:nvhost module is busy\n", __func__); | ||
746 | return ret; | ||
747 | } | ||
748 | |||
749 | vi_write(vi, TEGRA_VI_CFG_CG_CTRL, 1); | ||
750 | |||
751 | ret = tegra_camera_emc_clk_enable(); | ||
752 | if (ret) | ||
753 | goto err_emc_enable; | ||
754 | |||
755 | return 0; | ||
756 | |||
757 | err_emc_enable: | ||
758 | nvhost_module_idle(vi->ndev); | ||
759 | |||
760 | return ret; | ||
761 | } | ||
762 | |||
763 | void tegra_vi2_power_off(struct tegra_mc_vi *vi) | ||
764 | { | ||
765 | tegra_channel_ec_close(vi); | ||
766 | tegra_camera_emc_clk_disable(); | ||
767 | nvhost_module_idle(vi->ndev); | ||
768 | } | ||
769 | |||
770 | int vi2_power_on(struct tegra_channel *chan) | ||
771 | { | ||
772 | int ret = 0; | ||
773 | struct tegra_mc_vi *vi; | ||
774 | struct vi *tegra_vi; | ||
775 | struct tegra_csi_device *csi; | ||
776 | |||
777 | vi = chan->vi; | ||
778 | tegra_vi = vi->vi; | ||
779 | csi = vi->csi; | ||
780 | |||
781 | ret = nvhost_module_add_client(vi->ndev, &chan->video); | ||
782 | if (ret) | ||
783 | return ret; | ||
784 | |||
785 | if (atomic_add_return(1, &vi->power_on_refcnt) == 1) { | ||
786 | tegra_vi2_power_on(vi); | ||
787 | if (chan->pg_mode) | ||
788 | tegra_vi->tpg_opened = true; | ||
789 | else | ||
790 | tegra_vi->sensor_opened = true; | ||
791 | } | ||
792 | |||
793 | if ((atomic_add_return(1, &chan->power_on_refcnt) == 1)) | ||
794 | ret = tegra_channel_set_power(chan, 1); | ||
795 | |||
796 | return ret; | ||
797 | } | ||
798 | |||
799 | void vi2_power_off(struct tegra_channel *chan) | ||
800 | { | ||
801 | int ret = 0; | ||
802 | struct tegra_mc_vi *vi; | ||
803 | struct vi *tegra_vi; | ||
804 | struct tegra_csi_device *csi; | ||
805 | |||
806 | vi = chan->vi; | ||
807 | tegra_vi = vi->vi; | ||
808 | csi = vi->csi; | ||
809 | |||
810 | if (atomic_dec_and_test(&chan->power_on_refcnt)) { | ||
811 | ret = tegra_channel_set_power(chan, 0); | ||
812 | if (ret < 0) | ||
813 | dev_err(vi->dev, "Failed to power off subdevices\n"); | ||
814 | } | ||
815 | |||
816 | /* The last release then turn off power */ | ||
817 | if (atomic_dec_and_test(&vi->power_on_refcnt)) { | ||
818 | tegra_vi2_power_off(vi); | ||
819 | if (vi->pg_mode) | ||
820 | tegra_vi->tpg_opened = false; | ||
821 | else | ||
822 | tegra_vi->sensor_opened = false; | ||
823 | } | ||
824 | nvhost_module_remove_client(vi->ndev, &chan->video); | ||
825 | } | ||
diff --git a/drivers/media/platform/tegra/camera/vi/vi2_fops.h b/drivers/media/platform/tegra/camera/vi/vi2_fops.h new file mode 100644 index 000000000..66c59879c --- /dev/null +++ b/drivers/media/platform/tegra/camera/vi/vi2_fops.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * Tegra Video Input 2 device common APIs | ||
3 | * | ||
4 | * Tegra Graphics Host VI | ||
5 | * | ||
6 | * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. | ||
7 | * | ||
8 | * Author: Bryan Wu <pengw@nvidia.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #ifndef __T210_VI_H__ | ||
16 | #define __T210_VI_H__ | ||
17 | |||
18 | int vi2_power_on(struct tegra_channel *chan); | ||
19 | void vi2_power_off(struct tegra_channel *chan); | ||
20 | int vi2_channel_start_streaming(struct vb2_queue *vq, u32 count); | ||
21 | int vi2_channel_stop_streaming(struct vb2_queue *vq); | ||
22 | int vi2_add_ctrls(struct tegra_channel *chan); | ||
23 | void vi2_init_video_formats(struct tegra_channel *chan); | ||
24 | |||
25 | struct tegra_vi_fops vi2_fops = { | ||
26 | .vi_power_on = vi2_power_on, | ||
27 | .vi_power_off = vi2_power_off, | ||
28 | .vi_start_streaming = vi2_channel_start_streaming, | ||
29 | .vi_stop_streaming = vi2_channel_stop_streaming, | ||
30 | .vi_add_ctrls = vi2_add_ctrls, | ||
31 | .vi_init_video_formats = vi2_init_video_formats, | ||
32 | }; | ||
33 | |||
34 | #endif | ||
diff --git a/drivers/media/platform/tegra/camera/vi/vi2_formats.h b/drivers/media/platform/tegra/camera/vi/vi2_formats.h new file mode 100644 index 000000000..c272eac3e --- /dev/null +++ b/drivers/media/platform/tegra/camera/vi/vi2_formats.h | |||
@@ -0,0 +1,131 @@ | |||
1 | /* | ||
2 | * NVIDIA Tegra Video Input Device Driver VI2 formats | ||
3 | * | ||
4 | * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * Author: Bhanu Murthy V <bmurthyv@nvidia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef __VI2_FORMATS_H_ | ||
14 | #define __VI2_FORMATS_H_ | ||
15 | |||
16 | #include "camera/vi/core.h" | ||
17 | |||
18 | /* | ||
19 | * These go into the TEGRA_VI_CSI_n_IMAGE_DEF registers bits 23:16 | ||
20 | * Output pixel memory format for the VI channel. | ||
21 | */ | ||
22 | enum tegra_image_format { | ||
23 | TEGRA_IMAGE_FORMAT_T_L8 = 16, | ||
24 | |||
25 | TEGRA_IMAGE_FORMAT_T_R16_I = 32, | ||
26 | TEGRA_IMAGE_FORMAT_T_B5G6R5, | ||
27 | TEGRA_IMAGE_FORMAT_T_R5G6B5, | ||
28 | TEGRA_IMAGE_FORMAT_T_A1B5G5R5, | ||
29 | TEGRA_IMAGE_FORMAT_T_A1R5G5B5, | ||
30 | TEGRA_IMAGE_FORMAT_T_B5G5R5A1, | ||
31 | TEGRA_IMAGE_FORMAT_T_R5G5B5A1, | ||
32 | TEGRA_IMAGE_FORMAT_T_A4B4G4R4, | ||
33 | TEGRA_IMAGE_FORMAT_T_A4R4G4B4, | ||
34 | TEGRA_IMAGE_FORMAT_T_B4G4R4A4, | ||
35 | TEGRA_IMAGE_FORMAT_T_R4G4B4A4, | ||
36 | |||
37 | TEGRA_IMAGE_FORMAT_T_A8B8G8R8 = 64, | ||
38 | TEGRA_IMAGE_FORMAT_T_A8R8G8B8, | ||
39 | TEGRA_IMAGE_FORMAT_T_B8G8R8A8, | ||
40 | TEGRA_IMAGE_FORMAT_T_R8G8B8A8, | ||
41 | TEGRA_IMAGE_FORMAT_T_A2B10G10R10, | ||
42 | TEGRA_IMAGE_FORMAT_T_A2R10G10B10, | ||
43 | TEGRA_IMAGE_FORMAT_T_B10G10R10A2, | ||
44 | TEGRA_IMAGE_FORMAT_T_R10G10B10A2, | ||
45 | |||
46 | TEGRA_IMAGE_FORMAT_T_A8Y8U8V8 = 193, | ||
47 | TEGRA_IMAGE_FORMAT_T_V8U8Y8A8, | ||
48 | |||
49 | TEGRA_IMAGE_FORMAT_T_A2Y10U10V10 = 197, | ||
50 | TEGRA_IMAGE_FORMAT_T_V10U10Y10A2, | ||
51 | |||
52 | TEGRA_IMAGE_FORMAT_T_Y8_U8__Y8_V8 = 200, | ||
53 | TEGRA_IMAGE_FORMAT_T_Y8_V8__Y8_U8, | ||
54 | TEGRA_IMAGE_FORMAT_T_U8_Y8__V8_Y8, | ||
55 | TEGRA_IMAGE_FORMAT_T_T_V8_Y8__U8_Y8, | ||
56 | |||
57 | TEGRA_IMAGE_FORMAT_T_T_Y8__U8__V8_N444 = 224, | ||
58 | TEGRA_IMAGE_FORMAT_T_Y8__U8V8_N444, | ||
59 | TEGRA_IMAGE_FORMAT_T_Y8__V8U8_N444, | ||
60 | TEGRA_IMAGE_FORMAT_T_Y8__U8__V8_N422, | ||
61 | TEGRA_IMAGE_FORMAT_T_Y8__U8V8_N422, | ||
62 | TEGRA_IMAGE_FORMAT_T_Y8__V8U8_N422, | ||
63 | TEGRA_IMAGE_FORMAT_T_Y8__U8__V8_N420, | ||
64 | TEGRA_IMAGE_FORMAT_T_Y8__U8V8_N420, | ||
65 | TEGRA_IMAGE_FORMAT_T_Y8__V8U8_N420, | ||
66 | TEGRA_IMAGE_FORMAT_T_X2Lc10Lb10La10, | ||
67 | TEGRA_IMAGE_FORMAT_T_A2R6R6R6R6R6, | ||
68 | }; | ||
69 | |||
70 | static const struct tegra_video_format vi2_video_formats[] = { | ||
71 | /* RAW 6: TODO */ | ||
72 | |||
73 | /* RAW 7: TODO */ | ||
74 | |||
75 | /* RAW 8 */ | ||
76 | TEGRA_VIDEO_FORMAT(RAW8, 8, SRGGB8_1X8, 1, 1, T_L8, | ||
77 | RAW8, SRGGB8, "RGRG.. GBGB.."), | ||
78 | TEGRA_VIDEO_FORMAT(RAW8, 8, SGRBG8_1X8, 1, 1, T_L8, | ||
79 | RAW8, SGRBG8, "GRGR.. BGBG.."), | ||
80 | TEGRA_VIDEO_FORMAT(RAW8, 8, SGBRG8_1X8, 1, 1, T_L8, | ||
81 | RAW8, SGBRG8, "GBGB.. RGRG.."), | ||
82 | TEGRA_VIDEO_FORMAT(RAW8, 8, SBGGR8_1X8, 1, 1, T_L8, | ||
83 | RAW8, SBGGR8, "BGBG.. GRGR.."), | ||
84 | |||
85 | /* RAW 10 */ | ||
86 | TEGRA_VIDEO_FORMAT(RAW10, 10, SRGGB10_1X10, 2, 1, T_R16_I, | ||
87 | RAW10, SRGGB10, "RGRG.. GBGB.."), | ||
88 | TEGRA_VIDEO_FORMAT(RAW10, 10, SGRBG10_1X10, 2, 1, T_R16_I, | ||
89 | RAW10, SGRBG10, "GRGR.. BGBG.."), | ||
90 | TEGRA_VIDEO_FORMAT(RAW10, 10, SGBRG10_1X10, 2, 1, T_R16_I, | ||
91 | RAW10, SGBRG10, "GBGB.. RGRG.."), | ||
92 | TEGRA_VIDEO_FORMAT(RAW10, 10, SBGGR10_1X10, 2, 1, T_R16_I, | ||
93 | RAW10, SBGGR10, "BGBG.. GRGR.."), | ||
94 | |||
95 | /* RAW 10 Packed format */ | ||
96 | TEGRA_VIDEO_FORMAT(RAW10, 10, XBGGR10P_3X10, 4, 3, T_X2Lc10Lb10La10, | ||
97 | RAW10, XBGGR10P, "BGBG.. GRGR.."), | ||
98 | TEGRA_VIDEO_FORMAT(RAW10, 10, XRGGB10P_3X10, 4, 3, T_X2Lc10Lb10La10, | ||
99 | RAW10, XRGGB10P, "RGRG.. GBGB.."), | ||
100 | |||
101 | /* RAW 12 */ | ||
102 | TEGRA_VIDEO_FORMAT(RAW12, 12, SRGGB12_1X12, 2, 1, T_R16_I, | ||
103 | RAW12, SRGGB12, "RGRG.. GBGB.."), | ||
104 | TEGRA_VIDEO_FORMAT(RAW12, 12, SGRBG12_1X12, 2, 1, T_R16_I, | ||
105 | RAW12, SGRBG12, "GRGR.. BGBG.."), | ||
106 | TEGRA_VIDEO_FORMAT(RAW12, 12, SGBRG12_1X12, 2, 1, T_R16_I, | ||
107 | RAW12, SGBRG12, "GBGB.. RGRG.."), | ||
108 | TEGRA_VIDEO_FORMAT(RAW12, 12, SBGGR12_1X12, 2, 1, T_R16_I, | ||
109 | RAW12, SBGGR12, "BGBG.. GRGR.."), | ||
110 | |||
111 | /* RGB888 */ | ||
112 | TEGRA_VIDEO_FORMAT(RGB888, 24, RGB888_1X24, 4, 1, T_A8R8G8B8, | ||
113 | RGB888, ABGR32, "BGRA-8-8-8-8"), | ||
114 | TEGRA_VIDEO_FORMAT(RGB888, 24, RGB888_1X32_PADHI, 4, 1, T_A8B8G8R8, | ||
115 | RGB888, RGB32, "RGB-8-8-8-8"), | ||
116 | |||
117 | /* YUV422 */ | ||
118 | TEGRA_VIDEO_FORMAT(YUV422, 16, UYVY8_1X16, 2, 1, T_U8_Y8__V8_Y8, | ||
119 | YUV422_8, UYVY, "YUV 4:2:2"), | ||
120 | TEGRA_VIDEO_FORMAT(YUV422, 16, UYVY8_1X16, 1, 1, T_Y8__V8U8_N422, | ||
121 | YUV422_8, NV16, "NV16"), | ||
122 | TEGRA_VIDEO_FORMAT(YUV422, 16, UYVY8_2X8, 2, 1, T_U8_Y8__V8_Y8, | ||
123 | YUV422_8, UYVY, "YUV 4:2:2 UYVY"), | ||
124 | TEGRA_VIDEO_FORMAT(YUV422, 16, VYUY8_2X8, 2, 1, T_T_V8_Y8__U8_Y8, | ||
125 | YUV422_8, VYUY, "YUV 4:2:2 VYUY"), | ||
126 | TEGRA_VIDEO_FORMAT(YUV422, 16, YUYV8_2X8, 2, 1, T_Y8_U8__Y8_V8, | ||
127 | YUV422_8, YUYV, "YUV 4:2:2 YUYV"), | ||
128 | TEGRA_VIDEO_FORMAT(YUV422, 16, YVYU8_2X8, 2, 1, T_Y8_V8__Y8_U8, | ||
129 | YUV422_8, YVYU, "YUV 4:2:2 YVYU"), | ||
130 | }; | ||
131 | #endif | ||
diff --git a/drivers/media/platform/tegra/camera/vi/vi4_fops.c b/drivers/media/platform/tegra/camera/vi/vi4_fops.c new file mode 100644 index 000000000..d78ed3421 --- /dev/null +++ b/drivers/media/platform/tegra/camera/vi/vi4_fops.c | |||
@@ -0,0 +1,1056 @@ | |||
1 | /* | ||
2 | * Tegra Video Input 4 device common APIs | ||
3 | * | ||
4 | * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * Author: Frank Chen <frank@nvidia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | #include <linux/freezer.h> | ||
13 | #include <linux/kthread.h> | ||
14 | #include <linux/nvhost.h> | ||
15 | #include <linux/tegra-powergate.h> | ||
16 | #include <media/capture.h> | ||
17 | #include <media/tegra_camera_platform.h> | ||
18 | #include "linux/nvhost_ioctl.h" | ||
19 | #include "mc_common.h" | ||
20 | #include "nvhost_acm.h" | ||
21 | #include "vi4_formats.h" | ||
22 | #include "vi4_registers.h" | ||
23 | #include "vi/vi4.h" | ||
24 | #include "vi/vi_notify.h" | ||
25 | |||
26 | #define DEFAULT_FRAMERATE 30 | ||
27 | #define DEFAULT_CSI_FREQ 204000000 | ||
28 | #define BPP_MEM 2 | ||
29 | #define MAX_VI_CHANNEL 12 | ||
30 | #define NUM_PPC 8 | ||
31 | #define VI_CSI_CLK_SCALE 110 | ||
32 | #define SOF_SYNCPT_IDX 0 | ||
33 | #define FE_SYNCPT_IDX 1 | ||
34 | |||
35 | void tegra_channel_queued_buf_done(struct tegra_channel *chan, | ||
36 | enum vb2_buffer_state state); | ||
37 | int tegra_channel_set_stream(struct tegra_channel *chan, bool on); | ||
38 | void tegra_channel_ring_buffer(struct tegra_channel *chan, | ||
39 | struct vb2_v4l2_buffer *vb, | ||
40 | struct timespec *ts, int state); | ||
41 | struct tegra_channel_buffer *dequeue_buffer(struct tegra_channel *chan); | ||
42 | void tegra_channel_init_ring_buffer(struct tegra_channel *chan); | ||
43 | void free_ring_buffers(struct tegra_channel *chan, int frames); | ||
44 | int tegra_channel_set_power(struct tegra_channel *chan, bool on); | ||
45 | static void tegra_channel_stop_kthreads(struct tegra_channel *chan); | ||
46 | static int tegra_channel_stop_increments(struct tegra_channel *chan); | ||
47 | static void tegra_channel_notify_status_callback( | ||
48 | struct vi_notify_channel *, | ||
49 | const struct vi_capture_status *, | ||
50 | void *); | ||
51 | static void tegra_channel_error_worker(struct work_struct *status_work); | ||
52 | static void tegra_channel_notify_error_callback(void *); | ||
53 | |||
54 | u32 csimux_config_stream[] = { | ||
55 | CSIMUX_CONFIG_STREAM_0, | ||
56 | CSIMUX_CONFIG_STREAM_1, | ||
57 | CSIMUX_CONFIG_STREAM_2, | ||
58 | CSIMUX_CONFIG_STREAM_3, | ||
59 | CSIMUX_CONFIG_STREAM_4, | ||
60 | CSIMUX_CONFIG_STREAM_5 | ||
61 | }; | ||
62 | |||
63 | static void vi4_write(struct tegra_channel *chan, unsigned int addr, u32 val) | ||
64 | { | ||
65 | writel(val, chan->vi->iomem + addr); | ||
66 | } | ||
67 | |||
68 | static u32 vi4_read(struct tegra_channel *chan, unsigned int addr) | ||
69 | { | ||
70 | return readl(chan->vi->iomem + addr); | ||
71 | } | ||
72 | |||
73 | static void vi4_channel_write(struct tegra_channel *chan, | ||
74 | unsigned int index, unsigned int addr, u32 val) | ||
75 | { | ||
76 | writel(val, | ||
77 | chan->vi->iomem + VI4_CHANNEL_OFFSET * (index + 1) + addr); | ||
78 | } | ||
79 | |||
80 | void vi4_init_video_formats(struct tegra_channel *chan) | ||
81 | { | ||
82 | int i; | ||
83 | |||
84 | chan->num_video_formats = ARRAY_SIZE(vi4_video_formats); | ||
85 | for (i = 0; i < chan->num_video_formats; i++) | ||
86 | chan->video_formats[i] = &vi4_video_formats[i]; | ||
87 | } | ||
88 | |||
89 | long vi4_default_ioctl(struct file *file, void *fh, | ||
90 | bool use_prio, unsigned int cmd, void *arg) | ||
91 | { | ||
92 | struct v4l2_fh *vfh = file->private_data; | ||
93 | struct tegra_channel *chan = to_tegra_channel(vfh->vdev); | ||
94 | long err = 0; | ||
95 | |||
96 | switch (_IOC_NR(cmd)) { | ||
97 | #if defined(CONFIG_TEGRA_CAMERA_RTCPU) | ||
98 | case _IOC_NR(VIDIOC_CAPTURE_SETUP): | ||
99 | if (chan->bypass) | ||
100 | err = vi_capture_setup(chan, | ||
101 | (struct vi_capture_setup *)arg); | ||
102 | else { | ||
103 | dev_err(&chan->video.dev, "not in bypass mode\n"); | ||
104 | err = -ENODEV; | ||
105 | } | ||
106 | if (err) | ||
107 | dev_err(&chan->video.dev, "capture setup failed\n"); | ||
108 | break; | ||
109 | case _IOC_NR(VIDIOC_CAPTURE_RESET): | ||
110 | if (chan->bypass) | ||
111 | err = vi_capture_reset(chan, *(uint32_t *)arg); | ||
112 | else { | ||
113 | dev_err(&chan->video.dev, "not in bypass mode\n"); | ||
114 | err = -ENODEV; | ||
115 | } | ||
116 | if (err) | ||
117 | dev_err(&chan->video.dev, "capture reset failed\n"); | ||
118 | break; | ||
119 | case _IOC_NR(VIDIOC_CAPTURE_RELEASE): | ||
120 | if (chan->bypass) | ||
121 | err = vi_capture_release(chan, *(uint32_t *)arg); | ||
122 | else { | ||
123 | dev_err(&chan->video.dev, "not in bypass mode\n"); | ||
124 | err = -ENODEV; | ||
125 | } | ||
126 | if (err) | ||
127 | dev_err(&chan->video.dev, "capture release failed\n"); | ||
128 | break; | ||
129 | case _IOC_NR(VIDIOC_CAPTURE_GET_INFO): | ||
130 | if (chan->bypass) | ||
131 | err = vi_capture_get_info(chan, | ||
132 | (struct vi_capture_info *)arg); | ||
133 | else { | ||
134 | dev_err(&chan->video.dev, "not in bypass mode\n"); | ||
135 | err = -ENODEV; | ||
136 | } | ||
137 | if (err) | ||
138 | dev_err(&chan->video.dev, "capture get info failed\n"); | ||
139 | break; | ||
140 | case _IOC_NR(VIDIOC_CAPTURE_SET_CONFIG): | ||
141 | if (chan->bypass) | ||
142 | err = vi_capture_control_message(chan, | ||
143 | (struct vi_capture_control_msg *)arg); | ||
144 | else { | ||
145 | dev_err(&chan->video.dev, "not in bypass mode\n"); | ||
146 | err = -ENODEV; | ||
147 | } | ||
148 | if (err) | ||
149 | dev_err(&chan->video.dev, "capture config failed\n"); | ||
150 | break; | ||
151 | case _IOC_NR(VIDIOC_CAPTURE_REQUEST): | ||
152 | if (chan->bypass) | ||
153 | err = vi_capture_request(chan, | ||
154 | (struct vi_capture_req *)arg); | ||
155 | else { | ||
156 | dev_err(&chan->video.dev, "not in bypass mode\n"); | ||
157 | err = -ENODEV; | ||
158 | } | ||
159 | if (err) | ||
160 | dev_err(&chan->video.dev, | ||
161 | "capture request submit failed\n"); | ||
162 | break; | ||
163 | case _IOC_NR(VIDIOC_CAPTURE_STATUS): | ||
164 | if (chan->bypass) | ||
165 | err = vi_capture_status(chan, *(uint32_t *)arg); | ||
166 | else { | ||
167 | dev_err(&chan->video.dev, "not in bypass mode\n"); | ||
168 | err = -ENODEV; | ||
169 | } | ||
170 | if (err) | ||
171 | dev_err(&chan->video.dev, | ||
172 | "capture get status failed\n"); | ||
173 | break; | ||
174 | #endif | ||
175 | default: | ||
176 | dev_err(&chan->video.dev, "%s:Unknown ioctl\n", __func__); | ||
177 | return -ENOIOCTLCMD; | ||
178 | } | ||
179 | |||
180 | return err; | ||
181 | } | ||
182 | |||
183 | |||
184 | int tegra_vi4_s_ctrl(struct v4l2_ctrl *ctrl) | ||
185 | { | ||
186 | struct tegra_channel *chan = container_of(ctrl->handler, | ||
187 | struct tegra_channel, ctrl_handler); | ||
188 | int err = 0; | ||
189 | |||
190 | switch (ctrl->id) { | ||
191 | case V4L2_CID_WRITE_ISPFORMAT: | ||
192 | chan->write_ispformat = ctrl->val; | ||
193 | break; | ||
194 | default: | ||
195 | dev_err(&chan->video.dev, "%s:Not valid ctrl\n", __func__); | ||
196 | return -EINVAL; | ||
197 | } | ||
198 | |||
199 | return err; | ||
200 | } | ||
201 | |||
202 | static const struct v4l2_ctrl_ops vi4_ctrl_ops = { | ||
203 | .s_ctrl = tegra_vi4_s_ctrl, | ||
204 | }; | ||
205 | |||
206 | static const struct v4l2_ctrl_config vi4_custom_ctrls[] = { | ||
207 | { | ||
208 | .ops = &vi4_ctrl_ops, | ||
209 | .id = V4L2_CID_WRITE_ISPFORMAT, | ||
210 | .name = "Write ISP format", | ||
211 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
212 | .def = 1, | ||
213 | .min = 1, | ||
214 | .max = 1, | ||
215 | .step = 1, | ||
216 | }, | ||
217 | }; | ||
218 | |||
219 | int vi4_add_ctrls(struct tegra_channel *chan) | ||
220 | { | ||
221 | int i; | ||
222 | |||
223 | /* Add vi4 custom controls */ | ||
224 | for (i = 0; i < ARRAY_SIZE(vi4_custom_ctrls); i++) { | ||
225 | v4l2_ctrl_new_custom(&chan->ctrl_handler, | ||
226 | &vi4_custom_ctrls[i], NULL); | ||
227 | if (chan->ctrl_handler.error) { | ||
228 | dev_err(chan->vi->dev, | ||
229 | "Failed to add %s ctrl\n", | ||
230 | vi4_custom_ctrls[i].name); | ||
231 | return chan->ctrl_handler.error; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | static bool vi4_init(struct tegra_channel *chan) | ||
239 | { | ||
240 | vi4_write(chan, CFG_INTERRUPT_MASK, 0x3f0000f9); | ||
241 | vi4_write(chan, CFG_INTERRUPT_STATUS, 0x3f000001); | ||
242 | vi4_write(chan, NOTIFY_ERROR, 0x1); | ||
243 | vi4_write(chan, NOTIFY_TAG_CLASSIFY_0, 0xe39c08e3); | ||
244 | return true; | ||
245 | } | ||
246 | |||
247 | static bool vi4_check_status(struct tegra_channel *chan) | ||
248 | { | ||
249 | int status; | ||
250 | |||
251 | /* check interrupt status error */ | ||
252 | status = vi4_read(chan, CFG_INTERRUPT_STATUS); | ||
253 | if (status & 0x1) | ||
254 | dev_err(chan->vi->dev, | ||
255 | "VI_CFG_INTERRUPT_STATUS_0: MASTER_ERR_STATUS error!\n"); | ||
256 | |||
257 | /* Check VI NOTIFY input FIFO error */ | ||
258 | status = vi4_read(chan, NOTIFY_ERROR); | ||
259 | if (status & 0x1) | ||
260 | dev_err(chan->vi->dev, | ||
261 | "VI_NOTIFY_ERROR_0: NOTIFY_FIFO_OVERFLOW error!\n"); | ||
262 | |||
263 | return true; | ||
264 | } | ||
265 | |||
266 | static bool vi_notify_wait(struct tegra_channel *chan, | ||
267 | struct timespec *ts) | ||
268 | { | ||
269 | int i, err; | ||
270 | u32 thresh[TEGRA_CSI_BLOCKS], temp; | ||
271 | |||
272 | /* | ||
273 | * Increment syncpt for ATOMP_FE | ||
274 | * | ||
275 | * This is needed in order to keep the syncpt max up to date, | ||
276 | * even if we are not waiting for ATOMP_FE here | ||
277 | */ | ||
278 | for (i = 0; i < chan->valid_ports; i++) | ||
279 | temp = nvhost_syncpt_incr_max_ext(chan->vi->ndev, | ||
280 | chan->syncpt[i][FE_SYNCPT_IDX], 1); | ||
281 | |||
282 | /* | ||
283 | * Increment syncpt for PXL_SOF | ||
284 | * | ||
285 | * Increment and retrieve PXL_SOF syncpt max value. | ||
286 | * This value will be used to wait for next syncpt | ||
287 | */ | ||
288 | for (i = 0; i < chan->valid_ports; i++) | ||
289 | thresh[i] = nvhost_syncpt_incr_max_ext(chan->vi->ndev, | ||
290 | chan->syncpt[i][SOF_SYNCPT_IDX], 1); | ||
291 | |||
292 | /* | ||
293 | * Wait for PXL_SOF syncpt | ||
294 | * | ||
295 | * Use the syncpt max value we just set as threshold | ||
296 | */ | ||
297 | for (i = 0; i < chan->valid_ports; i++) { | ||
298 | err = nvhost_syncpt_wait_timeout_ext(chan->vi->ndev, | ||
299 | chan->syncpt[i][SOF_SYNCPT_IDX], thresh[i], | ||
300 | 250, NULL, NULL); | ||
301 | if (unlikely(err)) | ||
302 | dev_err(chan->vi->dev, | ||
303 | "PXL_SOF syncpt timeout! err = %d\n", err); | ||
304 | else { | ||
305 | struct vi_capture_status status; | ||
306 | |||
307 | err = vi_notify_get_capture_status(chan->vnc[i], | ||
308 | chan->vnc_id[i], | ||
309 | thresh[i], &status); | ||
310 | if (unlikely(err)) | ||
311 | dev_err(chan->vi->dev, | ||
312 | "no capture status! err = %d\n", err); | ||
313 | else | ||
314 | *ts = ns_to_timespec((s64)status.sof_ts); | ||
315 | } | ||
316 | } | ||
317 | return true; | ||
318 | } | ||
319 | |||
320 | static void tegra_channel_surface_setup( | ||
321 | struct tegra_channel *chan, struct tegra_channel_buffer *buf, int index) | ||
322 | { | ||
323 | int vnc_id = chan->vnc_id[index]; | ||
324 | unsigned int offset = chan->buffer_offset[index]; | ||
325 | |||
326 | vi4_channel_write(chan, vnc_id, ATOMP_EMB_SURFACE_OFFSET0, 0x0); | ||
327 | vi4_channel_write(chan, vnc_id, ATOMP_EMB_SURFACE_OFFSET0_H, 0x0); | ||
328 | vi4_channel_write(chan, vnc_id, ATOMP_EMB_SURFACE_STRIDE0, 0x0); | ||
329 | vi4_channel_write(chan, vnc_id, | ||
330 | ATOMP_SURFACE_OFFSET0, buf->addr + offset); | ||
331 | vi4_channel_write(chan, vnc_id, | ||
332 | ATOMP_SURFACE_STRIDE0, chan->format.bytesperline); | ||
333 | vi4_channel_write(chan, vnc_id, ATOMP_SURFACE_OFFSET0_H, 0x0); | ||
334 | |||
335 | if (chan->fmtinfo->fourcc == V4L2_PIX_FMT_NV16) { | ||
336 | vi4_channel_write(chan, vnc_id, | ||
337 | ATOMP_SURFACE_OFFSET1, buf->addr + offset + | ||
338 | chan->format.sizeimage / 2); | ||
339 | vi4_channel_write(chan, vnc_id, | ||
340 | ATOMP_SURFACE_OFFSET1_H, 0x0); | ||
341 | vi4_channel_write(chan, vnc_id, | ||
342 | ATOMP_SURFACE_STRIDE1, chan->format.bytesperline); | ||
343 | |||
344 | } else { | ||
345 | vi4_channel_write(chan, vnc_id, ATOMP_SURFACE_OFFSET1, 0x0); | ||
346 | vi4_channel_write(chan, vnc_id, ATOMP_SURFACE_OFFSET1_H, 0x0); | ||
347 | vi4_channel_write(chan, vnc_id, ATOMP_SURFACE_STRIDE1, 0x0); | ||
348 | } | ||
349 | |||
350 | vi4_channel_write(chan, vnc_id, ATOMP_SURFACE_OFFSET2, 0x0); | ||
351 | vi4_channel_write(chan, vnc_id, ATOMP_SURFACE_OFFSET2_H, 0x0); | ||
352 | vi4_channel_write(chan, vnc_id, ATOMP_SURFACE_STRIDE2, 0x0); | ||
353 | } | ||
354 | |||
355 | static void tegra_channel_handle_error(struct tegra_channel *chan) | ||
356 | { | ||
357 | struct v4l2_subdev *sd_on_csi = chan->subdev_on_csi; | ||
358 | static const struct v4l2_event source_ev_fmt = { | ||
359 | .type = V4L2_EVENT_SOURCE_CHANGE, | ||
360 | .u.src_change.changes = V4L2_EVENT_SRC_ERROR, | ||
361 | }; | ||
362 | |||
363 | tegra_channel_stop_increments(chan); | ||
364 | vb2_queue_error(&chan->queue); | ||
365 | |||
366 | /* Application gets notified after CSI Tx's are reset */ | ||
367 | if (sd_on_csi->devnode) | ||
368 | v4l2_subdev_notify_event(sd_on_csi, &source_ev_fmt); | ||
369 | } | ||
370 | |||
371 | static void tegra_channel_status_worker(struct work_struct *status_work) | ||
372 | { | ||
373 | struct tegra_channel *chan; | ||
374 | |||
375 | chan = container_of(status_work, struct tegra_channel, status_work); | ||
376 | |||
377 | tegra_channel_handle_error(chan); | ||
378 | } | ||
379 | |||
380 | static void tegra_channel_notify_status_callback( | ||
381 | struct vi_notify_channel *vnc, | ||
382 | const struct vi_capture_status *status, | ||
383 | void *client_data) | ||
384 | { | ||
385 | struct tegra_channel *chan = (struct tegra_channel *)client_data; | ||
386 | int i; | ||
387 | |||
388 | spin_lock(&chan->capture_state_lock); | ||
389 | if (chan->capture_state == CAPTURE_GOOD) | ||
390 | chan->capture_state = CAPTURE_ERROR; | ||
391 | else { | ||
392 | spin_unlock(&chan->capture_state_lock); | ||
393 | return; | ||
394 | } | ||
395 | spin_unlock(&chan->capture_state_lock); | ||
396 | |||
397 | for (i = 0; i < chan->valid_ports; i++) | ||
398 | dev_err(chan->vi->dev, "Status: %2u channel:%02X frame:%04X\n", | ||
399 | status->status, chan->vnc_id[i], status->frame); | ||
400 | dev_err(chan->vi->dev, " timestamp sof %llu eof %llu data 0x%08x\n", | ||
401 | status->sof_ts, status->eof_ts, status->data); | ||
402 | dev_err(chan->vi->dev, " capture_id %u stream %2u vchan %2u\n", | ||
403 | status->capture_id, status->st, status->vc); | ||
404 | |||
405 | schedule_work(&chan->status_work); | ||
406 | } | ||
407 | |||
408 | static int tegra_channel_notify_enable( | ||
409 | struct tegra_channel *chan, unsigned int index) | ||
410 | { | ||
411 | struct tegra_vi4_syncpts_req req; | ||
412 | int i, err; | ||
413 | |||
414 | chan->vnc_id[index] = -1; | ||
415 | for (i = 0; i < MAX_VI_CHANNEL; i++) { | ||
416 | chan->vnc[index] = vi_notify_channel_open(i); | ||
417 | if (!IS_ERR(chan->vnc[index])) { | ||
418 | chan->vnc_id[index] = i; | ||
419 | break; | ||
420 | } | ||
421 | } | ||
422 | if (chan->vnc_id[index] < 0) { | ||
423 | dev_err(chan->vi->dev, "No VI channel available!\n"); | ||
424 | return -EFAULT; | ||
425 | } | ||
426 | |||
427 | vi_notify_channel_set_notify_funcs(chan->vnc[index], | ||
428 | &tegra_channel_notify_status_callback, | ||
429 | &tegra_channel_notify_error_callback, | ||
430 | (void *)chan); | ||
431 | |||
432 | /* get PXL_SOF syncpt id */ | ||
433 | chan->syncpt[index][SOF_SYNCPT_IDX] = | ||
434 | nvhost_get_syncpt_client_managed(chan->vi->ndev, "tegra-vi4"); | ||
435 | if (chan->syncpt[index][SOF_SYNCPT_IDX] == 0) { | ||
436 | dev_err(chan->vi->dev, "Failed to get PXL_SOF syncpt!\n"); | ||
437 | return -EFAULT; | ||
438 | } | ||
439 | |||
440 | /* get ATOMP_FE syncpt id */ | ||
441 | chan->syncpt[index][FE_SYNCPT_IDX] = | ||
442 | nvhost_get_syncpt_client_managed(chan->vi->ndev, "tegra-vi4"); | ||
443 | if (chan->syncpt[index][FE_SYNCPT_IDX] == 0) { | ||
444 | dev_err(chan->vi->dev, "Failed to get ATOMP_FE syncpt!\n"); | ||
445 | nvhost_syncpt_put_ref_ext( | ||
446 | chan->vi->ndev, chan->syncpt[index][SOF_SYNCPT_IDX]); | ||
447 | return -EFAULT; | ||
448 | } | ||
449 | |||
450 | nvhost_syncpt_set_min_eq_max_ext( | ||
451 | chan->vi->ndev, chan->syncpt[index][SOF_SYNCPT_IDX]); | ||
452 | nvhost_syncpt_set_min_eq_max_ext( | ||
453 | chan->vi->ndev, chan->syncpt[index][FE_SYNCPT_IDX]); | ||
454 | |||
455 | /* enable VI Notify report */ | ||
456 | req.syncpt_ids[0] = chan->syncpt[index][SOF_SYNCPT_IDX]; /* PXL_SOF */ | ||
457 | req.syncpt_ids[1] = chan->syncpt[index][FE_SYNCPT_IDX]; /* ATOMP_FE */ | ||
458 | req.syncpt_ids[2] = 0xffffffff; | ||
459 | req.stream = chan->port[index]; | ||
460 | req.vc = 0; | ||
461 | req.pad = 0; | ||
462 | |||
463 | err = vi_notify_channel_enable_reports( | ||
464 | chan->vnc_id[index], chan->vnc[index], &req); | ||
465 | if (err < 0) | ||
466 | dev_err(chan->vi->dev, | ||
467 | "Failed to enable report for VI Notify, err = %d\n", | ||
468 | err); | ||
469 | |||
470 | return err; | ||
471 | } | ||
472 | |||
473 | static int tegra_channel_notify_disable( | ||
474 | struct tegra_channel *chan, unsigned int index) | ||
475 | { | ||
476 | int err; | ||
477 | int ret = 0; | ||
478 | struct tegra_vi4_syncpts_req req; | ||
479 | |||
480 | /* free syncpts */ | ||
481 | nvhost_syncpt_put_ref_ext( | ||
482 | chan->vi->ndev, chan->syncpt[index][SOF_SYNCPT_IDX]); | ||
483 | nvhost_syncpt_put_ref_ext( | ||
484 | chan->vi->ndev, chan->syncpt[index][FE_SYNCPT_IDX]); | ||
485 | |||
486 | /* close vi-notifier */ | ||
487 | req.syncpt_ids[0] = 0xffffffff; | ||
488 | req.syncpt_ids[1] = 0xffffffff; | ||
489 | req.syncpt_ids[2] = 0xffffffff; | ||
490 | req.stream = chan->port[index]; | ||
491 | req.vc = 0; | ||
492 | req.pad = 0; | ||
493 | |||
494 | err = vi_notify_channel_reset( | ||
495 | chan->vnc_id[index], chan->vnc[index], &req); | ||
496 | if (err < 0) { | ||
497 | dev_err(chan->vi->dev, | ||
498 | "VI Notify channel reset failed, err = %d\n", err); | ||
499 | if (!ret) | ||
500 | ret = err; | ||
501 | } | ||
502 | |||
503 | err = vi_notify_channel_close(chan->vnc_id[index], chan->vnc[index]); | ||
504 | if (err < 0) { | ||
505 | dev_err(chan->vi->dev, | ||
506 | "VI Notify channel close failed, err = %d\n", err); | ||
507 | if (!ret) | ||
508 | ret = err; | ||
509 | } | ||
510 | |||
511 | return ret; | ||
512 | } | ||
513 | |||
514 | static int tegra_channel_capture_setup(struct tegra_channel *chan, | ||
515 | unsigned int index) | ||
516 | { | ||
517 | u32 height = chan->format.height; | ||
518 | u32 width = chan->format.width; | ||
519 | u32 format = chan->fmtinfo->img_fmt; | ||
520 | u32 data_type = chan->fmtinfo->img_dt; | ||
521 | u32 csi_port = chan->port[index]; | ||
522 | u32 stream = 1U << csi_port; | ||
523 | u32 virtual_ch = 1U << 0; | ||
524 | u32 vnc_id; | ||
525 | int err; | ||
526 | |||
527 | if (chan->valid_ports > 1) { | ||
528 | height = chan->gang_height; | ||
529 | width = chan->gang_width; | ||
530 | } | ||
531 | |||
532 | err = tegra_channel_notify_enable(chan, index); | ||
533 | if (err < 0) { | ||
534 | dev_err(chan->vi->dev, | ||
535 | "Failed to setup VI Notifier, err = %d\n", err); | ||
536 | return err; | ||
537 | } | ||
538 | |||
539 | vnc_id = chan->vnc_id[index]; | ||
540 | |||
541 | vi4_write(chan, csimux_config_stream[csi_port], 0x1); | ||
542 | |||
543 | vi4_channel_write(chan, vnc_id, MATCH, | ||
544 | ((stream << STREAM_SHIFT) & STREAM) | | ||
545 | STREAM_MASK | | ||
546 | ((virtual_ch << VIRTUAL_CHANNEL_SHIFT) & | ||
547 | VIRTUAL_CHANNEL) | | ||
548 | VIRTUAL_CHANNEL_MASK); | ||
549 | |||
550 | vi4_channel_write(chan, vnc_id, MATCH_DATATYPE, | ||
551 | ((data_type << DATATYPE_SHIFT) & DATATYPE) | | ||
552 | DATATYPE_MASK); | ||
553 | |||
554 | vi4_channel_write(chan, vnc_id, DT_OVERRIDE, 0x0); | ||
555 | |||
556 | vi4_channel_write(chan, vnc_id, MATCH_FRAMEID, | ||
557 | ((0 << FRAMEID_SHIFT) & FRAMEID) | 0); | ||
558 | |||
559 | vi4_channel_write(chan, vnc_id, FRAME_X, width); | ||
560 | vi4_channel_write(chan, vnc_id, FRAME_Y, height); | ||
561 | vi4_channel_write(chan, vnc_id, SKIP_X, 0x0); | ||
562 | vi4_channel_write(chan, vnc_id, CROP_X, width); | ||
563 | vi4_channel_write(chan, vnc_id, OUT_X, width); | ||
564 | vi4_channel_write(chan, vnc_id, SKIP_Y, 0x0); | ||
565 | vi4_channel_write(chan, vnc_id, CROP_Y, height); | ||
566 | vi4_channel_write(chan, vnc_id, OUT_Y, height); | ||
567 | vi4_channel_write(chan, vnc_id, PIXFMT_ENABLE, PIXFMT_EN); | ||
568 | vi4_channel_write(chan, vnc_id, PIXFMT_WIDE, 0x0); | ||
569 | vi4_channel_write(chan, vnc_id, PIXFMT_FORMAT, format); | ||
570 | vi4_channel_write(chan, vnc_id, DPCM_STRIP, 0x0); | ||
571 | vi4_channel_write(chan, vnc_id, ATOMP_DPCM_CHUNK, 0x0); | ||
572 | vi4_channel_write(chan, vnc_id, ISPBUFA, 0x0); | ||
573 | vi4_channel_write(chan, vnc_id, LINE_TIMER, 0x1000000); | ||
574 | vi4_channel_write(chan, vnc_id, EMBED_X, 0x0); | ||
575 | vi4_channel_write(chan, vnc_id, EMBED_Y, 0x0); | ||
576 | /* | ||
577 | * Set ATOMP_RESERVE to 0 so rctpu won't increment syncpt | ||
578 | * for captureInfo. This is copied from nvvi driver. | ||
579 | * | ||
580 | * If we don't set this register to 0, ATOMP_FE syncpt | ||
581 | * will be increment by 2 for each frame | ||
582 | */ | ||
583 | vi4_channel_write(chan, vnc_id, ATOMP_RESERVE, 0x0); | ||
584 | dev_dbg(chan->vi->dev, | ||
585 | "Create Surface with imgW=%d, imgH=%d, memFmt=%d\n", | ||
586 | width, height, format); | ||
587 | |||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | static int tegra_channel_capture_frame(struct tegra_channel *chan, | ||
592 | struct tegra_channel_buffer *buf) | ||
593 | { | ||
594 | struct vb2_v4l2_buffer *vb = &buf->buf; | ||
595 | struct timespec ts; | ||
596 | int state = VB2_BUF_STATE_DONE; | ||
597 | unsigned long flags; | ||
598 | int err = false; | ||
599 | int i; | ||
600 | |||
601 | for (i = 0; i < chan->valid_ports; i++) | ||
602 | tegra_channel_surface_setup(chan, buf, i); | ||
603 | |||
604 | if (!chan->bfirst_fstart) { | ||
605 | err = tegra_channel_set_stream(chan, true); | ||
606 | if (err < 0) | ||
607 | return err; | ||
608 | } | ||
609 | |||
610 | for (i = 0; i < chan->valid_ports; i++) { | ||
611 | vi4_channel_write(chan, chan->vnc_id[i], CHANNEL_COMMAND, LOAD); | ||
612 | vi4_channel_write(chan, chan->vnc_id[i], | ||
613 | CONTROL, SINGLESHOT | MATCH_STATE_EN); | ||
614 | } | ||
615 | |||
616 | /* wait for vi notifier events */ | ||
617 | vi_notify_wait(chan, &ts); | ||
618 | |||
619 | vi4_check_status(chan); | ||
620 | |||
621 | spin_lock_irqsave(&chan->capture_state_lock, flags); | ||
622 | if (chan->capture_state != CAPTURE_ERROR) | ||
623 | chan->capture_state = CAPTURE_GOOD; | ||
624 | spin_unlock_irqrestore(&chan->capture_state_lock, flags); | ||
625 | |||
626 | tegra_channel_ring_buffer(chan, vb, &ts, state); | ||
627 | |||
628 | return 0; | ||
629 | } | ||
630 | |||
631 | static int tegra_channel_stop_increments(struct tegra_channel *chan) | ||
632 | { | ||
633 | int i; | ||
634 | struct tegra_vi4_syncpts_req req = { | ||
635 | .syncpt_ids = { | ||
636 | 0xffffffff, | ||
637 | 0xffffffff, | ||
638 | 0xffffffff, | ||
639 | }, | ||
640 | .stream = chan->port[0], | ||
641 | .vc = 0, | ||
642 | }; | ||
643 | |||
644 | /* No need to check errors. There's nothing we could do. */ | ||
645 | for (i = 0; i < chan->valid_ports; i++) | ||
646 | vi_notify_channel_reset(chan->vnc_id[i], chan->vnc[i], &req); | ||
647 | |||
648 | return 0; | ||
649 | } | ||
650 | |||
651 | static void tegra_channel_capture_done(struct tegra_channel *chan) | ||
652 | { | ||
653 | struct timespec ts; | ||
654 | struct tegra_channel_buffer *buf; | ||
655 | int state = VB2_BUF_STATE_DONE; | ||
656 | u32 thresh[TEGRA_CSI_BLOCKS]; | ||
657 | int i, err; | ||
658 | |||
659 | /* dequeue buffer and return if no buffer exists */ | ||
660 | buf = dequeue_buffer(chan); | ||
661 | if (!buf) | ||
662 | return; | ||
663 | |||
664 | /* make sure to read the last frame out before exit */ | ||
665 | for (i = 0; i < chan->valid_ports; i++) { | ||
666 | tegra_channel_surface_setup(chan, buf, i); | ||
667 | vi4_channel_write(chan, chan->vnc_id[i], CHANNEL_COMMAND, LOAD); | ||
668 | vi4_channel_write(chan, chan->vnc_id[i], | ||
669 | CONTROL, SINGLESHOT | MATCH_STATE_EN); | ||
670 | } | ||
671 | |||
672 | for (i = 0; i < chan->valid_ports; i++) { | ||
673 | err = nvhost_syncpt_read_ext_check(chan->vi->ndev, | ||
674 | chan->syncpt[i][FE_SYNCPT_IDX], &thresh[i]); | ||
675 | /* Get current ATOMP_FE syncpt min value */ | ||
676 | if (!err) { | ||
677 | struct vi_capture_status status; | ||
678 | u32 index = thresh[i] + 1; | ||
679 | /* Wait for ATOMP_FE syncpt | ||
680 | * | ||
681 | * This is to make sure we don't exit the capture thread | ||
682 | * before the last frame is done writing to memory | ||
683 | */ | ||
684 | err = nvhost_syncpt_wait_timeout_ext(chan->vi->ndev, | ||
685 | chan->syncpt[i][FE_SYNCPT_IDX], | ||
686 | index, | ||
687 | 250, NULL, NULL); | ||
688 | if (unlikely(err)) | ||
689 | dev_err(chan->vi->dev, | ||
690 | "ATOMP_FE syncpt timeout!\n"); | ||
691 | else { | ||
692 | err = vi_notify_get_capture_status(chan->vnc[i], | ||
693 | chan->vnc_id[i], | ||
694 | index, &status); | ||
695 | if (unlikely(err)) | ||
696 | dev_err(chan->vi->dev, | ||
697 | "no capture status! err = %d\n", | ||
698 | err); | ||
699 | else | ||
700 | ts = ns_to_timespec((s64)status.eof_ts); | ||
701 | } | ||
702 | } | ||
703 | } | ||
704 | |||
705 | /* Mark capture state to IDLE as capture is finished */ | ||
706 | chan->capture_state = CAPTURE_IDLE; | ||
707 | |||
708 | tegra_channel_ring_buffer(chan, &buf->buf, &ts, state); | ||
709 | } | ||
710 | |||
711 | static int tegra_channel_kthread_capture_start(void *data) | ||
712 | { | ||
713 | struct tegra_channel *chan = data; | ||
714 | struct tegra_channel_buffer *buf; | ||
715 | int err = 0; | ||
716 | |||
717 | set_freezable(); | ||
718 | |||
719 | while (1) { | ||
720 | |||
721 | try_to_freeze(); | ||
722 | |||
723 | wait_event_interruptible(chan->start_wait, | ||
724 | !list_empty(&chan->capture) || | ||
725 | kthread_should_stop()); | ||
726 | |||
727 | if (kthread_should_stop()) | ||
728 | break; | ||
729 | |||
730 | /* source is not streaming if error is non-zero */ | ||
731 | /* wait till kthread stop and dont DeQ buffers */ | ||
732 | if (err) | ||
733 | continue; | ||
734 | |||
735 | buf = dequeue_buffer(chan); | ||
736 | if (!buf) | ||
737 | continue; | ||
738 | |||
739 | err = tegra_channel_capture_frame(chan, buf); | ||
740 | } | ||
741 | |||
742 | return 0; | ||
743 | } | ||
744 | |||
745 | static void tegra_channel_stop_kthreads(struct tegra_channel *chan) | ||
746 | { | ||
747 | mutex_lock(&chan->stop_kthread_lock); | ||
748 | /* Stop the kthread for capture */ | ||
749 | if (chan->kthread_capture_start) { | ||
750 | kthread_stop(chan->kthread_capture_start); | ||
751 | chan->kthread_capture_start = NULL; | ||
752 | } | ||
753 | mutex_unlock(&chan->stop_kthread_lock); | ||
754 | } | ||
755 | |||
756 | static int tegra_channel_update_clknbw(struct tegra_channel *chan, u8 on) | ||
757 | { | ||
758 | int ret = 0; | ||
759 | unsigned long request_pixelrate; | ||
760 | struct v4l2_subdev_frame_interval fie; | ||
761 | unsigned long csi_freq = 0; | ||
762 | |||
763 | fie.interval.denominator = DEFAULT_FRAMERATE; | ||
764 | fie.interval.numerator = 1; | ||
765 | |||
766 | if (v4l2_subdev_has_op(chan->subdev_on_csi, | ||
767 | video, g_frame_interval)) | ||
768 | v4l2_subdev_call(chan->subdev_on_csi, video, | ||
769 | g_frame_interval, &fie); | ||
770 | if (on) { | ||
771 | /* for PG, using default frequence */ | ||
772 | if (chan->pg_mode) { | ||
773 | csi_freq = DEFAULT_CSI_FREQ; | ||
774 | request_pixelrate = csi_freq * NUM_PPC; | ||
775 | } else { | ||
776 | /** | ||
777 | * TODO: use real sensor pixelrate | ||
778 | * See PowerService code | ||
779 | */ | ||
780 | request_pixelrate = (long long)(chan->format.width | ||
781 | * chan->format.height | ||
782 | * fie.interval.denominator / 100) | ||
783 | * VI_CSI_CLK_SCALE; | ||
784 | csi_freq = ((long long)chan->format.width | ||
785 | * chan->format.height | ||
786 | * fie.interval.denominator) / NUM_PPC; | ||
787 | } | ||
788 | |||
789 | /* VI clk should be slightly faster than CSI clk*/ | ||
790 | ret = nvhost_module_set_rate(chan->vi->ndev, &chan->video, | ||
791 | request_pixelrate, 0, NVHOST_PIXELRATE); | ||
792 | if (ret) { | ||
793 | dev_err(chan->vi->dev, "Fail to update vi clk\n"); | ||
794 | return ret; | ||
795 | } | ||
796 | } else { | ||
797 | csi_freq = DEFAULT_CSI_FREQ; | ||
798 | ret = nvhost_module_set_rate(chan->vi->ndev, &chan->video, 0, 0, | ||
799 | NVHOST_PIXELRATE); | ||
800 | if (ret) { | ||
801 | dev_err(chan->vi->dev, "Fail to update vi clk\n"); | ||
802 | return ret; | ||
803 | } | ||
804 | } | ||
805 | if (chan->pg_mode) | ||
806 | chan->requested_kbyteps = (on > 0 ? 1 : -1) * | ||
807 | ((long long)csi_freq * BPP_MEM * 110 / 100) / 1000; | ||
808 | else | ||
809 | chan->requested_kbyteps = (on > 0 ? 1 : -1) * | ||
810 | (((long long) chan->format.width * chan->format.height | ||
811 | * fie.interval.denominator * BPP_MEM) * 115 / 100) / 1000; | ||
812 | |||
813 | mutex_lock(&chan->vi->bw_update_lock); | ||
814 | chan->vi->aggregated_kbyteps += chan->requested_kbyteps; | ||
815 | ret = vi_v4l2_update_isobw(chan->vi->aggregated_kbyteps, 0); | ||
816 | mutex_unlock(&chan->vi->bw_update_lock); | ||
817 | if (ret) | ||
818 | dev_info(chan->vi->dev, | ||
819 | "WAR:Calculation not precise.Ignore BW request failure\n"); | ||
820 | ret = vi4_v4l2_set_la(chan->vi->ndev, 0, 0); | ||
821 | if (ret) | ||
822 | dev_info(chan->vi->dev, | ||
823 | "WAR:Calculation not precise.Ignore LA failure\n"); | ||
824 | return 0; | ||
825 | } | ||
826 | |||
827 | int vi4_channel_start_streaming(struct vb2_queue *vq, u32 count) | ||
828 | { | ||
829 | struct tegra_channel *chan = vb2_get_drv_priv(vq); | ||
830 | struct media_pipeline *pipe = chan->video.entity.pipe; | ||
831 | int ret = 0, i; | ||
832 | unsigned long flags; | ||
833 | struct v4l2_ctrl *override_ctrl; | ||
834 | |||
835 | vi4_init(chan); | ||
836 | ret = media_entity_pipeline_start(&chan->video.entity, pipe); | ||
837 | if (ret < 0) | ||
838 | goto error_pipeline_start; | ||
839 | |||
840 | if (chan->bypass) { | ||
841 | ret = tegra_channel_set_stream(chan, true); | ||
842 | if (ret < 0) | ||
843 | goto error_set_stream; | ||
844 | return ret; | ||
845 | } | ||
846 | |||
847 | spin_lock_irqsave(&chan->capture_state_lock, flags); | ||
848 | chan->capture_state = CAPTURE_IDLE; | ||
849 | spin_unlock_irqrestore(&chan->capture_state_lock, flags); | ||
850 | |||
851 | for (i = 0; i < chan->valid_ports; i++) { | ||
852 | ret = tegra_channel_capture_setup(chan, i); | ||
853 | if (ret < 0) | ||
854 | goto error_capture_setup; | ||
855 | } | ||
856 | |||
857 | chan->sequence = 0; | ||
858 | tegra_channel_init_ring_buffer(chan); | ||
859 | |||
860 | /* disable override for vi mode */ | ||
861 | override_ctrl = v4l2_ctrl_find( | ||
862 | &chan->ctrl_handler, V4L2_CID_OVERRIDE_ENABLE); | ||
863 | if (!chan->pg_mode) { | ||
864 | if (override_ctrl) { | ||
865 | ret = v4l2_ctrl_s_ctrl(override_ctrl, false); | ||
866 | if (ret < 0) | ||
867 | dev_err(&chan->video.dev, | ||
868 | "failed to disable override control\n"); | ||
869 | } else | ||
870 | dev_err(&chan->video.dev, | ||
871 | "No override control\n"); | ||
872 | } | ||
873 | |||
874 | /* Update clock and bandwidth based on the format */ | ||
875 | ret = tegra_channel_update_clknbw(chan, 1); | ||
876 | if (ret) | ||
877 | goto error_capture_setup; | ||
878 | |||
879 | INIT_WORK(&chan->error_work, tegra_channel_error_worker); | ||
880 | INIT_WORK(&chan->status_work, tegra_channel_status_worker); | ||
881 | |||
882 | /* Start kthread to capture data to buffer */ | ||
883 | chan->kthread_capture_start = kthread_run( | ||
884 | tegra_channel_kthread_capture_start, | ||
885 | chan, chan->video.name); | ||
886 | if (IS_ERR(chan->kthread_capture_start)) { | ||
887 | dev_err(&chan->video.dev, | ||
888 | "failed to run kthread for capture start\n"); | ||
889 | ret = PTR_ERR(chan->kthread_capture_start); | ||
890 | goto error_capture_setup; | ||
891 | } | ||
892 | |||
893 | return 0; | ||
894 | |||
895 | error_capture_setup: | ||
896 | if (!chan->pg_mode) | ||
897 | tegra_channel_set_stream(chan, false); | ||
898 | error_set_stream: | ||
899 | media_entity_pipeline_stop(&chan->video.entity); | ||
900 | error_pipeline_start: | ||
901 | vq->start_streaming_called = 0; | ||
902 | tegra_channel_queued_buf_done(chan, VB2_BUF_STATE_QUEUED); | ||
903 | |||
904 | return ret; | ||
905 | } | ||
906 | |||
907 | int vi4_channel_stop_streaming(struct vb2_queue *vq) | ||
908 | { | ||
909 | struct tegra_channel *chan = vb2_get_drv_priv(vq); | ||
910 | bool is_streaming = atomic_read(&chan->is_streaming); | ||
911 | int i; | ||
912 | |||
913 | for (i = 0; i < chan->valid_ports; i++) { | ||
914 | if (chan->vnc_id[i] == -1) | ||
915 | return 0; | ||
916 | } | ||
917 | |||
918 | cancel_work_sync(&chan->status_work); | ||
919 | cancel_work_sync(&chan->error_work); | ||
920 | |||
921 | if (!chan->bypass) { | ||
922 | tegra_channel_stop_kthreads(chan); | ||
923 | /* wait for last frame memory write ack */ | ||
924 | if (is_streaming) | ||
925 | tegra_channel_capture_done(chan); | ||
926 | for (i = 0; i < chan->valid_ports; i++) | ||
927 | tegra_channel_notify_disable(chan, i); | ||
928 | /* free all the ring buffers */ | ||
929 | free_ring_buffers(chan, chan->num_buffers); | ||
930 | /* dequeue buffers back to app which are in capture queue */ | ||
931 | tegra_channel_queued_buf_done(chan, VB2_BUF_STATE_ERROR); | ||
932 | } | ||
933 | |||
934 | tegra_channel_set_stream(chan, false); | ||
935 | media_entity_pipeline_stop(&chan->video.entity); | ||
936 | |||
937 | if (!chan->bypass) | ||
938 | tegra_channel_update_clknbw(chan, 0); | ||
939 | |||
940 | return 0; | ||
941 | } | ||
942 | |||
943 | int tegra_vi4_power_on(struct tegra_mc_vi *vi) | ||
944 | { | ||
945 | int ret; | ||
946 | |||
947 | ret = nvhost_module_busy(vi->ndev); | ||
948 | if (ret) { | ||
949 | dev_err(vi->dev, "%s:nvhost module is busy\n", __func__); | ||
950 | return ret; | ||
951 | } | ||
952 | |||
953 | ret = tegra_camera_emc_clk_enable(); | ||
954 | if (ret) | ||
955 | goto err_emc_enable; | ||
956 | |||
957 | return 0; | ||
958 | |||
959 | err_emc_enable: | ||
960 | nvhost_module_idle(vi->ndev); | ||
961 | |||
962 | return ret; | ||
963 | } | ||
964 | |||
965 | void tegra_vi4_power_off(struct tegra_mc_vi *vi) | ||
966 | { | ||
967 | tegra_channel_ec_close(vi); | ||
968 | tegra_camera_emc_clk_disable(); | ||
969 | nvhost_module_idle(vi->ndev); | ||
970 | } | ||
971 | |||
972 | int vi4_power_on(struct tegra_channel *chan) | ||
973 | { | ||
974 | int ret = 0; | ||
975 | struct tegra_mc_vi *vi; | ||
976 | struct tegra_csi_device *csi; | ||
977 | |||
978 | vi = chan->vi; | ||
979 | csi = vi->csi; | ||
980 | |||
981 | /* Use chan->video as identifier of vi4 nvhost_module client | ||
982 | * since they are unique per channel | ||
983 | */ | ||
984 | ret = nvhost_module_add_client(vi->ndev, &chan->video); | ||
985 | if (ret < 0) | ||
986 | return ret; | ||
987 | |||
988 | ret = tegra_vi4_power_on(vi); | ||
989 | if (ret < 0) | ||
990 | return ret; | ||
991 | |||
992 | if (atomic_add_return(1, &chan->power_on_refcnt) == 1) { | ||
993 | ret = tegra_channel_set_power(chan, 1); | ||
994 | if (ret < 0) { | ||
995 | dev_err(vi->dev, "Failed to power on subdevices\n"); | ||
996 | return ret; | ||
997 | } | ||
998 | } | ||
999 | |||
1000 | #if defined(CONFIG_TEGRA_CAMERA_RTCPU) | ||
1001 | ret = vi_capture_init(chan); | ||
1002 | if (ret < 0) | ||
1003 | return ret; | ||
1004 | #endif | ||
1005 | |||
1006 | return 0; | ||
1007 | } | ||
1008 | |||
1009 | void vi4_power_off(struct tegra_channel *chan) | ||
1010 | { | ||
1011 | int ret = 0; | ||
1012 | struct tegra_mc_vi *vi; | ||
1013 | struct tegra_csi_device *csi; | ||
1014 | |||
1015 | vi = chan->vi; | ||
1016 | csi = vi->csi; | ||
1017 | |||
1018 | #if defined(CONFIG_TEGRA_CAMERA_RTCPU) | ||
1019 | vi_capture_shutdown(chan); | ||
1020 | #endif | ||
1021 | |||
1022 | if (atomic_dec_and_test(&chan->power_on_refcnt)) { | ||
1023 | ret = tegra_channel_set_power(chan, 0); | ||
1024 | if (ret < 0) | ||
1025 | dev_err(vi->dev, "Failed to power off subdevices\n"); | ||
1026 | } | ||
1027 | |||
1028 | tegra_vi4_power_off(vi); | ||
1029 | nvhost_module_remove_client(vi->ndev, &chan->video); | ||
1030 | } | ||
1031 | |||
1032 | static void tegra_channel_error_worker(struct work_struct *error_work) | ||
1033 | { | ||
1034 | struct tegra_channel *chan; | ||
1035 | |||
1036 | chan = container_of(error_work, struct tegra_channel, error_work); | ||
1037 | |||
1038 | vi4_power_off(chan); | ||
1039 | tegra_channel_handle_error(chan); | ||
1040 | } | ||
1041 | |||
1042 | static void tegra_channel_notify_error_callback(void *client_data) | ||
1043 | { | ||
1044 | struct tegra_channel *chan = (struct tegra_channel *)client_data; | ||
1045 | |||
1046 | spin_lock(&chan->capture_state_lock); | ||
1047 | if (chan->capture_state == CAPTURE_GOOD) | ||
1048 | chan->capture_state = CAPTURE_ERROR; | ||
1049 | else { | ||
1050 | spin_unlock(&chan->capture_state_lock); | ||
1051 | return; | ||
1052 | } | ||
1053 | spin_unlock(&chan->capture_state_lock); | ||
1054 | |||
1055 | schedule_work(&chan->error_work); | ||
1056 | } | ||
diff --git a/drivers/media/platform/tegra/camera/vi/vi4_fops.h b/drivers/media/platform/tegra/camera/vi/vi4_fops.h new file mode 100644 index 000000000..4f48aca8d --- /dev/null +++ b/drivers/media/platform/tegra/camera/vi/vi4_fops.h | |||
@@ -0,0 +1,37 @@ | |||
1 | /* | ||
2 | * Tegra Video Input 4 device common APIs | ||
3 | * | ||
4 | * Tegra Graphics Host VI | ||
5 | * | ||
6 | * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. | ||
7 | * | ||
8 | * Author: Frank Chen <frankc@nvidia.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #ifndef __T186_VI_H__ | ||
16 | #define __T186_VI_H__ | ||
17 | |||
18 | int vi4_power_on(struct tegra_channel *chan); | ||
19 | void vi4_power_off(struct tegra_channel *chan); | ||
20 | int vi4_channel_start_streaming(struct vb2_queue *vq, u32 count); | ||
21 | int vi4_channel_stop_streaming(struct vb2_queue *vq); | ||
22 | int vi4_add_ctrls(struct tegra_channel *chan); | ||
23 | void vi4_init_video_formats(struct tegra_channel *chan); | ||
24 | long vi4_default_ioctl(struct file *file, void *fh, | ||
25 | bool use_prio, unsigned int cmd, void *arg); | ||
26 | |||
27 | struct tegra_vi_fops vi4_fops = { | ||
28 | .vi_power_on = vi4_power_on, | ||
29 | .vi_power_off = vi4_power_off, | ||
30 | .vi_start_streaming = vi4_channel_start_streaming, | ||
31 | .vi_stop_streaming = vi4_channel_stop_streaming, | ||
32 | .vi_add_ctrls = vi4_add_ctrls, | ||
33 | .vi_init_video_formats = vi4_init_video_formats, | ||
34 | .vi_default_ioctl = vi4_default_ioctl, | ||
35 | }; | ||
36 | |||
37 | #endif | ||
diff --git a/drivers/media/platform/tegra/camera/vi/vi4_formats.h b/drivers/media/platform/tegra/camera/vi/vi4_formats.h new file mode 100644 index 000000000..bbdbbab71 --- /dev/null +++ b/drivers/media/platform/tegra/camera/vi/vi4_formats.h | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * NVIDIA Tegra Video Input Device Driver VI4 formats | ||
3 | * | ||
4 | * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * Author: Bhanu Murthy V <bmurthyv@nvidia.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef __VI4_FORMATS_H_ | ||
14 | #define __VI4_FORMATS_H_ | ||
15 | |||
16 | #include "camera/vi/core.h" | ||
17 | |||
18 | /* | ||
19 | * These go into the VI_CHn_PIXFMT_FORMAT register bits 7:0 | ||
20 | * Output pixel memory format for the VI channel. | ||
21 | */ | ||
22 | enum tegra_image_format { | ||
23 | TEGRA_IMAGE_FORMAT_T_L8 = 16, | ||
24 | |||
25 | TEGRA_IMAGE_FORMAT_T_R16_I = 32, | ||
26 | TEGRA_IMAGE_FORMAT_T_B5G6R5, | ||
27 | TEGRA_IMAGE_FORMAT_T_R5G6B5, | ||
28 | TEGRA_IMAGE_FORMAT_T_A1B5G5R5, | ||
29 | TEGRA_IMAGE_FORMAT_T_A1R5G5B5, | ||
30 | TEGRA_IMAGE_FORMAT_T_B5G5R5A1, | ||
31 | TEGRA_IMAGE_FORMAT_T_R5G5B5A1, | ||
32 | TEGRA_IMAGE_FORMAT_T_A4B4G4R4, | ||
33 | TEGRA_IMAGE_FORMAT_T_A4R4G4B4, | ||
34 | TEGRA_IMAGE_FORMAT_T_B4G4R4A4, | ||
35 | TEGRA_IMAGE_FORMAT_T_R4G4B4A4, | ||
36 | |||
37 | TEGRA_IMAGE_FORMAT_T_A8B8G8R8 = 64, | ||
38 | TEGRA_IMAGE_FORMAT_T_A8R8G8B8, | ||
39 | TEGRA_IMAGE_FORMAT_T_B8G8R8A8, | ||
40 | TEGRA_IMAGE_FORMAT_T_R8G8B8A8, | ||
41 | TEGRA_IMAGE_FORMAT_T_A2B10G10R10, | ||
42 | TEGRA_IMAGE_FORMAT_T_A2R10G10B10, | ||
43 | TEGRA_IMAGE_FORMAT_T_B10G10R10A2, | ||
44 | TEGRA_IMAGE_FORMAT_T_R10G10B10A2, | ||
45 | |||
46 | TEGRA_IMAGE_FORMAT_T_A8Y8U8V8 = 193, | ||
47 | TEGRA_IMAGE_FORMAT_T_V8U8Y8A8, | ||
48 | |||
49 | TEGRA_IMAGE_FORMAT_T_A2Y10U10V10 = 197, | ||
50 | TEGRA_IMAGE_FORMAT_T_V10U10Y10A2, | ||
51 | |||
52 | TEGRA_IMAGE_FORMAT_T_Y8_U8__Y8_V8 = 200, | ||
53 | TEGRA_IMAGE_FORMAT_T_Y8_V8__Y8_U8, | ||
54 | |||
55 | TEGRA_IMAGE_FORMAT_T_U8_Y8__V8_Y8 = 203, | ||
56 | |||
57 | TEGRA_IMAGE_FORMAT_T_T_V8_Y8__U8_Y8 = 223, | ||
58 | TEGRA_IMAGE_FORMAT_T_T_Y8__U8__V8_N444, | ||
59 | TEGRA_IMAGE_FORMAT_T_Y8__U8V8_N444, | ||
60 | TEGRA_IMAGE_FORMAT_T_Y8__V8U8_N444, | ||
61 | TEGRA_IMAGE_FORMAT_T_Y8__U8__V8_N422, | ||
62 | TEGRA_IMAGE_FORMAT_T_Y8__U8V8_N422, | ||
63 | TEGRA_IMAGE_FORMAT_T_Y8__V8U8_N422, | ||
64 | TEGRA_IMAGE_FORMAT_T_Y8__U8__V8_N420, | ||
65 | TEGRA_IMAGE_FORMAT_T_Y8__U8V8_N420, | ||
66 | TEGRA_IMAGE_FORMAT_T_Y8__V8U8_N420, | ||
67 | |||
68 | TEGRA_IMAGE_FORMAT_T_Y10__U10__V10_N422 = 240, | ||
69 | TEGRA_IMAGE_FORMAT_T_Y10__U10V10_N422, | ||
70 | TEGRA_IMAGE_FORMAT_T_Y10__V10U10_N422, | ||
71 | TEGRA_IMAGE_FORMAT_T_Y10__U10__V10_N420, | ||
72 | TEGRA_IMAGE_FORMAT_T_Y10__U10V10_N420, | ||
73 | TEGRA_IMAGE_FORMAT_T_Y10__V10U10_N420, | ||
74 | |||
75 | TEGRA_IMAGE_FORMAT_T_R16 = 248, | ||
76 | TEGRA_IMAGE_FORMAT_T_R32, | ||
77 | TEGRA_IMAGE_FORMAT_T_L16_F, | ||
78 | TEGRA_IMAGE_FORMAT_T_L32_F, | ||
79 | |||
80 | TEGRA_IMAGE_FORMAT_T_DPCM_RAW10 = 254, | ||
81 | TEGRA_IMAGE_FORMAT_T_DPCM_RAW12, | ||
82 | }; | ||
83 | |||
84 | static const struct tegra_video_format vi4_video_formats[] = { | ||
85 | /* RAW 6: TODO */ | ||
86 | |||
87 | /* RAW 7: TODO */ | ||
88 | |||
89 | /* RAW 8 */ | ||
90 | TEGRA_VIDEO_FORMAT(RAW8, 8, SRGGB8_1X8, 1, 1, T_L8, | ||
91 | RAW8, SRGGB8, "RGRG.. GBGB.."), | ||
92 | TEGRA_VIDEO_FORMAT(RAW8, 8, SGRBG8_1X8, 1, 1, T_L8, | ||
93 | RAW8, SGRBG8, "GRGR.. BGBG.."), | ||
94 | TEGRA_VIDEO_FORMAT(RAW8, 8, SGBRG8_1X8, 1, 1, T_L8, | ||
95 | RAW8, SGBRG8, "GBGB.. RGRG.."), | ||
96 | TEGRA_VIDEO_FORMAT(RAW8, 8, SBGGR8_1X8, 1, 1, T_L8, | ||
97 | RAW8, SBGGR8, "BGBG.. GRGR.."), | ||
98 | |||
99 | /* RAW 10 */ | ||
100 | TEGRA_VIDEO_FORMAT(RAW10, 10, SRGGB10_1X10, 2, 1, T_R16_I, | ||
101 | RAW10, SRGGB10, "RGRG.. GBGB.."), | ||
102 | TEGRA_VIDEO_FORMAT(RAW10, 10, SGRBG10_1X10, 2, 1, T_R16_I, | ||
103 | RAW10, SGRBG10, "GRGR.. BGBG.."), | ||
104 | TEGRA_VIDEO_FORMAT(RAW10, 10, SGBRG10_1X10, 2, 1, T_R16_I, | ||
105 | RAW10, SGBRG10, "GBGB.. RGRG.."), | ||
106 | TEGRA_VIDEO_FORMAT(RAW10, 10, SBGGR10_1X10, 2, 1, T_R16_I, | ||
107 | RAW10, SBGGR10, "BGBG.. GRGR.."), | ||
108 | |||
109 | /* RAW 12 */ | ||
110 | TEGRA_VIDEO_FORMAT(RAW12, 12, SRGGB12_1X12, 2, 1, T_R16_I, | ||
111 | RAW12, SRGGB12, "RGRG.. GBGB.."), | ||
112 | TEGRA_VIDEO_FORMAT(RAW12, 12, SGRBG12_1X12, 2, 1, T_R16_I, | ||
113 | RAW12, SGRBG12, "GRGR.. BGBG.."), | ||
114 | TEGRA_VIDEO_FORMAT(RAW12, 12, SGBRG12_1X12, 2, 1, T_R16_I, | ||
115 | RAW12, SGBRG12, "GBGB.. RGRG.."), | ||
116 | TEGRA_VIDEO_FORMAT(RAW12, 12, SBGGR12_1X12, 2, 1, T_R16_I, | ||
117 | RAW12, SBGGR12, "BGBG.. GRGR.."), | ||
118 | |||
119 | /* RGB888 */ | ||
120 | TEGRA_VIDEO_FORMAT(RGB888, 24, RGB888_1X24, 4, 1, T_A8R8G8B8, | ||
121 | RGB888, ABGR32, "BGRA-8-8-8-8"), | ||
122 | TEGRA_VIDEO_FORMAT(RGB888, 24, RGB888_1X32_PADHI, 4, 1, T_A8B8G8R8, | ||
123 | RGB888, RGB32, "RGB-8-8-8-8"), | ||
124 | |||
125 | /* YUV422 */ | ||
126 | TEGRA_VIDEO_FORMAT(YUV422, 16, UYVY8_1X16, 2, 1, T_U8_Y8__V8_Y8, | ||
127 | YUV422_8, UYVY, "YUV 4:2:2"), | ||
128 | TEGRA_VIDEO_FORMAT(YUV422, 16, UYVY8_1X16, 1, 1, T_Y8__V8U8_N422, | ||
129 | YUV422_8, NV16, "NV16"), | ||
130 | TEGRA_VIDEO_FORMAT(YUV422, 16, UYVY8_2X8, 2, 1, T_U8_Y8__V8_Y8, | ||
131 | YUV422_8, UYVY, "YUV 4:2:2 UYVY"), | ||
132 | TEGRA_VIDEO_FORMAT(YUV422, 16, VYUY8_2X8, 2, 1, T_T_V8_Y8__U8_Y8, | ||
133 | YUV422_8, VYUY, "YUV 4:2:2 VYUY"), | ||
134 | TEGRA_VIDEO_FORMAT(YUV422, 16, YUYV8_2X8, 2, 1, T_Y8_U8__Y8_V8, | ||
135 | YUV422_8, YUYV, "YUV 4:2:2 YUYV"), | ||
136 | TEGRA_VIDEO_FORMAT(YUV422, 16, YVYU8_2X8, 2, 1, T_Y8_V8__Y8_U8, | ||
137 | YUV422_8, YVYU, "YUV 4:2:2 YVYU"), | ||
138 | }; | ||
139 | |||
140 | #endif | ||
diff --git a/drivers/media/platform/tegra/camera/vi/vi4_registers.h b/drivers/media/platform/tegra/camera/vi/vi4_registers.h new file mode 100644 index 000000000..588ebb324 --- /dev/null +++ b/drivers/media/platform/tegra/camera/vi/vi4_registers.h | |||
@@ -0,0 +1,272 @@ | |||
1 | /* | ||
2 | * drivers/media/platform/tegra/camera/vi/vi4_registers.h | ||
3 | * | ||
4 | * Tegra 18x VI register offsets | ||
5 | * | ||
6 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms and conditions of the GNU General Public License, | ||
10 | * version 2, as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | #ifndef __VI4_REGISTERS_H__ | ||
22 | #define __VI4_REGISTERS_H__ | ||
23 | |||
24 | /* VI registers. Start from 0x0 */ | ||
25 | #define VI_STREAMS (6) | ||
26 | #define VIRTUAL_CHANNELS (4) | ||
27 | #define VI4_CHANNEL_OFFSET 0x10000 | ||
28 | |||
29 | #define CFG_INTERRUPT_STATUS 0x44 | ||
30 | #define CFG_INTERRUPT_MASK 0x48 | ||
31 | #define VGP6_INT_MASK (0x1 << 29) | ||
32 | #define VGP5_INT_MASK (0x1 << 28) | ||
33 | #define VGP4_INT_MASK (0x1 << 27) | ||
34 | #define VGP3_INT_MASK (0x1 << 26) | ||
35 | #define VGP2_INT_MASK (0x1 << 25) | ||
36 | #define VGP1_INT_MASK (0x1 << 24) | ||
37 | #define HOST_PKTINJECT_STALL_ERR_MASK (0x1 << 7) | ||
38 | #define CSIMUX_FIFO_OVFL_ERR_MASK (0x1 << 6) | ||
39 | #define ATOMP_PACKER_OVFL_ERR_MASK (0x1 << 5) | ||
40 | #define FMLITE_BUF_OVFL_ERR_MASK (0x1 << 4) | ||
41 | #define NOTIFY_FIFO_OVFL_ERR_MASK (0x1 << 3) | ||
42 | #define ISPBUFA_ERR_MASK (0x1 << 0) | ||
43 | |||
44 | #define CFG_PWM_HIGH_PULSE 0x50 | ||
45 | #define PWM_HIGH_PULSE (0xffffffff << 0) | ||
46 | |||
47 | #define CSIMUX_CONFIG_STREAM_0 0x424 | ||
48 | #define CSIMUX_CONFIG_STREAM_1 0x428 | ||
49 | #define CSIMUX_CONFIG_STREAM_2 0x42C | ||
50 | #define CSIMUX_CONFIG_STREAM_3 0x430 | ||
51 | #define CSIMUX_CONFIG_STREAM_4 0x434 | ||
52 | #define CSIMUX_CONFIG_STREAM_5 0x438 | ||
53 | #define FRAMEIDGEN (0xf << 26) | ||
54 | #define STICKYFAULT (0x1 << 25) | ||
55 | #define VPR (0x1 << 24) | ||
56 | #define SRESET (0x1 << 23) | ||
57 | #define QBLOCK (0x1 << 22) | ||
58 | #define FEINJECT (0x1 << 21) | ||
59 | #define FESHORTTIMER (0x1 << 20) | ||
60 | #define FEMAXTIME (0xffff << 4) | ||
61 | #define WT (0xf << 0) | ||
62 | |||
63 | #define NOTIFY_FIFO_TAG_0 0x4000 | ||
64 | #define NOTIFY_FRAME_ID (0xffff << 16) | ||
65 | #define NOTIFY_CHANNEL (0xff << 8) | ||
66 | #define NOTIFY_CHANNEL_SHIFT (8) | ||
67 | #define NOTIFY_TAG (0x1f << 1) | ||
68 | #define NOTIFY_TAG_SHIFT (1) | ||
69 | #define NOTIFY_VALID (0x1 << 0) | ||
70 | |||
71 | #define TAG_FS 0 | ||
72 | #define TAG_FE 1 | ||
73 | #define TAG_CSIMUX_FRAME 2 | ||
74 | #define TAG_CSIMUX_STREAM 3 | ||
75 | #define TAG_CHANSEL_PXL_SOF 4 | ||
76 | #define TAG_CHANSEL_PXL_EOF 5 | ||
77 | #define TAG_CHANSEL_EMBED_SOF 6 | ||
78 | #define TAG_CHANSEL_EMBED_EOF 7 | ||
79 | #define TAG_CHANSEL_NLINES 8 | ||
80 | #define TAG_CHANSEL_FAULT 9 | ||
81 | #define TAG_CHANSEL_FAULT_FE 10 | ||
82 | #define TAG_CHANSEL_NOMATCH 11 | ||
83 | #define TAG_CHANSEL_COLLISION 12 | ||
84 | #define TAG_CHANSEL_SHORT_FRAME 13 | ||
85 | #define TAG_CHANSEL_LOAD_FRAMED 14 | ||
86 | #define TAG_ATOMP_PACKER_OVERFLOW 15 | ||
87 | #define TAG_ATOMP_FS 16 | ||
88 | #define TAG_ATOMP_FE 17 | ||
89 | #define TAG_ATOMP_FRAME_DONE 18 | ||
90 | #define TAG_ATOMP_EMB_DATA_DONE 19 | ||
91 | #define TAG_ATOMP_FRAME_NLINES_DONE 20 | ||
92 | #define TAG_ATOMP_FRAME_TRUNCATED 21 | ||
93 | #define TAG_ATOMP_FRAME_TOSSED 22 | ||
94 | #define TAG_ATOMP_PDAF_DATA_DONE 23 | ||
95 | #define TAG_ISPBUF_FIFO_OVERFLOW 26 | ||
96 | #define TAG_ISPBUF_FS 27 | ||
97 | #define TAG_ISPBUF_FE 28 | ||
98 | #define TAG_VGP0_DONE 29 | ||
99 | #define TAG_VGP1_DONE 30 | ||
100 | #define TAG_FMLITE_DONE 31 | ||
101 | |||
102 | #define NOTIFY_FIFO_TIMESTAMP_0 0x4004 | ||
103 | #define NOTIFY_TIMESTAMP (0xffffffff << 0) | ||
104 | |||
105 | #define NOTIFY_FIFO_DATA_0 0x4008 | ||
106 | #define NOTIFY_DATA (0xffffffff << 0) | ||
107 | |||
108 | #define NOTIFY_TAG_CLASSIFY_0 0x6000 | ||
109 | #define NOTIFY_TAG_CLASSIFY_1 0x6004 | ||
110 | #define NOTIFY_TAG_CLASSIFY_2 0x6008 | ||
111 | #define NOTIFY_TAG_CLASSIFY_3 0x600c | ||
112 | #define NOTIFY_TAG_CLASSIFY_4 0x6010 | ||
113 | #define STREAM5_FEINJECT_VC (0xf << 20) | ||
114 | #define STREAM4_FEINJECT_VC (0xf << 16) | ||
115 | #define STREAM3_FEINJECT_VC (0xf << 12) | ||
116 | #define STREAM2_FEINJECT_VC (0xf << 8) | ||
117 | #define STREAM1_FEINJECT_VC (0xf << 4) | ||
118 | #define STREAM0_FEINJECT_VC (0xf << 0) | ||
119 | |||
120 | #define NOTIFY_FIFO_OCCUPANCY_0 0x6014 | ||
121 | #define NOTIFY_MAX (0x3ff << 20) | ||
122 | #define NOTIFY_CURRENT (0x3ff << 10) | ||
123 | #define NOTIFY_CURRENT_SHIFT 10 | ||
124 | #define NOTIFY_SIZE (0x3ff << 0) | ||
125 | |||
126 | /* VI_CH registers. Start from 0x10000, offset 0x10000 */ | ||
127 | #define CHANNEL_COMMAND 0x004 | ||
128 | #define WR_ACT_SEL (0x1 << 5) | ||
129 | #define RD_MUX_SEL (0x1 << 4) | ||
130 | #define AUTOLOAD (0x1 << 1) | ||
131 | #define LOAD (0x1 << 0) | ||
132 | |||
133 | #define CONTROL 0x01c | ||
134 | #define SPARE (0xffff << 16) | ||
135 | #define POST_RUNAWAY_EMBED (0x1 << 4) | ||
136 | #define POST_RUNAWAY_PIXEL (0x1 << 3) | ||
137 | #define EARLY_ABORT (0x1 << 2) | ||
138 | #define SINGLESHOT (0x1 << 1) | ||
139 | #define MATCH_STATE_EN (0x1 << 0) | ||
140 | |||
141 | #define MATCH 0x020 | ||
142 | #define STREAM (0x3f << 14) | ||
143 | #define STREAM_SHIFT (14) | ||
144 | #define STREAM_MASK (0x3f << 8) | ||
145 | #define VIRTUAL_CHANNEL (0xf << 4) | ||
146 | #define VIRTUAL_CHANNEL_SHIFT (4) | ||
147 | #define VIRTUAL_CHANNEL_MASK (0xf << 0) | ||
148 | |||
149 | #define MATCH_DATATYPE 0x024 | ||
150 | #define DATATYPE (0x3f << 6) | ||
151 | #define DATATYPE_SHIFT (6) | ||
152 | #define DATATYPE_MASK (0x3f << 0) | ||
153 | #define DATATYPE_MASK_SHIFT (0) | ||
154 | |||
155 | #define MATCH_FRAMEID 0x028 | ||
156 | #define FRAMEID (0xffff << 16) | ||
157 | #define FRAMEID_SHIFT (16) | ||
158 | #define FRAMEID_MASK (0xffff << 0) | ||
159 | |||
160 | #define DT_OVERRIDE 0x02c | ||
161 | #define OVRD_DT (0x3f << 1) | ||
162 | #define DT_OVRD_EN (0x1 << 0) | ||
163 | |||
164 | #define FRAME_X 0x030 | ||
165 | #define CROP_X 0x04c | ||
166 | #define OUT_X 0x058 | ||
167 | #define WIDTH (0xffff < 0) | ||
168 | |||
169 | #define FRAME_Y 0x034 | ||
170 | #define CROP_Y 0x054 | ||
171 | #define OUT_Y 0x05c | ||
172 | #define HEIGHT (0xffff < 0) | ||
173 | |||
174 | #define EMBED_X 0x038 | ||
175 | #define MAX_BYTES (0x3ffff < 0) | ||
176 | |||
177 | #define EMBED_Y 0x03c | ||
178 | #define SKIP_Y 0x050 | ||
179 | #define LINES (0xffff < 0) | ||
180 | /* for EMBED_Y only */ | ||
181 | #define EXPECT (0x1 << 24) | ||
182 | |||
183 | #define LINE_TIMER 0x044 | ||
184 | #define LINE_TIMER_EN (0x1 << 25) | ||
185 | #define PERIODIC (0x1 << 24) | ||
186 | #define TRIPLINE (0xffff << 0) | ||
187 | |||
188 | #define SKIP_X 0x048 | ||
189 | #define PACKETS (0x1fff << 0) | ||
190 | |||
191 | #define NOTIFY_MASK 0x060 | ||
192 | #define MASK_DTYPE_MISMATCH (0x1 << 31) | ||
193 | #define MASK_EMBED_INFRINGE (0x1 << 22) | ||
194 | #define MASK_EMBED_LONG_LINE (0x1 << 21) | ||
195 | #define MASK_EMBED_SPURIOUS (0x1 << 20) | ||
196 | #define MASK_EMBED_RUNAWAY (0x1 << 19) | ||
197 | #define MASK_EMBED_MISSING_LE (0x1 << 18) | ||
198 | #define MASK_EMBED_EOF (0x1 << 17) | ||
199 | #define MASK_EMBED_SOF (0x1 << 16) | ||
200 | #define MASK_PIXEL_LINE_TIMER (0x1 << 7) | ||
201 | #define MASK_PIXEL_SHORT_LINE (0x1 << 6) | ||
202 | #define MASK_PIXEL_LONG_LINE (0x1 << 5) | ||
203 | #define MASK_PIXEL_SPURIOUS (0x1 << 4) | ||
204 | #define MASK_PIXEL_RUNAWAY (0x1 << 3) | ||
205 | #define MASK_PIXEL_MISSING_LE (0x1 << 2) | ||
206 | #define MASK_PIXEL_EOF (0x1 << 1) | ||
207 | #define MASK_PIXEL_SOF (0x1 << 0) | ||
208 | |||
209 | #define NOTIFY_MASK_XCPT 0x064 | ||
210 | #define MASK_NOMATCH (0x1 << 9) | ||
211 | #define MASK_EMBED_OPEN_LINE (0x1 << 8) | ||
212 | #define MASK_PIXEL_OPEN_LINE (0x1 << 7) | ||
213 | #define MASK_FORCE_FE (0x1 << 6) | ||
214 | #define MASK_STALE_FRAME (0x1 << 5) | ||
215 | #define MASK_COLLISION (0x1 << 4) | ||
216 | #define MASK_EMPTY_FRAME (0x1 << 3) | ||
217 | #define MASK_EMBED_SHORT_FRAME (0x1 << 2) | ||
218 | #define MASK_PIXEL_SHORT_FRAME (0x1 << 1) | ||
219 | #define MASK_LOAD_FRAMED (0x1 << 0) | ||
220 | |||
221 | #define FRAME_COUNT 0x06c | ||
222 | |||
223 | #define PIXFMT_ENABLE 0x080 | ||
224 | #define PDAF_EN (0x1 << 2) | ||
225 | #define COMPAND_EN (0x1 << 1) | ||
226 | #define PIXFMT_EN (0x1 << 0) | ||
227 | |||
228 | #define PIXFMT_FORMAT 0x084 | ||
229 | #define FORMAT (0xff << 0) | ||
230 | /* refer to enum tegra_image_format in core.h */ | ||
231 | |||
232 | #define PIXFMT_WIDE 0x088 | ||
233 | #define ENDIAN_BIG (0x0 << 1) | ||
234 | #define ENDIAN_LITTLE (0x1 << 1) | ||
235 | #define PIXFMT_WIDE_EN (0x1 << 0) | ||
236 | |||
237 | #define DPCM_STRIP 0x0b8 | ||
238 | #define OVERFETCH (0x1fff < 16) | ||
239 | #define STRIP_WIDTH (0x1fff < 0) | ||
240 | |||
241 | #define ATOMP_DPCM_CHUNK 0x0ec | ||
242 | #define CHUNK_OFFSET (0x3ffff << 0) | ||
243 | |||
244 | #define ATOMP_SURFACE_OFFSET0 0x0e0 | ||
245 | #define ATOMP_SURFACE_OFFSET1 0x0f0 | ||
246 | #define ATOMP_SURFACE_OFFSET2 0x0fc | ||
247 | #define ATOMP_EMB_SURFACE_OFFSET0 0x108 | ||
248 | #define SURFACE_OFFSET (0xffffffff << 0) | ||
249 | |||
250 | #define ATOMP_SURFACE_OFFSET0_H 0x0e4 | ||
251 | #define ATOMP_SURFACE_OFFSET1_H 0x0f4 | ||
252 | #define ATOMP_SURFACE_OFFSET2_H 0x100 | ||
253 | #define ATOMP_EMB_SURFACE_OFFSET0_H 0x10c | ||
254 | #define SURFACE_OFFSET_HI (0xff << 0) | ||
255 | |||
256 | #define ATOMP_SURFACE_STRIDE0 0x0e8 | ||
257 | #define ATOMP_SURFACE_STRIDE1 0x0f8 | ||
258 | #define ATOMP_SURFACE_STRIDE2 0x104 | ||
259 | #define ATOMP_EMB_SURFACE_STRIDE0 0x110 | ||
260 | #define SURFACE_STRIDE (0x3ffff << 0) | ||
261 | #define ATOMP_RESERVE 0x120 | ||
262 | |||
263 | #define ISPBUFA 0x134 | ||
264 | #define ISPBUFA_EN (0x1 << 0) | ||
265 | |||
266 | #define ISPBUFA_ERROR 0x1000 | ||
267 | #define FIFO_OVERFLOW (0x1 << 0) | ||
268 | |||
269 | #define FMLITE_ERROR 0x313c | ||
270 | #define NOTIFY_ERROR 0x6020 | ||
271 | |||
272 | #endif /* __VI4_REGISTERS_H__ */ | ||
diff --git a/drivers/media/platform/tegra/mipical/Kconfig b/drivers/media/platform/tegra/mipical/Kconfig new file mode 100644 index 000000000..e00659b2b --- /dev/null +++ b/drivers/media/platform/tegra/mipical/Kconfig | |||
@@ -0,0 +1,11 @@ | |||
1 | config TEGRA_MIPI_CAL | ||
2 | depends on TEGRA_DC || TEGRA_CAMERA_PLATFORM | ||
3 | bool "Enable MIPI Cal driver" | ||
4 | default y | ||
5 | select REGMAP | ||
6 | select REGMAP_MMIO | ||
7 | help | ||
8 | Provides an interfaces to do MIPI calibration for both DSI and CSI blocks. | ||
9 | You will always want this enabled if you are using either Camera or Display. | ||
10 | Disabling this can cause issues for drivers that depend on it being present. | ||
11 | Leaving this on is harmless even if no drivers that need it are enabled. | ||
diff --git a/drivers/media/platform/tegra/mipical/Makefile b/drivers/media/platform/tegra/mipical/Makefile new file mode 100644 index 000000000..ffd996e09 --- /dev/null +++ b/drivers/media/platform/tegra/mipical/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | GCOV_PROFILE := y | ||
2 | # | ||
3 | # Makefile for Mipical driver | ||
4 | # | ||
5 | obj-$(CONFIG_TEGRA_MIPI_CAL) += mipi_cal.o | ||
6 | obj-$(CONFIG_TEGRA_MIPI_CAL) += vmipi/vmipi.o | ||
diff --git a/drivers/media/platform/tegra/mipical/mipi_cal.c b/drivers/media/platform/tegra/mipical/mipi_cal.c new file mode 100644 index 000000000..d53af8ae3 --- /dev/null +++ b/drivers/media/platform/tegra/mipical/mipi_cal.c | |||
@@ -0,0 +1,1096 @@ | |||
1 | /* | ||
2 | * mipi_cal.c | ||
3 | * | ||
4 | * Copyright (c) 2016-2017, NVIDIA CORPORATION, All rights reserved. | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | #include <linux/device.h> | ||
17 | #include <linux/clk.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/of_platform.h> | ||
20 | #include <linux/regmap.h> | ||
21 | #include <linux/io.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/export.h> | ||
26 | #include <linux/reset.h> | ||
27 | #include <linux/string.h> | ||
28 | #include <linux/debugfs.h> | ||
29 | #include <linux/clk/tegra.h> | ||
30 | #include <linux/pm.h> | ||
31 | #include <linux/miscdevice.h> | ||
32 | #include <linux/fs.h> | ||
33 | #include <linux/uaccess.h> | ||
34 | |||
35 | #include <soc/tegra/fuse.h> | ||
36 | #include <soc/tegra/tegra_powergate.h> | ||
37 | #include <linux/tegra_prod.h> | ||
38 | #include <uapi/misc/tegra_mipi_ioctl.h> | ||
39 | |||
40 | #include "registers.h" | ||
41 | #include "mipi_cal.h" | ||
42 | #include "vmipi/vmipi.h" | ||
43 | |||
44 | #define DRV_NAME "tegra_mipi_cal" | ||
45 | #define MIPI_CAL_TIMEOUT_MSEC 500 | ||
46 | |||
47 | struct tegra_mipi_bias { | ||
48 | /* BIAS_PAD_CFG0 */ | ||
49 | u8 pad_pdvclamp; | ||
50 | u8 e_vclamp_ref; | ||
51 | /* BIAS_PAD_CFG1 */ | ||
52 | u8 pad_driv_up_ref; | ||
53 | u8 pad_driv_dn_ref; | ||
54 | /* BIAS_PAD_CFG2 */ | ||
55 | u8 pad_vclamp_level; | ||
56 | u8 pad_vauxp_level; | ||
57 | }; | ||
58 | |||
59 | struct tegra_mipi_prod_csi { | ||
60 | struct tegra_mipi_bias bias_csi; | ||
61 | u8 overide_x; | ||
62 | u8 termos_x; | ||
63 | u8 termos_x_clk; | ||
64 | }; | ||
65 | |||
66 | struct tegra_mipi_prod_dsi { | ||
67 | struct tegra_mipi_bias bias_dsi; | ||
68 | u8 overide_x; | ||
69 | u8 hspdos_x; | ||
70 | u8 hspuos_x; | ||
71 | u8 termos_x; | ||
72 | u8 clk_overide_x; | ||
73 | u8 clk_hspdos_x; | ||
74 | u8 clk_hspuos_x; | ||
75 | u8 clk_hstermos_x; | ||
76 | }; | ||
77 | |||
78 | struct tegra_mipi; | ||
79 | struct tegra_mipi { | ||
80 | struct device *dev; | ||
81 | struct clk *mipi_cal_clk; | ||
82 | struct clk *mipi_cal_fixed; | ||
83 | struct reset_control *rst; | ||
84 | struct regmap *regmap; | ||
85 | struct mutex lock; | ||
86 | /* Legacy way of storing mipical reg config */ | ||
87 | struct tegra_mipi_prod_csi *prod_csi; | ||
88 | struct tegra_mipi_prod_dsi *prod_dsi; | ||
89 | /* If use tegra_prod framework */ | ||
90 | struct tegra_prod *prod_gr_csi; | ||
91 | struct tegra_prod *prod_gr_dsi; | ||
92 | const struct tegra_mipi_soc *soc; | ||
93 | void __iomem *io; | ||
94 | atomic_t refcount; | ||
95 | struct miscdevice misc_dev; | ||
96 | }; | ||
97 | |||
98 | static struct tegra_mipi *mipi; | ||
99 | static const struct regmap_config t210_mipi_cal_regmap_config = { | ||
100 | .reg_bits = 32, | ||
101 | .reg_stride = 4, | ||
102 | .val_bits = 32, | ||
103 | .cache_type = REGCACHE_NONE, | ||
104 | .fast_io = 1, | ||
105 | }; | ||
106 | |||
107 | #define ADDR(x) (x + mipi->soc->addr_offset) | ||
108 | #define dump_register(nm) \ | ||
109 | { \ | ||
110 | .name = #nm, \ | ||
111 | .offset = nm, \ | ||
112 | } | ||
113 | struct tegra_mipi_soc { | ||
114 | int powergate_id; | ||
115 | unsigned int total_dsilanes; | ||
116 | unsigned int total_cillanes; | ||
117 | char addr_offset; | ||
118 | char ppsb_war; | ||
119 | int (*pad_enable)(struct tegra_mipi *mipi); | ||
120 | int (*pad_disable)(struct tegra_mipi *mipi); | ||
121 | int (*calibrate)(struct tegra_mipi *mipi, int lanes); | ||
122 | int (*parse_cfg)(struct platform_device *pdev, struct tegra_mipi *mipi); | ||
123 | u8 virtual_dev; | ||
124 | }; | ||
125 | |||
126 | static int mipical_write(struct regmap *map, | ||
127 | unsigned int reg, unsigned int val) | ||
128 | { | ||
129 | int ret, rb_val; | ||
130 | |||
131 | ret = regmap_write(map, reg, val); | ||
132 | if (mipi->soc->ppsb_war) | ||
133 | /* Read back register to make sure that register writes completed */ | ||
134 | regmap_read(map, reg, &rb_val); | ||
135 | |||
136 | return ret; | ||
137 | } | ||
138 | |||
139 | static int mipical_update_bits(struct regmap *map, unsigned int reg, | ||
140 | unsigned int mask, unsigned int val) | ||
141 | { | ||
142 | int ret, rb_val; | ||
143 | |||
144 | ret = regmap_update_bits(map, reg, mask, val); | ||
145 | if (mipi->soc->ppsb_war) | ||
146 | /* Read back register to make sure that register writes completed */ | ||
147 | regmap_read(map, reg, &rb_val); | ||
148 | |||
149 | return ret; | ||
150 | } | ||
151 | static int tegra_mipi_clk_enable(struct tegra_mipi *mipi) | ||
152 | { | ||
153 | int err; | ||
154 | |||
155 | err = tegra_unpowergate_partition(mipi->soc->powergate_id); | ||
156 | if (err) { | ||
157 | dev_err(mipi->dev, "Fail to unpowergate SOR\n"); | ||
158 | return err; | ||
159 | } | ||
160 | |||
161 | err = clk_prepare_enable(mipi->mipi_cal_fixed); | ||
162 | if (err) { | ||
163 | dev_err(mipi->dev, "Fail to enable uart_mipi_cal clk\n"); | ||
164 | goto err_fixed_clk; | ||
165 | } | ||
166 | mdelay(1); | ||
167 | err = clk_prepare_enable(mipi->mipi_cal_clk); | ||
168 | if (err) { | ||
169 | dev_err(mipi->dev, "Fail to enable mipi_cal clk\n"); | ||
170 | goto err_mipi_cal_clk; | ||
171 | } | ||
172 | return 0; | ||
173 | |||
174 | err_mipi_cal_clk: | ||
175 | clk_disable_unprepare(mipi->mipi_cal_fixed); | ||
176 | err_fixed_clk: | ||
177 | tegra_powergate_partition(mipi->soc->powergate_id); | ||
178 | |||
179 | return err; | ||
180 | } | ||
181 | |||
182 | static void tegra_mipi_clk_disable(struct tegra_mipi *mipi) | ||
183 | { | ||
184 | clk_disable_unprepare(mipi->mipi_cal_clk); | ||
185 | clk_disable_unprepare(mipi->mipi_cal_fixed); | ||
186 | tegra_powergate_partition(mipi->soc->powergate_id); | ||
187 | } | ||
188 | |||
189 | static void tegra_mipi_print(struct tegra_mipi *mipi) __maybe_unused; | ||
190 | static void tegra_mipi_print(struct tegra_mipi *mipi) | ||
191 | { | ||
192 | int val; | ||
193 | unsigned long rate; | ||
194 | #define pr_reg(a) \ | ||
195 | do { \ | ||
196 | regmap_read(mipi->regmap, ADDR(a), &val); \ | ||
197 | dev_info(mipi->dev, "%-30s %#04x %#010x\n", \ | ||
198 | #a, a + mipi->soc->addr_offset, val); \ | ||
199 | } while (0) | ||
200 | |||
201 | rate = clk_get_rate(mipi->mipi_cal_fixed); | ||
202 | dev_dbg(mipi->dev, "Fixed clk %luMHz\n", rate/1000000); | ||
203 | |||
204 | pr_reg(MIPI_CAL_CTRL); | ||
205 | pr_reg(CIL_MIPI_CAL_STATUS); | ||
206 | pr_reg(CIL_MIPI_CAL_STATUS_2); | ||
207 | pr_reg(CILA_MIPI_CAL_CONFIG); | ||
208 | pr_reg(CILB_MIPI_CAL_CONFIG); | ||
209 | pr_reg(CILC_MIPI_CAL_CONFIG); | ||
210 | pr_reg(CILD_MIPI_CAL_CONFIG); | ||
211 | pr_reg(CILE_MIPI_CAL_CONFIG); | ||
212 | pr_reg(CILF_MIPI_CAL_CONFIG); | ||
213 | pr_reg(DSIA_MIPI_CAL_CONFIG); | ||
214 | pr_reg(DSIB_MIPI_CAL_CONFIG); | ||
215 | pr_reg(DSIC_MIPI_CAL_CONFIG); | ||
216 | pr_reg(DSID_MIPI_CAL_CONFIG); | ||
217 | pr_reg(MIPI_BIAS_PAD_CFG0); | ||
218 | pr_reg(MIPI_BIAS_PAD_CFG1); | ||
219 | pr_reg(MIPI_BIAS_PAD_CFG2); | ||
220 | pr_reg(DSIA_MIPI_CAL_CONFIG_2); | ||
221 | pr_reg(DSIB_MIPI_CAL_CONFIG_2); | ||
222 | pr_reg(DSIC_MIPI_CAL_CONFIG_2); | ||
223 | pr_reg(DSID_MIPI_CAL_CONFIG_2); | ||
224 | #undef pr_reg | ||
225 | } | ||
226 | static int tegra_mipi_wait(struct tegra_mipi *mipi, int lanes) | ||
227 | { | ||
228 | unsigned long timeout; | ||
229 | int val; | ||
230 | |||
231 | mipical_write(mipi->regmap, ADDR(CIL_MIPI_CAL_STATUS), 0xffffffff); | ||
232 | mipical_write(mipi->regmap, ADDR(CIL_MIPI_CAL_STATUS_2), 0xffffffff); | ||
233 | mipical_update_bits(mipi->regmap, ADDR(MIPI_CAL_CTRL), STARTCAL, 0x1); | ||
234 | |||
235 | timeout = jiffies + msecs_to_jiffies(MIPI_CAL_TIMEOUT_MSEC); | ||
236 | while (time_before(jiffies, timeout)) { | ||
237 | regmap_read(mipi->regmap, ADDR(CIL_MIPI_CAL_STATUS), &val); | ||
238 | if (((val & lanes) == lanes) && ((val & CAL_ACTIVE) == 0)) | ||
239 | return 0; | ||
240 | usleep_range(10, 50); | ||
241 | } | ||
242 | /* Sometimes there is false timeout. Sleep past the timeout and did | ||
243 | * not check the status again. | ||
244 | * Later status register dump shows no timeout. | ||
245 | * Add another check here in case sleep past the timeout. | ||
246 | */ | ||
247 | regmap_read(mipi->regmap, ADDR(CIL_MIPI_CAL_STATUS), &val); | ||
248 | if (((val & lanes) == lanes) && ((val & CAL_ACTIVE) == 0)) | ||
249 | return 0; | ||
250 | dev_err(mipi->dev, "Mipi cal timeout,val:%x, lanes:%x\n", val, lanes); | ||
251 | tegra_mipi_print(mipi); | ||
252 | return -ETIMEDOUT; | ||
253 | |||
254 | } | ||
255 | |||
256 | static int tegra_mipi_apply_bias_prod(struct regmap *reg, | ||
257 | struct tegra_mipi_bias *bias) | ||
258 | { | ||
259 | int ret; | ||
260 | unsigned int val; | ||
261 | |||
262 | val = (bias->pad_pdvclamp << PDVCLAMP_SHIFT) | | ||
263 | (bias->e_vclamp_ref << E_VCLAMP_REF_SHIFT); | ||
264 | ret = mipical_write(reg, ADDR(MIPI_BIAS_PAD_CFG0), val); | ||
265 | if (ret) | ||
266 | return ret; | ||
267 | val = (bias->pad_driv_up_ref << PAD_DRIV_UP_REF_SHIFT) | | ||
268 | (bias->pad_driv_dn_ref << PAD_DRIV_DN_REF_SHIFT); | ||
269 | ret = mipical_write(reg, ADDR(MIPI_BIAS_PAD_CFG1), val); | ||
270 | if (ret) | ||
271 | return ret; | ||
272 | val = (bias->pad_vclamp_level << PAD_VCLAMP_LEVEL_SHIFT) | | ||
273 | (bias->pad_vauxp_level << PAD_VAUXP_LEVEL_SHIFT); | ||
274 | ret = mipical_write(reg, ADDR(MIPI_BIAS_PAD_CFG2), val); | ||
275 | |||
276 | return ret; | ||
277 | } | ||
278 | static void tegra_mipi_apply_csi_prod(struct regmap *reg, | ||
279 | struct tegra_mipi_prod_csi *prod_csi, | ||
280 | int lanes) | ||
281 | { | ||
282 | int val; | ||
283 | |||
284 | tegra_mipi_apply_bias_prod(reg, &prod_csi->bias_csi); | ||
285 | val = (prod_csi->termos_x << TERMOSA_SHIFT) | | ||
286 | (prod_csi->termos_x_clk << TERMOSA_CLK_SHIFT); | ||
287 | |||
288 | if (lanes & CSIA) | ||
289 | mipical_write(reg, ADDR(CILA_MIPI_CAL_CONFIG), val); | ||
290 | if (lanes & CSIB) | ||
291 | mipical_write(reg, ADDR(CILB_MIPI_CAL_CONFIG), val); | ||
292 | if (lanes & CSIC) | ||
293 | mipical_write(reg, ADDR(CILC_MIPI_CAL_CONFIG), val); | ||
294 | if (lanes & CSID) | ||
295 | mipical_write(reg, ADDR(CILD_MIPI_CAL_CONFIG), val); | ||
296 | if (lanes & CSIE) | ||
297 | mipical_write(reg, ADDR(CILE_MIPI_CAL_CONFIG), val); | ||
298 | if (lanes & CSIF) | ||
299 | mipical_write(reg, ADDR(CILF_MIPI_CAL_CONFIG), val); | ||
300 | } | ||
301 | |||
302 | static void tegra_mipi_apply_dsi_prod(struct regmap *reg, | ||
303 | struct tegra_mipi_prod_dsi *prod_dsi, | ||
304 | int lanes) | ||
305 | { | ||
306 | int val, clk_val; | ||
307 | |||
308 | tegra_mipi_apply_bias_prod(reg, &prod_dsi->bias_dsi); | ||
309 | val = (prod_dsi->hspuos_x << HSPUOSDSIA_SHIFT) | | ||
310 | (prod_dsi->termos_x << TERMOSDSIA_SHIFT); | ||
311 | clk_val = (prod_dsi->clk_hspuos_x << HSCLKPUOSDSIA_SHIFT) | | ||
312 | (prod_dsi->clk_hstermos_x << HSCLKTERMOSDSIA_SHIFT); | ||
313 | if (lanes & DSIA) { | ||
314 | mipical_write(reg, ADDR(DSIA_MIPI_CAL_CONFIG), val); | ||
315 | mipical_write(reg, ADDR(DSIA_MIPI_CAL_CONFIG_2), clk_val); | ||
316 | } | ||
317 | if (lanes & DSIB) { | ||
318 | mipical_write(reg, ADDR(DSIB_MIPI_CAL_CONFIG), val); | ||
319 | mipical_write(reg, ADDR(DSIB_MIPI_CAL_CONFIG_2), clk_val); | ||
320 | } | ||
321 | if (lanes & DSIC) { | ||
322 | mipical_write(reg, ADDR(DSIC_MIPI_CAL_CONFIG), val); | ||
323 | mipical_write(reg, ADDR(DSIC_MIPI_CAL_CONFIG_2), clk_val); | ||
324 | } | ||
325 | if (lanes & DSID) { | ||
326 | mipical_write(reg, ADDR(DSID_MIPI_CAL_CONFIG), val); | ||
327 | mipical_write(reg, ADDR(DSID_MIPI_CAL_CONFIG_2), clk_val); | ||
328 | } | ||
329 | |||
330 | } | ||
331 | |||
332 | static int _t18x_tegra_mipi_bias_pad_enable(struct tegra_mipi *mipi) | ||
333 | { | ||
334 | if (atomic_read(&mipi->refcount) < 0) { | ||
335 | WARN_ON(1); | ||
336 | return -EINVAL; | ||
337 | } | ||
338 | if (atomic_inc_return(&mipi->refcount) == 1) { | ||
339 | tegra_mipi_clk_enable(mipi); | ||
340 | mipical_update_bits(mipi->regmap, ADDR(MIPI_BIAS_PAD_CFG0), | ||
341 | PDVCLAMP, 0 << PDVCLAMP_SHIFT); | ||
342 | mipical_update_bits(mipi->regmap, ADDR(MIPI_BIAS_PAD_CFG2), | ||
343 | PDVREG, 0 << PDVREG_SHIFT); | ||
344 | } | ||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static int _t18x_tegra_mipi_bias_pad_disable(struct tegra_mipi *mipi) | ||
349 | { | ||
350 | if (atomic_read(&mipi->refcount) < 1) { | ||
351 | WARN_ON(1); | ||
352 | return -EINVAL; | ||
353 | } | ||
354 | if (atomic_dec_return(&mipi->refcount) == 0) { | ||
355 | mipical_update_bits(mipi->regmap, ADDR(MIPI_BIAS_PAD_CFG0), | ||
356 | PDVCLAMP, 1 << PDVCLAMP_SHIFT); | ||
357 | mipical_update_bits(mipi->regmap, ADDR(MIPI_BIAS_PAD_CFG2), | ||
358 | PDVREG, 1 << PDVREG_SHIFT); | ||
359 | tegra_mipi_clk_disable(mipi); | ||
360 | } | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static int _t21x_tegra_mipi_bias_pad_enable(struct tegra_mipi *mipi) | ||
365 | { | ||
366 | if (atomic_read(&mipi->refcount) < 0) { | ||
367 | WARN_ON(1); | ||
368 | return -EINVAL; | ||
369 | } | ||
370 | if (atomic_inc_return(&mipi->refcount) == 1) { | ||
371 | tegra_mipi_clk_enable(mipi); | ||
372 | return mipical_update_bits(mipi->regmap, | ||
373 | ADDR(MIPI_BIAS_PAD_CFG2), PDVREG, 0); | ||
374 | } | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | int tegra_mipi_bias_pad_enable(void) | ||
379 | { | ||
380 | if (!mipi) | ||
381 | return -EPROBE_DEFER; | ||
382 | dev_dbg(mipi->dev, "%s", __func__); | ||
383 | |||
384 | if (mipi->soc->pad_enable) | ||
385 | return mipi->soc->pad_enable(mipi); | ||
386 | else | ||
387 | return 0; | ||
388 | } | ||
389 | EXPORT_SYMBOL(tegra_mipi_bias_pad_enable); | ||
390 | |||
391 | static int _t21x_tegra_mipi_bias_pad_disable(struct tegra_mipi *mipi) | ||
392 | { | ||
393 | if (atomic_read(&mipi->refcount) < 1) { | ||
394 | WARN_ON(1); | ||
395 | return -EINVAL; | ||
396 | } | ||
397 | if (atomic_dec_return(&mipi->refcount) == 0) { | ||
398 | mipical_update_bits(mipi->regmap, | ||
399 | ADDR(MIPI_BIAS_PAD_CFG2), PDVREG, PDVREG); | ||
400 | tegra_mipi_clk_disable(mipi); | ||
401 | } | ||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | int tegra_mipi_bias_pad_disable(void) | ||
406 | { | ||
407 | if (!mipi) | ||
408 | return -ENODEV; | ||
409 | dev_dbg(mipi->dev, "%s", __func__); | ||
410 | |||
411 | if (mipi->soc->pad_disable) | ||
412 | return mipi->soc->pad_disable(mipi); | ||
413 | else | ||
414 | return 0; | ||
415 | } | ||
416 | EXPORT_SYMBOL(tegra_mipi_bias_pad_disable); | ||
417 | |||
418 | static void select_lanes(struct tegra_mipi *mipi, int lanes) | ||
419 | { | ||
420 | mipical_update_bits(mipi->regmap, ADDR(CILA_MIPI_CAL_CONFIG), SELA, | ||
421 | ((lanes & CSIA) != 0 ? SELA : 0)); | ||
422 | mipical_update_bits(mipi->regmap, ADDR(CILB_MIPI_CAL_CONFIG), SELA, | ||
423 | ((lanes & CSIB) != 0 ? SELA : 0)); | ||
424 | mipical_update_bits(mipi->regmap, ADDR(CILC_MIPI_CAL_CONFIG), SELA, | ||
425 | ((lanes & CSIC) != 0 ? SELA : 0)); | ||
426 | mipical_update_bits(mipi->regmap, ADDR(CILD_MIPI_CAL_CONFIG), SELA, | ||
427 | ((lanes & CSID) != 0 ? SELA : 0)); | ||
428 | mipical_update_bits(mipi->regmap, ADDR(CILE_MIPI_CAL_CONFIG), SELA, | ||
429 | ((lanes & CSIE) != 0 ? SELA : 0)); | ||
430 | mipical_update_bits(mipi->regmap, ADDR(CILF_MIPI_CAL_CONFIG), SELA, | ||
431 | ((lanes & CSIF) != 0 ? SELA : 0)); | ||
432 | |||
433 | mipical_update_bits(mipi->regmap, ADDR(DSIA_MIPI_CAL_CONFIG), SELDSIA, | ||
434 | ((lanes & DSIA) != 0 ? SELDSIA : 0)); | ||
435 | mipical_update_bits(mipi->regmap, ADDR(DSIB_MIPI_CAL_CONFIG), SELDSIA, | ||
436 | ((lanes & DSIB) != 0 ? SELDSIA : 0)); | ||
437 | mipical_update_bits(mipi->regmap, ADDR(DSIC_MIPI_CAL_CONFIG), SELDSIA, | ||
438 | ((lanes & DSIC) != 0 ? SELDSIA : 0)); | ||
439 | mipical_update_bits(mipi->regmap, ADDR(DSID_MIPI_CAL_CONFIG), SELDSIA, | ||
440 | ((lanes & DSID) != 0 ? SELDSIA : 0)); | ||
441 | mipical_update_bits(mipi->regmap, ADDR(DSIA_MIPI_CAL_CONFIG_2), | ||
442 | CLKSELDSIA, ((lanes & DSIA) != 0 ? CLKSELDSIA : 0)); | ||
443 | mipical_update_bits(mipi->regmap, ADDR(DSIB_MIPI_CAL_CONFIG_2), | ||
444 | CLKSELDSIA, ((lanes & DSIB) != 0 ? CLKSELDSIA : 0)); | ||
445 | mipical_update_bits(mipi->regmap, ADDR(DSIC_MIPI_CAL_CONFIG_2), | ||
446 | CLKSELDSIA, ((lanes & DSIC) != 0 ? CLKSELDSIA : 0)); | ||
447 | mipical_update_bits(mipi->regmap, ADDR(DSID_MIPI_CAL_CONFIG_2), | ||
448 | CLKSELDSIA, ((lanes & DSID) != 0 ? CLKSELDSIA : 0)); | ||
449 | } | ||
450 | |||
451 | static void clear_all(struct tegra_mipi *mipi) | ||
452 | { | ||
453 | mipical_write(mipi->regmap, ADDR(CILA_MIPI_CAL_CONFIG), 0); | ||
454 | mipical_write(mipi->regmap, ADDR(CILB_MIPI_CAL_CONFIG), 0); | ||
455 | mipical_write(mipi->regmap, ADDR(CILC_MIPI_CAL_CONFIG), 0); | ||
456 | mipical_write(mipi->regmap, ADDR(CILD_MIPI_CAL_CONFIG), 0); | ||
457 | mipical_write(mipi->regmap, ADDR(CILE_MIPI_CAL_CONFIG), 0); | ||
458 | mipical_write(mipi->regmap, ADDR(CILF_MIPI_CAL_CONFIG), 0); | ||
459 | |||
460 | mipical_write(mipi->regmap, ADDR(DSIA_MIPI_CAL_CONFIG), 0); | ||
461 | mipical_write(mipi->regmap, ADDR(DSIB_MIPI_CAL_CONFIG), 0); | ||
462 | mipical_write(mipi->regmap, ADDR(DSIC_MIPI_CAL_CONFIG), 0); | ||
463 | mipical_write(mipi->regmap, ADDR(DSID_MIPI_CAL_CONFIG), 0); | ||
464 | mipical_write(mipi->regmap, ADDR(DSIA_MIPI_CAL_CONFIG_2), 0); | ||
465 | mipical_write(mipi->regmap, ADDR(DSIB_MIPI_CAL_CONFIG_2), 0); | ||
466 | mipical_write(mipi->regmap, ADDR(DSIC_MIPI_CAL_CONFIG_2), 0); | ||
467 | mipical_write(mipi->regmap, ADDR(DSID_MIPI_CAL_CONFIG_2), 0); | ||
468 | } | ||
469 | |||
470 | #ifdef CONFIG_DEBUG_FS | ||
471 | static struct debugfs_reg32 mipical_regs[] = { | ||
472 | dump_register(MIPI_CAL_CTRL), | ||
473 | dump_register(MIPI_CAL_AUTOCAL_CTRL0), | ||
474 | dump_register(CIL_MIPI_CAL_STATUS), | ||
475 | dump_register(CIL_MIPI_CAL_STATUS_2), | ||
476 | dump_register(CILA_MIPI_CAL_CONFIG), | ||
477 | dump_register(CILB_MIPI_CAL_CONFIG), | ||
478 | dump_register(CILC_MIPI_CAL_CONFIG), | ||
479 | dump_register(CILD_MIPI_CAL_CONFIG), | ||
480 | dump_register(CILE_MIPI_CAL_CONFIG), | ||
481 | dump_register(CILF_MIPI_CAL_CONFIG), | ||
482 | dump_register(DSIA_MIPI_CAL_CONFIG), | ||
483 | dump_register(DSIB_MIPI_CAL_CONFIG), | ||
484 | dump_register(DSIC_MIPI_CAL_CONFIG), | ||
485 | dump_register(DSID_MIPI_CAL_CONFIG), | ||
486 | dump_register(MIPI_BIAS_PAD_CFG0), | ||
487 | dump_register(MIPI_BIAS_PAD_CFG1), | ||
488 | dump_register(MIPI_BIAS_PAD_CFG2), | ||
489 | dump_register(DSIA_MIPI_CAL_CONFIG_2), | ||
490 | dump_register(DSIB_MIPI_CAL_CONFIG_2), | ||
491 | dump_register(DSIC_MIPI_CAL_CONFIG_2), | ||
492 | dump_register(DSID_MIPI_CAL_CONFIG_2), | ||
493 | }; | ||
494 | |||
495 | static u32 mipical_status; | ||
496 | static u32 timeout_ct; | ||
497 | static u32 counts; | ||
498 | |||
499 | static int dbgfs_show_regs(struct seq_file *s, void *data) | ||
500 | { | ||
501 | struct tegra_mipi *mipi = s->private; | ||
502 | int err; | ||
503 | |||
504 | err = tegra_unpowergate_partition(mipi->soc->powergate_id); | ||
505 | if (err) { | ||
506 | dev_err(mipi->dev, "Fail to unpowergate SOR\n"); | ||
507 | return err; | ||
508 | } | ||
509 | |||
510 | err = tegra_mipi_clk_enable(mipi); | ||
511 | if (err) { | ||
512 | dev_err(mipi->dev, "Fail to enable mipi clk\n"); | ||
513 | goto clk_err; | ||
514 | } | ||
515 | debugfs_print_regs32(s, mipical_regs, ARRAY_SIZE(mipical_regs), | ||
516 | mipi->io, ""); | ||
517 | tegra_mipi_clk_disable(mipi); | ||
518 | err = 0; | ||
519 | |||
520 | clk_err: | ||
521 | tegra_powergate_partition(mipi->soc->powergate_id); | ||
522 | return err; | ||
523 | } | ||
524 | |||
525 | static int dbgfs_open(struct inode *inode, struct file *file) | ||
526 | { | ||
527 | return single_open(file, dbgfs_show_regs, inode->i_private); | ||
528 | } | ||
529 | |||
530 | static const struct file_operations dbgfs_ops = { | ||
531 | .open = dbgfs_open, | ||
532 | .read = seq_read, | ||
533 | .llseek = seq_lseek, | ||
534 | .release = single_release | ||
535 | }; | ||
536 | |||
537 | static int dbgfs_mipi_init(struct tegra_mipi *mipi) | ||
538 | { | ||
539 | struct dentry *dir; | ||
540 | struct dentry *val; | ||
541 | int i; | ||
542 | |||
543 | dir = debugfs_create_dir(DRV_NAME, NULL); | ||
544 | if (!dir) | ||
545 | return -ENOMEM; | ||
546 | |||
547 | val = debugfs_create_x32("LAST_STATUS", S_IRUGO, dir, &mipical_status); | ||
548 | if (!val) | ||
549 | goto err; | ||
550 | val = debugfs_create_u32("COUNT", S_IRUGO | S_IWUGO, dir, &counts); | ||
551 | if (!val) | ||
552 | goto err; | ||
553 | val = debugfs_create_u32("TIMEOUTS", S_IRUGO | S_IWUGO, dir, | ||
554 | &timeout_ct); | ||
555 | if (!val) | ||
556 | goto err; | ||
557 | |||
558 | val = debugfs_create_file("regs", S_IRUGO, dir, mipi, &dbgfs_ops); | ||
559 | if (!val) | ||
560 | goto err; | ||
561 | |||
562 | /* Assign register address with adjusted offset */ | ||
563 | for (i = 0; i < ARRAY_SIZE(mipical_regs); ++i) | ||
564 | mipical_regs[i].offset += mipi->soc->addr_offset; | ||
565 | return 0; | ||
566 | err: | ||
567 | dev_err(mipi->dev, "%s:Fail to create debugfs\n", __func__); | ||
568 | debugfs_remove_recursive(dir); | ||
569 | return -ENODEV; | ||
570 | } | ||
571 | #endif | ||
572 | static int _tegra_mipi_calibration(struct tegra_mipi *mipi, int lanes) | ||
573 | { | ||
574 | int err; | ||
575 | |||
576 | mutex_lock(&mipi->lock); | ||
577 | /* clean up lanes */ | ||
578 | clear_all(mipi); | ||
579 | |||
580 | /* Apply MIPI_CAL PROD_Set */ | ||
581 | if (lanes & (CSIA|CSIB|CSIC|CSID|CSIE|CSIF)) | ||
582 | tegra_mipi_apply_csi_prod(mipi->regmap, mipi->prod_csi, | ||
583 | lanes); | ||
584 | else | ||
585 | tegra_mipi_apply_dsi_prod(mipi->regmap, mipi->prod_dsi, | ||
586 | lanes); | ||
587 | |||
588 | /*Select lanes */ | ||
589 | select_lanes(mipi, lanes); | ||
590 | /* Start calibration */ | ||
591 | err = tegra_mipi_wait(mipi, lanes); | ||
592 | |||
593 | #ifdef CONFIG_DEBUG_FS | ||
594 | regmap_read(mipi->regmap, ADDR(CIL_MIPI_CAL_STATUS), &mipical_status); | ||
595 | counts++; | ||
596 | if (err) | ||
597 | timeout_ct++; | ||
598 | #endif | ||
599 | mutex_unlock(&mipi->lock); | ||
600 | return err; | ||
601 | } | ||
602 | static int tegra_mipical_using_prod(struct tegra_mipi *mipi, int lanes) | ||
603 | { | ||
604 | int err = 0; | ||
605 | |||
606 | mutex_lock(&mipi->lock); | ||
607 | |||
608 | /* clean up lanes */ | ||
609 | clear_all(mipi); | ||
610 | |||
611 | /* Apply MIPI_CAL PROD_Set */ | ||
612 | if (lanes & (CSIA|CSIB|CSIC|CSID|CSIE|CSIF)) { | ||
613 | if (!IS_ERR(mipi->prod_gr_csi)) | ||
614 | err = tegra_prod_set_by_name(&mipi->io, "prod", | ||
615 | mipi->prod_gr_csi); | ||
616 | } else { | ||
617 | if (!IS_ERR(mipi->prod_gr_dsi)) | ||
618 | err = tegra_prod_set_by_name(&mipi->io, | ||
619 | "prod", mipi->prod_gr_dsi); | ||
620 | } | ||
621 | if (err) { | ||
622 | dev_err(mipi->dev, "tegra_prod set failed\n"); | ||
623 | goto err_unlock; | ||
624 | } | ||
625 | /*Select lanes */ | ||
626 | select_lanes(mipi, lanes); | ||
627 | /* Start calibration */ | ||
628 | err = tegra_mipi_wait(mipi, lanes); | ||
629 | |||
630 | #ifdef CONFIG_DEBUG_FS | ||
631 | regmap_read(mipi->regmap, ADDR(CIL_MIPI_CAL_STATUS), &mipical_status); | ||
632 | counts++; | ||
633 | if (err) | ||
634 | timeout_ct++; | ||
635 | #endif | ||
636 | err_unlock: | ||
637 | mutex_unlock(&mipi->lock); | ||
638 | return err; | ||
639 | |||
640 | } | ||
641 | int tegra_mipi_calibration(int lanes) | ||
642 | { | ||
643 | if (!mipi) | ||
644 | return -ENODEV; | ||
645 | dev_dbg(mipi->dev, "%s", __func__); | ||
646 | if (mipi->soc->calibrate) | ||
647 | return mipi->soc->calibrate(mipi, lanes); | ||
648 | else | ||
649 | return 0; | ||
650 | |||
651 | } | ||
652 | EXPORT_SYMBOL(tegra_mipi_calibration); | ||
653 | |||
654 | static void parse_bias_prod(struct device_node *np, | ||
655 | struct tegra_mipi_bias *bias) | ||
656 | { | ||
657 | int ret; | ||
658 | unsigned int v; | ||
659 | |||
660 | ret = of_property_read_u32(np, "bias-pad-cfg0", &v); | ||
661 | if (!ret) { | ||
662 | bias->pad_pdvclamp = (v & PDVCLAMP) >> PDVCLAMP_SHIFT; | ||
663 | bias->e_vclamp_ref = (v & E_VCLAMP_REF) >> E_VCLAMP_REF_SHIFT; | ||
664 | } | ||
665 | |||
666 | ret = of_property_read_u32(np, "bias-pad-cfg1", &v); | ||
667 | if (!ret) { | ||
668 | bias->pad_driv_up_ref = | ||
669 | (v & PAD_DRIV_UP_REF) >> PAD_DRIV_UP_REF_SHIFT; | ||
670 | bias->pad_driv_dn_ref = | ||
671 | (v & PAD_DRIV_DN_REF) >> PAD_DRIV_DN_REF_SHIFT; | ||
672 | } | ||
673 | |||
674 | ret = of_property_read_u32(np, "bias-pad-cfg2", &v); | ||
675 | if (!ret) { | ||
676 | bias->pad_vclamp_level = | ||
677 | (v & PAD_VCLAMP_LEVEL) >> PAD_VCLAMP_LEVEL_SHIFT; | ||
678 | bias->pad_vauxp_level = | ||
679 | (v & PAD_VAUXP_LEVEL) >> PAD_VAUXP_LEVEL_SHIFT; | ||
680 | } | ||
681 | } | ||
682 | |||
683 | static void parse_dsi_prod(struct device_node *np, | ||
684 | struct tegra_mipi_prod_dsi *dsi) | ||
685 | { | ||
686 | int ret; | ||
687 | unsigned int v; | ||
688 | |||
689 | if (!np) | ||
690 | return; | ||
691 | ret = of_property_read_u32(np, "dsix-cfg", &v); | ||
692 | if (!ret) { | ||
693 | dsi->overide_x = (v & OVERIDEDSIA) >> OVERIDEDSIA_SHIFT; | ||
694 | dsi->hspdos_x = (v & HSPDOSDSIA) >> HSPDOSDSIA_SHIFT; | ||
695 | dsi->hspuos_x = (v & HSPUOSDSIA) >> HSPUOSDSIA_SHIFT; | ||
696 | dsi->termos_x = (v & TERMOSDSIA) >> TERMOSDSIA_SHIFT; | ||
697 | } | ||
698 | ret = of_property_read_u32(np, "dsix-cfg2", &v); | ||
699 | if (!ret) { | ||
700 | dsi->clk_overide_x = | ||
701 | (v & CLKOVERIDEDSIA) >> CLKOVERIDEDSIA_SHIFT; | ||
702 | dsi->clk_hspdos_x = (v & HSCLKPDOSDSIA) >> HSCLKPDOSDSIA_SHIFT; | ||
703 | dsi->clk_hspuos_x = (v & HSCLKPUOSDSIA) >> HSCLKPUOSDSIA_SHIFT; | ||
704 | dsi->clk_hstermos_x = | ||
705 | (v & HSCLKTERMOSDSIA) >> HSCLKTERMOSDSIA_SHIFT; | ||
706 | } | ||
707 | parse_bias_prod(np, &dsi->bias_dsi); | ||
708 | } | ||
709 | static void parse_csi_prod(struct device_node *np, | ||
710 | struct tegra_mipi_prod_csi *csi) | ||
711 | { | ||
712 | int ret; | ||
713 | unsigned int v; | ||
714 | |||
715 | if (!np) | ||
716 | return; | ||
717 | ret = of_property_read_u32(np, "cilx-cfg", &v); | ||
718 | if (!ret) { | ||
719 | csi->overide_x = (v & OVERIDEA) >> OVERIDEA_SHIFT; | ||
720 | csi->termos_x = (v & TERMOSA) >> TERMOSA_SHIFT; | ||
721 | csi->termos_x_clk = (v & TERMOSA_CLK) >> TERMOSA_CLK_SHIFT; | ||
722 | } | ||
723 | parse_bias_prod(np, &csi->bias_csi); | ||
724 | |||
725 | } | ||
726 | static void parse_prod(struct device_node *np, struct tegra_mipi *mipi) | ||
727 | { | ||
728 | struct device_node *next; | ||
729 | |||
730 | if (!np) | ||
731 | return; | ||
732 | next = of_get_child_by_name(np, "dsi"); | ||
733 | parse_dsi_prod(next, mipi->prod_dsi); | ||
734 | next = of_get_child_by_name(np, "csi"); | ||
735 | parse_csi_prod(next, mipi->prod_csi); | ||
736 | } | ||
737 | |||
738 | static void print_config(struct tegra_mipi *mipi) | ||
739 | { | ||
740 | struct tegra_mipi_prod_csi *csi = mipi->prod_csi; | ||
741 | struct tegra_mipi_prod_dsi *dsi = mipi->prod_dsi; | ||
742 | #define pr_val(x) dev_dbg(mipi->dev, "%s:%x", #x, x) | ||
743 | |||
744 | pr_val(csi->overide_x); | ||
745 | pr_val(csi->termos_x); | ||
746 | pr_val(csi->termos_x_clk); | ||
747 | pr_val(dsi->overide_x); | ||
748 | pr_val(dsi->hspdos_x); | ||
749 | pr_val(dsi->hspuos_x); | ||
750 | pr_val(dsi->termos_x); | ||
751 | pr_val(dsi->clk_overide_x); | ||
752 | pr_val(dsi->clk_hspdos_x); | ||
753 | pr_val(dsi->clk_hspuos_x); | ||
754 | pr_val(dsi->clk_hstermos_x); | ||
755 | #undef pr_val | ||
756 | } | ||
757 | |||
758 | static int tegra_prod_get_config(struct platform_device *pdev, | ||
759 | struct tegra_mipi *mipi) | ||
760 | { | ||
761 | struct device_node *np; | ||
762 | |||
763 | if (mipi->prod_gr_dsi != NULL && mipi->prod_gr_csi != NULL) | ||
764 | return 0; | ||
765 | |||
766 | np = of_find_node_by_name(NULL, "mipical"); | ||
767 | if (!np) { | ||
768 | pr_err("%s: Can not find dsi prod node\n", __func__); | ||
769 | } else { | ||
770 | mipi->prod_gr_dsi = | ||
771 | devm_tegra_prod_get_from_node(mipi->dev, np); | ||
772 | if (IS_ERR(mipi->prod_gr_dsi)) | ||
773 | dev_err(mipi->dev, "Fail to get DSI PROD settings\n"); | ||
774 | } | ||
775 | |||
776 | np = of_find_node_by_name(NULL, "csi_mipical"); | ||
777 | if (!np) { | ||
778 | pr_err("%s: Can not find csi_mipical node\n", __func__); | ||
779 | } else { | ||
780 | mipi->prod_gr_csi = | ||
781 | devm_tegra_prod_get_from_node(mipi->dev, np); | ||
782 | if (IS_ERR(mipi->prod_gr_csi)) | ||
783 | dev_err(mipi->dev, "Fail to get CSI PROD settings\n"); | ||
784 | } | ||
785 | |||
786 | return 0; | ||
787 | } | ||
788 | |||
789 | static int tegra_mipi_parse_config(struct platform_device *pdev, | ||
790 | struct tegra_mipi *mipi) | ||
791 | { | ||
792 | struct device_node *np = pdev->dev.of_node; | ||
793 | struct device_node *next; | ||
794 | |||
795 | if (!np) | ||
796 | return -ENODEV; | ||
797 | |||
798 | if (of_device_is_compatible(np, "nvidia,tegra210-mipical")) | ||
799 | parse_prod(np, mipi); | ||
800 | |||
801 | if (of_device_is_compatible(np, "nvidia, tegra186-mipical")) { | ||
802 | if (tegra_chip_get_revision() == TEGRA186_REVISION_A01) { | ||
803 | dev_dbg(mipi->dev, "T186-A01\n"); | ||
804 | next = of_get_child_by_name(np, "a01"); | ||
805 | parse_prod(next, mipi); | ||
806 | } else { | ||
807 | dev_dbg(mipi->dev, "T186-A02\n"); | ||
808 | next = of_get_child_by_name(np, "a02"); | ||
809 | parse_prod(next, mipi); | ||
810 | } | ||
811 | } | ||
812 | print_config(mipi); | ||
813 | return 0; | ||
814 | } | ||
815 | static const struct tegra_mipi_soc tegra21x_mipi_soc = { | ||
816 | .total_dsilanes = 4, | ||
817 | .total_cillanes = 6, | ||
818 | .addr_offset = 0, | ||
819 | .ppsb_war = 1, | ||
820 | .pad_enable = &_t21x_tegra_mipi_bias_pad_enable, | ||
821 | .pad_disable = &_t21x_tegra_mipi_bias_pad_disable, | ||
822 | .calibrate = &_tegra_mipi_calibration, | ||
823 | .parse_cfg = &tegra_mipi_parse_config, | ||
824 | .powergate_id = TEGRA210_POWER_DOMAIN_SOR, | ||
825 | }; | ||
826 | |||
827 | static const struct tegra_mipi_soc tegra18x_mipi_soc = { | ||
828 | .total_dsilanes = 4, | ||
829 | .total_cillanes = 6, | ||
830 | .addr_offset = 4, | ||
831 | .ppsb_war = 0, | ||
832 | .pad_enable = &_t18x_tegra_mipi_bias_pad_enable, | ||
833 | .pad_disable = &_t18x_tegra_mipi_bias_pad_disable, | ||
834 | .calibrate = &tegra_mipical_using_prod, | ||
835 | .parse_cfg = &tegra_prod_get_config, | ||
836 | .powergate_id = TEGRA186_POWER_DOMAIN_DISP, | ||
837 | }; | ||
838 | |||
839 | static const struct tegra_mipi_soc tegra_vmipi_soc = { | ||
840 | .pad_enable = &tegra_vmipi_bias_pad_enable, | ||
841 | .pad_disable = &tegra_vmipi_bias_pad_disable, | ||
842 | .calibrate = &tegra_vmipi_calibration, | ||
843 | .virtual_dev = 1, | ||
844 | }; | ||
845 | |||
846 | static const struct of_device_id tegra_mipi_of_match[] = { | ||
847 | { | ||
848 | .compatible = "nvidia,tegra210-mipical", | ||
849 | .data = &tegra21x_mipi_soc, | ||
850 | }, { | ||
851 | .compatible = "nvidia, tegra186-mipical", | ||
852 | .data = &tegra18x_mipi_soc, | ||
853 | }, { | ||
854 | .compatible = "nvidia, tegra186-mipical-shared-multi-os", | ||
855 | .data = &tegra18x_mipi_soc, | ||
856 | }, { | ||
857 | .compatible = "nvidia,tegra-mipical-hv", | ||
858 | .data = &tegra_vmipi_soc, | ||
859 | }, { | ||
860 | } | ||
861 | }; | ||
862 | MODULE_DEVICE_TABLE(of, tegra_mipi_of_match); | ||
863 | |||
864 | static int tegra_mipi_open(struct inode *inode, struct file *file) | ||
865 | { | ||
866 | return 0; | ||
867 | } | ||
868 | static int tegra_mipi_release(struct inode *inode, struct file *file) | ||
869 | { | ||
870 | return 0; | ||
871 | } | ||
872 | static long mipi_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
873 | { | ||
874 | struct tegra_mipi *mipi = container_of(file->private_data, | ||
875 | struct tegra_mipi, misc_dev); | ||
876 | if (_IOC_TYPE(cmd) != TEGRA_MIPI_IOCTL_MAGIC) | ||
877 | return -EINVAL; | ||
878 | |||
879 | switch (_IOC_NR(cmd)) { | ||
880 | case _IOC_NR(TEGRA_MIPI_IOCTL_BIAS_PAD_CTRL): { | ||
881 | unsigned int enable = 0; | ||
882 | int err; | ||
883 | |||
884 | if (copy_from_user(&enable, (const void __user *)arg, | ||
885 | sizeof(unsigned int))) { | ||
886 | dev_err(mipi->dev, "Fail to get user data\n"); | ||
887 | return -EFAULT; | ||
888 | } | ||
889 | if (enable) | ||
890 | err = tegra_mipi_bias_pad_enable(); | ||
891 | else | ||
892 | err = tegra_mipi_bias_pad_disable(); | ||
893 | return err; | ||
894 | } | ||
895 | case _IOC_NR(TEGRA_MIPI_IOCTL_CAL): { | ||
896 | int lanes = 0; | ||
897 | |||
898 | if (copy_from_user(&lanes, (const void __user *)arg, | ||
899 | sizeof(int))) { | ||
900 | dev_err(mipi->dev, "Fail to get user data\n"); | ||
901 | return -EFAULT; | ||
902 | } | ||
903 | if (lanes) | ||
904 | return tegra_mipi_calibration(lanes); | ||
905 | |||
906 | dev_err(mipi->dev, "Selected lane %x, skip mipical\n", lanes); | ||
907 | return 0; | ||
908 | } | ||
909 | default: | ||
910 | dev_err(mipi->dev, "Unknown ioctl\n"); | ||
911 | return -EINVAL; | ||
912 | } | ||
913 | return 0; | ||
914 | } | ||
915 | |||
916 | static const struct file_operations tegra_mipi_miscdev_fops = { | ||
917 | .owner = THIS_MODULE, | ||
918 | .open = tegra_mipi_open, | ||
919 | .release = tegra_mipi_release, | ||
920 | .unlocked_ioctl = mipi_ioctl, | ||
921 | #ifdef CONFIG_COMPAT | ||
922 | .compat_ioctl = mipi_ioctl, | ||
923 | #endif | ||
924 | }; | ||
925 | |||
926 | static int tegra_mipi_misc_register(struct tegra_mipi *mipi) | ||
927 | { | ||
928 | int err; | ||
929 | |||
930 | if (!mipi) | ||
931 | return -EINVAL; | ||
932 | |||
933 | mipi->misc_dev.minor = MISC_DYNAMIC_MINOR; | ||
934 | mipi->misc_dev.name = DRV_NAME; | ||
935 | mipi->misc_dev.fops = &tegra_mipi_miscdev_fops; | ||
936 | err = misc_register(&mipi->misc_dev); | ||
937 | if (err) | ||
938 | dev_err(mipi->dev, "Fail to register misc dev\n"); | ||
939 | |||
940 | return err; | ||
941 | } | ||
942 | |||
943 | int tegra_vmipi_probe(struct platform_device *pdev) | ||
944 | { | ||
945 | int err; | ||
946 | |||
947 | err = tegra_vmipi_init(pdev); | ||
948 | if (err) { | ||
949 | dev_err(&pdev->dev, "Mipi cal virtual dev probe failed\n"); | ||
950 | return err; | ||
951 | } | ||
952 | |||
953 | err = tegra_mipi_misc_register(mipi); | ||
954 | if (err) | ||
955 | tegra_vmipi_deinit(); | ||
956 | |||
957 | return err; | ||
958 | } | ||
959 | |||
960 | static int tegra_mipi_probe(struct platform_device *pdev) | ||
961 | { | ||
962 | const struct of_device_id *match; | ||
963 | struct resource *mem, *memregion; | ||
964 | void __iomem *regs; | ||
965 | int err = 0; | ||
966 | struct device_node *np; | ||
967 | const struct tegra_mipi_soc *cdata = NULL; | ||
968 | |||
969 | np = pdev->dev.of_node; | ||
970 | match = of_match_device(tegra_mipi_of_match, &pdev->dev); | ||
971 | if (!match) { | ||
972 | dev_err(&pdev->dev, "No device match found\n"); | ||
973 | return -ENODEV; | ||
974 | } | ||
975 | cdata = match->data; | ||
976 | mipi = devm_kzalloc(&pdev->dev, sizeof(*mipi), GFP_KERNEL); | ||
977 | if (!mipi) | ||
978 | return -ENOMEM; | ||
979 | |||
980 | mipi->dev = &pdev->dev; | ||
981 | mipi->soc = cdata; | ||
982 | platform_set_drvdata(pdev, mipi); | ||
983 | |||
984 | if (mipi->soc->virtual_dev) | ||
985 | return tegra_vmipi_probe(pdev); | ||
986 | |||
987 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
988 | if (!mem) { | ||
989 | dev_err(&pdev->dev, "No memory resource\n"); | ||
990 | return -EINVAL; | ||
991 | } | ||
992 | memregion = devm_request_mem_region(&pdev->dev, mem->start, | ||
993 | resource_size(mem), pdev->name); | ||
994 | if (!memregion) { | ||
995 | dev_err(&pdev->dev, "Cannot request mem region\n"); | ||
996 | return -EBUSY; | ||
997 | } | ||
998 | regs = devm_ioremap_nocache(&pdev->dev, mem->start, resource_size(mem)); | ||
999 | if (!regs) { | ||
1000 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
1001 | return -ENOMEM; | ||
1002 | } | ||
1003 | |||
1004 | mipi->io = regs; | ||
1005 | mipi->regmap = devm_regmap_init_mmio(&pdev->dev, regs, | ||
1006 | &t210_mipi_cal_regmap_config); | ||
1007 | if (IS_ERR(mipi->regmap)) { | ||
1008 | dev_err(&pdev->dev, "Fai to initialize regmap\n"); | ||
1009 | return PTR_ERR(mipi->regmap); | ||
1010 | } | ||
1011 | |||
1012 | mipi->mipi_cal_clk = devm_clk_get(&pdev->dev, "mipi_cal"); | ||
1013 | if (IS_ERR(mipi->mipi_cal_clk)) | ||
1014 | return PTR_ERR(mipi->mipi_cal_clk); | ||
1015 | |||
1016 | if (of_device_is_compatible(np, "nvidia,tegra210-mipical")) { | ||
1017 | mipi->mipi_cal_fixed = devm_clk_get(&pdev->dev, | ||
1018 | "uart_mipi_cal"); | ||
1019 | if (IS_ERR(mipi->mipi_cal_fixed)) | ||
1020 | return PTR_ERR(mipi->mipi_cal_fixed); | ||
1021 | mipi->prod_csi = devm_kzalloc(&pdev->dev, | ||
1022 | sizeof(*mipi->prod_csi), GFP_KERNEL); | ||
1023 | mipi->prod_dsi = devm_kzalloc(&pdev->dev, | ||
1024 | sizeof(*mipi->prod_dsi), GFP_KERNEL); | ||
1025 | } else if (of_device_is_compatible(np, "nvidia, tegra186-mipical")) { | ||
1026 | mipi->mipi_cal_fixed = devm_clk_get(&pdev->dev, | ||
1027 | "uart_fs_mipi_cal"); | ||
1028 | if (IS_ERR(mipi->mipi_cal_fixed)) | ||
1029 | return PTR_ERR(mipi->mipi_cal_fixed); | ||
1030 | mipi->rst = devm_reset_control_get(mipi->dev, "mipi_cal"); | ||
1031 | reset_control_deassert(mipi->rst); | ||
1032 | /* Bug 200224083 requires both register fields set to 1 | ||
1033 | * after de-asserted | ||
1034 | */ | ||
1035 | tegra_mipi_clk_enable(mipi); | ||
1036 | mipical_update_bits(mipi->regmap, ADDR(MIPI_BIAS_PAD_CFG0), | ||
1037 | PDVCLAMP, 1 << PDVCLAMP_SHIFT); | ||
1038 | mipical_update_bits(mipi->regmap, ADDR(MIPI_BIAS_PAD_CFG2), | ||
1039 | PDVREG, 1 << PDVREG_SHIFT); | ||
1040 | tegra_mipi_clk_disable(mipi); | ||
1041 | } else if (of_device_is_compatible(np, "nvidia, tegra186-mipical-shared-multi-os")) { | ||
1042 | mipi->mipi_cal_fixed = devm_clk_get(&pdev->dev, | ||
1043 | "uart_fs_mipi_cal"); | ||
1044 | if (IS_ERR(mipi->mipi_cal_fixed)) | ||
1045 | return PTR_ERR(mipi->mipi_cal_fixed); | ||
1046 | mipi->rst = devm_reset_control_get(mipi->dev, "mipi_cal"); | ||
1047 | reset_control_deassert(mipi->rst); | ||
1048 | } | ||
1049 | |||
1050 | if (mipi->soc->parse_cfg) | ||
1051 | err = mipi->soc->parse_cfg(pdev, mipi); | ||
1052 | if (err) | ||
1053 | return err; | ||
1054 | |||
1055 | mutex_init(&mipi->lock); | ||
1056 | atomic_set(&mipi->refcount, 0); | ||
1057 | |||
1058 | err = tegra_mipi_misc_register(mipi); | ||
1059 | if (err) | ||
1060 | return err; | ||
1061 | |||
1062 | #ifdef CONFIG_DEBUG_FS | ||
1063 | err = dbgfs_mipi_init(mipi); | ||
1064 | if (err) | ||
1065 | dev_err(&pdev->dev, "Fail to create debugfs\n"); | ||
1066 | #endif | ||
1067 | |||
1068 | dev_dbg(&pdev->dev, "Mipi cal done probing...\n"); | ||
1069 | return err; | ||
1070 | } | ||
1071 | |||
1072 | static struct platform_driver tegra_mipi_cal_platform_driver = { | ||
1073 | .driver = { | ||
1074 | .name = DRV_NAME, | ||
1075 | .owner = THIS_MODULE, | ||
1076 | .of_match_table = tegra_mipi_of_match, | ||
1077 | }, | ||
1078 | .probe = tegra_mipi_probe, | ||
1079 | }; | ||
1080 | |||
1081 | static int __init tegra_mipi_module_init(void) | ||
1082 | { | ||
1083 | return platform_driver_register(&tegra_mipi_cal_platform_driver); | ||
1084 | } | ||
1085 | |||
1086 | static void __exit tegra_mipi_module_exit(void) | ||
1087 | { | ||
1088 | platform_driver_unregister(&tegra_mipi_cal_platform_driver); | ||
1089 | } | ||
1090 | subsys_initcall(tegra_mipi_module_init); | ||
1091 | module_exit(tegra_mipi_module_exit); | ||
1092 | |||
1093 | MODULE_AUTHOR("Wenjia Zhou <wenjiaz@nvidia.com>"); | ||
1094 | MODULE_DESCRIPTION("Common MIPI calibration driver for CSI and DSI"); | ||
1095 | MODULE_LICENSE("GPL v2"); | ||
1096 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/drivers/media/platform/tegra/mipical/mipi_cal.h b/drivers/media/platform/tegra/mipical/mipi_cal.h new file mode 100644 index 000000000..0fd5171fb --- /dev/null +++ b/drivers/media/platform/tegra/mipical/mipi_cal.h | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * mipi_cal.h | ||
3 | * | ||
4 | * Copyright (c) 2016-2017, NVIDIA CORPORATION, All rights reserved. | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #ifndef MIPI_CAL_H | ||
18 | #define MIPI_CAL_H | ||
19 | |||
20 | #define DSID (1 << 31) | ||
21 | #define DSIC (1 << 30) | ||
22 | #define DSIB (1 << 29) | ||
23 | #define DSIA (1 << 28) | ||
24 | #define CSIF (1 << 25) | ||
25 | #define CSIE (1 << 24) | ||
26 | #define CSID (1 << 23) | ||
27 | #define CSIC (1 << 22) | ||
28 | #define CSIB (1 << 21) | ||
29 | #define CSIA (1 << 20) | ||
30 | #define MIPI_CPHY 1 | ||
31 | |||
32 | #ifdef CONFIG_TEGRA_MIPI_CAL | ||
33 | int tegra_mipi_bias_pad_enable(void); | ||
34 | int tegra_mipi_bias_pad_disable(void); | ||
35 | int tegra_mipi_calibration(int lanes); | ||
36 | #else | ||
37 | static inline int tegra_mipi_bias_pad_enable(void) | ||
38 | { | ||
39 | return 0; | ||
40 | } | ||
41 | static inline int tegra_mipi_bias_pad_disable(void) | ||
42 | { | ||
43 | return 0; | ||
44 | } | ||
45 | static inline int tegra_mipi_calibration(int lanes) | ||
46 | { | ||
47 | return 0; | ||
48 | } | ||
49 | #endif | ||
50 | #endif | ||
diff --git a/drivers/media/platform/tegra/mipical/registers.h b/drivers/media/platform/tegra/mipical/registers.h new file mode 100644 index 000000000..5f209790b --- /dev/null +++ b/drivers/media/platform/tegra/mipical/registers.h | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * registers.h | ||
3 | * | ||
4 | * Copyright (c) 2016-2017, NVIDIA CORPORATION, All rights reserved. | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | /* New register on T186 that starts | ||
18 | * at offset 0 | ||
19 | */ | ||
20 | #define MIPI_CAL_MODE 0x00 | ||
21 | |||
22 | /* T210 register offset*/ | ||
23 | #define MIPI_CAL_CTRL 0x00 | ||
24 | #define NOISE_FLT (0xf << 26) | ||
25 | #define PRESCALE (0x3 << 24) | ||
26 | #define CLKEN_OVR (1 << 4) | ||
27 | #define AUTOCAL_EN (1 << 1) | ||
28 | #define STARTCAL (1 << 0) | ||
29 | #define MIPI_CAL_AUTOCAL_CTRL0 0x04 | ||
30 | #define CIL_MIPI_CAL_STATUS 0x08 | ||
31 | #define CAL_DONE_DSID (1 << 31) | ||
32 | #define CAL_DONE_DSIC (1 << 30) | ||
33 | #define CAL_DONE_DSIB (1 << 29) | ||
34 | #define CAL_DONE_DSIA (1 << 28) | ||
35 | #define CAL_DONE_CSIF (1 << 25) | ||
36 | #define CAL_DONE_CSIE (1 << 24) | ||
37 | #define CAL_DONE_CSID (1 << 23) | ||
38 | #define CAL_DONE_CSIC (1 << 22) | ||
39 | #define CAL_DONE_CSIB (1 << 21) | ||
40 | #define CAL_DONE_CSIA (1 << 20) | ||
41 | #define CAL_DONE (1 << 16) | ||
42 | #define CAL_ACTIVE (1 << 0) | ||
43 | #define CIL_MIPI_CAL_STATUS_2 0x0c | ||
44 | #define CILA_MIPI_CAL_CONFIG 0x14 | ||
45 | #define OVERIDEA (1 << 30) | ||
46 | #define OVERIDEA_SHIFT 30 | ||
47 | #define SELA (1 << 21) | ||
48 | #define TERMOSA_CLK (0x1f << 11) | ||
49 | #define TERMOSA_CLK_SHIFT 11 | ||
50 | #define TERMOSA 0x1f | ||
51 | #define TERMOSA_SHIFT 0 | ||
52 | #define CILB_MIPI_CAL_CONFIG 0x18 | ||
53 | #define CILC_MIPI_CAL_CONFIG 0x1c | ||
54 | #define CILD_MIPI_CAL_CONFIG 0x20 | ||
55 | #define CILE_MIPI_CAL_CONFIG 0x24 | ||
56 | #define CILF_MIPI_CAL_CONFIG 0x28 | ||
57 | #define DSIA_MIPI_CAL_CONFIG 0x38 | ||
58 | #define OVERIDEDSIA (1 << 30) | ||
59 | #define OVERIDEDSIA_SHIFT 30 | ||
60 | #define SELDSIA (1 << 21) | ||
61 | #define HSPDOSDSIA (0x1f << 16) | ||
62 | #define HSPDOSDSIA_SHIFT 16 | ||
63 | #define HSPUOSDSIA (0x1f << 8) | ||
64 | #define HSPUOSDSIA_SHIFT 8 | ||
65 | #define TERMOSDSIA 0x1f | ||
66 | #define TERMOSDSIA_SHIFT 0 | ||
67 | #define DSIB_MIPI_CAL_CONFIG 0x3c | ||
68 | #define DSIC_MIPI_CAL_CONFIG 0x40 | ||
69 | #define DSID_MIPI_CAL_CONFIG 0x44 | ||
70 | #define MIPI_BIAS_PAD_CFG0 0x58 | ||
71 | #define E_VCLAMP_REF (1 << 0) | ||
72 | #define E_VCLAMP_REF_SHIFT 0 | ||
73 | #define PDVCLAMP (1 << 1) | ||
74 | #define PDVCLAMP_SHIFT 1 | ||
75 | #define MIPI_BIAS_PAD_CFG1 0x5c | ||
76 | #define PAD_DRIV_UP_REF (0x7 << 8) | ||
77 | #define PAD_DRIV_UP_REF_SHIFT 8 | ||
78 | #define PAD_DRIV_DN_REF (0x7 << 16) | ||
79 | #define PAD_DRIV_DN_REF_SHIFT 16 | ||
80 | #define MIPI_BIAS_PAD_CFG2 0x60 | ||
81 | #define PDVREG (1 << 1) | ||
82 | #define PDVREG_SHIFT 1 | ||
83 | #define PAD_VAUXP_LEVEL (0x7 << 4) | ||
84 | #define PAD_VAUXP_LEVEL_SHIFT 4 | ||
85 | #define PAD_VCLAMP_LEVEL (0x7 << 16) | ||
86 | #define PAD_VCLAMP_LEVEL_SHIFT 16 | ||
87 | #define DSIA_MIPI_CAL_CONFIG_2 0x64 | ||
88 | #define CLKOVERIDEDSIA (1 << 30) | ||
89 | #define CLKOVERIDEDSIA_SHIFT 30 | ||
90 | #define CLKSELDSIA (1 << 21) | ||
91 | #define HSCLKTERMOSDSIA (0x1f << 16) | ||
92 | #define HSCLKTERMOSDSIA_SHIFT 16 | ||
93 | #define HSCLKPDOSDSIA (0x1f << 8) | ||
94 | #define HSCLKPDOSDSIA_SHIFT 8 | ||
95 | #define HSCLKPUOSDSIA 0x1f | ||
96 | #define HSCLKPUOSDSIA_SHIFT 0 | ||
97 | #define DSIB_MIPI_CAL_CONFIG_2 0x68 | ||
98 | #define DSIC_MIPI_CAL_CONFIG_2 0x70 | ||
99 | #define DSID_MIPI_CAL_CONFIG_2 0x74 | ||
diff --git a/drivers/media/platform/tegra/mipical/vmipi/vmipi.c b/drivers/media/platform/tegra/mipical/vmipi/vmipi.c new file mode 100644 index 000000000..ea441c53e --- /dev/null +++ b/drivers/media/platform/tegra/mipical/vmipi/vmipi.c | |||
@@ -0,0 +1,246 @@ | |||
1 | /* | ||
2 | * vmipi.c | ||
3 | * | ||
4 | * Copyright (c) 2017, NVIDIA CORPORATION, All rights reserved. | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | #include <linux/device.h> | ||
17 | #include <linux/of_platform.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/mutex.h> | ||
23 | #include <linux/semaphore.h> | ||
24 | #include <linux/wait.h> | ||
25 | #include <linux/tegra-ivc.h> | ||
26 | |||
27 | #include "mipi_cal.h" | ||
28 | #include "vmipi.h" | ||
29 | |||
30 | const char *tegra_vmipi_cmd[] = { | ||
31 | "TEGRA_VMIPI_CMD_CALIBRATE", | ||
32 | "TEGRA_VMIPI_CMD_BIAS_PAD_ENABLE", | ||
33 | "TEGRA_VMIPI_CMD_BIAS_PAD_DISABLE", | ||
34 | }; | ||
35 | |||
36 | struct tegra_vmipi_ivc_context { | ||
37 | struct device *dev; | ||
38 | struct tegra_hv_ivc_cookie *cookie; | ||
39 | wait_queue_head_t tx_wq; | ||
40 | wait_queue_head_t rx_wq; | ||
41 | struct mutex lock; | ||
42 | }; | ||
43 | static struct tegra_vmipi_ivc_context *ctx; | ||
44 | |||
45 | static int tegra_vmipi_ivc_send(struct tegra_vmipi_cmd_msg *msg, int size) | ||
46 | { | ||
47 | int ret = 0; | ||
48 | |||
49 | if (!tegra_hv_ivc_can_write(ctx->cookie)) { | ||
50 | ret = wait_event_timeout(ctx->tx_wq, | ||
51 | tegra_hv_ivc_can_write(ctx->cookie), | ||
52 | msecs_to_jiffies(500)); | ||
53 | if (!ret) { | ||
54 | dev_err(ctx->dev, | ||
55 | "%s timeout waiting for tx buffer for cmd %s\n", | ||
56 | __func__, tegra_vmipi_cmd[msg->cmd]); | ||
57 | return -ETIMEDOUT; | ||
58 | } | ||
59 | } | ||
60 | |||
61 | ret = tegra_hv_ivc_write(ctx->cookie, msg, size); | ||
62 | if (ret != size) { | ||
63 | dev_err(ctx->dev, | ||
64 | "%s: ivc send incorrect msg size %d for cmd %s\n", | ||
65 | __func__, ret, tegra_vmipi_cmd[msg->cmd]); | ||
66 | return -EIO; | ||
67 | } | ||
68 | |||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | static int tegra_vmipi_ivc_rcv(struct tegra_vmipi_cmd_msg *msg, int size) | ||
73 | { | ||
74 | int ret = 0, len; | ||
75 | |||
76 | if (!tegra_hv_ivc_can_read(ctx->cookie)) { | ||
77 | ret = wait_event_timeout(ctx->rx_wq, | ||
78 | tegra_hv_ivc_can_read(ctx->cookie), | ||
79 | msecs_to_jiffies(500)); | ||
80 | if (!ret) { | ||
81 | dev_err(ctx->dev, | ||
82 | "%s timeout waiting for rx buffer for cmd %s\n", | ||
83 | __func__, tegra_vmipi_cmd[msg->cmd]); | ||
84 | ret = -ETIMEDOUT; | ||
85 | goto out; | ||
86 | } | ||
87 | ret = 0; | ||
88 | } | ||
89 | |||
90 | len = tegra_hv_ivc_read(ctx->cookie, msg, size); | ||
91 | if (len != size) { | ||
92 | dev_err(ctx->dev, | ||
93 | "%s: ivc read incorrect msg size %d for cmd %s\n", | ||
94 | __func__, len, tegra_vmipi_cmd[msg->cmd]); | ||
95 | ret = -EIO; | ||
96 | } | ||
97 | |||
98 | out: | ||
99 | if (tegra_hv_ivc_can_write(ctx->cookie)) | ||
100 | wake_up(&ctx->tx_wq); | ||
101 | |||
102 | return ret ? ret : msg->ret; | ||
103 | } | ||
104 | |||
105 | static irqreturn_t tegra_vmipi_ivc_isr(int irq, void *data) | ||
106 | { | ||
107 | struct tegra_vmipi_ivc_context *ictx = | ||
108 | (struct tegra_vmipi_ivc_context *)data; | ||
109 | |||
110 | if (tegra_hv_ivc_channel_notified(ictx->cookie)) | ||
111 | return IRQ_HANDLED; | ||
112 | |||
113 | wake_up(&ictx->rx_wq); | ||
114 | return IRQ_HANDLED; | ||
115 | } | ||
116 | |||
117 | static int tegra_vmipi_ivc_send_rcv(struct tegra_vmipi_cmd_msg *msg, int size) | ||
118 | { | ||
119 | int err; | ||
120 | |||
121 | if (!msg || !size) | ||
122 | return -EINVAL; | ||
123 | |||
124 | mutex_lock(&ctx->lock); | ||
125 | |||
126 | err = tegra_vmipi_ivc_send(msg, size); | ||
127 | if (err) | ||
128 | goto out; | ||
129 | |||
130 | err = tegra_vmipi_ivc_rcv(msg, size); | ||
131 | |||
132 | out: | ||
133 | mutex_unlock(&ctx->lock); | ||
134 | |||
135 | return err; | ||
136 | } | ||
137 | |||
138 | int tegra_vmipi_calibration(struct tegra_mipi *mipi, int lanes) | ||
139 | { | ||
140 | struct tegra_vmipi_cmd_msg msg; | ||
141 | int size = sizeof(msg); | ||
142 | struct tegra_vmipi_calibrate_params *p; | ||
143 | |||
144 | if (!ctx) | ||
145 | return -EINVAL; | ||
146 | |||
147 | msg.cmd = TEGRA_VMIPI_CMD_CALIBRATE; | ||
148 | p = &msg.params.calibrate; | ||
149 | p->lanes = lanes; | ||
150 | return tegra_vmipi_ivc_send_rcv(&msg, size); | ||
151 | } | ||
152 | |||
153 | int tegra_vmipi_bias_pad_enable(struct tegra_mipi *mipi) | ||
154 | { | ||
155 | struct tegra_vmipi_cmd_msg msg; | ||
156 | int size = sizeof(msg); | ||
157 | |||
158 | if (!ctx) | ||
159 | return -EINVAL; | ||
160 | |||
161 | msg.cmd = TEGRA_VMIPI_CMD_BIAS_PAD_ENABLE; | ||
162 | return tegra_vmipi_ivc_send_rcv(&msg, size); | ||
163 | } | ||
164 | |||
165 | int tegra_vmipi_bias_pad_disable(struct tegra_mipi *mipi) | ||
166 | { | ||
167 | struct tegra_vmipi_cmd_msg msg; | ||
168 | int size = sizeof(msg); | ||
169 | |||
170 | if (!ctx) | ||
171 | return -EINVAL; | ||
172 | |||
173 | msg.cmd = TEGRA_VMIPI_CMD_BIAS_PAD_DISABLE; | ||
174 | return tegra_vmipi_ivc_send_rcv(&msg, size); | ||
175 | } | ||
176 | |||
177 | int tegra_vmipi_init(struct platform_device *pdev) | ||
178 | { | ||
179 | static struct tegra_vmipi_ivc_context *context; | ||
180 | struct device_node *np, *ivcq_np; | ||
181 | struct tegra_hv_ivc_cookie *cookie; | ||
182 | int err, ivcq; | ||
183 | |||
184 | if (!pdev) | ||
185 | return -ENODEV; | ||
186 | |||
187 | context = devm_kzalloc(&pdev->dev, sizeof(*context), GFP_KERNEL); | ||
188 | if (!context) | ||
189 | return -ENOMEM; | ||
190 | |||
191 | context->dev = &pdev->dev; | ||
192 | |||
193 | np = pdev->dev.of_node; | ||
194 | ivcq_np = of_parse_phandle(np, "ivc_queue", 0); | ||
195 | if (!ivcq_np) { | ||
196 | dev_err(&pdev->dev, "Fail to find vmipi ivc queue\n"); | ||
197 | return -ENOMEM; | ||
198 | } | ||
199 | |||
200 | err = of_property_read_u32_index(np, "ivc_queue", 1, &ivcq); | ||
201 | if (err) { | ||
202 | dev_err(&pdev->dev, "Fail to read vmipi ivc queue value\n"); | ||
203 | of_node_put(ivcq_np); | ||
204 | return -EINVAL; | ||
205 | } | ||
206 | of_node_put(ivcq_np); | ||
207 | |||
208 | cookie = tegra_hv_ivc_reserve(ivcq_np, ivcq, NULL); | ||
209 | if (IS_ERR_OR_NULL(cookie)) { | ||
210 | if (cookie == ERR_PTR(-EPROBE_DEFER)) | ||
211 | return -EPROBE_DEFER; | ||
212 | |||
213 | dev_err(&pdev->dev, | ||
214 | "Fail to reserve vmipi ivc queue %d\n", ivcq); | ||
215 | return PTR_ERR(cookie); | ||
216 | } | ||
217 | context->cookie = cookie; | ||
218 | |||
219 | init_waitqueue_head(&context->tx_wq); | ||
220 | init_waitqueue_head(&context->rx_wq); | ||
221 | |||
222 | mutex_init(&context->lock); | ||
223 | |||
224 | tegra_hv_ivc_channel_reset(context->cookie); | ||
225 | |||
226 | err = devm_request_irq(&pdev->dev, cookie->irq, tegra_vmipi_ivc_isr, 0, | ||
227 | "mipi-virt", context); | ||
228 | if (err) { | ||
229 | dev_err(&pdev->dev, "Fail to request vmipi ivc irq %d\n", | ||
230 | cookie->irq); | ||
231 | goto fail; | ||
232 | } | ||
233 | |||
234 | ctx = context; | ||
235 | return 0; | ||
236 | |||
237 | fail: | ||
238 | tegra_hv_ivc_unreserve(context->cookie); | ||
239 | return err; | ||
240 | } | ||
241 | |||
242 | void tegra_vmipi_deinit(void) | ||
243 | { | ||
244 | if (ctx) | ||
245 | tegra_hv_ivc_unreserve(ctx->cookie); | ||
246 | } | ||
diff --git a/drivers/media/platform/tegra/mipical/vmipi/vmipi.h b/drivers/media/platform/tegra/mipical/vmipi/vmipi.h new file mode 100644 index 000000000..694f1ac21 --- /dev/null +++ b/drivers/media/platform/tegra/mipical/vmipi/vmipi.h | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | * vmipi.h | ||
3 | * | ||
4 | * Copyright (c) 2017, NVIDIA CORPORATION, All rights reserved. | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #ifndef VMIPI_H | ||
18 | #define VMIPI_H | ||
19 | |||
20 | struct tegra_mipi; | ||
21 | |||
22 | enum { | ||
23 | TEGRA_VMIPI_CMD_CALIBRATE = 0, | ||
24 | TEGRA_VMIPI_CMD_BIAS_PAD_ENABLE = 1, | ||
25 | TEGRA_VMIPI_CMD_BIAS_PAD_DISABLE = 2, | ||
26 | }; | ||
27 | |||
28 | struct tegra_vmipi_calibrate_params { | ||
29 | u32 lanes; | ||
30 | }; | ||
31 | |||
32 | struct tegra_vmipi_cmd_msg { | ||
33 | u32 cmd; | ||
34 | int ret; | ||
35 | union { | ||
36 | struct tegra_vmipi_calibrate_params calibrate; | ||
37 | } params; | ||
38 | }; | ||
39 | |||
40 | #ifdef CONFIG_TEGRA_MIPI_CAL | ||
41 | int tegra_vmipi_init(struct platform_device *pdev); | ||
42 | void tegra_vmipi_deinit(void); | ||
43 | int tegra_vmipi_bias_pad_enable(struct tegra_mipi *mipi); | ||
44 | int tegra_vmipi_bias_pad_disable(struct tegra_mipi *mipi); | ||
45 | int tegra_vmipi_calibration(struct tegra_mipi *mipi, int lanes); | ||
46 | #else | ||
47 | static inline int tegra_vmipi_init(struct platform_device *pdev) | ||
48 | { | ||
49 | return 0; | ||
50 | } | ||
51 | static inline void tegra_vmipi_init(void) {} | ||
52 | static inline int tegra_vmipi_bias_pad_enable(struct tegra_mipi *mipi) | ||
53 | { | ||
54 | return 0; | ||
55 | } | ||
56 | static inline int tegra_vmipi_bias_pad_disable(struct tegra_mipi *mipi) | ||
57 | { | ||
58 | return 0; | ||
59 | } | ||
60 | static inline int tegra_vmipi_calibration(struct tegra_mipi *mipi, | ||
61 | int lanes) | ||
62 | { | ||
63 | return 0; | ||
64 | } | ||
65 | #endif | ||
66 | #endif | ||
diff --git a/drivers/media/platform/tegra/regmap_util.c b/drivers/media/platform/tegra/regmap_util.c new file mode 100644 index 000000000..c21dcac78 --- /dev/null +++ b/drivers/media/platform/tegra/regmap_util.c | |||
@@ -0,0 +1,173 @@ | |||
1 | /* | ||
2 | * regmap_util.c - utilities for writing regmap tables | ||
3 | * | ||
4 | * Copyright (c) 2013-2016, NVIDIA Corporation. All Rights Reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <linux/regmap.h> | ||
20 | #include <media/camera_common.h> | ||
21 | |||
22 | int | ||
23 | regmap_util_write_table_8(struct regmap *regmap, | ||
24 | const struct reg_8 table[], | ||
25 | const struct reg_8 override_list[], | ||
26 | int num_override_regs, u16 wait_ms_addr, u16 end_addr) | ||
27 | { | ||
28 | int err; | ||
29 | const struct reg_8 *next; | ||
30 | int i; | ||
31 | u8 val; | ||
32 | |||
33 | int range_start = -1; | ||
34 | int range_count = 0; | ||
35 | /* bug 200048392 - | ||
36 | * the vi i2c cannot take a FIFO buffer bigger than 16 bytes | ||
37 | */ | ||
38 | u8 range_vals[16]; | ||
39 | int max_range_vals = ARRAY_SIZE(range_vals); | ||
40 | |||
41 | for (next = table;; next++) { | ||
42 | /* If we have a range open and */ | ||
43 | /* either the address doesn't match */ | ||
44 | /* or the temporary storage is full, flush */ | ||
45 | if ((next->addr != range_start + range_count) || | ||
46 | (next->addr == end_addr) || | ||
47 | (next->addr == wait_ms_addr) || | ||
48 | (range_count == max_range_vals)) { | ||
49 | |||
50 | if (range_count == 1) { | ||
51 | err = | ||
52 | regmap_write(regmap, range_start, | ||
53 | range_vals[0]); | ||
54 | } else if (range_count > 1) { | ||
55 | err = | ||
56 | regmap_bulk_write(regmap, range_start, | ||
57 | &range_vals[0], | ||
58 | range_count); | ||
59 | } | ||
60 | |||
61 | if (err) { | ||
62 | pr_err("%s:regmap_util_write_table:%d", | ||
63 | __func__, err); | ||
64 | return err; | ||
65 | } | ||
66 | |||
67 | range_start = -1; | ||
68 | range_count = 0; | ||
69 | |||
70 | /* Handle special address values */ | ||
71 | if (next->addr == end_addr) | ||
72 | break; | ||
73 | |||
74 | if (next->addr == wait_ms_addr) { | ||
75 | msleep_range(next->val); | ||
76 | continue; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | val = next->val; | ||
81 | |||
82 | /* When an override list is passed in, replace the reg */ | ||
83 | /* value to write if the reg is in the list */ | ||
84 | if (override_list) { | ||
85 | for (i = 0; i < num_override_regs; i++) { | ||
86 | if (next->addr == override_list[i].addr) { | ||
87 | val = override_list[i].val; | ||
88 | break; | ||
89 | } | ||
90 | } | ||
91 | } | ||
92 | |||
93 | if (range_start == -1) | ||
94 | range_start = next->addr; | ||
95 | |||
96 | range_vals[range_count++] = val; | ||
97 | } | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | int | ||
102 | regmap_util_write_table_16_as_8(struct regmap *regmap, | ||
103 | const struct reg_16 table[], | ||
104 | const struct reg_16 override_list[], | ||
105 | int num_override_regs, | ||
106 | u16 wait_ms_addr, u16 end_addr) | ||
107 | { | ||
108 | int err; | ||
109 | const struct reg_16 *next; | ||
110 | int i; | ||
111 | u16 val; | ||
112 | |||
113 | int range_start = -1; | ||
114 | int range_count = 0; | ||
115 | u8 range_vals[256]; | ||
116 | int max_range_vals = ARRAY_SIZE(range_vals); | ||
117 | |||
118 | for (next = table;; next++) { | ||
119 | /* If we have a range open and */ | ||
120 | /* either the address doesn't match */ | ||
121 | /* or the temporary storage is full, flush*/ | ||
122 | if ((next->addr != range_start + range_count) || | ||
123 | (next->addr == end_addr) || | ||
124 | (next->addr == wait_ms_addr) || | ||
125 | (range_count == max_range_vals)) { | ||
126 | |||
127 | if (range_count > 1) { | ||
128 | err = | ||
129 | regmap_bulk_write(regmap, range_start, | ||
130 | &range_vals[0], | ||
131 | range_count); | ||
132 | } | ||
133 | |||
134 | if (err) { | ||
135 | pr_err("%s:regmap_util_write_table:%d", | ||
136 | __func__, err); | ||
137 | return err; | ||
138 | } | ||
139 | |||
140 | range_start = -1; | ||
141 | range_count = 0; | ||
142 | |||
143 | /* Handle special address values */ | ||
144 | if (next->addr == end_addr) | ||
145 | break; | ||
146 | |||
147 | if (next->addr == wait_ms_addr) { | ||
148 | msleep_range(next->val); | ||
149 | continue; | ||
150 | } | ||
151 | } | ||
152 | |||
153 | val = next->val; | ||
154 | |||
155 | /* When an override list is passed in, replace the reg */ | ||
156 | /* value to write if the reg is in the list */ | ||
157 | if (override_list) { | ||
158 | for (i = 0; i < num_override_regs; i++) { | ||
159 | if (next->addr == override_list[i].addr) { | ||
160 | val = override_list[i].val; | ||
161 | break; | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | |||
166 | if (range_start == -1) | ||
167 | range_start = next->addr; | ||
168 | |||
169 | range_vals[range_count++] = (u8) (val >> 8); | ||
170 | range_vals[range_count++] = (u8) (val & 0xFF); | ||
171 | } | ||
172 | return 0; | ||
173 | } | ||
diff --git a/drivers/media/platform/tegra/tpg/Makefile b/drivers/media/platform/tegra/tpg/Makefile new file mode 100644 index 000000000..135473166 --- /dev/null +++ b/drivers/media/platform/tegra/tpg/Makefile | |||
@@ -0,0 +1,14 @@ | |||
1 | GCOV_PROFILE := y | ||
2 | ccflags-y += -I../nvhost/drivers/video/tegra/host | ||
3 | ccflags-y += -Idrivers/media/platform/tegra | ||
4 | ccflags-y += -Werror | ||
5 | |||
6 | ifeq ($(CONFIG_ARCH_TEGRA_18x_SOC),y) | ||
7 | ccflags-y += -I../t18x/drivers/video/tegra/host | ||
8 | nvhost-vi-tpg-objs += tpg_t18x.o | ||
9 | else | ||
10 | nvhost-vi-tpg-objs += tpg_t21x.o | ||
11 | endif | ||
12 | |||
13 | |||
14 | obj-$(CONFIG_VIDEO_TEGRA_VI_TPG) += nvhost-vi-tpg.o | ||
diff --git a/drivers/media/platform/tegra/tpg/tpg_t18x.c b/drivers/media/platform/tegra/tpg/tpg_t18x.c new file mode 100644 index 000000000..539d9b4de --- /dev/null +++ b/drivers/media/platform/tegra/tpg/tpg_t18x.c | |||
@@ -0,0 +1,199 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/host/tpg/tpg.c | ||
3 | * | ||
4 | * Tegra VI test pattern generator driver | ||
5 | * | ||
6 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms and conditions of the GNU General Public License, | ||
10 | * version 2, as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/export.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/debugfs.h> | ||
24 | |||
25 | #include "camera/vi/mc_common.h" | ||
26 | #include "camera/csi/csi.h" | ||
27 | #include "vi/vi4.h" | ||
28 | #include "nvcsi/nvcsi.h" | ||
29 | #include "host1x/host1x.h" | ||
30 | |||
31 | /* PG generate 1 pixel per nvcsi_clk: | ||
32 | * ((width + hblank) * height + vblank) * fps = nvcsi_clk_freq | ||
33 | * | ||
34 | */ | ||
35 | const struct tpg_frmfmt tegra18x_csi_tpg_frmfmt[] = { | ||
36 | {{1280, 720}, V4L2_PIX_FMT_SRGGB10, 120, 750, 0xffff}, | ||
37 | {{1920, 1080}, V4L2_PIX_FMT_SRGGB10, 60, 930, 0xffff}, | ||
38 | {{3840, 2160}, V4L2_PIX_FMT_SRGGB10, 20, 900, 0xffff}, | ||
39 | {{1280, 720}, V4L2_PIX_FMT_RGB32, 60, 3351, 0xffff}, | ||
40 | {{1920, 1080}, V4L2_PIX_FMT_RGB32, 30, 4315, 0xffff}, | ||
41 | {{3840, 2160}, V4L2_PIX_FMT_RGB32, 20, 851, 0xffff}, | ||
42 | }; | ||
43 | |||
44 | #define TPG_PORT_IDX 0 | ||
45 | |||
46 | static int tpg_debugfs_height_show(void *data, u64 *val) | ||
47 | { | ||
48 | struct tegra_csi_channel *chan = data; | ||
49 | struct tegra_csi_port *port = &chan->ports[TPG_PORT_IDX]; | ||
50 | |||
51 | mutex_lock(&chan->format_lock); | ||
52 | *val = port->format.height; | ||
53 | mutex_unlock(&chan->format_lock); | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static int tpg_debugfs_height_write(void *data, u64 val) | ||
59 | { | ||
60 | struct tegra_csi_channel *chan = data; | ||
61 | struct tegra_csi_device *csi = chan->csi; | ||
62 | struct tegra_csi_port *port = &chan->ports[TPG_PORT_IDX]; | ||
63 | |||
64 | mutex_lock(&chan->format_lock); | ||
65 | port->format.height = val; | ||
66 | mutex_unlock(&chan->format_lock); | ||
67 | |||
68 | if (csi->fops->csi_override_format) | ||
69 | csi->fops->csi_override_format(chan, TPG_PORT_IDX); | ||
70 | |||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | DEFINE_SIMPLE_ATTRIBUTE(tpg_debugfs_height_fops, | ||
75 | tpg_debugfs_height_show, | ||
76 | tpg_debugfs_height_write, | ||
77 | "%lld\n"); | ||
78 | |||
79 | static int tpg_debugfs_width_show(void *data, u64 *val) | ||
80 | { | ||
81 | struct tegra_csi_channel *chan = data; | ||
82 | struct tegra_csi_port *port = &chan->ports[TPG_PORT_IDX]; | ||
83 | |||
84 | mutex_lock(&chan->format_lock); | ||
85 | *val = port->format.width; | ||
86 | mutex_unlock(&chan->format_lock); | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static int tpg_debugfs_width_write(void *data, u64 val) | ||
92 | { | ||
93 | struct tegra_csi_channel *chan = data; | ||
94 | struct tegra_csi_device *csi = chan->csi; | ||
95 | struct tegra_csi_port *port = &chan->ports[TPG_PORT_IDX]; | ||
96 | |||
97 | mutex_lock(&chan->format_lock); | ||
98 | port->format.width = val; | ||
99 | mutex_unlock(&chan->format_lock); | ||
100 | |||
101 | if (csi->fops->csi_override_format) | ||
102 | csi->fops->csi_override_format(chan, TPG_PORT_IDX); | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | DEFINE_SIMPLE_ATTRIBUTE(tpg_debugfs_width_fops, | ||
108 | tpg_debugfs_width_show, | ||
109 | tpg_debugfs_width_write, | ||
110 | "%lld\n"); | ||
111 | |||
112 | |||
113 | static void tpg_remove_debugfs(struct tegra_csi_device *csi) | ||
114 | { | ||
115 | debugfs_remove_recursive(csi->debugdir); | ||
116 | csi->debugdir = NULL; | ||
117 | } | ||
118 | |||
119 | static int tpg_create_debugfs(struct tegra_csi_device *csi) | ||
120 | { | ||
121 | struct dentry *dir; | ||
122 | struct tegra_csi_channel *chan; | ||
123 | |||
124 | csi->debugdir = dir = debugfs_create_dir("tpg", NULL); | ||
125 | if (dir == NULL) | ||
126 | return -ENOMEM; | ||
127 | |||
128 | list_for_each_entry(chan, &csi->csi_chans, list) { | ||
129 | const struct tegra_channel *vi_chan = | ||
130 | v4l2_get_subdev_hostdata(&chan->subdev); | ||
131 | if (vi_chan->pg_mode) { | ||
132 | const char *name = vi_chan->video.name; | ||
133 | |||
134 | dev_dbg(csi->dev, "debugfs node installed %s\n", name); | ||
135 | dir = debugfs_create_dir(name, csi->debugdir); | ||
136 | if (!dir) | ||
137 | goto error; | ||
138 | |||
139 | if (!debugfs_create_file("height", S_IRUGO | S_IWUSR, | ||
140 | dir, chan, | ||
141 | &tpg_debugfs_height_fops)) | ||
142 | goto error; | ||
143 | if (!debugfs_create_file("width", S_IRUGO | S_IWUSR, | ||
144 | dir, chan, | ||
145 | &tpg_debugfs_width_fops)) | ||
146 | goto error; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | return 0; | ||
151 | error: | ||
152 | tpg_remove_debugfs(csi); | ||
153 | return -ENOMEM; | ||
154 | } | ||
155 | |||
156 | static int __init tpg_probe_t18x(void) | ||
157 | { | ||
158 | struct tegra_csi_device *mc_csi = tegra_get_mc_csi(); | ||
159 | struct tegra_mc_vi *mc_vi = tegra_get_mc_vi(); | ||
160 | int err; | ||
161 | |||
162 | dev_info(mc_csi->dev, "%s\n", __func__); | ||
163 | mc_vi->csi = mc_csi; | ||
164 | /* Init CSI related media controller interface */ | ||
165 | mc_csi->tpg_frmfmt_table = tegra18x_csi_tpg_frmfmt; | ||
166 | mc_csi->tpg_frmfmt_table_size = ARRAY_SIZE(tegra18x_csi_tpg_frmfmt); | ||
167 | err = tpg_csi_media_controller_init(mc_csi, TEGRA_VI_PG_PATCH); | ||
168 | if (err) | ||
169 | return -EINVAL; | ||
170 | err = tpg_vi_media_controller_init(mc_vi, TEGRA_VI_PG_PATCH); | ||
171 | if (err) | ||
172 | goto vi_init_err; | ||
173 | |||
174 | err = tpg_create_debugfs(mc_csi); | ||
175 | if (err) | ||
176 | goto debugfs_init_err; | ||
177 | |||
178 | return err; | ||
179 | debugfs_init_err: | ||
180 | tpg_remove_debugfs(mc_csi); | ||
181 | vi_init_err: | ||
182 | tpg_csi_media_controller_cleanup(mc_csi); | ||
183 | dev_err(mc_csi->dev, "%s error\n", __func__); | ||
184 | return err; | ||
185 | } | ||
186 | static void __exit tpg_remove_t18x(void) | ||
187 | { | ||
188 | struct tegra_csi_device *mc_csi = tegra_get_mc_csi(); | ||
189 | struct tegra_mc_vi *mc_vi = tegra_get_mc_vi(); | ||
190 | |||
191 | dev_info(mc_csi->dev, "%s\n", __func__); | ||
192 | tpg_remove_debugfs(mc_csi); | ||
193 | tpg_csi_media_controller_cleanup(mc_csi); | ||
194 | tpg_vi_media_controller_cleanup(mc_vi); | ||
195 | } | ||
196 | |||
197 | module_init(tpg_probe_t18x); | ||
198 | module_exit(tpg_remove_t18x); | ||
199 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/platform/tegra/tpg/tpg_t21x.c b/drivers/media/platform/tegra/tpg/tpg_t21x.c new file mode 100644 index 000000000..6291d0209 --- /dev/null +++ b/drivers/media/platform/tegra/tpg/tpg_t21x.c | |||
@@ -0,0 +1,210 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/host/tpg/tpg.c | ||
3 | * | ||
4 | * Tegra VI test pattern generator driver | ||
5 | * | ||
6 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms and conditions of the GNU General Public License, | ||
10 | * version 2, as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/export.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/debugfs.h> | ||
24 | |||
25 | #include "camera/vi/mc_common.h" | ||
26 | #include "camera/csi/csi.h" | ||
27 | #include "vi/vi.h" | ||
28 | #include "host1x/host1x.h" | ||
29 | |||
30 | /* | ||
31 | * total_cycles_per_lane for one second = pll_d freq / 8 | ||
32 | * width_in_bytes = ((width * bpp) / 8) | ||
33 | * cycles_per_line = width_in_bytes + hblank | ||
34 | * cycles_per_image = (cycles_per_line * height) + vblank | ||
35 | * image_cycles_per_lane = cycles_per_image / numlanes | ||
36 | * framerate = total_cycles_per_lane / image_cycles_per_lane | ||
37 | * As per IAS maximum overhead of ~15% can occur | ||
38 | * hblank and vblank are tuned to consider overhead during capture | ||
39 | * e.g. for 1920x1080, RAW 10 and two lane TPG | ||
40 | * cycles_per_lane = (((((1920 * 10)/8) + 512) * 1080) + 8) / 2 ~ 1572480 | ||
41 | * framerate = ((927000000 / 8) / 1572480) ~ 73fps | ||
42 | * Max overhead of 15% results in minimum of 62fps (max can be 73fps) | ||
43 | * Note: with changing resolution, bpp and hblank overhead % varies. | ||
44 | */ | ||
45 | |||
46 | static struct tpg_frmfmt tegra21x_csi_tpg_frmfmt[] = { | ||
47 | {{1280, 720}, V4L2_PIX_FMT_SRGGB10, 120, 512, 8}, | ||
48 | {{1920, 1080}, V4L2_PIX_FMT_SRGGB10, 60, 512, 8}, | ||
49 | {{3840, 2160}, V4L2_PIX_FMT_SRGGB10, 20, 8, 8}, | ||
50 | {{1280, 720}, V4L2_PIX_FMT_RGB32, 60, 512, 8}, | ||
51 | {{1920, 1080}, V4L2_PIX_FMT_RGB32, 30, 512, 8}, | ||
52 | {{3840, 2160}, V4L2_PIX_FMT_RGB32, 8, 8, 8}, | ||
53 | }; | ||
54 | |||
55 | #define TPG_PORT_IDX 0 | ||
56 | |||
57 | static int tpg_debugfs_height_show(void *data, u64 *val) | ||
58 | { | ||
59 | struct tegra_csi_channel *chan = data; | ||
60 | struct tegra_csi_port *port = &chan->ports[TPG_PORT_IDX]; | ||
61 | |||
62 | mutex_lock(&chan->format_lock); | ||
63 | *val = port->format.height; | ||
64 | mutex_unlock(&chan->format_lock); | ||
65 | |||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static int tpg_debugfs_height_write(void *data, u64 val) | ||
70 | { | ||
71 | struct tegra_csi_channel *chan = data; | ||
72 | struct tegra_csi_device *csi = chan->csi; | ||
73 | struct tegra_csi_port *port = &chan->ports[TPG_PORT_IDX]; | ||
74 | |||
75 | mutex_lock(&chan->format_lock); | ||
76 | port->format.height = val; | ||
77 | mutex_unlock(&chan->format_lock); | ||
78 | |||
79 | if (csi->fops->csi_override_format) | ||
80 | csi->fops->csi_override_format(chan, TPG_PORT_IDX); | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | DEFINE_SIMPLE_ATTRIBUTE(tpg_debugfs_height_fops, | ||
86 | tpg_debugfs_height_show, | ||
87 | tpg_debugfs_height_write, | ||
88 | "%lld\n"); | ||
89 | |||
90 | static int tpg_debugfs_width_show(void *data, u64 *val) | ||
91 | { | ||
92 | struct tegra_csi_channel *chan = data; | ||
93 | struct tegra_csi_port *port = &chan->ports[TPG_PORT_IDX]; | ||
94 | |||
95 | mutex_lock(&chan->format_lock); | ||
96 | *val = port->format.width; | ||
97 | mutex_unlock(&chan->format_lock); | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int tpg_debugfs_width_write(void *data, u64 val) | ||
103 | { | ||
104 | struct tegra_csi_channel *chan = data; | ||
105 | struct tegra_csi_device *csi = chan->csi; | ||
106 | struct tegra_csi_port *port = &chan->ports[TPG_PORT_IDX]; | ||
107 | |||
108 | mutex_lock(&chan->format_lock); | ||
109 | port->format.width = val; | ||
110 | mutex_unlock(&chan->format_lock); | ||
111 | |||
112 | if (csi->fops->csi_override_format) | ||
113 | csi->fops->csi_override_format(chan, TPG_PORT_IDX); | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | DEFINE_SIMPLE_ATTRIBUTE(tpg_debugfs_width_fops, | ||
119 | tpg_debugfs_width_show, | ||
120 | tpg_debugfs_width_write, | ||
121 | "%lld\n"); | ||
122 | |||
123 | |||
124 | static void tpg_remove_debugfs(struct tegra_csi_device *csi) | ||
125 | { | ||
126 | debugfs_remove_recursive(csi->debugdir); | ||
127 | csi->debugdir = NULL; | ||
128 | } | ||
129 | |||
130 | static int tpg_create_debugfs(struct tegra_csi_device *csi) | ||
131 | { | ||
132 | struct dentry *dir; | ||
133 | struct tegra_csi_channel *chan; | ||
134 | |||
135 | csi->debugdir = dir = debugfs_create_dir("tpg", NULL); | ||
136 | if (dir == NULL) | ||
137 | return -ENOMEM; | ||
138 | |||
139 | list_for_each_entry(chan, &csi->csi_chans, list) { | ||
140 | const struct tegra_channel *vi_chan = | ||
141 | v4l2_get_subdev_hostdata(&chan->subdev); | ||
142 | if (vi_chan->pg_mode) { | ||
143 | const char *name = vi_chan->video.name; | ||
144 | |||
145 | dev_dbg(csi->dev, "debugfs node installed %s\n", name); | ||
146 | dir = debugfs_create_dir(name, csi->debugdir); | ||
147 | if (!dir) | ||
148 | goto error; | ||
149 | |||
150 | if (!debugfs_create_file("height", S_IRUGO | S_IWUSR, | ||
151 | dir, chan, | ||
152 | &tpg_debugfs_height_fops)) | ||
153 | goto error; | ||
154 | if (!debugfs_create_file("width", S_IRUGO | S_IWUSR, | ||
155 | dir, chan, | ||
156 | &tpg_debugfs_width_fops)) | ||
157 | goto error; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | return 0; | ||
162 | error: | ||
163 | tpg_remove_debugfs(csi); | ||
164 | return -ENOMEM; | ||
165 | } | ||
166 | |||
167 | static int __init tpg_probe_t21x(void) | ||
168 | { | ||
169 | struct tegra_csi_device *mc_csi = &(tegra_vi_get()->csi); | ||
170 | struct tegra_mc_vi *mc_vi = &(tegra_vi_get()->mc_vi); | ||
171 | int err; | ||
172 | |||
173 | dev_info(mc_csi->dev, "%s\n", __func__); | ||
174 | mc_vi->csi = mc_csi; | ||
175 | /* Init CSI related media controller interface */ | ||
176 | mc_csi->tpg_frmfmt_table = tegra21x_csi_tpg_frmfmt; | ||
177 | mc_csi->tpg_frmfmt_table_size = ARRAY_SIZE(tegra21x_csi_tpg_frmfmt); | ||
178 | err = tpg_csi_media_controller_init(mc_csi, TEGRA_VI_PG_PATCH); | ||
179 | if (err) | ||
180 | return -EINVAL; | ||
181 | err = tpg_vi_media_controller_init(mc_vi, TEGRA_VI_PG_PATCH); | ||
182 | if (err) | ||
183 | goto vi_init_err; | ||
184 | |||
185 | err = tpg_create_debugfs(mc_csi); | ||
186 | if (err) | ||
187 | goto debugfs_init_err; | ||
188 | |||
189 | return err; | ||
190 | debugfs_init_err: | ||
191 | tpg_remove_debugfs(mc_csi); | ||
192 | vi_init_err: | ||
193 | tpg_csi_media_controller_cleanup(mc_csi); | ||
194 | dev_err(mc_csi->dev, "%s error\n", __func__); | ||
195 | return err; | ||
196 | } | ||
197 | static void __exit tpg_remove_t21x(void) | ||
198 | { | ||
199 | struct tegra_csi_device *mc_csi = &(tegra_vi_get()->csi); | ||
200 | struct tegra_mc_vi *mc_vi = &(tegra_vi_get()->mc_vi); | ||
201 | |||
202 | dev_info(mc_csi->dev, "%s\n", __func__); | ||
203 | tpg_remove_debugfs(mc_csi); | ||
204 | tpg_csi_media_controller_cleanup(mc_csi); | ||
205 | tpg_vi_media_controller_cleanup(mc_vi); | ||
206 | } | ||
207 | |||
208 | module_init(tpg_probe_t21x); | ||
209 | module_exit(tpg_remove_t21x); | ||
210 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/platform/tegra/vi/Makefile b/drivers/media/platform/tegra/vi/Makefile new file mode 100644 index 000000000..6cd9767ea --- /dev/null +++ b/drivers/media/platform/tegra/vi/Makefile | |||
@@ -0,0 +1,17 @@ | |||
1 | GCOV_PROFILE := y | ||
2 | ccflags-y += -I../nvhost/drivers/video/tegra/host | ||
3 | ccflags-y += -Idrivers/video/tegra/camera | ||
4 | ccflags-y += -Idrivers/media/platform/tegra/ | ||
5 | ccflags-y += -Werror | ||
6 | |||
7 | ifeq ($(CONFIG_ARCH_TEGRA_18x_SOC),y) | ||
8 | ccflags-y += -I../t18x/drivers/video/tegra/host/ | ||
9 | endif | ||
10 | |||
11 | ifneq (,$(filter $(CONFIG_VIDEO_TEGRA_VI),y m)) | ||
12 | obj-y += vi_irq.o | ||
13 | obj-y += tegra_vi.o | ||
14 | endif | ||
15 | |||
16 | nvhost-vi-objs += vi.o | ||
17 | obj-$(CONFIG_VIDEO_TEGRA_VI) += nvhost-vi.o | ||
diff --git a/drivers/media/platform/tegra/vi/tegra_vi.c b/drivers/media/platform/tegra/vi/tegra_vi.c new file mode 100644 index 000000000..4d2e3b714 --- /dev/null +++ b/drivers/media/platform/tegra/vi/tegra_vi.c | |||
@@ -0,0 +1,515 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2013-2016, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #include <linux/fs.h> | ||
18 | #include <linux/file.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/nvhost.h> | ||
22 | #include <linux/nvhost_vi_ioctl.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/regulator/consumer.h> | ||
25 | #include <linux/uaccess.h> | ||
26 | #include <linux/clk.h> | ||
27 | |||
28 | #include <linux/platform/tegra/latency_allowance.h> | ||
29 | |||
30 | #include "bus_client.h" | ||
31 | #include "nvhost_acm.h" | ||
32 | #include "chip_support.h" | ||
33 | #include "host1x/host1x.h" | ||
34 | #include "vi/vi.h" | ||
35 | #include "vi/vi_irq.h" | ||
36 | |||
37 | #define T12_VI_CFG_CG_CTRL 0xb8 | ||
38 | #define T12_CG_2ND_LEVEL_EN 1 | ||
39 | #define T12_VI_CSI_0_SW_RESET 0x100 | ||
40 | #define T12_CSI_CSI_SW_SENSOR_A_RESET 0x858 | ||
41 | #define T12_CSI_CSICIL_SW_SENSOR_A_RESET 0x94c | ||
42 | #define T12_VI_CSI_0_CSI_IMAGE_DT 0x120 | ||
43 | |||
44 | #define T12_VI_CSI_1_SW_RESET 0x200 | ||
45 | #define T12_CSI_CSI_SW_SENSOR_B_RESET 0x88c | ||
46 | #define T12_CSI_CSICIL_SW_SENSOR_B_RESET 0x980 | ||
47 | #define T12_VI_CSI_1_CSI_IMAGE_DT 0x220 | ||
48 | |||
49 | #define T21_CSI_CILA_PAD_CONFIG0 0x92c | ||
50 | #define T21_CSI1_CILA_PAD_CONFIG0 0x112c | ||
51 | #define T21_CSI2_CILA_PAD_CONFIG0 0x192c | ||
52 | |||
53 | #define VI_MAX_BPP 2 | ||
54 | |||
55 | int nvhost_vi_finalize_poweron(struct platform_device *dev) | ||
56 | { | ||
57 | struct vi *tegra_vi = nvhost_get_private_data(dev); | ||
58 | int ret = 0; | ||
59 | |||
60 | if (!tegra_vi) | ||
61 | return -EINVAL; | ||
62 | |||
63 | if (tegra_vi->reg) { | ||
64 | ret = regulator_enable(tegra_vi->reg); | ||
65 | if (ret) { | ||
66 | dev_err(&dev->dev, | ||
67 | "%s: enable csi regulator failed.\n", | ||
68 | __func__); | ||
69 | return ret; | ||
70 | } | ||
71 | } | ||
72 | |||
73 | #ifdef CONFIG_ARCH_TEGRA_12x_SOC | ||
74 | /* Only do this for vi.0 not for slave device vi.1 */ | ||
75 | if (dev->id == 0) | ||
76 | host1x_writel(dev, T12_VI_CFG_CG_CTRL, T12_CG_2ND_LEVEL_EN); | ||
77 | #endif | ||
78 | |||
79 | ret = vi_enable_irq(tegra_vi); | ||
80 | if (ret) | ||
81 | dev_err(&tegra_vi->ndev->dev, "%s: vi_enable_irq failed\n", | ||
82 | __func__); | ||
83 | |||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | int nvhost_vi_prepare_poweroff(struct platform_device *dev) | ||
88 | { | ||
89 | int ret = 0; | ||
90 | struct vi *tegra_vi = nvhost_get_private_data(dev); | ||
91 | |||
92 | if (!tegra_vi) | ||
93 | return -EINVAL; | ||
94 | |||
95 | ret = vi_disable_irq(tegra_vi); | ||
96 | if (ret) { | ||
97 | dev_err(&tegra_vi->ndev->dev, "%s: vi_disable_irq failed\n", | ||
98 | __func__); | ||
99 | return ret; | ||
100 | } | ||
101 | |||
102 | if (tegra_vi->reg) { | ||
103 | ret = regulator_disable(tegra_vi->reg); | ||
104 | if (ret) | ||
105 | dev_err(&dev->dev, | ||
106 | "%s: disable csi regulator failed.\n", | ||
107 | __func__); | ||
108 | } | ||
109 | |||
110 | return ret; | ||
111 | } | ||
112 | |||
113 | #if defined(CONFIG_TEGRA_ISOMGR) | ||
114 | static int vi_isomgr_register(struct vi *tegra_vi) | ||
115 | { | ||
116 | int iso_client_id = TEGRA_ISO_CLIENT_VI_0; | ||
117 | struct clk *vi_clk; | ||
118 | struct nvhost_device_data *pdata = | ||
119 | platform_get_drvdata(tegra_vi->ndev); | ||
120 | |||
121 | dev_dbg(&tegra_vi->ndev->dev, "%s++\n", __func__); | ||
122 | |||
123 | if (WARN_ONCE(pdata == NULL, "pdata not found, %s failed\n", __func__)) | ||
124 | return -ENODEV; | ||
125 | |||
126 | /* Get max VI BW */ | ||
127 | vi_clk = pdata->clk[0]; | ||
128 | tegra_vi->max_bw = | ||
129 | (clk_round_rate(vi_clk, UINT_MAX) / 1000) * VI_MAX_BPP; | ||
130 | |||
131 | /* Register with max possible BW in VI usecases.*/ | ||
132 | tegra_vi->isomgr_handle = tegra_isomgr_register(iso_client_id, | ||
133 | tegra_vi->max_bw, | ||
134 | NULL, /* tegra_isomgr_renegotiate */ | ||
135 | NULL); /* *priv */ | ||
136 | |||
137 | if (!tegra_vi->isomgr_handle) { | ||
138 | dev_err(&tegra_vi->ndev->dev, "%s: unable to register isomgr\n", | ||
139 | __func__); | ||
140 | return -ENOMEM; | ||
141 | } | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | static int vi_set_isomgr_request(struct vi *tegra_vi, uint vi_bw, uint lt) | ||
147 | { | ||
148 | int ret = 0; | ||
149 | |||
150 | dev_dbg(&tegra_vi->ndev->dev, | ||
151 | "%s++ bw=%u, lt=%u\n", __func__, vi_bw, lt); | ||
152 | |||
153 | /* return value of tegra_isomgr_reserve is dvfs latency in usec */ | ||
154 | ret = tegra_isomgr_reserve(tegra_vi->isomgr_handle, | ||
155 | vi_bw, /* KB/sec */ | ||
156 | lt); /* usec */ | ||
157 | if (!ret) { | ||
158 | dev_err(&tegra_vi->ndev->dev, | ||
159 | "%s: failed to reserve %u KBps\n", __func__, vi_bw); | ||
160 | return -ENOMEM; | ||
161 | } | ||
162 | |||
163 | /* return value of tegra_isomgr_realize is dvfs latency in usec */ | ||
164 | ret = tegra_isomgr_realize(tegra_vi->isomgr_handle); | ||
165 | if (ret) | ||
166 | dev_dbg(&tegra_vi->ndev->dev, | ||
167 | "%s: tegra_vi isomgr latency is %d usec", | ||
168 | __func__, ret); | ||
169 | else { | ||
170 | dev_err(&tegra_vi->ndev->dev, | ||
171 | "%s: failed to realize %u KBps\n", __func__, vi_bw); | ||
172 | return -ENOMEM; | ||
173 | } | ||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static int vi_isomgr_release(struct vi *tegra_vi) | ||
178 | { | ||
179 | int ret = 0; | ||
180 | |||
181 | dev_dbg(&tegra_vi->ndev->dev, "%s++\n", __func__); | ||
182 | |||
183 | /* deallocate isomgr bw */ | ||
184 | ret = vi_set_isomgr_request(tegra_vi, 0, 0); | ||
185 | if (ret) { | ||
186 | dev_err(&tegra_vi->ndev->dev, | ||
187 | "%s: failed to deallocate memory in isomgr\n", | ||
188 | __func__); | ||
189 | return -ENOMEM; | ||
190 | } | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | #endif | ||
195 | |||
196 | static int vi_set_la(u32 vi_bw) | ||
197 | { | ||
198 | int ret = 0; | ||
199 | |||
200 | #ifdef CONFIG_TEGRA_MC | ||
201 | ret = tegra_set_camera_ptsa(TEGRA_LA_VI_W, vi_bw, 1); | ||
202 | |||
203 | if (!ret) { | ||
204 | ret = tegra_set_latency_allowance(TEGRA_LA_VI_W, | ||
205 | vi_bw); | ||
206 | |||
207 | if (ret) | ||
208 | pr_err("%s: set latency failed: %d\n", | ||
209 | __func__, ret); | ||
210 | } else { | ||
211 | pr_err("%s: set ptsa failed: %d\n", __func__, ret); | ||
212 | } | ||
213 | #endif | ||
214 | |||
215 | return ret; | ||
216 | } | ||
217 | |||
218 | int vi_v4l2_set_la(struct vi *tegra_vi, u32 vi_bypass_bw, bool is_ioctl) | ||
219 | { | ||
220 | int ret = 0; | ||
221 | unsigned long total_bw; | ||
222 | |||
223 | mutex_lock(&tegra_vi->update_la_lock); | ||
224 | if (is_ioctl) | ||
225 | tegra_vi->vi_bypass_bw = vi_bypass_bw; | ||
226 | total_bw = tegra_vi->mc_vi.aggregated_kbyteps + tegra_vi->vi_bypass_bw; | ||
227 | ret = vi_set_la(total_bw); | ||
228 | mutex_unlock(&tegra_vi->update_la_lock); | ||
229 | return ret; | ||
230 | } | ||
231 | EXPORT_SYMBOL(vi_v4l2_set_la); | ||
232 | |||
233 | static long vi_ioctl(struct file *file, | ||
234 | unsigned int cmd, unsigned long arg) | ||
235 | { | ||
236 | struct vi *tegra_vi = file->private_data; | ||
237 | |||
238 | if (_IOC_TYPE(cmd) != NVHOST_VI_IOCTL_MAGIC) | ||
239 | return -EFAULT; | ||
240 | |||
241 | switch (_IOC_NR(cmd)) { | ||
242 | case _IOC_NR(NVHOST_VI_IOCTL_ENABLE_TPG): { | ||
243 | uint enable; | ||
244 | int ret; | ||
245 | struct clk *clk; | ||
246 | |||
247 | if (copy_from_user(&enable, | ||
248 | (const void __user *)arg, sizeof(uint))) { | ||
249 | dev_err(&tegra_vi->ndev->dev, | ||
250 | "%s: Failed to copy arg from user\n", __func__); | ||
251 | return -EFAULT; | ||
252 | } | ||
253 | |||
254 | clk = clk_get(NULL, "pll_d"); | ||
255 | if (IS_ERR(clk)) | ||
256 | return -EINVAL; | ||
257 | |||
258 | if (enable) | ||
259 | ret = tegra_clk_cfg_ex(clk, | ||
260 | TEGRA_CLK_PLLD_CSI_OUT_ENB, 1); | ||
261 | else | ||
262 | ret = tegra_clk_cfg_ex(clk, | ||
263 | TEGRA_CLK_MIPI_CSI_OUT_ENB, 1); | ||
264 | clk_put(clk); | ||
265 | |||
266 | return ret; | ||
267 | } | ||
268 | case _IOC_NR(NVHOST_VI_IOCTL_GET_VI_CLK): { | ||
269 | int ret; | ||
270 | u64 vi_clk_rate = 0; | ||
271 | |||
272 | ret = nvhost_module_get_rate(tegra_vi->ndev, | ||
273 | (unsigned long *)&vi_clk_rate, 0); | ||
274 | if (ret) { | ||
275 | dev_err(&tegra_vi->ndev->dev, | ||
276 | "%s: failed to get vi clk\n", | ||
277 | __func__); | ||
278 | return ret; | ||
279 | } | ||
280 | |||
281 | if (copy_to_user((void __user *)arg, | ||
282 | &vi_clk_rate, sizeof(vi_clk_rate))) { | ||
283 | dev_err(&tegra_vi->ndev->dev, | ||
284 | "%s:Failed to copy vi clk rate to user\n", | ||
285 | __func__); | ||
286 | return -EFAULT; | ||
287 | } | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | case _IOC_NR(NVHOST_VI_IOCTL_SET_VI_LA_BW): { | ||
292 | u32 ret = 0; | ||
293 | u32 vi_la_bw; | ||
294 | |||
295 | if (copy_from_user(&vi_la_bw, | ||
296 | (const void __user *)arg, | ||
297 | sizeof(vi_la_bw))) { | ||
298 | dev_err(&tegra_vi->ndev->dev, | ||
299 | "%s: Failed to copy arg from user\n", __func__); | ||
300 | return -EFAULT; | ||
301 | } | ||
302 | |||
303 | /* Set latency allowance for VI, BW is in MBps */ | ||
304 | ret = vi_v4l2_set_la(tegra_vi, vi_la_bw, 1); | ||
305 | if (ret) { | ||
306 | dev_err(&tegra_vi->ndev->dev, | ||
307 | "%s: failed to set la vi_bw %u MBps\n", | ||
308 | __func__, vi_la_bw); | ||
309 | return -ENOMEM; | ||
310 | } | ||
311 | |||
312 | return 0; | ||
313 | } | ||
314 | case _IOC_NR(NVHOST_VI_IOCTL_SET_EMC_INFO): { | ||
315 | uint vi_bw; | ||
316 | int ret; | ||
317 | |||
318 | if (copy_from_user(&vi_bw, | ||
319 | (const void __user *)arg, sizeof(uint))) { | ||
320 | dev_err(&tegra_vi->ndev->dev, | ||
321 | "%s: Failed to copy arg from user\n", __func__); | ||
322 | return -EFAULT; | ||
323 | } | ||
324 | |||
325 | ret = vi_set_la(vi_bw/1000); | ||
326 | if (ret) { | ||
327 | dev_err(&tegra_vi->ndev->dev, | ||
328 | "%s: failed to set la for vi_bw %u MBps\n", | ||
329 | __func__, vi_bw/1000); | ||
330 | return -ENOMEM; | ||
331 | } | ||
332 | |||
333 | #if defined(CONFIG_TEGRA_ISOMGR) | ||
334 | /* | ||
335 | * Register VI as isomgr client. | ||
336 | */ | ||
337 | if (!tegra_vi->isomgr_handle) { | ||
338 | ret = vi_isomgr_register(tegra_vi); | ||
339 | if (ret) { | ||
340 | dev_err(&tegra_vi->ndev->dev, | ||
341 | "%s: failed to register VI as isomgr client\n", | ||
342 | __func__); | ||
343 | return -ENOMEM; | ||
344 | } | ||
345 | } | ||
346 | |||
347 | if (vi_bw > tegra_vi->max_bw) { | ||
348 | dev_err(&tegra_vi->ndev->dev, | ||
349 | "%s: Requested ISO BW %u is more than " | ||
350 | "VI's max BW %u possible\n", | ||
351 | __func__, vi_bw, tegra_vi->max_bw); | ||
352 | return -EINVAL; | ||
353 | } | ||
354 | |||
355 | /* | ||
356 | * Set VI ISO BW requirements. | ||
357 | * There is no way to figure out what latency | ||
358 | * can be tolerated in VI without reading VI | ||
359 | * registers for now. 3 usec is minimum time | ||
360 | * to switch PLL source. Let's put 4 usec as | ||
361 | * latency for now. | ||
362 | */ | ||
363 | ret = vi_set_isomgr_request(tegra_vi, vi_bw, 4); | ||
364 | if (ret) { | ||
365 | dev_err(&tegra_vi->ndev->dev, | ||
366 | "%s: failed to reserve %u KBps\n", | ||
367 | __func__, vi_bw); | ||
368 | return -ENOMEM; | ||
369 | } | ||
370 | #endif | ||
371 | return ret; | ||
372 | } | ||
373 | case _IOC_NR(NVHOST_VI_IOCTL_SET_VI_CLK): { | ||
374 | long vi_clk_rate = 0; | ||
375 | |||
376 | if (copy_from_user(&vi_clk_rate, | ||
377 | (const void __user *)arg, sizeof(long))) { | ||
378 | dev_err(&tegra_vi->ndev->dev, | ||
379 | "%s: Failed to copy arg from user\n", __func__); | ||
380 | return -EFAULT; | ||
381 | } | ||
382 | |||
383 | return nvhost_module_set_rate(tegra_vi->ndev, | ||
384 | tegra_vi, vi_clk_rate, 0, NVHOST_CLOCK); | ||
385 | } | ||
386 | default: | ||
387 | dev_err(&tegra_vi->ndev->dev, | ||
388 | "%s: Unknown vi ioctl.\n", __func__); | ||
389 | return -EINVAL; | ||
390 | } | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int vi_open(struct inode *inode, struct file *file) | ||
395 | { | ||
396 | struct nvhost_device_data *pdata; | ||
397 | struct vi *vi; | ||
398 | int err = 0; | ||
399 | |||
400 | pdata = container_of(inode->i_cdev, | ||
401 | struct nvhost_device_data, ctrl_cdev); | ||
402 | if (WARN_ONCE(pdata == NULL, "pdata not found, %s failed\n", __func__)) | ||
403 | return -ENODEV; | ||
404 | |||
405 | vi = (struct vi *)pdata->private_data; | ||
406 | if (WARN_ONCE(vi == NULL, "vi not found, %s failed\n", __func__)) | ||
407 | return -ENODEV; | ||
408 | |||
409 | file->private_data = vi; | ||
410 | |||
411 | /* add vi client to acm */ | ||
412 | if (nvhost_module_add_client(vi->ndev, vi)) { | ||
413 | dev_err(&vi->ndev->dev, | ||
414 | "%s: failed add vi client\n", | ||
415 | __func__); | ||
416 | return -ENOMEM; | ||
417 | } | ||
418 | |||
419 | return err; | ||
420 | } | ||
421 | |||
422 | static int vi_release(struct inode *inode, struct file *file) | ||
423 | { | ||
424 | int ret = 0; | ||
425 | struct vi *tegra_vi = file->private_data; | ||
426 | |||
427 | #if defined(CONFIG_TEGRA_ISOMGR) | ||
428 | /* nullify isomgr request */ | ||
429 | if (tegra_vi->isomgr_handle) { | ||
430 | ret = vi_isomgr_release(tegra_vi); | ||
431 | if (ret) { | ||
432 | dev_err(&tegra_vi->ndev->dev, | ||
433 | "%s: failed to deallocate memory in isomgr\n", | ||
434 | __func__); | ||
435 | return -ENOMEM; | ||
436 | } | ||
437 | } | ||
438 | #endif | ||
439 | |||
440 | /* remove vi client from acm */ | ||
441 | nvhost_module_remove_client(tegra_vi->ndev, tegra_vi); | ||
442 | |||
443 | return ret; | ||
444 | } | ||
445 | |||
446 | const struct file_operations tegra_vi_ctrl_ops = { | ||
447 | .owner = THIS_MODULE, | ||
448 | .open = vi_open, | ||
449 | .unlocked_ioctl = vi_ioctl, | ||
450 | #ifdef CONFIG_COMPAT | ||
451 | .compat_ioctl = vi_ioctl, | ||
452 | #endif | ||
453 | .release = vi_release, | ||
454 | }; | ||
455 | |||
456 | /* Reset sensor data if respective clk is ON */ | ||
457 | void nvhost_vi_reset_all(struct platform_device *pdev) | ||
458 | { | ||
459 | void __iomem *reset_reg[4]; | ||
460 | int err; | ||
461 | bool enabled = false; | ||
462 | struct nvhost_device_data *pdata = pdev->dev.platform_data; | ||
463 | struct clk *clk; | ||
464 | |||
465 | err = nvhost_clk_get(pdev, "cilab", &clk); | ||
466 | if (!err) { | ||
467 | reset_reg[0] = pdata->aperture[0] + | ||
468 | T12_VI_CSI_0_SW_RESET; | ||
469 | reset_reg[1] = pdata->aperture[0] + | ||
470 | T12_CSI_CSI_SW_SENSOR_A_RESET; | ||
471 | reset_reg[2] = pdata->aperture[0] + | ||
472 | T12_CSI_CSICIL_SW_SENSOR_A_RESET; | ||
473 | reset_reg[3] = pdata->aperture[0] + | ||
474 | T12_VI_CSI_0_CSI_IMAGE_DT; | ||
475 | |||
476 | writel(0, reset_reg[3]); | ||
477 | writel(0x1, reset_reg[2]); | ||
478 | writel(0x1, reset_reg[1]); | ||
479 | writel(0x1f, reset_reg[0]); | ||
480 | |||
481 | udelay(10); | ||
482 | |||
483 | writel(0, reset_reg[2]); | ||
484 | writel(0, reset_reg[1]); | ||
485 | } | ||
486 | |||
487 | err = nvhost_clk_get(pdev, "cilcd", &clk); | ||
488 | if (!err) | ||
489 | enabled = true; | ||
490 | |||
491 | err = nvhost_clk_get(pdev, "cile", &clk); | ||
492 | if (!err) | ||
493 | enabled = true; | ||
494 | |||
495 | if (enabled) { | ||
496 | reset_reg[0] = pdata->aperture[0] + | ||
497 | T12_VI_CSI_1_SW_RESET; | ||
498 | reset_reg[1] = pdata->aperture[0] + | ||
499 | T12_CSI_CSI_SW_SENSOR_B_RESET; | ||
500 | reset_reg[2] = pdata->aperture[0] + | ||
501 | T12_CSI_CSICIL_SW_SENSOR_B_RESET; | ||
502 | reset_reg[3] = pdata->aperture[0] + | ||
503 | T12_VI_CSI_1_CSI_IMAGE_DT; | ||
504 | |||
505 | writel(0, reset_reg[3]); | ||
506 | writel(0x1, reset_reg[2]); | ||
507 | writel(0x1, reset_reg[1]); | ||
508 | writel(0x1f, reset_reg[0]); | ||
509 | |||
510 | udelay(10); | ||
511 | |||
512 | writel(0, reset_reg[2]); | ||
513 | writel(0, reset_reg[1]); | ||
514 | } | ||
515 | } | ||
diff --git a/drivers/media/platform/tegra/vi/vi.c b/drivers/media/platform/tegra/vi/vi.c new file mode 100644 index 000000000..61f47fd40 --- /dev/null +++ b/drivers/media/platform/tegra/vi/vi.c | |||
@@ -0,0 +1,611 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/host/vi/vi.c | ||
3 | * | ||
4 | * Tegra Graphics Host VI | ||
5 | * | ||
6 | * Copyright (c) 2012-2017, NVIDIA CORPORATION. All rights reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms and conditions of the GNU General Public License, | ||
10 | * version 2, as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | #include <linux/init.h> | ||
22 | #include <linux/export.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/resource.h> | ||
25 | #include <linux/pm_runtime.h> | ||
26 | #include <linux/of.h> | ||
27 | #include <linux/of_device.h> | ||
28 | #include <linux/of_platform.h> | ||
29 | #include <linux/clk/tegra.h> | ||
30 | #include <linux/tegra-soc.h> | ||
31 | #include <linux/tegra_pm_domains.h> | ||
32 | #include <linux/debugfs.h> | ||
33 | #include <linux/slab.h> | ||
34 | |||
35 | #include <media/tegra_v4l2_camera.h> | ||
36 | |||
37 | #include "dev.h" | ||
38 | #include "bus_client.h" | ||
39 | #include "nvhost_acm.h" | ||
40 | #include "t210/t210.h" | ||
41 | #include "vi/vi.h" | ||
42 | #include "vi/vi_irq.h" | ||
43 | #include "camera/vi/vi2_fops.h" | ||
44 | #include "camera/csi/csi2_fops.h" | ||
45 | |||
46 | #include "tegra_camera_dev_mfi.h" | ||
47 | |||
48 | #define MAX_DEVID_LENGTH 16 | ||
49 | #define TEGRA_VI_NAME "tegra_vi" | ||
50 | |||
51 | struct vi *tegra_vi; | ||
52 | |||
53 | struct vi *tegra_vi_get(void) | ||
54 | { | ||
55 | return tegra_vi; | ||
56 | } | ||
57 | EXPORT_SYMBOL(tegra_vi_get); | ||
58 | |||
59 | static struct tegra_t210_vi_data t21_vi_data = { | ||
60 | .info = (struct nvhost_device_data *)&t21_vi_info, | ||
61 | .vi_fops = &vi2_fops, | ||
62 | .csi_fops = &csi2_fops, | ||
63 | }; | ||
64 | |||
65 | static struct of_device_id tegra_vi_of_match[] = { | ||
66 | { .compatible = "nvidia,tegra210-vi", | ||
67 | .data = (struct tegra_t210_vi_data *)&t21_vi_data }, | ||
68 | { }, | ||
69 | }; | ||
70 | |||
71 | static struct i2c_camera_ctrl *i2c_ctrl; | ||
72 | |||
73 | static void (*mfi_callback)(void *); | ||
74 | static struct mfi_cb_arg *mfi_callback_arg; | ||
75 | static DEFINE_MUTEX(vi_isr_lock); | ||
76 | |||
77 | int tegra_vi_register_mfi_cb(callback cb, void *cb_arg) | ||
78 | { | ||
79 | mutex_lock(&vi_isr_lock); | ||
80 | if (mfi_callback || mfi_callback_arg) { | ||
81 | pr_err("cb already registered\n"); | ||
82 | mutex_unlock(&vi_isr_lock); | ||
83 | return -1; | ||
84 | } | ||
85 | |||
86 | mfi_callback = cb; | ||
87 | mfi_callback_arg = (struct mfi_cb_arg *)cb_arg; | ||
88 | mutex_unlock(&vi_isr_lock); | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | EXPORT_SYMBOL(tegra_vi_register_mfi_cb); | ||
93 | |||
94 | int tegra_vi_unregister_mfi_cb(void) | ||
95 | { | ||
96 | mutex_lock(&vi_isr_lock); | ||
97 | mfi_callback = NULL; | ||
98 | mfi_callback_arg = NULL; | ||
99 | mutex_unlock(&vi_isr_lock); | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | EXPORT_SYMBOL(tegra_vi_unregister_mfi_cb); | ||
104 | |||
105 | struct tegra_mfi_chan { | ||
106 | struct work_struct mfi_cb_work; | ||
107 | struct rcu_head rcu; | ||
108 | u8 channel; | ||
109 | }; | ||
110 | |||
111 | struct tegra_vi_mfi_ctx { | ||
112 | u8 num_channels; | ||
113 | struct workqueue_struct *mfi_workqueue; | ||
114 | struct tegra_mfi_chan __rcu *mfi_chans; | ||
115 | }; | ||
116 | |||
117 | static void vi_mfi_worker(struct work_struct *vi_work) | ||
118 | { | ||
119 | struct tegra_mfi_chan *mfi_chan = | ||
120 | container_of(vi_work, struct tegra_mfi_chan, mfi_cb_work); | ||
121 | |||
122 | mutex_lock(&vi_isr_lock); | ||
123 | if (mfi_callback == NULL) { | ||
124 | pr_debug("NULL callback\n"); | ||
125 | mutex_unlock(&vi_isr_lock); | ||
126 | return; | ||
127 | } | ||
128 | if (mfi_callback_arg) | ||
129 | mfi_callback_arg->vi_chan = mfi_chan->channel; | ||
130 | mfi_callback(mfi_callback_arg); | ||
131 | mutex_unlock(&vi_isr_lock); | ||
132 | } | ||
133 | |||
134 | int tegra_vi_mfi_event_notify(struct tegra_vi_mfi_ctx *mfi_ctx, u8 channel) | ||
135 | { | ||
136 | struct tegra_mfi_chan *chan; | ||
137 | |||
138 | if (!mfi_ctx) { | ||
139 | pr_err("Invalid mfi_ctx\n"); | ||
140 | return -EINVAL; | ||
141 | } | ||
142 | |||
143 | if (channel > mfi_ctx->num_channels-1) { | ||
144 | pr_err("Invalid mfi channel\n"); | ||
145 | return -EINVAL; | ||
146 | } | ||
147 | |||
148 | rcu_read_lock(); | ||
149 | chan = rcu_dereference(mfi_ctx->mfi_chans); | ||
150 | queue_work(mfi_ctx->mfi_workqueue, &chan[channel].mfi_cb_work); | ||
151 | rcu_read_unlock(); | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | EXPORT_SYMBOL(tegra_vi_mfi_event_notify); | ||
156 | |||
157 | bool tegra_vi_has_mfi_callback(void) | ||
158 | { | ||
159 | bool ret; | ||
160 | |||
161 | mutex_lock(&vi_isr_lock); | ||
162 | ret = mfi_callback ? true : false; | ||
163 | mutex_unlock(&vi_isr_lock); | ||
164 | |||
165 | return ret; | ||
166 | } | ||
167 | EXPORT_SYMBOL(tegra_vi_has_mfi_callback); | ||
168 | |||
169 | int tegra_vi_init_mfi(struct tegra_vi_mfi_ctx **pmfi_ctx, u8 num_channels) | ||
170 | { | ||
171 | u8 i; | ||
172 | struct tegra_mfi_chan *chan; | ||
173 | struct tegra_vi_mfi_ctx *mfi_ctx; | ||
174 | |||
175 | if (!pmfi_ctx) { | ||
176 | pr_err("mfi_ctx is invalid\n"); | ||
177 | return -EINVAL; | ||
178 | } | ||
179 | |||
180 | mfi_ctx = kzalloc(sizeof(*mfi_ctx), GFP_KERNEL); | ||
181 | if (unlikely(mfi_ctx == NULL)) | ||
182 | return -ENOMEM; | ||
183 | |||
184 | /* create workqueue for mfi callback */ | ||
185 | mfi_ctx->mfi_workqueue = alloc_workqueue("mfi_workqueue", | ||
186 | WQ_HIGHPRI | WQ_UNBOUND, 1); | ||
187 | if (!mfi_ctx->mfi_workqueue) { | ||
188 | pr_err("Failed to allocated mfi_workqueue"); | ||
189 | tegra_vi_deinit_mfi(&mfi_ctx); | ||
190 | return -ENOMEM; | ||
191 | } | ||
192 | |||
193 | chan = kcalloc(num_channels, sizeof(*chan), GFP_KERNEL); | ||
194 | if (unlikely(chan == NULL)) { | ||
195 | tegra_vi_deinit_mfi(&mfi_ctx); | ||
196 | return -ENOMEM; | ||
197 | } | ||
198 | |||
199 | mfi_ctx->num_channels = num_channels; | ||
200 | |||
201 | /* Init mfi callback work */ | ||
202 | for (i = 0; i < num_channels; i++) { | ||
203 | INIT_WORK(&chan[i].mfi_cb_work, vi_mfi_worker); | ||
204 | chan[i].channel = i; | ||
205 | } | ||
206 | |||
207 | rcu_assign_pointer(mfi_ctx->mfi_chans, chan); | ||
208 | |||
209 | *pmfi_ctx = mfi_ctx; | ||
210 | |||
211 | return 0; | ||
212 | } | ||
213 | EXPORT_SYMBOL(tegra_vi_init_mfi); | ||
214 | |||
215 | void tegra_vi_deinit_mfi(struct tegra_vi_mfi_ctx **pmfi_ctx) | ||
216 | { | ||
217 | struct tegra_vi_mfi_ctx *mfi_ctx; | ||
218 | |||
219 | if (!pmfi_ctx || !*pmfi_ctx) | ||
220 | return; | ||
221 | |||
222 | mfi_ctx = *pmfi_ctx; | ||
223 | |||
224 | flush_workqueue(mfi_ctx->mfi_workqueue); | ||
225 | destroy_workqueue(mfi_ctx->mfi_workqueue); | ||
226 | |||
227 | kfree_rcu(mfi_ctx->mfi_chans, rcu); | ||
228 | |||
229 | kfree(mfi_ctx); | ||
230 | mfi_ctx = NULL; | ||
231 | } | ||
232 | EXPORT_SYMBOL(tegra_vi_deinit_mfi); | ||
233 | |||
234 | #if defined(CONFIG_TEGRA_ISOMGR) | ||
235 | static int vi_isomgr_unregister(struct vi *tegra_vi) | ||
236 | { | ||
237 | tegra_isomgr_unregister(tegra_vi->isomgr_handle); | ||
238 | tegra_vi->isomgr_handle = NULL; | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | #endif | ||
243 | |||
244 | static int vi_out_show(struct seq_file *s, void *unused) | ||
245 | { | ||
246 | struct vi *vi = s->private; | ||
247 | |||
248 | seq_printf(s, "vi overflow: %u\n", | ||
249 | atomic_read(&(vi->vi_out.overflow))); | ||
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | static int vi_out_open(struct inode *inode, struct file *file) | ||
255 | { | ||
256 | return single_open(file, vi_out_show, inode->i_private); | ||
257 | } | ||
258 | |||
259 | static const struct file_operations vi_out_fops = { | ||
260 | .open = vi_out_open, | ||
261 | .read = seq_read, | ||
262 | .llseek = seq_lseek, | ||
263 | .release = single_release, | ||
264 | }; | ||
265 | |||
266 | static void vi_remove_debugfs(struct vi *vi) | ||
267 | { | ||
268 | debugfs_remove_recursive(vi->debugdir); | ||
269 | vi->debugdir = NULL; | ||
270 | } | ||
271 | |||
272 | static void vi_create_debugfs(struct vi *vi) | ||
273 | { | ||
274 | struct dentry *ret; | ||
275 | char tegra_vi_name[20]; | ||
276 | char debugfs_file_name[20]; | ||
277 | |||
278 | |||
279 | snprintf(tegra_vi_name, sizeof(tegra_vi_name), "%s", TEGRA_VI_NAME); | ||
280 | |||
281 | vi->debugdir = debugfs_create_dir(tegra_vi_name, NULL); | ||
282 | if (!vi->debugdir) { | ||
283 | dev_err(&vi->ndev->dev, | ||
284 | "%s: failed to create %s directory", | ||
285 | __func__, tegra_vi_name); | ||
286 | goto create_debugfs_fail; | ||
287 | } | ||
288 | |||
289 | snprintf(debugfs_file_name, sizeof(debugfs_file_name), "%s", "vi_out"); | ||
290 | |||
291 | ret = debugfs_create_file(debugfs_file_name, S_IRUGO, | ||
292 | vi->debugdir, vi, &vi_out_fops); | ||
293 | if (!ret) { | ||
294 | dev_err(&vi->ndev->dev, | ||
295 | "%s: failed to create %s", __func__, debugfs_file_name); | ||
296 | goto create_debugfs_fail; | ||
297 | } | ||
298 | |||
299 | return; | ||
300 | |||
301 | create_debugfs_fail: | ||
302 | dev_err(&vi->ndev->dev, "%s: could not create debugfs", __func__); | ||
303 | vi_remove_debugfs(vi); | ||
304 | } | ||
305 | |||
306 | static int nvhost_vi_slcg_handler(struct notifier_block *nb, | ||
307 | unsigned long action, void *data) | ||
308 | { | ||
309 | struct clk *clk; | ||
310 | int ret = 0; | ||
311 | |||
312 | struct nvhost_device_data *pdata = | ||
313 | container_of(nb, struct nvhost_device_data, | ||
314 | toggle_slcg_notifier); | ||
315 | struct vi *tegra_vi = (struct vi *)pdata->private_data; | ||
316 | |||
317 | if (tegra_vi->mc_vi.pg_mode) | ||
318 | return NOTIFY_OK; | ||
319 | |||
320 | clk = clk_get(NULL, "pll_d"); | ||
321 | if (IS_ERR(clk)) | ||
322 | return -EINVAL; | ||
323 | |||
324 | /* Make CSI sourced from PLL_D */ | ||
325 | ret = tegra_clk_cfg_ex(clk, TEGRA_CLK_PLLD_CSI_OUT_ENB, 1); | ||
326 | if (ret) { | ||
327 | dev_err(&pdata->pdev->dev, | ||
328 | "%s: failed to select CSI source pll_d: %d\n", | ||
329 | __func__, ret); | ||
330 | return ret; | ||
331 | } | ||
332 | |||
333 | /* Enable PLL_D */ | ||
334 | ret = clk_prepare_enable(clk); | ||
335 | if (ret) { | ||
336 | dev_err(&pdata->pdev->dev, "Can't enable pll_d: %d\n", ret); | ||
337 | return ret; | ||
338 | } | ||
339 | |||
340 | udelay(1); | ||
341 | |||
342 | /* Disable PLL_D */ | ||
343 | clk_disable_unprepare(clk); | ||
344 | |||
345 | /* Restore CSI source */ | ||
346 | ret = tegra_clk_cfg_ex(clk, TEGRA_CLK_MIPI_CSI_OUT_ENB, 1); | ||
347 | if (ret) { | ||
348 | dev_err(&pdata->pdev->dev, | ||
349 | "%s: failed to restore csi source: %d\n", | ||
350 | __func__, ret); | ||
351 | return ret; | ||
352 | } | ||
353 | |||
354 | clk_put(clk); | ||
355 | |||
356 | return NOTIFY_OK; | ||
357 | } | ||
358 | |||
359 | static int vi_probe(struct platform_device *dev) | ||
360 | { | ||
361 | int err = 0; | ||
362 | struct nvhost_device_data *pdata = NULL; | ||
363 | struct tegra_t210_vi_data *data = NULL; | ||
364 | u8 num_channels; | ||
365 | |||
366 | if (dev->dev.of_node) { | ||
367 | const struct of_device_id *match; | ||
368 | |||
369 | match = of_match_device(tegra_vi_of_match, &dev->dev); | ||
370 | if (match) { | ||
371 | data = (struct tegra_t210_vi_data *)match->data; | ||
372 | pdata = data->info; | ||
373 | dev->dev.platform_data = pdata; | ||
374 | } | ||
375 | /* DT initializes it to -1, use below WAR to set correct value. | ||
376 | * TODO: Once proper fix for dev-id goes in, remove it. | ||
377 | */ | ||
378 | dev->id = dev->dev.id; | ||
379 | } else | ||
380 | pdata = (struct nvhost_device_data *)dev->dev.platform_data; | ||
381 | |||
382 | WARN_ON(!pdata); | ||
383 | if (!pdata) { | ||
384 | dev_info(&dev->dev, "no platform data\n"); | ||
385 | return -ENODATA; | ||
386 | } | ||
387 | |||
388 | err = nvhost_check_bondout(pdata->bond_out_id); | ||
389 | if (err) { | ||
390 | dev_warn(&dev->dev, "No VI unit present. err:%d", err); | ||
391 | return err; | ||
392 | } | ||
393 | |||
394 | pdata->pdev = dev; | ||
395 | mutex_init(&pdata->lock); | ||
396 | platform_set_drvdata(dev, pdata); | ||
397 | |||
398 | dev_info(&dev->dev, "%s: ++\n", __func__); | ||
399 | |||
400 | tegra_vi = devm_kzalloc(&dev->dev, sizeof(struct vi), GFP_KERNEL); | ||
401 | if (!tegra_vi) | ||
402 | return -ENOMEM; | ||
403 | |||
404 | tegra_vi->ndev = dev; | ||
405 | tegra_vi->dev = &dev->dev; | ||
406 | err = nvhost_client_device_get_resources(dev); | ||
407 | if (err) | ||
408 | goto vi_probe_fail; | ||
409 | |||
410 | num_channels = 6; | ||
411 | |||
412 | err = tegra_vi_init_mfi(&tegra_vi->mfi_ctx, num_channels); | ||
413 | if (err) | ||
414 | goto vi_probe_fail; | ||
415 | |||
416 | if (!pdata->aperture[0]) { | ||
417 | dev_err(&dev->dev, "%s: failed to map register base\n", | ||
418 | __func__); | ||
419 | return -ENXIO; | ||
420 | } | ||
421 | |||
422 | /* call vi_intr_init and stats_work */ | ||
423 | INIT_WORK(&tegra_vi->stats_work, vi_stats_worker); | ||
424 | |||
425 | err = vi_intr_init(tegra_vi); | ||
426 | if (err) | ||
427 | goto vi_mfi_init_fail; | ||
428 | |||
429 | vi_create_debugfs(tegra_vi); | ||
430 | |||
431 | i2c_ctrl = pdata->private_data; | ||
432 | pdata->private_data = tegra_vi; | ||
433 | mutex_init(&tegra_vi->update_la_lock); | ||
434 | |||
435 | /* Create I2C Devices according to settings from board file */ | ||
436 | if (i2c_ctrl && i2c_ctrl->new_devices) | ||
437 | i2c_ctrl->new_devices(dev); | ||
438 | |||
439 | tegra_vi->reg = regulator_get(&tegra_vi->ndev->dev, "avdd_dsi_csi"); | ||
440 | if (IS_ERR(tegra_vi->reg)) { | ||
441 | err = PTR_ERR(tegra_vi->reg); | ||
442 | if (err == -ENODEV) | ||
443 | dev_info(&tegra_vi->ndev->dev, | ||
444 | "%s: no regulator device\n", __func__); | ||
445 | else | ||
446 | dev_err(&tegra_vi->ndev->dev, | ||
447 | "%s: couldn't get regulator\n", __func__); | ||
448 | tegra_vi->reg = NULL; | ||
449 | if (tegra_platform_is_silicon()) | ||
450 | goto camera_i2c_unregister; | ||
451 | } | ||
452 | |||
453 | #ifdef CONFIG_TEGRA_CAMERA | ||
454 | tegra_vi->camera = tegra_camera_register(dev); | ||
455 | if (!tegra_vi->camera) { | ||
456 | dev_err(&dev->dev, "%s: can't register tegra_camera\n", | ||
457 | __func__); | ||
458 | goto vi_regulator_put; | ||
459 | } | ||
460 | #endif | ||
461 | |||
462 | if (pdata->slcg_notifier_enable && | ||
463 | (pdata->powergate_id != -1)) { | ||
464 | pdata->toggle_slcg_notifier.notifier_call = | ||
465 | &nvhost_vi_slcg_handler; | ||
466 | |||
467 | slcg_register_notifier(pdata->powergate_id, | ||
468 | &pdata->toggle_slcg_notifier); | ||
469 | } | ||
470 | |||
471 | nvhost_module_init(dev); | ||
472 | |||
473 | err = nvhost_client_device_init(dev); | ||
474 | if (err) | ||
475 | goto camera_unregister; | ||
476 | |||
477 | tegra_vi->mc_vi.vi = tegra_vi; | ||
478 | tegra_vi->mc_vi.csi = &tegra_vi->csi; | ||
479 | tegra_vi->mc_vi.reg = tegra_vi->reg; | ||
480 | tegra_vi->mc_vi.fops = data->vi_fops; | ||
481 | tegra_vi->csi.fops = data->csi_fops; | ||
482 | err = tegra_csi_media_controller_init(&tegra_vi->csi, dev); | ||
483 | if (err) | ||
484 | goto vi_mc_init_error; | ||
485 | |||
486 | err = tegra_vi_media_controller_init(&tegra_vi->mc_vi, dev); | ||
487 | if (err) | ||
488 | goto vi_mc_init_error; | ||
489 | |||
490 | return 0; | ||
491 | |||
492 | vi_mc_init_error: | ||
493 | nvhost_client_device_release(dev); | ||
494 | camera_unregister: | ||
495 | #ifdef CONFIG_TEGRA_CAMERA | ||
496 | tegra_camera_unregister(tegra_vi->camera); | ||
497 | vi_regulator_put: | ||
498 | #endif | ||
499 | |||
500 | regulator_put(tegra_vi->reg); | ||
501 | tegra_vi->reg = NULL; | ||
502 | |||
503 | camera_i2c_unregister: | ||
504 | if (i2c_ctrl && i2c_ctrl->remove_devices) | ||
505 | i2c_ctrl->remove_devices(dev); | ||
506 | pdata->private_data = i2c_ctrl; | ||
507 | vi_mfi_init_fail: | ||
508 | tegra_vi_deinit_mfi(&tegra_vi->mfi_ctx); | ||
509 | vi_probe_fail: | ||
510 | dev_err(&dev->dev, "%s: failed\n", __func__); | ||
511 | return err; | ||
512 | } | ||
513 | |||
514 | static int __exit vi_remove(struct platform_device *dev) | ||
515 | { | ||
516 | #ifdef CONFIG_TEGRA_CAMERA | ||
517 | int err = 0; | ||
518 | #endif | ||
519 | struct nvhost_device_data *pdata = platform_get_drvdata(dev); | ||
520 | struct vi *tegra_vi = (struct vi *)pdata->private_data; | ||
521 | |||
522 | #ifdef CONFIG_PM | ||
523 | if (atomic_read(&dev->dev.power.usage_count) > 0) | ||
524 | return -EBUSY; | ||
525 | #endif | ||
526 | |||
527 | dev_info(&dev->dev, "%s: ++\n", __func__); | ||
528 | |||
529 | #if defined(CONFIG_TEGRA_ISOMGR) | ||
530 | if (tegra_vi->isomgr_handle) | ||
531 | vi_isomgr_unregister(tegra_vi); | ||
532 | #endif | ||
533 | |||
534 | tegra_vi_deinit_mfi(&tegra_vi->mfi_ctx); | ||
535 | |||
536 | vi_remove_debugfs(tegra_vi); | ||
537 | |||
538 | tegra_vi_media_controller_cleanup(&tegra_vi->mc_vi); | ||
539 | |||
540 | nvhost_client_device_release(dev); | ||
541 | |||
542 | if (pdata->slcg_notifier_enable && | ||
543 | (pdata->powergate_id != -1)) | ||
544 | slcg_unregister_notifier(pdata->powergate_id, | ||
545 | &pdata->toggle_slcg_notifier); | ||
546 | |||
547 | vi_intr_free(tegra_vi); | ||
548 | |||
549 | pdata->aperture[0] = NULL; | ||
550 | #ifdef CONFIG_TEGRA_CAMERA | ||
551 | err = tegra_camera_unregister(tegra_vi->camera); | ||
552 | if (err) | ||
553 | return err; | ||
554 | #endif | ||
555 | |||
556 | #ifdef CONFIG_PM_GENERIC_DOMAINS | ||
557 | tegra_pd_remove_device(&dev->dev); | ||
558 | #endif | ||
559 | |||
560 | regulator_put(tegra_vi->reg); | ||
561 | tegra_vi->reg = NULL; | ||
562 | |||
563 | /* Remove I2C Devices according to settings from board file */ | ||
564 | if (i2c_ctrl && i2c_ctrl->remove_devices) | ||
565 | i2c_ctrl->remove_devices(dev); | ||
566 | |||
567 | pdata->private_data = i2c_ctrl; | ||
568 | |||
569 | return 0; | ||
570 | } | ||
571 | |||
572 | static struct platform_driver vi_driver = { | ||
573 | .probe = vi_probe, | ||
574 | .remove = __exit_p(vi_remove), | ||
575 | .driver = { | ||
576 | .owner = THIS_MODULE, | ||
577 | .name = "vi", | ||
578 | #ifdef CONFIG_PM | ||
579 | .pm = &nvhost_module_pm_ops, | ||
580 | #endif | ||
581 | #ifdef CONFIG_OF | ||
582 | .of_match_table = tegra_vi_of_match, | ||
583 | #endif | ||
584 | } | ||
585 | }; | ||
586 | |||
587 | static struct of_device_id tegra_vi_domain_match[] = { | ||
588 | {.compatible = "nvidia,tegra210-ve-pd", | ||
589 | .data = (struct nvhost_device_data *)&t21_vi_info}, | ||
590 | {}, | ||
591 | }; | ||
592 | |||
593 | static int __init vi_init(void) | ||
594 | { | ||
595 | int ret; | ||
596 | |||
597 | ret = nvhost_domain_init(tegra_vi_domain_match); | ||
598 | if (ret) | ||
599 | return ret; | ||
600 | |||
601 | return platform_driver_register(&vi_driver); | ||
602 | } | ||
603 | |||
604 | static void __exit vi_exit(void) | ||
605 | { | ||
606 | platform_driver_unregister(&vi_driver); | ||
607 | } | ||
608 | |||
609 | late_initcall(vi_init); | ||
610 | module_exit(vi_exit); | ||
611 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/media/platform/tegra/vi/vi.h b/drivers/media/platform/tegra/vi/vi.h new file mode 100644 index 000000000..a03057265 --- /dev/null +++ b/drivers/media/platform/tegra/vi/vi.h | |||
@@ -0,0 +1,128 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/host/vi/vi.h | ||
3 | * | ||
4 | * Tegra Graphics Host VI | ||
5 | * | ||
6 | * Copyright (c) 2012-2016, NVIDIA CORPORATION. All rights reserved. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms and conditions of the GNU General Public License, | ||
10 | * version 2, as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | #ifndef __NVHOST_VI_H__ | ||
22 | #define __NVHOST_VI_H__ | ||
23 | |||
24 | #include <linux/platform/tegra/isomgr.h> | ||
25 | #include <linux/tegra-powergate.h> | ||
26 | #include <linux/clk/tegra.h> | ||
27 | |||
28 | #include "camera/vi/mc_common.h" | ||
29 | #include "chip_support.h" | ||
30 | |||
31 | #define VI_CFG_INTERRUPT_MASK_0 0x8c | ||
32 | #define VI_CFG_INTERRUPT_STATUS_0 0x98 | ||
33 | |||
34 | #define CSI_CSI_PIXEL_PARSER_A_INTERRUPT_MASK_0 0x850 | ||
35 | #define CSI_CSI_PIXEL_PARSER_A_STATUS_0 0x854 | ||
36 | #define PPA_FIFO_OVRF (1 << 5) | ||
37 | |||
38 | #define CSI_CSI_PIXEL_PARSER_B_INTERRUPT_MASK_0 0x884 | ||
39 | #define CSI_CSI_PIXEL_PARSER_B_STATUS_0 0x888 | ||
40 | #define PPB_FIFO_OVRF (1 << 5) | ||
41 | |||
42 | #define VI_CSI_0_ERROR_STATUS 0x184 | ||
43 | #define VI_CSI_1_ERROR_STATUS 0x284 | ||
44 | #define VI_CSI_0_WD_CTRL 0x18c | ||
45 | #define VI_CSI_1_WD_CTRL 0x28c | ||
46 | #define VI_CSI_0_ERROR_INT_MASK_0 0x188 | ||
47 | #define VI_CSI_1_ERROR_INT_MASK_0 0x288 | ||
48 | |||
49 | #ifdef TEGRA_21X_OR_HIGHER_CONFIG | ||
50 | #define VI_CSI_2_ERROR_STATUS 0x384 | ||
51 | #define VI_CSI_3_ERROR_STATUS 0x484 | ||
52 | #define VI_CSI_4_ERROR_STATUS 0x584 | ||
53 | #define VI_CSI_5_ERROR_STATUS 0x684 | ||
54 | |||
55 | #define VI_CSI_2_WD_CTRL 0x38c | ||
56 | #define VI_CSI_3_WD_CTRL 0x48c | ||
57 | #define VI_CSI_4_WD_CTRL 0x58c | ||
58 | #define VI_CSI_5_WD_CTRL 0x68c | ||
59 | |||
60 | #define VI_CSI_2_ERROR_INT_MASK_0 0x388 | ||
61 | #define VI_CSI_3_ERROR_INT_MASK_0 0x488 | ||
62 | #define VI_CSI_4_ERROR_INT_MASK_0 0x588 | ||
63 | #define VI_CSI_5_ERROR_INT_MASK_0 0x688 | ||
64 | |||
65 | #define CSI1_CSI_PIXEL_PARSER_A_INTERRUPT_MASK_0 0x1050 | ||
66 | #define CSI1_CSI_PIXEL_PARSER_A_STATUS_0 0x1054 | ||
67 | #define CSI1_CSI_PIXEL_PARSER_B_INTERRUPT_MASK_0 0x1084 | ||
68 | #define CSI1_CSI_PIXEL_PARSER_B_STATUS_0 0x1088 | ||
69 | #define CSI2_CSI_PIXEL_PARSER_A_INTERRUPT_MASK_0 0x1850 | ||
70 | #define CSI2_CSI_PIXEL_PARSER_A_STATUS_0 0x1854 | ||
71 | #define CSI2_CSI_PIXEL_PARSER_B_INTERRUPT_MASK_0 0x1884 | ||
72 | #define CSI2_CSI_PIXEL_PARSER_B_STATUS_0 0x1888 | ||
73 | |||
74 | #define NUM_VI_WATCHDOG 6 | ||
75 | #else | ||
76 | #define NUM_VI_WATCHDOG 2 | ||
77 | #endif | ||
78 | |||
79 | typedef void (*callback)(void *); | ||
80 | |||
81 | struct tegra_vi_stats { | ||
82 | atomic_t overflow; | ||
83 | }; | ||
84 | |||
85 | struct tegra_vi_mfi_ctx; | ||
86 | |||
87 | struct vi { | ||
88 | struct tegra_camera *camera; | ||
89 | struct platform_device *ndev; | ||
90 | struct device *dev; | ||
91 | struct tegra_vi_data *data; | ||
92 | struct tegra_mc_vi mc_vi; | ||
93 | struct tegra_csi_device csi; | ||
94 | |||
95 | struct regulator *reg; | ||
96 | struct dentry *debugdir; | ||
97 | struct tegra_vi_stats vi_out; | ||
98 | struct work_struct stats_work; | ||
99 | struct tegra_vi_mfi_ctx *mfi_ctx; | ||
100 | #if defined(CONFIG_TEGRA_ISOMGR) | ||
101 | tegra_isomgr_handle isomgr_handle; | ||
102 | #endif | ||
103 | int vi_irq; | ||
104 | uint vi_bypass_bw; | ||
105 | uint max_bw; | ||
106 | struct mutex update_la_lock; | ||
107 | bool master_deinitialized; | ||
108 | bool tpg_opened; | ||
109 | bool sensor_opened; | ||
110 | bool bypass; | ||
111 | }; | ||
112 | |||
113 | extern const struct file_operations tegra_vi_ctrl_ops; | ||
114 | int nvhost_vi_prepare_poweroff(struct platform_device *); | ||
115 | int nvhost_vi_finalize_poweron(struct platform_device *); | ||
116 | |||
117 | void nvhost_vi_reset_all(struct platform_device *); | ||
118 | struct vi *tegra_vi_get(void); | ||
119 | int vi_v4l2_set_la(struct vi *tegra_vi, u32 vi_bypass_bw, bool is_ioctl); | ||
120 | |||
121 | int tegra_vi_register_mfi_cb(callback cb, void *cb_arg); | ||
122 | int tegra_vi_unregister_mfi_cb(void); | ||
123 | |||
124 | bool tegra_vi_has_mfi_callback(void); | ||
125 | int tegra_vi_mfi_event_notify(struct tegra_vi_mfi_ctx *mfi_ctx, u8 channel); | ||
126 | int tegra_vi_init_mfi(struct tegra_vi_mfi_ctx **mfi_ctx, u8 num_channels); | ||
127 | void tegra_vi_deinit_mfi(struct tegra_vi_mfi_ctx **mfi_ctx); | ||
128 | #endif | ||
diff --git a/drivers/media/platform/tegra/vi/vi_irq.c b/drivers/media/platform/tegra/vi/vi_irq.c new file mode 100644 index 000000000..9f3cc3f3c --- /dev/null +++ b/drivers/media/platform/tegra/vi/vi_irq.c | |||
@@ -0,0 +1,244 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/host/vi/vi_irq.c | ||
3 | * | ||
4 | * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/nvhost.h> | ||
20 | |||
21 | #include "nvhost_acm.h" | ||
22 | #include "vi/vi.h" | ||
23 | #include "vi/vi_irq.h" | ||
24 | |||
25 | static const int status_reg_table[] = { | ||
26 | VI_CFG_INTERRUPT_STATUS_0, | ||
27 | CSI_CSI_PIXEL_PARSER_A_STATUS_0, | ||
28 | CSI_CSI_PIXEL_PARSER_B_STATUS_0, | ||
29 | VI_CSI_0_ERROR_STATUS, | ||
30 | VI_CSI_1_ERROR_STATUS, | ||
31 | #ifdef TEGRA_21X_OR_HIGHER_CONFIG | ||
32 | VI_CSI_2_ERROR_STATUS, | ||
33 | VI_CSI_3_ERROR_STATUS, | ||
34 | VI_CSI_4_ERROR_STATUS, | ||
35 | VI_CSI_5_ERROR_STATUS, | ||
36 | CSI1_CSI_PIXEL_PARSER_A_STATUS_0, | ||
37 | CSI1_CSI_PIXEL_PARSER_B_STATUS_0, | ||
38 | CSI2_CSI_PIXEL_PARSER_A_STATUS_0, | ||
39 | CSI2_CSI_PIXEL_PARSER_B_STATUS_0, | ||
40 | #endif | ||
41 | }; | ||
42 | |||
43 | static const int mask_reg_table[] = { | ||
44 | VI_CFG_INTERRUPT_MASK_0, | ||
45 | CSI_CSI_PIXEL_PARSER_A_INTERRUPT_MASK_0, | ||
46 | CSI_CSI_PIXEL_PARSER_B_INTERRUPT_MASK_0, | ||
47 | VI_CSI_0_ERROR_INT_MASK_0, | ||
48 | VI_CSI_1_ERROR_INT_MASK_0, | ||
49 | VI_CSI_0_WD_CTRL, | ||
50 | VI_CSI_1_WD_CTRL, | ||
51 | #ifdef TEGRA_21X_OR_HIGHER_CONFIG | ||
52 | VI_CSI_2_WD_CTRL, | ||
53 | VI_CSI_3_WD_CTRL, | ||
54 | VI_CSI_4_WD_CTRL, | ||
55 | VI_CSI_5_WD_CTRL, | ||
56 | VI_CSI_2_ERROR_INT_MASK_0, | ||
57 | VI_CSI_3_ERROR_INT_MASK_0, | ||
58 | VI_CSI_4_ERROR_INT_MASK_0, | ||
59 | VI_CSI_5_ERROR_INT_MASK_0, | ||
60 | CSI1_CSI_PIXEL_PARSER_A_INTERRUPT_MASK_0, | ||
61 | CSI1_CSI_PIXEL_PARSER_B_INTERRUPT_MASK_0, | ||
62 | CSI2_CSI_PIXEL_PARSER_A_INTERRUPT_MASK_0, | ||
63 | CSI2_CSI_PIXEL_PARSER_B_INTERRUPT_MASK_0, | ||
64 | #endif | ||
65 | }; | ||
66 | |||
67 | static inline void clear_state(struct vi *tegra_vi, int addr) | ||
68 | { | ||
69 | int val; | ||
70 | |||
71 | val = host1x_readl(tegra_vi->ndev, addr); | ||
72 | host1x_writel(tegra_vi->ndev, addr, val); | ||
73 | } | ||
74 | |||
75 | int vi_enable_irq(struct vi *tegra_vi) | ||
76 | { | ||
77 | int i; | ||
78 | |||
79 | /* Mask all VI interrupt */ | ||
80 | for (i = 0; i < ARRAY_SIZE(mask_reg_table); i++) | ||
81 | host1x_writel(tegra_vi->ndev, mask_reg_table[i], 0); | ||
82 | |||
83 | /* Clear all VI interrupt state registers */ | ||
84 | for (i = 0; i < ARRAY_SIZE(status_reg_table); i++) | ||
85 | clear_state(tegra_vi, status_reg_table[i]); | ||
86 | |||
87 | enable_irq(tegra_vi->vi_irq); | ||
88 | |||
89 | return 0; | ||
90 | |||
91 | } | ||
92 | EXPORT_SYMBOL(vi_enable_irq); | ||
93 | |||
94 | int vi_disable_irq(struct vi *tegra_vi) | ||
95 | { | ||
96 | int i; | ||
97 | |||
98 | disable_irq(tegra_vi->vi_irq); | ||
99 | |||
100 | /* Mask all VI interrupt */ | ||
101 | for (i = 0; i < ARRAY_SIZE(mask_reg_table); i++) | ||
102 | host1x_writel(tegra_vi->ndev, mask_reg_table[i], 0); | ||
103 | |||
104 | /* Clear all VI interrupt state registers */ | ||
105 | for (i = 0; i < ARRAY_SIZE(status_reg_table); i++) | ||
106 | clear_state(tegra_vi, status_reg_table[i]); | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | EXPORT_SYMBOL(vi_disable_irq); | ||
111 | |||
112 | static irqreturn_t vi_checkwd(struct vi *tegra_vi, int stream) | ||
113 | { | ||
114 | int err_addr, wd_addr, val; | ||
115 | |||
116 | switch (stream) { | ||
117 | case 0: | ||
118 | err_addr = VI_CSI_0_ERROR_STATUS; | ||
119 | wd_addr = VI_CSI_0_WD_CTRL; | ||
120 | break; | ||
121 | case 1: | ||
122 | err_addr = VI_CSI_1_ERROR_STATUS; | ||
123 | wd_addr = VI_CSI_1_WD_CTRL; | ||
124 | break; | ||
125 | #ifdef TEGRA_21X_OR_HIGHER_CONFIG | ||
126 | case 2: | ||
127 | err_addr = VI_CSI_2_ERROR_STATUS; | ||
128 | wd_addr = VI_CSI_2_WD_CTRL; | ||
129 | break; | ||
130 | case 3: | ||
131 | err_addr = VI_CSI_3_ERROR_STATUS; | ||
132 | wd_addr = VI_CSI_3_WD_CTRL; | ||
133 | break; | ||
134 | case 4: | ||
135 | err_addr = VI_CSI_4_ERROR_STATUS; | ||
136 | wd_addr = VI_CSI_4_WD_CTRL; | ||
137 | break; | ||
138 | case 5: | ||
139 | err_addr = VI_CSI_5_ERROR_STATUS; | ||
140 | wd_addr = VI_CSI_5_WD_CTRL; | ||
141 | break; | ||
142 | #endif | ||
143 | default: | ||
144 | return IRQ_NONE; | ||
145 | } | ||
146 | |||
147 | val = host1x_readl(tegra_vi->ndev, err_addr); | ||
148 | if (val & 0x20) { | ||
149 | host1x_writel(tegra_vi->ndev, wd_addr, 0); | ||
150 | host1x_writel(tegra_vi->ndev, err_addr, 0x20); | ||
151 | tegra_vi_mfi_event_notify(tegra_vi->mfi_ctx, stream); | ||
152 | return IRQ_HANDLED; | ||
153 | } | ||
154 | |||
155 | return IRQ_NONE; | ||
156 | } | ||
157 | |||
158 | static irqreturn_t vi_isr(int irq, void *dev_id) | ||
159 | { | ||
160 | struct vi *tegra_vi = (struct vi *)dev_id; | ||
161 | int i, val; | ||
162 | irqreturn_t result; | ||
163 | |||
164 | for (i = 0; i < NUM_VI_WATCHDOG; i++) { | ||
165 | result = vi_checkwd(tegra_vi, i); | ||
166 | if (result == IRQ_HANDLED) | ||
167 | goto handled; | ||
168 | } | ||
169 | |||
170 | dev_dbg(&tegra_vi->ndev->dev, "%s: ++", __func__); | ||
171 | |||
172 | val = host1x_readl(tegra_vi->ndev, CSI_CSI_PIXEL_PARSER_A_STATUS_0); | ||
173 | |||
174 | /* changes required as per t124 register spec */ | ||
175 | if (val & PPA_FIFO_OVRF) | ||
176 | atomic_inc(&(tegra_vi->vi_out.overflow)); | ||
177 | |||
178 | /* Disable IRQ */ | ||
179 | vi_disable_irq(tegra_vi); | ||
180 | |||
181 | schedule_work(&tegra_vi->stats_work); | ||
182 | |||
183 | handled: | ||
184 | return IRQ_HANDLED; | ||
185 | } | ||
186 | EXPORT_SYMBOL(vi_isr); | ||
187 | |||
188 | void vi_stats_worker(struct work_struct *work) | ||
189 | { | ||
190 | struct vi *tegra_vi = container_of(work, struct vi, stats_work); | ||
191 | |||
192 | dev_dbg(&tegra_vi->ndev->dev, | ||
193 | "%s: vi_out dropped data %u times", __func__, | ||
194 | atomic_read(&(tegra_vi->vi_out.overflow))); | ||
195 | |||
196 | /* Enable IRQ's */ | ||
197 | vi_enable_irq(tegra_vi); | ||
198 | } | ||
199 | EXPORT_SYMBOL(vi_stats_worker); | ||
200 | |||
201 | int vi_intr_init(struct vi *tegra_vi) | ||
202 | { | ||
203 | struct platform_device *ndev = tegra_vi->ndev; | ||
204 | |||
205 | /* Interrupt resources are only associated with | ||
206 | * master dev vi.0 so irq must be programmed | ||
207 | * with it only. | ||
208 | */ | ||
209 | int ret; | ||
210 | |||
211 | dev_dbg(&tegra_vi->ndev->dev, "%s: ++", __func__); | ||
212 | |||
213 | tegra_vi->vi_irq = platform_get_irq(ndev, 0); | ||
214 | if (IS_ERR_VALUE(tegra_vi->vi_irq)) { | ||
215 | dev_err(&tegra_vi->ndev->dev, "missing camera irq\n"); | ||
216 | return -ENXIO; | ||
217 | } | ||
218 | |||
219 | ret = request_irq(tegra_vi->vi_irq, | ||
220 | vi_isr, | ||
221 | IRQF_SHARED, | ||
222 | dev_name(&tegra_vi->ndev->dev), | ||
223 | tegra_vi); | ||
224 | if (ret) { | ||
225 | dev_err(&tegra_vi->ndev->dev, "failed to get irq\n"); | ||
226 | return -EBUSY; | ||
227 | } | ||
228 | |||
229 | disable_irq(tegra_vi->vi_irq); | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | EXPORT_SYMBOL(vi_intr_init); | ||
234 | |||
235 | int vi_intr_free(struct vi *tegra_vi) | ||
236 | { | ||
237 | dev_dbg(&tegra_vi->ndev->dev, "%s: ++", __func__); | ||
238 | |||
239 | free_irq(tegra_vi->vi_irq, tegra_vi); | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | EXPORT_SYMBOL(vi_intr_free); | ||
244 | |||
diff --git a/drivers/media/platform/tegra/vi/vi_irq.h b/drivers/media/platform/tegra/vi/vi_irq.h new file mode 100644 index 000000000..26fed8a00 --- /dev/null +++ b/drivers/media/platform/tegra/vi/vi_irq.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/host/vi/vi_irq.h | ||
3 | * | ||
4 | * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #ifndef __DRIVERS_VIDEO_VI_IRQ_H | ||
18 | #define __DRIVERS_VIDEO_VI_IRQ_H | ||
19 | |||
20 | int vi_intr_init(struct vi *vi); | ||
21 | int vi_intr_free(struct vi *vi); | ||
22 | void vi_stats_worker(struct work_struct *work); | ||
23 | int vi_enable_irq(struct vi *vi); | ||
24 | int vi_disable_irq(struct vi *vi); | ||
25 | #endif | ||
26 | |||
diff --git a/drivers/video/tegra/camera/Makefile b/drivers/video/tegra/camera/Makefile new file mode 100644 index 000000000..87d2e3a72 --- /dev/null +++ b/drivers/video/tegra/camera/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | GCOV_PROFILE := y | ||
2 | ccflags-y += -Idrivers/media/platform/tegra/vi | ||
3 | ccflags-y += -I../nvhost/drivers/video/tegra/host | ||
4 | ccflags-y += -Idrivers/video/tegra/host | ||
5 | ccflags-y += -Idrivers/media/platform/tegra/ | ||
6 | |||
7 | ifdef CONFIG_TEGRA_CAMERA_PLATFORM | ||
8 | obj-y += tegra_camera_platform.o | ||
9 | obj-y += tegra_camera_dev_mfi.o | ||
10 | endif | ||
diff --git a/drivers/video/tegra/camera/camera_priv.h b/drivers/video/tegra/camera/camera_priv.h new file mode 100644 index 000000000..a854013dd --- /dev/null +++ b/drivers/video/tegra/camera/camera_priv.h | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/camera/camera_priv.h | ||
3 | * | ||
4 | * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #ifndef __DRIVERS_VIDEO_TEGRA_CAMERA_CAMERA_PRIV_H | ||
18 | #define __DRIVERS_VIDEO_TEGRA_CAMERA_CAMERA_PRIV_H | ||
19 | |||
20 | #include <linux/nvhost.h> | ||
21 | #include <linux/io.h> | ||
22 | #include "camera_priv_defs.h" | ||
23 | |||
24 | static inline unsigned long tegra_camera_readl(struct tegra_camera *camera, | ||
25 | unsigned long reg) | ||
26 | { | ||
27 | unsigned long ret; | ||
28 | struct platform_device *ndev = to_platform_device(camera->dev); | ||
29 | struct nvhost_device_data *pdata = platform_get_drvdata(ndev); | ||
30 | |||
31 | WARN(!tegra_is_clk_enabled(camera->clock[CAMERA_VI_CLK].clk), | ||
32 | "VI is clock-gated"); | ||
33 | |||
34 | ret = readl(pdata->aperture[0] + reg); | ||
35 | return ret; | ||
36 | } | ||
37 | |||
38 | static inline void tegra_camera_writel(struct tegra_camera *camera, | ||
39 | unsigned long val, | ||
40 | unsigned long reg) | ||
41 | { | ||
42 | struct platform_device *ndev = to_platform_device(camera->dev); | ||
43 | struct nvhost_device_data *pdata = platform_get_drvdata(ndev); | ||
44 | |||
45 | WARN(!tegra_is_clk_enabled(camera->clock[CAMERA_VI_CLK].clk), | ||
46 | "VI is clock-gated"); | ||
47 | |||
48 | writel(val, pdata->aperture[0] + reg); | ||
49 | } | ||
50 | |||
51 | |||
52 | #endif | ||
diff --git a/drivers/video/tegra/camera/camera_priv_defs.h b/drivers/video/tegra/camera/camera_priv_defs.h new file mode 100644 index 000000000..7a2c8a6d3 --- /dev/null +++ b/drivers/video/tegra/camera/camera_priv_defs.h | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/camera/camera_priv_defs.h | ||
3 | * | ||
4 | * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #ifndef __DRIVERS_VIDEO_TEGRA_CAMERA_CAMERA_PRIV_DEFS_H | ||
18 | #define __DRIVERS_VIDEO_TEGRA_CAMERA_CAMERA_PRIV_DEFS_H | ||
19 | |||
20 | #include <linux/miscdevice.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/ioctl.h> | ||
23 | #include <linux/fs.h> | ||
24 | #include <linux/device.h> | ||
25 | #include <linux/regulator/consumer.h> | ||
26 | #include <linux/clk.h> | ||
27 | #include <linux/io.h> | ||
28 | #include <linux/uaccess.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/export.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/clk/tegra.h> | ||
33 | #include <linux/tegra-powergate.h> | ||
34 | |||
35 | #if defined(CONFIG_TEGRA_ISOMGR) | ||
36 | #include <linux/platform/tegra/isomgr.h> | ||
37 | #endif | ||
38 | |||
39 | #include <video/tegra_camera.h> | ||
40 | |||
41 | |||
42 | /* | ||
43 | * CAMERA_*_CLK is only for internal driver use. | ||
44 | * TEGRA_CAMERA_*_CLK is enum used between driver and user space. | ||
45 | * TEGRA_CAMERA_*_CLK is defined in tegra_camera.h | ||
46 | */ | ||
47 | enum { | ||
48 | CAMERA_VI_CLK, | ||
49 | CAMERA_EMC_CLK, | ||
50 | CAMERA_ISP_CLK, | ||
51 | CAMERA_CSI_CLK, | ||
52 | #if defined(CONFIG_ARCH_TEGRA_11x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC) | ||
53 | CAMERA_CILAB_CLK, | ||
54 | CAMERA_CILE_CLK, | ||
55 | CAMERA_PLL_D2_CLK, | ||
56 | #endif | ||
57 | |||
58 | #ifdef CONFIG_ARCH_TEGRA_11x_SOC | ||
59 | CAMERA_CILCD_CLK, | ||
60 | #endif | ||
61 | CAMERA_SCLK, | ||
62 | CAMERA_CLK_MAX, | ||
63 | }; | ||
64 | |||
65 | struct clock { | ||
66 | struct clk *clk; | ||
67 | bool on; | ||
68 | }; | ||
69 | |||
70 | struct vi_stats { | ||
71 | atomic_t overflow; | ||
72 | }; | ||
73 | |||
74 | struct tegra_camera { | ||
75 | struct device *dev; | ||
76 | struct miscdevice misc_dev; | ||
77 | struct clock clock[CAMERA_CLK_MAX]; | ||
78 | struct regulator *reg; | ||
79 | struct tegra_camera_clk_info info; | ||
80 | struct mutex tegra_camera_lock; | ||
81 | atomic_t in_use; | ||
82 | int power_on; | ||
83 | int irq; | ||
84 | struct dentry *debugdir; | ||
85 | struct vi_stats vi_out0; | ||
86 | struct vi_stats vi_out1; | ||
87 | struct work_struct stats_work; | ||
88 | #if defined(CONFIG_TEGRA_ISOMGR) | ||
89 | tegra_isomgr_handle isomgr_handle; | ||
90 | #endif | ||
91 | }; | ||
92 | |||
93 | /* | ||
94 | * index: clock enum value | ||
95 | * name: clock name | ||
96 | * init: default clock state when camera is opened. | ||
97 | * freq: initial clock frequency to set when camera is opened. If it is 0, | ||
98 | * then no need to set clock freq. | ||
99 | */ | ||
100 | struct clock_data { | ||
101 | int index; | ||
102 | char *name; | ||
103 | bool init; | ||
104 | unsigned long freq; | ||
105 | }; | ||
106 | |||
107 | struct tegra_camera *tegra_camera_register(struct platform_device *ndev); | ||
108 | int tegra_camera_unregister(struct tegra_camera *camera); | ||
109 | #ifdef CONFIG_PM | ||
110 | int tegra_camera_suspend(struct tegra_camera *camera); | ||
111 | int tegra_camera_resume(struct tegra_camera *camera); | ||
112 | #endif | ||
113 | |||
114 | #endif | ||
diff --git a/drivers/video/tegra/camera/tegra_camera_dev_mfi.c b/drivers/video/tegra/camera/tegra_camera_dev_mfi.c new file mode 100644 index 000000000..67e6eaaa1 --- /dev/null +++ b/drivers/video/tegra/camera/tegra_camera_dev_mfi.c | |||
@@ -0,0 +1,271 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/camera/tegra_camera_dev_mfi.c | ||
3 | * | ||
4 | * Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved. | ||
5 | |||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | |||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | |||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <linux/slab.h> | ||
20 | |||
21 | #include "tegra_camera_dev_mfi.h" | ||
22 | |||
23 | static LIST_HEAD(cmfidev_list); | ||
24 | static DEFINE_MUTEX(cmfidev_mutex); | ||
25 | |||
26 | int tegra_camera_dev_mfi_init(void) | ||
27 | { | ||
28 | INIT_LIST_HEAD(&cmfidev_list); | ||
29 | |||
30 | return 0; | ||
31 | } | ||
32 | |||
33 | void tegra_camera_dev_mfi_cb(void *stub) | ||
34 | { | ||
35 | u32 idx = 0; | ||
36 | struct camera_mfi_dev *itr = NULL; | ||
37 | int err = 0; | ||
38 | mutex_lock(&cmfidev_mutex); | ||
39 | list_for_each_entry(itr, &cmfidev_list, list) { | ||
40 | if (itr->regmap) { | ||
41 | /* MFI driver has to delay the focuser writes by one | ||
42 | * frame, which is required to get sync in focus | ||
43 | * position and sharpness. | ||
44 | * So write previous frame focuser settings in current | ||
45 | * frame's callback, and then save current frame focuser | ||
46 | * writes for next callback. | ||
47 | */ | ||
48 | for (idx = 0; idx < itr->prev_num_used; idx++) { | ||
49 | err = regmap_write(itr->regmap, | ||
50 | itr->prev_reg[idx].addr, | ||
51 | itr->prev_reg[idx].val); | ||
52 | if (err) | ||
53 | pr_err("%s: [%s] regmap_write failed\n", | ||
54 | __func__, itr->name); | ||
55 | } | ||
56 | /* Consume current settings, which would be programmed | ||
57 | * in next frame callback. | ||
58 | */ | ||
59 | for (idx = 0; idx < itr->num_used; idx++) { | ||
60 | itr->prev_reg[idx].addr = itr->reg[idx].addr; | ||
61 | itr->prev_reg[idx].val = itr->reg[idx].val; | ||
62 | } | ||
63 | itr->prev_num_used = itr->num_used; | ||
64 | } else if (itr->i2c_client) { | ||
65 | for (idx = 0; idx < itr->num_used; idx++) { | ||
66 | err = i2c_transfer(itr->i2c_client->adapter, | ||
67 | &itr->msg[idx].msg, 1); | ||
68 | if (err != 1) | ||
69 | pr_err("%s: [%s] i2c_transfer failed\n", | ||
70 | __func__, itr->name); | ||
71 | } | ||
72 | } else { | ||
73 | pr_err("%s [%s] Unknown device mechanism\n", | ||
74 | __func__, itr->name); | ||
75 | } | ||
76 | itr->num_used = 0; | ||
77 | } | ||
78 | mutex_unlock(&cmfidev_mutex); | ||
79 | } | ||
80 | |||
81 | int tegra_camera_dev_mfi_wr_add_i2c( | ||
82 | struct camera_mfi_dev *cmfidev, | ||
83 | struct i2c_msg *msg, int num) | ||
84 | { | ||
85 | int err = -ENODEV; | ||
86 | int i = 0; | ||
87 | struct camera_mfi_dev *itr = NULL; | ||
88 | |||
89 | if (!strcmp(cmfidev->name, "")) { | ||
90 | err = -EINVAL; | ||
91 | goto cmfi_wr_add_i2c_end; | ||
92 | } | ||
93 | |||
94 | mutex_lock(&cmfidev_mutex); | ||
95 | list_for_each_entry(itr, &cmfidev_list, list) { | ||
96 | if (!strcmp(itr->name, cmfidev->name)) { | ||
97 | if (itr->num_used == CAMERA_REGCACHE_MAX) | ||
98 | err = -ENOSPC; | ||
99 | else { | ||
100 | for (i = 0; i < num; i++) { | ||
101 | itr->msg[itr->num_used].msg = msg[i]; | ||
102 | memcpy(itr->msg[itr->num_used].buf, | ||
103 | msg[i].buf, | ||
104 | msg[i].len); | ||
105 | itr->msg[itr->num_used].msg.buf = | ||
106 | itr->msg[itr->num_used].buf; | ||
107 | itr->num_used++; | ||
108 | } | ||
109 | err = 0; | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | mutex_unlock(&cmfidev_mutex); | ||
114 | |||
115 | cmfi_wr_add_i2c_end: | ||
116 | return err; | ||
117 | } | ||
118 | EXPORT_SYMBOL(tegra_camera_dev_mfi_wr_add_i2c); | ||
119 | |||
120 | int tegra_camera_dev_mfi_wr_add( | ||
121 | struct camera_mfi_dev *cmfidev, | ||
122 | u32 offset, u32 val) | ||
123 | { | ||
124 | int err = -ENODEV; | ||
125 | struct camera_mfi_dev *itr = NULL; | ||
126 | |||
127 | if (cmfidev->name == NULL || !strcmp(cmfidev->name, "")) { | ||
128 | err = -EINVAL; | ||
129 | goto cmfi_wr_add_end; | ||
130 | } | ||
131 | |||
132 | mutex_lock(&cmfidev_mutex); | ||
133 | list_for_each_entry(itr, &cmfidev_list, list) { | ||
134 | if (!strcmp(itr->name, cmfidev->name)) { | ||
135 | if (itr->num_used == CAMERA_REGCACHE_MAX) { | ||
136 | err = -ENOSPC; | ||
137 | } else { | ||
138 | itr->reg[itr->num_used].addr = offset; | ||
139 | itr->reg[itr->num_used].val = val; | ||
140 | itr->num_used++; | ||
141 | err = 0; | ||
142 | } | ||
143 | } | ||
144 | } | ||
145 | mutex_unlock(&cmfidev_mutex); | ||
146 | |||
147 | cmfi_wr_add_end: | ||
148 | return err; | ||
149 | } | ||
150 | EXPORT_SYMBOL(tegra_camera_dev_mfi_wr_add); | ||
151 | |||
152 | int tegra_camera_dev_mfi_clear(struct camera_mfi_dev *cmfidev) | ||
153 | { | ||
154 | int err = -ENODEV; | ||
155 | struct camera_mfi_dev *itr = NULL; | ||
156 | |||
157 | if (cmfidev == NULL) { | ||
158 | err = -EINVAL; | ||
159 | goto cmfidev_clear_end; | ||
160 | } | ||
161 | |||
162 | if (cmfidev->name == NULL || !strcmp(cmfidev->name, "")) { | ||
163 | err = -EINVAL; | ||
164 | goto cmfidev_clear_end; | ||
165 | } | ||
166 | |||
167 | mutex_lock(&cmfidev_mutex); | ||
168 | list_for_each_entry(itr, &cmfidev_list, list) { | ||
169 | if (!strcmp(itr->name, cmfidev->name)) { | ||
170 | if (itr->num_used > 0) | ||
171 | pr_info("%s [%s] force clear Q pending writes\n", | ||
172 | __func__, itr->name); | ||
173 | itr->num_used = 0; | ||
174 | err = 0; | ||
175 | } | ||
176 | } | ||
177 | mutex_unlock(&cmfidev_mutex); | ||
178 | |||
179 | cmfidev_clear_end: | ||
180 | return err; | ||
181 | } | ||
182 | EXPORT_SYMBOL(tegra_camera_dev_mfi_clear); | ||
183 | |||
184 | int tegra_camera_dev_mfi_add_i2cclient( | ||
185 | struct camera_mfi_dev **cmfidev, | ||
186 | u8 *name, | ||
187 | struct i2c_client *i2c_client) | ||
188 | { | ||
189 | int err = 0; | ||
190 | struct camera_mfi_dev *itr = NULL; | ||
191 | struct camera_mfi_dev *new_cmfidev = NULL; | ||
192 | |||
193 | if (name == NULL || !strcmp(name, "")) | ||
194 | return -EINVAL; | ||
195 | |||
196 | mutex_lock(&cmfidev_mutex); | ||
197 | list_for_each_entry(itr, &cmfidev_list, list) { | ||
198 | if (!strcmp(itr->name, name)) { | ||
199 | err = -EEXIST; | ||
200 | goto cmfidev_add_i2c_unlock; | ||
201 | } | ||
202 | } | ||
203 | if (!err) { | ||
204 | new_cmfidev = | ||
205 | kzalloc(sizeof(struct camera_mfi_dev), GFP_KERNEL); | ||
206 | if (!new_cmfidev) { | ||
207 | pr_err("%s memory low!\n", __func__); | ||
208 | err = -ENOMEM; | ||
209 | goto cmfidev_add_i2c_unlock; | ||
210 | } | ||
211 | memset(new_cmfidev, 0, sizeof(struct camera_mfi_dev)); | ||
212 | strncpy(new_cmfidev->name, name, sizeof(new_cmfidev->name)-1); | ||
213 | INIT_LIST_HEAD(&new_cmfidev->list); | ||
214 | new_cmfidev->i2c_client = i2c_client; | ||
215 | new_cmfidev->num_used = 0; | ||
216 | list_add(&new_cmfidev->list, &cmfidev_list); | ||
217 | } | ||
218 | |||
219 | *cmfidev = new_cmfidev; | ||
220 | |||
221 | cmfidev_add_i2c_unlock: | ||
222 | mutex_unlock(&cmfidev_mutex); | ||
223 | |||
224 | return err; | ||
225 | } | ||
226 | EXPORT_SYMBOL(tegra_camera_dev_mfi_add_i2cclient); | ||
227 | |||
228 | int tegra_camera_dev_mfi_add_regmap( | ||
229 | struct camera_mfi_dev **cmfidev, | ||
230 | u8 *name, | ||
231 | struct regmap *regmap) | ||
232 | { | ||
233 | int err = 0; | ||
234 | struct camera_mfi_dev *itr = NULL; | ||
235 | struct camera_mfi_dev *new_cmfidev = NULL; | ||
236 | |||
237 | if (name == NULL || !strcmp(name, "")) | ||
238 | return -EINVAL; | ||
239 | |||
240 | mutex_lock(&cmfidev_mutex); | ||
241 | list_for_each_entry(itr, &cmfidev_list, list) { | ||
242 | if (!strcmp(itr->name, name)) { | ||
243 | err = -EEXIST; | ||
244 | goto cmfidev_add_regmap_unlock; | ||
245 | } | ||
246 | } | ||
247 | if (!err) { | ||
248 | new_cmfidev = | ||
249 | kzalloc(sizeof(struct camera_mfi_dev), GFP_KERNEL); | ||
250 | if (!new_cmfidev) { | ||
251 | pr_err("%s memory low!\n", __func__); | ||
252 | err = -ENOMEM; | ||
253 | goto cmfidev_add_regmap_unlock; | ||
254 | } | ||
255 | memset(new_cmfidev, 0, sizeof(struct camera_mfi_dev)); | ||
256 | strncpy(new_cmfidev->name, name, sizeof(new_cmfidev->name)-1); | ||
257 | INIT_LIST_HEAD(&new_cmfidev->list); | ||
258 | new_cmfidev->regmap = regmap; | ||
259 | new_cmfidev->num_used = 0; | ||
260 | new_cmfidev->prev_num_used = 0; | ||
261 | list_add(&new_cmfidev->list, &cmfidev_list); | ||
262 | } | ||
263 | |||
264 | *cmfidev = new_cmfidev; | ||
265 | |||
266 | cmfidev_add_regmap_unlock: | ||
267 | mutex_unlock(&cmfidev_mutex); | ||
268 | |||
269 | return err; | ||
270 | } | ||
271 | EXPORT_SYMBOL(tegra_camera_dev_mfi_add_regmap); | ||
diff --git a/drivers/video/tegra/camera/tegra_camera_dev_mfi.h b/drivers/video/tegra/camera/tegra_camera_dev_mfi.h new file mode 100644 index 000000000..675212502 --- /dev/null +++ b/drivers/video/tegra/camera/tegra_camera_dev_mfi.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved. | ||
3 | |||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | |||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | |||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #ifndef __CAMERA_DEV_MFI_H__ | ||
18 | #define __CAMERA_DEV_MFI_H__ | ||
19 | |||
20 | #include <linux/list.h> | ||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/regmap.h> | ||
23 | |||
24 | #define CAMERA_MAX_NAME_LENGTH 32 | ||
25 | #define CAMERA_REGCACHE_MAX (128) | ||
26 | |||
27 | struct cam_reg { | ||
28 | u32 addr; | ||
29 | u32 val; | ||
30 | }; | ||
31 | |||
32 | struct cam_i2c_msg { | ||
33 | struct i2c_msg msg; | ||
34 | u8 buf[8]; | ||
35 | }; | ||
36 | |||
37 | struct camera_mfi_dev { | ||
38 | char name[CAMERA_MAX_NAME_LENGTH]; | ||
39 | struct regmap *regmap; | ||
40 | struct cam_reg reg[CAMERA_REGCACHE_MAX]; | ||
41 | struct cam_reg prev_reg[CAMERA_REGCACHE_MAX]; | ||
42 | struct i2c_client *i2c_client; | ||
43 | struct cam_i2c_msg msg[CAMERA_REGCACHE_MAX]; | ||
44 | u32 num_used; | ||
45 | u32 prev_num_used; | ||
46 | struct list_head list; | ||
47 | }; | ||
48 | |||
49 | struct mfi_cb_arg { | ||
50 | u8 vi_chan; | ||
51 | }; | ||
52 | |||
53 | int tegra_camera_dev_mfi_init(void); | ||
54 | void tegra_camera_dev_mfi_cb(void *stub); | ||
55 | int tegra_camera_dev_mfi_clear(struct camera_mfi_dev *cmfidev); | ||
56 | int tegra_camera_dev_mfi_wr_add( | ||
57 | struct camera_mfi_dev *cmfidev, u32 offset, u32 val); | ||
58 | int tegra_camera_dev_mfi_wr_add_i2c( | ||
59 | struct camera_mfi_dev *cmfidev, struct i2c_msg *msg, int num); | ||
60 | int tegra_camera_dev_mfi_add_regmap( | ||
61 | struct camera_mfi_dev **cmfidev, u8 *name, struct regmap *regmap); | ||
62 | int tegra_camera_dev_mfi_add_i2cclient( | ||
63 | struct camera_mfi_dev **cmfidev, u8 *name, | ||
64 | struct i2c_client *i2c_client); | ||
65 | |||
66 | #endif | ||
67 | /* __CAMERA_DEV_MFI_H__ */ | ||
diff --git a/drivers/video/tegra/camera/tegra_camera_platform.c b/drivers/video/tegra/camera/tegra_camera_platform.c new file mode 100644 index 000000000..206294c5b --- /dev/null +++ b/drivers/video/tegra/camera/tegra_camera_platform.c | |||
@@ -0,0 +1,582 @@ | |||
1 | /* | ||
2 | * drivers/video/tegra/camera/tegra_camera_platform.c | ||
3 | * | ||
4 | * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved. | ||
5 | * | ||
6 | * This software is licensed under the terms of the GNU General Public | ||
7 | * License version 2, as published by the Free Software Foundation, and | ||
8 | * may be copied, distributed, and modified under those terms. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | #include <linux/fs.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/uaccess.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/miscdevice.h> | ||
22 | #include <linux/clk.h> | ||
23 | #include <linux/of.h> | ||
24 | #include <soc/tegra/tegra_emc.h> | ||
25 | |||
26 | #include "vi/vi.h" | ||
27 | #include "tegra_camera_dev_mfi.h" | ||
28 | #include <media/tegra_camera_platform.h> | ||
29 | #include "camera_priv_defs.h" | ||
30 | |||
31 | #define CAMDEV_NAME "tegra_camera_ctrl" | ||
32 | |||
33 | /* Peak BPP for any of the YUV/Bayer formats */ | ||
34 | #define CAMERA_PEAK_BPP 2 | ||
35 | |||
36 | #define LANE_SPEED_1_GBPS 1000000000 | ||
37 | #define LANE_SPEED_1_5_GBPS 1500000000 | ||
38 | |||
39 | #if defined(CONFIG_TEGRA_BWMGR) | ||
40 | #include <linux/platform/tegra/emc_bwmgr.h> | ||
41 | #endif | ||
42 | |||
43 | struct tegra_camera_info { | ||
44 | char devname[64]; | ||
45 | atomic_t in_use; | ||
46 | struct device *dev; | ||
47 | #if defined(CONFIG_TEGRA_BWMGR) | ||
48 | /* bandwidth manager handle */ | ||
49 | struct tegra_bwmgr_client *bwmgr_handle; | ||
50 | #endif | ||
51 | struct clk *emc; | ||
52 | struct clk *iso_emc; | ||
53 | #if defined(CONFIG_TEGRA_ISOMGR) | ||
54 | tegra_isomgr_handle isomgr_handle; | ||
55 | u64 max_bw; | ||
56 | #endif | ||
57 | struct mutex update_bw_lock; | ||
58 | u32 vi_mode_isobw; | ||
59 | u64 bypass_mode_isobw; | ||
60 | /* set max bw by default */ | ||
61 | bool en_max_bw; | ||
62 | }; | ||
63 | |||
64 | static const struct of_device_id tegra_camera_of_ids[] = { | ||
65 | { .compatible = "nvidia, tegra-camera-platform" }, | ||
66 | { }, | ||
67 | }; | ||
68 | |||
69 | static struct miscdevice tegra_camera_misc; | ||
70 | |||
71 | static int tegra_camera_isomgr_register(struct tegra_camera_info *info, | ||
72 | struct device *dev) | ||
73 | { | ||
74 | #if defined(CONFIG_TEGRA_ISOMGR) | ||
75 | int ret = 0; | ||
76 | u32 num_csi_lanes = 0; | ||
77 | u32 max_lane_speed = 0; | ||
78 | u32 bits_per_pixel = 0; | ||
79 | u32 vi_bpp = 0; | ||
80 | u64 vi_iso_bw = 0; | ||
81 | u32 vi_margin_pct = 0; | ||
82 | u32 max_pixel_rate = 0; | ||
83 | u32 isp_bpp = 0; | ||
84 | u64 isp_iso_bw = 0; | ||
85 | u32 isp_margin_pct = 0; | ||
86 | u32 tpg_max_iso = 0; | ||
87 | struct device_node *np = dev->of_node; | ||
88 | |||
89 | dev_dbg(info->dev, "%s++\n", __func__); | ||
90 | |||
91 | ret |= of_property_read_u32(np, "num_csi_lanes", &num_csi_lanes); | ||
92 | ret |= of_property_read_u32(np, "max_lane_speed", &max_lane_speed); | ||
93 | ret |= of_property_read_u32(np, "min_bits_per_pixel", &bits_per_pixel); | ||
94 | ret |= of_property_read_u32(np, "vi_peak_byte_per_pixel", &vi_bpp); | ||
95 | ret |= of_property_read_u32(np, "vi_bw_margin_pct", &vi_margin_pct); | ||
96 | ret |= of_property_read_u32(np, "max_pixel_rate", &max_pixel_rate); | ||
97 | ret |= of_property_read_u32(np, "isp_peak_byte_per_pixel", &isp_bpp); | ||
98 | ret |= of_property_read_u32(np, "isp_bw_margin_pct", &isp_margin_pct); | ||
99 | |||
100 | if (ret) | ||
101 | dev_info(info->dev, "%s: some fields not in DT.\n", __func__); | ||
102 | |||
103 | /* | ||
104 | * Use per-camera specifics to calculate ISO BW needed, | ||
105 | * which is smaller than the per-asic max. | ||
106 | * | ||
107 | * The formula for VI ISO BW is based on total number | ||
108 | * of active csi lanes when all cameras on the camera | ||
109 | * board are active. | ||
110 | * | ||
111 | * The formula for ISP ISO BW is based on max number | ||
112 | * of ISP's used in ISO mode given number of camera(s) | ||
113 | * on the camera board and the number of ISP's on the ASIC. | ||
114 | * | ||
115 | * The final ISO BW is based on the max of the two. | ||
116 | */ | ||
117 | if (!bits_per_pixel) { | ||
118 | dev_err(info->dev, "bits_per_pixel is invalid\n"); | ||
119 | return -EINVAL; | ||
120 | } | ||
121 | vi_iso_bw = ((num_csi_lanes * max_lane_speed) / bits_per_pixel) | ||
122 | * vi_bpp * (100 + vi_margin_pct) / 100; | ||
123 | isp_iso_bw = max_pixel_rate * isp_bpp * (100 + isp_margin_pct) / 100; | ||
124 | if (vi_iso_bw > isp_iso_bw) | ||
125 | info->max_bw = vi_iso_bw; | ||
126 | else | ||
127 | info->max_bw = isp_iso_bw; | ||
128 | |||
129 | if (!info->max_bw) { | ||
130 | dev_err(info->dev, "%s: BW must be non-zero\n", __func__); | ||
131 | return -EINVAL; | ||
132 | } | ||
133 | |||
134 | ret = of_property_read_u32(np, "tpg_max_iso", &tpg_max_iso); | ||
135 | if (ret) | ||
136 | tpg_max_iso = 0; | ||
137 | else { | ||
138 | dev_info(info->dev, "%s tpg_max_iso = %uKBs\n", __func__, | ||
139 | tpg_max_iso); | ||
140 | info->max_bw = max_t(u64, info->max_bw, tpg_max_iso); | ||
141 | } | ||
142 | |||
143 | dev_info(info->dev, "%s isp_iso_bw=%llu, vi_iso_bw=%llu, max_bw=%llu\n", | ||
144 | __func__, isp_iso_bw, vi_iso_bw, info->max_bw); | ||
145 | |||
146 | /* Register with max possible BW for CAMERA usecases.*/ | ||
147 | info->isomgr_handle = tegra_isomgr_register( | ||
148 | TEGRA_ISO_CLIENT_TEGRA_CAMERA, | ||
149 | info->max_bw, | ||
150 | NULL, /* tegra_isomgr_renegotiate */ | ||
151 | NULL); /* *priv */ | ||
152 | |||
153 | if (IS_ERR(info->isomgr_handle)) { | ||
154 | dev_err(info->dev, | ||
155 | "%s: unable to register to isomgr\n", | ||
156 | __func__); | ||
157 | return -ENOMEM; | ||
158 | } | ||
159 | #endif | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | static int tegra_camera_isomgr_unregister(struct tegra_camera_info *info) | ||
165 | { | ||
166 | #if defined(CONFIG_TEGRA_ISOMGR) | ||
167 | tegra_isomgr_unregister(info->isomgr_handle); | ||
168 | info->isomgr_handle = NULL; | ||
169 | #endif | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static int tegra_camera_isomgr_request( | ||
175 | struct tegra_camera_info *info, uint iso_bw, uint lt) | ||
176 | { | ||
177 | #if defined(CONFIG_TEGRA_ISOMGR) | ||
178 | int ret = 0; | ||
179 | |||
180 | dev_dbg(info->dev, | ||
181 | "%s++ bw=%u, lt=%u\n", __func__, iso_bw, lt); | ||
182 | |||
183 | if (!info->isomgr_handle) { | ||
184 | dev_err(info->dev, | ||
185 | "%s: isomgr_handle is NULL\n", | ||
186 | __func__); | ||
187 | return -EINVAL; | ||
188 | } | ||
189 | |||
190 | /* return value of tegra_isomgr_reserve is dvfs latency in usec */ | ||
191 | ret = tegra_isomgr_reserve(info->isomgr_handle, | ||
192 | iso_bw, /* KB/sec */ | ||
193 | lt); /* usec */ | ||
194 | if (!ret) { | ||
195 | dev_err(info->dev, | ||
196 | "%s: failed to reserve %u KBps\n", __func__, iso_bw); | ||
197 | return -ENOMEM; | ||
198 | } | ||
199 | |||
200 | /* return value of tegra_isomgr_realize is dvfs latency in usec */ | ||
201 | ret = tegra_isomgr_realize(info->isomgr_handle); | ||
202 | if (ret) | ||
203 | dev_dbg(info->dev, | ||
204 | "%s: tegra_camera isomgr latency is %d usec", | ||
205 | __func__, ret); | ||
206 | else { | ||
207 | dev_err(info->dev, | ||
208 | "%s: failed to realize %u KBps\n", __func__, iso_bw); | ||
209 | return -ENOMEM; | ||
210 | } | ||
211 | #endif | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static int tegra_camera_isomgr_release(struct tegra_camera_info *info) | ||
217 | { | ||
218 | #if defined(CONFIG_TEGRA_ISOMGR) | ||
219 | int ret = 0; | ||
220 | |||
221 | dev_dbg(info->dev, "%s++\n", __func__); | ||
222 | |||
223 | /* deallocate bypass mode isomgr bw */ | ||
224 | info->bypass_mode_isobw = 0; | ||
225 | return vi_v4l2_update_isobw(0, 1); | ||
226 | #endif | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | int tegra_camera_emc_clk_enable(void) | ||
231 | { | ||
232 | #if defined(CONFIG_TEGRA_BWMGR) | ||
233 | return 0; | ||
234 | #else | ||
235 | struct tegra_camera_info *info; | ||
236 | int ret = 0; | ||
237 | |||
238 | info = dev_get_drvdata(tegra_camera_misc.parent); | ||
239 | if (!info) | ||
240 | return -EINVAL; | ||
241 | ret = clk_prepare_enable(info->emc); | ||
242 | if (ret) { | ||
243 | dev_err(info->dev, "Cannot enable camera.emc\n"); | ||
244 | return ret; | ||
245 | } | ||
246 | |||
247 | ret = clk_prepare_enable(info->iso_emc); | ||
248 | if (ret) { | ||
249 | dev_err(info->dev, "Cannot enable camera_iso.emc\n"); | ||
250 | goto err_iso_emc; | ||
251 | } | ||
252 | |||
253 | return 0; | ||
254 | err_iso_emc: | ||
255 | clk_disable_unprepare(info->emc); | ||
256 | return ret; | ||
257 | #endif | ||
258 | } | ||
259 | EXPORT_SYMBOL(tegra_camera_emc_clk_enable); | ||
260 | |||
261 | int tegra_camera_emc_clk_disable(void) | ||
262 | { | ||
263 | #if defined(CONFIG_TEGRA_BWMGR) | ||
264 | return 0; | ||
265 | #else | ||
266 | struct tegra_camera_info *info; | ||
267 | |||
268 | info = dev_get_drvdata(tegra_camera_misc.parent); | ||
269 | if (!info) | ||
270 | return -EINVAL; | ||
271 | clk_disable_unprepare(info->emc); | ||
272 | clk_disable_unprepare(info->iso_emc); | ||
273 | return 0; | ||
274 | #endif | ||
275 | } | ||
276 | EXPORT_SYMBOL(tegra_camera_emc_clk_disable); | ||
277 | |||
278 | static int tegra_camera_open(struct inode *inode, struct file *file) | ||
279 | { | ||
280 | struct tegra_camera_info *info; | ||
281 | struct miscdevice *mdev; | ||
282 | |||
283 | mdev = file->private_data; | ||
284 | info = dev_get_drvdata(mdev->parent); | ||
285 | file->private_data = info; | ||
286 | #if defined(CONFIG_TEGRA_BWMGR) | ||
287 | /* get bandwidth manager handle if needed */ | ||
288 | info->bwmgr_handle = | ||
289 | tegra_bwmgr_register(TEGRA_BWMGR_CLIENT_CAMERA); | ||
290 | |||
291 | /* set the initial rate */ | ||
292 | if (IS_ERR_OR_NULL(info->bwmgr_handle)) { | ||
293 | info->bwmgr_handle = NULL; | ||
294 | return -ENODEV; | ||
295 | } | ||
296 | tegra_bwmgr_set_emc(info->bwmgr_handle, 0, | ||
297 | TEGRA_BWMGR_SET_EMC_SHARED_BW); | ||
298 | return 0; | ||
299 | #else | ||
300 | return tegra_camera_emc_clk_enable(); | ||
301 | #endif | ||
302 | } | ||
303 | |||
304 | static int tegra_camera_release(struct inode *inode, struct file *file) | ||
305 | { | ||
306 | |||
307 | struct tegra_camera_info *info; | ||
308 | int ret; | ||
309 | |||
310 | info = file->private_data; | ||
311 | #if defined(CONFIG_TEGRA_BWMGR) | ||
312 | tegra_bwmgr_unregister(info->bwmgr_handle); | ||
313 | #else | ||
314 | tegra_camera_emc_clk_disable(); | ||
315 | #endif | ||
316 | /* nullify isomgr request */ | ||
317 | ret = tegra_camera_isomgr_release(info); | ||
318 | if (ret) { | ||
319 | dev_err(info->dev, | ||
320 | "%s: failed to deallocate memory in isomgr\n", | ||
321 | __func__); | ||
322 | return -ENOMEM; | ||
323 | } | ||
324 | return ret; | ||
325 | } | ||
326 | |||
327 | #ifdef CONFIG_DEBUG_FS | ||
328 | static u64 vi_mode_d; | ||
329 | static u64 bypass_mode_d; | ||
330 | |||
331 | static int dbgfs_tegra_camera_init(void) | ||
332 | { | ||
333 | struct dentry *dir; | ||
334 | struct dentry *val; | ||
335 | |||
336 | dir = debugfs_create_dir("tegra_camera_platform", NULL); | ||
337 | if (!dir) | ||
338 | return -ENOMEM; | ||
339 | |||
340 | val = debugfs_create_u64("vi", S_IRUGO, dir, &vi_mode_d); | ||
341 | if (!val) | ||
342 | return -ENOMEM; | ||
343 | val = debugfs_create_u64("scf", S_IRUGO, dir, &bypass_mode_d); | ||
344 | if (!val) | ||
345 | return -ENOMEM; | ||
346 | return 0; | ||
347 | } | ||
348 | #endif | ||
349 | |||
350 | /* | ||
351 | * vi_kbyteps: Iso bw request from V4L2 vi driver. | ||
352 | * is_ioctl: Whether this function is called by userspace or kernel. | ||
353 | * This function aggregates V4L2 vi driver's request with userspace (SCF) | ||
354 | * iso bw request and submit total to isomgr. | ||
355 | */ | ||
356 | int vi_v4l2_update_isobw(u32 vi_kbyteps, u32 is_ioctl) | ||
357 | { | ||
358 | struct tegra_camera_info *info; | ||
359 | unsigned long total_khz; | ||
360 | unsigned long bw; | ||
361 | int ret = 0; | ||
362 | |||
363 | if (tegra_camera_misc.parent == NULL) { | ||
364 | pr_info("driver not enabled, cannot update bw\n"); | ||
365 | return -ENODEV; | ||
366 | } | ||
367 | |||
368 | info = dev_get_drvdata(tegra_camera_misc.parent); | ||
369 | if (!info) | ||
370 | return -ENODEV; | ||
371 | mutex_lock(&info->update_bw_lock); | ||
372 | if (!is_ioctl) | ||
373 | info->vi_mode_isobw = vi_kbyteps; | ||
374 | bw = info->bypass_mode_isobw + info->vi_mode_isobw; | ||
375 | |||
376 | /* Use Khz to prevent overflow */ | ||
377 | total_khz = tegra_emc_bw_to_freq_req(bw); | ||
378 | total_khz = min(ULONG_MAX / 1000, total_khz); | ||
379 | |||
380 | dev_dbg(info->dev, "%s:Set iso bw %lu kbyteps at %lu KHz\n", | ||
381 | __func__, bw, total_khz); | ||
382 | #if !defined(CONFIG_TEGRA_BWMGR) | ||
383 | ret = clk_set_rate(info->iso_emc, total_khz * 1000); | ||
384 | if (ret) | ||
385 | dev_err(info->dev, "%s:Failed to set iso bw\n", | ||
386 | __func__); | ||
387 | #endif | ||
388 | /* | ||
389 | * Request to ISOMGR. | ||
390 | * 3 usec is minimum time to switch PLL source. | ||
391 | * Let's put 4 usec as latency for now. | ||
392 | */ | ||
393 | ret = tegra_camera_isomgr_request(info, bw, 4); | ||
394 | if (ret) { | ||
395 | dev_err(info->dev, | ||
396 | "%s: failed to reserve %lu KBps with isomgr\n", | ||
397 | __func__, bw); | ||
398 | mutex_unlock(&info->update_bw_lock); | ||
399 | return -ENOMEM; | ||
400 | } | ||
401 | |||
402 | #ifdef CONFIG_DEBUG_FS | ||
403 | vi_mode_d = info->vi_mode_isobw; | ||
404 | bypass_mode_d = info->bypass_mode_isobw; | ||
405 | #endif | ||
406 | mutex_unlock(&info->update_bw_lock); | ||
407 | return ret; | ||
408 | } | ||
409 | EXPORT_SYMBOL(vi_v4l2_update_isobw); | ||
410 | |||
411 | static long tegra_camera_ioctl(struct file *file, | ||
412 | unsigned int cmd, unsigned long arg) | ||
413 | { | ||
414 | int ret = 0; | ||
415 | struct tegra_camera_info *info; | ||
416 | |||
417 | info = file->private_data; | ||
418 | |||
419 | switch (_IOC_NR(cmd)) { | ||
420 | case _IOC_NR(TEGRA_CAMERA_IOCTL_SET_BW): | ||
421 | { | ||
422 | struct bw_info kcopy; | ||
423 | unsigned long mc_khz = 0; | ||
424 | |||
425 | memset(&kcopy, 0, sizeof(kcopy)); | ||
426 | |||
427 | if (copy_from_user(&kcopy, (const void __user *)arg, | ||
428 | sizeof(struct bw_info))) { | ||
429 | dev_err(info->dev, "%s:Failed to get data from user\n", | ||
430 | __func__); | ||
431 | return -EFAULT; | ||
432 | } | ||
433 | /* Use Khz to prevent overflow */ | ||
434 | mc_khz = tegra_emc_bw_to_freq_req(kcopy.bw); | ||
435 | mc_khz = min(ULONG_MAX / 1000, mc_khz); | ||
436 | |||
437 | if (kcopy.is_iso) { | ||
438 | info->bypass_mode_isobw = kcopy.bw; | ||
439 | ret = vi_v4l2_update_isobw(0, 1); | ||
440 | } else { | ||
441 | dev_dbg(info->dev, "%s:Set bw %llu at %lu KHz\n", | ||
442 | __func__, kcopy.bw, mc_khz); | ||
443 | #if defined(CONFIG_TEGRA_BWMGR) | ||
444 | ret = tegra_bwmgr_set_emc(info->bwmgr_handle, | ||
445 | mc_khz*1000, TEGRA_BWMGR_SET_EMC_SHARED_BW); | ||
446 | #else | ||
447 | ret = clk_set_rate(info->emc, mc_khz * 1000); | ||
448 | #endif | ||
449 | } | ||
450 | break; | ||
451 | } | ||
452 | default: | ||
453 | break; | ||
454 | } | ||
455 | return ret; | ||
456 | } | ||
457 | |||
458 | static const struct file_operations tegra_camera_ops = { | ||
459 | .owner = THIS_MODULE, | ||
460 | .open = tegra_camera_open, | ||
461 | .unlocked_ioctl = tegra_camera_ioctl, | ||
462 | #ifdef CONFIG_COMPAT | ||
463 | .compat_ioctl = tegra_camera_ioctl, | ||
464 | #endif | ||
465 | .release = tegra_camera_release, | ||
466 | }; | ||
467 | |||
468 | |||
469 | |||
470 | static int tegra_camera_probe(struct platform_device *pdev) | ||
471 | { | ||
472 | int ret; | ||
473 | struct tegra_camera_info *info; | ||
474 | |||
475 | dev_info(&pdev->dev, "%s:camera_platform_driver probe\n", __func__); | ||
476 | |||
477 | tegra_camera_misc.minor = MISC_DYNAMIC_MINOR; | ||
478 | tegra_camera_misc.name = CAMDEV_NAME; | ||
479 | tegra_camera_misc.fops = &tegra_camera_ops; | ||
480 | tegra_camera_misc.parent = &pdev->dev; | ||
481 | |||
482 | ret = misc_register(&tegra_camera_misc); | ||
483 | if (ret) { | ||
484 | dev_err(tegra_camera_misc.this_device, | ||
485 | "register failed for %s\n", | ||
486 | tegra_camera_misc.name); | ||
487 | return ret; | ||
488 | } | ||
489 | info = devm_kzalloc(tegra_camera_misc.this_device, | ||
490 | sizeof(struct tegra_camera_info), GFP_KERNEL); | ||
491 | if (!info) | ||
492 | return -ENOMEM; | ||
493 | |||
494 | strcpy(info->devname, tegra_camera_misc.name); | ||
495 | info->dev = tegra_camera_misc.this_device; | ||
496 | |||
497 | #if !defined(CONFIG_TEGRA_BWMGR) | ||
498 | info->emc = devm_clk_get(info->dev, "emc"); | ||
499 | if (IS_ERR(info->emc)) { | ||
500 | dev_err(info->dev, "Failed to get camera.emc\n"); | ||
501 | return -EINVAL; | ||
502 | } | ||
503 | clk_set_rate(info->emc, 0); | ||
504 | info->iso_emc = devm_clk_get(info->dev, "iso.emc"); | ||
505 | if (IS_ERR(info->iso_emc)) { | ||
506 | dev_err(info->dev, "Failed to get camera_iso.emc\n"); | ||
507 | return -EINVAL; | ||
508 | } | ||
509 | clk_set_rate(info->iso_emc, 0); | ||
510 | #endif | ||
511 | mutex_init(&info->update_bw_lock); | ||
512 | /* Register Camera as isomgr client. */ | ||
513 | ret = tegra_camera_isomgr_register(info, &pdev->dev); | ||
514 | if (ret) { | ||
515 | dev_err(info->dev, | ||
516 | "%s: failed to register CAMERA as isomgr client\n", | ||
517 | __func__); | ||
518 | return -ENOMEM; | ||
519 | } | ||
520 | |||
521 | info->en_max_bw = of_property_read_bool(pdev->dev.of_node, | ||
522 | "default-max-bw"); | ||
523 | if (info->en_max_bw == true) { | ||
524 | ret = tegra_camera_isomgr_request(info, info->max_bw, 4); | ||
525 | if (ret) { | ||
526 | dev_err(info->dev, | ||
527 | "%s: failed to request max bw\n", __func__); | ||
528 | tegra_camera_isomgr_unregister(info); | ||
529 | return -EFAULT; | ||
530 | } | ||
531 | } | ||
532 | |||
533 | tegra_camera_dev_mfi_init(); | ||
534 | tegra_vi_register_mfi_cb(tegra_camera_dev_mfi_cb, NULL); | ||
535 | |||
536 | platform_set_drvdata(pdev, info); | ||
537 | #ifdef CONFIG_DEBUG_FS | ||
538 | ret = dbgfs_tegra_camera_init(); | ||
539 | if (ret) | ||
540 | dev_err(info->dev, "Fail to create debugfs"); | ||
541 | #endif | ||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | static int tegra_camera_remove(struct platform_device *pdev) | ||
546 | { | ||
547 | struct tegra_camera_info *info = platform_get_drvdata(pdev); | ||
548 | |||
549 | dev_info(&pdev->dev, "%s:camera_platform_driver remove\n", __func__); | ||
550 | |||
551 | /* deallocate isomgr bw */ | ||
552 | if (info->en_max_bw) | ||
553 | tegra_camera_isomgr_request(info, 0, 4); | ||
554 | |||
555 | tegra_vi_unregister_mfi_cb(); | ||
556 | tegra_camera_isomgr_unregister(info); | ||
557 | misc_deregister(&tegra_camera_misc); | ||
558 | |||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | static struct platform_driver tegra_camera_driver = { | ||
563 | .probe = tegra_camera_probe, | ||
564 | .remove = tegra_camera_remove, | ||
565 | .driver = { | ||
566 | .owner = THIS_MODULE, | ||
567 | .name = "tegra_camera_platform", | ||
568 | .of_match_table = tegra_camera_of_ids | ||
569 | } | ||
570 | }; | ||
571 | static int __init tegra_camera_init(void) | ||
572 | { | ||
573 | return platform_driver_register(&tegra_camera_driver); | ||
574 | } | ||
575 | static void __exit tegra_camera_exit(void) | ||
576 | { | ||
577 | platform_driver_unregister(&tegra_camera_driver); | ||
578 | } | ||
579 | |||
580 | module_init(tegra_camera_init); | ||
581 | module_exit(tegra_camera_exit); | ||
582 | |||