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