18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * mt9t112 Camera Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2018 Jacopo Mondi <jacopo+renesas@jmondi.org> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2009 Renesas Solutions Corp. 88c2ecf20Sopenharmony_ci * Kuninori Morimoto <morimoto.kuninori@renesas.com> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Based on ov772x driver, mt9m111 driver, 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com> 138c2ecf20Sopenharmony_ci * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr> 148c2ecf20Sopenharmony_ci * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> 158c2ecf20Sopenharmony_ci * Copyright (C) 2008 Magnus Damm 168c2ecf20Sopenharmony_ci * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * TODO: This driver lacks support for frame rate control due to missing 198c2ecf20Sopenharmony_ci * register level documentation and suitable hardware for testing. 208c2ecf20Sopenharmony_ci * v4l-utils compliance tools will report errors. 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <linux/clk.h> 248c2ecf20Sopenharmony_ci#include <linux/delay.h> 258c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 268c2ecf20Sopenharmony_ci#include <linux/i2c.h> 278c2ecf20Sopenharmony_ci#include <linux/init.h> 288c2ecf20Sopenharmony_ci#include <linux/module.h> 298c2ecf20Sopenharmony_ci#include <linux/slab.h> 308c2ecf20Sopenharmony_ci#include <linux/v4l2-mediabus.h> 318c2ecf20Sopenharmony_ci#include <linux/videodev2.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <media/i2c/mt9t112.h> 348c2ecf20Sopenharmony_ci#include <media/v4l2-common.h> 358c2ecf20Sopenharmony_ci#include <media/v4l2-image-sizes.h> 368c2ecf20Sopenharmony_ci#include <media/v4l2-subdev.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* you can check PLL/clock info */ 398c2ecf20Sopenharmony_ci/* #define EXT_CLOCK 24000000 */ 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/************************************************************************ 428c2ecf20Sopenharmony_ci * macro 438c2ecf20Sopenharmony_ci ***********************************************************************/ 448c2ecf20Sopenharmony_ci/* 458c2ecf20Sopenharmony_ci * frame size 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci#define MAX_WIDTH 2048 488c2ecf20Sopenharmony_ci#define MAX_HEIGHT 1536 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* 518c2ecf20Sopenharmony_ci * macro of read/write 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_ci#define ECHECKER(ret, x) \ 548c2ecf20Sopenharmony_ci do { \ 558c2ecf20Sopenharmony_ci (ret) = (x); \ 568c2ecf20Sopenharmony_ci if ((ret) < 0) \ 578c2ecf20Sopenharmony_ci return (ret); \ 588c2ecf20Sopenharmony_ci } while (0) 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define mt9t112_reg_write(ret, client, a, b) \ 618c2ecf20Sopenharmony_ci ECHECKER(ret, __mt9t112_reg_write(client, a, b)) 628c2ecf20Sopenharmony_ci#define mt9t112_mcu_write(ret, client, a, b) \ 638c2ecf20Sopenharmony_ci ECHECKER(ret, __mt9t112_mcu_write(client, a, b)) 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define mt9t112_reg_mask_set(ret, client, a, b, c) \ 668c2ecf20Sopenharmony_ci ECHECKER(ret, __mt9t112_reg_mask_set(client, a, b, c)) 678c2ecf20Sopenharmony_ci#define mt9t112_mcu_mask_set(ret, client, a, b, c) \ 688c2ecf20Sopenharmony_ci ECHECKER(ret, __mt9t112_mcu_mask_set(client, a, b, c)) 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#define mt9t112_reg_read(ret, client, a) \ 718c2ecf20Sopenharmony_ci ECHECKER(ret, __mt9t112_reg_read(client, a)) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* 748c2ecf20Sopenharmony_ci * Logical address 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_ci#define _VAR(id, offset, base) (base | (id & 0x1f) << 10 | (offset & 0x3ff)) 778c2ecf20Sopenharmony_ci#define VAR(id, offset) _VAR(id, offset, 0x0000) 788c2ecf20Sopenharmony_ci#define VAR8(id, offset) _VAR(id, offset, 0x8000) 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/************************************************************************ 818c2ecf20Sopenharmony_ci * struct 828c2ecf20Sopenharmony_ci ***********************************************************************/ 838c2ecf20Sopenharmony_cistruct mt9t112_format { 848c2ecf20Sopenharmony_ci u32 code; 858c2ecf20Sopenharmony_ci enum v4l2_colorspace colorspace; 868c2ecf20Sopenharmony_ci u16 fmt; 878c2ecf20Sopenharmony_ci u16 order; 888c2ecf20Sopenharmony_ci}; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistruct mt9t112_priv { 918c2ecf20Sopenharmony_ci struct v4l2_subdev subdev; 928c2ecf20Sopenharmony_ci struct mt9t112_platform_data *info; 938c2ecf20Sopenharmony_ci struct i2c_client *client; 948c2ecf20Sopenharmony_ci struct v4l2_rect frame; 958c2ecf20Sopenharmony_ci struct clk *clk; 968c2ecf20Sopenharmony_ci struct gpio_desc *standby_gpio; 978c2ecf20Sopenharmony_ci const struct mt9t112_format *format; 988c2ecf20Sopenharmony_ci int num_formats; 998c2ecf20Sopenharmony_ci bool init_done; 1008c2ecf20Sopenharmony_ci}; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/************************************************************************ 1038c2ecf20Sopenharmony_ci * supported format 1048c2ecf20Sopenharmony_ci ***********************************************************************/ 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic const struct mt9t112_format mt9t112_cfmts[] = { 1078c2ecf20Sopenharmony_ci { 1088c2ecf20Sopenharmony_ci .code = MEDIA_BUS_FMT_UYVY8_2X8, 1098c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 1108c2ecf20Sopenharmony_ci .fmt = 1, 1118c2ecf20Sopenharmony_ci .order = 0, 1128c2ecf20Sopenharmony_ci }, { 1138c2ecf20Sopenharmony_ci .code = MEDIA_BUS_FMT_VYUY8_2X8, 1148c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 1158c2ecf20Sopenharmony_ci .fmt = 1, 1168c2ecf20Sopenharmony_ci .order = 1, 1178c2ecf20Sopenharmony_ci }, { 1188c2ecf20Sopenharmony_ci .code = MEDIA_BUS_FMT_YUYV8_2X8, 1198c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 1208c2ecf20Sopenharmony_ci .fmt = 1, 1218c2ecf20Sopenharmony_ci .order = 2, 1228c2ecf20Sopenharmony_ci }, { 1238c2ecf20Sopenharmony_ci .code = MEDIA_BUS_FMT_YVYU8_2X8, 1248c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 1258c2ecf20Sopenharmony_ci .fmt = 1, 1268c2ecf20Sopenharmony_ci .order = 3, 1278c2ecf20Sopenharmony_ci }, { 1288c2ecf20Sopenharmony_ci .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, 1298c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 1308c2ecf20Sopenharmony_ci .fmt = 8, 1318c2ecf20Sopenharmony_ci .order = 2, 1328c2ecf20Sopenharmony_ci }, { 1338c2ecf20Sopenharmony_ci .code = MEDIA_BUS_FMT_RGB565_2X8_LE, 1348c2ecf20Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 1358c2ecf20Sopenharmony_ci .fmt = 4, 1368c2ecf20Sopenharmony_ci .order = 2, 1378c2ecf20Sopenharmony_ci }, 1388c2ecf20Sopenharmony_ci}; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/************************************************************************ 1418c2ecf20Sopenharmony_ci * general function 1428c2ecf20Sopenharmony_ci ***********************************************************************/ 1438c2ecf20Sopenharmony_cistatic struct mt9t112_priv *to_mt9t112(const struct i2c_client *client) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci return container_of(i2c_get_clientdata(client), 1468c2ecf20Sopenharmony_ci struct mt9t112_priv, 1478c2ecf20Sopenharmony_ci subdev); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic int __mt9t112_reg_read(const struct i2c_client *client, u16 command) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci struct i2c_msg msg[2]; 1538c2ecf20Sopenharmony_ci u8 buf[2]; 1548c2ecf20Sopenharmony_ci int ret; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci command = swab16(command); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci msg[0].addr = client->addr; 1598c2ecf20Sopenharmony_ci msg[0].flags = 0; 1608c2ecf20Sopenharmony_ci msg[0].len = 2; 1618c2ecf20Sopenharmony_ci msg[0].buf = (u8 *)&command; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci msg[1].addr = client->addr; 1648c2ecf20Sopenharmony_ci msg[1].flags = I2C_M_RD; 1658c2ecf20Sopenharmony_ci msg[1].len = 2; 1668c2ecf20Sopenharmony_ci msg[1].buf = buf; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* 1698c2ecf20Sopenharmony_ci * If return value of this function is < 0, it means error, else, 1708c2ecf20Sopenharmony_ci * below 16bit is valid data. 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_ci ret = i2c_transfer(client->adapter, msg, 2); 1738c2ecf20Sopenharmony_ci if (ret < 0) 1748c2ecf20Sopenharmony_ci return ret; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci memcpy(&ret, buf, 2); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return swab16(ret); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic int __mt9t112_reg_write(const struct i2c_client *client, 1828c2ecf20Sopenharmony_ci u16 command, u16 data) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct i2c_msg msg; 1858c2ecf20Sopenharmony_ci u8 buf[4]; 1868c2ecf20Sopenharmony_ci int ret; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci command = swab16(command); 1898c2ecf20Sopenharmony_ci data = swab16(data); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci memcpy(buf + 0, &command, 2); 1928c2ecf20Sopenharmony_ci memcpy(buf + 2, &data, 2); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci msg.addr = client->addr; 1958c2ecf20Sopenharmony_ci msg.flags = 0; 1968c2ecf20Sopenharmony_ci msg.len = 4; 1978c2ecf20Sopenharmony_ci msg.buf = buf; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* 2008c2ecf20Sopenharmony_ci * i2c_transfer return message length, but this function should 2018c2ecf20Sopenharmony_ci * return 0 if correct case. 2028c2ecf20Sopenharmony_ci */ 2038c2ecf20Sopenharmony_ci ret = i2c_transfer(client->adapter, &msg, 1); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci return ret >= 0 ? 0 : ret; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic int __mt9t112_reg_mask_set(const struct i2c_client *client, 2098c2ecf20Sopenharmony_ci u16 command, u16 mask, u16 set) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci int val = __mt9t112_reg_read(client, command); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (val < 0) 2148c2ecf20Sopenharmony_ci return val; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci val &= ~mask; 2178c2ecf20Sopenharmony_ci val |= set & mask; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci return __mt9t112_reg_write(client, command, val); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci/* mcu access */ 2238c2ecf20Sopenharmony_cistatic int __mt9t112_mcu_read(const struct i2c_client *client, u16 command) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci int ret; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci ret = __mt9t112_reg_write(client, 0x098E, command); 2288c2ecf20Sopenharmony_ci if (ret < 0) 2298c2ecf20Sopenharmony_ci return ret; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci return __mt9t112_reg_read(client, 0x0990); 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic int __mt9t112_mcu_write(const struct i2c_client *client, 2358c2ecf20Sopenharmony_ci u16 command, u16 data) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci int ret; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci ret = __mt9t112_reg_write(client, 0x098E, command); 2408c2ecf20Sopenharmony_ci if (ret < 0) 2418c2ecf20Sopenharmony_ci return ret; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci return __mt9t112_reg_write(client, 0x0990, data); 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic int __mt9t112_mcu_mask_set(const struct i2c_client *client, 2478c2ecf20Sopenharmony_ci u16 command, u16 mask, u16 set) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci int val = __mt9t112_mcu_read(client, command); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (val < 0) 2528c2ecf20Sopenharmony_ci return val; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci val &= ~mask; 2558c2ecf20Sopenharmony_ci val |= set & mask; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return __mt9t112_mcu_write(client, command, val); 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic int mt9t112_reset(const struct i2c_client *client) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci int ret; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0001); 2658c2ecf20Sopenharmony_ci usleep_range(1000, 5000); 2668c2ecf20Sopenharmony_ci mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0000); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci return ret; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci#ifndef EXT_CLOCK 2728c2ecf20Sopenharmony_ci#define CLOCK_INFO(a, b) 2738c2ecf20Sopenharmony_ci#else 2748c2ecf20Sopenharmony_ci#define CLOCK_INFO(a, b) mt9t112_clock_info(a, b) 2758c2ecf20Sopenharmony_cistatic int mt9t112_clock_info(const struct i2c_client *client, u32 ext) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci int m, n, p1, p2, p3, p4, p5, p6, p7; 2788c2ecf20Sopenharmony_ci u32 vco, clk; 2798c2ecf20Sopenharmony_ci char *enable; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci ext /= 1000; /* kbyte order */ 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci mt9t112_reg_read(n, client, 0x0012); 2848c2ecf20Sopenharmony_ci p1 = n & 0x000f; 2858c2ecf20Sopenharmony_ci n = n >> 4; 2868c2ecf20Sopenharmony_ci p2 = n & 0x000f; 2878c2ecf20Sopenharmony_ci n = n >> 4; 2888c2ecf20Sopenharmony_ci p3 = n & 0x000f; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci mt9t112_reg_read(n, client, 0x002a); 2918c2ecf20Sopenharmony_ci p4 = n & 0x000f; 2928c2ecf20Sopenharmony_ci n = n >> 4; 2938c2ecf20Sopenharmony_ci p5 = n & 0x000f; 2948c2ecf20Sopenharmony_ci n = n >> 4; 2958c2ecf20Sopenharmony_ci p6 = n & 0x000f; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci mt9t112_reg_read(n, client, 0x002c); 2988c2ecf20Sopenharmony_ci p7 = n & 0x000f; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci mt9t112_reg_read(n, client, 0x0010); 3018c2ecf20Sopenharmony_ci m = n & 0x00ff; 3028c2ecf20Sopenharmony_ci n = (n >> 8) & 0x003f; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci enable = ((ext < 6000) || (ext > 54000)) ? "X" : ""; 3058c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "EXTCLK : %10u K %s\n", ext, enable); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci vco = 2 * m * ext / (n + 1); 3088c2ecf20Sopenharmony_ci enable = ((vco < 384000) || (vco > 768000)) ? "X" : ""; 3098c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "VCO : %10u K %s\n", vco, enable); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci clk = vco / (p1 + 1) / (p2 + 1); 3128c2ecf20Sopenharmony_ci enable = (clk > 96000) ? "X" : ""; 3138c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "PIXCLK : %10u K %s\n", clk, enable); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci clk = vco / (p3 + 1); 3168c2ecf20Sopenharmony_ci enable = (clk > 768000) ? "X" : ""; 3178c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "MIPICLK : %10u K %s\n", clk, enable); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci clk = vco / (p6 + 1); 3208c2ecf20Sopenharmony_ci enable = (clk > 96000) ? "X" : ""; 3218c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "MCU CLK : %10u K %s\n", clk, enable); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci clk = vco / (p5 + 1); 3248c2ecf20Sopenharmony_ci enable = (clk > 54000) ? "X" : ""; 3258c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "SOC CLK : %10u K %s\n", clk, enable); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci clk = vco / (p4 + 1); 3288c2ecf20Sopenharmony_ci enable = (clk > 70000) ? "X" : ""; 3298c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "Sensor CLK : %10u K %s\n", clk, enable); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci clk = vco / (p7 + 1); 3328c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "External sensor : %10u K\n", clk); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci clk = ext / (n + 1); 3358c2ecf20Sopenharmony_ci enable = ((clk < 2000) || (clk > 24000)) ? "X" : ""; 3368c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "PFD : %10u K %s\n", clk, enable); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci return 0; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci#endif 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic int mt9t112_set_a_frame_size(const struct i2c_client *client, 3438c2ecf20Sopenharmony_ci u16 width, u16 height) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci int ret; 3468c2ecf20Sopenharmony_ci u16 wstart = (MAX_WIDTH - width) / 2; 3478c2ecf20Sopenharmony_ci u16 hstart = (MAX_HEIGHT - height) / 2; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci /* (Context A) Image Width/Height. */ 3508c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(26, 0), width); 3518c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(26, 2), height); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci /* (Context A) Output Width/Height. */ 3548c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 43), 8 + width); 3558c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 45), 8 + height); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* (Context A) Start Row/Column. */ 3588c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 2), 4 + hstart); 3598c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 4), 4 + wstart); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* (Context A) End Row/Column. */ 3628c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 6), 11 + height + hstart); 3638c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 8), 11 + width + wstart); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return ret; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic int mt9t112_set_pll_dividers(const struct i2c_client *client, 3718c2ecf20Sopenharmony_ci u8 m, u8 n, u8 p1, u8 p2, u8 p3, u8 p4, 3728c2ecf20Sopenharmony_ci u8 p5, u8 p6, u8 p7) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci int ret; 3758c2ecf20Sopenharmony_ci u16 val; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci /* N/M */ 3788c2ecf20Sopenharmony_ci val = (n << 8) | (m << 0); 3798c2ecf20Sopenharmony_ci mt9t112_reg_mask_set(ret, client, 0x0010, 0x3fff, val); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* P1/P2/P3 */ 3828c2ecf20Sopenharmony_ci val = ((p3 & 0x0F) << 8) | ((p2 & 0x0F) << 4) | ((p1 & 0x0F) << 0); 3838c2ecf20Sopenharmony_ci mt9t112_reg_mask_set(ret, client, 0x0012, 0x0fff, val); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* P4/P5/P6 */ 3868c2ecf20Sopenharmony_ci val = (0x7 << 12) | ((p6 & 0x0F) << 8) | ((p5 & 0x0F) << 4) | 3878c2ecf20Sopenharmony_ci ((p4 & 0x0F) << 0); 3888c2ecf20Sopenharmony_ci mt9t112_reg_mask_set(ret, client, 0x002A, 0x7fff, val); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* P7 */ 3918c2ecf20Sopenharmony_ci val = (0x1 << 12) | ((p7 & 0x0F) << 0); 3928c2ecf20Sopenharmony_ci mt9t112_reg_mask_set(ret, client, 0x002C, 0x100f, val); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci return ret; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic int mt9t112_init_pll(const struct i2c_client *client) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci struct mt9t112_priv *priv = to_mt9t112(client); 4008c2ecf20Sopenharmony_ci int data, i, ret; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci mt9t112_reg_mask_set(ret, client, 0x0014, 0x003, 0x0001); 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci /* PLL control: BYPASS PLL = 8517. */ 4058c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x0014, 0x2145); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci /* Replace these registers when new timing parameters are generated. */ 4088c2ecf20Sopenharmony_ci mt9t112_set_pll_dividers(client, 4098c2ecf20Sopenharmony_ci priv->info->divider.m, priv->info->divider.n, 4108c2ecf20Sopenharmony_ci priv->info->divider.p1, priv->info->divider.p2, 4118c2ecf20Sopenharmony_ci priv->info->divider.p3, priv->info->divider.p4, 4128c2ecf20Sopenharmony_ci priv->info->divider.p5, priv->info->divider.p6, 4138c2ecf20Sopenharmony_ci priv->info->divider.p7); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* 4168c2ecf20Sopenharmony_ci * TEST_BYPASS on 4178c2ecf20Sopenharmony_ci * PLL_ENABLE on 4188c2ecf20Sopenharmony_ci * SEL_LOCK_DET on 4198c2ecf20Sopenharmony_ci * TEST_BYPASS off 4208c2ecf20Sopenharmony_ci */ 4218c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x0014, 0x2525); 4228c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x0014, 0x2527); 4238c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x0014, 0x3427); 4248c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x0014, 0x3027); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci mdelay(10); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci /* 4298c2ecf20Sopenharmony_ci * PLL_BYPASS off 4308c2ecf20Sopenharmony_ci * Reference clock count 4318c2ecf20Sopenharmony_ci * I2C Master Clock Divider 4328c2ecf20Sopenharmony_ci */ 4338c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x0014, 0x3046); 4348c2ecf20Sopenharmony_ci /* JPEG initialization workaround */ 4358c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x0016, 0x0400); 4368c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x0022, 0x0190); 4378c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x3B84, 0x0212); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci /* External sensor clock is PLL bypass. */ 4408c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x002E, 0x0500); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci mt9t112_reg_mask_set(ret, client, 0x0018, 0x0002, 0x0002); 4438c2ecf20Sopenharmony_ci mt9t112_reg_mask_set(ret, client, 0x3B82, 0x0004, 0x0004); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* MCU disabled. */ 4468c2ecf20Sopenharmony_ci mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0x0004); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci /* Out of standby. */ 4498c2ecf20Sopenharmony_ci mt9t112_reg_mask_set(ret, client, 0x0018, 0x0001, 0); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci mdelay(50); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci /* 4548c2ecf20Sopenharmony_ci * Standby Workaround 4558c2ecf20Sopenharmony_ci * Disable Secondary I2C Pads 4568c2ecf20Sopenharmony_ci */ 4578c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x0614, 0x0001); 4588c2ecf20Sopenharmony_ci mdelay(1); 4598c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x0614, 0x0001); 4608c2ecf20Sopenharmony_ci mdelay(1); 4618c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x0614, 0x0001); 4628c2ecf20Sopenharmony_ci mdelay(1); 4638c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x0614, 0x0001); 4648c2ecf20Sopenharmony_ci mdelay(1); 4658c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x0614, 0x0001); 4668c2ecf20Sopenharmony_ci mdelay(1); 4678c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x0614, 0x0001); 4688c2ecf20Sopenharmony_ci mdelay(1); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* Poll to verify out of standby. Must Poll this bit. */ 4718c2ecf20Sopenharmony_ci for (i = 0; i < 100; i++) { 4728c2ecf20Sopenharmony_ci mt9t112_reg_read(data, client, 0x0018); 4738c2ecf20Sopenharmony_ci if (!(data & 0x4000)) 4748c2ecf20Sopenharmony_ci break; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci mdelay(10); 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci return ret; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic int mt9t112_init_setting(const struct i2c_client *client) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci int ret; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci /* Adaptive Output Clock (A) */ 4878c2ecf20Sopenharmony_ci mt9t112_mcu_mask_set(ret, client, VAR(26, 160), 0x0040, 0x0000); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci /* Read Mode (A) */ 4908c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 12), 0x0024); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* Fine Correction (A) */ 4938c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 15), 0x00CC); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci /* Fine IT Min (A) */ 4968c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 17), 0x01f1); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci /* Fine IT Max Margin (A) */ 4998c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 19), 0x00fF); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci /* Base Frame Lines (A) */ 5028c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 29), 0x032D); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci /* Min Line Length (A) */ 5058c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 31), 0x073a); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci /* Line Length (A) */ 5088c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 37), 0x07d0); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci /* Adaptive Output Clock (B) */ 5118c2ecf20Sopenharmony_ci mt9t112_mcu_mask_set(ret, client, VAR(27, 160), 0x0040, 0x0000); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci /* Row Start (B) */ 5148c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 74), 0x004); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci /* Column Start (B) */ 5178c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 76), 0x004); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci /* Row End (B) */ 5208c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 78), 0x60B); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci /* Column End (B) */ 5238c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 80), 0x80B); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci /* Fine Correction (B) */ 5268c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 87), 0x008C); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci /* Fine IT Min (B) */ 5298c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 89), 0x01F1); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci /* Fine IT Max Margin (B) */ 5328c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 91), 0x00FF); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci /* Base Frame Lines (B) */ 5358c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 101), 0x0668); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci /* Min Line Length (B) */ 5388c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 103), 0x0AF0); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci /* Line Length (B) */ 5418c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 109), 0x0AF0); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci /* 5448c2ecf20Sopenharmony_ci * Flicker Detection registers. 5458c2ecf20Sopenharmony_ci * This section should be replaced whenever new timing file is 5468c2ecf20Sopenharmony_ci * generated. All the following registers need to be replaced. 5478c2ecf20Sopenharmony_ci * Following registers are generated from Register Wizard but user can 5488c2ecf20Sopenharmony_ci * modify them. For detail see auto flicker detection tuning. 5498c2ecf20Sopenharmony_ci */ 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci /* FD_FDPERIOD_SELECT */ 5528c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(8, 5), 0x01); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci /* PRI_B_CONFIG_FD_ALGO_RUN */ 5558c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(27, 17), 0x0003); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* PRI_A_CONFIG_FD_ALGO_RUN */ 5588c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(26, 17), 0x0003); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci /* 5618c2ecf20Sopenharmony_ci * AFD range detection tuning registers. 5628c2ecf20Sopenharmony_ci */ 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci /* Search_f1_50 */ 5658c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(18, 165), 0x25); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci /* Search_f2_50 */ 5688c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(18, 166), 0x28); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci /* Search_f1_60 */ 5718c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(18, 167), 0x2C); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* Search_f2_60 */ 5748c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(18, 168), 0x2F); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci /* Period_50Hz (A) */ 5778c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(18, 68), 0xBA); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /* Secret register by Aptina. */ 5808c2ecf20Sopenharmony_ci /* Period_50Hz (A MSB) */ 5818c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(18, 303), 0x00); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci /* Period_60Hz (A) */ 5848c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(18, 69), 0x9B); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci /* Secret register by Aptina. */ 5878c2ecf20Sopenharmony_ci /* Period_60Hz (A MSB) */ 5888c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(18, 301), 0x00); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci /* Period_50Hz (B) */ 5918c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(18, 140), 0x82); 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci /* Secret register by Aptina. */ 5948c2ecf20Sopenharmony_ci /* Period_50Hz (B) MSB */ 5958c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(18, 304), 0x00); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci /* Period_60Hz (B) */ 5988c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(18, 141), 0x6D); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci /* Secret register by Aptina. */ 6018c2ecf20Sopenharmony_ci /* Period_60Hz (B) MSB */ 6028c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(18, 302), 0x00); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci /* FD Mode */ 6058c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(8, 2), 0x10); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci /* Stat_min */ 6088c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(8, 9), 0x02); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci /* Stat_max */ 6118c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(8, 10), 0x03); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci /* Min_amplitude */ 6148c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(8, 12), 0x0A); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci /* RX FIFO Watermark (A) */ 6178c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 70), 0x0014); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci /* RX FIFO Watermark (B) */ 6208c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(18, 142), 0x0014); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci /* MCLK: 16MHz 6238c2ecf20Sopenharmony_ci * PCLK: 73MHz 6248c2ecf20Sopenharmony_ci * CorePixCLK: 36.5 MHz 6258c2ecf20Sopenharmony_ci */ 6268c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(18, 0x0044), 133); 6278c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(18, 0x0045), 110); 6288c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(18, 0x008c), 130); 6298c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(18, 0x008d), 108); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(18, 0x00A5), 27); 6328c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(18, 0x00a6), 30); 6338c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(18, 0x00a7), 32); 6348c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(18, 0x00a8), 35); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci return ret; 6378c2ecf20Sopenharmony_ci} 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic int mt9t112_auto_focus_setting(const struct i2c_client *client) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci int ret; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(12, 13), 0x000F); 6448c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(12, 23), 0x0F0F); 6458c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x0614, 0x0000); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05); 6508c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(12, 2), 0x02); 6518c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(12, 3), 0x0002); 6528c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(17, 3), 0x8001); 6538c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(17, 11), 0x0025); 6548c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(17, 13), 0x0193); 6558c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(17, 33), 0x18); 6568c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x05); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci return ret; 6598c2ecf20Sopenharmony_ci} 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_cistatic int mt9t112_auto_focus_trigger(const struct i2c_client *client) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci int ret; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(12, 25), 0x01); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci return ret; 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_cistatic int mt9t112_init_camera(const struct i2c_client *client) 6718c2ecf20Sopenharmony_ci{ 6728c2ecf20Sopenharmony_ci int ret; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci ECHECKER(ret, mt9t112_reset(client)); 6758c2ecf20Sopenharmony_ci ECHECKER(ret, mt9t112_init_pll(client)); 6768c2ecf20Sopenharmony_ci ECHECKER(ret, mt9t112_init_setting(client)); 6778c2ecf20Sopenharmony_ci ECHECKER(ret, mt9t112_auto_focus_setting(client)); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci /* Analog setting B.*/ 6828c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x3084, 0x2409); 6838c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x3092, 0x0A49); 6848c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x3094, 0x4949); 6858c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x3096, 0x4950); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci /* 6888c2ecf20Sopenharmony_ci * Disable adaptive clock. 6898c2ecf20Sopenharmony_ci * PRI_A_CONFIG_JPEG_OB_TX_CONTROL_VAR 6908c2ecf20Sopenharmony_ci * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR 6918c2ecf20Sopenharmony_ci */ 6928c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(26, 160), 0x0A2E); 6938c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(27, 160), 0x0A2E); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci /* 6968c2ecf20Sopenharmony_ci * Configure Status in Status_before_length Format and enable header. 6978c2ecf20Sopenharmony_ci * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR 6988c2ecf20Sopenharmony_ci */ 6998c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(27, 144), 0x0CB4); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci /* 7028c2ecf20Sopenharmony_ci * Enable JPEG in context B. 7038c2ecf20Sopenharmony_ci * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR 7048c2ecf20Sopenharmony_ci */ 7058c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(27, 142), 0x01); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci /* Disable Dac_TXLO. */ 7088c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x316C, 0x350F); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci /* Set max slew rates. */ 7118c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x1E, 0x777); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci return ret; 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci/************************************************************************ 7178c2ecf20Sopenharmony_ci * v4l2_subdev_core_ops 7188c2ecf20Sopenharmony_ci ***********************************************************************/ 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG 7218c2ecf20Sopenharmony_cistatic int mt9t112_g_register(struct v4l2_subdev *sd, 7228c2ecf20Sopenharmony_ci struct v4l2_dbg_register *reg) 7238c2ecf20Sopenharmony_ci{ 7248c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(sd); 7258c2ecf20Sopenharmony_ci int ret; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci reg->size = 2; 7288c2ecf20Sopenharmony_ci mt9t112_reg_read(ret, client, reg->reg); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci reg->val = (__u64)ret; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci return 0; 7338c2ecf20Sopenharmony_ci} 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_cistatic int mt9t112_s_register(struct v4l2_subdev *sd, 7368c2ecf20Sopenharmony_ci const struct v4l2_dbg_register *reg) 7378c2ecf20Sopenharmony_ci{ 7388c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(sd); 7398c2ecf20Sopenharmony_ci int ret; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, reg->reg, reg->val); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci return ret; 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ci#endif 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cistatic int mt9t112_power_on(struct mt9t112_priv *priv) 7488c2ecf20Sopenharmony_ci{ 7498c2ecf20Sopenharmony_ci int ret; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->clk); 7528c2ecf20Sopenharmony_ci if (ret) 7538c2ecf20Sopenharmony_ci return ret; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci if (priv->standby_gpio) { 7568c2ecf20Sopenharmony_ci gpiod_set_value(priv->standby_gpio, 0); 7578c2ecf20Sopenharmony_ci msleep(100); 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci return 0; 7618c2ecf20Sopenharmony_ci} 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_cistatic int mt9t112_power_off(struct mt9t112_priv *priv) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk); 7668c2ecf20Sopenharmony_ci if (priv->standby_gpio) { 7678c2ecf20Sopenharmony_ci gpiod_set_value(priv->standby_gpio, 1); 7688c2ecf20Sopenharmony_ci msleep(100); 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci return 0; 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic int mt9t112_s_power(struct v4l2_subdev *sd, int on) 7758c2ecf20Sopenharmony_ci{ 7768c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(sd); 7778c2ecf20Sopenharmony_ci struct mt9t112_priv *priv = to_mt9t112(client); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci return on ? mt9t112_power_on(priv) : 7808c2ecf20Sopenharmony_ci mt9t112_power_off(priv); 7818c2ecf20Sopenharmony_ci} 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = { 7848c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG 7858c2ecf20Sopenharmony_ci .g_register = mt9t112_g_register, 7868c2ecf20Sopenharmony_ci .s_register = mt9t112_s_register, 7878c2ecf20Sopenharmony_ci#endif 7888c2ecf20Sopenharmony_ci .s_power = mt9t112_s_power, 7898c2ecf20Sopenharmony_ci}; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci/************************************************************************ 7928c2ecf20Sopenharmony_ci * v4l2_subdev_video_ops 7938c2ecf20Sopenharmony_ci **********************************************************************/ 7948c2ecf20Sopenharmony_cistatic int mt9t112_s_stream(struct v4l2_subdev *sd, int enable) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(sd); 7978c2ecf20Sopenharmony_ci struct mt9t112_priv *priv = to_mt9t112(client); 7988c2ecf20Sopenharmony_ci int ret = 0; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci if (!enable) { 8018c2ecf20Sopenharmony_ci /* FIXME 8028c2ecf20Sopenharmony_ci * 8038c2ecf20Sopenharmony_ci * If user selected large output size, and used it long time, 8048c2ecf20Sopenharmony_ci * mt9t112 camera will be very warm. 8058c2ecf20Sopenharmony_ci * 8068c2ecf20Sopenharmony_ci * But current driver can not stop mt9t112 camera. 8078c2ecf20Sopenharmony_ci * So, set small size here to solve this problem. 8088c2ecf20Sopenharmony_ci */ 8098c2ecf20Sopenharmony_ci mt9t112_set_a_frame_size(client, VGA_WIDTH, VGA_HEIGHT); 8108c2ecf20Sopenharmony_ci return ret; 8118c2ecf20Sopenharmony_ci } 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci if (!priv->init_done) { 8148c2ecf20Sopenharmony_ci u16 param = MT9T112_FLAG_PCLK_RISING_EDGE & priv->info->flags ? 8158c2ecf20Sopenharmony_ci 0x0001 : 0x0000; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci ECHECKER(ret, mt9t112_init_camera(client)); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci /* Invert PCLK (Data sampled on falling edge of pixclk). */ 8208c2ecf20Sopenharmony_ci mt9t112_reg_write(ret, client, 0x3C20, param); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci mdelay(5); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci priv->init_done = true; 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(26, 7), priv->format->fmt); 8288c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR(26, 9), priv->format->order); 8298c2ecf20Sopenharmony_ci mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci mt9t112_set_a_frame_size(client, priv->frame.width, priv->frame.height); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci ECHECKER(ret, mt9t112_auto_focus_trigger(client)); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "format : %d\n", priv->format->code); 8368c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "size : %d x %d\n", 8378c2ecf20Sopenharmony_ci priv->frame.width, 8388c2ecf20Sopenharmony_ci priv->frame.height); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci CLOCK_INFO(client, EXT_CLOCK); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci return ret; 8438c2ecf20Sopenharmony_ci} 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_cistatic int mt9t112_set_params(struct mt9t112_priv *priv, 8468c2ecf20Sopenharmony_ci const struct v4l2_rect *rect, 8478c2ecf20Sopenharmony_ci u32 code) 8488c2ecf20Sopenharmony_ci{ 8498c2ecf20Sopenharmony_ci int i; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci /* 8528c2ecf20Sopenharmony_ci * get color format 8538c2ecf20Sopenharmony_ci */ 8548c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_formats; i++) 8558c2ecf20Sopenharmony_ci if (mt9t112_cfmts[i].code == code) 8568c2ecf20Sopenharmony_ci break; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci if (i == priv->num_formats) 8598c2ecf20Sopenharmony_ci return -EINVAL; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci priv->frame = *rect; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci /* 8648c2ecf20Sopenharmony_ci * frame size check 8658c2ecf20Sopenharmony_ci */ 8668c2ecf20Sopenharmony_ci v4l_bound_align_image(&priv->frame.width, 0, MAX_WIDTH, 0, 8678c2ecf20Sopenharmony_ci &priv->frame.height, 0, MAX_HEIGHT, 0, 0); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci priv->format = mt9t112_cfmts + i; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci return 0; 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_cistatic int mt9t112_get_selection(struct v4l2_subdev *sd, 8758c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 8768c2ecf20Sopenharmony_ci struct v4l2_subdev_selection *sel) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(sd); 8798c2ecf20Sopenharmony_ci struct mt9t112_priv *priv = to_mt9t112(client); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) 8828c2ecf20Sopenharmony_ci return -EINVAL; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci switch (sel->target) { 8858c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_CROP_BOUNDS: 8868c2ecf20Sopenharmony_ci sel->r.left = 0; 8878c2ecf20Sopenharmony_ci sel->r.top = 0; 8888c2ecf20Sopenharmony_ci sel->r.width = MAX_WIDTH; 8898c2ecf20Sopenharmony_ci sel->r.height = MAX_HEIGHT; 8908c2ecf20Sopenharmony_ci return 0; 8918c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_CROP: 8928c2ecf20Sopenharmony_ci sel->r = priv->frame; 8938c2ecf20Sopenharmony_ci return 0; 8948c2ecf20Sopenharmony_ci default: 8958c2ecf20Sopenharmony_ci return -EINVAL; 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci} 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_cistatic int mt9t112_set_selection(struct v4l2_subdev *sd, 9008c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 9018c2ecf20Sopenharmony_ci struct v4l2_subdev_selection *sel) 9028c2ecf20Sopenharmony_ci{ 9038c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(sd); 9048c2ecf20Sopenharmony_ci struct mt9t112_priv *priv = to_mt9t112(client); 9058c2ecf20Sopenharmony_ci const struct v4l2_rect *rect = &sel->r; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || 9088c2ecf20Sopenharmony_ci sel->target != V4L2_SEL_TGT_CROP) 9098c2ecf20Sopenharmony_ci return -EINVAL; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci return mt9t112_set_params(priv, rect, priv->format->code); 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic int mt9t112_get_fmt(struct v4l2_subdev *sd, 9158c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 9168c2ecf20Sopenharmony_ci struct v4l2_subdev_format *format) 9178c2ecf20Sopenharmony_ci{ 9188c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *mf = &format->format; 9198c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(sd); 9208c2ecf20Sopenharmony_ci struct mt9t112_priv *priv = to_mt9t112(client); 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci if (format->pad) 9238c2ecf20Sopenharmony_ci return -EINVAL; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci mf->width = priv->frame.width; 9268c2ecf20Sopenharmony_ci mf->height = priv->frame.height; 9278c2ecf20Sopenharmony_ci mf->colorspace = priv->format->colorspace; 9288c2ecf20Sopenharmony_ci mf->code = priv->format->code; 9298c2ecf20Sopenharmony_ci mf->field = V4L2_FIELD_NONE; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci return 0; 9328c2ecf20Sopenharmony_ci} 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_cistatic int mt9t112_s_fmt(struct v4l2_subdev *sd, 9358c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *mf) 9368c2ecf20Sopenharmony_ci{ 9378c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(sd); 9388c2ecf20Sopenharmony_ci struct mt9t112_priv *priv = to_mt9t112(client); 9398c2ecf20Sopenharmony_ci struct v4l2_rect rect = { 9408c2ecf20Sopenharmony_ci .width = mf->width, 9418c2ecf20Sopenharmony_ci .height = mf->height, 9428c2ecf20Sopenharmony_ci .left = priv->frame.left, 9438c2ecf20Sopenharmony_ci .top = priv->frame.top, 9448c2ecf20Sopenharmony_ci }; 9458c2ecf20Sopenharmony_ci int ret; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci ret = mt9t112_set_params(priv, &rect, mf->code); 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci if (!ret) 9508c2ecf20Sopenharmony_ci mf->colorspace = priv->format->colorspace; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci return ret; 9538c2ecf20Sopenharmony_ci} 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_cistatic int mt9t112_set_fmt(struct v4l2_subdev *sd, 9568c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 9578c2ecf20Sopenharmony_ci struct v4l2_subdev_format *format) 9588c2ecf20Sopenharmony_ci{ 9598c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(sd); 9608c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *mf = &format->format; 9618c2ecf20Sopenharmony_ci struct mt9t112_priv *priv = to_mt9t112(client); 9628c2ecf20Sopenharmony_ci int i; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci if (format->pad) 9658c2ecf20Sopenharmony_ci return -EINVAL; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci for (i = 0; i < priv->num_formats; i++) 9688c2ecf20Sopenharmony_ci if (mt9t112_cfmts[i].code == mf->code) 9698c2ecf20Sopenharmony_ci break; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci if (i == priv->num_formats) { 9728c2ecf20Sopenharmony_ci mf->code = MEDIA_BUS_FMT_UYVY8_2X8; 9738c2ecf20Sopenharmony_ci mf->colorspace = V4L2_COLORSPACE_JPEG; 9748c2ecf20Sopenharmony_ci } else { 9758c2ecf20Sopenharmony_ci mf->colorspace = mt9t112_cfmts[i].colorspace; 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci v4l_bound_align_image(&mf->width, 0, MAX_WIDTH, 0, 9798c2ecf20Sopenharmony_ci &mf->height, 0, MAX_HEIGHT, 0, 0); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci mf->field = V4L2_FIELD_NONE; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) 9848c2ecf20Sopenharmony_ci return mt9t112_s_fmt(sd, mf); 9858c2ecf20Sopenharmony_ci cfg->try_fmt = *mf; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci return 0; 9888c2ecf20Sopenharmony_ci} 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_cistatic int mt9t112_enum_mbus_code(struct v4l2_subdev *sd, 9918c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 9928c2ecf20Sopenharmony_ci struct v4l2_subdev_mbus_code_enum *code) 9938c2ecf20Sopenharmony_ci{ 9948c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(sd); 9958c2ecf20Sopenharmony_ci struct mt9t112_priv *priv = to_mt9t112(client); 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci if (code->pad || code->index >= priv->num_formats) 9988c2ecf20Sopenharmony_ci return -EINVAL; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci code->code = mt9t112_cfmts[code->index].code; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci return 0; 10038c2ecf20Sopenharmony_ci} 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { 10068c2ecf20Sopenharmony_ci .s_stream = mt9t112_s_stream, 10078c2ecf20Sopenharmony_ci}; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_pad_ops mt9t112_subdev_pad_ops = { 10108c2ecf20Sopenharmony_ci .enum_mbus_code = mt9t112_enum_mbus_code, 10118c2ecf20Sopenharmony_ci .get_selection = mt9t112_get_selection, 10128c2ecf20Sopenharmony_ci .set_selection = mt9t112_set_selection, 10138c2ecf20Sopenharmony_ci .get_fmt = mt9t112_get_fmt, 10148c2ecf20Sopenharmony_ci .set_fmt = mt9t112_set_fmt, 10158c2ecf20Sopenharmony_ci}; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci/************************************************************************ 10188c2ecf20Sopenharmony_ci * i2c driver 10198c2ecf20Sopenharmony_ci ***********************************************************************/ 10208c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops mt9t112_subdev_ops = { 10218c2ecf20Sopenharmony_ci .core = &mt9t112_subdev_core_ops, 10228c2ecf20Sopenharmony_ci .video = &mt9t112_subdev_video_ops, 10238c2ecf20Sopenharmony_ci .pad = &mt9t112_subdev_pad_ops, 10248c2ecf20Sopenharmony_ci}; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_cistatic int mt9t112_camera_probe(struct i2c_client *client) 10278c2ecf20Sopenharmony_ci{ 10288c2ecf20Sopenharmony_ci struct mt9t112_priv *priv = to_mt9t112(client); 10298c2ecf20Sopenharmony_ci const char *devname; 10308c2ecf20Sopenharmony_ci int chipid; 10318c2ecf20Sopenharmony_ci int ret; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci ret = mt9t112_s_power(&priv->subdev, 1); 10348c2ecf20Sopenharmony_ci if (ret < 0) 10358c2ecf20Sopenharmony_ci return ret; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci /* Check and show chip ID. */ 10388c2ecf20Sopenharmony_ci mt9t112_reg_read(chipid, client, 0x0000); 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci switch (chipid) { 10418c2ecf20Sopenharmony_ci case 0x2680: 10428c2ecf20Sopenharmony_ci devname = "mt9t111"; 10438c2ecf20Sopenharmony_ci priv->num_formats = 1; 10448c2ecf20Sopenharmony_ci break; 10458c2ecf20Sopenharmony_ci case 0x2682: 10468c2ecf20Sopenharmony_ci devname = "mt9t112"; 10478c2ecf20Sopenharmony_ci priv->num_formats = ARRAY_SIZE(mt9t112_cfmts); 10488c2ecf20Sopenharmony_ci break; 10498c2ecf20Sopenharmony_ci default: 10508c2ecf20Sopenharmony_ci dev_err(&client->dev, "Product ID error %04x\n", chipid); 10518c2ecf20Sopenharmony_ci ret = -ENODEV; 10528c2ecf20Sopenharmony_ci goto done; 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci dev_info(&client->dev, "%s chip ID %04x\n", devname, chipid); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_cidone: 10588c2ecf20Sopenharmony_ci mt9t112_s_power(&priv->subdev, 0); 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci return ret; 10618c2ecf20Sopenharmony_ci} 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_cistatic int mt9t112_probe(struct i2c_client *client, 10648c2ecf20Sopenharmony_ci const struct i2c_device_id *did) 10658c2ecf20Sopenharmony_ci{ 10668c2ecf20Sopenharmony_ci struct mt9t112_priv *priv; 10678c2ecf20Sopenharmony_ci int ret; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci if (!client->dev.platform_data) { 10708c2ecf20Sopenharmony_ci dev_err(&client->dev, "mt9t112: missing platform data!\n"); 10718c2ecf20Sopenharmony_ci return -EINVAL; 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); 10758c2ecf20Sopenharmony_ci if (!priv) 10768c2ecf20Sopenharmony_ci return -ENOMEM; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci priv->info = client->dev.platform_data; 10798c2ecf20Sopenharmony_ci priv->init_done = false; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci priv->clk = devm_clk_get(&client->dev, "extclk"); 10848c2ecf20Sopenharmony_ci if (PTR_ERR(priv->clk) == -ENOENT) { 10858c2ecf20Sopenharmony_ci priv->clk = NULL; 10868c2ecf20Sopenharmony_ci } else if (IS_ERR(priv->clk)) { 10878c2ecf20Sopenharmony_ci dev_err(&client->dev, "Unable to get clock \"extclk\"\n"); 10888c2ecf20Sopenharmony_ci return PTR_ERR(priv->clk); 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci priv->standby_gpio = devm_gpiod_get_optional(&client->dev, "standby", 10928c2ecf20Sopenharmony_ci GPIOD_OUT_HIGH); 10938c2ecf20Sopenharmony_ci if (IS_ERR(priv->standby_gpio)) { 10948c2ecf20Sopenharmony_ci dev_err(&client->dev, "Unable to get gpio \"standby\"\n"); 10958c2ecf20Sopenharmony_ci return PTR_ERR(priv->standby_gpio); 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci ret = mt9t112_camera_probe(client); 10998c2ecf20Sopenharmony_ci if (ret) 11008c2ecf20Sopenharmony_ci return ret; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci return v4l2_async_register_subdev(&priv->subdev); 11038c2ecf20Sopenharmony_ci} 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_cistatic int mt9t112_remove(struct i2c_client *client) 11068c2ecf20Sopenharmony_ci{ 11078c2ecf20Sopenharmony_ci struct mt9t112_priv *priv = to_mt9t112(client); 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk); 11108c2ecf20Sopenharmony_ci v4l2_async_unregister_subdev(&priv->subdev); 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci return 0; 11138c2ecf20Sopenharmony_ci} 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_cistatic const struct i2c_device_id mt9t112_id[] = { 11168c2ecf20Sopenharmony_ci { "mt9t112", 0 }, 11178c2ecf20Sopenharmony_ci { } 11188c2ecf20Sopenharmony_ci}; 11198c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, mt9t112_id); 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_cistatic struct i2c_driver mt9t112_i2c_driver = { 11228c2ecf20Sopenharmony_ci .driver = { 11238c2ecf20Sopenharmony_ci .name = "mt9t112", 11248c2ecf20Sopenharmony_ci }, 11258c2ecf20Sopenharmony_ci .probe = mt9t112_probe, 11268c2ecf20Sopenharmony_ci .remove = mt9t112_remove, 11278c2ecf20Sopenharmony_ci .id_table = mt9t112_id, 11288c2ecf20Sopenharmony_ci}; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_cimodule_i2c_driver(mt9t112_i2c_driver); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("V4L2 driver for MT9T111/MT9T112 camera sensor"); 11338c2ecf20Sopenharmony_ciMODULE_AUTHOR("Kuninori Morimoto"); 11348c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1135