18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * A V4L2 driver for Sony IMX219 cameras. 48c2ecf20Sopenharmony_ci * Copyright (C) 2019, Raspberry Pi (Trading) Ltd 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Based on Sony imx258 camera driver 78c2ecf20Sopenharmony_ci * Copyright (C) 2018 Intel Corporation 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * DT / fwnode changes, and regulator / GPIO control taken from imx214 driver 108c2ecf20Sopenharmony_ci * Copyright 2018 Qtechnology A/S 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Flip handling taken from the Sony IMX319 driver. 138c2ecf20Sopenharmony_ci * Copyright (C) 2018 Intel Corporation 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/clk.h> 188c2ecf20Sopenharmony_ci#include <linux/delay.h> 198c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 208c2ecf20Sopenharmony_ci#include <linux/i2c.h> 218c2ecf20Sopenharmony_ci#include <linux/module.h> 228c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 238c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 248c2ecf20Sopenharmony_ci#include <media/v4l2-ctrls.h> 258c2ecf20Sopenharmony_ci#include <media/v4l2-device.h> 268c2ecf20Sopenharmony_ci#include <media/v4l2-event.h> 278c2ecf20Sopenharmony_ci#include <media/v4l2-fwnode.h> 288c2ecf20Sopenharmony_ci#include <media/v4l2-mediabus.h> 298c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define IMX219_REG_VALUE_08BIT 1 328c2ecf20Sopenharmony_ci#define IMX219_REG_VALUE_16BIT 2 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define IMX219_REG_MODE_SELECT 0x0100 358c2ecf20Sopenharmony_ci#define IMX219_MODE_STANDBY 0x00 368c2ecf20Sopenharmony_ci#define IMX219_MODE_STREAMING 0x01 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* Chip ID */ 398c2ecf20Sopenharmony_ci#define IMX219_REG_CHIP_ID 0x0000 408c2ecf20Sopenharmony_ci#define IMX219_CHIP_ID 0x0219 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* External clock frequency is 24.0M */ 438c2ecf20Sopenharmony_ci#define IMX219_XCLK_FREQ 24000000 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* Pixel rate is fixed at 182.4M for all the modes */ 468c2ecf20Sopenharmony_ci#define IMX219_PIXEL_RATE 182400000 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define IMX219_DEFAULT_LINK_FREQ 456000000 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* V_TIMING internal */ 518c2ecf20Sopenharmony_ci#define IMX219_REG_VTS 0x0160 528c2ecf20Sopenharmony_ci#define IMX219_VTS_15FPS 0x0dc6 538c2ecf20Sopenharmony_ci#define IMX219_VTS_30FPS_1080P 0x06e3 548c2ecf20Sopenharmony_ci#define IMX219_VTS_30FPS_BINNED 0x06e3 558c2ecf20Sopenharmony_ci#define IMX219_VTS_30FPS_640x480 0x06e3 568c2ecf20Sopenharmony_ci#define IMX219_VTS_MAX 0xffff 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define IMX219_VBLANK_MIN 4 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/*Frame Length Line*/ 618c2ecf20Sopenharmony_ci#define IMX219_FLL_MIN 0x08a6 628c2ecf20Sopenharmony_ci#define IMX219_FLL_MAX 0xffff 638c2ecf20Sopenharmony_ci#define IMX219_FLL_STEP 1 648c2ecf20Sopenharmony_ci#define IMX219_FLL_DEFAULT 0x0c98 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/* HBLANK control - read only */ 678c2ecf20Sopenharmony_ci#define IMX219_PPL_DEFAULT 3448 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* Exposure control */ 708c2ecf20Sopenharmony_ci#define IMX219_REG_EXPOSURE 0x015a 718c2ecf20Sopenharmony_ci#define IMX219_EXPOSURE_MIN 4 728c2ecf20Sopenharmony_ci#define IMX219_EXPOSURE_STEP 1 738c2ecf20Sopenharmony_ci#define IMX219_EXPOSURE_DEFAULT 0x640 748c2ecf20Sopenharmony_ci#define IMX219_EXPOSURE_MAX 65535 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* Analog gain control */ 778c2ecf20Sopenharmony_ci#define IMX219_REG_ANALOG_GAIN 0x0157 788c2ecf20Sopenharmony_ci#define IMX219_ANA_GAIN_MIN 0 798c2ecf20Sopenharmony_ci#define IMX219_ANA_GAIN_MAX 232 808c2ecf20Sopenharmony_ci#define IMX219_ANA_GAIN_STEP 1 818c2ecf20Sopenharmony_ci#define IMX219_ANA_GAIN_DEFAULT 0x0 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* Digital gain control */ 848c2ecf20Sopenharmony_ci#define IMX219_REG_DIGITAL_GAIN 0x0158 858c2ecf20Sopenharmony_ci#define IMX219_DGTL_GAIN_MIN 0x0100 868c2ecf20Sopenharmony_ci#define IMX219_DGTL_GAIN_MAX 0x0fff 878c2ecf20Sopenharmony_ci#define IMX219_DGTL_GAIN_DEFAULT 0x0100 888c2ecf20Sopenharmony_ci#define IMX219_DGTL_GAIN_STEP 1 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci#define IMX219_REG_ORIENTATION 0x0172 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* Binning Mode */ 938c2ecf20Sopenharmony_ci#define IMX219_REG_BINNING_MODE 0x0174 948c2ecf20Sopenharmony_ci#define IMX219_BINNING_NONE 0x0000 958c2ecf20Sopenharmony_ci#define IMX219_BINNING_2X2 0x0101 968c2ecf20Sopenharmony_ci#define IMX219_BINNING_2X2_ANALOG 0x0303 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* Test Pattern Control */ 998c2ecf20Sopenharmony_ci#define IMX219_REG_TEST_PATTERN 0x0600 1008c2ecf20Sopenharmony_ci#define IMX219_TEST_PATTERN_DISABLE 0 1018c2ecf20Sopenharmony_ci#define IMX219_TEST_PATTERN_SOLID_COLOR 1 1028c2ecf20Sopenharmony_ci#define IMX219_TEST_PATTERN_COLOR_BARS 2 1038c2ecf20Sopenharmony_ci#define IMX219_TEST_PATTERN_GREY_COLOR 3 1048c2ecf20Sopenharmony_ci#define IMX219_TEST_PATTERN_PN9 4 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* Test pattern colour components */ 1078c2ecf20Sopenharmony_ci#define IMX219_REG_TESTP_RED 0x0602 1088c2ecf20Sopenharmony_ci#define IMX219_REG_TESTP_GREENR 0x0604 1098c2ecf20Sopenharmony_ci#define IMX219_REG_TESTP_BLUE 0x0606 1108c2ecf20Sopenharmony_ci#define IMX219_REG_TESTP_GREENB 0x0608 1118c2ecf20Sopenharmony_ci#define IMX219_TESTP_COLOUR_MIN 0 1128c2ecf20Sopenharmony_ci#define IMX219_TESTP_COLOUR_MAX 0x03ff 1138c2ecf20Sopenharmony_ci#define IMX219_TESTP_COLOUR_STEP 1 1148c2ecf20Sopenharmony_ci#define IMX219_TESTP_RED_DEFAULT IMX219_TESTP_COLOUR_MAX 1158c2ecf20Sopenharmony_ci#define IMX219_TESTP_GREENR_DEFAULT 0 1168c2ecf20Sopenharmony_ci#define IMX219_TESTP_BLUE_DEFAULT 0 1178c2ecf20Sopenharmony_ci#define IMX219_TESTP_GREENB_DEFAULT 0 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/* IMX219 native and active pixel array size. */ 1208c2ecf20Sopenharmony_ci#define IMX219_NATIVE_WIDTH 3296U 1218c2ecf20Sopenharmony_ci#define IMX219_NATIVE_HEIGHT 2480U 1228c2ecf20Sopenharmony_ci#define IMX219_PIXEL_ARRAY_LEFT 8U 1238c2ecf20Sopenharmony_ci#define IMX219_PIXEL_ARRAY_TOP 8U 1248c2ecf20Sopenharmony_ci#define IMX219_PIXEL_ARRAY_WIDTH 3280U 1258c2ecf20Sopenharmony_ci#define IMX219_PIXEL_ARRAY_HEIGHT 2464U 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistruct imx219_reg { 1288c2ecf20Sopenharmony_ci u16 address; 1298c2ecf20Sopenharmony_ci u8 val; 1308c2ecf20Sopenharmony_ci}; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistruct imx219_reg_list { 1338c2ecf20Sopenharmony_ci unsigned int num_of_regs; 1348c2ecf20Sopenharmony_ci const struct imx219_reg *regs; 1358c2ecf20Sopenharmony_ci}; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci/* Mode : resolution and related config&values */ 1388c2ecf20Sopenharmony_cistruct imx219_mode { 1398c2ecf20Sopenharmony_ci /* Frame width */ 1408c2ecf20Sopenharmony_ci unsigned int width; 1418c2ecf20Sopenharmony_ci /* Frame height */ 1428c2ecf20Sopenharmony_ci unsigned int height; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* Analog crop rectangle. */ 1458c2ecf20Sopenharmony_ci struct v4l2_rect crop; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* V-timing */ 1488c2ecf20Sopenharmony_ci unsigned int vts_def; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci /* Default register values */ 1518c2ecf20Sopenharmony_ci struct imx219_reg_list reg_list; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* 2x2 binning is used */ 1548c2ecf20Sopenharmony_ci bool binning; 1558c2ecf20Sopenharmony_ci}; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic const struct imx219_reg imx219_common_regs[] = { 1588c2ecf20Sopenharmony_ci {0x0100, 0x00}, /* Mode Select */ 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* To Access Addresses 3000-5fff, send the following commands */ 1618c2ecf20Sopenharmony_ci {0x30eb, 0x0c}, 1628c2ecf20Sopenharmony_ci {0x30eb, 0x05}, 1638c2ecf20Sopenharmony_ci {0x300a, 0xff}, 1648c2ecf20Sopenharmony_ci {0x300b, 0xff}, 1658c2ecf20Sopenharmony_ci {0x30eb, 0x05}, 1668c2ecf20Sopenharmony_ci {0x30eb, 0x09}, 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* PLL Clock Table */ 1698c2ecf20Sopenharmony_ci {0x0301, 0x05}, /* VTPXCK_DIV */ 1708c2ecf20Sopenharmony_ci {0x0303, 0x01}, /* VTSYSCK_DIV */ 1718c2ecf20Sopenharmony_ci {0x0304, 0x03}, /* PREPLLCK_VT_DIV 0x03 = AUTO set */ 1728c2ecf20Sopenharmony_ci {0x0305, 0x03}, /* PREPLLCK_OP_DIV 0x03 = AUTO set */ 1738c2ecf20Sopenharmony_ci {0x0306, 0x00}, /* PLL_VT_MPY */ 1748c2ecf20Sopenharmony_ci {0x0307, 0x39}, 1758c2ecf20Sopenharmony_ci {0x030b, 0x01}, /* OP_SYS_CLK_DIV */ 1768c2ecf20Sopenharmony_ci {0x030c, 0x00}, /* PLL_OP_MPY */ 1778c2ecf20Sopenharmony_ci {0x030d, 0x72}, 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* Undocumented registers */ 1808c2ecf20Sopenharmony_ci {0x455e, 0x00}, 1818c2ecf20Sopenharmony_ci {0x471e, 0x4b}, 1828c2ecf20Sopenharmony_ci {0x4767, 0x0f}, 1838c2ecf20Sopenharmony_ci {0x4750, 0x14}, 1848c2ecf20Sopenharmony_ci {0x4540, 0x00}, 1858c2ecf20Sopenharmony_ci {0x47b4, 0x14}, 1868c2ecf20Sopenharmony_ci {0x4713, 0x30}, 1878c2ecf20Sopenharmony_ci {0x478b, 0x10}, 1888c2ecf20Sopenharmony_ci {0x478f, 0x10}, 1898c2ecf20Sopenharmony_ci {0x4793, 0x10}, 1908c2ecf20Sopenharmony_ci {0x4797, 0x0e}, 1918c2ecf20Sopenharmony_ci {0x479b, 0x0e}, 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* Frame Bank Register Group "A" */ 1948c2ecf20Sopenharmony_ci {0x0162, 0x0d}, /* Line_Length_A */ 1958c2ecf20Sopenharmony_ci {0x0163, 0x78}, 1968c2ecf20Sopenharmony_ci {0x0170, 0x01}, /* X_ODD_INC_A */ 1978c2ecf20Sopenharmony_ci {0x0171, 0x01}, /* Y_ODD_INC_A */ 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* Output setup registers */ 2008c2ecf20Sopenharmony_ci {0x0114, 0x01}, /* CSI 2-Lane Mode */ 2018c2ecf20Sopenharmony_ci {0x0128, 0x00}, /* DPHY Auto Mode */ 2028c2ecf20Sopenharmony_ci {0x012a, 0x18}, /* EXCK_Freq */ 2038c2ecf20Sopenharmony_ci {0x012b, 0x00}, 2048c2ecf20Sopenharmony_ci}; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci/* 2078c2ecf20Sopenharmony_ci * Register sets lifted off the i2C interface from the Raspberry Pi firmware 2088c2ecf20Sopenharmony_ci * driver. 2098c2ecf20Sopenharmony_ci * 3280x2464 = mode 2, 1920x1080 = mode 1, 1640x1232 = mode 4, 640x480 = mode 7. 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_cistatic const struct imx219_reg mode_3280x2464_regs[] = { 2128c2ecf20Sopenharmony_ci {0x0164, 0x00}, 2138c2ecf20Sopenharmony_ci {0x0165, 0x00}, 2148c2ecf20Sopenharmony_ci {0x0166, 0x0c}, 2158c2ecf20Sopenharmony_ci {0x0167, 0xcf}, 2168c2ecf20Sopenharmony_ci {0x0168, 0x00}, 2178c2ecf20Sopenharmony_ci {0x0169, 0x00}, 2188c2ecf20Sopenharmony_ci {0x016a, 0x09}, 2198c2ecf20Sopenharmony_ci {0x016b, 0x9f}, 2208c2ecf20Sopenharmony_ci {0x016c, 0x0c}, 2218c2ecf20Sopenharmony_ci {0x016d, 0xd0}, 2228c2ecf20Sopenharmony_ci {0x016e, 0x09}, 2238c2ecf20Sopenharmony_ci {0x016f, 0xa0}, 2248c2ecf20Sopenharmony_ci {0x0624, 0x0c}, 2258c2ecf20Sopenharmony_ci {0x0625, 0xd0}, 2268c2ecf20Sopenharmony_ci {0x0626, 0x09}, 2278c2ecf20Sopenharmony_ci {0x0627, 0xa0}, 2288c2ecf20Sopenharmony_ci}; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic const struct imx219_reg mode_1920_1080_regs[] = { 2318c2ecf20Sopenharmony_ci {0x0164, 0x02}, 2328c2ecf20Sopenharmony_ci {0x0165, 0xa8}, 2338c2ecf20Sopenharmony_ci {0x0166, 0x0a}, 2348c2ecf20Sopenharmony_ci {0x0167, 0x27}, 2358c2ecf20Sopenharmony_ci {0x0168, 0x02}, 2368c2ecf20Sopenharmony_ci {0x0169, 0xb4}, 2378c2ecf20Sopenharmony_ci {0x016a, 0x06}, 2388c2ecf20Sopenharmony_ci {0x016b, 0xeb}, 2398c2ecf20Sopenharmony_ci {0x016c, 0x07}, 2408c2ecf20Sopenharmony_ci {0x016d, 0x80}, 2418c2ecf20Sopenharmony_ci {0x016e, 0x04}, 2428c2ecf20Sopenharmony_ci {0x016f, 0x38}, 2438c2ecf20Sopenharmony_ci {0x0624, 0x07}, 2448c2ecf20Sopenharmony_ci {0x0625, 0x80}, 2458c2ecf20Sopenharmony_ci {0x0626, 0x04}, 2468c2ecf20Sopenharmony_ci {0x0627, 0x38}, 2478c2ecf20Sopenharmony_ci}; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic const struct imx219_reg mode_1640_1232_regs[] = { 2508c2ecf20Sopenharmony_ci {0x0164, 0x00}, 2518c2ecf20Sopenharmony_ci {0x0165, 0x00}, 2528c2ecf20Sopenharmony_ci {0x0166, 0x0c}, 2538c2ecf20Sopenharmony_ci {0x0167, 0xcf}, 2548c2ecf20Sopenharmony_ci {0x0168, 0x00}, 2558c2ecf20Sopenharmony_ci {0x0169, 0x00}, 2568c2ecf20Sopenharmony_ci {0x016a, 0x09}, 2578c2ecf20Sopenharmony_ci {0x016b, 0x9f}, 2588c2ecf20Sopenharmony_ci {0x016c, 0x06}, 2598c2ecf20Sopenharmony_ci {0x016d, 0x68}, 2608c2ecf20Sopenharmony_ci {0x016e, 0x04}, 2618c2ecf20Sopenharmony_ci {0x016f, 0xd0}, 2628c2ecf20Sopenharmony_ci {0x0624, 0x06}, 2638c2ecf20Sopenharmony_ci {0x0625, 0x68}, 2648c2ecf20Sopenharmony_ci {0x0626, 0x04}, 2658c2ecf20Sopenharmony_ci {0x0627, 0xd0}, 2668c2ecf20Sopenharmony_ci}; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic const struct imx219_reg mode_640_480_regs[] = { 2698c2ecf20Sopenharmony_ci {0x0164, 0x03}, 2708c2ecf20Sopenharmony_ci {0x0165, 0xe8}, 2718c2ecf20Sopenharmony_ci {0x0166, 0x08}, 2728c2ecf20Sopenharmony_ci {0x0167, 0xe7}, 2738c2ecf20Sopenharmony_ci {0x0168, 0x02}, 2748c2ecf20Sopenharmony_ci {0x0169, 0xf0}, 2758c2ecf20Sopenharmony_ci {0x016a, 0x06}, 2768c2ecf20Sopenharmony_ci {0x016b, 0xaf}, 2778c2ecf20Sopenharmony_ci {0x016c, 0x02}, 2788c2ecf20Sopenharmony_ci {0x016d, 0x80}, 2798c2ecf20Sopenharmony_ci {0x016e, 0x01}, 2808c2ecf20Sopenharmony_ci {0x016f, 0xe0}, 2818c2ecf20Sopenharmony_ci {0x0624, 0x06}, 2828c2ecf20Sopenharmony_ci {0x0625, 0x68}, 2838c2ecf20Sopenharmony_ci {0x0626, 0x04}, 2848c2ecf20Sopenharmony_ci {0x0627, 0xd0}, 2858c2ecf20Sopenharmony_ci}; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic const struct imx219_reg raw8_framefmt_regs[] = { 2888c2ecf20Sopenharmony_ci {0x018c, 0x08}, 2898c2ecf20Sopenharmony_ci {0x018d, 0x08}, 2908c2ecf20Sopenharmony_ci {0x0309, 0x08}, 2918c2ecf20Sopenharmony_ci}; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic const struct imx219_reg raw10_framefmt_regs[] = { 2948c2ecf20Sopenharmony_ci {0x018c, 0x0a}, 2958c2ecf20Sopenharmony_ci {0x018d, 0x0a}, 2968c2ecf20Sopenharmony_ci {0x0309, 0x0a}, 2978c2ecf20Sopenharmony_ci}; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic const char * const imx219_test_pattern_menu[] = { 3008c2ecf20Sopenharmony_ci "Disabled", 3018c2ecf20Sopenharmony_ci "Color Bars", 3028c2ecf20Sopenharmony_ci "Solid Color", 3038c2ecf20Sopenharmony_ci "Grey Color Bars", 3048c2ecf20Sopenharmony_ci "PN9" 3058c2ecf20Sopenharmony_ci}; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic const int imx219_test_pattern_val[] = { 3088c2ecf20Sopenharmony_ci IMX219_TEST_PATTERN_DISABLE, 3098c2ecf20Sopenharmony_ci IMX219_TEST_PATTERN_COLOR_BARS, 3108c2ecf20Sopenharmony_ci IMX219_TEST_PATTERN_SOLID_COLOR, 3118c2ecf20Sopenharmony_ci IMX219_TEST_PATTERN_GREY_COLOR, 3128c2ecf20Sopenharmony_ci IMX219_TEST_PATTERN_PN9, 3138c2ecf20Sopenharmony_ci}; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci/* regulator supplies */ 3168c2ecf20Sopenharmony_cistatic const char * const imx219_supply_name[] = { 3178c2ecf20Sopenharmony_ci /* Supplies can be enabled in any order */ 3188c2ecf20Sopenharmony_ci "VANA", /* Analog (2.8V) supply */ 3198c2ecf20Sopenharmony_ci "VDIG", /* Digital Core (1.8V) supply */ 3208c2ecf20Sopenharmony_ci "VDDL", /* IF (1.2V) supply */ 3218c2ecf20Sopenharmony_ci}; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci#define IMX219_NUM_SUPPLIES ARRAY_SIZE(imx219_supply_name) 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci/* 3268c2ecf20Sopenharmony_ci * The supported formats. 3278c2ecf20Sopenharmony_ci * This table MUST contain 4 entries per format, to cover the various flip 3288c2ecf20Sopenharmony_ci * combinations in the order 3298c2ecf20Sopenharmony_ci * - no flip 3308c2ecf20Sopenharmony_ci * - h flip 3318c2ecf20Sopenharmony_ci * - v flip 3328c2ecf20Sopenharmony_ci * - h&v flips 3338c2ecf20Sopenharmony_ci */ 3348c2ecf20Sopenharmony_cistatic const u32 codes[] = { 3358c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SRGGB10_1X10, 3368c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGRBG10_1X10, 3378c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGBRG10_1X10, 3388c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SBGGR10_1X10, 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SRGGB8_1X8, 3418c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGRBG8_1X8, 3428c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGBRG8_1X8, 3438c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SBGGR8_1X8, 3448c2ecf20Sopenharmony_ci}; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci/* 3478c2ecf20Sopenharmony_ci * Initialisation delay between XCLR low->high and the moment when the sensor 3488c2ecf20Sopenharmony_ci * can start capture (i.e. can leave software stanby) must be not less than: 3498c2ecf20Sopenharmony_ci * t4 + max(t5, t6 + <time to initialize the sensor register over I2C>) 3508c2ecf20Sopenharmony_ci * where 3518c2ecf20Sopenharmony_ci * t4 is fixed, and is max 200uS, 3528c2ecf20Sopenharmony_ci * t5 is fixed, and is 6000uS, 3538c2ecf20Sopenharmony_ci * t6 depends on the sensor external clock, and is max 32000 clock periods. 3548c2ecf20Sopenharmony_ci * As per sensor datasheet, the external clock must be from 6MHz to 27MHz. 3558c2ecf20Sopenharmony_ci * So for any acceptable external clock t6 is always within the range of 3568c2ecf20Sopenharmony_ci * 1185 to 5333 uS, and is always less than t5. 3578c2ecf20Sopenharmony_ci * For this reason this is always safe to wait (t4 + t5) = 6200 uS, then 3588c2ecf20Sopenharmony_ci * initialize the sensor over I2C, and then exit the software standby. 3598c2ecf20Sopenharmony_ci * 3608c2ecf20Sopenharmony_ci * This start-up time can be optimized a bit more, if we start the writes 3618c2ecf20Sopenharmony_ci * over I2C after (t4+t6), but before (t4+t5) expires. But then sensor 3628c2ecf20Sopenharmony_ci * initialization over I2C may complete before (t4+t5) expires, and we must 3638c2ecf20Sopenharmony_ci * ensure that capture is not started before (t4+t5). 3648c2ecf20Sopenharmony_ci * 3658c2ecf20Sopenharmony_ci * This delay doesn't account for the power supply startup time. If needed, 3668c2ecf20Sopenharmony_ci * this should be taken care of via the regulator framework. E.g. in the 3678c2ecf20Sopenharmony_ci * case of DT for regulator-fixed one should define the startup-delay-us 3688c2ecf20Sopenharmony_ci * property. 3698c2ecf20Sopenharmony_ci */ 3708c2ecf20Sopenharmony_ci#define IMX219_XCLR_MIN_DELAY_US 6200 3718c2ecf20Sopenharmony_ci#define IMX219_XCLR_DELAY_RANGE_US 1000 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci/* Mode configs */ 3748c2ecf20Sopenharmony_cistatic const struct imx219_mode supported_modes[] = { 3758c2ecf20Sopenharmony_ci { 3768c2ecf20Sopenharmony_ci /* 8MPix 15fps mode */ 3778c2ecf20Sopenharmony_ci .width = 3280, 3788c2ecf20Sopenharmony_ci .height = 2464, 3798c2ecf20Sopenharmony_ci .crop = { 3808c2ecf20Sopenharmony_ci .left = IMX219_PIXEL_ARRAY_LEFT, 3818c2ecf20Sopenharmony_ci .top = IMX219_PIXEL_ARRAY_TOP, 3828c2ecf20Sopenharmony_ci .width = 3280, 3838c2ecf20Sopenharmony_ci .height = 2464 3848c2ecf20Sopenharmony_ci }, 3858c2ecf20Sopenharmony_ci .vts_def = IMX219_VTS_15FPS, 3868c2ecf20Sopenharmony_ci .reg_list = { 3878c2ecf20Sopenharmony_ci .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs), 3888c2ecf20Sopenharmony_ci .regs = mode_3280x2464_regs, 3898c2ecf20Sopenharmony_ci }, 3908c2ecf20Sopenharmony_ci .binning = false, 3918c2ecf20Sopenharmony_ci }, 3928c2ecf20Sopenharmony_ci { 3938c2ecf20Sopenharmony_ci /* 1080P 30fps cropped */ 3948c2ecf20Sopenharmony_ci .width = 1920, 3958c2ecf20Sopenharmony_ci .height = 1080, 3968c2ecf20Sopenharmony_ci .crop = { 3978c2ecf20Sopenharmony_ci .left = 688, 3988c2ecf20Sopenharmony_ci .top = 700, 3998c2ecf20Sopenharmony_ci .width = 1920, 4008c2ecf20Sopenharmony_ci .height = 1080 4018c2ecf20Sopenharmony_ci }, 4028c2ecf20Sopenharmony_ci .vts_def = IMX219_VTS_30FPS_1080P, 4038c2ecf20Sopenharmony_ci .reg_list = { 4048c2ecf20Sopenharmony_ci .num_of_regs = ARRAY_SIZE(mode_1920_1080_regs), 4058c2ecf20Sopenharmony_ci .regs = mode_1920_1080_regs, 4068c2ecf20Sopenharmony_ci }, 4078c2ecf20Sopenharmony_ci .binning = false, 4088c2ecf20Sopenharmony_ci }, 4098c2ecf20Sopenharmony_ci { 4108c2ecf20Sopenharmony_ci /* 2x2 binned 30fps mode */ 4118c2ecf20Sopenharmony_ci .width = 1640, 4128c2ecf20Sopenharmony_ci .height = 1232, 4138c2ecf20Sopenharmony_ci .crop = { 4148c2ecf20Sopenharmony_ci .left = IMX219_PIXEL_ARRAY_LEFT, 4158c2ecf20Sopenharmony_ci .top = IMX219_PIXEL_ARRAY_TOP, 4168c2ecf20Sopenharmony_ci .width = 3280, 4178c2ecf20Sopenharmony_ci .height = 2464 4188c2ecf20Sopenharmony_ci }, 4198c2ecf20Sopenharmony_ci .vts_def = IMX219_VTS_30FPS_BINNED, 4208c2ecf20Sopenharmony_ci .reg_list = { 4218c2ecf20Sopenharmony_ci .num_of_regs = ARRAY_SIZE(mode_1640_1232_regs), 4228c2ecf20Sopenharmony_ci .regs = mode_1640_1232_regs, 4238c2ecf20Sopenharmony_ci }, 4248c2ecf20Sopenharmony_ci .binning = true, 4258c2ecf20Sopenharmony_ci }, 4268c2ecf20Sopenharmony_ci { 4278c2ecf20Sopenharmony_ci /* 640x480 30fps mode */ 4288c2ecf20Sopenharmony_ci .width = 640, 4298c2ecf20Sopenharmony_ci .height = 480, 4308c2ecf20Sopenharmony_ci .crop = { 4318c2ecf20Sopenharmony_ci .left = 1008, 4328c2ecf20Sopenharmony_ci .top = 760, 4338c2ecf20Sopenharmony_ci .width = 1280, 4348c2ecf20Sopenharmony_ci .height = 960 4358c2ecf20Sopenharmony_ci }, 4368c2ecf20Sopenharmony_ci .vts_def = IMX219_VTS_30FPS_640x480, 4378c2ecf20Sopenharmony_ci .reg_list = { 4388c2ecf20Sopenharmony_ci .num_of_regs = ARRAY_SIZE(mode_640_480_regs), 4398c2ecf20Sopenharmony_ci .regs = mode_640_480_regs, 4408c2ecf20Sopenharmony_ci }, 4418c2ecf20Sopenharmony_ci .binning = true, 4428c2ecf20Sopenharmony_ci }, 4438c2ecf20Sopenharmony_ci}; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_cistruct imx219 { 4468c2ecf20Sopenharmony_ci struct v4l2_subdev sd; 4478c2ecf20Sopenharmony_ci struct media_pad pad; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt fmt; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci struct clk *xclk; /* system clock to IMX219 */ 4528c2ecf20Sopenharmony_ci u32 xclk_freq; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci struct gpio_desc *reset_gpio; 4558c2ecf20Sopenharmony_ci struct regulator_bulk_data supplies[IMX219_NUM_SUPPLIES]; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler ctrl_handler; 4588c2ecf20Sopenharmony_ci /* V4L2 Controls */ 4598c2ecf20Sopenharmony_ci struct v4l2_ctrl *pixel_rate; 4608c2ecf20Sopenharmony_ci struct v4l2_ctrl *exposure; 4618c2ecf20Sopenharmony_ci struct v4l2_ctrl *vflip; 4628c2ecf20Sopenharmony_ci struct v4l2_ctrl *hflip; 4638c2ecf20Sopenharmony_ci struct v4l2_ctrl *vblank; 4648c2ecf20Sopenharmony_ci struct v4l2_ctrl *hblank; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* Current mode */ 4678c2ecf20Sopenharmony_ci const struct imx219_mode *mode; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci /* 4708c2ecf20Sopenharmony_ci * Mutex for serialized access: 4718c2ecf20Sopenharmony_ci * Protect sensor module set pad format and start/stop streaming safely. 4728c2ecf20Sopenharmony_ci */ 4738c2ecf20Sopenharmony_ci struct mutex mutex; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* Streaming on/off */ 4768c2ecf20Sopenharmony_ci bool streaming; 4778c2ecf20Sopenharmony_ci}; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic inline struct imx219 *to_imx219(struct v4l2_subdev *_sd) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci return container_of(_sd, struct imx219, sd); 4828c2ecf20Sopenharmony_ci} 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci/* Read registers up to 2 at a time */ 4858c2ecf20Sopenharmony_cistatic int imx219_read_reg(struct imx219 *imx219, u16 reg, u32 len, u32 *val) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); 4888c2ecf20Sopenharmony_ci struct i2c_msg msgs[2]; 4898c2ecf20Sopenharmony_ci u8 addr_buf[2] = { reg >> 8, reg & 0xff }; 4908c2ecf20Sopenharmony_ci u8 data_buf[4] = { 0, }; 4918c2ecf20Sopenharmony_ci int ret; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci if (len > 4) 4948c2ecf20Sopenharmony_ci return -EINVAL; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* Write register address */ 4978c2ecf20Sopenharmony_ci msgs[0].addr = client->addr; 4988c2ecf20Sopenharmony_ci msgs[0].flags = 0; 4998c2ecf20Sopenharmony_ci msgs[0].len = ARRAY_SIZE(addr_buf); 5008c2ecf20Sopenharmony_ci msgs[0].buf = addr_buf; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* Read data from register */ 5038c2ecf20Sopenharmony_ci msgs[1].addr = client->addr; 5048c2ecf20Sopenharmony_ci msgs[1].flags = I2C_M_RD; 5058c2ecf20Sopenharmony_ci msgs[1].len = len; 5068c2ecf20Sopenharmony_ci msgs[1].buf = &data_buf[4 - len]; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 5098c2ecf20Sopenharmony_ci if (ret != ARRAY_SIZE(msgs)) 5108c2ecf20Sopenharmony_ci return -EIO; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci *val = get_unaligned_be32(data_buf); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci return 0; 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci/* Write registers up to 2 at a time */ 5188c2ecf20Sopenharmony_cistatic int imx219_write_reg(struct imx219 *imx219, u16 reg, u32 len, u32 val) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); 5218c2ecf20Sopenharmony_ci u8 buf[6]; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (len > 4) 5248c2ecf20Sopenharmony_ci return -EINVAL; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci put_unaligned_be16(reg, buf); 5278c2ecf20Sopenharmony_ci put_unaligned_be32(val << (8 * (4 - len)), buf + 2); 5288c2ecf20Sopenharmony_ci if (i2c_master_send(client, buf, len + 2) != len + 2) 5298c2ecf20Sopenharmony_ci return -EIO; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci return 0; 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci/* Write a list of registers */ 5358c2ecf20Sopenharmony_cistatic int imx219_write_regs(struct imx219 *imx219, 5368c2ecf20Sopenharmony_ci const struct imx219_reg *regs, u32 len) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); 5398c2ecf20Sopenharmony_ci unsigned int i; 5408c2ecf20Sopenharmony_ci int ret; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 5438c2ecf20Sopenharmony_ci ret = imx219_write_reg(imx219, regs[i].address, 1, regs[i].val); 5448c2ecf20Sopenharmony_ci if (ret) { 5458c2ecf20Sopenharmony_ci dev_err_ratelimited(&client->dev, 5468c2ecf20Sopenharmony_ci "Failed to write reg 0x%4.4x. error = %d\n", 5478c2ecf20Sopenharmony_ci regs[i].address, ret); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci return ret; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci return 0; 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci/* Get bayer order based on flip setting. */ 5578c2ecf20Sopenharmony_cistatic u32 imx219_get_format_code(struct imx219 *imx219, u32 code) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci unsigned int i; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci lockdep_assert_held(&imx219->mutex); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(codes); i++) 5648c2ecf20Sopenharmony_ci if (codes[i] == code) 5658c2ecf20Sopenharmony_ci break; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci if (i >= ARRAY_SIZE(codes)) 5688c2ecf20Sopenharmony_ci i = 0; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci i = (i & ~3) | (imx219->vflip->val ? 2 : 0) | 5718c2ecf20Sopenharmony_ci (imx219->hflip->val ? 1 : 0); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci return codes[i]; 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic void imx219_set_default_format(struct imx219 *imx219) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *fmt; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci fmt = &imx219->fmt; 5818c2ecf20Sopenharmony_ci fmt->code = MEDIA_BUS_FMT_SRGGB10_1X10; 5828c2ecf20Sopenharmony_ci fmt->colorspace = V4L2_COLORSPACE_SRGB; 5838c2ecf20Sopenharmony_ci fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); 5848c2ecf20Sopenharmony_ci fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, 5858c2ecf20Sopenharmony_ci fmt->colorspace, 5868c2ecf20Sopenharmony_ci fmt->ycbcr_enc); 5878c2ecf20Sopenharmony_ci fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); 5888c2ecf20Sopenharmony_ci fmt->width = supported_modes[0].width; 5898c2ecf20Sopenharmony_ci fmt->height = supported_modes[0].height; 5908c2ecf20Sopenharmony_ci fmt->field = V4L2_FIELD_NONE; 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic int imx219_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci struct imx219 *imx219 = to_imx219(sd); 5968c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *try_fmt = 5978c2ecf20Sopenharmony_ci v4l2_subdev_get_try_format(sd, fh->pad, 0); 5988c2ecf20Sopenharmony_ci struct v4l2_rect *try_crop; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci mutex_lock(&imx219->mutex); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci /* Initialize try_fmt */ 6038c2ecf20Sopenharmony_ci try_fmt->width = supported_modes[0].width; 6048c2ecf20Sopenharmony_ci try_fmt->height = supported_modes[0].height; 6058c2ecf20Sopenharmony_ci try_fmt->code = imx219_get_format_code(imx219, 6068c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SRGGB10_1X10); 6078c2ecf20Sopenharmony_ci try_fmt->field = V4L2_FIELD_NONE; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci /* Initialize try_crop rectangle. */ 6108c2ecf20Sopenharmony_ci try_crop = v4l2_subdev_get_try_crop(sd, fh->pad, 0); 6118c2ecf20Sopenharmony_ci try_crop->top = IMX219_PIXEL_ARRAY_TOP; 6128c2ecf20Sopenharmony_ci try_crop->left = IMX219_PIXEL_ARRAY_LEFT; 6138c2ecf20Sopenharmony_ci try_crop->width = IMX219_PIXEL_ARRAY_WIDTH; 6148c2ecf20Sopenharmony_ci try_crop->height = IMX219_PIXEL_ARRAY_HEIGHT; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci mutex_unlock(&imx219->mutex); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci return 0; 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_cistatic int imx219_set_ctrl(struct v4l2_ctrl *ctrl) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci struct imx219 *imx219 = 6248c2ecf20Sopenharmony_ci container_of(ctrl->handler, struct imx219, ctrl_handler); 6258c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); 6268c2ecf20Sopenharmony_ci int ret; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci if (ctrl->id == V4L2_CID_VBLANK) { 6298c2ecf20Sopenharmony_ci int exposure_max, exposure_def; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci /* Update max exposure while meeting expected vblanking */ 6328c2ecf20Sopenharmony_ci exposure_max = imx219->mode->height + ctrl->val - 4; 6338c2ecf20Sopenharmony_ci exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? 6348c2ecf20Sopenharmony_ci exposure_max : IMX219_EXPOSURE_DEFAULT; 6358c2ecf20Sopenharmony_ci __v4l2_ctrl_modify_range(imx219->exposure, 6368c2ecf20Sopenharmony_ci imx219->exposure->minimum, 6378c2ecf20Sopenharmony_ci exposure_max, imx219->exposure->step, 6388c2ecf20Sopenharmony_ci exposure_def); 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci /* 6428c2ecf20Sopenharmony_ci * Applying V4L2 control value only happens 6438c2ecf20Sopenharmony_ci * when power is up for streaming 6448c2ecf20Sopenharmony_ci */ 6458c2ecf20Sopenharmony_ci if (pm_runtime_get_if_in_use(&client->dev) == 0) 6468c2ecf20Sopenharmony_ci return 0; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci switch (ctrl->id) { 6498c2ecf20Sopenharmony_ci case V4L2_CID_ANALOGUE_GAIN: 6508c2ecf20Sopenharmony_ci ret = imx219_write_reg(imx219, IMX219_REG_ANALOG_GAIN, 6518c2ecf20Sopenharmony_ci IMX219_REG_VALUE_08BIT, ctrl->val); 6528c2ecf20Sopenharmony_ci break; 6538c2ecf20Sopenharmony_ci case V4L2_CID_EXPOSURE: 6548c2ecf20Sopenharmony_ci ret = imx219_write_reg(imx219, IMX219_REG_EXPOSURE, 6558c2ecf20Sopenharmony_ci IMX219_REG_VALUE_16BIT, ctrl->val); 6568c2ecf20Sopenharmony_ci break; 6578c2ecf20Sopenharmony_ci case V4L2_CID_DIGITAL_GAIN: 6588c2ecf20Sopenharmony_ci ret = imx219_write_reg(imx219, IMX219_REG_DIGITAL_GAIN, 6598c2ecf20Sopenharmony_ci IMX219_REG_VALUE_16BIT, ctrl->val); 6608c2ecf20Sopenharmony_ci break; 6618c2ecf20Sopenharmony_ci case V4L2_CID_TEST_PATTERN: 6628c2ecf20Sopenharmony_ci ret = imx219_write_reg(imx219, IMX219_REG_TEST_PATTERN, 6638c2ecf20Sopenharmony_ci IMX219_REG_VALUE_16BIT, 6648c2ecf20Sopenharmony_ci imx219_test_pattern_val[ctrl->val]); 6658c2ecf20Sopenharmony_ci break; 6668c2ecf20Sopenharmony_ci case V4L2_CID_HFLIP: 6678c2ecf20Sopenharmony_ci case V4L2_CID_VFLIP: 6688c2ecf20Sopenharmony_ci ret = imx219_write_reg(imx219, IMX219_REG_ORIENTATION, 1, 6698c2ecf20Sopenharmony_ci imx219->hflip->val | 6708c2ecf20Sopenharmony_ci imx219->vflip->val << 1); 6718c2ecf20Sopenharmony_ci break; 6728c2ecf20Sopenharmony_ci case V4L2_CID_VBLANK: 6738c2ecf20Sopenharmony_ci ret = imx219_write_reg(imx219, IMX219_REG_VTS, 6748c2ecf20Sopenharmony_ci IMX219_REG_VALUE_16BIT, 6758c2ecf20Sopenharmony_ci imx219->mode->height + ctrl->val); 6768c2ecf20Sopenharmony_ci break; 6778c2ecf20Sopenharmony_ci case V4L2_CID_TEST_PATTERN_RED: 6788c2ecf20Sopenharmony_ci ret = imx219_write_reg(imx219, IMX219_REG_TESTP_RED, 6798c2ecf20Sopenharmony_ci IMX219_REG_VALUE_16BIT, ctrl->val); 6808c2ecf20Sopenharmony_ci break; 6818c2ecf20Sopenharmony_ci case V4L2_CID_TEST_PATTERN_GREENR: 6828c2ecf20Sopenharmony_ci ret = imx219_write_reg(imx219, IMX219_REG_TESTP_GREENR, 6838c2ecf20Sopenharmony_ci IMX219_REG_VALUE_16BIT, ctrl->val); 6848c2ecf20Sopenharmony_ci break; 6858c2ecf20Sopenharmony_ci case V4L2_CID_TEST_PATTERN_BLUE: 6868c2ecf20Sopenharmony_ci ret = imx219_write_reg(imx219, IMX219_REG_TESTP_BLUE, 6878c2ecf20Sopenharmony_ci IMX219_REG_VALUE_16BIT, ctrl->val); 6888c2ecf20Sopenharmony_ci break; 6898c2ecf20Sopenharmony_ci case V4L2_CID_TEST_PATTERN_GREENB: 6908c2ecf20Sopenharmony_ci ret = imx219_write_reg(imx219, IMX219_REG_TESTP_GREENB, 6918c2ecf20Sopenharmony_ci IMX219_REG_VALUE_16BIT, ctrl->val); 6928c2ecf20Sopenharmony_ci break; 6938c2ecf20Sopenharmony_ci default: 6948c2ecf20Sopenharmony_ci dev_info(&client->dev, 6958c2ecf20Sopenharmony_ci "ctrl(id:0x%x,val:0x%x) is not handled\n", 6968c2ecf20Sopenharmony_ci ctrl->id, ctrl->val); 6978c2ecf20Sopenharmony_ci ret = -EINVAL; 6988c2ecf20Sopenharmony_ci break; 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci pm_runtime_put(&client->dev); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci return ret; 7048c2ecf20Sopenharmony_ci} 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops imx219_ctrl_ops = { 7078c2ecf20Sopenharmony_ci .s_ctrl = imx219_set_ctrl, 7088c2ecf20Sopenharmony_ci}; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_cistatic int imx219_enum_mbus_code(struct v4l2_subdev *sd, 7118c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 7128c2ecf20Sopenharmony_ci struct v4l2_subdev_mbus_code_enum *code) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci struct imx219 *imx219 = to_imx219(sd); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (code->index >= (ARRAY_SIZE(codes) / 4)) 7178c2ecf20Sopenharmony_ci return -EINVAL; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci code->code = imx219_get_format_code(imx219, codes[code->index * 4]); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci return 0; 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_cistatic int imx219_enum_frame_size(struct v4l2_subdev *sd, 7258c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 7268c2ecf20Sopenharmony_ci struct v4l2_subdev_frame_size_enum *fse) 7278c2ecf20Sopenharmony_ci{ 7288c2ecf20Sopenharmony_ci struct imx219 *imx219 = to_imx219(sd); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci if (fse->index >= ARRAY_SIZE(supported_modes)) 7318c2ecf20Sopenharmony_ci return -EINVAL; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci if (fse->code != imx219_get_format_code(imx219, fse->code)) 7348c2ecf20Sopenharmony_ci return -EINVAL; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci fse->min_width = supported_modes[fse->index].width; 7378c2ecf20Sopenharmony_ci fse->max_width = fse->min_width; 7388c2ecf20Sopenharmony_ci fse->min_height = supported_modes[fse->index].height; 7398c2ecf20Sopenharmony_ci fse->max_height = fse->min_height; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci return 0; 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic void imx219_reset_colorspace(struct v4l2_mbus_framefmt *fmt) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci fmt->colorspace = V4L2_COLORSPACE_SRGB; 7478c2ecf20Sopenharmony_ci fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); 7488c2ecf20Sopenharmony_ci fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, 7498c2ecf20Sopenharmony_ci fmt->colorspace, 7508c2ecf20Sopenharmony_ci fmt->ycbcr_enc); 7518c2ecf20Sopenharmony_ci fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_cistatic void imx219_update_pad_format(struct imx219 *imx219, 7558c2ecf20Sopenharmony_ci const struct imx219_mode *mode, 7568c2ecf20Sopenharmony_ci struct v4l2_subdev_format *fmt) 7578c2ecf20Sopenharmony_ci{ 7588c2ecf20Sopenharmony_ci fmt->format.width = mode->width; 7598c2ecf20Sopenharmony_ci fmt->format.height = mode->height; 7608c2ecf20Sopenharmony_ci fmt->format.field = V4L2_FIELD_NONE; 7618c2ecf20Sopenharmony_ci imx219_reset_colorspace(&fmt->format); 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic int __imx219_get_pad_format(struct imx219 *imx219, 7658c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 7668c2ecf20Sopenharmony_ci struct v4l2_subdev_format *fmt) 7678c2ecf20Sopenharmony_ci{ 7688c2ecf20Sopenharmony_ci if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { 7698c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *try_fmt = 7708c2ecf20Sopenharmony_ci v4l2_subdev_get_try_format(&imx219->sd, cfg, fmt->pad); 7718c2ecf20Sopenharmony_ci /* update the code which could change due to vflip or hflip: */ 7728c2ecf20Sopenharmony_ci try_fmt->code = imx219_get_format_code(imx219, try_fmt->code); 7738c2ecf20Sopenharmony_ci fmt->format = *try_fmt; 7748c2ecf20Sopenharmony_ci } else { 7758c2ecf20Sopenharmony_ci imx219_update_pad_format(imx219, imx219->mode, fmt); 7768c2ecf20Sopenharmony_ci fmt->format.code = imx219_get_format_code(imx219, 7778c2ecf20Sopenharmony_ci imx219->fmt.code); 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci return 0; 7818c2ecf20Sopenharmony_ci} 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cistatic int imx219_get_pad_format(struct v4l2_subdev *sd, 7848c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 7858c2ecf20Sopenharmony_ci struct v4l2_subdev_format *fmt) 7868c2ecf20Sopenharmony_ci{ 7878c2ecf20Sopenharmony_ci struct imx219 *imx219 = to_imx219(sd); 7888c2ecf20Sopenharmony_ci int ret; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci mutex_lock(&imx219->mutex); 7918c2ecf20Sopenharmony_ci ret = __imx219_get_pad_format(imx219, cfg, fmt); 7928c2ecf20Sopenharmony_ci mutex_unlock(&imx219->mutex); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci return ret; 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistatic int imx219_set_pad_format(struct v4l2_subdev *sd, 7988c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 7998c2ecf20Sopenharmony_ci struct v4l2_subdev_format *fmt) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci struct imx219 *imx219 = to_imx219(sd); 8028c2ecf20Sopenharmony_ci const struct imx219_mode *mode; 8038c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *framefmt; 8048c2ecf20Sopenharmony_ci int exposure_max, exposure_def, hblank; 8058c2ecf20Sopenharmony_ci unsigned int i; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci mutex_lock(&imx219->mutex); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(codes); i++) 8108c2ecf20Sopenharmony_ci if (codes[i] == fmt->format.code) 8118c2ecf20Sopenharmony_ci break; 8128c2ecf20Sopenharmony_ci if (i >= ARRAY_SIZE(codes)) 8138c2ecf20Sopenharmony_ci i = 0; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci /* Bayer order varies with flips */ 8168c2ecf20Sopenharmony_ci fmt->format.code = imx219_get_format_code(imx219, codes[i]); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci mode = v4l2_find_nearest_size(supported_modes, 8198c2ecf20Sopenharmony_ci ARRAY_SIZE(supported_modes), 8208c2ecf20Sopenharmony_ci width, height, 8218c2ecf20Sopenharmony_ci fmt->format.width, fmt->format.height); 8228c2ecf20Sopenharmony_ci imx219_update_pad_format(imx219, mode, fmt); 8238c2ecf20Sopenharmony_ci if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { 8248c2ecf20Sopenharmony_ci framefmt = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); 8258c2ecf20Sopenharmony_ci *framefmt = fmt->format; 8268c2ecf20Sopenharmony_ci } else if (imx219->mode != mode || 8278c2ecf20Sopenharmony_ci imx219->fmt.code != fmt->format.code) { 8288c2ecf20Sopenharmony_ci imx219->fmt = fmt->format; 8298c2ecf20Sopenharmony_ci imx219->mode = mode; 8308c2ecf20Sopenharmony_ci /* Update limits and set FPS to default */ 8318c2ecf20Sopenharmony_ci __v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN, 8328c2ecf20Sopenharmony_ci IMX219_VTS_MAX - mode->height, 1, 8338c2ecf20Sopenharmony_ci mode->vts_def - mode->height); 8348c2ecf20Sopenharmony_ci __v4l2_ctrl_s_ctrl(imx219->vblank, 8358c2ecf20Sopenharmony_ci mode->vts_def - mode->height); 8368c2ecf20Sopenharmony_ci /* Update max exposure while meeting expected vblanking */ 8378c2ecf20Sopenharmony_ci exposure_max = mode->vts_def - 4; 8388c2ecf20Sopenharmony_ci exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? 8398c2ecf20Sopenharmony_ci exposure_max : IMX219_EXPOSURE_DEFAULT; 8408c2ecf20Sopenharmony_ci __v4l2_ctrl_modify_range(imx219->exposure, 8418c2ecf20Sopenharmony_ci imx219->exposure->minimum, 8428c2ecf20Sopenharmony_ci exposure_max, imx219->exposure->step, 8438c2ecf20Sopenharmony_ci exposure_def); 8448c2ecf20Sopenharmony_ci /* 8458c2ecf20Sopenharmony_ci * Currently PPL is fixed to IMX219_PPL_DEFAULT, so hblank 8468c2ecf20Sopenharmony_ci * depends on mode->width only, and is not changeble in any 8478c2ecf20Sopenharmony_ci * way other than changing the mode. 8488c2ecf20Sopenharmony_ci */ 8498c2ecf20Sopenharmony_ci hblank = IMX219_PPL_DEFAULT - mode->width; 8508c2ecf20Sopenharmony_ci __v4l2_ctrl_modify_range(imx219->hblank, hblank, hblank, 1, 8518c2ecf20Sopenharmony_ci hblank); 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci mutex_unlock(&imx219->mutex); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci return 0; 8578c2ecf20Sopenharmony_ci} 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_cistatic int imx219_set_framefmt(struct imx219 *imx219) 8608c2ecf20Sopenharmony_ci{ 8618c2ecf20Sopenharmony_ci switch (imx219->fmt.code) { 8628c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SRGGB8_1X8: 8638c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SGRBG8_1X8: 8648c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SGBRG8_1X8: 8658c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SBGGR8_1X8: 8668c2ecf20Sopenharmony_ci return imx219_write_regs(imx219, raw8_framefmt_regs, 8678c2ecf20Sopenharmony_ci ARRAY_SIZE(raw8_framefmt_regs)); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SRGGB10_1X10: 8708c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SGRBG10_1X10: 8718c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SGBRG10_1X10: 8728c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SBGGR10_1X10: 8738c2ecf20Sopenharmony_ci return imx219_write_regs(imx219, raw10_framefmt_regs, 8748c2ecf20Sopenharmony_ci ARRAY_SIZE(raw10_framefmt_regs)); 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci return -EINVAL; 8788c2ecf20Sopenharmony_ci} 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_cistatic int imx219_set_binning(struct imx219 *imx219) 8818c2ecf20Sopenharmony_ci{ 8828c2ecf20Sopenharmony_ci if (!imx219->mode->binning) { 8838c2ecf20Sopenharmony_ci return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE, 8848c2ecf20Sopenharmony_ci IMX219_REG_VALUE_16BIT, 8858c2ecf20Sopenharmony_ci IMX219_BINNING_NONE); 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci switch (imx219->fmt.code) { 8898c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SRGGB8_1X8: 8908c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SGRBG8_1X8: 8918c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SGBRG8_1X8: 8928c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SBGGR8_1X8: 8938c2ecf20Sopenharmony_ci return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE, 8948c2ecf20Sopenharmony_ci IMX219_REG_VALUE_16BIT, 8958c2ecf20Sopenharmony_ci IMX219_BINNING_2X2_ANALOG); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SRGGB10_1X10: 8988c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SGRBG10_1X10: 8998c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SGBRG10_1X10: 9008c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SBGGR10_1X10: 9018c2ecf20Sopenharmony_ci return imx219_write_reg(imx219, IMX219_REG_BINNING_MODE, 9028c2ecf20Sopenharmony_ci IMX219_REG_VALUE_16BIT, 9038c2ecf20Sopenharmony_ci IMX219_BINNING_2X2); 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci return -EINVAL; 9078c2ecf20Sopenharmony_ci} 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_cistatic const struct v4l2_rect * 9108c2ecf20Sopenharmony_ci__imx219_get_pad_crop(struct imx219 *imx219, struct v4l2_subdev_pad_config *cfg, 9118c2ecf20Sopenharmony_ci unsigned int pad, enum v4l2_subdev_format_whence which) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci switch (which) { 9148c2ecf20Sopenharmony_ci case V4L2_SUBDEV_FORMAT_TRY: 9158c2ecf20Sopenharmony_ci return v4l2_subdev_get_try_crop(&imx219->sd, cfg, pad); 9168c2ecf20Sopenharmony_ci case V4L2_SUBDEV_FORMAT_ACTIVE: 9178c2ecf20Sopenharmony_ci return &imx219->mode->crop; 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci return NULL; 9218c2ecf20Sopenharmony_ci} 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_cistatic int imx219_get_selection(struct v4l2_subdev *sd, 9248c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 9258c2ecf20Sopenharmony_ci struct v4l2_subdev_selection *sel) 9268c2ecf20Sopenharmony_ci{ 9278c2ecf20Sopenharmony_ci switch (sel->target) { 9288c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_CROP: { 9298c2ecf20Sopenharmony_ci struct imx219 *imx219 = to_imx219(sd); 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci mutex_lock(&imx219->mutex); 9328c2ecf20Sopenharmony_ci sel->r = *__imx219_get_pad_crop(imx219, cfg, sel->pad, 9338c2ecf20Sopenharmony_ci sel->which); 9348c2ecf20Sopenharmony_ci mutex_unlock(&imx219->mutex); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci return 0; 9378c2ecf20Sopenharmony_ci } 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_NATIVE_SIZE: 9408c2ecf20Sopenharmony_ci sel->r.top = 0; 9418c2ecf20Sopenharmony_ci sel->r.left = 0; 9428c2ecf20Sopenharmony_ci sel->r.width = IMX219_NATIVE_WIDTH; 9438c2ecf20Sopenharmony_ci sel->r.height = IMX219_NATIVE_HEIGHT; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci return 0; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_CROP_DEFAULT: 9488c2ecf20Sopenharmony_ci case V4L2_SEL_TGT_CROP_BOUNDS: 9498c2ecf20Sopenharmony_ci sel->r.top = IMX219_PIXEL_ARRAY_TOP; 9508c2ecf20Sopenharmony_ci sel->r.left = IMX219_PIXEL_ARRAY_LEFT; 9518c2ecf20Sopenharmony_ci sel->r.width = IMX219_PIXEL_ARRAY_WIDTH; 9528c2ecf20Sopenharmony_ci sel->r.height = IMX219_PIXEL_ARRAY_HEIGHT; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci return 0; 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci return -EINVAL; 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_cistatic int imx219_start_streaming(struct imx219 *imx219) 9618c2ecf20Sopenharmony_ci{ 9628c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); 9638c2ecf20Sopenharmony_ci const struct imx219_reg_list *reg_list; 9648c2ecf20Sopenharmony_ci int ret; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(&client->dev); 9678c2ecf20Sopenharmony_ci if (ret < 0) { 9688c2ecf20Sopenharmony_ci pm_runtime_put_noidle(&client->dev); 9698c2ecf20Sopenharmony_ci return ret; 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci /* Send all registers that are common to all modes */ 9738c2ecf20Sopenharmony_ci ret = imx219_write_regs(imx219, imx219_common_regs, ARRAY_SIZE(imx219_common_regs)); 9748c2ecf20Sopenharmony_ci if (ret) { 9758c2ecf20Sopenharmony_ci dev_err(&client->dev, "%s failed to send mfg header\n", __func__); 9768c2ecf20Sopenharmony_ci goto err_rpm_put; 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci /* Apply default values of current mode */ 9808c2ecf20Sopenharmony_ci reg_list = &imx219->mode->reg_list; 9818c2ecf20Sopenharmony_ci ret = imx219_write_regs(imx219, reg_list->regs, reg_list->num_of_regs); 9828c2ecf20Sopenharmony_ci if (ret) { 9838c2ecf20Sopenharmony_ci dev_err(&client->dev, "%s failed to set mode\n", __func__); 9848c2ecf20Sopenharmony_ci goto err_rpm_put; 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci ret = imx219_set_framefmt(imx219); 9888c2ecf20Sopenharmony_ci if (ret) { 9898c2ecf20Sopenharmony_ci dev_err(&client->dev, "%s failed to set frame format: %d\n", 9908c2ecf20Sopenharmony_ci __func__, ret); 9918c2ecf20Sopenharmony_ci goto err_rpm_put; 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci ret = imx219_set_binning(imx219); 9958c2ecf20Sopenharmony_ci if (ret) { 9968c2ecf20Sopenharmony_ci dev_err(&client->dev, "%s failed to set binning: %d\n", 9978c2ecf20Sopenharmony_ci __func__, ret); 9988c2ecf20Sopenharmony_ci goto err_rpm_put; 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci /* Apply customized values from user */ 10028c2ecf20Sopenharmony_ci ret = __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler); 10038c2ecf20Sopenharmony_ci if (ret) 10048c2ecf20Sopenharmony_ci goto err_rpm_put; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci /* set stream on register */ 10078c2ecf20Sopenharmony_ci ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT, 10088c2ecf20Sopenharmony_ci IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING); 10098c2ecf20Sopenharmony_ci if (ret) 10108c2ecf20Sopenharmony_ci goto err_rpm_put; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci /* vflip and hflip cannot change during streaming */ 10138c2ecf20Sopenharmony_ci __v4l2_ctrl_grab(imx219->vflip, true); 10148c2ecf20Sopenharmony_ci __v4l2_ctrl_grab(imx219->hflip, true); 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci return 0; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_cierr_rpm_put: 10198c2ecf20Sopenharmony_ci pm_runtime_put(&client->dev); 10208c2ecf20Sopenharmony_ci return ret; 10218c2ecf20Sopenharmony_ci} 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_cistatic void imx219_stop_streaming(struct imx219 *imx219) 10248c2ecf20Sopenharmony_ci{ 10258c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); 10268c2ecf20Sopenharmony_ci int ret; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci /* set stream off register */ 10298c2ecf20Sopenharmony_ci ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT, 10308c2ecf20Sopenharmony_ci IMX219_REG_VALUE_08BIT, IMX219_MODE_STANDBY); 10318c2ecf20Sopenharmony_ci if (ret) 10328c2ecf20Sopenharmony_ci dev_err(&client->dev, "%s failed to set stream\n", __func__); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci __v4l2_ctrl_grab(imx219->vflip, false); 10358c2ecf20Sopenharmony_ci __v4l2_ctrl_grab(imx219->hflip, false); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci pm_runtime_put(&client->dev); 10388c2ecf20Sopenharmony_ci} 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_cistatic int imx219_set_stream(struct v4l2_subdev *sd, int enable) 10418c2ecf20Sopenharmony_ci{ 10428c2ecf20Sopenharmony_ci struct imx219 *imx219 = to_imx219(sd); 10438c2ecf20Sopenharmony_ci int ret = 0; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci mutex_lock(&imx219->mutex); 10468c2ecf20Sopenharmony_ci if (imx219->streaming == enable) { 10478c2ecf20Sopenharmony_ci mutex_unlock(&imx219->mutex); 10488c2ecf20Sopenharmony_ci return 0; 10498c2ecf20Sopenharmony_ci } 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci if (enable) { 10528c2ecf20Sopenharmony_ci /* 10538c2ecf20Sopenharmony_ci * Apply default & customized values 10548c2ecf20Sopenharmony_ci * and then start streaming. 10558c2ecf20Sopenharmony_ci */ 10568c2ecf20Sopenharmony_ci ret = imx219_start_streaming(imx219); 10578c2ecf20Sopenharmony_ci if (ret) 10588c2ecf20Sopenharmony_ci goto err_unlock; 10598c2ecf20Sopenharmony_ci } else { 10608c2ecf20Sopenharmony_ci imx219_stop_streaming(imx219); 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci imx219->streaming = enable; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci mutex_unlock(&imx219->mutex); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci return ret; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_cierr_unlock: 10708c2ecf20Sopenharmony_ci mutex_unlock(&imx219->mutex); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci return ret; 10738c2ecf20Sopenharmony_ci} 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci/* Power/clock management functions */ 10768c2ecf20Sopenharmony_cistatic int imx219_power_on(struct device *dev) 10778c2ecf20Sopenharmony_ci{ 10788c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 10798c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = i2c_get_clientdata(client); 10808c2ecf20Sopenharmony_ci struct imx219 *imx219 = to_imx219(sd); 10818c2ecf20Sopenharmony_ci int ret; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci ret = regulator_bulk_enable(IMX219_NUM_SUPPLIES, 10848c2ecf20Sopenharmony_ci imx219->supplies); 10858c2ecf20Sopenharmony_ci if (ret) { 10868c2ecf20Sopenharmony_ci dev_err(&client->dev, "%s: failed to enable regulators\n", 10878c2ecf20Sopenharmony_ci __func__); 10888c2ecf20Sopenharmony_ci return ret; 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci ret = clk_prepare_enable(imx219->xclk); 10928c2ecf20Sopenharmony_ci if (ret) { 10938c2ecf20Sopenharmony_ci dev_err(&client->dev, "%s: failed to enable clock\n", 10948c2ecf20Sopenharmony_ci __func__); 10958c2ecf20Sopenharmony_ci goto reg_off; 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(imx219->reset_gpio, 1); 10998c2ecf20Sopenharmony_ci usleep_range(IMX219_XCLR_MIN_DELAY_US, 11008c2ecf20Sopenharmony_ci IMX219_XCLR_MIN_DELAY_US + IMX219_XCLR_DELAY_RANGE_US); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci return 0; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_cireg_off: 11058c2ecf20Sopenharmony_ci regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies); 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci return ret; 11088c2ecf20Sopenharmony_ci} 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_cistatic int imx219_power_off(struct device *dev) 11118c2ecf20Sopenharmony_ci{ 11128c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 11138c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = i2c_get_clientdata(client); 11148c2ecf20Sopenharmony_ci struct imx219 *imx219 = to_imx219(sd); 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(imx219->reset_gpio, 0); 11178c2ecf20Sopenharmony_ci regulator_bulk_disable(IMX219_NUM_SUPPLIES, imx219->supplies); 11188c2ecf20Sopenharmony_ci clk_disable_unprepare(imx219->xclk); 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci return 0; 11218c2ecf20Sopenharmony_ci} 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_cistatic int __maybe_unused imx219_suspend(struct device *dev) 11248c2ecf20Sopenharmony_ci{ 11258c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 11268c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = i2c_get_clientdata(client); 11278c2ecf20Sopenharmony_ci struct imx219 *imx219 = to_imx219(sd); 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci if (imx219->streaming) 11308c2ecf20Sopenharmony_ci imx219_stop_streaming(imx219); 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci return 0; 11338c2ecf20Sopenharmony_ci} 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_cistatic int __maybe_unused imx219_resume(struct device *dev) 11368c2ecf20Sopenharmony_ci{ 11378c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 11388c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = i2c_get_clientdata(client); 11398c2ecf20Sopenharmony_ci struct imx219 *imx219 = to_imx219(sd); 11408c2ecf20Sopenharmony_ci int ret; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci if (imx219->streaming) { 11438c2ecf20Sopenharmony_ci ret = imx219_start_streaming(imx219); 11448c2ecf20Sopenharmony_ci if (ret) 11458c2ecf20Sopenharmony_ci goto error; 11468c2ecf20Sopenharmony_ci } 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci return 0; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_cierror: 11518c2ecf20Sopenharmony_ci imx219_stop_streaming(imx219); 11528c2ecf20Sopenharmony_ci imx219->streaming = false; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci return ret; 11558c2ecf20Sopenharmony_ci} 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_cistatic int imx219_get_regulators(struct imx219 *imx219) 11588c2ecf20Sopenharmony_ci{ 11598c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); 11608c2ecf20Sopenharmony_ci unsigned int i; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci for (i = 0; i < IMX219_NUM_SUPPLIES; i++) 11638c2ecf20Sopenharmony_ci imx219->supplies[i].supply = imx219_supply_name[i]; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci return devm_regulator_bulk_get(&client->dev, 11668c2ecf20Sopenharmony_ci IMX219_NUM_SUPPLIES, 11678c2ecf20Sopenharmony_ci imx219->supplies); 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci/* Verify chip ID */ 11718c2ecf20Sopenharmony_cistatic int imx219_identify_module(struct imx219 *imx219) 11728c2ecf20Sopenharmony_ci{ 11738c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); 11748c2ecf20Sopenharmony_ci int ret; 11758c2ecf20Sopenharmony_ci u32 val; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci ret = imx219_read_reg(imx219, IMX219_REG_CHIP_ID, 11788c2ecf20Sopenharmony_ci IMX219_REG_VALUE_16BIT, &val); 11798c2ecf20Sopenharmony_ci if (ret) { 11808c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to read chip id %x\n", 11818c2ecf20Sopenharmony_ci IMX219_CHIP_ID); 11828c2ecf20Sopenharmony_ci return ret; 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci if (val != IMX219_CHIP_ID) { 11868c2ecf20Sopenharmony_ci dev_err(&client->dev, "chip id mismatch: %x!=%x\n", 11878c2ecf20Sopenharmony_ci IMX219_CHIP_ID, val); 11888c2ecf20Sopenharmony_ci return -EIO; 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci return 0; 11928c2ecf20Sopenharmony_ci} 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_core_ops imx219_core_ops = { 11958c2ecf20Sopenharmony_ci .subscribe_event = v4l2_ctrl_subdev_subscribe_event, 11968c2ecf20Sopenharmony_ci .unsubscribe_event = v4l2_event_subdev_unsubscribe, 11978c2ecf20Sopenharmony_ci}; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_video_ops imx219_video_ops = { 12008c2ecf20Sopenharmony_ci .s_stream = imx219_set_stream, 12018c2ecf20Sopenharmony_ci}; 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_pad_ops imx219_pad_ops = { 12048c2ecf20Sopenharmony_ci .enum_mbus_code = imx219_enum_mbus_code, 12058c2ecf20Sopenharmony_ci .get_fmt = imx219_get_pad_format, 12068c2ecf20Sopenharmony_ci .set_fmt = imx219_set_pad_format, 12078c2ecf20Sopenharmony_ci .get_selection = imx219_get_selection, 12088c2ecf20Sopenharmony_ci .enum_frame_size = imx219_enum_frame_size, 12098c2ecf20Sopenharmony_ci}; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops imx219_subdev_ops = { 12128c2ecf20Sopenharmony_ci .core = &imx219_core_ops, 12138c2ecf20Sopenharmony_ci .video = &imx219_video_ops, 12148c2ecf20Sopenharmony_ci .pad = &imx219_pad_ops, 12158c2ecf20Sopenharmony_ci}; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_internal_ops imx219_internal_ops = { 12188c2ecf20Sopenharmony_ci .open = imx219_open, 12198c2ecf20Sopenharmony_ci}; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci/* Initialize control handlers */ 12228c2ecf20Sopenharmony_cistatic int imx219_init_controls(struct imx219 *imx219) 12238c2ecf20Sopenharmony_ci{ 12248c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); 12258c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler *ctrl_hdlr; 12268c2ecf20Sopenharmony_ci unsigned int height = imx219->mode->height; 12278c2ecf20Sopenharmony_ci struct v4l2_fwnode_device_properties props; 12288c2ecf20Sopenharmony_ci int exposure_max, exposure_def, hblank; 12298c2ecf20Sopenharmony_ci int i, ret; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci ctrl_hdlr = &imx219->ctrl_handler; 12328c2ecf20Sopenharmony_ci ret = v4l2_ctrl_handler_init(ctrl_hdlr, 11); 12338c2ecf20Sopenharmony_ci if (ret) 12348c2ecf20Sopenharmony_ci return ret; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci mutex_init(&imx219->mutex); 12378c2ecf20Sopenharmony_ci ctrl_hdlr->lock = &imx219->mutex; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci /* By default, PIXEL_RATE is read only */ 12408c2ecf20Sopenharmony_ci imx219->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, 12418c2ecf20Sopenharmony_ci V4L2_CID_PIXEL_RATE, 12428c2ecf20Sopenharmony_ci IMX219_PIXEL_RATE, 12438c2ecf20Sopenharmony_ci IMX219_PIXEL_RATE, 1, 12448c2ecf20Sopenharmony_ci IMX219_PIXEL_RATE); 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci /* Initial vblank/hblank/exposure parameters based on current mode */ 12478c2ecf20Sopenharmony_ci imx219->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, 12488c2ecf20Sopenharmony_ci V4L2_CID_VBLANK, IMX219_VBLANK_MIN, 12498c2ecf20Sopenharmony_ci IMX219_VTS_MAX - height, 1, 12508c2ecf20Sopenharmony_ci imx219->mode->vts_def - height); 12518c2ecf20Sopenharmony_ci hblank = IMX219_PPL_DEFAULT - imx219->mode->width; 12528c2ecf20Sopenharmony_ci imx219->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, 12538c2ecf20Sopenharmony_ci V4L2_CID_HBLANK, hblank, hblank, 12548c2ecf20Sopenharmony_ci 1, hblank); 12558c2ecf20Sopenharmony_ci if (imx219->hblank) 12568c2ecf20Sopenharmony_ci imx219->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; 12578c2ecf20Sopenharmony_ci exposure_max = imx219->mode->vts_def - 4; 12588c2ecf20Sopenharmony_ci exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? 12598c2ecf20Sopenharmony_ci exposure_max : IMX219_EXPOSURE_DEFAULT; 12608c2ecf20Sopenharmony_ci imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, 12618c2ecf20Sopenharmony_ci V4L2_CID_EXPOSURE, 12628c2ecf20Sopenharmony_ci IMX219_EXPOSURE_MIN, exposure_max, 12638c2ecf20Sopenharmony_ci IMX219_EXPOSURE_STEP, 12648c2ecf20Sopenharmony_ci exposure_def); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, 12678c2ecf20Sopenharmony_ci IMX219_ANA_GAIN_MIN, IMX219_ANA_GAIN_MAX, 12688c2ecf20Sopenharmony_ci IMX219_ANA_GAIN_STEP, IMX219_ANA_GAIN_DEFAULT); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_DIGITAL_GAIN, 12718c2ecf20Sopenharmony_ci IMX219_DGTL_GAIN_MIN, IMX219_DGTL_GAIN_MAX, 12728c2ecf20Sopenharmony_ci IMX219_DGTL_GAIN_STEP, IMX219_DGTL_GAIN_DEFAULT); 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci imx219->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, 12758c2ecf20Sopenharmony_ci V4L2_CID_HFLIP, 0, 1, 1, 0); 12768c2ecf20Sopenharmony_ci if (imx219->hflip) 12778c2ecf20Sopenharmony_ci imx219->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci imx219->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, 12808c2ecf20Sopenharmony_ci V4L2_CID_VFLIP, 0, 1, 1, 0); 12818c2ecf20Sopenharmony_ci if (imx219->vflip) 12828c2ecf20Sopenharmony_ci imx219->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx219_ctrl_ops, 12858c2ecf20Sopenharmony_ci V4L2_CID_TEST_PATTERN, 12868c2ecf20Sopenharmony_ci ARRAY_SIZE(imx219_test_pattern_menu) - 1, 12878c2ecf20Sopenharmony_ci 0, 0, imx219_test_pattern_menu); 12888c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 12898c2ecf20Sopenharmony_ci /* 12908c2ecf20Sopenharmony_ci * The assumption is that 12918c2ecf20Sopenharmony_ci * V4L2_CID_TEST_PATTERN_GREENR == V4L2_CID_TEST_PATTERN_RED + 1 12928c2ecf20Sopenharmony_ci * V4L2_CID_TEST_PATTERN_BLUE == V4L2_CID_TEST_PATTERN_RED + 2 12938c2ecf20Sopenharmony_ci * V4L2_CID_TEST_PATTERN_GREENB == V4L2_CID_TEST_PATTERN_RED + 3 12948c2ecf20Sopenharmony_ci */ 12958c2ecf20Sopenharmony_ci v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, 12968c2ecf20Sopenharmony_ci V4L2_CID_TEST_PATTERN_RED + i, 12978c2ecf20Sopenharmony_ci IMX219_TESTP_COLOUR_MIN, 12988c2ecf20Sopenharmony_ci IMX219_TESTP_COLOUR_MAX, 12998c2ecf20Sopenharmony_ci IMX219_TESTP_COLOUR_STEP, 13008c2ecf20Sopenharmony_ci IMX219_TESTP_COLOUR_MAX); 13018c2ecf20Sopenharmony_ci /* The "Solid color" pattern is white by default */ 13028c2ecf20Sopenharmony_ci } 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci if (ctrl_hdlr->error) { 13058c2ecf20Sopenharmony_ci ret = ctrl_hdlr->error; 13068c2ecf20Sopenharmony_ci dev_err(&client->dev, "%s control init failed (%d)\n", 13078c2ecf20Sopenharmony_ci __func__, ret); 13088c2ecf20Sopenharmony_ci goto error; 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci ret = v4l2_fwnode_device_parse(&client->dev, &props); 13128c2ecf20Sopenharmony_ci if (ret) 13138c2ecf20Sopenharmony_ci goto error; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx219_ctrl_ops, 13168c2ecf20Sopenharmony_ci &props); 13178c2ecf20Sopenharmony_ci if (ret) 13188c2ecf20Sopenharmony_ci goto error; 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci imx219->sd.ctrl_handler = ctrl_hdlr; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci return 0; 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_cierror: 13258c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(ctrl_hdlr); 13268c2ecf20Sopenharmony_ci mutex_destroy(&imx219->mutex); 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci return ret; 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_cistatic void imx219_free_controls(struct imx219 *imx219) 13328c2ecf20Sopenharmony_ci{ 13338c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(imx219->sd.ctrl_handler); 13348c2ecf20Sopenharmony_ci mutex_destroy(&imx219->mutex); 13358c2ecf20Sopenharmony_ci} 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_cistatic int imx219_check_hwcfg(struct device *dev) 13388c2ecf20Sopenharmony_ci{ 13398c2ecf20Sopenharmony_ci struct fwnode_handle *endpoint; 13408c2ecf20Sopenharmony_ci struct v4l2_fwnode_endpoint ep_cfg = { 13418c2ecf20Sopenharmony_ci .bus_type = V4L2_MBUS_CSI2_DPHY 13428c2ecf20Sopenharmony_ci }; 13438c2ecf20Sopenharmony_ci int ret = -EINVAL; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); 13468c2ecf20Sopenharmony_ci if (!endpoint) { 13478c2ecf20Sopenharmony_ci dev_err(dev, "endpoint node not found\n"); 13488c2ecf20Sopenharmony_ci return -EINVAL; 13498c2ecf20Sopenharmony_ci } 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) { 13528c2ecf20Sopenharmony_ci dev_err(dev, "could not parse endpoint\n"); 13538c2ecf20Sopenharmony_ci goto error_out; 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci /* Check the number of MIPI CSI2 data lanes */ 13578c2ecf20Sopenharmony_ci if (ep_cfg.bus.mipi_csi2.num_data_lanes != 2) { 13588c2ecf20Sopenharmony_ci dev_err(dev, "only 2 data lanes are currently supported\n"); 13598c2ecf20Sopenharmony_ci goto error_out; 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci /* Check the link frequency set in device tree */ 13638c2ecf20Sopenharmony_ci if (!ep_cfg.nr_of_link_frequencies) { 13648c2ecf20Sopenharmony_ci dev_err(dev, "link-frequency property not found in DT\n"); 13658c2ecf20Sopenharmony_ci goto error_out; 13668c2ecf20Sopenharmony_ci } 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci if (ep_cfg.nr_of_link_frequencies != 1 || 13698c2ecf20Sopenharmony_ci ep_cfg.link_frequencies[0] != IMX219_DEFAULT_LINK_FREQ) { 13708c2ecf20Sopenharmony_ci dev_err(dev, "Link frequency not supported: %lld\n", 13718c2ecf20Sopenharmony_ci ep_cfg.link_frequencies[0]); 13728c2ecf20Sopenharmony_ci goto error_out; 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci ret = 0; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_cierror_out: 13788c2ecf20Sopenharmony_ci v4l2_fwnode_endpoint_free(&ep_cfg); 13798c2ecf20Sopenharmony_ci fwnode_handle_put(endpoint); 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci return ret; 13828c2ecf20Sopenharmony_ci} 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_cistatic int imx219_probe(struct i2c_client *client) 13858c2ecf20Sopenharmony_ci{ 13868c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 13878c2ecf20Sopenharmony_ci struct imx219 *imx219; 13888c2ecf20Sopenharmony_ci int ret; 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci imx219 = devm_kzalloc(&client->dev, sizeof(*imx219), GFP_KERNEL); 13918c2ecf20Sopenharmony_ci if (!imx219) 13928c2ecf20Sopenharmony_ci return -ENOMEM; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci v4l2_i2c_subdev_init(&imx219->sd, client, &imx219_subdev_ops); 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci /* Check the hardware configuration in device tree */ 13978c2ecf20Sopenharmony_ci if (imx219_check_hwcfg(dev)) 13988c2ecf20Sopenharmony_ci return -EINVAL; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci /* Get system clock (xclk) */ 14018c2ecf20Sopenharmony_ci imx219->xclk = devm_clk_get(dev, NULL); 14028c2ecf20Sopenharmony_ci if (IS_ERR(imx219->xclk)) { 14038c2ecf20Sopenharmony_ci dev_err(dev, "failed to get xclk\n"); 14048c2ecf20Sopenharmony_ci return PTR_ERR(imx219->xclk); 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci imx219->xclk_freq = clk_get_rate(imx219->xclk); 14088c2ecf20Sopenharmony_ci if (imx219->xclk_freq != IMX219_XCLK_FREQ) { 14098c2ecf20Sopenharmony_ci dev_err(dev, "xclk frequency not supported: %d Hz\n", 14108c2ecf20Sopenharmony_ci imx219->xclk_freq); 14118c2ecf20Sopenharmony_ci return -EINVAL; 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci ret = imx219_get_regulators(imx219); 14158c2ecf20Sopenharmony_ci if (ret) { 14168c2ecf20Sopenharmony_ci dev_err(dev, "failed to get regulators\n"); 14178c2ecf20Sopenharmony_ci return ret; 14188c2ecf20Sopenharmony_ci } 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci /* Request optional enable pin */ 14218c2ecf20Sopenharmony_ci imx219->reset_gpio = devm_gpiod_get_optional(dev, "reset", 14228c2ecf20Sopenharmony_ci GPIOD_OUT_HIGH); 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci /* 14258c2ecf20Sopenharmony_ci * The sensor must be powered for imx219_identify_module() 14268c2ecf20Sopenharmony_ci * to be able to read the CHIP_ID register 14278c2ecf20Sopenharmony_ci */ 14288c2ecf20Sopenharmony_ci ret = imx219_power_on(dev); 14298c2ecf20Sopenharmony_ci if (ret) 14308c2ecf20Sopenharmony_ci return ret; 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci ret = imx219_identify_module(imx219); 14338c2ecf20Sopenharmony_ci if (ret) 14348c2ecf20Sopenharmony_ci goto error_power_off; 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci /* Set default mode to max resolution */ 14378c2ecf20Sopenharmony_ci imx219->mode = &supported_modes[0]; 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci /* sensor doesn't enter LP-11 state upon power up until and unless 14408c2ecf20Sopenharmony_ci * streaming is started, so upon power up switch the modes to: 14418c2ecf20Sopenharmony_ci * streaming -> standby 14428c2ecf20Sopenharmony_ci */ 14438c2ecf20Sopenharmony_ci ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT, 14448c2ecf20Sopenharmony_ci IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING); 14458c2ecf20Sopenharmony_ci if (ret < 0) 14468c2ecf20Sopenharmony_ci goto error_power_off; 14478c2ecf20Sopenharmony_ci usleep_range(100, 110); 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci /* put sensor back to standby mode */ 14508c2ecf20Sopenharmony_ci ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT, 14518c2ecf20Sopenharmony_ci IMX219_REG_VALUE_08BIT, IMX219_MODE_STANDBY); 14528c2ecf20Sopenharmony_ci if (ret < 0) 14538c2ecf20Sopenharmony_ci goto error_power_off; 14548c2ecf20Sopenharmony_ci usleep_range(100, 110); 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci ret = imx219_init_controls(imx219); 14578c2ecf20Sopenharmony_ci if (ret) 14588c2ecf20Sopenharmony_ci goto error_power_off; 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci /* Initialize subdev */ 14618c2ecf20Sopenharmony_ci imx219->sd.internal_ops = &imx219_internal_ops; 14628c2ecf20Sopenharmony_ci imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 14638c2ecf20Sopenharmony_ci imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci /* Initialize source pad */ 14668c2ecf20Sopenharmony_ci imx219->pad.flags = MEDIA_PAD_FL_SOURCE; 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci /* Initialize default format */ 14698c2ecf20Sopenharmony_ci imx219_set_default_format(imx219); 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci ret = media_entity_pads_init(&imx219->sd.entity, 1, &imx219->pad); 14728c2ecf20Sopenharmony_ci if (ret) { 14738c2ecf20Sopenharmony_ci dev_err(dev, "failed to init entity pads: %d\n", ret); 14748c2ecf20Sopenharmony_ci goto error_handler_free; 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci ret = v4l2_async_register_subdev_sensor_common(&imx219->sd); 14788c2ecf20Sopenharmony_ci if (ret < 0) { 14798c2ecf20Sopenharmony_ci dev_err(dev, "failed to register sensor sub-device: %d\n", ret); 14808c2ecf20Sopenharmony_ci goto error_media_entity; 14818c2ecf20Sopenharmony_ci } 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci /* Enable runtime PM and turn off the device */ 14848c2ecf20Sopenharmony_ci pm_runtime_set_active(dev); 14858c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 14868c2ecf20Sopenharmony_ci pm_runtime_idle(dev); 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci return 0; 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_cierror_media_entity: 14918c2ecf20Sopenharmony_ci media_entity_cleanup(&imx219->sd.entity); 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_cierror_handler_free: 14948c2ecf20Sopenharmony_ci imx219_free_controls(imx219); 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_cierror_power_off: 14978c2ecf20Sopenharmony_ci imx219_power_off(dev); 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci return ret; 15008c2ecf20Sopenharmony_ci} 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_cistatic int imx219_remove(struct i2c_client *client) 15038c2ecf20Sopenharmony_ci{ 15048c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = i2c_get_clientdata(client); 15058c2ecf20Sopenharmony_ci struct imx219 *imx219 = to_imx219(sd); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci v4l2_async_unregister_subdev(sd); 15088c2ecf20Sopenharmony_ci media_entity_cleanup(&sd->entity); 15098c2ecf20Sopenharmony_ci imx219_free_controls(imx219); 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci pm_runtime_disable(&client->dev); 15128c2ecf20Sopenharmony_ci if (!pm_runtime_status_suspended(&client->dev)) 15138c2ecf20Sopenharmony_ci imx219_power_off(&client->dev); 15148c2ecf20Sopenharmony_ci pm_runtime_set_suspended(&client->dev); 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci return 0; 15178c2ecf20Sopenharmony_ci} 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_cistatic const struct of_device_id imx219_dt_ids[] = { 15208c2ecf20Sopenharmony_ci { .compatible = "sony,imx219" }, 15218c2ecf20Sopenharmony_ci { /* sentinel */ } 15228c2ecf20Sopenharmony_ci}; 15238c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, imx219_dt_ids); 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_cistatic const struct dev_pm_ops imx219_pm_ops = { 15268c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(imx219_suspend, imx219_resume) 15278c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(imx219_power_off, imx219_power_on, NULL) 15288c2ecf20Sopenharmony_ci}; 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_cistatic struct i2c_driver imx219_i2c_driver = { 15318c2ecf20Sopenharmony_ci .driver = { 15328c2ecf20Sopenharmony_ci .name = "imx219", 15338c2ecf20Sopenharmony_ci .of_match_table = imx219_dt_ids, 15348c2ecf20Sopenharmony_ci .pm = &imx219_pm_ops, 15358c2ecf20Sopenharmony_ci }, 15368c2ecf20Sopenharmony_ci .probe_new = imx219_probe, 15378c2ecf20Sopenharmony_ci .remove = imx219_remove, 15388c2ecf20Sopenharmony_ci}; 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_cimodule_i2c_driver(imx219_i2c_driver); 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ciMODULE_AUTHOR("Dave Stevenson <dave.stevenson@raspberrypi.com"); 15438c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Sony IMX219 sensor driver"); 15448c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1545