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