162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * camss-ispif.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Qualcomm MSM Camera Subsystem - ISPIF (ISP Interface) Module 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. 862306a36Sopenharmony_ci * Copyright (C) 2015-2018 Linaro Ltd. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci#include <linux/clk.h> 1162306a36Sopenharmony_ci#include <linux/completion.h> 1262306a36Sopenharmony_ci#include <linux/interrupt.h> 1362306a36Sopenharmony_ci#include <linux/io.h> 1462306a36Sopenharmony_ci#include <linux/iopoll.h> 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/mutex.h> 1762306a36Sopenharmony_ci#include <linux/platform_device.h> 1862306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1962306a36Sopenharmony_ci#include <media/media-entity.h> 2062306a36Sopenharmony_ci#include <media/v4l2-device.h> 2162306a36Sopenharmony_ci#include <media/v4l2-subdev.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "camss-ispif.h" 2462306a36Sopenharmony_ci#include "camss.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define MSM_ISPIF_NAME "msm_ispif" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define ISPIF_RST_CMD_0 0x008 2962306a36Sopenharmony_ci#define ISPIF_RST_CMD_1 0x00c 3062306a36Sopenharmony_ci#define ISPIF_RST_CMD_0_STROBED_RST_EN (1 << 0) 3162306a36Sopenharmony_ci#define ISPIF_RST_CMD_0_MISC_LOGIC_RST (1 << 1) 3262306a36Sopenharmony_ci#define ISPIF_RST_CMD_0_SW_REG_RST (1 << 2) 3362306a36Sopenharmony_ci#define ISPIF_RST_CMD_0_PIX_INTF_0_CSID_RST (1 << 3) 3462306a36Sopenharmony_ci#define ISPIF_RST_CMD_0_PIX_INTF_0_VFE_RST (1 << 4) 3562306a36Sopenharmony_ci#define ISPIF_RST_CMD_0_PIX_INTF_1_CSID_RST (1 << 5) 3662306a36Sopenharmony_ci#define ISPIF_RST_CMD_0_PIX_INTF_1_VFE_RST (1 << 6) 3762306a36Sopenharmony_ci#define ISPIF_RST_CMD_0_RDI_INTF_0_CSID_RST (1 << 7) 3862306a36Sopenharmony_ci#define ISPIF_RST_CMD_0_RDI_INTF_0_VFE_RST (1 << 8) 3962306a36Sopenharmony_ci#define ISPIF_RST_CMD_0_RDI_INTF_1_CSID_RST (1 << 9) 4062306a36Sopenharmony_ci#define ISPIF_RST_CMD_0_RDI_INTF_1_VFE_RST (1 << 10) 4162306a36Sopenharmony_ci#define ISPIF_RST_CMD_0_RDI_INTF_2_CSID_RST (1 << 11) 4262306a36Sopenharmony_ci#define ISPIF_RST_CMD_0_RDI_INTF_2_VFE_RST (1 << 12) 4362306a36Sopenharmony_ci#define ISPIF_RST_CMD_0_PIX_OUTPUT_0_MISR_RST (1 << 16) 4462306a36Sopenharmony_ci#define ISPIF_RST_CMD_0_RDI_OUTPUT_0_MISR_RST (1 << 17) 4562306a36Sopenharmony_ci#define ISPIF_RST_CMD_0_RDI_OUTPUT_1_MISR_RST (1 << 18) 4662306a36Sopenharmony_ci#define ISPIF_RST_CMD_0_RDI_OUTPUT_2_MISR_RST (1 << 19) 4762306a36Sopenharmony_ci#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x01c 4862306a36Sopenharmony_ci#define ISPIF_VFE_m_CTRL_0(m) (0x200 + 0x200 * (m)) 4962306a36Sopenharmony_ci#define ISPIF_VFE_m_CTRL_0_PIX0_LINE_BUF_EN (1 << 6) 5062306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_MASK_0(m) (0x208 + 0x200 * (m)) 5162306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_MASK_0_PIX0_ENABLE 0x00001249 5262306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_MASK_0_PIX0_MASK 0x00001fff 5362306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_MASK_0_RDI0_ENABLE 0x02492000 5462306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_MASK_0_RDI0_MASK 0x03ffe000 5562306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_MASK_1(m) (0x20c + 0x200 * (m)) 5662306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_MASK_1_PIX1_ENABLE 0x00001249 5762306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_MASK_1_PIX1_MASK 0x00001fff 5862306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_MASK_1_RDI1_ENABLE 0x02492000 5962306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_MASK_1_RDI1_MASK 0x03ffe000 6062306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_MASK_2(m) (0x210 + 0x200 * (m)) 6162306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_MASK_2_RDI2_ENABLE 0x00001249 6262306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_MASK_2_RDI2_MASK 0x00001fff 6362306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_STATUS_0(m) (0x21c + 0x200 * (m)) 6462306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW (1 << 12) 6562306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW (1 << 25) 6662306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_STATUS_1(m) (0x220 + 0x200 * (m)) 6762306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW (1 << 12) 6862306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW (1 << 25) 6962306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_STATUS_2(m) (0x224 + 0x200 * (m)) 7062306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW (1 << 12) 7162306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_CLEAR_0(m) (0x230 + 0x200 * (m)) 7262306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_CLEAR_1(m) (0x234 + 0x200 * (m)) 7362306a36Sopenharmony_ci#define ISPIF_VFE_m_IRQ_CLEAR_2(m) (0x238 + 0x200 * (m)) 7462306a36Sopenharmony_ci#define ISPIF_VFE_m_INTF_INPUT_SEL(m) (0x244 + 0x200 * (m)) 7562306a36Sopenharmony_ci#define ISPIF_VFE_m_INTF_CMD_0(m) (0x248 + 0x200 * (m)) 7662306a36Sopenharmony_ci#define ISPIF_VFE_m_INTF_CMD_1(m) (0x24c + 0x200 * (m)) 7762306a36Sopenharmony_ci#define ISPIF_VFE_m_PIX_INTF_n_CID_MASK(m, n) \ 7862306a36Sopenharmony_ci (0x254 + 0x200 * (m) + 0x4 * (n)) 7962306a36Sopenharmony_ci#define ISPIF_VFE_m_RDI_INTF_n_CID_MASK(m, n) \ 8062306a36Sopenharmony_ci (0x264 + 0x200 * (m) + 0x4 * (n)) 8162306a36Sopenharmony_ci/* PACK_CFG registers are 8x96 only */ 8262306a36Sopenharmony_ci#define ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_0(m, n) \ 8362306a36Sopenharmony_ci (0x270 + 0x200 * (m) + 0x4 * (n)) 8462306a36Sopenharmony_ci#define ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_1(m, n) \ 8562306a36Sopenharmony_ci (0x27c + 0x200 * (m) + 0x4 * (n)) 8662306a36Sopenharmony_ci#define ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_0_CID_c_PLAIN(c) \ 8762306a36Sopenharmony_ci (1 << ((cid % 8) * 4)) 8862306a36Sopenharmony_ci#define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n) \ 8962306a36Sopenharmony_ci (0x2c0 + 0x200 * (m) + 0x4 * (n)) 9062306a36Sopenharmony_ci#define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n) \ 9162306a36Sopenharmony_ci (0x2d0 + 0x200 * (m) + 0x4 * (n)) 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#define CSI_PIX_CLK_MUX_SEL 0x000 9462306a36Sopenharmony_ci#define CSI_RDI_CLK_MUX_SEL 0x008 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci#define ISPIF_TIMEOUT_SLEEP_US 1000 9762306a36Sopenharmony_ci#define ISPIF_TIMEOUT_ALL_US 1000000 9862306a36Sopenharmony_ci#define ISPIF_RESET_TIMEOUT_MS 500 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cienum ispif_intf_cmd { 10162306a36Sopenharmony_ci CMD_DISABLE_FRAME_BOUNDARY = 0x0, 10262306a36Sopenharmony_ci CMD_ENABLE_FRAME_BOUNDARY = 0x1, 10362306a36Sopenharmony_ci CMD_DISABLE_IMMEDIATELY = 0x2, 10462306a36Sopenharmony_ci CMD_ALL_DISABLE_IMMEDIATELY = 0xaaaaaaaa, 10562306a36Sopenharmony_ci CMD_ALL_NO_CHANGE = 0xffffffff, 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic const u32 ispif_formats_8x16[] = { 10962306a36Sopenharmony_ci MEDIA_BUS_FMT_UYVY8_2X8, 11062306a36Sopenharmony_ci MEDIA_BUS_FMT_VYUY8_2X8, 11162306a36Sopenharmony_ci MEDIA_BUS_FMT_YUYV8_2X8, 11262306a36Sopenharmony_ci MEDIA_BUS_FMT_YVYU8_2X8, 11362306a36Sopenharmony_ci MEDIA_BUS_FMT_SBGGR8_1X8, 11462306a36Sopenharmony_ci MEDIA_BUS_FMT_SGBRG8_1X8, 11562306a36Sopenharmony_ci MEDIA_BUS_FMT_SGRBG8_1X8, 11662306a36Sopenharmony_ci MEDIA_BUS_FMT_SRGGB8_1X8, 11762306a36Sopenharmony_ci MEDIA_BUS_FMT_SBGGR10_1X10, 11862306a36Sopenharmony_ci MEDIA_BUS_FMT_SGBRG10_1X10, 11962306a36Sopenharmony_ci MEDIA_BUS_FMT_SGRBG10_1X10, 12062306a36Sopenharmony_ci MEDIA_BUS_FMT_SRGGB10_1X10, 12162306a36Sopenharmony_ci MEDIA_BUS_FMT_SBGGR12_1X12, 12262306a36Sopenharmony_ci MEDIA_BUS_FMT_SGBRG12_1X12, 12362306a36Sopenharmony_ci MEDIA_BUS_FMT_SGRBG12_1X12, 12462306a36Sopenharmony_ci MEDIA_BUS_FMT_SRGGB12_1X12, 12562306a36Sopenharmony_ci MEDIA_BUS_FMT_Y10_1X10, 12662306a36Sopenharmony_ci}; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic const u32 ispif_formats_8x96[] = { 12962306a36Sopenharmony_ci MEDIA_BUS_FMT_UYVY8_2X8, 13062306a36Sopenharmony_ci MEDIA_BUS_FMT_VYUY8_2X8, 13162306a36Sopenharmony_ci MEDIA_BUS_FMT_YUYV8_2X8, 13262306a36Sopenharmony_ci MEDIA_BUS_FMT_YVYU8_2X8, 13362306a36Sopenharmony_ci MEDIA_BUS_FMT_SBGGR8_1X8, 13462306a36Sopenharmony_ci MEDIA_BUS_FMT_SGBRG8_1X8, 13562306a36Sopenharmony_ci MEDIA_BUS_FMT_SGRBG8_1X8, 13662306a36Sopenharmony_ci MEDIA_BUS_FMT_SRGGB8_1X8, 13762306a36Sopenharmony_ci MEDIA_BUS_FMT_SBGGR10_1X10, 13862306a36Sopenharmony_ci MEDIA_BUS_FMT_SGBRG10_1X10, 13962306a36Sopenharmony_ci MEDIA_BUS_FMT_SGRBG10_1X10, 14062306a36Sopenharmony_ci MEDIA_BUS_FMT_SRGGB10_1X10, 14162306a36Sopenharmony_ci MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, 14262306a36Sopenharmony_ci MEDIA_BUS_FMT_SBGGR12_1X12, 14362306a36Sopenharmony_ci MEDIA_BUS_FMT_SGBRG12_1X12, 14462306a36Sopenharmony_ci MEDIA_BUS_FMT_SGRBG12_1X12, 14562306a36Sopenharmony_ci MEDIA_BUS_FMT_SRGGB12_1X12, 14662306a36Sopenharmony_ci MEDIA_BUS_FMT_SBGGR14_1X14, 14762306a36Sopenharmony_ci MEDIA_BUS_FMT_SGBRG14_1X14, 14862306a36Sopenharmony_ci MEDIA_BUS_FMT_SGRBG14_1X14, 14962306a36Sopenharmony_ci MEDIA_BUS_FMT_SRGGB14_1X14, 15062306a36Sopenharmony_ci MEDIA_BUS_FMT_Y10_1X10, 15162306a36Sopenharmony_ci MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, 15262306a36Sopenharmony_ci}; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/* 15562306a36Sopenharmony_ci * ispif_isr_8x96 - ISPIF module interrupt handler for 8x96 15662306a36Sopenharmony_ci * @irq: Interrupt line 15762306a36Sopenharmony_ci * @dev: ISPIF device 15862306a36Sopenharmony_ci * 15962306a36Sopenharmony_ci * Return IRQ_HANDLED on success 16062306a36Sopenharmony_ci */ 16162306a36Sopenharmony_cistatic irqreturn_t ispif_isr_8x96(int irq, void *dev) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct ispif_device *ispif = dev; 16462306a36Sopenharmony_ci struct camss *camss = ispif->camss; 16562306a36Sopenharmony_ci u32 value0, value1, value2, value3, value4, value5; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci value0 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_0(0)); 16862306a36Sopenharmony_ci value1 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_1(0)); 16962306a36Sopenharmony_ci value2 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_2(0)); 17062306a36Sopenharmony_ci value3 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_0(1)); 17162306a36Sopenharmony_ci value4 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_1(1)); 17262306a36Sopenharmony_ci value5 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_2(1)); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci writel_relaxed(value0, ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(0)); 17562306a36Sopenharmony_ci writel_relaxed(value1, ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(0)); 17662306a36Sopenharmony_ci writel_relaxed(value2, ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(0)); 17762306a36Sopenharmony_ci writel_relaxed(value3, ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(1)); 17862306a36Sopenharmony_ci writel_relaxed(value4, ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(1)); 17962306a36Sopenharmony_ci writel_relaxed(value5, ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(1)); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci writel(0x1, ispif->base + ISPIF_IRQ_GLOBAL_CLEAR_CMD); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if ((value0 >> 27) & 0x1) 18462306a36Sopenharmony_ci complete(&ispif->reset_complete[0]); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if ((value3 >> 27) & 0x1) 18762306a36Sopenharmony_ci complete(&ispif->reset_complete[1]); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW)) 19062306a36Sopenharmony_ci dev_err_ratelimited(camss->dev, "VFE0 pix0 overflow\n"); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW)) 19362306a36Sopenharmony_ci dev_err_ratelimited(camss->dev, "VFE0 rdi0 overflow\n"); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW)) 19662306a36Sopenharmony_ci dev_err_ratelimited(camss->dev, "VFE0 pix1 overflow\n"); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW)) 19962306a36Sopenharmony_ci dev_err_ratelimited(camss->dev, "VFE0 rdi1 overflow\n"); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (unlikely(value2 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW)) 20262306a36Sopenharmony_ci dev_err_ratelimited(camss->dev, "VFE0 rdi2 overflow\n"); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (unlikely(value3 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW)) 20562306a36Sopenharmony_ci dev_err_ratelimited(camss->dev, "VFE1 pix0 overflow\n"); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (unlikely(value3 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW)) 20862306a36Sopenharmony_ci dev_err_ratelimited(camss->dev, "VFE1 rdi0 overflow\n"); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (unlikely(value4 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW)) 21162306a36Sopenharmony_ci dev_err_ratelimited(camss->dev, "VFE1 pix1 overflow\n"); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (unlikely(value4 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW)) 21462306a36Sopenharmony_ci dev_err_ratelimited(camss->dev, "VFE1 rdi1 overflow\n"); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (unlikely(value5 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW)) 21762306a36Sopenharmony_ci dev_err_ratelimited(camss->dev, "VFE1 rdi2 overflow\n"); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci return IRQ_HANDLED; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci/* 22362306a36Sopenharmony_ci * ispif_isr_8x16 - ISPIF module interrupt handler for 8x16 22462306a36Sopenharmony_ci * @irq: Interrupt line 22562306a36Sopenharmony_ci * @dev: ISPIF device 22662306a36Sopenharmony_ci * 22762306a36Sopenharmony_ci * Return IRQ_HANDLED on success 22862306a36Sopenharmony_ci */ 22962306a36Sopenharmony_cistatic irqreturn_t ispif_isr_8x16(int irq, void *dev) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci struct ispif_device *ispif = dev; 23262306a36Sopenharmony_ci struct camss *camss = ispif->camss; 23362306a36Sopenharmony_ci u32 value0, value1, value2; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci value0 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_0(0)); 23662306a36Sopenharmony_ci value1 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_1(0)); 23762306a36Sopenharmony_ci value2 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_2(0)); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci writel_relaxed(value0, ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(0)); 24062306a36Sopenharmony_ci writel_relaxed(value1, ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(0)); 24162306a36Sopenharmony_ci writel_relaxed(value2, ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(0)); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci writel(0x1, ispif->base + ISPIF_IRQ_GLOBAL_CLEAR_CMD); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if ((value0 >> 27) & 0x1) 24662306a36Sopenharmony_ci complete(&ispif->reset_complete[0]); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW)) 24962306a36Sopenharmony_ci dev_err_ratelimited(camss->dev, "VFE0 pix0 overflow\n"); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW)) 25262306a36Sopenharmony_ci dev_err_ratelimited(camss->dev, "VFE0 rdi0 overflow\n"); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW)) 25562306a36Sopenharmony_ci dev_err_ratelimited(camss->dev, "VFE0 pix1 overflow\n"); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW)) 25862306a36Sopenharmony_ci dev_err_ratelimited(camss->dev, "VFE0 rdi1 overflow\n"); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (unlikely(value2 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW)) 26162306a36Sopenharmony_ci dev_err_ratelimited(camss->dev, "VFE0 rdi2 overflow\n"); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci return IRQ_HANDLED; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct camss *camss = ispif->camss; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci unsigned long time; 27162306a36Sopenharmony_ci u32 val; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (vfe_id > (camss->vfe_num - 1)) { 27462306a36Sopenharmony_ci dev_err(camss->dev, 27562306a36Sopenharmony_ci "Error: asked reset for invalid VFE%d\n", vfe_id); 27662306a36Sopenharmony_ci return -ENOENT; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci reinit_completion(&ispif->reset_complete[vfe_id]); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci val = ISPIF_RST_CMD_0_STROBED_RST_EN | 28262306a36Sopenharmony_ci ISPIF_RST_CMD_0_MISC_LOGIC_RST | 28362306a36Sopenharmony_ci ISPIF_RST_CMD_0_SW_REG_RST | 28462306a36Sopenharmony_ci ISPIF_RST_CMD_0_PIX_INTF_0_CSID_RST | 28562306a36Sopenharmony_ci ISPIF_RST_CMD_0_PIX_INTF_0_VFE_RST | 28662306a36Sopenharmony_ci ISPIF_RST_CMD_0_PIX_INTF_1_CSID_RST | 28762306a36Sopenharmony_ci ISPIF_RST_CMD_0_PIX_INTF_1_VFE_RST | 28862306a36Sopenharmony_ci ISPIF_RST_CMD_0_RDI_INTF_0_CSID_RST | 28962306a36Sopenharmony_ci ISPIF_RST_CMD_0_RDI_INTF_0_VFE_RST | 29062306a36Sopenharmony_ci ISPIF_RST_CMD_0_RDI_INTF_1_CSID_RST | 29162306a36Sopenharmony_ci ISPIF_RST_CMD_0_RDI_INTF_1_VFE_RST | 29262306a36Sopenharmony_ci ISPIF_RST_CMD_0_RDI_INTF_2_CSID_RST | 29362306a36Sopenharmony_ci ISPIF_RST_CMD_0_RDI_INTF_2_VFE_RST | 29462306a36Sopenharmony_ci ISPIF_RST_CMD_0_PIX_OUTPUT_0_MISR_RST | 29562306a36Sopenharmony_ci ISPIF_RST_CMD_0_RDI_OUTPUT_0_MISR_RST | 29662306a36Sopenharmony_ci ISPIF_RST_CMD_0_RDI_OUTPUT_1_MISR_RST | 29762306a36Sopenharmony_ci ISPIF_RST_CMD_0_RDI_OUTPUT_2_MISR_RST; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (vfe_id == 1) 30062306a36Sopenharmony_ci writel_relaxed(val, ispif->base + ISPIF_RST_CMD_1); 30162306a36Sopenharmony_ci else 30262306a36Sopenharmony_ci writel_relaxed(val, ispif->base + ISPIF_RST_CMD_0); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci time = wait_for_completion_timeout(&ispif->reset_complete[vfe_id], 30562306a36Sopenharmony_ci msecs_to_jiffies(ISPIF_RESET_TIMEOUT_MS)); 30662306a36Sopenharmony_ci if (!time) { 30762306a36Sopenharmony_ci dev_err(camss->dev, 30862306a36Sopenharmony_ci "ISPIF for VFE%d reset timeout\n", vfe_id); 30962306a36Sopenharmony_ci return -EIO; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci return 0; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci/* 31662306a36Sopenharmony_ci * ispif_reset - Trigger reset on ISPIF module and wait to complete 31762306a36Sopenharmony_ci * @ispif: ISPIF device 31862306a36Sopenharmony_ci * 31962306a36Sopenharmony_ci * Return 0 on success or a negative error code otherwise 32062306a36Sopenharmony_ci */ 32162306a36Sopenharmony_cistatic int ispif_reset(struct ispif_device *ispif, u8 vfe_id) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci struct camss *camss = ispif->camss; 32462306a36Sopenharmony_ci int ret; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci ret = camss_pm_domain_on(camss, PM_DOMAIN_VFE0); 32762306a36Sopenharmony_ci if (ret < 0) 32862306a36Sopenharmony_ci return ret; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci ret = camss_pm_domain_on(camss, PM_DOMAIN_VFE1); 33162306a36Sopenharmony_ci if (ret < 0) 33262306a36Sopenharmony_ci return ret; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci ret = camss_enable_clocks(ispif->nclocks_for_reset, 33562306a36Sopenharmony_ci ispif->clock_for_reset, 33662306a36Sopenharmony_ci camss->dev); 33762306a36Sopenharmony_ci if (ret < 0) 33862306a36Sopenharmony_ci return ret; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci ret = ispif_vfe_reset(ispif, vfe_id); 34162306a36Sopenharmony_ci if (ret) 34262306a36Sopenharmony_ci dev_dbg(camss->dev, "ISPIF Reset failed\n"); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci camss_disable_clocks(ispif->nclocks_for_reset, ispif->clock_for_reset); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci camss_pm_domain_off(camss, PM_DOMAIN_VFE0); 34762306a36Sopenharmony_ci camss_pm_domain_off(camss, PM_DOMAIN_VFE1); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci return ret; 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci/* 35362306a36Sopenharmony_ci * ispif_set_power - Power on/off ISPIF module 35462306a36Sopenharmony_ci * @sd: ISPIF V4L2 subdevice 35562306a36Sopenharmony_ci * @on: Requested power state 35662306a36Sopenharmony_ci * 35762306a36Sopenharmony_ci * Return 0 on success or a negative error code otherwise 35862306a36Sopenharmony_ci */ 35962306a36Sopenharmony_cistatic int ispif_set_power(struct v4l2_subdev *sd, int on) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci struct ispif_line *line = v4l2_get_subdevdata(sd); 36262306a36Sopenharmony_ci struct ispif_device *ispif = line->ispif; 36362306a36Sopenharmony_ci struct device *dev = ispif->camss->dev; 36462306a36Sopenharmony_ci int ret = 0; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci mutex_lock(&ispif->power_lock); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if (on) { 36962306a36Sopenharmony_ci if (ispif->power_count) { 37062306a36Sopenharmony_ci /* Power is already on */ 37162306a36Sopenharmony_ci ispif->power_count++; 37262306a36Sopenharmony_ci goto exit; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(dev); 37662306a36Sopenharmony_ci if (ret < 0) 37762306a36Sopenharmony_ci goto exit; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci ret = camss_enable_clocks(ispif->nclocks, ispif->clock, dev); 38062306a36Sopenharmony_ci if (ret < 0) { 38162306a36Sopenharmony_ci pm_runtime_put_sync(dev); 38262306a36Sopenharmony_ci goto exit; 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci ret = ispif_reset(ispif, line->vfe_id); 38662306a36Sopenharmony_ci if (ret < 0) { 38762306a36Sopenharmony_ci pm_runtime_put_sync(dev); 38862306a36Sopenharmony_ci camss_disable_clocks(ispif->nclocks, ispif->clock); 38962306a36Sopenharmony_ci goto exit; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci ispif->intf_cmd[line->vfe_id].cmd_0 = CMD_ALL_NO_CHANGE; 39362306a36Sopenharmony_ci ispif->intf_cmd[line->vfe_id].cmd_1 = CMD_ALL_NO_CHANGE; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci ispif->power_count++; 39662306a36Sopenharmony_ci } else { 39762306a36Sopenharmony_ci if (ispif->power_count == 0) { 39862306a36Sopenharmony_ci dev_err(dev, "ispif power off on power_count == 0\n"); 39962306a36Sopenharmony_ci goto exit; 40062306a36Sopenharmony_ci } else if (ispif->power_count == 1) { 40162306a36Sopenharmony_ci camss_disable_clocks(ispif->nclocks, ispif->clock); 40262306a36Sopenharmony_ci pm_runtime_put_sync(dev); 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci ispif->power_count--; 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ciexit: 40962306a36Sopenharmony_ci mutex_unlock(&ispif->power_lock); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci return ret; 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci/* 41562306a36Sopenharmony_ci * ispif_select_clk_mux - Select clock for PIX/RDI interface 41662306a36Sopenharmony_ci * @ispif: ISPIF device 41762306a36Sopenharmony_ci * @intf: VFE interface 41862306a36Sopenharmony_ci * @csid: CSID HW module id 41962306a36Sopenharmony_ci * @vfe: VFE HW module id 42062306a36Sopenharmony_ci * @enable: enable or disable the selected clock 42162306a36Sopenharmony_ci */ 42262306a36Sopenharmony_cistatic void ispif_select_clk_mux(struct ispif_device *ispif, 42362306a36Sopenharmony_ci enum ispif_intf intf, u8 csid, 42462306a36Sopenharmony_ci u8 vfe, u8 enable) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci u32 val; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci switch (intf) { 42962306a36Sopenharmony_ci case PIX0: 43062306a36Sopenharmony_ci val = readl_relaxed(ispif->base_clk_mux + CSI_PIX_CLK_MUX_SEL); 43162306a36Sopenharmony_ci val &= ~(0xf << (vfe * 8)); 43262306a36Sopenharmony_ci if (enable) 43362306a36Sopenharmony_ci val |= (csid << (vfe * 8)); 43462306a36Sopenharmony_ci writel_relaxed(val, ispif->base_clk_mux + CSI_PIX_CLK_MUX_SEL); 43562306a36Sopenharmony_ci break; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci case RDI0: 43862306a36Sopenharmony_ci val = readl_relaxed(ispif->base_clk_mux + CSI_RDI_CLK_MUX_SEL); 43962306a36Sopenharmony_ci val &= ~(0xf << (vfe * 12)); 44062306a36Sopenharmony_ci if (enable) 44162306a36Sopenharmony_ci val |= (csid << (vfe * 12)); 44262306a36Sopenharmony_ci writel_relaxed(val, ispif->base_clk_mux + CSI_RDI_CLK_MUX_SEL); 44362306a36Sopenharmony_ci break; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci case PIX1: 44662306a36Sopenharmony_ci val = readl_relaxed(ispif->base_clk_mux + CSI_PIX_CLK_MUX_SEL); 44762306a36Sopenharmony_ci val &= ~(0xf << (4 + (vfe * 8))); 44862306a36Sopenharmony_ci if (enable) 44962306a36Sopenharmony_ci val |= (csid << (4 + (vfe * 8))); 45062306a36Sopenharmony_ci writel_relaxed(val, ispif->base_clk_mux + CSI_PIX_CLK_MUX_SEL); 45162306a36Sopenharmony_ci break; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci case RDI1: 45462306a36Sopenharmony_ci val = readl_relaxed(ispif->base_clk_mux + CSI_RDI_CLK_MUX_SEL); 45562306a36Sopenharmony_ci val &= ~(0xf << (4 + (vfe * 12))); 45662306a36Sopenharmony_ci if (enable) 45762306a36Sopenharmony_ci val |= (csid << (4 + (vfe * 12))); 45862306a36Sopenharmony_ci writel_relaxed(val, ispif->base_clk_mux + CSI_RDI_CLK_MUX_SEL); 45962306a36Sopenharmony_ci break; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci case RDI2: 46262306a36Sopenharmony_ci val = readl_relaxed(ispif->base_clk_mux + CSI_RDI_CLK_MUX_SEL); 46362306a36Sopenharmony_ci val &= ~(0xf << (8 + (vfe * 12))); 46462306a36Sopenharmony_ci if (enable) 46562306a36Sopenharmony_ci val |= (csid << (8 + (vfe * 12))); 46662306a36Sopenharmony_ci writel_relaxed(val, ispif->base_clk_mux + CSI_RDI_CLK_MUX_SEL); 46762306a36Sopenharmony_ci break; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci mb(); 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci/* 47462306a36Sopenharmony_ci * ispif_validate_intf_status - Validate current status of PIX/RDI interface 47562306a36Sopenharmony_ci * @ispif: ISPIF device 47662306a36Sopenharmony_ci * @intf: VFE interface 47762306a36Sopenharmony_ci * @vfe: VFE HW module id 47862306a36Sopenharmony_ci * 47962306a36Sopenharmony_ci * Return 0 when interface is idle or -EBUSY otherwise 48062306a36Sopenharmony_ci */ 48162306a36Sopenharmony_cistatic int ispif_validate_intf_status(struct ispif_device *ispif, 48262306a36Sopenharmony_ci enum ispif_intf intf, u8 vfe) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci int ret = 0; 48562306a36Sopenharmony_ci u32 val = 0; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci switch (intf) { 48862306a36Sopenharmony_ci case PIX0: 48962306a36Sopenharmony_ci val = readl_relaxed(ispif->base + 49062306a36Sopenharmony_ci ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe, 0)); 49162306a36Sopenharmony_ci break; 49262306a36Sopenharmony_ci case RDI0: 49362306a36Sopenharmony_ci val = readl_relaxed(ispif->base + 49462306a36Sopenharmony_ci ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe, 0)); 49562306a36Sopenharmony_ci break; 49662306a36Sopenharmony_ci case PIX1: 49762306a36Sopenharmony_ci val = readl_relaxed(ispif->base + 49862306a36Sopenharmony_ci ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe, 1)); 49962306a36Sopenharmony_ci break; 50062306a36Sopenharmony_ci case RDI1: 50162306a36Sopenharmony_ci val = readl_relaxed(ispif->base + 50262306a36Sopenharmony_ci ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe, 1)); 50362306a36Sopenharmony_ci break; 50462306a36Sopenharmony_ci case RDI2: 50562306a36Sopenharmony_ci val = readl_relaxed(ispif->base + 50662306a36Sopenharmony_ci ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe, 2)); 50762306a36Sopenharmony_ci break; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if ((val & 0xf) != 0xf) { 51162306a36Sopenharmony_ci dev_err(ispif->camss->dev, "%s: ispif is busy: 0x%x\n", 51262306a36Sopenharmony_ci __func__, val); 51362306a36Sopenharmony_ci ret = -EBUSY; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci return ret; 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci/* 52062306a36Sopenharmony_ci * ispif_wait_for_stop - Wait for PIX/RDI interface to stop 52162306a36Sopenharmony_ci * @ispif: ISPIF device 52262306a36Sopenharmony_ci * @intf: VFE interface 52362306a36Sopenharmony_ci * @vfe: VFE HW module id 52462306a36Sopenharmony_ci * 52562306a36Sopenharmony_ci * Return 0 on success or a negative error code otherwise 52662306a36Sopenharmony_ci */ 52762306a36Sopenharmony_cistatic int ispif_wait_for_stop(struct ispif_device *ispif, 52862306a36Sopenharmony_ci enum ispif_intf intf, u8 vfe) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci u32 addr = 0; 53162306a36Sopenharmony_ci u32 stop_flag = 0; 53262306a36Sopenharmony_ci int ret; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci switch (intf) { 53562306a36Sopenharmony_ci case PIX0: 53662306a36Sopenharmony_ci addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe, 0); 53762306a36Sopenharmony_ci break; 53862306a36Sopenharmony_ci case RDI0: 53962306a36Sopenharmony_ci addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe, 0); 54062306a36Sopenharmony_ci break; 54162306a36Sopenharmony_ci case PIX1: 54262306a36Sopenharmony_ci addr = ISPIF_VFE_m_PIX_INTF_n_STATUS(vfe, 1); 54362306a36Sopenharmony_ci break; 54462306a36Sopenharmony_ci case RDI1: 54562306a36Sopenharmony_ci addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe, 1); 54662306a36Sopenharmony_ci break; 54762306a36Sopenharmony_ci case RDI2: 54862306a36Sopenharmony_ci addr = ISPIF_VFE_m_RDI_INTF_n_STATUS(vfe, 2); 54962306a36Sopenharmony_ci break; 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci ret = readl_poll_timeout(ispif->base + addr, 55362306a36Sopenharmony_ci stop_flag, 55462306a36Sopenharmony_ci (stop_flag & 0xf) == 0xf, 55562306a36Sopenharmony_ci ISPIF_TIMEOUT_SLEEP_US, 55662306a36Sopenharmony_ci ISPIF_TIMEOUT_ALL_US); 55762306a36Sopenharmony_ci if (ret < 0) 55862306a36Sopenharmony_ci dev_err(ispif->camss->dev, "%s: ispif stop timeout\n", 55962306a36Sopenharmony_ci __func__); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci return ret; 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci/* 56562306a36Sopenharmony_ci * ispif_select_csid - Select CSID HW module for input from 56662306a36Sopenharmony_ci * @ispif: ISPIF device 56762306a36Sopenharmony_ci * @intf: VFE interface 56862306a36Sopenharmony_ci * @csid: CSID HW module id 56962306a36Sopenharmony_ci * @vfe: VFE HW module id 57062306a36Sopenharmony_ci * @enable: enable or disable the selected input 57162306a36Sopenharmony_ci */ 57262306a36Sopenharmony_cistatic void ispif_select_csid(struct ispif_device *ispif, enum ispif_intf intf, 57362306a36Sopenharmony_ci u8 csid, u8 vfe, u8 enable) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci u32 val; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci val = readl_relaxed(ispif->base + ISPIF_VFE_m_INTF_INPUT_SEL(vfe)); 57862306a36Sopenharmony_ci switch (intf) { 57962306a36Sopenharmony_ci case PIX0: 58062306a36Sopenharmony_ci val &= ~(BIT(1) | BIT(0)); 58162306a36Sopenharmony_ci if (enable) 58262306a36Sopenharmony_ci val |= csid; 58362306a36Sopenharmony_ci break; 58462306a36Sopenharmony_ci case RDI0: 58562306a36Sopenharmony_ci val &= ~(BIT(5) | BIT(4)); 58662306a36Sopenharmony_ci if (enable) 58762306a36Sopenharmony_ci val |= (csid << 4); 58862306a36Sopenharmony_ci break; 58962306a36Sopenharmony_ci case PIX1: 59062306a36Sopenharmony_ci val &= ~(BIT(9) | BIT(8)); 59162306a36Sopenharmony_ci if (enable) 59262306a36Sopenharmony_ci val |= (csid << 8); 59362306a36Sopenharmony_ci break; 59462306a36Sopenharmony_ci case RDI1: 59562306a36Sopenharmony_ci val &= ~(BIT(13) | BIT(12)); 59662306a36Sopenharmony_ci if (enable) 59762306a36Sopenharmony_ci val |= (csid << 12); 59862306a36Sopenharmony_ci break; 59962306a36Sopenharmony_ci case RDI2: 60062306a36Sopenharmony_ci val &= ~(BIT(21) | BIT(20)); 60162306a36Sopenharmony_ci if (enable) 60262306a36Sopenharmony_ci val |= (csid << 20); 60362306a36Sopenharmony_ci break; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci writel(val, ispif->base + ISPIF_VFE_m_INTF_INPUT_SEL(vfe)); 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci/* 61062306a36Sopenharmony_ci * ispif_select_cid - Enable/disable desired CID 61162306a36Sopenharmony_ci * @ispif: ISPIF device 61262306a36Sopenharmony_ci * @intf: VFE interface 61362306a36Sopenharmony_ci * @cid: desired CID to enable/disable 61462306a36Sopenharmony_ci * @vfe: VFE HW module id 61562306a36Sopenharmony_ci * @enable: enable or disable the desired CID 61662306a36Sopenharmony_ci */ 61762306a36Sopenharmony_cistatic void ispif_select_cid(struct ispif_device *ispif, enum ispif_intf intf, 61862306a36Sopenharmony_ci u8 cid, u8 vfe, u8 enable) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci u32 cid_mask = 1 << cid; 62162306a36Sopenharmony_ci u32 addr = 0; 62262306a36Sopenharmony_ci u32 val; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci switch (intf) { 62562306a36Sopenharmony_ci case PIX0: 62662306a36Sopenharmony_ci addr = ISPIF_VFE_m_PIX_INTF_n_CID_MASK(vfe, 0); 62762306a36Sopenharmony_ci break; 62862306a36Sopenharmony_ci case RDI0: 62962306a36Sopenharmony_ci addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe, 0); 63062306a36Sopenharmony_ci break; 63162306a36Sopenharmony_ci case PIX1: 63262306a36Sopenharmony_ci addr = ISPIF_VFE_m_PIX_INTF_n_CID_MASK(vfe, 1); 63362306a36Sopenharmony_ci break; 63462306a36Sopenharmony_ci case RDI1: 63562306a36Sopenharmony_ci addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe, 1); 63662306a36Sopenharmony_ci break; 63762306a36Sopenharmony_ci case RDI2: 63862306a36Sopenharmony_ci addr = ISPIF_VFE_m_RDI_INTF_n_CID_MASK(vfe, 2); 63962306a36Sopenharmony_ci break; 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci val = readl_relaxed(ispif->base + addr); 64362306a36Sopenharmony_ci if (enable) 64462306a36Sopenharmony_ci val |= cid_mask; 64562306a36Sopenharmony_ci else 64662306a36Sopenharmony_ci val &= ~cid_mask; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci writel(val, ispif->base + addr); 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci/* 65262306a36Sopenharmony_ci * ispif_config_irq - Enable/disable interrupts for PIX/RDI interface 65362306a36Sopenharmony_ci * @ispif: ISPIF device 65462306a36Sopenharmony_ci * @intf: VFE interface 65562306a36Sopenharmony_ci * @vfe: VFE HW module id 65662306a36Sopenharmony_ci * @enable: enable or disable 65762306a36Sopenharmony_ci */ 65862306a36Sopenharmony_cistatic void ispif_config_irq(struct ispif_device *ispif, enum ispif_intf intf, 65962306a36Sopenharmony_ci u8 vfe, u8 enable) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci u32 val; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci switch (intf) { 66462306a36Sopenharmony_ci case PIX0: 66562306a36Sopenharmony_ci val = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_MASK_0(vfe)); 66662306a36Sopenharmony_ci val &= ~ISPIF_VFE_m_IRQ_MASK_0_PIX0_MASK; 66762306a36Sopenharmony_ci if (enable) 66862306a36Sopenharmony_ci val |= ISPIF_VFE_m_IRQ_MASK_0_PIX0_ENABLE; 66962306a36Sopenharmony_ci writel_relaxed(val, ispif->base + ISPIF_VFE_m_IRQ_MASK_0(vfe)); 67062306a36Sopenharmony_ci writel_relaxed(ISPIF_VFE_m_IRQ_MASK_0_PIX0_ENABLE, 67162306a36Sopenharmony_ci ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(vfe)); 67262306a36Sopenharmony_ci break; 67362306a36Sopenharmony_ci case RDI0: 67462306a36Sopenharmony_ci val = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_MASK_0(vfe)); 67562306a36Sopenharmony_ci val &= ~ISPIF_VFE_m_IRQ_MASK_0_RDI0_MASK; 67662306a36Sopenharmony_ci if (enable) 67762306a36Sopenharmony_ci val |= ISPIF_VFE_m_IRQ_MASK_0_RDI0_ENABLE; 67862306a36Sopenharmony_ci writel_relaxed(val, ispif->base + ISPIF_VFE_m_IRQ_MASK_0(vfe)); 67962306a36Sopenharmony_ci writel_relaxed(ISPIF_VFE_m_IRQ_MASK_0_RDI0_ENABLE, 68062306a36Sopenharmony_ci ispif->base + ISPIF_VFE_m_IRQ_CLEAR_0(vfe)); 68162306a36Sopenharmony_ci break; 68262306a36Sopenharmony_ci case PIX1: 68362306a36Sopenharmony_ci val = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_MASK_1(vfe)); 68462306a36Sopenharmony_ci val &= ~ISPIF_VFE_m_IRQ_MASK_1_PIX1_MASK; 68562306a36Sopenharmony_ci if (enable) 68662306a36Sopenharmony_ci val |= ISPIF_VFE_m_IRQ_MASK_1_PIX1_ENABLE; 68762306a36Sopenharmony_ci writel_relaxed(val, ispif->base + ISPIF_VFE_m_IRQ_MASK_1(vfe)); 68862306a36Sopenharmony_ci writel_relaxed(ISPIF_VFE_m_IRQ_MASK_1_PIX1_ENABLE, 68962306a36Sopenharmony_ci ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(vfe)); 69062306a36Sopenharmony_ci break; 69162306a36Sopenharmony_ci case RDI1: 69262306a36Sopenharmony_ci val = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_MASK_1(vfe)); 69362306a36Sopenharmony_ci val &= ~ISPIF_VFE_m_IRQ_MASK_1_RDI1_MASK; 69462306a36Sopenharmony_ci if (enable) 69562306a36Sopenharmony_ci val |= ISPIF_VFE_m_IRQ_MASK_1_RDI1_ENABLE; 69662306a36Sopenharmony_ci writel_relaxed(val, ispif->base + ISPIF_VFE_m_IRQ_MASK_1(vfe)); 69762306a36Sopenharmony_ci writel_relaxed(ISPIF_VFE_m_IRQ_MASK_1_RDI1_ENABLE, 69862306a36Sopenharmony_ci ispif->base + ISPIF_VFE_m_IRQ_CLEAR_1(vfe)); 69962306a36Sopenharmony_ci break; 70062306a36Sopenharmony_ci case RDI2: 70162306a36Sopenharmony_ci val = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_MASK_2(vfe)); 70262306a36Sopenharmony_ci val &= ~ISPIF_VFE_m_IRQ_MASK_2_RDI2_MASK; 70362306a36Sopenharmony_ci if (enable) 70462306a36Sopenharmony_ci val |= ISPIF_VFE_m_IRQ_MASK_2_RDI2_ENABLE; 70562306a36Sopenharmony_ci writel_relaxed(val, ispif->base + ISPIF_VFE_m_IRQ_MASK_2(vfe)); 70662306a36Sopenharmony_ci writel_relaxed(ISPIF_VFE_m_IRQ_MASK_2_RDI2_ENABLE, 70762306a36Sopenharmony_ci ispif->base + ISPIF_VFE_m_IRQ_CLEAR_2(vfe)); 70862306a36Sopenharmony_ci break; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci writel(0x1, ispif->base + ISPIF_IRQ_GLOBAL_CLEAR_CMD); 71262306a36Sopenharmony_ci} 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci/* 71562306a36Sopenharmony_ci * ispif_config_pack - Config packing for PRDI mode 71662306a36Sopenharmony_ci * @ispif: ISPIF device 71762306a36Sopenharmony_ci * @code: media bus format code 71862306a36Sopenharmony_ci * @intf: VFE interface 71962306a36Sopenharmony_ci * @cid: desired CID to handle 72062306a36Sopenharmony_ci * @vfe: VFE HW module id 72162306a36Sopenharmony_ci * @enable: enable or disable 72262306a36Sopenharmony_ci */ 72362306a36Sopenharmony_cistatic void ispif_config_pack(struct ispif_device *ispif, u32 code, 72462306a36Sopenharmony_ci enum ispif_intf intf, u8 cid, u8 vfe, u8 enable) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci u32 addr, val; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci if (code != MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE && 72962306a36Sopenharmony_ci code != MEDIA_BUS_FMT_Y10_2X8_PADHI_LE) 73062306a36Sopenharmony_ci return; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci switch (intf) { 73362306a36Sopenharmony_ci case RDI0: 73462306a36Sopenharmony_ci if (cid < 8) 73562306a36Sopenharmony_ci addr = ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_0(vfe, 0); 73662306a36Sopenharmony_ci else 73762306a36Sopenharmony_ci addr = ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_1(vfe, 0); 73862306a36Sopenharmony_ci break; 73962306a36Sopenharmony_ci case RDI1: 74062306a36Sopenharmony_ci if (cid < 8) 74162306a36Sopenharmony_ci addr = ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_0(vfe, 1); 74262306a36Sopenharmony_ci else 74362306a36Sopenharmony_ci addr = ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_1(vfe, 1); 74462306a36Sopenharmony_ci break; 74562306a36Sopenharmony_ci case RDI2: 74662306a36Sopenharmony_ci if (cid < 8) 74762306a36Sopenharmony_ci addr = ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_0(vfe, 2); 74862306a36Sopenharmony_ci else 74962306a36Sopenharmony_ci addr = ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_1(vfe, 2); 75062306a36Sopenharmony_ci break; 75162306a36Sopenharmony_ci default: 75262306a36Sopenharmony_ci return; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci if (enable) 75662306a36Sopenharmony_ci val = ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_0_CID_c_PLAIN(cid); 75762306a36Sopenharmony_ci else 75862306a36Sopenharmony_ci val = 0; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci writel_relaxed(val, ispif->base + addr); 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci/* 76462306a36Sopenharmony_ci * ispif_set_intf_cmd - Set command to enable/disable interface 76562306a36Sopenharmony_ci * @ispif: ISPIF device 76662306a36Sopenharmony_ci * @cmd: interface command 76762306a36Sopenharmony_ci * @intf: VFE interface 76862306a36Sopenharmony_ci * @vfe: VFE HW module id 76962306a36Sopenharmony_ci * @vc: virtual channel 77062306a36Sopenharmony_ci */ 77162306a36Sopenharmony_cistatic void ispif_set_intf_cmd(struct ispif_device *ispif, u8 cmd, 77262306a36Sopenharmony_ci enum ispif_intf intf, u8 vfe, u8 vc) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci u32 *val; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci if (intf == RDI2) { 77762306a36Sopenharmony_ci val = &ispif->intf_cmd[vfe].cmd_1; 77862306a36Sopenharmony_ci *val &= ~(0x3 << (vc * 2 + 8)); 77962306a36Sopenharmony_ci *val |= (cmd << (vc * 2 + 8)); 78062306a36Sopenharmony_ci wmb(); 78162306a36Sopenharmony_ci writel_relaxed(*val, ispif->base + ISPIF_VFE_m_INTF_CMD_1(vfe)); 78262306a36Sopenharmony_ci wmb(); 78362306a36Sopenharmony_ci } else { 78462306a36Sopenharmony_ci val = &ispif->intf_cmd[vfe].cmd_0; 78562306a36Sopenharmony_ci *val &= ~(0x3 << (vc * 2 + intf * 8)); 78662306a36Sopenharmony_ci *val |= (cmd << (vc * 2 + intf * 8)); 78762306a36Sopenharmony_ci wmb(); 78862306a36Sopenharmony_ci writel_relaxed(*val, ispif->base + ISPIF_VFE_m_INTF_CMD_0(vfe)); 78962306a36Sopenharmony_ci wmb(); 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci/* 79462306a36Sopenharmony_ci * ispif_set_stream - Enable/disable streaming on ISPIF module 79562306a36Sopenharmony_ci * @sd: ISPIF V4L2 subdevice 79662306a36Sopenharmony_ci * @enable: Requested streaming state 79762306a36Sopenharmony_ci * 79862306a36Sopenharmony_ci * Main configuration of ISPIF module is also done here. 79962306a36Sopenharmony_ci * 80062306a36Sopenharmony_ci * Return 0 on success or a negative error code otherwise 80162306a36Sopenharmony_ci */ 80262306a36Sopenharmony_cistatic int ispif_set_stream(struct v4l2_subdev *sd, int enable) 80362306a36Sopenharmony_ci{ 80462306a36Sopenharmony_ci struct ispif_line *line = v4l2_get_subdevdata(sd); 80562306a36Sopenharmony_ci struct ispif_device *ispif = line->ispif; 80662306a36Sopenharmony_ci struct camss *camss = ispif->camss; 80762306a36Sopenharmony_ci enum ispif_intf intf = line->interface; 80862306a36Sopenharmony_ci u8 csid = line->csid_id; 80962306a36Sopenharmony_ci u8 vfe = line->vfe_id; 81062306a36Sopenharmony_ci u8 vc = 0; /* Virtual Channel 0 */ 81162306a36Sopenharmony_ci u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */ 81262306a36Sopenharmony_ci int ret; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci if (enable) { 81562306a36Sopenharmony_ci if (!media_pad_remote_pad_first(&line->pads[MSM_ISPIF_PAD_SINK])) 81662306a36Sopenharmony_ci return -ENOLINK; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci /* Config */ 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci mutex_lock(&ispif->config_lock); 82162306a36Sopenharmony_ci ispif_select_clk_mux(ispif, intf, csid, vfe, 1); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci ret = ispif_validate_intf_status(ispif, intf, vfe); 82462306a36Sopenharmony_ci if (ret < 0) { 82562306a36Sopenharmony_ci mutex_unlock(&ispif->config_lock); 82662306a36Sopenharmony_ci return ret; 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci ispif_select_csid(ispif, intf, csid, vfe, 1); 83062306a36Sopenharmony_ci ispif_select_cid(ispif, intf, cid, vfe, 1); 83162306a36Sopenharmony_ci ispif_config_irq(ispif, intf, vfe, 1); 83262306a36Sopenharmony_ci if (camss->version == CAMSS_8x96 || 83362306a36Sopenharmony_ci camss->version == CAMSS_660) 83462306a36Sopenharmony_ci ispif_config_pack(ispif, 83562306a36Sopenharmony_ci line->fmt[MSM_ISPIF_PAD_SINK].code, 83662306a36Sopenharmony_ci intf, cid, vfe, 1); 83762306a36Sopenharmony_ci ispif_set_intf_cmd(ispif, CMD_ENABLE_FRAME_BOUNDARY, 83862306a36Sopenharmony_ci intf, vfe, vc); 83962306a36Sopenharmony_ci } else { 84062306a36Sopenharmony_ci mutex_lock(&ispif->config_lock); 84162306a36Sopenharmony_ci ispif_set_intf_cmd(ispif, CMD_DISABLE_FRAME_BOUNDARY, 84262306a36Sopenharmony_ci intf, vfe, vc); 84362306a36Sopenharmony_ci mutex_unlock(&ispif->config_lock); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci ret = ispif_wait_for_stop(ispif, intf, vfe); 84662306a36Sopenharmony_ci if (ret < 0) 84762306a36Sopenharmony_ci return ret; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci mutex_lock(&ispif->config_lock); 85062306a36Sopenharmony_ci if (camss->version == CAMSS_8x96 || 85162306a36Sopenharmony_ci camss->version == CAMSS_660) 85262306a36Sopenharmony_ci ispif_config_pack(ispif, 85362306a36Sopenharmony_ci line->fmt[MSM_ISPIF_PAD_SINK].code, 85462306a36Sopenharmony_ci intf, cid, vfe, 0); 85562306a36Sopenharmony_ci ispif_config_irq(ispif, intf, vfe, 0); 85662306a36Sopenharmony_ci ispif_select_cid(ispif, intf, cid, vfe, 0); 85762306a36Sopenharmony_ci ispif_select_csid(ispif, intf, csid, vfe, 0); 85862306a36Sopenharmony_ci ispif_select_clk_mux(ispif, intf, csid, vfe, 0); 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci mutex_unlock(&ispif->config_lock); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci return 0; 86462306a36Sopenharmony_ci} 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci/* 86762306a36Sopenharmony_ci * __ispif_get_format - Get pointer to format structure 86862306a36Sopenharmony_ci * @ispif: ISPIF line 86962306a36Sopenharmony_ci * @cfg: V4L2 subdev pad configuration 87062306a36Sopenharmony_ci * @pad: pad from which format is requested 87162306a36Sopenharmony_ci * @which: TRY or ACTIVE format 87262306a36Sopenharmony_ci * 87362306a36Sopenharmony_ci * Return pointer to TRY or ACTIVE format structure 87462306a36Sopenharmony_ci */ 87562306a36Sopenharmony_cistatic struct v4l2_mbus_framefmt * 87662306a36Sopenharmony_ci__ispif_get_format(struct ispif_line *line, 87762306a36Sopenharmony_ci struct v4l2_subdev_state *sd_state, 87862306a36Sopenharmony_ci unsigned int pad, 87962306a36Sopenharmony_ci enum v4l2_subdev_format_whence which) 88062306a36Sopenharmony_ci{ 88162306a36Sopenharmony_ci if (which == V4L2_SUBDEV_FORMAT_TRY) 88262306a36Sopenharmony_ci return v4l2_subdev_get_try_format(&line->subdev, sd_state, 88362306a36Sopenharmony_ci pad); 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci return &line->fmt[pad]; 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci/* 88962306a36Sopenharmony_ci * ispif_try_format - Handle try format by pad subdev method 89062306a36Sopenharmony_ci * @ispif: ISPIF line 89162306a36Sopenharmony_ci * @cfg: V4L2 subdev pad configuration 89262306a36Sopenharmony_ci * @pad: pad on which format is requested 89362306a36Sopenharmony_ci * @fmt: pointer to v4l2 format structure 89462306a36Sopenharmony_ci * @which: wanted subdev format 89562306a36Sopenharmony_ci */ 89662306a36Sopenharmony_cistatic void ispif_try_format(struct ispif_line *line, 89762306a36Sopenharmony_ci struct v4l2_subdev_state *sd_state, 89862306a36Sopenharmony_ci unsigned int pad, 89962306a36Sopenharmony_ci struct v4l2_mbus_framefmt *fmt, 90062306a36Sopenharmony_ci enum v4l2_subdev_format_whence which) 90162306a36Sopenharmony_ci{ 90262306a36Sopenharmony_ci unsigned int i; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci switch (pad) { 90562306a36Sopenharmony_ci case MSM_ISPIF_PAD_SINK: 90662306a36Sopenharmony_ci /* Set format on sink pad */ 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci for (i = 0; i < line->nformats; i++) 90962306a36Sopenharmony_ci if (fmt->code == line->formats[i]) 91062306a36Sopenharmony_ci break; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci /* If not found, use UYVY as default */ 91362306a36Sopenharmony_ci if (i >= line->nformats) 91462306a36Sopenharmony_ci fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci fmt->width = clamp_t(u32, fmt->width, 1, 8191); 91762306a36Sopenharmony_ci fmt->height = clamp_t(u32, fmt->height, 1, 8191); 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci fmt->field = V4L2_FIELD_NONE; 92062306a36Sopenharmony_ci fmt->colorspace = V4L2_COLORSPACE_SRGB; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci break; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci case MSM_ISPIF_PAD_SRC: 92562306a36Sopenharmony_ci /* Set and return a format same as sink pad */ 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci *fmt = *__ispif_get_format(line, sd_state, MSM_ISPIF_PAD_SINK, 92862306a36Sopenharmony_ci which); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci break; 93162306a36Sopenharmony_ci } 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci fmt->colorspace = V4L2_COLORSPACE_SRGB; 93462306a36Sopenharmony_ci} 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci/* 93762306a36Sopenharmony_ci * ispif_enum_mbus_code - Handle pixel format enumeration 93862306a36Sopenharmony_ci * @sd: ISPIF V4L2 subdevice 93962306a36Sopenharmony_ci * @cfg: V4L2 subdev pad configuration 94062306a36Sopenharmony_ci * @code: pointer to v4l2_subdev_mbus_code_enum structure 94162306a36Sopenharmony_ci * return -EINVAL or zero on success 94262306a36Sopenharmony_ci */ 94362306a36Sopenharmony_cistatic int ispif_enum_mbus_code(struct v4l2_subdev *sd, 94462306a36Sopenharmony_ci struct v4l2_subdev_state *sd_state, 94562306a36Sopenharmony_ci struct v4l2_subdev_mbus_code_enum *code) 94662306a36Sopenharmony_ci{ 94762306a36Sopenharmony_ci struct ispif_line *line = v4l2_get_subdevdata(sd); 94862306a36Sopenharmony_ci struct v4l2_mbus_framefmt *format; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci if (code->pad == MSM_ISPIF_PAD_SINK) { 95162306a36Sopenharmony_ci if (code->index >= line->nformats) 95262306a36Sopenharmony_ci return -EINVAL; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci code->code = line->formats[code->index]; 95562306a36Sopenharmony_ci } else { 95662306a36Sopenharmony_ci if (code->index > 0) 95762306a36Sopenharmony_ci return -EINVAL; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci format = __ispif_get_format(line, sd_state, 96062306a36Sopenharmony_ci MSM_ISPIF_PAD_SINK, 96162306a36Sopenharmony_ci code->which); 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci code->code = format->code; 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci return 0; 96762306a36Sopenharmony_ci} 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci/* 97062306a36Sopenharmony_ci * ispif_enum_frame_size - Handle frame size enumeration 97162306a36Sopenharmony_ci * @sd: ISPIF V4L2 subdevice 97262306a36Sopenharmony_ci * @cfg: V4L2 subdev pad configuration 97362306a36Sopenharmony_ci * @fse: pointer to v4l2_subdev_frame_size_enum structure 97462306a36Sopenharmony_ci * return -EINVAL or zero on success 97562306a36Sopenharmony_ci */ 97662306a36Sopenharmony_cistatic int ispif_enum_frame_size(struct v4l2_subdev *sd, 97762306a36Sopenharmony_ci struct v4l2_subdev_state *sd_state, 97862306a36Sopenharmony_ci struct v4l2_subdev_frame_size_enum *fse) 97962306a36Sopenharmony_ci{ 98062306a36Sopenharmony_ci struct ispif_line *line = v4l2_get_subdevdata(sd); 98162306a36Sopenharmony_ci struct v4l2_mbus_framefmt format; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci if (fse->index != 0) 98462306a36Sopenharmony_ci return -EINVAL; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci format.code = fse->code; 98762306a36Sopenharmony_ci format.width = 1; 98862306a36Sopenharmony_ci format.height = 1; 98962306a36Sopenharmony_ci ispif_try_format(line, sd_state, fse->pad, &format, fse->which); 99062306a36Sopenharmony_ci fse->min_width = format.width; 99162306a36Sopenharmony_ci fse->min_height = format.height; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci if (format.code != fse->code) 99462306a36Sopenharmony_ci return -EINVAL; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci format.code = fse->code; 99762306a36Sopenharmony_ci format.width = -1; 99862306a36Sopenharmony_ci format.height = -1; 99962306a36Sopenharmony_ci ispif_try_format(line, sd_state, fse->pad, &format, fse->which); 100062306a36Sopenharmony_ci fse->max_width = format.width; 100162306a36Sopenharmony_ci fse->max_height = format.height; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci return 0; 100462306a36Sopenharmony_ci} 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci/* 100762306a36Sopenharmony_ci * ispif_get_format - Handle get format by pads subdev method 100862306a36Sopenharmony_ci * @sd: ISPIF V4L2 subdevice 100962306a36Sopenharmony_ci * @cfg: V4L2 subdev pad configuration 101062306a36Sopenharmony_ci * @fmt: pointer to v4l2 subdev format structure 101162306a36Sopenharmony_ci * 101262306a36Sopenharmony_ci * Return -EINVAL or zero on success 101362306a36Sopenharmony_ci */ 101462306a36Sopenharmony_cistatic int ispif_get_format(struct v4l2_subdev *sd, 101562306a36Sopenharmony_ci struct v4l2_subdev_state *sd_state, 101662306a36Sopenharmony_ci struct v4l2_subdev_format *fmt) 101762306a36Sopenharmony_ci{ 101862306a36Sopenharmony_ci struct ispif_line *line = v4l2_get_subdevdata(sd); 101962306a36Sopenharmony_ci struct v4l2_mbus_framefmt *format; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci format = __ispif_get_format(line, sd_state, fmt->pad, fmt->which); 102262306a36Sopenharmony_ci if (format == NULL) 102362306a36Sopenharmony_ci return -EINVAL; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci fmt->format = *format; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci return 0; 102862306a36Sopenharmony_ci} 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci/* 103162306a36Sopenharmony_ci * ispif_set_format - Handle set format by pads subdev method 103262306a36Sopenharmony_ci * @sd: ISPIF V4L2 subdevice 103362306a36Sopenharmony_ci * @cfg: V4L2 subdev pad configuration 103462306a36Sopenharmony_ci * @fmt: pointer to v4l2 subdev format structure 103562306a36Sopenharmony_ci * 103662306a36Sopenharmony_ci * Return -EINVAL or zero on success 103762306a36Sopenharmony_ci */ 103862306a36Sopenharmony_cistatic int ispif_set_format(struct v4l2_subdev *sd, 103962306a36Sopenharmony_ci struct v4l2_subdev_state *sd_state, 104062306a36Sopenharmony_ci struct v4l2_subdev_format *fmt) 104162306a36Sopenharmony_ci{ 104262306a36Sopenharmony_ci struct ispif_line *line = v4l2_get_subdevdata(sd); 104362306a36Sopenharmony_ci struct v4l2_mbus_framefmt *format; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci format = __ispif_get_format(line, sd_state, fmt->pad, fmt->which); 104662306a36Sopenharmony_ci if (format == NULL) 104762306a36Sopenharmony_ci return -EINVAL; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci ispif_try_format(line, sd_state, fmt->pad, &fmt->format, fmt->which); 105062306a36Sopenharmony_ci *format = fmt->format; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci /* Propagate the format from sink to source */ 105362306a36Sopenharmony_ci if (fmt->pad == MSM_ISPIF_PAD_SINK) { 105462306a36Sopenharmony_ci format = __ispif_get_format(line, sd_state, MSM_ISPIF_PAD_SRC, 105562306a36Sopenharmony_ci fmt->which); 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci *format = fmt->format; 105862306a36Sopenharmony_ci ispif_try_format(line, sd_state, MSM_ISPIF_PAD_SRC, format, 105962306a36Sopenharmony_ci fmt->which); 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci return 0; 106362306a36Sopenharmony_ci} 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci/* 106662306a36Sopenharmony_ci * ispif_init_formats - Initialize formats on all pads 106762306a36Sopenharmony_ci * @sd: ISPIF V4L2 subdevice 106862306a36Sopenharmony_ci * @fh: V4L2 subdev file handle 106962306a36Sopenharmony_ci * 107062306a36Sopenharmony_ci * Initialize all pad formats with default values. 107162306a36Sopenharmony_ci * 107262306a36Sopenharmony_ci * Return 0 on success or a negative error code otherwise 107362306a36Sopenharmony_ci */ 107462306a36Sopenharmony_cistatic int ispif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 107562306a36Sopenharmony_ci{ 107662306a36Sopenharmony_ci struct v4l2_subdev_format format = { 107762306a36Sopenharmony_ci .pad = MSM_ISPIF_PAD_SINK, 107862306a36Sopenharmony_ci .which = fh ? V4L2_SUBDEV_FORMAT_TRY : 107962306a36Sopenharmony_ci V4L2_SUBDEV_FORMAT_ACTIVE, 108062306a36Sopenharmony_ci .format = { 108162306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_UYVY8_2X8, 108262306a36Sopenharmony_ci .width = 1920, 108362306a36Sopenharmony_ci .height = 1080 108462306a36Sopenharmony_ci } 108562306a36Sopenharmony_ci }; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci return ispif_set_format(sd, fh ? fh->state : NULL, &format); 108862306a36Sopenharmony_ci} 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci/* 109162306a36Sopenharmony_ci * msm_ispif_subdev_init - Initialize ISPIF device structure and resources 109262306a36Sopenharmony_ci * @ispif: ISPIF device 109362306a36Sopenharmony_ci * @res: ISPIF module resources table 109462306a36Sopenharmony_ci * 109562306a36Sopenharmony_ci * Return 0 on success or a negative error code otherwise 109662306a36Sopenharmony_ci */ 109762306a36Sopenharmony_ciint msm_ispif_subdev_init(struct camss *camss, 109862306a36Sopenharmony_ci const struct resources_ispif *res) 109962306a36Sopenharmony_ci{ 110062306a36Sopenharmony_ci struct device *dev = camss->dev; 110162306a36Sopenharmony_ci struct ispif_device *ispif = camss->ispif; 110262306a36Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 110362306a36Sopenharmony_ci int i; 110462306a36Sopenharmony_ci int ret; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci if (!camss->ispif) 110762306a36Sopenharmony_ci return 0; 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci ispif->camss = camss; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci /* Number of ISPIF lines - same as number of CSID hardware modules */ 111262306a36Sopenharmony_ci if (camss->version == CAMSS_8x16) 111362306a36Sopenharmony_ci ispif->line_num = 2; 111462306a36Sopenharmony_ci else if (camss->version == CAMSS_8x96 || 111562306a36Sopenharmony_ci camss->version == CAMSS_660) 111662306a36Sopenharmony_ci ispif->line_num = 4; 111762306a36Sopenharmony_ci else 111862306a36Sopenharmony_ci return -EINVAL; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci ispif->line = devm_kcalloc(dev, ispif->line_num, 112162306a36Sopenharmony_ci sizeof(*ispif->line), GFP_KERNEL); 112262306a36Sopenharmony_ci if (!ispif->line) 112362306a36Sopenharmony_ci return -ENOMEM; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci for (i = 0; i < ispif->line_num; i++) { 112662306a36Sopenharmony_ci ispif->line[i].ispif = ispif; 112762306a36Sopenharmony_ci ispif->line[i].id = i; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci if (camss->version == CAMSS_8x16) { 113062306a36Sopenharmony_ci ispif->line[i].formats = ispif_formats_8x16; 113162306a36Sopenharmony_ci ispif->line[i].nformats = 113262306a36Sopenharmony_ci ARRAY_SIZE(ispif_formats_8x16); 113362306a36Sopenharmony_ci } else if (camss->version == CAMSS_8x96 || 113462306a36Sopenharmony_ci camss->version == CAMSS_660) { 113562306a36Sopenharmony_ci ispif->line[i].formats = ispif_formats_8x96; 113662306a36Sopenharmony_ci ispif->line[i].nformats = 113762306a36Sopenharmony_ci ARRAY_SIZE(ispif_formats_8x96); 113862306a36Sopenharmony_ci } else { 113962306a36Sopenharmony_ci return -EINVAL; 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci } 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci /* Memory */ 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci ispif->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]); 114662306a36Sopenharmony_ci if (IS_ERR(ispif->base)) 114762306a36Sopenharmony_ci return PTR_ERR(ispif->base); 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci ispif->base_clk_mux = devm_platform_ioremap_resource_byname(pdev, res->reg[1]); 115062306a36Sopenharmony_ci if (IS_ERR(ispif->base_clk_mux)) 115162306a36Sopenharmony_ci return PTR_ERR(ispif->base_clk_mux); 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci /* Interrupt */ 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci ret = platform_get_irq_byname(pdev, res->interrupt); 115662306a36Sopenharmony_ci if (ret < 0) 115762306a36Sopenharmony_ci return ret; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci ispif->irq = ret; 116062306a36Sopenharmony_ci snprintf(ispif->irq_name, sizeof(ispif->irq_name), "%s_%s", 116162306a36Sopenharmony_ci dev_name(dev), MSM_ISPIF_NAME); 116262306a36Sopenharmony_ci if (camss->version == CAMSS_8x16) 116362306a36Sopenharmony_ci ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x16, 116462306a36Sopenharmony_ci IRQF_TRIGGER_RISING, ispif->irq_name, ispif); 116562306a36Sopenharmony_ci else if (camss->version == CAMSS_8x96 || 116662306a36Sopenharmony_ci camss->version == CAMSS_660) 116762306a36Sopenharmony_ci ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x96, 116862306a36Sopenharmony_ci IRQF_TRIGGER_RISING, ispif->irq_name, ispif); 116962306a36Sopenharmony_ci else 117062306a36Sopenharmony_ci ret = -EINVAL; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci if (ret < 0) { 117362306a36Sopenharmony_ci dev_err(dev, "request_irq failed: %d\n", ret); 117462306a36Sopenharmony_ci return ret; 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci /* Clocks */ 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci ispif->nclocks = 0; 118062306a36Sopenharmony_ci while (res->clock[ispif->nclocks]) 118162306a36Sopenharmony_ci ispif->nclocks++; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci ispif->clock = devm_kcalloc(dev, 118462306a36Sopenharmony_ci ispif->nclocks, sizeof(*ispif->clock), 118562306a36Sopenharmony_ci GFP_KERNEL); 118662306a36Sopenharmony_ci if (!ispif->clock) 118762306a36Sopenharmony_ci return -ENOMEM; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci for (i = 0; i < ispif->nclocks; i++) { 119062306a36Sopenharmony_ci struct camss_clock *clock = &ispif->clock[i]; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci clock->clk = devm_clk_get(dev, res->clock[i]); 119362306a36Sopenharmony_ci if (IS_ERR(clock->clk)) 119462306a36Sopenharmony_ci return PTR_ERR(clock->clk); 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci clock->freq = NULL; 119762306a36Sopenharmony_ci clock->nfreqs = 0; 119862306a36Sopenharmony_ci } 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci ispif->nclocks_for_reset = 0; 120162306a36Sopenharmony_ci while (res->clock_for_reset[ispif->nclocks_for_reset]) 120262306a36Sopenharmony_ci ispif->nclocks_for_reset++; 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci ispif->clock_for_reset = devm_kcalloc(dev, 120562306a36Sopenharmony_ci ispif->nclocks_for_reset, 120662306a36Sopenharmony_ci sizeof(*ispif->clock_for_reset), 120762306a36Sopenharmony_ci GFP_KERNEL); 120862306a36Sopenharmony_ci if (!ispif->clock_for_reset) 120962306a36Sopenharmony_ci return -ENOMEM; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci for (i = 0; i < ispif->nclocks_for_reset; i++) { 121262306a36Sopenharmony_ci struct camss_clock *clock = &ispif->clock_for_reset[i]; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci clock->clk = devm_clk_get(dev, res->clock_for_reset[i]); 121562306a36Sopenharmony_ci if (IS_ERR(clock->clk)) 121662306a36Sopenharmony_ci return PTR_ERR(clock->clk); 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci clock->freq = NULL; 121962306a36Sopenharmony_ci clock->nfreqs = 0; 122062306a36Sopenharmony_ci } 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci mutex_init(&ispif->power_lock); 122362306a36Sopenharmony_ci ispif->power_count = 0; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci mutex_init(&ispif->config_lock); 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci for (i = 0; i < MSM_ISPIF_VFE_NUM; i++) 122862306a36Sopenharmony_ci init_completion(&ispif->reset_complete[i]); 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci return 0; 123162306a36Sopenharmony_ci} 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci/* 123462306a36Sopenharmony_ci * ispif_get_intf - Get ISPIF interface to use by VFE line id 123562306a36Sopenharmony_ci * @line_id: VFE line id that the ISPIF line is connected to 123662306a36Sopenharmony_ci * 123762306a36Sopenharmony_ci * Return ISPIF interface to use 123862306a36Sopenharmony_ci */ 123962306a36Sopenharmony_cistatic enum ispif_intf ispif_get_intf(enum vfe_line_id line_id) 124062306a36Sopenharmony_ci{ 124162306a36Sopenharmony_ci switch (line_id) { 124262306a36Sopenharmony_ci case (VFE_LINE_RDI0): 124362306a36Sopenharmony_ci return RDI0; 124462306a36Sopenharmony_ci case (VFE_LINE_RDI1): 124562306a36Sopenharmony_ci return RDI1; 124662306a36Sopenharmony_ci case (VFE_LINE_RDI2): 124762306a36Sopenharmony_ci return RDI2; 124862306a36Sopenharmony_ci case (VFE_LINE_PIX): 124962306a36Sopenharmony_ci return PIX0; 125062306a36Sopenharmony_ci default: 125162306a36Sopenharmony_ci return RDI0; 125262306a36Sopenharmony_ci } 125362306a36Sopenharmony_ci} 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci/* 125662306a36Sopenharmony_ci * ispif_get_vfe_id - Get VFE HW module id 125762306a36Sopenharmony_ci * @entity: Pointer to VFE media entity structure 125862306a36Sopenharmony_ci * @id: Return CSID HW module id here 125962306a36Sopenharmony_ci */ 126062306a36Sopenharmony_cistatic void ispif_get_vfe_id(struct media_entity *entity, u8 *id) 126162306a36Sopenharmony_ci{ 126262306a36Sopenharmony_ci struct v4l2_subdev *sd; 126362306a36Sopenharmony_ci struct vfe_line *line; 126462306a36Sopenharmony_ci struct vfe_device *vfe; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci sd = media_entity_to_v4l2_subdev(entity); 126762306a36Sopenharmony_ci line = v4l2_get_subdevdata(sd); 126862306a36Sopenharmony_ci vfe = to_vfe(line); 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci *id = vfe->id; 127162306a36Sopenharmony_ci} 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci/* 127462306a36Sopenharmony_ci * ispif_get_vfe_line_id - Get VFE line id by media entity 127562306a36Sopenharmony_ci * @entity: Pointer to VFE media entity structure 127662306a36Sopenharmony_ci * @id: Return VFE line id here 127762306a36Sopenharmony_ci */ 127862306a36Sopenharmony_cistatic void ispif_get_vfe_line_id(struct media_entity *entity, 127962306a36Sopenharmony_ci enum vfe_line_id *id) 128062306a36Sopenharmony_ci{ 128162306a36Sopenharmony_ci struct v4l2_subdev *sd; 128262306a36Sopenharmony_ci struct vfe_line *line; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci sd = media_entity_to_v4l2_subdev(entity); 128562306a36Sopenharmony_ci line = v4l2_get_subdevdata(sd); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci *id = line->id; 128862306a36Sopenharmony_ci} 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci/* 129162306a36Sopenharmony_ci * ispif_link_setup - Setup ISPIF connections 129262306a36Sopenharmony_ci * @entity: Pointer to media entity structure 129362306a36Sopenharmony_ci * @local: Pointer to local pad 129462306a36Sopenharmony_ci * @remote: Pointer to remote pad 129562306a36Sopenharmony_ci * @flags: Link flags 129662306a36Sopenharmony_ci * 129762306a36Sopenharmony_ci * Return 0 on success 129862306a36Sopenharmony_ci */ 129962306a36Sopenharmony_cistatic int ispif_link_setup(struct media_entity *entity, 130062306a36Sopenharmony_ci const struct media_pad *local, 130162306a36Sopenharmony_ci const struct media_pad *remote, u32 flags) 130262306a36Sopenharmony_ci{ 130362306a36Sopenharmony_ci if (flags & MEDIA_LNK_FL_ENABLED) { 130462306a36Sopenharmony_ci if (media_pad_remote_pad_first(local)) 130562306a36Sopenharmony_ci return -EBUSY; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci if (local->flags & MEDIA_PAD_FL_SINK) { 130862306a36Sopenharmony_ci struct v4l2_subdev *sd; 130962306a36Sopenharmony_ci struct ispif_line *line; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci sd = media_entity_to_v4l2_subdev(entity); 131262306a36Sopenharmony_ci line = v4l2_get_subdevdata(sd); 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci msm_csid_get_csid_id(remote->entity, &line->csid_id); 131562306a36Sopenharmony_ci } else { /* MEDIA_PAD_FL_SOURCE */ 131662306a36Sopenharmony_ci struct v4l2_subdev *sd; 131762306a36Sopenharmony_ci struct ispif_line *line; 131862306a36Sopenharmony_ci enum vfe_line_id id; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci sd = media_entity_to_v4l2_subdev(entity); 132162306a36Sopenharmony_ci line = v4l2_get_subdevdata(sd); 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci ispif_get_vfe_id(remote->entity, &line->vfe_id); 132462306a36Sopenharmony_ci ispif_get_vfe_line_id(remote->entity, &id); 132562306a36Sopenharmony_ci line->interface = ispif_get_intf(id); 132662306a36Sopenharmony_ci } 132762306a36Sopenharmony_ci } 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci return 0; 133062306a36Sopenharmony_ci} 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_cistatic const struct v4l2_subdev_core_ops ispif_core_ops = { 133362306a36Sopenharmony_ci .s_power = ispif_set_power, 133462306a36Sopenharmony_ci}; 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_cistatic const struct v4l2_subdev_video_ops ispif_video_ops = { 133762306a36Sopenharmony_ci .s_stream = ispif_set_stream, 133862306a36Sopenharmony_ci}; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_cistatic const struct v4l2_subdev_pad_ops ispif_pad_ops = { 134162306a36Sopenharmony_ci .enum_mbus_code = ispif_enum_mbus_code, 134262306a36Sopenharmony_ci .enum_frame_size = ispif_enum_frame_size, 134362306a36Sopenharmony_ci .get_fmt = ispif_get_format, 134462306a36Sopenharmony_ci .set_fmt = ispif_set_format, 134562306a36Sopenharmony_ci}; 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_cistatic const struct v4l2_subdev_ops ispif_v4l2_ops = { 134862306a36Sopenharmony_ci .core = &ispif_core_ops, 134962306a36Sopenharmony_ci .video = &ispif_video_ops, 135062306a36Sopenharmony_ci .pad = &ispif_pad_ops, 135162306a36Sopenharmony_ci}; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_cistatic const struct v4l2_subdev_internal_ops ispif_v4l2_internal_ops = { 135462306a36Sopenharmony_ci .open = ispif_init_formats, 135562306a36Sopenharmony_ci}; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_cistatic const struct media_entity_operations ispif_media_ops = { 135862306a36Sopenharmony_ci .link_setup = ispif_link_setup, 135962306a36Sopenharmony_ci .link_validate = v4l2_subdev_link_validate, 136062306a36Sopenharmony_ci}; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci/* 136362306a36Sopenharmony_ci * msm_ispif_register_entities - Register subdev node for ISPIF module 136462306a36Sopenharmony_ci * @ispif: ISPIF device 136562306a36Sopenharmony_ci * @v4l2_dev: V4L2 device 136662306a36Sopenharmony_ci * 136762306a36Sopenharmony_ci * Return 0 on success or a negative error code otherwise 136862306a36Sopenharmony_ci */ 136962306a36Sopenharmony_ciint msm_ispif_register_entities(struct ispif_device *ispif, 137062306a36Sopenharmony_ci struct v4l2_device *v4l2_dev) 137162306a36Sopenharmony_ci{ 137262306a36Sopenharmony_ci struct camss *camss; 137362306a36Sopenharmony_ci int ret; 137462306a36Sopenharmony_ci int i; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci if (!ispif) 137762306a36Sopenharmony_ci return 0; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci camss = ispif->camss; 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci for (i = 0; i < ispif->line_num; i++) { 138262306a36Sopenharmony_ci struct v4l2_subdev *sd = &ispif->line[i].subdev; 138362306a36Sopenharmony_ci struct media_pad *pads = ispif->line[i].pads; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci v4l2_subdev_init(sd, &ispif_v4l2_ops); 138662306a36Sopenharmony_ci sd->internal_ops = &ispif_v4l2_internal_ops; 138762306a36Sopenharmony_ci sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 138862306a36Sopenharmony_ci snprintf(sd->name, ARRAY_SIZE(sd->name), "%s%d", 138962306a36Sopenharmony_ci MSM_ISPIF_NAME, i); 139062306a36Sopenharmony_ci v4l2_set_subdevdata(sd, &ispif->line[i]); 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci ret = ispif_init_formats(sd, NULL); 139362306a36Sopenharmony_ci if (ret < 0) { 139462306a36Sopenharmony_ci dev_err(camss->dev, "Failed to init format: %d\n", ret); 139562306a36Sopenharmony_ci goto error; 139662306a36Sopenharmony_ci } 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci pads[MSM_ISPIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 139962306a36Sopenharmony_ci pads[MSM_ISPIF_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; 140262306a36Sopenharmony_ci sd->entity.ops = &ispif_media_ops; 140362306a36Sopenharmony_ci ret = media_entity_pads_init(&sd->entity, MSM_ISPIF_PADS_NUM, 140462306a36Sopenharmony_ci pads); 140562306a36Sopenharmony_ci if (ret < 0) { 140662306a36Sopenharmony_ci dev_err(camss->dev, "Failed to init media entity: %d\n", 140762306a36Sopenharmony_ci ret); 140862306a36Sopenharmony_ci goto error; 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci ret = v4l2_device_register_subdev(v4l2_dev, sd); 141262306a36Sopenharmony_ci if (ret < 0) { 141362306a36Sopenharmony_ci dev_err(camss->dev, "Failed to register subdev: %d\n", 141462306a36Sopenharmony_ci ret); 141562306a36Sopenharmony_ci media_entity_cleanup(&sd->entity); 141662306a36Sopenharmony_ci goto error; 141762306a36Sopenharmony_ci } 141862306a36Sopenharmony_ci } 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci return 0; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_cierror: 142362306a36Sopenharmony_ci for (i--; i >= 0; i--) { 142462306a36Sopenharmony_ci struct v4l2_subdev *sd = &ispif->line[i].subdev; 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci v4l2_device_unregister_subdev(sd); 142762306a36Sopenharmony_ci media_entity_cleanup(&sd->entity); 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci return ret; 143162306a36Sopenharmony_ci} 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci/* 143462306a36Sopenharmony_ci * msm_ispif_unregister_entities - Unregister ISPIF module subdev node 143562306a36Sopenharmony_ci * @ispif: ISPIF device 143662306a36Sopenharmony_ci */ 143762306a36Sopenharmony_civoid msm_ispif_unregister_entities(struct ispif_device *ispif) 143862306a36Sopenharmony_ci{ 143962306a36Sopenharmony_ci int i; 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci if (!ispif) 144262306a36Sopenharmony_ci return; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci mutex_destroy(&ispif->power_lock); 144562306a36Sopenharmony_ci mutex_destroy(&ispif->config_lock); 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci for (i = 0; i < ispif->line_num; i++) { 144862306a36Sopenharmony_ci struct v4l2_subdev *sd = &ispif->line[i].subdev; 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci v4l2_device_unregister_subdev(sd); 145162306a36Sopenharmony_ci media_entity_cleanup(&sd->entity); 145262306a36Sopenharmony_ci } 145362306a36Sopenharmony_ci} 1454