18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * camss-csid.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. 88c2ecf20Sopenharmony_ci * Copyright (C) 2015-2018 Linaro Ltd. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci#include <linux/clk.h> 118c2ecf20Sopenharmony_ci#include <linux/completion.h> 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci#include <linux/io.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/of.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 178c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 188c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 198c2ecf20Sopenharmony_ci#include <media/media-entity.h> 208c2ecf20Sopenharmony_ci#include <media/v4l2-device.h> 218c2ecf20Sopenharmony_ci#include <media/v4l2-event.h> 228c2ecf20Sopenharmony_ci#include <media/v4l2-subdev.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "camss-csid.h" 258c2ecf20Sopenharmony_ci#include "camss.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define MSM_CSID_NAME "msm_csid" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define CAMSS_CSID_HW_VERSION 0x0 308c2ecf20Sopenharmony_ci#define CAMSS_CSID_CORE_CTRL_0 0x004 318c2ecf20Sopenharmony_ci#define CAMSS_CSID_CORE_CTRL_1 0x008 328c2ecf20Sopenharmony_ci#define CAMSS_CSID_RST_CMD(v) ((v) == CAMSS_8x16 ? 0x00c : 0x010) 338c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_LUT_VC_n(v, n) \ 348c2ecf20Sopenharmony_ci (((v) == CAMSS_8x16 ? 0x010 : 0x014) + 0x4 * (n)) 358c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_n_CFG(v, n) \ 368c2ecf20Sopenharmony_ci (((v) == CAMSS_8x16 ? 0x020 : 0x024) + 0x4 * (n)) 378c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_n_CFG_ISPIF_EN BIT(0) 388c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_n_CFG_RDI_EN BIT(1) 398c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT 4 408c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8 (0 << 8) 418c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16 (1 << 8) 428c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB (0 << 9) 438c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB (1 << 9) 448c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP (0 << 10) 458c2ecf20Sopenharmony_ci#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING (1 << 10) 468c2ecf20Sopenharmony_ci#define CAMSS_CSID_IRQ_CLEAR_CMD(v) ((v) == CAMSS_8x16 ? 0x060 : 0x064) 478c2ecf20Sopenharmony_ci#define CAMSS_CSID_IRQ_MASK(v) ((v) == CAMSS_8x16 ? 0x064 : 0x068) 488c2ecf20Sopenharmony_ci#define CAMSS_CSID_IRQ_STATUS(v) ((v) == CAMSS_8x16 ? 0x068 : 0x06c) 498c2ecf20Sopenharmony_ci#define CAMSS_CSID_TG_CTRL(v) ((v) == CAMSS_8x16 ? 0x0a0 : 0x0a8) 508c2ecf20Sopenharmony_ci#define CAMSS_CSID_TG_CTRL_DISABLE 0xa06436 518c2ecf20Sopenharmony_ci#define CAMSS_CSID_TG_CTRL_ENABLE 0xa06437 528c2ecf20Sopenharmony_ci#define CAMSS_CSID_TG_VC_CFG(v) ((v) == CAMSS_8x16 ? 0x0a4 : 0x0ac) 538c2ecf20Sopenharmony_ci#define CAMSS_CSID_TG_VC_CFG_H_BLANKING 0x3ff 548c2ecf20Sopenharmony_ci#define CAMSS_CSID_TG_VC_CFG_V_BLANKING 0x7f 558c2ecf20Sopenharmony_ci#define CAMSS_CSID_TG_DT_n_CGG_0(v, n) \ 568c2ecf20Sopenharmony_ci (((v) == CAMSS_8x16 ? 0x0ac : 0x0b4) + 0xc * (n)) 578c2ecf20Sopenharmony_ci#define CAMSS_CSID_TG_DT_n_CGG_1(v, n) \ 588c2ecf20Sopenharmony_ci (((v) == CAMSS_8x16 ? 0x0b0 : 0x0b8) + 0xc * (n)) 598c2ecf20Sopenharmony_ci#define CAMSS_CSID_TG_DT_n_CGG_2(v, n) \ 608c2ecf20Sopenharmony_ci (((v) == CAMSS_8x16 ? 0x0b4 : 0x0bc) + 0xc * (n)) 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define DATA_TYPE_EMBEDDED_DATA_8BIT 0x12 638c2ecf20Sopenharmony_ci#define DATA_TYPE_YUV422_8BIT 0x1e 648c2ecf20Sopenharmony_ci#define DATA_TYPE_RAW_6BIT 0x28 658c2ecf20Sopenharmony_ci#define DATA_TYPE_RAW_8BIT 0x2a 668c2ecf20Sopenharmony_ci#define DATA_TYPE_RAW_10BIT 0x2b 678c2ecf20Sopenharmony_ci#define DATA_TYPE_RAW_12BIT 0x2c 688c2ecf20Sopenharmony_ci#define DATA_TYPE_RAW_14BIT 0x2d 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#define DECODE_FORMAT_UNCOMPRESSED_6_BIT 0x0 718c2ecf20Sopenharmony_ci#define DECODE_FORMAT_UNCOMPRESSED_8_BIT 0x1 728c2ecf20Sopenharmony_ci#define DECODE_FORMAT_UNCOMPRESSED_10_BIT 0x2 738c2ecf20Sopenharmony_ci#define DECODE_FORMAT_UNCOMPRESSED_12_BIT 0x3 748c2ecf20Sopenharmony_ci#define DECODE_FORMAT_UNCOMPRESSED_14_BIT 0x8 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define CSID_RESET_TIMEOUT_MS 500 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistruct csid_format { 798c2ecf20Sopenharmony_ci u32 code; 808c2ecf20Sopenharmony_ci u8 data_type; 818c2ecf20Sopenharmony_ci u8 decode_format; 828c2ecf20Sopenharmony_ci u8 bpp; 838c2ecf20Sopenharmony_ci u8 spp; /* bus samples per pixel */ 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic const struct csid_format csid_formats_8x16[] = { 878c2ecf20Sopenharmony_ci { 888c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_UYVY8_2X8, 898c2ecf20Sopenharmony_ci DATA_TYPE_YUV422_8BIT, 908c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_8_BIT, 918c2ecf20Sopenharmony_ci 8, 928c2ecf20Sopenharmony_ci 2, 938c2ecf20Sopenharmony_ci }, 948c2ecf20Sopenharmony_ci { 958c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_VYUY8_2X8, 968c2ecf20Sopenharmony_ci DATA_TYPE_YUV422_8BIT, 978c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_8_BIT, 988c2ecf20Sopenharmony_ci 8, 998c2ecf20Sopenharmony_ci 2, 1008c2ecf20Sopenharmony_ci }, 1018c2ecf20Sopenharmony_ci { 1028c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_YUYV8_2X8, 1038c2ecf20Sopenharmony_ci DATA_TYPE_YUV422_8BIT, 1048c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_8_BIT, 1058c2ecf20Sopenharmony_ci 8, 1068c2ecf20Sopenharmony_ci 2, 1078c2ecf20Sopenharmony_ci }, 1088c2ecf20Sopenharmony_ci { 1098c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_YVYU8_2X8, 1108c2ecf20Sopenharmony_ci DATA_TYPE_YUV422_8BIT, 1118c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_8_BIT, 1128c2ecf20Sopenharmony_ci 8, 1138c2ecf20Sopenharmony_ci 2, 1148c2ecf20Sopenharmony_ci }, 1158c2ecf20Sopenharmony_ci { 1168c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SBGGR8_1X8, 1178c2ecf20Sopenharmony_ci DATA_TYPE_RAW_8BIT, 1188c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_8_BIT, 1198c2ecf20Sopenharmony_ci 8, 1208c2ecf20Sopenharmony_ci 1, 1218c2ecf20Sopenharmony_ci }, 1228c2ecf20Sopenharmony_ci { 1238c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGBRG8_1X8, 1248c2ecf20Sopenharmony_ci DATA_TYPE_RAW_8BIT, 1258c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_8_BIT, 1268c2ecf20Sopenharmony_ci 8, 1278c2ecf20Sopenharmony_ci 1, 1288c2ecf20Sopenharmony_ci }, 1298c2ecf20Sopenharmony_ci { 1308c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGRBG8_1X8, 1318c2ecf20Sopenharmony_ci DATA_TYPE_RAW_8BIT, 1328c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_8_BIT, 1338c2ecf20Sopenharmony_ci 8, 1348c2ecf20Sopenharmony_ci 1, 1358c2ecf20Sopenharmony_ci }, 1368c2ecf20Sopenharmony_ci { 1378c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SRGGB8_1X8, 1388c2ecf20Sopenharmony_ci DATA_TYPE_RAW_8BIT, 1398c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_8_BIT, 1408c2ecf20Sopenharmony_ci 8, 1418c2ecf20Sopenharmony_ci 1, 1428c2ecf20Sopenharmony_ci }, 1438c2ecf20Sopenharmony_ci { 1448c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SBGGR10_1X10, 1458c2ecf20Sopenharmony_ci DATA_TYPE_RAW_10BIT, 1468c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_10_BIT, 1478c2ecf20Sopenharmony_ci 10, 1488c2ecf20Sopenharmony_ci 1, 1498c2ecf20Sopenharmony_ci }, 1508c2ecf20Sopenharmony_ci { 1518c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGBRG10_1X10, 1528c2ecf20Sopenharmony_ci DATA_TYPE_RAW_10BIT, 1538c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_10_BIT, 1548c2ecf20Sopenharmony_ci 10, 1558c2ecf20Sopenharmony_ci 1, 1568c2ecf20Sopenharmony_ci }, 1578c2ecf20Sopenharmony_ci { 1588c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGRBG10_1X10, 1598c2ecf20Sopenharmony_ci DATA_TYPE_RAW_10BIT, 1608c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_10_BIT, 1618c2ecf20Sopenharmony_ci 10, 1628c2ecf20Sopenharmony_ci 1, 1638c2ecf20Sopenharmony_ci }, 1648c2ecf20Sopenharmony_ci { 1658c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SRGGB10_1X10, 1668c2ecf20Sopenharmony_ci DATA_TYPE_RAW_10BIT, 1678c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_10_BIT, 1688c2ecf20Sopenharmony_ci 10, 1698c2ecf20Sopenharmony_ci 1, 1708c2ecf20Sopenharmony_ci }, 1718c2ecf20Sopenharmony_ci { 1728c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SBGGR12_1X12, 1738c2ecf20Sopenharmony_ci DATA_TYPE_RAW_12BIT, 1748c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_12_BIT, 1758c2ecf20Sopenharmony_ci 12, 1768c2ecf20Sopenharmony_ci 1, 1778c2ecf20Sopenharmony_ci }, 1788c2ecf20Sopenharmony_ci { 1798c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGBRG12_1X12, 1808c2ecf20Sopenharmony_ci DATA_TYPE_RAW_12BIT, 1818c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_12_BIT, 1828c2ecf20Sopenharmony_ci 12, 1838c2ecf20Sopenharmony_ci 1, 1848c2ecf20Sopenharmony_ci }, 1858c2ecf20Sopenharmony_ci { 1868c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGRBG12_1X12, 1878c2ecf20Sopenharmony_ci DATA_TYPE_RAW_12BIT, 1888c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_12_BIT, 1898c2ecf20Sopenharmony_ci 12, 1908c2ecf20Sopenharmony_ci 1, 1918c2ecf20Sopenharmony_ci }, 1928c2ecf20Sopenharmony_ci { 1938c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SRGGB12_1X12, 1948c2ecf20Sopenharmony_ci DATA_TYPE_RAW_12BIT, 1958c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_12_BIT, 1968c2ecf20Sopenharmony_ci 12, 1978c2ecf20Sopenharmony_ci 1, 1988c2ecf20Sopenharmony_ci }, 1998c2ecf20Sopenharmony_ci { 2008c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_Y10_1X10, 2018c2ecf20Sopenharmony_ci DATA_TYPE_RAW_10BIT, 2028c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_10_BIT, 2038c2ecf20Sopenharmony_ci 10, 2048c2ecf20Sopenharmony_ci 1, 2058c2ecf20Sopenharmony_ci }, 2068c2ecf20Sopenharmony_ci}; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic const struct csid_format csid_formats_8x96[] = { 2098c2ecf20Sopenharmony_ci { 2108c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_UYVY8_2X8, 2118c2ecf20Sopenharmony_ci DATA_TYPE_YUV422_8BIT, 2128c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_8_BIT, 2138c2ecf20Sopenharmony_ci 8, 2148c2ecf20Sopenharmony_ci 2, 2158c2ecf20Sopenharmony_ci }, 2168c2ecf20Sopenharmony_ci { 2178c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_VYUY8_2X8, 2188c2ecf20Sopenharmony_ci DATA_TYPE_YUV422_8BIT, 2198c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_8_BIT, 2208c2ecf20Sopenharmony_ci 8, 2218c2ecf20Sopenharmony_ci 2, 2228c2ecf20Sopenharmony_ci }, 2238c2ecf20Sopenharmony_ci { 2248c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_YUYV8_2X8, 2258c2ecf20Sopenharmony_ci DATA_TYPE_YUV422_8BIT, 2268c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_8_BIT, 2278c2ecf20Sopenharmony_ci 8, 2288c2ecf20Sopenharmony_ci 2, 2298c2ecf20Sopenharmony_ci }, 2308c2ecf20Sopenharmony_ci { 2318c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_YVYU8_2X8, 2328c2ecf20Sopenharmony_ci DATA_TYPE_YUV422_8BIT, 2338c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_8_BIT, 2348c2ecf20Sopenharmony_ci 8, 2358c2ecf20Sopenharmony_ci 2, 2368c2ecf20Sopenharmony_ci }, 2378c2ecf20Sopenharmony_ci { 2388c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SBGGR8_1X8, 2398c2ecf20Sopenharmony_ci DATA_TYPE_RAW_8BIT, 2408c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_8_BIT, 2418c2ecf20Sopenharmony_ci 8, 2428c2ecf20Sopenharmony_ci 1, 2438c2ecf20Sopenharmony_ci }, 2448c2ecf20Sopenharmony_ci { 2458c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGBRG8_1X8, 2468c2ecf20Sopenharmony_ci DATA_TYPE_RAW_8BIT, 2478c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_8_BIT, 2488c2ecf20Sopenharmony_ci 8, 2498c2ecf20Sopenharmony_ci 1, 2508c2ecf20Sopenharmony_ci }, 2518c2ecf20Sopenharmony_ci { 2528c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGRBG8_1X8, 2538c2ecf20Sopenharmony_ci DATA_TYPE_RAW_8BIT, 2548c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_8_BIT, 2558c2ecf20Sopenharmony_ci 8, 2568c2ecf20Sopenharmony_ci 1, 2578c2ecf20Sopenharmony_ci }, 2588c2ecf20Sopenharmony_ci { 2598c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SRGGB8_1X8, 2608c2ecf20Sopenharmony_ci DATA_TYPE_RAW_8BIT, 2618c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_8_BIT, 2628c2ecf20Sopenharmony_ci 8, 2638c2ecf20Sopenharmony_ci 1, 2648c2ecf20Sopenharmony_ci }, 2658c2ecf20Sopenharmony_ci { 2668c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SBGGR10_1X10, 2678c2ecf20Sopenharmony_ci DATA_TYPE_RAW_10BIT, 2688c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_10_BIT, 2698c2ecf20Sopenharmony_ci 10, 2708c2ecf20Sopenharmony_ci 1, 2718c2ecf20Sopenharmony_ci }, 2728c2ecf20Sopenharmony_ci { 2738c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGBRG10_1X10, 2748c2ecf20Sopenharmony_ci DATA_TYPE_RAW_10BIT, 2758c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_10_BIT, 2768c2ecf20Sopenharmony_ci 10, 2778c2ecf20Sopenharmony_ci 1, 2788c2ecf20Sopenharmony_ci }, 2798c2ecf20Sopenharmony_ci { 2808c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGRBG10_1X10, 2818c2ecf20Sopenharmony_ci DATA_TYPE_RAW_10BIT, 2828c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_10_BIT, 2838c2ecf20Sopenharmony_ci 10, 2848c2ecf20Sopenharmony_ci 1, 2858c2ecf20Sopenharmony_ci }, 2868c2ecf20Sopenharmony_ci { 2878c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SRGGB10_1X10, 2888c2ecf20Sopenharmony_ci DATA_TYPE_RAW_10BIT, 2898c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_10_BIT, 2908c2ecf20Sopenharmony_ci 10, 2918c2ecf20Sopenharmony_ci 1, 2928c2ecf20Sopenharmony_ci }, 2938c2ecf20Sopenharmony_ci { 2948c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SBGGR12_1X12, 2958c2ecf20Sopenharmony_ci DATA_TYPE_RAW_12BIT, 2968c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_12_BIT, 2978c2ecf20Sopenharmony_ci 12, 2988c2ecf20Sopenharmony_ci 1, 2998c2ecf20Sopenharmony_ci }, 3008c2ecf20Sopenharmony_ci { 3018c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGBRG12_1X12, 3028c2ecf20Sopenharmony_ci DATA_TYPE_RAW_12BIT, 3038c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_12_BIT, 3048c2ecf20Sopenharmony_ci 12, 3058c2ecf20Sopenharmony_ci 1, 3068c2ecf20Sopenharmony_ci }, 3078c2ecf20Sopenharmony_ci { 3088c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGRBG12_1X12, 3098c2ecf20Sopenharmony_ci DATA_TYPE_RAW_12BIT, 3108c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_12_BIT, 3118c2ecf20Sopenharmony_ci 12, 3128c2ecf20Sopenharmony_ci 1, 3138c2ecf20Sopenharmony_ci }, 3148c2ecf20Sopenharmony_ci { 3158c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SRGGB12_1X12, 3168c2ecf20Sopenharmony_ci DATA_TYPE_RAW_12BIT, 3178c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_12_BIT, 3188c2ecf20Sopenharmony_ci 12, 3198c2ecf20Sopenharmony_ci 1, 3208c2ecf20Sopenharmony_ci }, 3218c2ecf20Sopenharmony_ci { 3228c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SBGGR14_1X14, 3238c2ecf20Sopenharmony_ci DATA_TYPE_RAW_14BIT, 3248c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_14_BIT, 3258c2ecf20Sopenharmony_ci 14, 3268c2ecf20Sopenharmony_ci 1, 3278c2ecf20Sopenharmony_ci }, 3288c2ecf20Sopenharmony_ci { 3298c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGBRG14_1X14, 3308c2ecf20Sopenharmony_ci DATA_TYPE_RAW_14BIT, 3318c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_14_BIT, 3328c2ecf20Sopenharmony_ci 14, 3338c2ecf20Sopenharmony_ci 1, 3348c2ecf20Sopenharmony_ci }, 3358c2ecf20Sopenharmony_ci { 3368c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGRBG14_1X14, 3378c2ecf20Sopenharmony_ci DATA_TYPE_RAW_14BIT, 3388c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_14_BIT, 3398c2ecf20Sopenharmony_ci 14, 3408c2ecf20Sopenharmony_ci 1, 3418c2ecf20Sopenharmony_ci }, 3428c2ecf20Sopenharmony_ci { 3438c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SRGGB14_1X14, 3448c2ecf20Sopenharmony_ci DATA_TYPE_RAW_14BIT, 3458c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_14_BIT, 3468c2ecf20Sopenharmony_ci 14, 3478c2ecf20Sopenharmony_ci 1, 3488c2ecf20Sopenharmony_ci }, 3498c2ecf20Sopenharmony_ci { 3508c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_Y10_1X10, 3518c2ecf20Sopenharmony_ci DATA_TYPE_RAW_10BIT, 3528c2ecf20Sopenharmony_ci DECODE_FORMAT_UNCOMPRESSED_10_BIT, 3538c2ecf20Sopenharmony_ci 10, 3548c2ecf20Sopenharmony_ci 1, 3558c2ecf20Sopenharmony_ci }, 3568c2ecf20Sopenharmony_ci}; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic u32 csid_find_code(u32 *code, unsigned int n_code, 3598c2ecf20Sopenharmony_ci unsigned int index, u32 req_code) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci int i; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (!req_code && (index >= n_code)) 3648c2ecf20Sopenharmony_ci return 0; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci for (i = 0; i < n_code; i++) 3678c2ecf20Sopenharmony_ci if (req_code) { 3688c2ecf20Sopenharmony_ci if (req_code == code[i]) 3698c2ecf20Sopenharmony_ci return req_code; 3708c2ecf20Sopenharmony_ci } else { 3718c2ecf20Sopenharmony_ci if (i == index) 3728c2ecf20Sopenharmony_ci return code[i]; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci return code[0]; 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code, 3798c2ecf20Sopenharmony_ci unsigned int index, u32 src_req_code) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci if (csid->camss->version == CAMSS_8x16) { 3828c2ecf20Sopenharmony_ci if (index > 0) 3838c2ecf20Sopenharmony_ci return 0; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci return sink_code; 3868c2ecf20Sopenharmony_ci } else if (csid->camss->version == CAMSS_8x96) { 3878c2ecf20Sopenharmony_ci switch (sink_code) { 3888c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SBGGR10_1X10: 3898c2ecf20Sopenharmony_ci { 3908c2ecf20Sopenharmony_ci u32 src_code[] = { 3918c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SBGGR10_1X10, 3928c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, 3938c2ecf20Sopenharmony_ci }; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci return csid_find_code(src_code, ARRAY_SIZE(src_code), 3968c2ecf20Sopenharmony_ci index, src_req_code); 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_Y10_1X10: 3998c2ecf20Sopenharmony_ci { 4008c2ecf20Sopenharmony_ci u32 src_code[] = { 4018c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_Y10_1X10, 4028c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, 4038c2ecf20Sopenharmony_ci }; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci return csid_find_code(src_code, ARRAY_SIZE(src_code), 4068c2ecf20Sopenharmony_ci index, src_req_code); 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci default: 4098c2ecf20Sopenharmony_ci if (index > 0) 4108c2ecf20Sopenharmony_ci return 0; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci return sink_code; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci } else { 4158c2ecf20Sopenharmony_ci return 0; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cistatic const struct csid_format *csid_get_fmt_entry( 4208c2ecf20Sopenharmony_ci const struct csid_format *formats, 4218c2ecf20Sopenharmony_ci unsigned int nformat, 4228c2ecf20Sopenharmony_ci u32 code) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci unsigned int i; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci for (i = 0; i < nformat; i++) 4278c2ecf20Sopenharmony_ci if (code == formats[i].code) 4288c2ecf20Sopenharmony_ci return &formats[i]; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci WARN(1, "Unknown format\n"); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci return &formats[0]; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci/* 4368c2ecf20Sopenharmony_ci * csid_isr - CSID module interrupt handler 4378c2ecf20Sopenharmony_ci * @irq: Interrupt line 4388c2ecf20Sopenharmony_ci * @dev: CSID device 4398c2ecf20Sopenharmony_ci * 4408c2ecf20Sopenharmony_ci * Return IRQ_HANDLED on success 4418c2ecf20Sopenharmony_ci */ 4428c2ecf20Sopenharmony_cistatic irqreturn_t csid_isr(int irq, void *dev) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci struct csid_device *csid = dev; 4458c2ecf20Sopenharmony_ci enum camss_version ver = csid->camss->version; 4468c2ecf20Sopenharmony_ci u32 value; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS(ver)); 4498c2ecf20Sopenharmony_ci writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD(ver)); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if ((value >> 11) & 0x1) 4528c2ecf20Sopenharmony_ci complete(&csid->reset_complete); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci return IRQ_HANDLED; 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci/* 4588c2ecf20Sopenharmony_ci * csid_set_clock_rates - Calculate and set clock rates on CSID module 4598c2ecf20Sopenharmony_ci * @csiphy: CSID device 4608c2ecf20Sopenharmony_ci */ 4618c2ecf20Sopenharmony_cistatic int csid_set_clock_rates(struct csid_device *csid) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci struct device *dev = csid->camss->dev; 4648c2ecf20Sopenharmony_ci u32 pixel_clock; 4658c2ecf20Sopenharmony_ci int i, j; 4668c2ecf20Sopenharmony_ci int ret; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci ret = camss_get_pixel_clock(&csid->subdev.entity, &pixel_clock); 4698c2ecf20Sopenharmony_ci if (ret) 4708c2ecf20Sopenharmony_ci pixel_clock = 0; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci for (i = 0; i < csid->nclocks; i++) { 4738c2ecf20Sopenharmony_ci struct camss_clock *clock = &csid->clock[i]; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (!strcmp(clock->name, "csi0") || 4768c2ecf20Sopenharmony_ci !strcmp(clock->name, "csi1") || 4778c2ecf20Sopenharmony_ci !strcmp(clock->name, "csi2") || 4788c2ecf20Sopenharmony_ci !strcmp(clock->name, "csi3")) { 4798c2ecf20Sopenharmony_ci const struct csid_format *f = csid_get_fmt_entry( 4808c2ecf20Sopenharmony_ci csid->formats, 4818c2ecf20Sopenharmony_ci csid->nformats, 4828c2ecf20Sopenharmony_ci csid->fmt[MSM_CSIPHY_PAD_SINK].code); 4838c2ecf20Sopenharmony_ci u8 num_lanes = csid->phy.lane_cnt; 4848c2ecf20Sopenharmony_ci u64 min_rate = pixel_clock * f->bpp / 4858c2ecf20Sopenharmony_ci (2 * num_lanes * 4); 4868c2ecf20Sopenharmony_ci long rate; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci camss_add_clock_margin(&min_rate); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci for (j = 0; j < clock->nfreqs; j++) 4918c2ecf20Sopenharmony_ci if (min_rate < clock->freq[j]) 4928c2ecf20Sopenharmony_ci break; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (j == clock->nfreqs) { 4958c2ecf20Sopenharmony_ci dev_err(dev, 4968c2ecf20Sopenharmony_ci "Pixel clock is too high for CSID\n"); 4978c2ecf20Sopenharmony_ci return -EINVAL; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci /* if sensor pixel clock is not available */ 5018c2ecf20Sopenharmony_ci /* set highest possible CSID clock rate */ 5028c2ecf20Sopenharmony_ci if (min_rate == 0) 5038c2ecf20Sopenharmony_ci j = clock->nfreqs - 1; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci rate = clk_round_rate(clock->clk, clock->freq[j]); 5068c2ecf20Sopenharmony_ci if (rate < 0) { 5078c2ecf20Sopenharmony_ci dev_err(dev, "clk round rate failed: %ld\n", 5088c2ecf20Sopenharmony_ci rate); 5098c2ecf20Sopenharmony_ci return -EINVAL; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci ret = clk_set_rate(clock->clk, rate); 5138c2ecf20Sopenharmony_ci if (ret < 0) { 5148c2ecf20Sopenharmony_ci dev_err(dev, "clk set rate failed: %d\n", ret); 5158c2ecf20Sopenharmony_ci return ret; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci return 0; 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci/* 5248c2ecf20Sopenharmony_ci * csid_reset - Trigger reset on CSID module and wait to complete 5258c2ecf20Sopenharmony_ci * @csid: CSID device 5268c2ecf20Sopenharmony_ci * 5278c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise 5288c2ecf20Sopenharmony_ci */ 5298c2ecf20Sopenharmony_cistatic int csid_reset(struct csid_device *csid) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci unsigned long time; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci reinit_completion(&csid->reset_complete); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci writel_relaxed(0x7fff, csid->base + 5368c2ecf20Sopenharmony_ci CAMSS_CSID_RST_CMD(csid->camss->version)); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci time = wait_for_completion_timeout(&csid->reset_complete, 5398c2ecf20Sopenharmony_ci msecs_to_jiffies(CSID_RESET_TIMEOUT_MS)); 5408c2ecf20Sopenharmony_ci if (!time) { 5418c2ecf20Sopenharmony_ci dev_err(csid->camss->dev, "CSID reset timeout\n"); 5428c2ecf20Sopenharmony_ci return -EIO; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci return 0; 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci/* 5498c2ecf20Sopenharmony_ci * csid_set_power - Power on/off CSID module 5508c2ecf20Sopenharmony_ci * @sd: CSID V4L2 subdevice 5518c2ecf20Sopenharmony_ci * @on: Requested power state 5528c2ecf20Sopenharmony_ci * 5538c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise 5548c2ecf20Sopenharmony_ci */ 5558c2ecf20Sopenharmony_cistatic int csid_set_power(struct v4l2_subdev *sd, int on) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci struct csid_device *csid = v4l2_get_subdevdata(sd); 5588c2ecf20Sopenharmony_ci struct device *dev = csid->camss->dev; 5598c2ecf20Sopenharmony_ci int ret; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (on) { 5628c2ecf20Sopenharmony_ci u32 hw_version; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(dev); 5658c2ecf20Sopenharmony_ci if (ret < 0) { 5668c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev); 5678c2ecf20Sopenharmony_ci return ret; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci ret = regulator_enable(csid->vdda); 5718c2ecf20Sopenharmony_ci if (ret < 0) { 5728c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev); 5738c2ecf20Sopenharmony_ci return ret; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci ret = csid_set_clock_rates(csid); 5778c2ecf20Sopenharmony_ci if (ret < 0) { 5788c2ecf20Sopenharmony_ci regulator_disable(csid->vdda); 5798c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev); 5808c2ecf20Sopenharmony_ci return ret; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci ret = camss_enable_clocks(csid->nclocks, csid->clock, dev); 5848c2ecf20Sopenharmony_ci if (ret < 0) { 5858c2ecf20Sopenharmony_ci regulator_disable(csid->vdda); 5868c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev); 5878c2ecf20Sopenharmony_ci return ret; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci enable_irq(csid->irq); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci ret = csid_reset(csid); 5938c2ecf20Sopenharmony_ci if (ret < 0) { 5948c2ecf20Sopenharmony_ci disable_irq(csid->irq); 5958c2ecf20Sopenharmony_ci camss_disable_clocks(csid->nclocks, csid->clock); 5968c2ecf20Sopenharmony_ci regulator_disable(csid->vdda); 5978c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev); 5988c2ecf20Sopenharmony_ci return ret; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION); 6028c2ecf20Sopenharmony_ci dev_dbg(dev, "CSID HW Version = 0x%08x\n", hw_version); 6038c2ecf20Sopenharmony_ci } else { 6048c2ecf20Sopenharmony_ci disable_irq(csid->irq); 6058c2ecf20Sopenharmony_ci camss_disable_clocks(csid->nclocks, csid->clock); 6068c2ecf20Sopenharmony_ci ret = regulator_disable(csid->vdda); 6078c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev); 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci return ret; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci/* 6148c2ecf20Sopenharmony_ci * csid_set_stream - Enable/disable streaming on CSID module 6158c2ecf20Sopenharmony_ci * @sd: CSID V4L2 subdevice 6168c2ecf20Sopenharmony_ci * @enable: Requested streaming state 6178c2ecf20Sopenharmony_ci * 6188c2ecf20Sopenharmony_ci * Main configuration of CSID module is also done here. 6198c2ecf20Sopenharmony_ci * 6208c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise 6218c2ecf20Sopenharmony_ci */ 6228c2ecf20Sopenharmony_cistatic int csid_set_stream(struct v4l2_subdev *sd, int enable) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci struct csid_device *csid = v4l2_get_subdevdata(sd); 6258c2ecf20Sopenharmony_ci struct csid_testgen_config *tg = &csid->testgen; 6268c2ecf20Sopenharmony_ci enum camss_version ver = csid->camss->version; 6278c2ecf20Sopenharmony_ci u32 val; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (enable) { 6308c2ecf20Sopenharmony_ci u8 vc = 0; /* Virtual Channel 0 */ 6318c2ecf20Sopenharmony_ci u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */ 6328c2ecf20Sopenharmony_ci u8 dt, dt_shift, df; 6338c2ecf20Sopenharmony_ci int ret; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci ret = v4l2_ctrl_handler_setup(&csid->ctrls); 6368c2ecf20Sopenharmony_ci if (ret < 0) { 6378c2ecf20Sopenharmony_ci dev_err(csid->camss->dev, 6388c2ecf20Sopenharmony_ci "could not sync v4l2 controls: %d\n", ret); 6398c2ecf20Sopenharmony_ci return ret; 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (!tg->enabled && 6438c2ecf20Sopenharmony_ci !media_entity_remote_pad(&csid->pads[MSM_CSID_PAD_SINK])) 6448c2ecf20Sopenharmony_ci return -ENOLINK; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci if (tg->enabled) { 6478c2ecf20Sopenharmony_ci /* Config Test Generator */ 6488c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *f = 6498c2ecf20Sopenharmony_ci &csid->fmt[MSM_CSID_PAD_SRC]; 6508c2ecf20Sopenharmony_ci const struct csid_format *format = csid_get_fmt_entry( 6518c2ecf20Sopenharmony_ci csid->formats, csid->nformats, f->code); 6528c2ecf20Sopenharmony_ci u32 num_bytes_per_line = 6538c2ecf20Sopenharmony_ci f->width * format->bpp * format->spp / 8; 6548c2ecf20Sopenharmony_ci u32 num_lines = f->height; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci /* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */ 6578c2ecf20Sopenharmony_ci /* 1:0 VC */ 6588c2ecf20Sopenharmony_ci val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) | 6598c2ecf20Sopenharmony_ci ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13); 6608c2ecf20Sopenharmony_ci writel_relaxed(val, csid->base + 6618c2ecf20Sopenharmony_ci CAMSS_CSID_TG_VC_CFG(ver)); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci /* 28:16 bytes per lines, 12:0 num of lines */ 6648c2ecf20Sopenharmony_ci val = ((num_bytes_per_line & 0x1fff) << 16) | 6658c2ecf20Sopenharmony_ci (num_lines & 0x1fff); 6668c2ecf20Sopenharmony_ci writel_relaxed(val, csid->base + 6678c2ecf20Sopenharmony_ci CAMSS_CSID_TG_DT_n_CGG_0(ver, 0)); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci dt = format->data_type; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci /* 5:0 data type */ 6728c2ecf20Sopenharmony_ci val = dt; 6738c2ecf20Sopenharmony_ci writel_relaxed(val, csid->base + 6748c2ecf20Sopenharmony_ci CAMSS_CSID_TG_DT_n_CGG_1(ver, 0)); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci /* 2:0 output test pattern */ 6778c2ecf20Sopenharmony_ci val = tg->payload_mode; 6788c2ecf20Sopenharmony_ci writel_relaxed(val, csid->base + 6798c2ecf20Sopenharmony_ci CAMSS_CSID_TG_DT_n_CGG_2(ver, 0)); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci df = format->decode_format; 6828c2ecf20Sopenharmony_ci } else { 6838c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *f = 6848c2ecf20Sopenharmony_ci &csid->fmt[MSM_CSID_PAD_SINK]; 6858c2ecf20Sopenharmony_ci const struct csid_format *format = csid_get_fmt_entry( 6868c2ecf20Sopenharmony_ci csid->formats, csid->nformats, f->code); 6878c2ecf20Sopenharmony_ci struct csid_phy_config *phy = &csid->phy; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci val = phy->lane_cnt - 1; 6908c2ecf20Sopenharmony_ci val |= phy->lane_assign << 4; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci writel_relaxed(val, 6938c2ecf20Sopenharmony_ci csid->base + CAMSS_CSID_CORE_CTRL_0); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci val = phy->csiphy_id << 17; 6968c2ecf20Sopenharmony_ci val |= 0x9; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci writel_relaxed(val, 6998c2ecf20Sopenharmony_ci csid->base + CAMSS_CSID_CORE_CTRL_1); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci dt = format->data_type; 7028c2ecf20Sopenharmony_ci df = format->decode_format; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci /* Config LUT */ 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci dt_shift = (cid % 4) * 8; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci val = readl_relaxed(csid->base + 7108c2ecf20Sopenharmony_ci CAMSS_CSID_CID_LUT_VC_n(ver, vc)); 7118c2ecf20Sopenharmony_ci val &= ~(0xff << dt_shift); 7128c2ecf20Sopenharmony_ci val |= dt << dt_shift; 7138c2ecf20Sopenharmony_ci writel_relaxed(val, csid->base + 7148c2ecf20Sopenharmony_ci CAMSS_CSID_CID_LUT_VC_n(ver, vc)); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci val = CAMSS_CSID_CID_n_CFG_ISPIF_EN; 7178c2ecf20Sopenharmony_ci val |= CAMSS_CSID_CID_n_CFG_RDI_EN; 7188c2ecf20Sopenharmony_ci val |= df << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT; 7198c2ecf20Sopenharmony_ci val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (csid->camss->version == CAMSS_8x96) { 7228c2ecf20Sopenharmony_ci u32 sink_code = csid->fmt[MSM_CSID_PAD_SINK].code; 7238c2ecf20Sopenharmony_ci u32 src_code = csid->fmt[MSM_CSID_PAD_SRC].code; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci if ((sink_code == MEDIA_BUS_FMT_SBGGR10_1X10 && 7268c2ecf20Sopenharmony_ci src_code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) || 7278c2ecf20Sopenharmony_ci (sink_code == MEDIA_BUS_FMT_Y10_1X10 && 7288c2ecf20Sopenharmony_ci src_code == MEDIA_BUS_FMT_Y10_2X8_PADHI_LE)) { 7298c2ecf20Sopenharmony_ci val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING; 7308c2ecf20Sopenharmony_ci val |= CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16; 7318c2ecf20Sopenharmony_ci val |= CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci } 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci writel_relaxed(val, csid->base + 7368c2ecf20Sopenharmony_ci CAMSS_CSID_CID_n_CFG(ver, cid)); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci if (tg->enabled) { 7398c2ecf20Sopenharmony_ci val = CAMSS_CSID_TG_CTRL_ENABLE; 7408c2ecf20Sopenharmony_ci writel_relaxed(val, csid->base + 7418c2ecf20Sopenharmony_ci CAMSS_CSID_TG_CTRL(ver)); 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci } else { 7448c2ecf20Sopenharmony_ci if (tg->enabled) { 7458c2ecf20Sopenharmony_ci val = CAMSS_CSID_TG_CTRL_DISABLE; 7468c2ecf20Sopenharmony_ci writel_relaxed(val, csid->base + 7478c2ecf20Sopenharmony_ci CAMSS_CSID_TG_CTRL(ver)); 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci return 0; 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci/* 7558c2ecf20Sopenharmony_ci * __csid_get_format - Get pointer to format structure 7568c2ecf20Sopenharmony_ci * @csid: CSID device 7578c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration 7588c2ecf20Sopenharmony_ci * @pad: pad from which format is requested 7598c2ecf20Sopenharmony_ci * @which: TRY or ACTIVE format 7608c2ecf20Sopenharmony_ci * 7618c2ecf20Sopenharmony_ci * Return pointer to TRY or ACTIVE format structure 7628c2ecf20Sopenharmony_ci */ 7638c2ecf20Sopenharmony_cistatic struct v4l2_mbus_framefmt * 7648c2ecf20Sopenharmony_ci__csid_get_format(struct csid_device *csid, 7658c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 7668c2ecf20Sopenharmony_ci unsigned int pad, 7678c2ecf20Sopenharmony_ci enum v4l2_subdev_format_whence which) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci if (which == V4L2_SUBDEV_FORMAT_TRY) 7708c2ecf20Sopenharmony_ci return v4l2_subdev_get_try_format(&csid->subdev, cfg, pad); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci return &csid->fmt[pad]; 7738c2ecf20Sopenharmony_ci} 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci/* 7768c2ecf20Sopenharmony_ci * csid_try_format - Handle try format by pad subdev method 7778c2ecf20Sopenharmony_ci * @csid: CSID device 7788c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration 7798c2ecf20Sopenharmony_ci * @pad: pad on which format is requested 7808c2ecf20Sopenharmony_ci * @fmt: pointer to v4l2 format structure 7818c2ecf20Sopenharmony_ci * @which: wanted subdev format 7828c2ecf20Sopenharmony_ci */ 7838c2ecf20Sopenharmony_cistatic void csid_try_format(struct csid_device *csid, 7848c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 7858c2ecf20Sopenharmony_ci unsigned int pad, 7868c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *fmt, 7878c2ecf20Sopenharmony_ci enum v4l2_subdev_format_whence which) 7888c2ecf20Sopenharmony_ci{ 7898c2ecf20Sopenharmony_ci unsigned int i; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci switch (pad) { 7928c2ecf20Sopenharmony_ci case MSM_CSID_PAD_SINK: 7938c2ecf20Sopenharmony_ci /* Set format on sink pad */ 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci for (i = 0; i < csid->nformats; i++) 7968c2ecf20Sopenharmony_ci if (fmt->code == csid->formats[i].code) 7978c2ecf20Sopenharmony_ci break; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci /* If not found, use UYVY as default */ 8008c2ecf20Sopenharmony_ci if (i >= csid->nformats) 8018c2ecf20Sopenharmony_ci fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci fmt->width = clamp_t(u32, fmt->width, 1, 8191); 8048c2ecf20Sopenharmony_ci fmt->height = clamp_t(u32, fmt->height, 1, 8191); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci fmt->field = V4L2_FIELD_NONE; 8078c2ecf20Sopenharmony_ci fmt->colorspace = V4L2_COLORSPACE_SRGB; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci break; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci case MSM_CSID_PAD_SRC: 8128c2ecf20Sopenharmony_ci if (csid->testgen_mode->cur.val == 0) { 8138c2ecf20Sopenharmony_ci /* Test generator is disabled, */ 8148c2ecf20Sopenharmony_ci /* keep pad formats in sync */ 8158c2ecf20Sopenharmony_ci u32 code = fmt->code; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci *fmt = *__csid_get_format(csid, cfg, 8188c2ecf20Sopenharmony_ci MSM_CSID_PAD_SINK, which); 8198c2ecf20Sopenharmony_ci fmt->code = csid_src_pad_code(csid, fmt->code, 0, code); 8208c2ecf20Sopenharmony_ci } else { 8218c2ecf20Sopenharmony_ci /* Test generator is enabled, set format on source */ 8228c2ecf20Sopenharmony_ci /* pad to allow test generator usage */ 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci for (i = 0; i < csid->nformats; i++) 8258c2ecf20Sopenharmony_ci if (csid->formats[i].code == fmt->code) 8268c2ecf20Sopenharmony_ci break; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci /* If not found, use UYVY as default */ 8298c2ecf20Sopenharmony_ci if (i >= csid->nformats) 8308c2ecf20Sopenharmony_ci fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci fmt->width = clamp_t(u32, fmt->width, 1, 8191); 8338c2ecf20Sopenharmony_ci fmt->height = clamp_t(u32, fmt->height, 1, 8191); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci fmt->field = V4L2_FIELD_NONE; 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci break; 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci fmt->colorspace = V4L2_COLORSPACE_SRGB; 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci/* 8448c2ecf20Sopenharmony_ci * csid_enum_mbus_code - Handle pixel format enumeration 8458c2ecf20Sopenharmony_ci * @sd: CSID V4L2 subdevice 8468c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration 8478c2ecf20Sopenharmony_ci * @code: pointer to v4l2_subdev_mbus_code_enum structure 8488c2ecf20Sopenharmony_ci * return -EINVAL or zero on success 8498c2ecf20Sopenharmony_ci */ 8508c2ecf20Sopenharmony_cistatic int csid_enum_mbus_code(struct v4l2_subdev *sd, 8518c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 8528c2ecf20Sopenharmony_ci struct v4l2_subdev_mbus_code_enum *code) 8538c2ecf20Sopenharmony_ci{ 8548c2ecf20Sopenharmony_ci struct csid_device *csid = v4l2_get_subdevdata(sd); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci if (code->pad == MSM_CSID_PAD_SINK) { 8578c2ecf20Sopenharmony_ci if (code->index >= csid->nformats) 8588c2ecf20Sopenharmony_ci return -EINVAL; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci code->code = csid->formats[code->index].code; 8618c2ecf20Sopenharmony_ci } else { 8628c2ecf20Sopenharmony_ci if (csid->testgen_mode->cur.val == 0) { 8638c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *sink_fmt; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci sink_fmt = __csid_get_format(csid, cfg, 8668c2ecf20Sopenharmony_ci MSM_CSID_PAD_SINK, 8678c2ecf20Sopenharmony_ci code->which); 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci code->code = csid_src_pad_code(csid, sink_fmt->code, 8708c2ecf20Sopenharmony_ci code->index, 0); 8718c2ecf20Sopenharmony_ci if (!code->code) 8728c2ecf20Sopenharmony_ci return -EINVAL; 8738c2ecf20Sopenharmony_ci } else { 8748c2ecf20Sopenharmony_ci if (code->index >= csid->nformats) 8758c2ecf20Sopenharmony_ci return -EINVAL; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci code->code = csid->formats[code->index].code; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci return 0; 8828c2ecf20Sopenharmony_ci} 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci/* 8858c2ecf20Sopenharmony_ci * csid_enum_frame_size - Handle frame size enumeration 8868c2ecf20Sopenharmony_ci * @sd: CSID V4L2 subdevice 8878c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration 8888c2ecf20Sopenharmony_ci * @fse: pointer to v4l2_subdev_frame_size_enum structure 8898c2ecf20Sopenharmony_ci * return -EINVAL or zero on success 8908c2ecf20Sopenharmony_ci */ 8918c2ecf20Sopenharmony_cistatic int csid_enum_frame_size(struct v4l2_subdev *sd, 8928c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 8938c2ecf20Sopenharmony_ci struct v4l2_subdev_frame_size_enum *fse) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci struct csid_device *csid = v4l2_get_subdevdata(sd); 8968c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt format; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci if (fse->index != 0) 8998c2ecf20Sopenharmony_ci return -EINVAL; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci format.code = fse->code; 9028c2ecf20Sopenharmony_ci format.width = 1; 9038c2ecf20Sopenharmony_ci format.height = 1; 9048c2ecf20Sopenharmony_ci csid_try_format(csid, cfg, fse->pad, &format, fse->which); 9058c2ecf20Sopenharmony_ci fse->min_width = format.width; 9068c2ecf20Sopenharmony_ci fse->min_height = format.height; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci if (format.code != fse->code) 9098c2ecf20Sopenharmony_ci return -EINVAL; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci format.code = fse->code; 9128c2ecf20Sopenharmony_ci format.width = -1; 9138c2ecf20Sopenharmony_ci format.height = -1; 9148c2ecf20Sopenharmony_ci csid_try_format(csid, cfg, fse->pad, &format, fse->which); 9158c2ecf20Sopenharmony_ci fse->max_width = format.width; 9168c2ecf20Sopenharmony_ci fse->max_height = format.height; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci return 0; 9198c2ecf20Sopenharmony_ci} 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci/* 9228c2ecf20Sopenharmony_ci * csid_get_format - Handle get format by pads subdev method 9238c2ecf20Sopenharmony_ci * @sd: CSID V4L2 subdevice 9248c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration 9258c2ecf20Sopenharmony_ci * @fmt: pointer to v4l2 subdev format structure 9268c2ecf20Sopenharmony_ci * 9278c2ecf20Sopenharmony_ci * Return -EINVAL or zero on success 9288c2ecf20Sopenharmony_ci */ 9298c2ecf20Sopenharmony_cistatic int csid_get_format(struct v4l2_subdev *sd, 9308c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 9318c2ecf20Sopenharmony_ci struct v4l2_subdev_format *fmt) 9328c2ecf20Sopenharmony_ci{ 9338c2ecf20Sopenharmony_ci struct csid_device *csid = v4l2_get_subdevdata(sd); 9348c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *format; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci format = __csid_get_format(csid, cfg, fmt->pad, fmt->which); 9378c2ecf20Sopenharmony_ci if (format == NULL) 9388c2ecf20Sopenharmony_ci return -EINVAL; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci fmt->format = *format; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci return 0; 9438c2ecf20Sopenharmony_ci} 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci/* 9468c2ecf20Sopenharmony_ci * csid_set_format - Handle set format by pads subdev method 9478c2ecf20Sopenharmony_ci * @sd: CSID V4L2 subdevice 9488c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration 9498c2ecf20Sopenharmony_ci * @fmt: pointer to v4l2 subdev format structure 9508c2ecf20Sopenharmony_ci * 9518c2ecf20Sopenharmony_ci * Return -EINVAL or zero on success 9528c2ecf20Sopenharmony_ci */ 9538c2ecf20Sopenharmony_cistatic int csid_set_format(struct v4l2_subdev *sd, 9548c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 9558c2ecf20Sopenharmony_ci struct v4l2_subdev_format *fmt) 9568c2ecf20Sopenharmony_ci{ 9578c2ecf20Sopenharmony_ci struct csid_device *csid = v4l2_get_subdevdata(sd); 9588c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *format; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci format = __csid_get_format(csid, cfg, fmt->pad, fmt->which); 9618c2ecf20Sopenharmony_ci if (format == NULL) 9628c2ecf20Sopenharmony_ci return -EINVAL; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci csid_try_format(csid, cfg, fmt->pad, &fmt->format, fmt->which); 9658c2ecf20Sopenharmony_ci *format = fmt->format; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci /* Propagate the format from sink to source */ 9688c2ecf20Sopenharmony_ci if (fmt->pad == MSM_CSID_PAD_SINK) { 9698c2ecf20Sopenharmony_ci format = __csid_get_format(csid, cfg, MSM_CSID_PAD_SRC, 9708c2ecf20Sopenharmony_ci fmt->which); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci *format = fmt->format; 9738c2ecf20Sopenharmony_ci csid_try_format(csid, cfg, MSM_CSID_PAD_SRC, format, 9748c2ecf20Sopenharmony_ci fmt->which); 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci return 0; 9788c2ecf20Sopenharmony_ci} 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci/* 9818c2ecf20Sopenharmony_ci * csid_init_formats - Initialize formats on all pads 9828c2ecf20Sopenharmony_ci * @sd: CSID V4L2 subdevice 9838c2ecf20Sopenharmony_ci * @fh: V4L2 subdev file handle 9848c2ecf20Sopenharmony_ci * 9858c2ecf20Sopenharmony_ci * Initialize all pad formats with default values. 9868c2ecf20Sopenharmony_ci * 9878c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise 9888c2ecf20Sopenharmony_ci */ 9898c2ecf20Sopenharmony_cistatic int csid_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 9908c2ecf20Sopenharmony_ci{ 9918c2ecf20Sopenharmony_ci struct v4l2_subdev_format format = { 9928c2ecf20Sopenharmony_ci .pad = MSM_CSID_PAD_SINK, 9938c2ecf20Sopenharmony_ci .which = fh ? V4L2_SUBDEV_FORMAT_TRY : 9948c2ecf20Sopenharmony_ci V4L2_SUBDEV_FORMAT_ACTIVE, 9958c2ecf20Sopenharmony_ci .format = { 9968c2ecf20Sopenharmony_ci .code = MEDIA_BUS_FMT_UYVY8_2X8, 9978c2ecf20Sopenharmony_ci .width = 1920, 9988c2ecf20Sopenharmony_ci .height = 1080 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci }; 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci return csid_set_format(sd, fh ? fh->pad : NULL, &format); 10038c2ecf20Sopenharmony_ci} 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_cistatic const char * const csid_test_pattern_menu[] = { 10068c2ecf20Sopenharmony_ci "Disabled", 10078c2ecf20Sopenharmony_ci "Incrementing", 10088c2ecf20Sopenharmony_ci "Alternating 0x55/0xAA", 10098c2ecf20Sopenharmony_ci "All Zeros 0x00", 10108c2ecf20Sopenharmony_ci "All Ones 0xFF", 10118c2ecf20Sopenharmony_ci "Pseudo-random Data", 10128c2ecf20Sopenharmony_ci}; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci/* 10158c2ecf20Sopenharmony_ci * csid_set_test_pattern - Set test generator's pattern mode 10168c2ecf20Sopenharmony_ci * @csid: CSID device 10178c2ecf20Sopenharmony_ci * @value: desired test pattern mode 10188c2ecf20Sopenharmony_ci * 10198c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise 10208c2ecf20Sopenharmony_ci */ 10218c2ecf20Sopenharmony_cistatic int csid_set_test_pattern(struct csid_device *csid, s32 value) 10228c2ecf20Sopenharmony_ci{ 10238c2ecf20Sopenharmony_ci struct csid_testgen_config *tg = &csid->testgen; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci /* If CSID is linked to CSIPHY, do not allow to enable test generator */ 10268c2ecf20Sopenharmony_ci if (value && media_entity_remote_pad(&csid->pads[MSM_CSID_PAD_SINK])) 10278c2ecf20Sopenharmony_ci return -EBUSY; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci tg->enabled = !!value; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci switch (value) { 10328c2ecf20Sopenharmony_ci case 1: 10338c2ecf20Sopenharmony_ci tg->payload_mode = CSID_PAYLOAD_MODE_INCREMENTING; 10348c2ecf20Sopenharmony_ci break; 10358c2ecf20Sopenharmony_ci case 2: 10368c2ecf20Sopenharmony_ci tg->payload_mode = CSID_PAYLOAD_MODE_ALTERNATING_55_AA; 10378c2ecf20Sopenharmony_ci break; 10388c2ecf20Sopenharmony_ci case 3: 10398c2ecf20Sopenharmony_ci tg->payload_mode = CSID_PAYLOAD_MODE_ALL_ZEROES; 10408c2ecf20Sopenharmony_ci break; 10418c2ecf20Sopenharmony_ci case 4: 10428c2ecf20Sopenharmony_ci tg->payload_mode = CSID_PAYLOAD_MODE_ALL_ONES; 10438c2ecf20Sopenharmony_ci break; 10448c2ecf20Sopenharmony_ci case 5: 10458c2ecf20Sopenharmony_ci tg->payload_mode = CSID_PAYLOAD_MODE_RANDOM; 10468c2ecf20Sopenharmony_ci break; 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci return 0; 10508c2ecf20Sopenharmony_ci} 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci/* 10538c2ecf20Sopenharmony_ci * csid_s_ctrl - Handle set control subdev method 10548c2ecf20Sopenharmony_ci * @ctrl: pointer to v4l2 control structure 10558c2ecf20Sopenharmony_ci * 10568c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise 10578c2ecf20Sopenharmony_ci */ 10588c2ecf20Sopenharmony_cistatic int csid_s_ctrl(struct v4l2_ctrl *ctrl) 10598c2ecf20Sopenharmony_ci{ 10608c2ecf20Sopenharmony_ci struct csid_device *csid = container_of(ctrl->handler, 10618c2ecf20Sopenharmony_ci struct csid_device, ctrls); 10628c2ecf20Sopenharmony_ci int ret = -EINVAL; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci switch (ctrl->id) { 10658c2ecf20Sopenharmony_ci case V4L2_CID_TEST_PATTERN: 10668c2ecf20Sopenharmony_ci ret = csid_set_test_pattern(csid, ctrl->val); 10678c2ecf20Sopenharmony_ci break; 10688c2ecf20Sopenharmony_ci } 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci return ret; 10718c2ecf20Sopenharmony_ci} 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops csid_ctrl_ops = { 10748c2ecf20Sopenharmony_ci .s_ctrl = csid_s_ctrl, 10758c2ecf20Sopenharmony_ci}; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci/* 10788c2ecf20Sopenharmony_ci * msm_csid_subdev_init - Initialize CSID device structure and resources 10798c2ecf20Sopenharmony_ci * @csid: CSID device 10808c2ecf20Sopenharmony_ci * @res: CSID module resources table 10818c2ecf20Sopenharmony_ci * @id: CSID module id 10828c2ecf20Sopenharmony_ci * 10838c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise 10848c2ecf20Sopenharmony_ci */ 10858c2ecf20Sopenharmony_ciint msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, 10868c2ecf20Sopenharmony_ci const struct resources *res, u8 id) 10878c2ecf20Sopenharmony_ci{ 10888c2ecf20Sopenharmony_ci struct device *dev = camss->dev; 10898c2ecf20Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 10908c2ecf20Sopenharmony_ci struct resource *r; 10918c2ecf20Sopenharmony_ci int i, j; 10928c2ecf20Sopenharmony_ci int ret; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci csid->camss = camss; 10958c2ecf20Sopenharmony_ci csid->id = id; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci if (camss->version == CAMSS_8x16) { 10988c2ecf20Sopenharmony_ci csid->formats = csid_formats_8x16; 10998c2ecf20Sopenharmony_ci csid->nformats = 11008c2ecf20Sopenharmony_ci ARRAY_SIZE(csid_formats_8x16); 11018c2ecf20Sopenharmony_ci } else if (camss->version == CAMSS_8x96) { 11028c2ecf20Sopenharmony_ci csid->formats = csid_formats_8x96; 11038c2ecf20Sopenharmony_ci csid->nformats = 11048c2ecf20Sopenharmony_ci ARRAY_SIZE(csid_formats_8x96); 11058c2ecf20Sopenharmony_ci } else { 11068c2ecf20Sopenharmony_ci return -EINVAL; 11078c2ecf20Sopenharmony_ci } 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci /* Memory */ 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]); 11128c2ecf20Sopenharmony_ci csid->base = devm_ioremap_resource(dev, r); 11138c2ecf20Sopenharmony_ci if (IS_ERR(csid->base)) { 11148c2ecf20Sopenharmony_ci dev_err(dev, "could not map memory\n"); 11158c2ecf20Sopenharmony_ci return PTR_ERR(csid->base); 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci /* Interrupt */ 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, 11218c2ecf20Sopenharmony_ci res->interrupt[0]); 11228c2ecf20Sopenharmony_ci if (!r) { 11238c2ecf20Sopenharmony_ci dev_err(dev, "missing IRQ\n"); 11248c2ecf20Sopenharmony_ci return -EINVAL; 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci csid->irq = r->start; 11288c2ecf20Sopenharmony_ci snprintf(csid->irq_name, sizeof(csid->irq_name), "%s_%s%d", 11298c2ecf20Sopenharmony_ci dev_name(dev), MSM_CSID_NAME, csid->id); 11308c2ecf20Sopenharmony_ci ret = devm_request_irq(dev, csid->irq, csid_isr, 11318c2ecf20Sopenharmony_ci IRQF_TRIGGER_RISING, csid->irq_name, csid); 11328c2ecf20Sopenharmony_ci if (ret < 0) { 11338c2ecf20Sopenharmony_ci dev_err(dev, "request_irq failed: %d\n", ret); 11348c2ecf20Sopenharmony_ci return ret; 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci disable_irq(csid->irq); 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci /* Clocks */ 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci csid->nclocks = 0; 11428c2ecf20Sopenharmony_ci while (res->clock[csid->nclocks]) 11438c2ecf20Sopenharmony_ci csid->nclocks++; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci csid->clock = devm_kcalloc(dev, csid->nclocks, sizeof(*csid->clock), 11468c2ecf20Sopenharmony_ci GFP_KERNEL); 11478c2ecf20Sopenharmony_ci if (!csid->clock) 11488c2ecf20Sopenharmony_ci return -ENOMEM; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci for (i = 0; i < csid->nclocks; i++) { 11518c2ecf20Sopenharmony_ci struct camss_clock *clock = &csid->clock[i]; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci clock->clk = devm_clk_get(dev, res->clock[i]); 11548c2ecf20Sopenharmony_ci if (IS_ERR(clock->clk)) 11558c2ecf20Sopenharmony_ci return PTR_ERR(clock->clk); 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci clock->name = res->clock[i]; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci clock->nfreqs = 0; 11608c2ecf20Sopenharmony_ci while (res->clock_rate[i][clock->nfreqs]) 11618c2ecf20Sopenharmony_ci clock->nfreqs++; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci if (!clock->nfreqs) { 11648c2ecf20Sopenharmony_ci clock->freq = NULL; 11658c2ecf20Sopenharmony_ci continue; 11668c2ecf20Sopenharmony_ci } 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci clock->freq = devm_kcalloc(dev, 11698c2ecf20Sopenharmony_ci clock->nfreqs, 11708c2ecf20Sopenharmony_ci sizeof(*clock->freq), 11718c2ecf20Sopenharmony_ci GFP_KERNEL); 11728c2ecf20Sopenharmony_ci if (!clock->freq) 11738c2ecf20Sopenharmony_ci return -ENOMEM; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci for (j = 0; j < clock->nfreqs; j++) 11768c2ecf20Sopenharmony_ci clock->freq[j] = res->clock_rate[i][j]; 11778c2ecf20Sopenharmony_ci } 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci /* Regulator */ 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci csid->vdda = devm_regulator_get(dev, res->regulator[0]); 11828c2ecf20Sopenharmony_ci if (IS_ERR(csid->vdda)) { 11838c2ecf20Sopenharmony_ci dev_err(dev, "could not get regulator\n"); 11848c2ecf20Sopenharmony_ci return PTR_ERR(csid->vdda); 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci init_completion(&csid->reset_complete); 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci return 0; 11908c2ecf20Sopenharmony_ci} 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci/* 11938c2ecf20Sopenharmony_ci * msm_csid_get_csid_id - Get CSID HW module id 11948c2ecf20Sopenharmony_ci * @entity: Pointer to CSID media entity structure 11958c2ecf20Sopenharmony_ci * @id: Return CSID HW module id here 11968c2ecf20Sopenharmony_ci */ 11978c2ecf20Sopenharmony_civoid msm_csid_get_csid_id(struct media_entity *entity, u8 *id) 11988c2ecf20Sopenharmony_ci{ 11998c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); 12008c2ecf20Sopenharmony_ci struct csid_device *csid = v4l2_get_subdevdata(sd); 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci *id = csid->id; 12038c2ecf20Sopenharmony_ci} 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci/* 12068c2ecf20Sopenharmony_ci * csid_get_lane_assign - Calculate CSI2 lane assign configuration parameter 12078c2ecf20Sopenharmony_ci * @lane_cfg - CSI2 lane configuration 12088c2ecf20Sopenharmony_ci * 12098c2ecf20Sopenharmony_ci * Return lane assign 12108c2ecf20Sopenharmony_ci */ 12118c2ecf20Sopenharmony_cistatic u32 csid_get_lane_assign(struct csiphy_lanes_cfg *lane_cfg) 12128c2ecf20Sopenharmony_ci{ 12138c2ecf20Sopenharmony_ci u32 lane_assign = 0; 12148c2ecf20Sopenharmony_ci int i; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci for (i = 0; i < lane_cfg->num_data; i++) 12178c2ecf20Sopenharmony_ci lane_assign |= lane_cfg->data[i].pos << (i * 4); 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci return lane_assign; 12208c2ecf20Sopenharmony_ci} 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci/* 12238c2ecf20Sopenharmony_ci * csid_link_setup - Setup CSID connections 12248c2ecf20Sopenharmony_ci * @entity: Pointer to media entity structure 12258c2ecf20Sopenharmony_ci * @local: Pointer to local pad 12268c2ecf20Sopenharmony_ci * @remote: Pointer to remote pad 12278c2ecf20Sopenharmony_ci * @flags: Link flags 12288c2ecf20Sopenharmony_ci * 12298c2ecf20Sopenharmony_ci * Return 0 on success 12308c2ecf20Sopenharmony_ci */ 12318c2ecf20Sopenharmony_cistatic int csid_link_setup(struct media_entity *entity, 12328c2ecf20Sopenharmony_ci const struct media_pad *local, 12338c2ecf20Sopenharmony_ci const struct media_pad *remote, u32 flags) 12348c2ecf20Sopenharmony_ci{ 12358c2ecf20Sopenharmony_ci if (flags & MEDIA_LNK_FL_ENABLED) 12368c2ecf20Sopenharmony_ci if (media_entity_remote_pad(local)) 12378c2ecf20Sopenharmony_ci return -EBUSY; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci if ((local->flags & MEDIA_PAD_FL_SINK) && 12408c2ecf20Sopenharmony_ci (flags & MEDIA_LNK_FL_ENABLED)) { 12418c2ecf20Sopenharmony_ci struct v4l2_subdev *sd; 12428c2ecf20Sopenharmony_ci struct csid_device *csid; 12438c2ecf20Sopenharmony_ci struct csiphy_device *csiphy; 12448c2ecf20Sopenharmony_ci struct csiphy_lanes_cfg *lane_cfg; 12458c2ecf20Sopenharmony_ci struct v4l2_subdev_format format = { 0 }; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci sd = media_entity_to_v4l2_subdev(entity); 12488c2ecf20Sopenharmony_ci csid = v4l2_get_subdevdata(sd); 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci /* If test generator is enabled */ 12518c2ecf20Sopenharmony_ci /* do not allow a link from CSIPHY to CSID */ 12528c2ecf20Sopenharmony_ci if (csid->testgen_mode->cur.val != 0) 12538c2ecf20Sopenharmony_ci return -EBUSY; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci sd = media_entity_to_v4l2_subdev(remote->entity); 12568c2ecf20Sopenharmony_ci csiphy = v4l2_get_subdevdata(sd); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci /* If a sensor is not linked to CSIPHY */ 12598c2ecf20Sopenharmony_ci /* do no allow a link from CSIPHY to CSID */ 12608c2ecf20Sopenharmony_ci if (!csiphy->cfg.csi2) 12618c2ecf20Sopenharmony_ci return -EPERM; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci csid->phy.csiphy_id = csiphy->id; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci lane_cfg = &csiphy->cfg.csi2->lane_cfg; 12668c2ecf20Sopenharmony_ci csid->phy.lane_cnt = lane_cfg->num_data; 12678c2ecf20Sopenharmony_ci csid->phy.lane_assign = csid_get_lane_assign(lane_cfg); 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci /* Reset format on source pad to sink pad format */ 12708c2ecf20Sopenharmony_ci format.pad = MSM_CSID_PAD_SRC; 12718c2ecf20Sopenharmony_ci format.which = V4L2_SUBDEV_FORMAT_ACTIVE; 12728c2ecf20Sopenharmony_ci csid_set_format(&csid->subdev, NULL, &format); 12738c2ecf20Sopenharmony_ci } 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci return 0; 12768c2ecf20Sopenharmony_ci} 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_core_ops csid_core_ops = { 12798c2ecf20Sopenharmony_ci .s_power = csid_set_power, 12808c2ecf20Sopenharmony_ci .subscribe_event = v4l2_ctrl_subdev_subscribe_event, 12818c2ecf20Sopenharmony_ci .unsubscribe_event = v4l2_event_subdev_unsubscribe, 12828c2ecf20Sopenharmony_ci}; 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_video_ops csid_video_ops = { 12858c2ecf20Sopenharmony_ci .s_stream = csid_set_stream, 12868c2ecf20Sopenharmony_ci}; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_pad_ops csid_pad_ops = { 12898c2ecf20Sopenharmony_ci .enum_mbus_code = csid_enum_mbus_code, 12908c2ecf20Sopenharmony_ci .enum_frame_size = csid_enum_frame_size, 12918c2ecf20Sopenharmony_ci .get_fmt = csid_get_format, 12928c2ecf20Sopenharmony_ci .set_fmt = csid_set_format, 12938c2ecf20Sopenharmony_ci}; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops csid_v4l2_ops = { 12968c2ecf20Sopenharmony_ci .core = &csid_core_ops, 12978c2ecf20Sopenharmony_ci .video = &csid_video_ops, 12988c2ecf20Sopenharmony_ci .pad = &csid_pad_ops, 12998c2ecf20Sopenharmony_ci}; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_internal_ops csid_v4l2_internal_ops = { 13028c2ecf20Sopenharmony_ci .open = csid_init_formats, 13038c2ecf20Sopenharmony_ci}; 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_cistatic const struct media_entity_operations csid_media_ops = { 13068c2ecf20Sopenharmony_ci .link_setup = csid_link_setup, 13078c2ecf20Sopenharmony_ci .link_validate = v4l2_subdev_link_validate, 13088c2ecf20Sopenharmony_ci}; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci/* 13118c2ecf20Sopenharmony_ci * msm_csid_register_entity - Register subdev node for CSID module 13128c2ecf20Sopenharmony_ci * @csid: CSID device 13138c2ecf20Sopenharmony_ci * @v4l2_dev: V4L2 device 13148c2ecf20Sopenharmony_ci * 13158c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code otherwise 13168c2ecf20Sopenharmony_ci */ 13178c2ecf20Sopenharmony_ciint msm_csid_register_entity(struct csid_device *csid, 13188c2ecf20Sopenharmony_ci struct v4l2_device *v4l2_dev) 13198c2ecf20Sopenharmony_ci{ 13208c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = &csid->subdev; 13218c2ecf20Sopenharmony_ci struct media_pad *pads = csid->pads; 13228c2ecf20Sopenharmony_ci struct device *dev = csid->camss->dev; 13238c2ecf20Sopenharmony_ci int ret; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci v4l2_subdev_init(sd, &csid_v4l2_ops); 13268c2ecf20Sopenharmony_ci sd->internal_ops = &csid_v4l2_internal_ops; 13278c2ecf20Sopenharmony_ci sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | 13288c2ecf20Sopenharmony_ci V4L2_SUBDEV_FL_HAS_EVENTS; 13298c2ecf20Sopenharmony_ci snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d", 13308c2ecf20Sopenharmony_ci MSM_CSID_NAME, csid->id); 13318c2ecf20Sopenharmony_ci v4l2_set_subdevdata(sd, csid); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci ret = v4l2_ctrl_handler_init(&csid->ctrls, 1); 13348c2ecf20Sopenharmony_ci if (ret < 0) { 13358c2ecf20Sopenharmony_ci dev_err(dev, "Failed to init ctrl handler: %d\n", ret); 13368c2ecf20Sopenharmony_ci return ret; 13378c2ecf20Sopenharmony_ci } 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci csid->testgen_mode = v4l2_ctrl_new_std_menu_items(&csid->ctrls, 13408c2ecf20Sopenharmony_ci &csid_ctrl_ops, V4L2_CID_TEST_PATTERN, 13418c2ecf20Sopenharmony_ci ARRAY_SIZE(csid_test_pattern_menu) - 1, 0, 0, 13428c2ecf20Sopenharmony_ci csid_test_pattern_menu); 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci if (csid->ctrls.error) { 13458c2ecf20Sopenharmony_ci dev_err(dev, "Failed to init ctrl: %d\n", csid->ctrls.error); 13468c2ecf20Sopenharmony_ci ret = csid->ctrls.error; 13478c2ecf20Sopenharmony_ci goto free_ctrl; 13488c2ecf20Sopenharmony_ci } 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci csid->subdev.ctrl_handler = &csid->ctrls; 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci ret = csid_init_formats(sd, NULL); 13538c2ecf20Sopenharmony_ci if (ret < 0) { 13548c2ecf20Sopenharmony_ci dev_err(dev, "Failed to init format: %d\n", ret); 13558c2ecf20Sopenharmony_ci goto free_ctrl; 13568c2ecf20Sopenharmony_ci } 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci pads[MSM_CSID_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 13598c2ecf20Sopenharmony_ci pads[MSM_CSID_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE; 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; 13628c2ecf20Sopenharmony_ci sd->entity.ops = &csid_media_ops; 13638c2ecf20Sopenharmony_ci ret = media_entity_pads_init(&sd->entity, MSM_CSID_PADS_NUM, pads); 13648c2ecf20Sopenharmony_ci if (ret < 0) { 13658c2ecf20Sopenharmony_ci dev_err(dev, "Failed to init media entity: %d\n", ret); 13668c2ecf20Sopenharmony_ci goto free_ctrl; 13678c2ecf20Sopenharmony_ci } 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci ret = v4l2_device_register_subdev(v4l2_dev, sd); 13708c2ecf20Sopenharmony_ci if (ret < 0) { 13718c2ecf20Sopenharmony_ci dev_err(dev, "Failed to register subdev: %d\n", ret); 13728c2ecf20Sopenharmony_ci goto media_cleanup; 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci return 0; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_cimedia_cleanup: 13788c2ecf20Sopenharmony_ci media_entity_cleanup(&sd->entity); 13798c2ecf20Sopenharmony_cifree_ctrl: 13808c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&csid->ctrls); 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci return ret; 13838c2ecf20Sopenharmony_ci} 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci/* 13868c2ecf20Sopenharmony_ci * msm_csid_unregister_entity - Unregister CSID module subdev node 13878c2ecf20Sopenharmony_ci * @csid: CSID device 13888c2ecf20Sopenharmony_ci */ 13898c2ecf20Sopenharmony_civoid msm_csid_unregister_entity(struct csid_device *csid) 13908c2ecf20Sopenharmony_ci{ 13918c2ecf20Sopenharmony_ci v4l2_device_unregister_subdev(&csid->subdev); 13928c2ecf20Sopenharmony_ci media_entity_cleanup(&csid->subdev.entity); 13938c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&csid->ctrls); 13948c2ecf20Sopenharmony_ci} 1395