18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Sony IMX290 CMOS Image Sensor Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2019 FRAMOS GmbH. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2019 Linaro Ltd. 88c2ecf20Sopenharmony_ci * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/clk.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 148c2ecf20Sopenharmony_ci#include <linux/i2c.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 178c2ecf20Sopenharmony_ci#include <linux/regmap.h> 188c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 198c2ecf20Sopenharmony_ci#include <media/media-entity.h> 208c2ecf20Sopenharmony_ci#include <media/v4l2-ctrls.h> 218c2ecf20Sopenharmony_ci#include <media/v4l2-device.h> 228c2ecf20Sopenharmony_ci#include <media/v4l2-fwnode.h> 238c2ecf20Sopenharmony_ci#include <media/v4l2-subdev.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define IMX290_STANDBY 0x3000 268c2ecf20Sopenharmony_ci#define IMX290_REGHOLD 0x3001 278c2ecf20Sopenharmony_ci#define IMX290_XMSTA 0x3002 288c2ecf20Sopenharmony_ci#define IMX290_FR_FDG_SEL 0x3009 298c2ecf20Sopenharmony_ci#define IMX290_BLKLEVEL_LOW 0x300a 308c2ecf20Sopenharmony_ci#define IMX290_BLKLEVEL_HIGH 0x300b 318c2ecf20Sopenharmony_ci#define IMX290_GAIN 0x3014 328c2ecf20Sopenharmony_ci#define IMX290_HMAX_LOW 0x301c 338c2ecf20Sopenharmony_ci#define IMX290_HMAX_HIGH 0x301d 348c2ecf20Sopenharmony_ci#define IMX290_PGCTRL 0x308c 358c2ecf20Sopenharmony_ci#define IMX290_PHY_LANE_NUM 0x3407 368c2ecf20Sopenharmony_ci#define IMX290_CSI_LANE_MODE 0x3443 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define IMX290_PGCTRL_REGEN BIT(0) 398c2ecf20Sopenharmony_ci#define IMX290_PGCTRL_THRU BIT(1) 408c2ecf20Sopenharmony_ci#define IMX290_PGCTRL_MODE(n) ((n) << 4) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic const char * const imx290_supply_name[] = { 438c2ecf20Sopenharmony_ci "vdda", 448c2ecf20Sopenharmony_ci "vddd", 458c2ecf20Sopenharmony_ci "vdddo", 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define IMX290_NUM_SUPPLIES ARRAY_SIZE(imx290_supply_name) 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistruct imx290_regval { 518c2ecf20Sopenharmony_ci u16 reg; 528c2ecf20Sopenharmony_ci u8 val; 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistruct imx290_mode { 568c2ecf20Sopenharmony_ci u32 width; 578c2ecf20Sopenharmony_ci u32 height; 588c2ecf20Sopenharmony_ci u32 hmax; 598c2ecf20Sopenharmony_ci u8 link_freq_index; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci const struct imx290_regval *data; 628c2ecf20Sopenharmony_ci u32 data_size; 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistruct imx290 { 668c2ecf20Sopenharmony_ci struct device *dev; 678c2ecf20Sopenharmony_ci struct clk *xclk; 688c2ecf20Sopenharmony_ci struct regmap *regmap; 698c2ecf20Sopenharmony_ci u8 nlanes; 708c2ecf20Sopenharmony_ci u8 bpp; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci struct v4l2_subdev sd; 738c2ecf20Sopenharmony_ci struct media_pad pad; 748c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt current_format; 758c2ecf20Sopenharmony_ci const struct imx290_mode *current_mode; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci struct regulator_bulk_data supplies[IMX290_NUM_SUPPLIES]; 788c2ecf20Sopenharmony_ci struct gpio_desc *rst_gpio; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler ctrls; 818c2ecf20Sopenharmony_ci struct v4l2_ctrl *link_freq; 828c2ecf20Sopenharmony_ci struct v4l2_ctrl *pixel_rate; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci struct mutex lock; 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistruct imx290_pixfmt { 888c2ecf20Sopenharmony_ci u32 code; 898c2ecf20Sopenharmony_ci u8 bpp; 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic const struct imx290_pixfmt imx290_formats[] = { 938c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SRGGB10_1X10, 10 }, 948c2ecf20Sopenharmony_ci { MEDIA_BUS_FMT_SRGGB12_1X12, 12 }, 958c2ecf20Sopenharmony_ci}; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic const struct regmap_config imx290_regmap_config = { 988c2ecf20Sopenharmony_ci .reg_bits = 16, 998c2ecf20Sopenharmony_ci .val_bits = 8, 1008c2ecf20Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 1018c2ecf20Sopenharmony_ci}; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic const char * const imx290_test_pattern_menu[] = { 1048c2ecf20Sopenharmony_ci "Disabled", 1058c2ecf20Sopenharmony_ci "Sequence Pattern 1", 1068c2ecf20Sopenharmony_ci "Horizontal Color-bar Chart", 1078c2ecf20Sopenharmony_ci "Vertical Color-bar Chart", 1088c2ecf20Sopenharmony_ci "Sequence Pattern 2", 1098c2ecf20Sopenharmony_ci "Gradation Pattern 1", 1108c2ecf20Sopenharmony_ci "Gradation Pattern 2", 1118c2ecf20Sopenharmony_ci "000/555h Toggle Pattern", 1128c2ecf20Sopenharmony_ci}; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic const struct imx290_regval imx290_global_init_settings[] = { 1158c2ecf20Sopenharmony_ci { 0x3007, 0x00 }, 1168c2ecf20Sopenharmony_ci { 0x3018, 0x65 }, 1178c2ecf20Sopenharmony_ci { 0x3019, 0x04 }, 1188c2ecf20Sopenharmony_ci { 0x301a, 0x00 }, 1198c2ecf20Sopenharmony_ci { 0x3444, 0x20 }, 1208c2ecf20Sopenharmony_ci { 0x3445, 0x25 }, 1218c2ecf20Sopenharmony_ci { 0x303a, 0x0c }, 1228c2ecf20Sopenharmony_ci { 0x3040, 0x00 }, 1238c2ecf20Sopenharmony_ci { 0x3041, 0x00 }, 1248c2ecf20Sopenharmony_ci { 0x303c, 0x00 }, 1258c2ecf20Sopenharmony_ci { 0x303d, 0x00 }, 1268c2ecf20Sopenharmony_ci { 0x3042, 0x9c }, 1278c2ecf20Sopenharmony_ci { 0x3043, 0x07 }, 1288c2ecf20Sopenharmony_ci { 0x303e, 0x49 }, 1298c2ecf20Sopenharmony_ci { 0x303f, 0x04 }, 1308c2ecf20Sopenharmony_ci { 0x304b, 0x0a }, 1318c2ecf20Sopenharmony_ci { 0x300f, 0x00 }, 1328c2ecf20Sopenharmony_ci { 0x3010, 0x21 }, 1338c2ecf20Sopenharmony_ci { 0x3012, 0x64 }, 1348c2ecf20Sopenharmony_ci { 0x3016, 0x09 }, 1358c2ecf20Sopenharmony_ci { 0x3070, 0x02 }, 1368c2ecf20Sopenharmony_ci { 0x3071, 0x11 }, 1378c2ecf20Sopenharmony_ci { 0x309b, 0x10 }, 1388c2ecf20Sopenharmony_ci { 0x309c, 0x22 }, 1398c2ecf20Sopenharmony_ci { 0x30a2, 0x02 }, 1408c2ecf20Sopenharmony_ci { 0x30a6, 0x20 }, 1418c2ecf20Sopenharmony_ci { 0x30a8, 0x20 }, 1428c2ecf20Sopenharmony_ci { 0x30aa, 0x20 }, 1438c2ecf20Sopenharmony_ci { 0x30ac, 0x20 }, 1448c2ecf20Sopenharmony_ci { 0x30b0, 0x43 }, 1458c2ecf20Sopenharmony_ci { 0x3119, 0x9e }, 1468c2ecf20Sopenharmony_ci { 0x311c, 0x1e }, 1478c2ecf20Sopenharmony_ci { 0x311e, 0x08 }, 1488c2ecf20Sopenharmony_ci { 0x3128, 0x05 }, 1498c2ecf20Sopenharmony_ci { 0x313d, 0x83 }, 1508c2ecf20Sopenharmony_ci { 0x3150, 0x03 }, 1518c2ecf20Sopenharmony_ci { 0x317e, 0x00 }, 1528c2ecf20Sopenharmony_ci { 0x32b8, 0x50 }, 1538c2ecf20Sopenharmony_ci { 0x32b9, 0x10 }, 1548c2ecf20Sopenharmony_ci { 0x32ba, 0x00 }, 1558c2ecf20Sopenharmony_ci { 0x32bb, 0x04 }, 1568c2ecf20Sopenharmony_ci { 0x32c8, 0x50 }, 1578c2ecf20Sopenharmony_ci { 0x32c9, 0x10 }, 1588c2ecf20Sopenharmony_ci { 0x32ca, 0x00 }, 1598c2ecf20Sopenharmony_ci { 0x32cb, 0x04 }, 1608c2ecf20Sopenharmony_ci { 0x332c, 0xd3 }, 1618c2ecf20Sopenharmony_ci { 0x332d, 0x10 }, 1628c2ecf20Sopenharmony_ci { 0x332e, 0x0d }, 1638c2ecf20Sopenharmony_ci { 0x3358, 0x06 }, 1648c2ecf20Sopenharmony_ci { 0x3359, 0xe1 }, 1658c2ecf20Sopenharmony_ci { 0x335a, 0x11 }, 1668c2ecf20Sopenharmony_ci { 0x3360, 0x1e }, 1678c2ecf20Sopenharmony_ci { 0x3361, 0x61 }, 1688c2ecf20Sopenharmony_ci { 0x3362, 0x10 }, 1698c2ecf20Sopenharmony_ci { 0x33b0, 0x50 }, 1708c2ecf20Sopenharmony_ci { 0x33b2, 0x1a }, 1718c2ecf20Sopenharmony_ci { 0x33b3, 0x04 }, 1728c2ecf20Sopenharmony_ci}; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic const struct imx290_regval imx290_1080p_settings[] = { 1758c2ecf20Sopenharmony_ci /* mode settings */ 1768c2ecf20Sopenharmony_ci { 0x3007, 0x00 }, 1778c2ecf20Sopenharmony_ci { 0x303a, 0x0c }, 1788c2ecf20Sopenharmony_ci { 0x3414, 0x0a }, 1798c2ecf20Sopenharmony_ci { 0x3472, 0x80 }, 1808c2ecf20Sopenharmony_ci { 0x3473, 0x07 }, 1818c2ecf20Sopenharmony_ci { 0x3418, 0x38 }, 1828c2ecf20Sopenharmony_ci { 0x3419, 0x04 }, 1838c2ecf20Sopenharmony_ci { 0x3012, 0x64 }, 1848c2ecf20Sopenharmony_ci { 0x3013, 0x00 }, 1858c2ecf20Sopenharmony_ci { 0x305c, 0x18 }, 1868c2ecf20Sopenharmony_ci { 0x305d, 0x03 }, 1878c2ecf20Sopenharmony_ci { 0x305e, 0x20 }, 1888c2ecf20Sopenharmony_ci { 0x305f, 0x01 }, 1898c2ecf20Sopenharmony_ci { 0x315e, 0x1a }, 1908c2ecf20Sopenharmony_ci { 0x3164, 0x1a }, 1918c2ecf20Sopenharmony_ci { 0x3480, 0x49 }, 1928c2ecf20Sopenharmony_ci /* data rate settings */ 1938c2ecf20Sopenharmony_ci { 0x3405, 0x10 }, 1948c2ecf20Sopenharmony_ci { 0x3446, 0x57 }, 1958c2ecf20Sopenharmony_ci { 0x3447, 0x00 }, 1968c2ecf20Sopenharmony_ci { 0x3448, 0x37 }, 1978c2ecf20Sopenharmony_ci { 0x3449, 0x00 }, 1988c2ecf20Sopenharmony_ci { 0x344a, 0x1f }, 1998c2ecf20Sopenharmony_ci { 0x344b, 0x00 }, 2008c2ecf20Sopenharmony_ci { 0x344c, 0x1f }, 2018c2ecf20Sopenharmony_ci { 0x344d, 0x00 }, 2028c2ecf20Sopenharmony_ci { 0x344e, 0x1f }, 2038c2ecf20Sopenharmony_ci { 0x344f, 0x00 }, 2048c2ecf20Sopenharmony_ci { 0x3450, 0x77 }, 2058c2ecf20Sopenharmony_ci { 0x3451, 0x00 }, 2068c2ecf20Sopenharmony_ci { 0x3452, 0x1f }, 2078c2ecf20Sopenharmony_ci { 0x3453, 0x00 }, 2088c2ecf20Sopenharmony_ci { 0x3454, 0x17 }, 2098c2ecf20Sopenharmony_ci { 0x3455, 0x00 }, 2108c2ecf20Sopenharmony_ci}; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic const struct imx290_regval imx290_720p_settings[] = { 2138c2ecf20Sopenharmony_ci /* mode settings */ 2148c2ecf20Sopenharmony_ci { 0x3007, 0x10 }, 2158c2ecf20Sopenharmony_ci { 0x303a, 0x06 }, 2168c2ecf20Sopenharmony_ci { 0x3414, 0x04 }, 2178c2ecf20Sopenharmony_ci { 0x3472, 0x00 }, 2188c2ecf20Sopenharmony_ci { 0x3473, 0x05 }, 2198c2ecf20Sopenharmony_ci { 0x3418, 0xd0 }, 2208c2ecf20Sopenharmony_ci { 0x3419, 0x02 }, 2218c2ecf20Sopenharmony_ci { 0x3012, 0x64 }, 2228c2ecf20Sopenharmony_ci { 0x3013, 0x00 }, 2238c2ecf20Sopenharmony_ci { 0x305c, 0x20 }, 2248c2ecf20Sopenharmony_ci { 0x305d, 0x00 }, 2258c2ecf20Sopenharmony_ci { 0x305e, 0x20 }, 2268c2ecf20Sopenharmony_ci { 0x305f, 0x01 }, 2278c2ecf20Sopenharmony_ci { 0x315e, 0x1a }, 2288c2ecf20Sopenharmony_ci { 0x3164, 0x1a }, 2298c2ecf20Sopenharmony_ci { 0x3480, 0x49 }, 2308c2ecf20Sopenharmony_ci /* data rate settings */ 2318c2ecf20Sopenharmony_ci { 0x3405, 0x10 }, 2328c2ecf20Sopenharmony_ci { 0x3446, 0x4f }, 2338c2ecf20Sopenharmony_ci { 0x3447, 0x00 }, 2348c2ecf20Sopenharmony_ci { 0x3448, 0x2f }, 2358c2ecf20Sopenharmony_ci { 0x3449, 0x00 }, 2368c2ecf20Sopenharmony_ci { 0x344a, 0x17 }, 2378c2ecf20Sopenharmony_ci { 0x344b, 0x00 }, 2388c2ecf20Sopenharmony_ci { 0x344c, 0x17 }, 2398c2ecf20Sopenharmony_ci { 0x344d, 0x00 }, 2408c2ecf20Sopenharmony_ci { 0x344e, 0x17 }, 2418c2ecf20Sopenharmony_ci { 0x344f, 0x00 }, 2428c2ecf20Sopenharmony_ci { 0x3450, 0x57 }, 2438c2ecf20Sopenharmony_ci { 0x3451, 0x00 }, 2448c2ecf20Sopenharmony_ci { 0x3452, 0x17 }, 2458c2ecf20Sopenharmony_ci { 0x3453, 0x00 }, 2468c2ecf20Sopenharmony_ci { 0x3454, 0x17 }, 2478c2ecf20Sopenharmony_ci { 0x3455, 0x00 }, 2488c2ecf20Sopenharmony_ci}; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic const struct imx290_regval imx290_10bit_settings[] = { 2518c2ecf20Sopenharmony_ci { 0x3005, 0x00}, 2528c2ecf20Sopenharmony_ci { 0x3046, 0x00}, 2538c2ecf20Sopenharmony_ci { 0x3129, 0x1d}, 2548c2ecf20Sopenharmony_ci { 0x317c, 0x12}, 2558c2ecf20Sopenharmony_ci { 0x31ec, 0x37}, 2568c2ecf20Sopenharmony_ci { 0x3441, 0x0a}, 2578c2ecf20Sopenharmony_ci { 0x3442, 0x0a}, 2588c2ecf20Sopenharmony_ci { 0x300a, 0x3c}, 2598c2ecf20Sopenharmony_ci { 0x300b, 0x00}, 2608c2ecf20Sopenharmony_ci}; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic const struct imx290_regval imx290_12bit_settings[] = { 2638c2ecf20Sopenharmony_ci { 0x3005, 0x01 }, 2648c2ecf20Sopenharmony_ci { 0x3046, 0x01 }, 2658c2ecf20Sopenharmony_ci { 0x3129, 0x00 }, 2668c2ecf20Sopenharmony_ci { 0x317c, 0x00 }, 2678c2ecf20Sopenharmony_ci { 0x31ec, 0x0e }, 2688c2ecf20Sopenharmony_ci { 0x3441, 0x0c }, 2698c2ecf20Sopenharmony_ci { 0x3442, 0x0c }, 2708c2ecf20Sopenharmony_ci { 0x300a, 0xf0 }, 2718c2ecf20Sopenharmony_ci { 0x300b, 0x00 }, 2728c2ecf20Sopenharmony_ci}; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci/* supported link frequencies */ 2758c2ecf20Sopenharmony_ci#define FREQ_INDEX_1080P 0 2768c2ecf20Sopenharmony_ci#define FREQ_INDEX_720P 1 2778c2ecf20Sopenharmony_cistatic const s64 imx290_link_freq_2lanes[] = { 2788c2ecf20Sopenharmony_ci [FREQ_INDEX_1080P] = 445500000, 2798c2ecf20Sopenharmony_ci [FREQ_INDEX_720P] = 297000000, 2808c2ecf20Sopenharmony_ci}; 2818c2ecf20Sopenharmony_cistatic const s64 imx290_link_freq_4lanes[] = { 2828c2ecf20Sopenharmony_ci [FREQ_INDEX_1080P] = 222750000, 2838c2ecf20Sopenharmony_ci [FREQ_INDEX_720P] = 148500000, 2848c2ecf20Sopenharmony_ci}; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci/* 2878c2ecf20Sopenharmony_ci * In this function and in the similar ones below We rely on imx290_probe() 2888c2ecf20Sopenharmony_ci * to ensure that nlanes is either 2 or 4. 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_cistatic inline const s64 *imx290_link_freqs_ptr(const struct imx290 *imx290) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci if (imx290->nlanes == 2) 2938c2ecf20Sopenharmony_ci return imx290_link_freq_2lanes; 2948c2ecf20Sopenharmony_ci else 2958c2ecf20Sopenharmony_ci return imx290_link_freq_4lanes; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic inline int imx290_link_freqs_num(const struct imx290 *imx290) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci if (imx290->nlanes == 2) 3018c2ecf20Sopenharmony_ci return ARRAY_SIZE(imx290_link_freq_2lanes); 3028c2ecf20Sopenharmony_ci else 3038c2ecf20Sopenharmony_ci return ARRAY_SIZE(imx290_link_freq_4lanes); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci/* Mode configs */ 3078c2ecf20Sopenharmony_cistatic const struct imx290_mode imx290_modes_2lanes[] = { 3088c2ecf20Sopenharmony_ci { 3098c2ecf20Sopenharmony_ci .width = 1920, 3108c2ecf20Sopenharmony_ci .height = 1080, 3118c2ecf20Sopenharmony_ci .hmax = 0x1130, 3128c2ecf20Sopenharmony_ci .link_freq_index = FREQ_INDEX_1080P, 3138c2ecf20Sopenharmony_ci .data = imx290_1080p_settings, 3148c2ecf20Sopenharmony_ci .data_size = ARRAY_SIZE(imx290_1080p_settings), 3158c2ecf20Sopenharmony_ci }, 3168c2ecf20Sopenharmony_ci { 3178c2ecf20Sopenharmony_ci .width = 1280, 3188c2ecf20Sopenharmony_ci .height = 720, 3198c2ecf20Sopenharmony_ci .hmax = 0x19c8, 3208c2ecf20Sopenharmony_ci .link_freq_index = FREQ_INDEX_720P, 3218c2ecf20Sopenharmony_ci .data = imx290_720p_settings, 3228c2ecf20Sopenharmony_ci .data_size = ARRAY_SIZE(imx290_720p_settings), 3238c2ecf20Sopenharmony_ci }, 3248c2ecf20Sopenharmony_ci}; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic const struct imx290_mode imx290_modes_4lanes[] = { 3278c2ecf20Sopenharmony_ci { 3288c2ecf20Sopenharmony_ci .width = 1920, 3298c2ecf20Sopenharmony_ci .height = 1080, 3308c2ecf20Sopenharmony_ci .hmax = 0x0898, 3318c2ecf20Sopenharmony_ci .link_freq_index = FREQ_INDEX_1080P, 3328c2ecf20Sopenharmony_ci .data = imx290_1080p_settings, 3338c2ecf20Sopenharmony_ci .data_size = ARRAY_SIZE(imx290_1080p_settings), 3348c2ecf20Sopenharmony_ci }, 3358c2ecf20Sopenharmony_ci { 3368c2ecf20Sopenharmony_ci .width = 1280, 3378c2ecf20Sopenharmony_ci .height = 720, 3388c2ecf20Sopenharmony_ci .hmax = 0x0ce4, 3398c2ecf20Sopenharmony_ci .link_freq_index = FREQ_INDEX_720P, 3408c2ecf20Sopenharmony_ci .data = imx290_720p_settings, 3418c2ecf20Sopenharmony_ci .data_size = ARRAY_SIZE(imx290_720p_settings), 3428c2ecf20Sopenharmony_ci }, 3438c2ecf20Sopenharmony_ci}; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic inline const struct imx290_mode *imx290_modes_ptr(const struct imx290 *imx290) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci if (imx290->nlanes == 2) 3488c2ecf20Sopenharmony_ci return imx290_modes_2lanes; 3498c2ecf20Sopenharmony_ci else 3508c2ecf20Sopenharmony_ci return imx290_modes_4lanes; 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic inline int imx290_modes_num(const struct imx290 *imx290) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci if (imx290->nlanes == 2) 3568c2ecf20Sopenharmony_ci return ARRAY_SIZE(imx290_modes_2lanes); 3578c2ecf20Sopenharmony_ci else 3588c2ecf20Sopenharmony_ci return ARRAY_SIZE(imx290_modes_4lanes); 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic inline struct imx290 *to_imx290(struct v4l2_subdev *_sd) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci return container_of(_sd, struct imx290, sd); 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic inline int imx290_read_reg(struct imx290 *imx290, u16 addr, u8 *value) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci unsigned int regval; 3698c2ecf20Sopenharmony_ci int ret; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci ret = regmap_read(imx290->regmap, addr, ®val); 3728c2ecf20Sopenharmony_ci if (ret) { 3738c2ecf20Sopenharmony_ci dev_err(imx290->dev, "I2C read failed for addr: %x\n", addr); 3748c2ecf20Sopenharmony_ci return ret; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci *value = regval & 0xff; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci return 0; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic int imx290_write_reg(struct imx290 *imx290, u16 addr, u8 value) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci int ret; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci ret = regmap_write(imx290->regmap, addr, value); 3878c2ecf20Sopenharmony_ci if (ret) { 3888c2ecf20Sopenharmony_ci dev_err(imx290->dev, "I2C write failed for addr: %x\n", addr); 3898c2ecf20Sopenharmony_ci return ret; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci return ret; 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic int imx290_set_register_array(struct imx290 *imx290, 3968c2ecf20Sopenharmony_ci const struct imx290_regval *settings, 3978c2ecf20Sopenharmony_ci unsigned int num_settings) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci unsigned int i; 4008c2ecf20Sopenharmony_ci int ret; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci for (i = 0; i < num_settings; ++i, ++settings) { 4038c2ecf20Sopenharmony_ci ret = imx290_write_reg(imx290, settings->reg, settings->val); 4048c2ecf20Sopenharmony_ci if (ret < 0) 4058c2ecf20Sopenharmony_ci return ret; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci /* Provide 10ms settle time */ 4098c2ecf20Sopenharmony_ci usleep_range(10000, 11000); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci return 0; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic int imx290_write_buffered_reg(struct imx290 *imx290, u16 address_low, 4158c2ecf20Sopenharmony_ci u8 nr_regs, u32 value) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci unsigned int i; 4188c2ecf20Sopenharmony_ci int ret; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci ret = imx290_write_reg(imx290, IMX290_REGHOLD, 0x01); 4218c2ecf20Sopenharmony_ci if (ret) { 4228c2ecf20Sopenharmony_ci dev_err(imx290->dev, "Error setting hold register\n"); 4238c2ecf20Sopenharmony_ci return ret; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci for (i = 0; i < nr_regs; i++) { 4278c2ecf20Sopenharmony_ci ret = imx290_write_reg(imx290, address_low + i, 4288c2ecf20Sopenharmony_ci (u8)(value >> (i * 8))); 4298c2ecf20Sopenharmony_ci if (ret) { 4308c2ecf20Sopenharmony_ci dev_err(imx290->dev, "Error writing buffered registers\n"); 4318c2ecf20Sopenharmony_ci return ret; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci ret = imx290_write_reg(imx290, IMX290_REGHOLD, 0x00); 4368c2ecf20Sopenharmony_ci if (ret) { 4378c2ecf20Sopenharmony_ci dev_err(imx290->dev, "Error setting hold register\n"); 4388c2ecf20Sopenharmony_ci return ret; 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci return ret; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic int imx290_set_gain(struct imx290 *imx290, u32 value) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci int ret; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci ret = imx290_write_buffered_reg(imx290, IMX290_GAIN, 1, value); 4498c2ecf20Sopenharmony_ci if (ret) 4508c2ecf20Sopenharmony_ci dev_err(imx290->dev, "Unable to write gain\n"); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci return ret; 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci/* Stop streaming */ 4568c2ecf20Sopenharmony_cistatic int imx290_stop_streaming(struct imx290 *imx290) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci int ret; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci ret = imx290_write_reg(imx290, IMX290_STANDBY, 0x01); 4618c2ecf20Sopenharmony_ci if (ret < 0) 4628c2ecf20Sopenharmony_ci return ret; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci msleep(30); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci return imx290_write_reg(imx290, IMX290_XMSTA, 0x01); 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic int imx290_set_ctrl(struct v4l2_ctrl *ctrl) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci struct imx290 *imx290 = container_of(ctrl->handler, 4728c2ecf20Sopenharmony_ci struct imx290, ctrls); 4738c2ecf20Sopenharmony_ci int ret = 0; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* V4L2 controls values will be applied only when power is already up */ 4768c2ecf20Sopenharmony_ci if (!pm_runtime_get_if_in_use(imx290->dev)) 4778c2ecf20Sopenharmony_ci return 0; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci switch (ctrl->id) { 4808c2ecf20Sopenharmony_ci case V4L2_CID_GAIN: 4818c2ecf20Sopenharmony_ci ret = imx290_set_gain(imx290, ctrl->val); 4828c2ecf20Sopenharmony_ci break; 4838c2ecf20Sopenharmony_ci case V4L2_CID_TEST_PATTERN: 4848c2ecf20Sopenharmony_ci if (ctrl->val) { 4858c2ecf20Sopenharmony_ci imx290_write_reg(imx290, IMX290_BLKLEVEL_LOW, 0x00); 4868c2ecf20Sopenharmony_ci imx290_write_reg(imx290, IMX290_BLKLEVEL_HIGH, 0x00); 4878c2ecf20Sopenharmony_ci usleep_range(10000, 11000); 4888c2ecf20Sopenharmony_ci imx290_write_reg(imx290, IMX290_PGCTRL, 4898c2ecf20Sopenharmony_ci (u8)(IMX290_PGCTRL_REGEN | 4908c2ecf20Sopenharmony_ci IMX290_PGCTRL_THRU | 4918c2ecf20Sopenharmony_ci IMX290_PGCTRL_MODE(ctrl->val))); 4928c2ecf20Sopenharmony_ci } else { 4938c2ecf20Sopenharmony_ci imx290_write_reg(imx290, IMX290_PGCTRL, 0x00); 4948c2ecf20Sopenharmony_ci usleep_range(10000, 11000); 4958c2ecf20Sopenharmony_ci if (imx290->bpp == 10) 4968c2ecf20Sopenharmony_ci imx290_write_reg(imx290, IMX290_BLKLEVEL_LOW, 4978c2ecf20Sopenharmony_ci 0x3c); 4988c2ecf20Sopenharmony_ci else /* 12 bits per pixel */ 4998c2ecf20Sopenharmony_ci imx290_write_reg(imx290, IMX290_BLKLEVEL_LOW, 5008c2ecf20Sopenharmony_ci 0xf0); 5018c2ecf20Sopenharmony_ci imx290_write_reg(imx290, IMX290_BLKLEVEL_HIGH, 0x00); 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci break; 5048c2ecf20Sopenharmony_ci default: 5058c2ecf20Sopenharmony_ci ret = -EINVAL; 5068c2ecf20Sopenharmony_ci break; 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci pm_runtime_put(imx290->dev); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci return ret; 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops imx290_ctrl_ops = { 5158c2ecf20Sopenharmony_ci .s_ctrl = imx290_set_ctrl, 5168c2ecf20Sopenharmony_ci}; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic int imx290_enum_mbus_code(struct v4l2_subdev *sd, 5198c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 5208c2ecf20Sopenharmony_ci struct v4l2_subdev_mbus_code_enum *code) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci if (code->index >= ARRAY_SIZE(imx290_formats)) 5238c2ecf20Sopenharmony_ci return -EINVAL; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci code->code = imx290_formats[code->index].code; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci return 0; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic int imx290_enum_frame_size(struct v4l2_subdev *sd, 5318c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 5328c2ecf20Sopenharmony_ci struct v4l2_subdev_frame_size_enum *fse) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci const struct imx290 *imx290 = to_imx290(sd); 5358c2ecf20Sopenharmony_ci const struct imx290_mode *imx290_modes = imx290_modes_ptr(imx290); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci if ((fse->code != imx290_formats[0].code) && 5388c2ecf20Sopenharmony_ci (fse->code != imx290_formats[1].code)) 5398c2ecf20Sopenharmony_ci return -EINVAL; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci if (fse->index >= imx290_modes_num(imx290)) 5428c2ecf20Sopenharmony_ci return -EINVAL; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci fse->min_width = imx290_modes[fse->index].width; 5458c2ecf20Sopenharmony_ci fse->max_width = imx290_modes[fse->index].width; 5468c2ecf20Sopenharmony_ci fse->min_height = imx290_modes[fse->index].height; 5478c2ecf20Sopenharmony_ci fse->max_height = imx290_modes[fse->index].height; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci return 0; 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cistatic int imx290_get_fmt(struct v4l2_subdev *sd, 5538c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 5548c2ecf20Sopenharmony_ci struct v4l2_subdev_format *fmt) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci struct imx290 *imx290 = to_imx290(sd); 5578c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *framefmt; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci mutex_lock(&imx290->lock); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) 5628c2ecf20Sopenharmony_ci framefmt = v4l2_subdev_get_try_format(&imx290->sd, cfg, 5638c2ecf20Sopenharmony_ci fmt->pad); 5648c2ecf20Sopenharmony_ci else 5658c2ecf20Sopenharmony_ci framefmt = &imx290->current_format; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci fmt->format = *framefmt; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci mutex_unlock(&imx290->lock); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci return 0; 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistatic inline u8 imx290_get_link_freq_index(struct imx290 *imx290) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci return imx290->current_mode->link_freq_index; 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistatic s64 imx290_get_link_freq(struct imx290 *imx290) 5808c2ecf20Sopenharmony_ci{ 5818c2ecf20Sopenharmony_ci u8 index = imx290_get_link_freq_index(imx290); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci return *(imx290_link_freqs_ptr(imx290) + index); 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic u64 imx290_calc_pixel_rate(struct imx290 *imx290) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci s64 link_freq = imx290_get_link_freq(imx290); 5898c2ecf20Sopenharmony_ci u8 nlanes = imx290->nlanes; 5908c2ecf20Sopenharmony_ci u64 pixel_rate; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* pixel rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ 5938c2ecf20Sopenharmony_ci pixel_rate = link_freq * 2 * nlanes; 5948c2ecf20Sopenharmony_ci do_div(pixel_rate, imx290->bpp); 5958c2ecf20Sopenharmony_ci return pixel_rate; 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistatic int imx290_set_fmt(struct v4l2_subdev *sd, 5998c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 6008c2ecf20Sopenharmony_ci struct v4l2_subdev_format *fmt) 6018c2ecf20Sopenharmony_ci{ 6028c2ecf20Sopenharmony_ci struct imx290 *imx290 = to_imx290(sd); 6038c2ecf20Sopenharmony_ci const struct imx290_mode *mode; 6048c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *format; 6058c2ecf20Sopenharmony_ci unsigned int i; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci mutex_lock(&imx290->lock); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci mode = v4l2_find_nearest_size(imx290_modes_ptr(imx290), 6108c2ecf20Sopenharmony_ci imx290_modes_num(imx290), width, height, 6118c2ecf20Sopenharmony_ci fmt->format.width, fmt->format.height); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci fmt->format.width = mode->width; 6148c2ecf20Sopenharmony_ci fmt->format.height = mode->height; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(imx290_formats); i++) 6178c2ecf20Sopenharmony_ci if (imx290_formats[i].code == fmt->format.code) 6188c2ecf20Sopenharmony_ci break; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci if (i >= ARRAY_SIZE(imx290_formats)) 6218c2ecf20Sopenharmony_ci i = 0; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci fmt->format.code = imx290_formats[i].code; 6248c2ecf20Sopenharmony_ci fmt->format.field = V4L2_FIELD_NONE; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { 6278c2ecf20Sopenharmony_ci format = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); 6288c2ecf20Sopenharmony_ci } else { 6298c2ecf20Sopenharmony_ci format = &imx290->current_format; 6308c2ecf20Sopenharmony_ci imx290->current_mode = mode; 6318c2ecf20Sopenharmony_ci imx290->bpp = imx290_formats[i].bpp; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci if (imx290->link_freq) 6348c2ecf20Sopenharmony_ci __v4l2_ctrl_s_ctrl(imx290->link_freq, 6358c2ecf20Sopenharmony_ci imx290_get_link_freq_index(imx290)); 6368c2ecf20Sopenharmony_ci if (imx290->pixel_rate) 6378c2ecf20Sopenharmony_ci __v4l2_ctrl_s_ctrl_int64(imx290->pixel_rate, 6388c2ecf20Sopenharmony_ci imx290_calc_pixel_rate(imx290)); 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci *format = fmt->format; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci mutex_unlock(&imx290->lock); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci return 0; 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_cistatic int imx290_entity_init_cfg(struct v4l2_subdev *subdev, 6498c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg) 6508c2ecf20Sopenharmony_ci{ 6518c2ecf20Sopenharmony_ci struct v4l2_subdev_format fmt = { 0 }; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci fmt.which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; 6548c2ecf20Sopenharmony_ci fmt.format.width = 1920; 6558c2ecf20Sopenharmony_ci fmt.format.height = 1080; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci imx290_set_fmt(subdev, cfg, &fmt); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci return 0; 6608c2ecf20Sopenharmony_ci} 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic int imx290_write_current_format(struct imx290 *imx290) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci int ret; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci switch (imx290->current_format.code) { 6678c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SRGGB10_1X10: 6688c2ecf20Sopenharmony_ci ret = imx290_set_register_array(imx290, imx290_10bit_settings, 6698c2ecf20Sopenharmony_ci ARRAY_SIZE( 6708c2ecf20Sopenharmony_ci imx290_10bit_settings)); 6718c2ecf20Sopenharmony_ci if (ret < 0) { 6728c2ecf20Sopenharmony_ci dev_err(imx290->dev, "Could not set format registers\n"); 6738c2ecf20Sopenharmony_ci return ret; 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci break; 6768c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SRGGB12_1X12: 6778c2ecf20Sopenharmony_ci ret = imx290_set_register_array(imx290, imx290_12bit_settings, 6788c2ecf20Sopenharmony_ci ARRAY_SIZE( 6798c2ecf20Sopenharmony_ci imx290_12bit_settings)); 6808c2ecf20Sopenharmony_ci if (ret < 0) { 6818c2ecf20Sopenharmony_ci dev_err(imx290->dev, "Could not set format registers\n"); 6828c2ecf20Sopenharmony_ci return ret; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci break; 6858c2ecf20Sopenharmony_ci default: 6868c2ecf20Sopenharmony_ci dev_err(imx290->dev, "Unknown pixel format\n"); 6878c2ecf20Sopenharmony_ci return -EINVAL; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci return 0; 6918c2ecf20Sopenharmony_ci} 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_cistatic int imx290_set_hmax(struct imx290 *imx290, u32 val) 6948c2ecf20Sopenharmony_ci{ 6958c2ecf20Sopenharmony_ci int ret; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci ret = imx290_write_reg(imx290, IMX290_HMAX_LOW, (val & 0xff)); 6988c2ecf20Sopenharmony_ci if (ret) { 6998c2ecf20Sopenharmony_ci dev_err(imx290->dev, "Error setting HMAX register\n"); 7008c2ecf20Sopenharmony_ci return ret; 7018c2ecf20Sopenharmony_ci } 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci ret = imx290_write_reg(imx290, IMX290_HMAX_HIGH, ((val >> 8) & 0xff)); 7048c2ecf20Sopenharmony_ci if (ret) { 7058c2ecf20Sopenharmony_ci dev_err(imx290->dev, "Error setting HMAX register\n"); 7068c2ecf20Sopenharmony_ci return ret; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci return 0; 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci/* Start streaming */ 7138c2ecf20Sopenharmony_cistatic int imx290_start_streaming(struct imx290 *imx290) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci int ret; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci /* Set init register settings */ 7188c2ecf20Sopenharmony_ci ret = imx290_set_register_array(imx290, imx290_global_init_settings, 7198c2ecf20Sopenharmony_ci ARRAY_SIZE( 7208c2ecf20Sopenharmony_ci imx290_global_init_settings)); 7218c2ecf20Sopenharmony_ci if (ret < 0) { 7228c2ecf20Sopenharmony_ci dev_err(imx290->dev, "Could not set init registers\n"); 7238c2ecf20Sopenharmony_ci return ret; 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci /* Apply the register values related to current frame format */ 7278c2ecf20Sopenharmony_ci ret = imx290_write_current_format(imx290); 7288c2ecf20Sopenharmony_ci if (ret < 0) { 7298c2ecf20Sopenharmony_ci dev_err(imx290->dev, "Could not set frame format\n"); 7308c2ecf20Sopenharmony_ci return ret; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci /* Apply default values of current mode */ 7348c2ecf20Sopenharmony_ci ret = imx290_set_register_array(imx290, imx290->current_mode->data, 7358c2ecf20Sopenharmony_ci imx290->current_mode->data_size); 7368c2ecf20Sopenharmony_ci if (ret < 0) { 7378c2ecf20Sopenharmony_ci dev_err(imx290->dev, "Could not set current mode\n"); 7388c2ecf20Sopenharmony_ci return ret; 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci ret = imx290_set_hmax(imx290, imx290->current_mode->hmax); 7418c2ecf20Sopenharmony_ci if (ret < 0) 7428c2ecf20Sopenharmony_ci return ret; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci /* Apply customized values from user */ 7458c2ecf20Sopenharmony_ci ret = v4l2_ctrl_handler_setup(imx290->sd.ctrl_handler); 7468c2ecf20Sopenharmony_ci if (ret) { 7478c2ecf20Sopenharmony_ci dev_err(imx290->dev, "Could not sync v4l2 controls\n"); 7488c2ecf20Sopenharmony_ci return ret; 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci ret = imx290_write_reg(imx290, IMX290_STANDBY, 0x00); 7528c2ecf20Sopenharmony_ci if (ret < 0) 7538c2ecf20Sopenharmony_ci return ret; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci msleep(30); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci /* Start streaming */ 7588c2ecf20Sopenharmony_ci return imx290_write_reg(imx290, IMX290_XMSTA, 0x00); 7598c2ecf20Sopenharmony_ci} 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_cistatic int imx290_set_stream(struct v4l2_subdev *sd, int enable) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci struct imx290 *imx290 = to_imx290(sd); 7648c2ecf20Sopenharmony_ci int ret = 0; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci if (enable) { 7678c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(imx290->dev); 7688c2ecf20Sopenharmony_ci if (ret < 0) { 7698c2ecf20Sopenharmony_ci pm_runtime_put_noidle(imx290->dev); 7708c2ecf20Sopenharmony_ci goto unlock_and_return; 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci ret = imx290_start_streaming(imx290); 7748c2ecf20Sopenharmony_ci if (ret) { 7758c2ecf20Sopenharmony_ci dev_err(imx290->dev, "Start stream failed\n"); 7768c2ecf20Sopenharmony_ci pm_runtime_put(imx290->dev); 7778c2ecf20Sopenharmony_ci goto unlock_and_return; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci } else { 7808c2ecf20Sopenharmony_ci imx290_stop_streaming(imx290); 7818c2ecf20Sopenharmony_ci pm_runtime_put(imx290->dev); 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ciunlock_and_return: 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci return ret; 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_cistatic int imx290_get_regulators(struct device *dev, struct imx290 *imx290) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci unsigned int i; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci for (i = 0; i < IMX290_NUM_SUPPLIES; i++) 7948c2ecf20Sopenharmony_ci imx290->supplies[i].supply = imx290_supply_name[i]; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci return devm_regulator_bulk_get(dev, IMX290_NUM_SUPPLIES, 7978c2ecf20Sopenharmony_ci imx290->supplies); 7988c2ecf20Sopenharmony_ci} 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_cistatic int imx290_set_data_lanes(struct imx290 *imx290) 8018c2ecf20Sopenharmony_ci{ 8028c2ecf20Sopenharmony_ci int ret = 0, laneval, frsel; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci switch (imx290->nlanes) { 8058c2ecf20Sopenharmony_ci case 2: 8068c2ecf20Sopenharmony_ci laneval = 0x01; 8078c2ecf20Sopenharmony_ci frsel = 0x02; 8088c2ecf20Sopenharmony_ci break; 8098c2ecf20Sopenharmony_ci case 4: 8108c2ecf20Sopenharmony_ci laneval = 0x03; 8118c2ecf20Sopenharmony_ci frsel = 0x01; 8128c2ecf20Sopenharmony_ci break; 8138c2ecf20Sopenharmony_ci default: 8148c2ecf20Sopenharmony_ci /* 8158c2ecf20Sopenharmony_ci * We should never hit this since the data lane count is 8168c2ecf20Sopenharmony_ci * validated in probe itself 8178c2ecf20Sopenharmony_ci */ 8188c2ecf20Sopenharmony_ci dev_err(imx290->dev, "Lane configuration not supported\n"); 8198c2ecf20Sopenharmony_ci ret = -EINVAL; 8208c2ecf20Sopenharmony_ci goto exit; 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci ret = imx290_write_reg(imx290, IMX290_PHY_LANE_NUM, laneval); 8248c2ecf20Sopenharmony_ci if (ret) { 8258c2ecf20Sopenharmony_ci dev_err(imx290->dev, "Error setting Physical Lane number register\n"); 8268c2ecf20Sopenharmony_ci goto exit; 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci ret = imx290_write_reg(imx290, IMX290_CSI_LANE_MODE, laneval); 8308c2ecf20Sopenharmony_ci if (ret) { 8318c2ecf20Sopenharmony_ci dev_err(imx290->dev, "Error setting CSI Lane mode register\n"); 8328c2ecf20Sopenharmony_ci goto exit; 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci ret = imx290_write_reg(imx290, IMX290_FR_FDG_SEL, frsel); 8368c2ecf20Sopenharmony_ci if (ret) 8378c2ecf20Sopenharmony_ci dev_err(imx290->dev, "Error setting FR/FDG SEL register\n"); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ciexit: 8408c2ecf20Sopenharmony_ci return ret; 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cistatic int imx290_power_on(struct device *dev) 8448c2ecf20Sopenharmony_ci{ 8458c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 8468c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = i2c_get_clientdata(client); 8478c2ecf20Sopenharmony_ci struct imx290 *imx290 = to_imx290(sd); 8488c2ecf20Sopenharmony_ci int ret; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci ret = clk_prepare_enable(imx290->xclk); 8518c2ecf20Sopenharmony_ci if (ret) { 8528c2ecf20Sopenharmony_ci dev_err(imx290->dev, "Failed to enable clock\n"); 8538c2ecf20Sopenharmony_ci return ret; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci ret = regulator_bulk_enable(IMX290_NUM_SUPPLIES, imx290->supplies); 8578c2ecf20Sopenharmony_ci if (ret) { 8588c2ecf20Sopenharmony_ci dev_err(imx290->dev, "Failed to enable regulators\n"); 8598c2ecf20Sopenharmony_ci clk_disable_unprepare(imx290->xclk); 8608c2ecf20Sopenharmony_ci return ret; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci usleep_range(1, 2); 8648c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(imx290->rst_gpio, 0); 8658c2ecf20Sopenharmony_ci usleep_range(30000, 31000); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci /* Set data lane count */ 8688c2ecf20Sopenharmony_ci imx290_set_data_lanes(imx290); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci return 0; 8718c2ecf20Sopenharmony_ci} 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_cistatic int imx290_power_off(struct device *dev) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 8768c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = i2c_get_clientdata(client); 8778c2ecf20Sopenharmony_ci struct imx290 *imx290 = to_imx290(sd); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci clk_disable_unprepare(imx290->xclk); 8808c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(imx290->rst_gpio, 1); 8818c2ecf20Sopenharmony_ci regulator_bulk_disable(IMX290_NUM_SUPPLIES, imx290->supplies); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci return 0; 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_cistatic const struct dev_pm_ops imx290_pm_ops = { 8878c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(imx290_power_off, imx290_power_on, NULL) 8888c2ecf20Sopenharmony_ci}; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_video_ops imx290_video_ops = { 8918c2ecf20Sopenharmony_ci .s_stream = imx290_set_stream, 8928c2ecf20Sopenharmony_ci}; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_pad_ops imx290_pad_ops = { 8958c2ecf20Sopenharmony_ci .init_cfg = imx290_entity_init_cfg, 8968c2ecf20Sopenharmony_ci .enum_mbus_code = imx290_enum_mbus_code, 8978c2ecf20Sopenharmony_ci .enum_frame_size = imx290_enum_frame_size, 8988c2ecf20Sopenharmony_ci .get_fmt = imx290_get_fmt, 8998c2ecf20Sopenharmony_ci .set_fmt = imx290_set_fmt, 9008c2ecf20Sopenharmony_ci}; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops imx290_subdev_ops = { 9038c2ecf20Sopenharmony_ci .video = &imx290_video_ops, 9048c2ecf20Sopenharmony_ci .pad = &imx290_pad_ops, 9058c2ecf20Sopenharmony_ci}; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_cistatic const struct media_entity_operations imx290_subdev_entity_ops = { 9088c2ecf20Sopenharmony_ci .link_validate = v4l2_subdev_link_validate, 9098c2ecf20Sopenharmony_ci}; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci/* 9128c2ecf20Sopenharmony_ci * Returns 0 if all link frequencies used by the driver for the given number 9138c2ecf20Sopenharmony_ci * of MIPI data lanes are mentioned in the device tree, or the value of the 9148c2ecf20Sopenharmony_ci * first missing frequency otherwise. 9158c2ecf20Sopenharmony_ci */ 9168c2ecf20Sopenharmony_cistatic s64 imx290_check_link_freqs(const struct imx290 *imx290, 9178c2ecf20Sopenharmony_ci const struct v4l2_fwnode_endpoint *ep) 9188c2ecf20Sopenharmony_ci{ 9198c2ecf20Sopenharmony_ci int i, j; 9208c2ecf20Sopenharmony_ci const s64 *freqs = imx290_link_freqs_ptr(imx290); 9218c2ecf20Sopenharmony_ci int freqs_count = imx290_link_freqs_num(imx290); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci for (i = 0; i < freqs_count; i++) { 9248c2ecf20Sopenharmony_ci for (j = 0; j < ep->nr_of_link_frequencies; j++) 9258c2ecf20Sopenharmony_ci if (freqs[i] == ep->link_frequencies[j]) 9268c2ecf20Sopenharmony_ci break; 9278c2ecf20Sopenharmony_ci if (j == ep->nr_of_link_frequencies) 9288c2ecf20Sopenharmony_ci return freqs[i]; 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci return 0; 9318c2ecf20Sopenharmony_ci} 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_cistatic int imx290_probe(struct i2c_client *client) 9348c2ecf20Sopenharmony_ci{ 9358c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 9368c2ecf20Sopenharmony_ci struct fwnode_handle *endpoint; 9378c2ecf20Sopenharmony_ci /* Only CSI2 is supported for now: */ 9388c2ecf20Sopenharmony_ci struct v4l2_fwnode_endpoint ep = { 9398c2ecf20Sopenharmony_ci .bus_type = V4L2_MBUS_CSI2_DPHY 9408c2ecf20Sopenharmony_ci }; 9418c2ecf20Sopenharmony_ci struct imx290 *imx290; 9428c2ecf20Sopenharmony_ci u32 xclk_freq; 9438c2ecf20Sopenharmony_ci s64 fq; 9448c2ecf20Sopenharmony_ci int ret; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci imx290 = devm_kzalloc(dev, sizeof(*imx290), GFP_KERNEL); 9478c2ecf20Sopenharmony_ci if (!imx290) 9488c2ecf20Sopenharmony_ci return -ENOMEM; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci imx290->dev = dev; 9518c2ecf20Sopenharmony_ci imx290->regmap = devm_regmap_init_i2c(client, &imx290_regmap_config); 9528c2ecf20Sopenharmony_ci if (IS_ERR(imx290->regmap)) { 9538c2ecf20Sopenharmony_ci dev_err(dev, "Unable to initialize I2C\n"); 9548c2ecf20Sopenharmony_ci return -ENODEV; 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); 9588c2ecf20Sopenharmony_ci if (!endpoint) { 9598c2ecf20Sopenharmony_ci dev_err(dev, "Endpoint node not found\n"); 9608c2ecf20Sopenharmony_ci return -EINVAL; 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep); 9648c2ecf20Sopenharmony_ci fwnode_handle_put(endpoint); 9658c2ecf20Sopenharmony_ci if (ret == -ENXIO) { 9668c2ecf20Sopenharmony_ci dev_err(dev, "Unsupported bus type, should be CSI2\n"); 9678c2ecf20Sopenharmony_ci goto free_err; 9688c2ecf20Sopenharmony_ci } else if (ret) { 9698c2ecf20Sopenharmony_ci dev_err(dev, "Parsing endpoint node failed\n"); 9708c2ecf20Sopenharmony_ci goto free_err; 9718c2ecf20Sopenharmony_ci } 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci /* Get number of data lanes */ 9748c2ecf20Sopenharmony_ci imx290->nlanes = ep.bus.mipi_csi2.num_data_lanes; 9758c2ecf20Sopenharmony_ci if (imx290->nlanes != 2 && imx290->nlanes != 4) { 9768c2ecf20Sopenharmony_ci dev_err(dev, "Invalid data lanes: %d\n", imx290->nlanes); 9778c2ecf20Sopenharmony_ci ret = -EINVAL; 9788c2ecf20Sopenharmony_ci goto free_err; 9798c2ecf20Sopenharmony_ci } 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci dev_dbg(dev, "Using %u data lanes\n", imx290->nlanes); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci if (!ep.nr_of_link_frequencies) { 9848c2ecf20Sopenharmony_ci dev_err(dev, "link-frequency property not found in DT\n"); 9858c2ecf20Sopenharmony_ci ret = -EINVAL; 9868c2ecf20Sopenharmony_ci goto free_err; 9878c2ecf20Sopenharmony_ci } 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci /* Check that link frequences for all the modes are in device tree */ 9908c2ecf20Sopenharmony_ci fq = imx290_check_link_freqs(imx290, &ep); 9918c2ecf20Sopenharmony_ci if (fq) { 9928c2ecf20Sopenharmony_ci dev_err(dev, "Link frequency of %lld is not supported\n", fq); 9938c2ecf20Sopenharmony_ci ret = -EINVAL; 9948c2ecf20Sopenharmony_ci goto free_err; 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci /* get system clock (xclk) */ 9988c2ecf20Sopenharmony_ci imx290->xclk = devm_clk_get(dev, "xclk"); 9998c2ecf20Sopenharmony_ci if (IS_ERR(imx290->xclk)) { 10008c2ecf20Sopenharmony_ci dev_err(dev, "Could not get xclk"); 10018c2ecf20Sopenharmony_ci ret = PTR_ERR(imx290->xclk); 10028c2ecf20Sopenharmony_ci goto free_err; 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", 10068c2ecf20Sopenharmony_ci &xclk_freq); 10078c2ecf20Sopenharmony_ci if (ret) { 10088c2ecf20Sopenharmony_ci dev_err(dev, "Could not get xclk frequency\n"); 10098c2ecf20Sopenharmony_ci goto free_err; 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci /* external clock must be 37.125 MHz */ 10138c2ecf20Sopenharmony_ci if (xclk_freq != 37125000) { 10148c2ecf20Sopenharmony_ci dev_err(dev, "External clock frequency %u is not supported\n", 10158c2ecf20Sopenharmony_ci xclk_freq); 10168c2ecf20Sopenharmony_ci ret = -EINVAL; 10178c2ecf20Sopenharmony_ci goto free_err; 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci ret = clk_set_rate(imx290->xclk, xclk_freq); 10218c2ecf20Sopenharmony_ci if (ret) { 10228c2ecf20Sopenharmony_ci dev_err(dev, "Could not set xclk frequency\n"); 10238c2ecf20Sopenharmony_ci goto free_err; 10248c2ecf20Sopenharmony_ci } 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci ret = imx290_get_regulators(dev, imx290); 10278c2ecf20Sopenharmony_ci if (ret < 0) { 10288c2ecf20Sopenharmony_ci dev_err(dev, "Cannot get regulators\n"); 10298c2ecf20Sopenharmony_ci goto free_err; 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci imx290->rst_gpio = devm_gpiod_get_optional(dev, "reset", 10338c2ecf20Sopenharmony_ci GPIOD_OUT_HIGH); 10348c2ecf20Sopenharmony_ci if (IS_ERR(imx290->rst_gpio)) { 10358c2ecf20Sopenharmony_ci dev_err(dev, "Cannot get reset gpio\n"); 10368c2ecf20Sopenharmony_ci ret = PTR_ERR(imx290->rst_gpio); 10378c2ecf20Sopenharmony_ci goto free_err; 10388c2ecf20Sopenharmony_ci } 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci mutex_init(&imx290->lock); 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci /* 10438c2ecf20Sopenharmony_ci * Initialize the frame format. In particular, imx290->current_mode 10448c2ecf20Sopenharmony_ci * and imx290->bpp are set to defaults: imx290_calc_pixel_rate() call 10458c2ecf20Sopenharmony_ci * below relies on these fields. 10468c2ecf20Sopenharmony_ci */ 10478c2ecf20Sopenharmony_ci imx290_entity_init_cfg(&imx290->sd, NULL); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci v4l2_ctrl_handler_init(&imx290->ctrls, 4); 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, 10528c2ecf20Sopenharmony_ci V4L2_CID_GAIN, 0, 72, 1, 0); 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci imx290->link_freq = 10558c2ecf20Sopenharmony_ci v4l2_ctrl_new_int_menu(&imx290->ctrls, &imx290_ctrl_ops, 10568c2ecf20Sopenharmony_ci V4L2_CID_LINK_FREQ, 10578c2ecf20Sopenharmony_ci imx290_link_freqs_num(imx290) - 1, 0, 10588c2ecf20Sopenharmony_ci imx290_link_freqs_ptr(imx290)); 10598c2ecf20Sopenharmony_ci if (imx290->link_freq) 10608c2ecf20Sopenharmony_ci imx290->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci imx290->pixel_rate = v4l2_ctrl_new_std(&imx290->ctrls, &imx290_ctrl_ops, 10638c2ecf20Sopenharmony_ci V4L2_CID_PIXEL_RATE, 10648c2ecf20Sopenharmony_ci 1, INT_MAX, 1, 10658c2ecf20Sopenharmony_ci imx290_calc_pixel_rate(imx290)); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci v4l2_ctrl_new_std_menu_items(&imx290->ctrls, &imx290_ctrl_ops, 10688c2ecf20Sopenharmony_ci V4L2_CID_TEST_PATTERN, 10698c2ecf20Sopenharmony_ci ARRAY_SIZE(imx290_test_pattern_menu) - 1, 10708c2ecf20Sopenharmony_ci 0, 0, imx290_test_pattern_menu); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci imx290->sd.ctrl_handler = &imx290->ctrls; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci if (imx290->ctrls.error) { 10758c2ecf20Sopenharmony_ci dev_err(dev, "Control initialization error %d\n", 10768c2ecf20Sopenharmony_ci imx290->ctrls.error); 10778c2ecf20Sopenharmony_ci ret = imx290->ctrls.error; 10788c2ecf20Sopenharmony_ci goto free_ctrl; 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops); 10828c2ecf20Sopenharmony_ci imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 10838c2ecf20Sopenharmony_ci imx290->sd.dev = &client->dev; 10848c2ecf20Sopenharmony_ci imx290->sd.entity.ops = &imx290_subdev_entity_ops; 10858c2ecf20Sopenharmony_ci imx290->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci imx290->pad.flags = MEDIA_PAD_FL_SOURCE; 10888c2ecf20Sopenharmony_ci ret = media_entity_pads_init(&imx290->sd.entity, 1, &imx290->pad); 10898c2ecf20Sopenharmony_ci if (ret < 0) { 10908c2ecf20Sopenharmony_ci dev_err(dev, "Could not register media entity\n"); 10918c2ecf20Sopenharmony_ci goto free_ctrl; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci ret = v4l2_async_register_subdev(&imx290->sd); 10958c2ecf20Sopenharmony_ci if (ret < 0) { 10968c2ecf20Sopenharmony_ci dev_err(dev, "Could not register v4l2 device\n"); 10978c2ecf20Sopenharmony_ci goto free_entity; 10988c2ecf20Sopenharmony_ci } 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci /* Power on the device to match runtime PM state below */ 11018c2ecf20Sopenharmony_ci ret = imx290_power_on(dev); 11028c2ecf20Sopenharmony_ci if (ret < 0) { 11038c2ecf20Sopenharmony_ci dev_err(dev, "Could not power on the device\n"); 11048c2ecf20Sopenharmony_ci goto free_entity; 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci pm_runtime_set_active(dev); 11088c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 11098c2ecf20Sopenharmony_ci pm_runtime_idle(dev); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci v4l2_fwnode_endpoint_free(&ep); 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci return 0; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_cifree_entity: 11168c2ecf20Sopenharmony_ci media_entity_cleanup(&imx290->sd.entity); 11178c2ecf20Sopenharmony_cifree_ctrl: 11188c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&imx290->ctrls); 11198c2ecf20Sopenharmony_ci mutex_destroy(&imx290->lock); 11208c2ecf20Sopenharmony_cifree_err: 11218c2ecf20Sopenharmony_ci v4l2_fwnode_endpoint_free(&ep); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci return ret; 11248c2ecf20Sopenharmony_ci} 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_cistatic int imx290_remove(struct i2c_client *client) 11278c2ecf20Sopenharmony_ci{ 11288c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = i2c_get_clientdata(client); 11298c2ecf20Sopenharmony_ci struct imx290 *imx290 = to_imx290(sd); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci v4l2_async_unregister_subdev(sd); 11328c2ecf20Sopenharmony_ci media_entity_cleanup(&sd->entity); 11338c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(sd->ctrl_handler); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci mutex_destroy(&imx290->lock); 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci pm_runtime_disable(imx290->dev); 11388c2ecf20Sopenharmony_ci if (!pm_runtime_status_suspended(imx290->dev)) 11398c2ecf20Sopenharmony_ci imx290_power_off(imx290->dev); 11408c2ecf20Sopenharmony_ci pm_runtime_set_suspended(imx290->dev); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci return 0; 11438c2ecf20Sopenharmony_ci} 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_cistatic const struct of_device_id imx290_of_match[] = { 11468c2ecf20Sopenharmony_ci { .compatible = "sony,imx290" }, 11478c2ecf20Sopenharmony_ci { /* sentinel */ } 11488c2ecf20Sopenharmony_ci}; 11498c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, imx290_of_match); 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_cistatic struct i2c_driver imx290_i2c_driver = { 11528c2ecf20Sopenharmony_ci .probe_new = imx290_probe, 11538c2ecf20Sopenharmony_ci .remove = imx290_remove, 11548c2ecf20Sopenharmony_ci .driver = { 11558c2ecf20Sopenharmony_ci .name = "imx290", 11568c2ecf20Sopenharmony_ci .pm = &imx290_pm_ops, 11578c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(imx290_of_match), 11588c2ecf20Sopenharmony_ci }, 11598c2ecf20Sopenharmony_ci}; 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_cimodule_i2c_driver(imx290_i2c_driver); 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Sony IMX290 CMOS Image Sensor Driver"); 11648c2ecf20Sopenharmony_ciMODULE_AUTHOR("FRAMOS GmbH"); 11658c2ecf20Sopenharmony_ciMODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); 11668c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1167