18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * imx214.c - imx214 sensor driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2018 Qtechnology A/S
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Ricardo Ribalda <ribalda@kernel.org>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci#include <linux/clk.h>
108c2ecf20Sopenharmony_ci#include <linux/delay.h>
118c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h>
128c2ecf20Sopenharmony_ci#include <linux/i2c.h>
138c2ecf20Sopenharmony_ci#include <linux/module.h>
148c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
158c2ecf20Sopenharmony_ci#include <linux/regmap.h>
168c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h>
178c2ecf20Sopenharmony_ci#include <media/media-entity.h>
188c2ecf20Sopenharmony_ci#include <media/v4l2-ctrls.h>
198c2ecf20Sopenharmony_ci#include <media/v4l2-fwnode.h>
208c2ecf20Sopenharmony_ci#include <media/v4l2-subdev.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define IMX214_DEFAULT_CLK_FREQ	24000000
238c2ecf20Sopenharmony_ci#define IMX214_DEFAULT_LINK_FREQ 480000000
248c2ecf20Sopenharmony_ci#define IMX214_DEFAULT_PIXEL_RATE ((IMX214_DEFAULT_LINK_FREQ * 8LL) / 10)
258c2ecf20Sopenharmony_ci#define IMX214_FPS 30
268c2ecf20Sopenharmony_ci#define IMX214_MBUS_CODE MEDIA_BUS_FMT_SRGGB10_1X10
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic const char * const imx214_supply_name[] = {
298c2ecf20Sopenharmony_ci	"vdda",
308c2ecf20Sopenharmony_ci	"vddd",
318c2ecf20Sopenharmony_ci	"vdddo",
328c2ecf20Sopenharmony_ci};
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define IMX214_NUM_SUPPLIES ARRAY_SIZE(imx214_supply_name)
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistruct imx214 {
378c2ecf20Sopenharmony_ci	struct device *dev;
388c2ecf20Sopenharmony_ci	struct clk *xclk;
398c2ecf20Sopenharmony_ci	struct regmap *regmap;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	struct v4l2_subdev sd;
428c2ecf20Sopenharmony_ci	struct media_pad pad;
438c2ecf20Sopenharmony_ci	struct v4l2_mbus_framefmt fmt;
448c2ecf20Sopenharmony_ci	struct v4l2_rect crop;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	struct v4l2_ctrl_handler ctrls;
478c2ecf20Sopenharmony_ci	struct v4l2_ctrl *pixel_rate;
488c2ecf20Sopenharmony_ci	struct v4l2_ctrl *link_freq;
498c2ecf20Sopenharmony_ci	struct v4l2_ctrl *exposure;
508c2ecf20Sopenharmony_ci	struct v4l2_ctrl *unit_size;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	struct regulator_bulk_data	supplies[IMX214_NUM_SUPPLIES];
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	struct gpio_desc *enable_gpio;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	/*
578c2ecf20Sopenharmony_ci	 * Serialize control access, get/set format, get selection
588c2ecf20Sopenharmony_ci	 * and start streaming.
598c2ecf20Sopenharmony_ci	 */
608c2ecf20Sopenharmony_ci	struct mutex mutex;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	bool streaming;
638c2ecf20Sopenharmony_ci};
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistruct reg_8 {
668c2ecf20Sopenharmony_ci	u16 addr;
678c2ecf20Sopenharmony_ci	u8 val;
688c2ecf20Sopenharmony_ci};
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cienum {
718c2ecf20Sopenharmony_ci	IMX214_TABLE_WAIT_MS = 0,
728c2ecf20Sopenharmony_ci	IMX214_TABLE_END,
738c2ecf20Sopenharmony_ci	IMX214_MAX_RETRIES,
748c2ecf20Sopenharmony_ci	IMX214_WAIT_MS
758c2ecf20Sopenharmony_ci};
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/*From imx214_mode_tbls.h*/
788c2ecf20Sopenharmony_cistatic const struct reg_8 mode_4096x2304[] = {
798c2ecf20Sopenharmony_ci	{0x0114, 0x03},
808c2ecf20Sopenharmony_ci	{0x0220, 0x00},
818c2ecf20Sopenharmony_ci	{0x0221, 0x11},
828c2ecf20Sopenharmony_ci	{0x0222, 0x01},
838c2ecf20Sopenharmony_ci	{0x0340, 0x0C},
848c2ecf20Sopenharmony_ci	{0x0341, 0x7A},
858c2ecf20Sopenharmony_ci	{0x0342, 0x13},
868c2ecf20Sopenharmony_ci	{0x0343, 0x90},
878c2ecf20Sopenharmony_ci	{0x0344, 0x00},
888c2ecf20Sopenharmony_ci	{0x0345, 0x38},
898c2ecf20Sopenharmony_ci	{0x0346, 0x01},
908c2ecf20Sopenharmony_ci	{0x0347, 0x98},
918c2ecf20Sopenharmony_ci	{0x0348, 0x10},
928c2ecf20Sopenharmony_ci	{0x0349, 0x37},
938c2ecf20Sopenharmony_ci	{0x034A, 0x0A},
948c2ecf20Sopenharmony_ci	{0x034B, 0x97},
958c2ecf20Sopenharmony_ci	{0x0381, 0x01},
968c2ecf20Sopenharmony_ci	{0x0383, 0x01},
978c2ecf20Sopenharmony_ci	{0x0385, 0x01},
988c2ecf20Sopenharmony_ci	{0x0387, 0x01},
998c2ecf20Sopenharmony_ci	{0x0900, 0x00},
1008c2ecf20Sopenharmony_ci	{0x0901, 0x00},
1018c2ecf20Sopenharmony_ci	{0x0902, 0x00},
1028c2ecf20Sopenharmony_ci	{0x3000, 0x35},
1038c2ecf20Sopenharmony_ci	{0x3054, 0x01},
1048c2ecf20Sopenharmony_ci	{0x305C, 0x11},
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	{0x0112, 0x0A},
1078c2ecf20Sopenharmony_ci	{0x0113, 0x0A},
1088c2ecf20Sopenharmony_ci	{0x034C, 0x10},
1098c2ecf20Sopenharmony_ci	{0x034D, 0x00},
1108c2ecf20Sopenharmony_ci	{0x034E, 0x09},
1118c2ecf20Sopenharmony_ci	{0x034F, 0x00},
1128c2ecf20Sopenharmony_ci	{0x0401, 0x00},
1138c2ecf20Sopenharmony_ci	{0x0404, 0x00},
1148c2ecf20Sopenharmony_ci	{0x0405, 0x10},
1158c2ecf20Sopenharmony_ci	{0x0408, 0x00},
1168c2ecf20Sopenharmony_ci	{0x0409, 0x00},
1178c2ecf20Sopenharmony_ci	{0x040A, 0x00},
1188c2ecf20Sopenharmony_ci	{0x040B, 0x00},
1198c2ecf20Sopenharmony_ci	{0x040C, 0x10},
1208c2ecf20Sopenharmony_ci	{0x040D, 0x00},
1218c2ecf20Sopenharmony_ci	{0x040E, 0x09},
1228c2ecf20Sopenharmony_ci	{0x040F, 0x00},
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	{0x0301, 0x05},
1258c2ecf20Sopenharmony_ci	{0x0303, 0x02},
1268c2ecf20Sopenharmony_ci	{0x0305, 0x03},
1278c2ecf20Sopenharmony_ci	{0x0306, 0x00},
1288c2ecf20Sopenharmony_ci	{0x0307, 0x96},
1298c2ecf20Sopenharmony_ci	{0x0309, 0x0A},
1308c2ecf20Sopenharmony_ci	{0x030B, 0x01},
1318c2ecf20Sopenharmony_ci	{0x0310, 0x00},
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	{0x0820, 0x12},
1348c2ecf20Sopenharmony_ci	{0x0821, 0xC0},
1358c2ecf20Sopenharmony_ci	{0x0822, 0x00},
1368c2ecf20Sopenharmony_ci	{0x0823, 0x00},
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	{0x3A03, 0x09},
1398c2ecf20Sopenharmony_ci	{0x3A04, 0x50},
1408c2ecf20Sopenharmony_ci	{0x3A05, 0x01},
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	{0x0B06, 0x01},
1438c2ecf20Sopenharmony_ci	{0x30A2, 0x00},
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	{0x30B4, 0x00},
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	{0x3A02, 0xFF},
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	{0x3011, 0x00},
1508c2ecf20Sopenharmony_ci	{0x3013, 0x01},
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	{0x0202, 0x0C},
1538c2ecf20Sopenharmony_ci	{0x0203, 0x70},
1548c2ecf20Sopenharmony_ci	{0x0224, 0x01},
1558c2ecf20Sopenharmony_ci	{0x0225, 0xF4},
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	{0x0204, 0x00},
1588c2ecf20Sopenharmony_ci	{0x0205, 0x00},
1598c2ecf20Sopenharmony_ci	{0x020E, 0x01},
1608c2ecf20Sopenharmony_ci	{0x020F, 0x00},
1618c2ecf20Sopenharmony_ci	{0x0210, 0x01},
1628c2ecf20Sopenharmony_ci	{0x0211, 0x00},
1638c2ecf20Sopenharmony_ci	{0x0212, 0x01},
1648c2ecf20Sopenharmony_ci	{0x0213, 0x00},
1658c2ecf20Sopenharmony_ci	{0x0214, 0x01},
1668c2ecf20Sopenharmony_ci	{0x0215, 0x00},
1678c2ecf20Sopenharmony_ci	{0x0216, 0x00},
1688c2ecf20Sopenharmony_ci	{0x0217, 0x00},
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	{0x4170, 0x00},
1718c2ecf20Sopenharmony_ci	{0x4171, 0x10},
1728c2ecf20Sopenharmony_ci	{0x4176, 0x00},
1738c2ecf20Sopenharmony_ci	{0x4177, 0x3C},
1748c2ecf20Sopenharmony_ci	{0xAE20, 0x04},
1758c2ecf20Sopenharmony_ci	{0xAE21, 0x5C},
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	{IMX214_TABLE_WAIT_MS, 10},
1788c2ecf20Sopenharmony_ci	{0x0138, 0x01},
1798c2ecf20Sopenharmony_ci	{IMX214_TABLE_END, 0x00}
1808c2ecf20Sopenharmony_ci};
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic const struct reg_8 mode_1920x1080[] = {
1838c2ecf20Sopenharmony_ci	{0x0114, 0x03},
1848c2ecf20Sopenharmony_ci	{0x0220, 0x00},
1858c2ecf20Sopenharmony_ci	{0x0221, 0x11},
1868c2ecf20Sopenharmony_ci	{0x0222, 0x01},
1878c2ecf20Sopenharmony_ci	{0x0340, 0x0C},
1888c2ecf20Sopenharmony_ci	{0x0341, 0x7A},
1898c2ecf20Sopenharmony_ci	{0x0342, 0x13},
1908c2ecf20Sopenharmony_ci	{0x0343, 0x90},
1918c2ecf20Sopenharmony_ci	{0x0344, 0x04},
1928c2ecf20Sopenharmony_ci	{0x0345, 0x78},
1938c2ecf20Sopenharmony_ci	{0x0346, 0x03},
1948c2ecf20Sopenharmony_ci	{0x0347, 0xFC},
1958c2ecf20Sopenharmony_ci	{0x0348, 0x0B},
1968c2ecf20Sopenharmony_ci	{0x0349, 0xF7},
1978c2ecf20Sopenharmony_ci	{0x034A, 0x08},
1988c2ecf20Sopenharmony_ci	{0x034B, 0x33},
1998c2ecf20Sopenharmony_ci	{0x0381, 0x01},
2008c2ecf20Sopenharmony_ci	{0x0383, 0x01},
2018c2ecf20Sopenharmony_ci	{0x0385, 0x01},
2028c2ecf20Sopenharmony_ci	{0x0387, 0x01},
2038c2ecf20Sopenharmony_ci	{0x0900, 0x00},
2048c2ecf20Sopenharmony_ci	{0x0901, 0x00},
2058c2ecf20Sopenharmony_ci	{0x0902, 0x00},
2068c2ecf20Sopenharmony_ci	{0x3000, 0x35},
2078c2ecf20Sopenharmony_ci	{0x3054, 0x01},
2088c2ecf20Sopenharmony_ci	{0x305C, 0x11},
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	{0x0112, 0x0A},
2118c2ecf20Sopenharmony_ci	{0x0113, 0x0A},
2128c2ecf20Sopenharmony_ci	{0x034C, 0x07},
2138c2ecf20Sopenharmony_ci	{0x034D, 0x80},
2148c2ecf20Sopenharmony_ci	{0x034E, 0x04},
2158c2ecf20Sopenharmony_ci	{0x034F, 0x38},
2168c2ecf20Sopenharmony_ci	{0x0401, 0x00},
2178c2ecf20Sopenharmony_ci	{0x0404, 0x00},
2188c2ecf20Sopenharmony_ci	{0x0405, 0x10},
2198c2ecf20Sopenharmony_ci	{0x0408, 0x00},
2208c2ecf20Sopenharmony_ci	{0x0409, 0x00},
2218c2ecf20Sopenharmony_ci	{0x040A, 0x00},
2228c2ecf20Sopenharmony_ci	{0x040B, 0x00},
2238c2ecf20Sopenharmony_ci	{0x040C, 0x07},
2248c2ecf20Sopenharmony_ci	{0x040D, 0x80},
2258c2ecf20Sopenharmony_ci	{0x040E, 0x04},
2268c2ecf20Sopenharmony_ci	{0x040F, 0x38},
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	{0x0301, 0x05},
2298c2ecf20Sopenharmony_ci	{0x0303, 0x02},
2308c2ecf20Sopenharmony_ci	{0x0305, 0x03},
2318c2ecf20Sopenharmony_ci	{0x0306, 0x00},
2328c2ecf20Sopenharmony_ci	{0x0307, 0x96},
2338c2ecf20Sopenharmony_ci	{0x0309, 0x0A},
2348c2ecf20Sopenharmony_ci	{0x030B, 0x01},
2358c2ecf20Sopenharmony_ci	{0x0310, 0x00},
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	{0x0820, 0x12},
2388c2ecf20Sopenharmony_ci	{0x0821, 0xC0},
2398c2ecf20Sopenharmony_ci	{0x0822, 0x00},
2408c2ecf20Sopenharmony_ci	{0x0823, 0x00},
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	{0x3A03, 0x04},
2438c2ecf20Sopenharmony_ci	{0x3A04, 0xF8},
2448c2ecf20Sopenharmony_ci	{0x3A05, 0x02},
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	{0x0B06, 0x01},
2478c2ecf20Sopenharmony_ci	{0x30A2, 0x00},
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	{0x30B4, 0x00},
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	{0x3A02, 0xFF},
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	{0x3011, 0x00},
2548c2ecf20Sopenharmony_ci	{0x3013, 0x01},
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	{0x0202, 0x0C},
2578c2ecf20Sopenharmony_ci	{0x0203, 0x70},
2588c2ecf20Sopenharmony_ci	{0x0224, 0x01},
2598c2ecf20Sopenharmony_ci	{0x0225, 0xF4},
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	{0x0204, 0x00},
2628c2ecf20Sopenharmony_ci	{0x0205, 0x00},
2638c2ecf20Sopenharmony_ci	{0x020E, 0x01},
2648c2ecf20Sopenharmony_ci	{0x020F, 0x00},
2658c2ecf20Sopenharmony_ci	{0x0210, 0x01},
2668c2ecf20Sopenharmony_ci	{0x0211, 0x00},
2678c2ecf20Sopenharmony_ci	{0x0212, 0x01},
2688c2ecf20Sopenharmony_ci	{0x0213, 0x00},
2698c2ecf20Sopenharmony_ci	{0x0214, 0x01},
2708c2ecf20Sopenharmony_ci	{0x0215, 0x00},
2718c2ecf20Sopenharmony_ci	{0x0216, 0x00},
2728c2ecf20Sopenharmony_ci	{0x0217, 0x00},
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	{0x4170, 0x00},
2758c2ecf20Sopenharmony_ci	{0x4171, 0x10},
2768c2ecf20Sopenharmony_ci	{0x4176, 0x00},
2778c2ecf20Sopenharmony_ci	{0x4177, 0x3C},
2788c2ecf20Sopenharmony_ci	{0xAE20, 0x04},
2798c2ecf20Sopenharmony_ci	{0xAE21, 0x5C},
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	{IMX214_TABLE_WAIT_MS, 10},
2828c2ecf20Sopenharmony_ci	{0x0138, 0x01},
2838c2ecf20Sopenharmony_ci	{IMX214_TABLE_END, 0x00}
2848c2ecf20Sopenharmony_ci};
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_cistatic const struct reg_8 mode_table_common[] = {
2878c2ecf20Sopenharmony_ci	/* software reset */
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	/* software standby settings */
2908c2ecf20Sopenharmony_ci	{0x0100, 0x00},
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	/* ATR setting */
2938c2ecf20Sopenharmony_ci	{0x9300, 0x02},
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	/* external clock setting */
2968c2ecf20Sopenharmony_ci	{0x0136, 0x18},
2978c2ecf20Sopenharmony_ci	{0x0137, 0x00},
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	/* global setting */
3008c2ecf20Sopenharmony_ci	/* basic config */
3018c2ecf20Sopenharmony_ci	{0x0101, 0x00},
3028c2ecf20Sopenharmony_ci	{0x0105, 0x01},
3038c2ecf20Sopenharmony_ci	{0x0106, 0x01},
3048c2ecf20Sopenharmony_ci	{0x4550, 0x02},
3058c2ecf20Sopenharmony_ci	{0x4601, 0x00},
3068c2ecf20Sopenharmony_ci	{0x4642, 0x05},
3078c2ecf20Sopenharmony_ci	{0x6227, 0x11},
3088c2ecf20Sopenharmony_ci	{0x6276, 0x00},
3098c2ecf20Sopenharmony_ci	{0x900E, 0x06},
3108c2ecf20Sopenharmony_ci	{0xA802, 0x90},
3118c2ecf20Sopenharmony_ci	{0xA803, 0x11},
3128c2ecf20Sopenharmony_ci	{0xA804, 0x62},
3138c2ecf20Sopenharmony_ci	{0xA805, 0x77},
3148c2ecf20Sopenharmony_ci	{0xA806, 0xAE},
3158c2ecf20Sopenharmony_ci	{0xA807, 0x34},
3168c2ecf20Sopenharmony_ci	{0xA808, 0xAE},
3178c2ecf20Sopenharmony_ci	{0xA809, 0x35},
3188c2ecf20Sopenharmony_ci	{0xA80A, 0x62},
3198c2ecf20Sopenharmony_ci	{0xA80B, 0x83},
3208c2ecf20Sopenharmony_ci	{0xAE33, 0x00},
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	/* analog setting */
3238c2ecf20Sopenharmony_ci	{0x4174, 0x00},
3248c2ecf20Sopenharmony_ci	{0x4175, 0x11},
3258c2ecf20Sopenharmony_ci	{0x4612, 0x29},
3268c2ecf20Sopenharmony_ci	{0x461B, 0x12},
3278c2ecf20Sopenharmony_ci	{0x461F, 0x06},
3288c2ecf20Sopenharmony_ci	{0x4635, 0x07},
3298c2ecf20Sopenharmony_ci	{0x4637, 0x30},
3308c2ecf20Sopenharmony_ci	{0x463F, 0x18},
3318c2ecf20Sopenharmony_ci	{0x4641, 0x0D},
3328c2ecf20Sopenharmony_ci	{0x465B, 0x12},
3338c2ecf20Sopenharmony_ci	{0x465F, 0x11},
3348c2ecf20Sopenharmony_ci	{0x4663, 0x11},
3358c2ecf20Sopenharmony_ci	{0x4667, 0x0F},
3368c2ecf20Sopenharmony_ci	{0x466F, 0x0F},
3378c2ecf20Sopenharmony_ci	{0x470E, 0x09},
3388c2ecf20Sopenharmony_ci	{0x4909, 0xAB},
3398c2ecf20Sopenharmony_ci	{0x490B, 0x95},
3408c2ecf20Sopenharmony_ci	{0x4915, 0x5D},
3418c2ecf20Sopenharmony_ci	{0x4A5F, 0xFF},
3428c2ecf20Sopenharmony_ci	{0x4A61, 0xFF},
3438c2ecf20Sopenharmony_ci	{0x4A73, 0x62},
3448c2ecf20Sopenharmony_ci	{0x4A85, 0x00},
3458c2ecf20Sopenharmony_ci	{0x4A87, 0xFF},
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	/* embedded data */
3488c2ecf20Sopenharmony_ci	{0x5041, 0x04},
3498c2ecf20Sopenharmony_ci	{0x583C, 0x04},
3508c2ecf20Sopenharmony_ci	{0x620E, 0x04},
3518c2ecf20Sopenharmony_ci	{0x6EB2, 0x01},
3528c2ecf20Sopenharmony_ci	{0x6EB3, 0x00},
3538c2ecf20Sopenharmony_ci	{0x9300, 0x02},
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	/* imagequality */
3568c2ecf20Sopenharmony_ci	/* HDR setting */
3578c2ecf20Sopenharmony_ci	{0x3001, 0x07},
3588c2ecf20Sopenharmony_ci	{0x6D12, 0x3F},
3598c2ecf20Sopenharmony_ci	{0x6D13, 0xFF},
3608c2ecf20Sopenharmony_ci	{0x9344, 0x03},
3618c2ecf20Sopenharmony_ci	{0x9706, 0x10},
3628c2ecf20Sopenharmony_ci	{0x9707, 0x03},
3638c2ecf20Sopenharmony_ci	{0x9708, 0x03},
3648c2ecf20Sopenharmony_ci	{0x9E04, 0x01},
3658c2ecf20Sopenharmony_ci	{0x9E05, 0x00},
3668c2ecf20Sopenharmony_ci	{0x9E0C, 0x01},
3678c2ecf20Sopenharmony_ci	{0x9E0D, 0x02},
3688c2ecf20Sopenharmony_ci	{0x9E24, 0x00},
3698c2ecf20Sopenharmony_ci	{0x9E25, 0x8C},
3708c2ecf20Sopenharmony_ci	{0x9E26, 0x00},
3718c2ecf20Sopenharmony_ci	{0x9E27, 0x94},
3728c2ecf20Sopenharmony_ci	{0x9E28, 0x00},
3738c2ecf20Sopenharmony_ci	{0x9E29, 0x96},
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	/* CNR parameter setting */
3768c2ecf20Sopenharmony_ci	{0x69DB, 0x01},
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	/* Moire reduction */
3798c2ecf20Sopenharmony_ci	{0x6957, 0x01},
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	/* image enhancement */
3828c2ecf20Sopenharmony_ci	{0x6987, 0x17},
3838c2ecf20Sopenharmony_ci	{0x698A, 0x03},
3848c2ecf20Sopenharmony_ci	{0x698B, 0x03},
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	/* white balanace */
3878c2ecf20Sopenharmony_ci	{0x0B8E, 0x01},
3888c2ecf20Sopenharmony_ci	{0x0B8F, 0x00},
3898c2ecf20Sopenharmony_ci	{0x0B90, 0x01},
3908c2ecf20Sopenharmony_ci	{0x0B91, 0x00},
3918c2ecf20Sopenharmony_ci	{0x0B92, 0x01},
3928c2ecf20Sopenharmony_ci	{0x0B93, 0x00},
3938c2ecf20Sopenharmony_ci	{0x0B94, 0x01},
3948c2ecf20Sopenharmony_ci	{0x0B95, 0x00},
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	/* ATR setting */
3978c2ecf20Sopenharmony_ci	{0x6E50, 0x00},
3988c2ecf20Sopenharmony_ci	{0x6E51, 0x32},
3998c2ecf20Sopenharmony_ci	{0x9340, 0x00},
4008c2ecf20Sopenharmony_ci	{0x9341, 0x3C},
4018c2ecf20Sopenharmony_ci	{0x9342, 0x03},
4028c2ecf20Sopenharmony_ci	{0x9343, 0xFF},
4038c2ecf20Sopenharmony_ci	{IMX214_TABLE_END, 0x00}
4048c2ecf20Sopenharmony_ci};
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci/*
4078c2ecf20Sopenharmony_ci * Declare modes in order, from biggest
4088c2ecf20Sopenharmony_ci * to smallest height.
4098c2ecf20Sopenharmony_ci */
4108c2ecf20Sopenharmony_cistatic const struct imx214_mode {
4118c2ecf20Sopenharmony_ci	u32 width;
4128c2ecf20Sopenharmony_ci	u32 height;
4138c2ecf20Sopenharmony_ci	const struct reg_8 *reg_table;
4148c2ecf20Sopenharmony_ci} imx214_modes[] = {
4158c2ecf20Sopenharmony_ci	{
4168c2ecf20Sopenharmony_ci		.width = 4096,
4178c2ecf20Sopenharmony_ci		.height = 2304,
4188c2ecf20Sopenharmony_ci		.reg_table = mode_4096x2304,
4198c2ecf20Sopenharmony_ci	},
4208c2ecf20Sopenharmony_ci	{
4218c2ecf20Sopenharmony_ci		.width = 1920,
4228c2ecf20Sopenharmony_ci		.height = 1080,
4238c2ecf20Sopenharmony_ci		.reg_table = mode_1920x1080,
4248c2ecf20Sopenharmony_ci	},
4258c2ecf20Sopenharmony_ci};
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistatic inline struct imx214 *to_imx214(struct v4l2_subdev *sd)
4288c2ecf20Sopenharmony_ci{
4298c2ecf20Sopenharmony_ci	return container_of(sd, struct imx214, sd);
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic int __maybe_unused imx214_power_on(struct device *dev)
4338c2ecf20Sopenharmony_ci{
4348c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
4358c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = i2c_get_clientdata(client);
4368c2ecf20Sopenharmony_ci	struct imx214 *imx214 = to_imx214(sd);
4378c2ecf20Sopenharmony_ci	int ret;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	ret = regulator_bulk_enable(IMX214_NUM_SUPPLIES, imx214->supplies);
4408c2ecf20Sopenharmony_ci	if (ret < 0) {
4418c2ecf20Sopenharmony_ci		dev_err(imx214->dev, "failed to enable regulators: %d\n", ret);
4428c2ecf20Sopenharmony_ci		return ret;
4438c2ecf20Sopenharmony_ci	}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	usleep_range(2000, 3000);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	ret = clk_prepare_enable(imx214->xclk);
4488c2ecf20Sopenharmony_ci	if (ret < 0) {
4498c2ecf20Sopenharmony_ci		regulator_bulk_disable(IMX214_NUM_SUPPLIES, imx214->supplies);
4508c2ecf20Sopenharmony_ci		dev_err(imx214->dev, "clk prepare enable failed\n");
4518c2ecf20Sopenharmony_ci		return ret;
4528c2ecf20Sopenharmony_ci	}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(imx214->enable_gpio, 1);
4558c2ecf20Sopenharmony_ci	usleep_range(12000, 15000);
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	return 0;
4588c2ecf20Sopenharmony_ci}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_cistatic int __maybe_unused imx214_power_off(struct device *dev)
4618c2ecf20Sopenharmony_ci{
4628c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
4638c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = i2c_get_clientdata(client);
4648c2ecf20Sopenharmony_ci	struct imx214 *imx214 = to_imx214(sd);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	gpiod_set_value_cansleep(imx214->enable_gpio, 0);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	clk_disable_unprepare(imx214->xclk);
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	regulator_bulk_disable(IMX214_NUM_SUPPLIES, imx214->supplies);
4718c2ecf20Sopenharmony_ci	usleep_range(10, 20);
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	return 0;
4748c2ecf20Sopenharmony_ci}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_cistatic int imx214_enum_mbus_code(struct v4l2_subdev *sd,
4778c2ecf20Sopenharmony_ci				 struct v4l2_subdev_pad_config *cfg,
4788c2ecf20Sopenharmony_ci				 struct v4l2_subdev_mbus_code_enum *code)
4798c2ecf20Sopenharmony_ci{
4808c2ecf20Sopenharmony_ci	if (code->index > 0)
4818c2ecf20Sopenharmony_ci		return -EINVAL;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	code->code = IMX214_MBUS_CODE;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	return 0;
4868c2ecf20Sopenharmony_ci}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_cistatic int imx214_enum_frame_size(struct v4l2_subdev *subdev,
4898c2ecf20Sopenharmony_ci				  struct v4l2_subdev_pad_config *cfg,
4908c2ecf20Sopenharmony_ci				  struct v4l2_subdev_frame_size_enum *fse)
4918c2ecf20Sopenharmony_ci{
4928c2ecf20Sopenharmony_ci	if (fse->code != IMX214_MBUS_CODE)
4938c2ecf20Sopenharmony_ci		return -EINVAL;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	if (fse->index >= ARRAY_SIZE(imx214_modes))
4968c2ecf20Sopenharmony_ci		return -EINVAL;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	fse->min_width = fse->max_width = imx214_modes[fse->index].width;
4998c2ecf20Sopenharmony_ci	fse->min_height = fse->max_height = imx214_modes[fse->index].height;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	return 0;
5028c2ecf20Sopenharmony_ci}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG
5058c2ecf20Sopenharmony_cistatic int imx214_s_register(struct v4l2_subdev *subdev,
5068c2ecf20Sopenharmony_ci			     const struct v4l2_dbg_register *reg)
5078c2ecf20Sopenharmony_ci{
5088c2ecf20Sopenharmony_ci	struct imx214 *imx214 = container_of(subdev, struct imx214, sd);
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	return regmap_write(imx214->regmap, reg->reg, reg->val);
5118c2ecf20Sopenharmony_ci}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_cistatic int imx214_g_register(struct v4l2_subdev *subdev,
5148c2ecf20Sopenharmony_ci			     struct v4l2_dbg_register *reg)
5158c2ecf20Sopenharmony_ci{
5168c2ecf20Sopenharmony_ci	struct imx214 *imx214 = container_of(subdev, struct imx214, sd);
5178c2ecf20Sopenharmony_ci	unsigned int aux;
5188c2ecf20Sopenharmony_ci	int ret;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	reg->size = 1;
5218c2ecf20Sopenharmony_ci	ret = regmap_read(imx214->regmap, reg->reg, &aux);
5228c2ecf20Sopenharmony_ci	reg->val = aux;
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	return ret;
5258c2ecf20Sopenharmony_ci}
5268c2ecf20Sopenharmony_ci#endif
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_core_ops imx214_core_ops = {
5298c2ecf20Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG
5308c2ecf20Sopenharmony_ci	.g_register = imx214_g_register,
5318c2ecf20Sopenharmony_ci	.s_register = imx214_s_register,
5328c2ecf20Sopenharmony_ci#endif
5338c2ecf20Sopenharmony_ci};
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_cistatic struct v4l2_mbus_framefmt *
5368c2ecf20Sopenharmony_ci__imx214_get_pad_format(struct imx214 *imx214,
5378c2ecf20Sopenharmony_ci			struct v4l2_subdev_pad_config *cfg,
5388c2ecf20Sopenharmony_ci			unsigned int pad,
5398c2ecf20Sopenharmony_ci			enum v4l2_subdev_format_whence which)
5408c2ecf20Sopenharmony_ci{
5418c2ecf20Sopenharmony_ci	switch (which) {
5428c2ecf20Sopenharmony_ci	case V4L2_SUBDEV_FORMAT_TRY:
5438c2ecf20Sopenharmony_ci		return v4l2_subdev_get_try_format(&imx214->sd, cfg, pad);
5448c2ecf20Sopenharmony_ci	case V4L2_SUBDEV_FORMAT_ACTIVE:
5458c2ecf20Sopenharmony_ci		return &imx214->fmt;
5468c2ecf20Sopenharmony_ci	default:
5478c2ecf20Sopenharmony_ci		return NULL;
5488c2ecf20Sopenharmony_ci	}
5498c2ecf20Sopenharmony_ci}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_cistatic int imx214_get_format(struct v4l2_subdev *sd,
5528c2ecf20Sopenharmony_ci			     struct v4l2_subdev_pad_config *cfg,
5538c2ecf20Sopenharmony_ci			     struct v4l2_subdev_format *format)
5548c2ecf20Sopenharmony_ci{
5558c2ecf20Sopenharmony_ci	struct imx214 *imx214 = to_imx214(sd);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	mutex_lock(&imx214->mutex);
5588c2ecf20Sopenharmony_ci	format->format = *__imx214_get_pad_format(imx214, cfg, format->pad,
5598c2ecf20Sopenharmony_ci						  format->which);
5608c2ecf20Sopenharmony_ci	mutex_unlock(&imx214->mutex);
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	return 0;
5638c2ecf20Sopenharmony_ci}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_cistatic struct v4l2_rect *
5668c2ecf20Sopenharmony_ci__imx214_get_pad_crop(struct imx214 *imx214, struct v4l2_subdev_pad_config *cfg,
5678c2ecf20Sopenharmony_ci		      unsigned int pad, enum v4l2_subdev_format_whence which)
5688c2ecf20Sopenharmony_ci{
5698c2ecf20Sopenharmony_ci	switch (which) {
5708c2ecf20Sopenharmony_ci	case V4L2_SUBDEV_FORMAT_TRY:
5718c2ecf20Sopenharmony_ci		return v4l2_subdev_get_try_crop(&imx214->sd, cfg, pad);
5728c2ecf20Sopenharmony_ci	case V4L2_SUBDEV_FORMAT_ACTIVE:
5738c2ecf20Sopenharmony_ci		return &imx214->crop;
5748c2ecf20Sopenharmony_ci	default:
5758c2ecf20Sopenharmony_ci		return NULL;
5768c2ecf20Sopenharmony_ci	}
5778c2ecf20Sopenharmony_ci}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_cistatic int imx214_set_format(struct v4l2_subdev *sd,
5808c2ecf20Sopenharmony_ci			     struct v4l2_subdev_pad_config *cfg,
5818c2ecf20Sopenharmony_ci			     struct v4l2_subdev_format *format)
5828c2ecf20Sopenharmony_ci{
5838c2ecf20Sopenharmony_ci	struct imx214 *imx214 = to_imx214(sd);
5848c2ecf20Sopenharmony_ci	struct v4l2_mbus_framefmt *__format;
5858c2ecf20Sopenharmony_ci	struct v4l2_rect *__crop;
5868c2ecf20Sopenharmony_ci	const struct imx214_mode *mode;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	mutex_lock(&imx214->mutex);
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	__crop = __imx214_get_pad_crop(imx214, cfg, format->pad, format->which);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	mode = v4l2_find_nearest_size(imx214_modes,
5938c2ecf20Sopenharmony_ci				      ARRAY_SIZE(imx214_modes), width, height,
5948c2ecf20Sopenharmony_ci				      format->format.width,
5958c2ecf20Sopenharmony_ci				      format->format.height);
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	__crop->width = mode->width;
5988c2ecf20Sopenharmony_ci	__crop->height = mode->height;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	__format = __imx214_get_pad_format(imx214, cfg, format->pad,
6018c2ecf20Sopenharmony_ci					   format->which);
6028c2ecf20Sopenharmony_ci	__format->width = __crop->width;
6038c2ecf20Sopenharmony_ci	__format->height = __crop->height;
6048c2ecf20Sopenharmony_ci	__format->code = IMX214_MBUS_CODE;
6058c2ecf20Sopenharmony_ci	__format->field = V4L2_FIELD_NONE;
6068c2ecf20Sopenharmony_ci	__format->colorspace = V4L2_COLORSPACE_SRGB;
6078c2ecf20Sopenharmony_ci	__format->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(__format->colorspace);
6088c2ecf20Sopenharmony_ci	__format->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true,
6098c2ecf20Sopenharmony_ci				__format->colorspace, __format->ycbcr_enc);
6108c2ecf20Sopenharmony_ci	__format->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(__format->colorspace);
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	format->format = *__format;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	mutex_unlock(&imx214->mutex);
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	return 0;
6178c2ecf20Sopenharmony_ci}
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_cistatic int imx214_get_selection(struct v4l2_subdev *sd,
6208c2ecf20Sopenharmony_ci				struct v4l2_subdev_pad_config *cfg,
6218c2ecf20Sopenharmony_ci				struct v4l2_subdev_selection *sel)
6228c2ecf20Sopenharmony_ci{
6238c2ecf20Sopenharmony_ci	struct imx214 *imx214 = to_imx214(sd);
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	if (sel->target != V4L2_SEL_TGT_CROP)
6268c2ecf20Sopenharmony_ci		return -EINVAL;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	mutex_lock(&imx214->mutex);
6298c2ecf20Sopenharmony_ci	sel->r = *__imx214_get_pad_crop(imx214, cfg, sel->pad,
6308c2ecf20Sopenharmony_ci					sel->which);
6318c2ecf20Sopenharmony_ci	mutex_unlock(&imx214->mutex);
6328c2ecf20Sopenharmony_ci	return 0;
6338c2ecf20Sopenharmony_ci}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_cistatic int imx214_entity_init_cfg(struct v4l2_subdev *subdev,
6368c2ecf20Sopenharmony_ci				  struct v4l2_subdev_pad_config *cfg)
6378c2ecf20Sopenharmony_ci{
6388c2ecf20Sopenharmony_ci	struct v4l2_subdev_format fmt = { };
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	fmt.which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
6418c2ecf20Sopenharmony_ci	fmt.format.width = imx214_modes[0].width;
6428c2ecf20Sopenharmony_ci	fmt.format.height = imx214_modes[0].height;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	imx214_set_format(subdev, cfg, &fmt);
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	return 0;
6478c2ecf20Sopenharmony_ci}
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_cistatic int imx214_set_ctrl(struct v4l2_ctrl *ctrl)
6508c2ecf20Sopenharmony_ci{
6518c2ecf20Sopenharmony_ci	struct imx214 *imx214 = container_of(ctrl->handler,
6528c2ecf20Sopenharmony_ci					     struct imx214, ctrls);
6538c2ecf20Sopenharmony_ci	u8 vals[2];
6548c2ecf20Sopenharmony_ci	int ret;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	/*
6578c2ecf20Sopenharmony_ci	 * Applying V4L2 control value only happens
6588c2ecf20Sopenharmony_ci	 * when power is up for streaming
6598c2ecf20Sopenharmony_ci	 */
6608c2ecf20Sopenharmony_ci	if (!pm_runtime_get_if_in_use(imx214->dev))
6618c2ecf20Sopenharmony_ci		return 0;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	switch (ctrl->id) {
6648c2ecf20Sopenharmony_ci	case V4L2_CID_EXPOSURE:
6658c2ecf20Sopenharmony_ci		vals[1] = ctrl->val;
6668c2ecf20Sopenharmony_ci		vals[0] = ctrl->val >> 8;
6678c2ecf20Sopenharmony_ci		ret = regmap_bulk_write(imx214->regmap, 0x202, vals, 2);
6688c2ecf20Sopenharmony_ci		if (ret < 0)
6698c2ecf20Sopenharmony_ci			dev_err(imx214->dev, "Error %d\n", ret);
6708c2ecf20Sopenharmony_ci		ret = 0;
6718c2ecf20Sopenharmony_ci		break;
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	default:
6748c2ecf20Sopenharmony_ci		ret = -EINVAL;
6758c2ecf20Sopenharmony_ci	}
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	pm_runtime_put(imx214->dev);
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	return ret;
6808c2ecf20Sopenharmony_ci}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops imx214_ctrl_ops = {
6838c2ecf20Sopenharmony_ci	.s_ctrl = imx214_set_ctrl,
6848c2ecf20Sopenharmony_ci};
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci#define MAX_CMD 4
6878c2ecf20Sopenharmony_cistatic int imx214_write_table(struct imx214 *imx214,
6888c2ecf20Sopenharmony_ci			      const struct reg_8 table[])
6898c2ecf20Sopenharmony_ci{
6908c2ecf20Sopenharmony_ci	u8 vals[MAX_CMD];
6918c2ecf20Sopenharmony_ci	int i;
6928c2ecf20Sopenharmony_ci	int ret;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	for (; table->addr != IMX214_TABLE_END ; table++) {
6958c2ecf20Sopenharmony_ci		if (table->addr == IMX214_TABLE_WAIT_MS) {
6968c2ecf20Sopenharmony_ci			usleep_range(table->val * 1000,
6978c2ecf20Sopenharmony_ci				     table->val * 1000 + 500);
6988c2ecf20Sopenharmony_ci			continue;
6998c2ecf20Sopenharmony_ci		}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci		for (i = 0; i < MAX_CMD; i++) {
7028c2ecf20Sopenharmony_ci			if (table[i].addr != (table[0].addr + i))
7038c2ecf20Sopenharmony_ci				break;
7048c2ecf20Sopenharmony_ci			vals[i] = table[i].val;
7058c2ecf20Sopenharmony_ci		}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci		ret = regmap_bulk_write(imx214->regmap, table->addr, vals, i);
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci		if (ret) {
7108c2ecf20Sopenharmony_ci			dev_err(imx214->dev, "write_table error: %d\n", ret);
7118c2ecf20Sopenharmony_ci			return ret;
7128c2ecf20Sopenharmony_ci		}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci		table += i - 1;
7158c2ecf20Sopenharmony_ci	}
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	return 0;
7188c2ecf20Sopenharmony_ci}
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_cistatic int imx214_start_streaming(struct imx214 *imx214)
7218c2ecf20Sopenharmony_ci{
7228c2ecf20Sopenharmony_ci	const struct imx214_mode *mode;
7238c2ecf20Sopenharmony_ci	int ret;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	mutex_lock(&imx214->mutex);
7268c2ecf20Sopenharmony_ci	ret = imx214_write_table(imx214, mode_table_common);
7278c2ecf20Sopenharmony_ci	if (ret < 0) {
7288c2ecf20Sopenharmony_ci		dev_err(imx214->dev, "could not sent common table %d\n", ret);
7298c2ecf20Sopenharmony_ci		goto error;
7308c2ecf20Sopenharmony_ci	}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	mode = v4l2_find_nearest_size(imx214_modes,
7338c2ecf20Sopenharmony_ci				ARRAY_SIZE(imx214_modes), width, height,
7348c2ecf20Sopenharmony_ci				imx214->fmt.width, imx214->fmt.height);
7358c2ecf20Sopenharmony_ci	ret = imx214_write_table(imx214, mode->reg_table);
7368c2ecf20Sopenharmony_ci	if (ret < 0) {
7378c2ecf20Sopenharmony_ci		dev_err(imx214->dev, "could not sent mode table %d\n", ret);
7388c2ecf20Sopenharmony_ci		goto error;
7398c2ecf20Sopenharmony_ci	}
7408c2ecf20Sopenharmony_ci	ret = __v4l2_ctrl_handler_setup(&imx214->ctrls);
7418c2ecf20Sopenharmony_ci	if (ret < 0) {
7428c2ecf20Sopenharmony_ci		dev_err(imx214->dev, "could not sync v4l2 controls\n");
7438c2ecf20Sopenharmony_ci		goto error;
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci	ret = regmap_write(imx214->regmap, 0x100, 1);
7468c2ecf20Sopenharmony_ci	if (ret < 0) {
7478c2ecf20Sopenharmony_ci		dev_err(imx214->dev, "could not sent start table %d\n", ret);
7488c2ecf20Sopenharmony_ci		goto error;
7498c2ecf20Sopenharmony_ci	}
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	mutex_unlock(&imx214->mutex);
7528c2ecf20Sopenharmony_ci	return 0;
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_cierror:
7558c2ecf20Sopenharmony_ci	mutex_unlock(&imx214->mutex);
7568c2ecf20Sopenharmony_ci	return ret;
7578c2ecf20Sopenharmony_ci}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_cistatic int imx214_stop_streaming(struct imx214 *imx214)
7608c2ecf20Sopenharmony_ci{
7618c2ecf20Sopenharmony_ci	int ret;
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	ret = regmap_write(imx214->regmap, 0x100, 0);
7648c2ecf20Sopenharmony_ci	if (ret < 0)
7658c2ecf20Sopenharmony_ci		dev_err(imx214->dev, "could not sent stop table %d\n",	ret);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	return ret;
7688c2ecf20Sopenharmony_ci}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_cistatic int imx214_s_stream(struct v4l2_subdev *subdev, int enable)
7718c2ecf20Sopenharmony_ci{
7728c2ecf20Sopenharmony_ci	struct imx214 *imx214 = to_imx214(subdev);
7738c2ecf20Sopenharmony_ci	int ret;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	if (imx214->streaming == enable)
7768c2ecf20Sopenharmony_ci		return 0;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	if (enable) {
7798c2ecf20Sopenharmony_ci		ret = pm_runtime_get_sync(imx214->dev);
7808c2ecf20Sopenharmony_ci		if (ret < 0) {
7818c2ecf20Sopenharmony_ci			pm_runtime_put_noidle(imx214->dev);
7828c2ecf20Sopenharmony_ci			return ret;
7838c2ecf20Sopenharmony_ci		}
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci		ret = imx214_start_streaming(imx214);
7868c2ecf20Sopenharmony_ci		if (ret < 0)
7878c2ecf20Sopenharmony_ci			goto err_rpm_put;
7888c2ecf20Sopenharmony_ci	} else {
7898c2ecf20Sopenharmony_ci		ret = imx214_stop_streaming(imx214);
7908c2ecf20Sopenharmony_ci		if (ret < 0)
7918c2ecf20Sopenharmony_ci			goto err_rpm_put;
7928c2ecf20Sopenharmony_ci		pm_runtime_put(imx214->dev);
7938c2ecf20Sopenharmony_ci	}
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	imx214->streaming = enable;
7968c2ecf20Sopenharmony_ci	return 0;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_cierr_rpm_put:
7998c2ecf20Sopenharmony_ci	pm_runtime_put(imx214->dev);
8008c2ecf20Sopenharmony_ci	return ret;
8018c2ecf20Sopenharmony_ci}
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_cistatic int imx214_g_frame_interval(struct v4l2_subdev *subdev,
8048c2ecf20Sopenharmony_ci				   struct v4l2_subdev_frame_interval *fival)
8058c2ecf20Sopenharmony_ci{
8068c2ecf20Sopenharmony_ci	fival->interval.numerator = 1;
8078c2ecf20Sopenharmony_ci	fival->interval.denominator = IMX214_FPS;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	return 0;
8108c2ecf20Sopenharmony_ci}
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_cistatic int imx214_enum_frame_interval(struct v4l2_subdev *subdev,
8138c2ecf20Sopenharmony_ci				struct v4l2_subdev_pad_config *cfg,
8148c2ecf20Sopenharmony_ci				struct v4l2_subdev_frame_interval_enum *fie)
8158c2ecf20Sopenharmony_ci{
8168c2ecf20Sopenharmony_ci	const struct imx214_mode *mode;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	if (fie->index != 0)
8198c2ecf20Sopenharmony_ci		return -EINVAL;
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	mode = v4l2_find_nearest_size(imx214_modes,
8228c2ecf20Sopenharmony_ci				ARRAY_SIZE(imx214_modes), width, height,
8238c2ecf20Sopenharmony_ci				fie->width, fie->height);
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	fie->code = IMX214_MBUS_CODE;
8268c2ecf20Sopenharmony_ci	fie->width = mode->width;
8278c2ecf20Sopenharmony_ci	fie->height = mode->height;
8288c2ecf20Sopenharmony_ci	fie->interval.numerator = 1;
8298c2ecf20Sopenharmony_ci	fie->interval.denominator = IMX214_FPS;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	return 0;
8328c2ecf20Sopenharmony_ci}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_video_ops imx214_video_ops = {
8358c2ecf20Sopenharmony_ci	.s_stream = imx214_s_stream,
8368c2ecf20Sopenharmony_ci	.g_frame_interval = imx214_g_frame_interval,
8378c2ecf20Sopenharmony_ci	.s_frame_interval = imx214_g_frame_interval,
8388c2ecf20Sopenharmony_ci};
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_pad_ops imx214_subdev_pad_ops = {
8418c2ecf20Sopenharmony_ci	.enum_mbus_code = imx214_enum_mbus_code,
8428c2ecf20Sopenharmony_ci	.enum_frame_size = imx214_enum_frame_size,
8438c2ecf20Sopenharmony_ci	.enum_frame_interval = imx214_enum_frame_interval,
8448c2ecf20Sopenharmony_ci	.get_fmt = imx214_get_format,
8458c2ecf20Sopenharmony_ci	.set_fmt = imx214_set_format,
8468c2ecf20Sopenharmony_ci	.get_selection = imx214_get_selection,
8478c2ecf20Sopenharmony_ci	.init_cfg = imx214_entity_init_cfg,
8488c2ecf20Sopenharmony_ci};
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops imx214_subdev_ops = {
8518c2ecf20Sopenharmony_ci	.core = &imx214_core_ops,
8528c2ecf20Sopenharmony_ci	.video = &imx214_video_ops,
8538c2ecf20Sopenharmony_ci	.pad = &imx214_subdev_pad_ops,
8548c2ecf20Sopenharmony_ci};
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_cistatic const struct regmap_config sensor_regmap_config = {
8578c2ecf20Sopenharmony_ci	.reg_bits = 16,
8588c2ecf20Sopenharmony_ci	.val_bits = 8,
8598c2ecf20Sopenharmony_ci	.cache_type = REGCACHE_RBTREE,
8608c2ecf20Sopenharmony_ci};
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_cistatic int imx214_get_regulators(struct device *dev, struct imx214 *imx214)
8638c2ecf20Sopenharmony_ci{
8648c2ecf20Sopenharmony_ci	unsigned int i;
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	for (i = 0; i < IMX214_NUM_SUPPLIES; i++)
8678c2ecf20Sopenharmony_ci		imx214->supplies[i].supply = imx214_supply_name[i];
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	return devm_regulator_bulk_get(dev, IMX214_NUM_SUPPLIES,
8708c2ecf20Sopenharmony_ci				       imx214->supplies);
8718c2ecf20Sopenharmony_ci}
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_cistatic int imx214_parse_fwnode(struct device *dev)
8748c2ecf20Sopenharmony_ci{
8758c2ecf20Sopenharmony_ci	struct fwnode_handle *endpoint;
8768c2ecf20Sopenharmony_ci	struct v4l2_fwnode_endpoint bus_cfg = {
8778c2ecf20Sopenharmony_ci		.bus_type = V4L2_MBUS_CSI2_DPHY,
8788c2ecf20Sopenharmony_ci	};
8798c2ecf20Sopenharmony_ci	unsigned int i;
8808c2ecf20Sopenharmony_ci	int ret;
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
8838c2ecf20Sopenharmony_ci	if (!endpoint) {
8848c2ecf20Sopenharmony_ci		dev_err(dev, "endpoint node not found\n");
8858c2ecf20Sopenharmony_ci		return -EINVAL;
8868c2ecf20Sopenharmony_ci	}
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg);
8898c2ecf20Sopenharmony_ci	if (ret) {
8908c2ecf20Sopenharmony_ci		dev_err(dev, "parsing endpoint node failed\n");
8918c2ecf20Sopenharmony_ci		goto done;
8928c2ecf20Sopenharmony_ci	}
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++)
8958c2ecf20Sopenharmony_ci		if (bus_cfg.link_frequencies[i] == IMX214_DEFAULT_LINK_FREQ)
8968c2ecf20Sopenharmony_ci			break;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	if (i == bus_cfg.nr_of_link_frequencies) {
8998c2ecf20Sopenharmony_ci		dev_err(dev, "link-frequencies %d not supported, Please review your DT\n",
9008c2ecf20Sopenharmony_ci			IMX214_DEFAULT_LINK_FREQ);
9018c2ecf20Sopenharmony_ci		ret = -EINVAL;
9028c2ecf20Sopenharmony_ci		goto done;
9038c2ecf20Sopenharmony_ci	}
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_cidone:
9068c2ecf20Sopenharmony_ci	v4l2_fwnode_endpoint_free(&bus_cfg);
9078c2ecf20Sopenharmony_ci	fwnode_handle_put(endpoint);
9088c2ecf20Sopenharmony_ci	return ret;
9098c2ecf20Sopenharmony_ci}
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_cistatic int __maybe_unused imx214_suspend(struct device *dev)
9128c2ecf20Sopenharmony_ci{
9138c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
9148c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = i2c_get_clientdata(client);
9158c2ecf20Sopenharmony_ci	struct imx214 *imx214 = to_imx214(sd);
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	if (imx214->streaming)
9188c2ecf20Sopenharmony_ci		imx214_stop_streaming(imx214);
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	return 0;
9218c2ecf20Sopenharmony_ci}
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_cistatic int __maybe_unused imx214_resume(struct device *dev)
9248c2ecf20Sopenharmony_ci{
9258c2ecf20Sopenharmony_ci	struct i2c_client *client = to_i2c_client(dev);
9268c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = i2c_get_clientdata(client);
9278c2ecf20Sopenharmony_ci	struct imx214 *imx214 = to_imx214(sd);
9288c2ecf20Sopenharmony_ci	int ret;
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	if (imx214->streaming) {
9318c2ecf20Sopenharmony_ci		ret = imx214_start_streaming(imx214);
9328c2ecf20Sopenharmony_ci		if (ret)
9338c2ecf20Sopenharmony_ci			goto error;
9348c2ecf20Sopenharmony_ci	}
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	return 0;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_cierror:
9398c2ecf20Sopenharmony_ci	imx214_stop_streaming(imx214);
9408c2ecf20Sopenharmony_ci	imx214->streaming = 0;
9418c2ecf20Sopenharmony_ci	return ret;
9428c2ecf20Sopenharmony_ci}
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_cistatic int imx214_probe(struct i2c_client *client)
9458c2ecf20Sopenharmony_ci{
9468c2ecf20Sopenharmony_ci	struct device *dev = &client->dev;
9478c2ecf20Sopenharmony_ci	struct imx214 *imx214;
9488c2ecf20Sopenharmony_ci	static const s64 link_freq[] = {
9498c2ecf20Sopenharmony_ci		IMX214_DEFAULT_LINK_FREQ,
9508c2ecf20Sopenharmony_ci	};
9518c2ecf20Sopenharmony_ci	static const struct v4l2_area unit_size = {
9528c2ecf20Sopenharmony_ci		.width = 1120,
9538c2ecf20Sopenharmony_ci		.height = 1120,
9548c2ecf20Sopenharmony_ci	};
9558c2ecf20Sopenharmony_ci	int ret;
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	ret = imx214_parse_fwnode(dev);
9588c2ecf20Sopenharmony_ci	if (ret)
9598c2ecf20Sopenharmony_ci		return ret;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	imx214 = devm_kzalloc(dev, sizeof(*imx214), GFP_KERNEL);
9628c2ecf20Sopenharmony_ci	if (!imx214)
9638c2ecf20Sopenharmony_ci		return -ENOMEM;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	imx214->dev = dev;
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	imx214->xclk = devm_clk_get(dev, NULL);
9688c2ecf20Sopenharmony_ci	if (IS_ERR(imx214->xclk)) {
9698c2ecf20Sopenharmony_ci		dev_err(dev, "could not get xclk");
9708c2ecf20Sopenharmony_ci		return PTR_ERR(imx214->xclk);
9718c2ecf20Sopenharmony_ci	}
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	ret = clk_set_rate(imx214->xclk, IMX214_DEFAULT_CLK_FREQ);
9748c2ecf20Sopenharmony_ci	if (ret) {
9758c2ecf20Sopenharmony_ci		dev_err(dev, "could not set xclk frequency\n");
9768c2ecf20Sopenharmony_ci		return ret;
9778c2ecf20Sopenharmony_ci	}
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	ret = imx214_get_regulators(dev, imx214);
9808c2ecf20Sopenharmony_ci	if (ret < 0) {
9818c2ecf20Sopenharmony_ci		dev_err(dev, "cannot get regulators\n");
9828c2ecf20Sopenharmony_ci		return ret;
9838c2ecf20Sopenharmony_ci	}
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	imx214->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
9868c2ecf20Sopenharmony_ci	if (IS_ERR(imx214->enable_gpio)) {
9878c2ecf20Sopenharmony_ci		dev_err(dev, "cannot get enable gpio\n");
9888c2ecf20Sopenharmony_ci		return PTR_ERR(imx214->enable_gpio);
9898c2ecf20Sopenharmony_ci	}
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci	imx214->regmap = devm_regmap_init_i2c(client, &sensor_regmap_config);
9928c2ecf20Sopenharmony_ci	if (IS_ERR(imx214->regmap)) {
9938c2ecf20Sopenharmony_ci		dev_err(dev, "regmap init failed\n");
9948c2ecf20Sopenharmony_ci		return PTR_ERR(imx214->regmap);
9958c2ecf20Sopenharmony_ci	}
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	v4l2_i2c_subdev_init(&imx214->sd, client, &imx214_subdev_ops);
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	/*
10008c2ecf20Sopenharmony_ci	 * Enable power initially, to avoid warnings
10018c2ecf20Sopenharmony_ci	 * from clk_disable on power_off
10028c2ecf20Sopenharmony_ci	 */
10038c2ecf20Sopenharmony_ci	imx214_power_on(imx214->dev);
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	pm_runtime_set_active(imx214->dev);
10068c2ecf20Sopenharmony_ci	pm_runtime_enable(imx214->dev);
10078c2ecf20Sopenharmony_ci	pm_runtime_idle(imx214->dev);
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_init(&imx214->ctrls, 3);
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	imx214->pixel_rate = v4l2_ctrl_new_std(&imx214->ctrls, NULL,
10128c2ecf20Sopenharmony_ci					       V4L2_CID_PIXEL_RATE, 0,
10138c2ecf20Sopenharmony_ci					       IMX214_DEFAULT_PIXEL_RATE, 1,
10148c2ecf20Sopenharmony_ci					       IMX214_DEFAULT_PIXEL_RATE);
10158c2ecf20Sopenharmony_ci	imx214->link_freq = v4l2_ctrl_new_int_menu(&imx214->ctrls, NULL,
10168c2ecf20Sopenharmony_ci						   V4L2_CID_LINK_FREQ,
10178c2ecf20Sopenharmony_ci						   ARRAY_SIZE(link_freq) - 1,
10188c2ecf20Sopenharmony_ci						   0, link_freq);
10198c2ecf20Sopenharmony_ci	if (imx214->link_freq)
10208c2ecf20Sopenharmony_ci		imx214->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	/*
10238c2ecf20Sopenharmony_ci	 * WARNING!
10248c2ecf20Sopenharmony_ci	 * Values obtained reverse engineering blobs and/or devices.
10258c2ecf20Sopenharmony_ci	 * Ranges and functionality might be wrong.
10268c2ecf20Sopenharmony_ci	 *
10278c2ecf20Sopenharmony_ci	 * Sony, please release some register set documentation for the
10288c2ecf20Sopenharmony_ci	 * device.
10298c2ecf20Sopenharmony_ci	 *
10308c2ecf20Sopenharmony_ci	 * Yours sincerely, Ricardo.
10318c2ecf20Sopenharmony_ci	 */
10328c2ecf20Sopenharmony_ci	imx214->exposure = v4l2_ctrl_new_std(&imx214->ctrls, &imx214_ctrl_ops,
10338c2ecf20Sopenharmony_ci					     V4L2_CID_EXPOSURE,
10348c2ecf20Sopenharmony_ci					     0, 3184, 1, 0x0c70);
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	imx214->unit_size = v4l2_ctrl_new_std_compound(&imx214->ctrls,
10378c2ecf20Sopenharmony_ci				NULL,
10388c2ecf20Sopenharmony_ci				V4L2_CID_UNIT_CELL_SIZE,
10398c2ecf20Sopenharmony_ci				v4l2_ctrl_ptr_create((void *)&unit_size));
10408c2ecf20Sopenharmony_ci	ret = imx214->ctrls.error;
10418c2ecf20Sopenharmony_ci	if (ret) {
10428c2ecf20Sopenharmony_ci		dev_err(&client->dev, "%s control init failed (%d)\n",
10438c2ecf20Sopenharmony_ci			__func__, ret);
10448c2ecf20Sopenharmony_ci		goto free_ctrl;
10458c2ecf20Sopenharmony_ci	}
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	imx214->sd.ctrl_handler = &imx214->ctrls;
10488c2ecf20Sopenharmony_ci	mutex_init(&imx214->mutex);
10498c2ecf20Sopenharmony_ci	imx214->ctrls.lock = &imx214->mutex;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	imx214->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
10528c2ecf20Sopenharmony_ci	imx214->pad.flags = MEDIA_PAD_FL_SOURCE;
10538c2ecf20Sopenharmony_ci	imx214->sd.dev = &client->dev;
10548c2ecf20Sopenharmony_ci	imx214->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	ret = media_entity_pads_init(&imx214->sd.entity, 1, &imx214->pad);
10578c2ecf20Sopenharmony_ci	if (ret < 0) {
10588c2ecf20Sopenharmony_ci		dev_err(dev, "could not register media entity\n");
10598c2ecf20Sopenharmony_ci		goto free_ctrl;
10608c2ecf20Sopenharmony_ci	}
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	imx214_entity_init_cfg(&imx214->sd, NULL);
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	ret = v4l2_async_register_subdev_sensor_common(&imx214->sd);
10658c2ecf20Sopenharmony_ci	if (ret < 0) {
10668c2ecf20Sopenharmony_ci		dev_err(dev, "could not register v4l2 device\n");
10678c2ecf20Sopenharmony_ci		goto free_entity;
10688c2ecf20Sopenharmony_ci	}
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	return 0;
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_cifree_entity:
10738c2ecf20Sopenharmony_ci	media_entity_cleanup(&imx214->sd.entity);
10748c2ecf20Sopenharmony_cifree_ctrl:
10758c2ecf20Sopenharmony_ci	mutex_destroy(&imx214->mutex);
10768c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_free(&imx214->ctrls);
10778c2ecf20Sopenharmony_ci	pm_runtime_disable(imx214->dev);
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	return ret;
10808c2ecf20Sopenharmony_ci}
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_cistatic int imx214_remove(struct i2c_client *client)
10838c2ecf20Sopenharmony_ci{
10848c2ecf20Sopenharmony_ci	struct v4l2_subdev *sd = i2c_get_clientdata(client);
10858c2ecf20Sopenharmony_ci	struct imx214 *imx214 = to_imx214(sd);
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	v4l2_async_unregister_subdev(&imx214->sd);
10888c2ecf20Sopenharmony_ci	media_entity_cleanup(&imx214->sd.entity);
10898c2ecf20Sopenharmony_ci	v4l2_ctrl_handler_free(&imx214->ctrls);
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci	pm_runtime_disable(&client->dev);
10928c2ecf20Sopenharmony_ci	pm_runtime_set_suspended(&client->dev);
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	mutex_destroy(&imx214->mutex);
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	return 0;
10978c2ecf20Sopenharmony_ci}
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_cistatic const struct of_device_id imx214_of_match[] = {
11008c2ecf20Sopenharmony_ci	{ .compatible = "sony,imx214" },
11018c2ecf20Sopenharmony_ci	{ }
11028c2ecf20Sopenharmony_ci};
11038c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, imx214_of_match);
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_cistatic const struct dev_pm_ops imx214_pm_ops = {
11068c2ecf20Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(imx214_suspend, imx214_resume)
11078c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(imx214_power_off, imx214_power_on, NULL)
11088c2ecf20Sopenharmony_ci};
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_cistatic struct i2c_driver imx214_i2c_driver = {
11118c2ecf20Sopenharmony_ci	.driver = {
11128c2ecf20Sopenharmony_ci		.of_match_table = imx214_of_match,
11138c2ecf20Sopenharmony_ci		.pm = &imx214_pm_ops,
11148c2ecf20Sopenharmony_ci		.name  = "imx214",
11158c2ecf20Sopenharmony_ci	},
11168c2ecf20Sopenharmony_ci	.probe_new  = imx214_probe,
11178c2ecf20Sopenharmony_ci	.remove = imx214_remove,
11188c2ecf20Sopenharmony_ci};
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_cimodule_i2c_driver(imx214_i2c_driver);
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Sony IMX214 Camera driver");
11238c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ricardo Ribalda <ribalda@kernel.org>");
11248c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
1125