18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ispccp2.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * TI OMAP3 ISP - CCP2 module 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2010 Nokia Corporation 88c2ecf20Sopenharmony_ci * Copyright (C) 2010 Texas Instruments, Inc. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com> 118c2ecf20Sopenharmony_ci * Sakari Ailus <sakari.ailus@iki.fi> 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/delay.h> 158c2ecf20Sopenharmony_ci#include <linux/device.h> 168c2ecf20Sopenharmony_ci#include <linux/mm.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/mutex.h> 198c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 208c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "isp.h" 238c2ecf20Sopenharmony_ci#include "ispreg.h" 248c2ecf20Sopenharmony_ci#include "ispccp2.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* Number of LCX channels */ 278c2ecf20Sopenharmony_ci#define CCP2_LCx_CHANS_NUM 3 288c2ecf20Sopenharmony_ci/* Max/Min size for CCP2 video port */ 298c2ecf20Sopenharmony_ci#define ISPCCP2_DAT_START_MIN 0 308c2ecf20Sopenharmony_ci#define ISPCCP2_DAT_START_MAX 4095 318c2ecf20Sopenharmony_ci#define ISPCCP2_DAT_SIZE_MIN 0 328c2ecf20Sopenharmony_ci#define ISPCCP2_DAT_SIZE_MAX 4095 338c2ecf20Sopenharmony_ci#define ISPCCP2_VPCLK_FRACDIV 65536 348c2ecf20Sopenharmony_ci#define ISPCCP2_LCx_CTRL_FORMAT_RAW8_DPCM10_VP 0x12 358c2ecf20Sopenharmony_ci#define ISPCCP2_LCx_CTRL_FORMAT_RAW10_VP 0x16 368c2ecf20Sopenharmony_ci/* Max/Min size for CCP2 memory channel */ 378c2ecf20Sopenharmony_ci#define ISPCCP2_LCM_HSIZE_COUNT_MIN 16 388c2ecf20Sopenharmony_ci#define ISPCCP2_LCM_HSIZE_COUNT_MAX 8191 398c2ecf20Sopenharmony_ci#define ISPCCP2_LCM_HSIZE_SKIP_MIN 0 408c2ecf20Sopenharmony_ci#define ISPCCP2_LCM_HSIZE_SKIP_MAX 8191 418c2ecf20Sopenharmony_ci#define ISPCCP2_LCM_VSIZE_MIN 1 428c2ecf20Sopenharmony_ci#define ISPCCP2_LCM_VSIZE_MAX 8191 438c2ecf20Sopenharmony_ci#define ISPCCP2_LCM_HWORDS_MIN 1 448c2ecf20Sopenharmony_ci#define ISPCCP2_LCM_HWORDS_MAX 4095 458c2ecf20Sopenharmony_ci#define ISPCCP2_LCM_CTRL_BURST_SIZE_32X 5 468c2ecf20Sopenharmony_ci#define ISPCCP2_LCM_CTRL_READ_THROTTLE_FULL 0 478c2ecf20Sopenharmony_ci#define ISPCCP2_LCM_CTRL_SRC_DECOMPR_DPCM10 2 488c2ecf20Sopenharmony_ci#define ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW8 2 498c2ecf20Sopenharmony_ci#define ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW10 3 508c2ecf20Sopenharmony_ci#define ISPCCP2_LCM_CTRL_DST_FORMAT_RAW10 3 518c2ecf20Sopenharmony_ci#define ISPCCP2_LCM_CTRL_DST_PORT_VP 0 528c2ecf20Sopenharmony_ci#define ISPCCP2_LCM_CTRL_DST_PORT_MEM 1 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* Set only the required bits */ 558c2ecf20Sopenharmony_ci#define BIT_SET(var, shift, mask, val) \ 568c2ecf20Sopenharmony_ci do { \ 578c2ecf20Sopenharmony_ci var = ((var) & ~((mask) << (shift))) \ 588c2ecf20Sopenharmony_ci | ((val) << (shift)); \ 598c2ecf20Sopenharmony_ci } while (0) 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * ccp2_print_status - Print current CCP2 module register values. 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ci#define CCP2_PRINT_REGISTER(isp, name)\ 658c2ecf20Sopenharmony_ci dev_dbg(isp->dev, "###CCP2 " #name "=0x%08x\n", \ 668c2ecf20Sopenharmony_ci isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_##name)) 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic void ccp2_print_status(struct isp_ccp2_device *ccp2) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct isp_device *isp = to_isp_device(ccp2); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci dev_dbg(isp->dev, "-------------CCP2 Register dump-------------\n"); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, SYSCONFIG); 758c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, SYSSTATUS); 768c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LC01_IRQENABLE); 778c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LC01_IRQSTATUS); 788c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LC23_IRQENABLE); 798c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LC23_IRQSTATUS); 808c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LCM_IRQENABLE); 818c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LCM_IRQSTATUS); 828c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, CTRL); 838c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LCx_CTRL(0)); 848c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LCx_CODE(0)); 858c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LCx_STAT_START(0)); 868c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LCx_STAT_SIZE(0)); 878c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LCx_SOF_ADDR(0)); 888c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LCx_EOF_ADDR(0)); 898c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LCx_DAT_START(0)); 908c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LCx_DAT_SIZE(0)); 918c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LCx_DAT_PING_ADDR(0)); 928c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LCx_DAT_PONG_ADDR(0)); 938c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LCx_DAT_OFST(0)); 948c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LCM_CTRL); 958c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LCM_VSIZE); 968c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LCM_HSIZE); 978c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LCM_PREFETCH); 988c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LCM_SRC_ADDR); 998c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LCM_SRC_OFST); 1008c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LCM_DST_ADDR); 1018c2ecf20Sopenharmony_ci CCP2_PRINT_REGISTER(isp, LCM_DST_OFST); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci dev_dbg(isp->dev, "--------------------------------------------\n"); 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* 1078c2ecf20Sopenharmony_ci * ccp2_reset - Reset the CCP2 1088c2ecf20Sopenharmony_ci * @ccp2: pointer to ISP CCP2 device 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_cistatic void ccp2_reset(struct isp_ccp2_device *ccp2) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct isp_device *isp = to_isp_device(ccp2); 1138c2ecf20Sopenharmony_ci int i = 0; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci /* Reset the CSI1/CCP2B and wait for reset to complete */ 1168c2ecf20Sopenharmony_ci isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSCONFIG, 1178c2ecf20Sopenharmony_ci ISPCCP2_SYSCONFIG_SOFT_RESET); 1188c2ecf20Sopenharmony_ci while (!(isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSSTATUS) & 1198c2ecf20Sopenharmony_ci ISPCCP2_SYSSTATUS_RESET_DONE)) { 1208c2ecf20Sopenharmony_ci udelay(10); 1218c2ecf20Sopenharmony_ci if (i++ > 10) { /* try read 10 times */ 1228c2ecf20Sopenharmony_ci dev_warn(isp->dev, 1238c2ecf20Sopenharmony_ci "omap3_isp: timeout waiting for ccp2 reset\n"); 1248c2ecf20Sopenharmony_ci break; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci/* 1308c2ecf20Sopenharmony_ci * ccp2_pwr_cfg - Configure the power mode settings 1318c2ecf20Sopenharmony_ci * @ccp2: pointer to ISP CCP2 device 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_cistatic void ccp2_pwr_cfg(struct isp_ccp2_device *ccp2) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci struct isp_device *isp = to_isp_device(ccp2); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci isp_reg_writel(isp, ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SMART | 1388c2ecf20Sopenharmony_ci ((isp->revision == ISP_REVISION_15_0 && isp->autoidle) ? 1398c2ecf20Sopenharmony_ci ISPCCP2_SYSCONFIG_AUTO_IDLE : 0), 1408c2ecf20Sopenharmony_ci OMAP3_ISP_IOMEM_CCP2, ISPCCP2_SYSCONFIG); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/* 1448c2ecf20Sopenharmony_ci * ccp2_if_enable - Enable CCP2 interface. 1458c2ecf20Sopenharmony_ci * @ccp2: pointer to ISP CCP2 device 1468c2ecf20Sopenharmony_ci * @enable: enable/disable flag 1478c2ecf20Sopenharmony_ci */ 1488c2ecf20Sopenharmony_cistatic int ccp2_if_enable(struct isp_ccp2_device *ccp2, u8 enable) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct isp_device *isp = to_isp_device(ccp2); 1518c2ecf20Sopenharmony_ci int ret; 1528c2ecf20Sopenharmony_ci int i; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (enable && ccp2->vdds_csib) { 1558c2ecf20Sopenharmony_ci ret = regulator_enable(ccp2->vdds_csib); 1568c2ecf20Sopenharmony_ci if (ret < 0) 1578c2ecf20Sopenharmony_ci return ret; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* Enable/Disable all the LCx channels */ 1618c2ecf20Sopenharmony_ci for (i = 0; i < CCP2_LCx_CHANS_NUM; i++) 1628c2ecf20Sopenharmony_ci isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(i), 1638c2ecf20Sopenharmony_ci ISPCCP2_LCx_CTRL_CHAN_EN, 1648c2ecf20Sopenharmony_ci enable ? ISPCCP2_LCx_CTRL_CHAN_EN : 0); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* Enable/Disable ccp2 interface in ccp2 mode */ 1678c2ecf20Sopenharmony_ci isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL, 1688c2ecf20Sopenharmony_ci ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN, 1698c2ecf20Sopenharmony_ci enable ? (ISPCCP2_CTRL_MODE | ISPCCP2_CTRL_IF_EN) : 0); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci if (!enable && ccp2->vdds_csib) 1728c2ecf20Sopenharmony_ci regulator_disable(ccp2->vdds_csib); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci return 0; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci/* 1788c2ecf20Sopenharmony_ci * ccp2_mem_enable - Enable CCP2 memory interface. 1798c2ecf20Sopenharmony_ci * @ccp2: pointer to ISP CCP2 device 1808c2ecf20Sopenharmony_ci * @enable: enable/disable flag 1818c2ecf20Sopenharmony_ci */ 1828c2ecf20Sopenharmony_cistatic void ccp2_mem_enable(struct isp_ccp2_device *ccp2, u8 enable) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct isp_device *isp = to_isp_device(ccp2); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (enable) 1878c2ecf20Sopenharmony_ci ccp2_if_enable(ccp2, 0); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* Enable/Disable ccp2 interface in ccp2 mode */ 1908c2ecf20Sopenharmony_ci isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL, 1918c2ecf20Sopenharmony_ci ISPCCP2_CTRL_MODE, enable ? ISPCCP2_CTRL_MODE : 0); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_CTRL, 1948c2ecf20Sopenharmony_ci ISPCCP2_LCM_CTRL_CHAN_EN, 1958c2ecf20Sopenharmony_ci enable ? ISPCCP2_LCM_CTRL_CHAN_EN : 0); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/* 1998c2ecf20Sopenharmony_ci * ccp2_phyif_config - Initialize CCP2 phy interface config 2008c2ecf20Sopenharmony_ci * @ccp2: Pointer to ISP CCP2 device 2018c2ecf20Sopenharmony_ci * @buscfg: CCP2 platform data 2028c2ecf20Sopenharmony_ci * 2038c2ecf20Sopenharmony_ci * Configure the CCP2 physical interface module from platform data. 2048c2ecf20Sopenharmony_ci * 2058c2ecf20Sopenharmony_ci * Returns -EIO if strobe is chosen in CSI1 mode, or 0 on success. 2068c2ecf20Sopenharmony_ci */ 2078c2ecf20Sopenharmony_cistatic int ccp2_phyif_config(struct isp_ccp2_device *ccp2, 2088c2ecf20Sopenharmony_ci const struct isp_ccp2_cfg *buscfg) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci struct isp_device *isp = to_isp_device(ccp2); 2118c2ecf20Sopenharmony_ci u32 val; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL) | 2148c2ecf20Sopenharmony_ci ISPCCP2_CTRL_MODE; 2158c2ecf20Sopenharmony_ci /* Data/strobe physical layer */ 2168c2ecf20Sopenharmony_ci BIT_SET(val, ISPCCP2_CTRL_PHY_SEL_SHIFT, ISPCCP2_CTRL_PHY_SEL_MASK, 2178c2ecf20Sopenharmony_ci buscfg->phy_layer); 2188c2ecf20Sopenharmony_ci BIT_SET(val, ISPCCP2_CTRL_IO_OUT_SEL_SHIFT, 2198c2ecf20Sopenharmony_ci ISPCCP2_CTRL_IO_OUT_SEL_MASK, buscfg->ccp2_mode); 2208c2ecf20Sopenharmony_ci BIT_SET(val, ISPCCP2_CTRL_INV_SHIFT, ISPCCP2_CTRL_INV_MASK, 2218c2ecf20Sopenharmony_ci buscfg->strobe_clk_pol); 2228c2ecf20Sopenharmony_ci BIT_SET(val, ISPCCP2_CTRL_VP_CLK_POL_SHIFT, 2238c2ecf20Sopenharmony_ci ISPCCP2_CTRL_VP_CLK_POL_MASK, buscfg->vp_clk_pol); 2248c2ecf20Sopenharmony_ci isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); 2278c2ecf20Sopenharmony_ci if (!(val & ISPCCP2_CTRL_MODE)) { 2288c2ecf20Sopenharmony_ci if (buscfg->ccp2_mode == ISP_CCP2_MODE_CCP2) 2298c2ecf20Sopenharmony_ci dev_warn(isp->dev, "OMAP3 CCP2 bus not available\n"); 2308c2ecf20Sopenharmony_ci if (buscfg->phy_layer == ISP_CCP2_PHY_DATA_STROBE) 2318c2ecf20Sopenharmony_ci /* Strobe mode requires CCP2 */ 2328c2ecf20Sopenharmony_ci return -EIO; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return 0; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci/* 2398c2ecf20Sopenharmony_ci * ccp2_vp_config - Initialize CCP2 video port interface. 2408c2ecf20Sopenharmony_ci * @ccp2: Pointer to ISP CCP2 device 2418c2ecf20Sopenharmony_ci * @vpclk_div: Video port divisor 2428c2ecf20Sopenharmony_ci * 2438c2ecf20Sopenharmony_ci * Configure the CCP2 video port with the given clock divisor. The valid divisor 2448c2ecf20Sopenharmony_ci * values depend on the ISP revision: 2458c2ecf20Sopenharmony_ci * 2468c2ecf20Sopenharmony_ci * - revision 1.0 and 2.0 1 to 4 2478c2ecf20Sopenharmony_ci * - revision 15.0 1 to 65536 2488c2ecf20Sopenharmony_ci * 2498c2ecf20Sopenharmony_ci * The exact divisor value used might differ from the requested value, as ISP 2508c2ecf20Sopenharmony_ci * revision 15.0 represent the divisor by 65536 divided by an integer. 2518c2ecf20Sopenharmony_ci */ 2528c2ecf20Sopenharmony_cistatic void ccp2_vp_config(struct isp_ccp2_device *ccp2, 2538c2ecf20Sopenharmony_ci unsigned int vpclk_div) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci struct isp_device *isp = to_isp_device(ccp2); 2568c2ecf20Sopenharmony_ci u32 val; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* ISPCCP2_CTRL Video port */ 2598c2ecf20Sopenharmony_ci val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); 2608c2ecf20Sopenharmony_ci val |= ISPCCP2_CTRL_VP_ONLY_EN; /* Disable the memory write port */ 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (isp->revision == ISP_REVISION_15_0) { 2638c2ecf20Sopenharmony_ci vpclk_div = clamp_t(unsigned int, vpclk_div, 1, 65536); 2648c2ecf20Sopenharmony_ci vpclk_div = min(ISPCCP2_VPCLK_FRACDIV / vpclk_div, 65535U); 2658c2ecf20Sopenharmony_ci BIT_SET(val, ISPCCP2_CTRL_VPCLK_DIV_SHIFT, 2668c2ecf20Sopenharmony_ci ISPCCP2_CTRL_VPCLK_DIV_MASK, vpclk_div); 2678c2ecf20Sopenharmony_ci } else { 2688c2ecf20Sopenharmony_ci vpclk_div = clamp_t(unsigned int, vpclk_div, 1, 4); 2698c2ecf20Sopenharmony_ci BIT_SET(val, ISPCCP2_CTRL_VP_OUT_CTRL_SHIFT, 2708c2ecf20Sopenharmony_ci ISPCCP2_CTRL_VP_OUT_CTRL_MASK, vpclk_div - 1); 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL); 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci/* 2778c2ecf20Sopenharmony_ci * ccp2_lcx_config - Initialize CCP2 logical channel interface. 2788c2ecf20Sopenharmony_ci * @ccp2: Pointer to ISP CCP2 device 2798c2ecf20Sopenharmony_ci * @config: Pointer to ISP LCx config structure. 2808c2ecf20Sopenharmony_ci * 2818c2ecf20Sopenharmony_ci * This will analyze the parameters passed by the interface config 2828c2ecf20Sopenharmony_ci * and configure CSI1/CCP2 logical channel 2838c2ecf20Sopenharmony_ci * 2848c2ecf20Sopenharmony_ci */ 2858c2ecf20Sopenharmony_cistatic void ccp2_lcx_config(struct isp_ccp2_device *ccp2, 2868c2ecf20Sopenharmony_ci struct isp_interface_lcx_config *config) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct isp_device *isp = to_isp_device(ccp2); 2898c2ecf20Sopenharmony_ci u32 val, format; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci switch (config->format) { 2928c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8: 2938c2ecf20Sopenharmony_ci format = ISPCCP2_LCx_CTRL_FORMAT_RAW8_DPCM10_VP; 2948c2ecf20Sopenharmony_ci break; 2958c2ecf20Sopenharmony_ci case MEDIA_BUS_FMT_SGRBG10_1X10: 2968c2ecf20Sopenharmony_ci default: 2978c2ecf20Sopenharmony_ci format = ISPCCP2_LCx_CTRL_FORMAT_RAW10_VP; /* RAW10+VP */ 2988c2ecf20Sopenharmony_ci break; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci /* ISPCCP2_LCx_CTRL logical channel #0 */ 3018c2ecf20Sopenharmony_ci val = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(0)) 3028c2ecf20Sopenharmony_ci | (ISPCCP2_LCx_CTRL_REGION_EN); /* Region */ 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (isp->revision == ISP_REVISION_15_0) { 3058c2ecf20Sopenharmony_ci /* CRC */ 3068c2ecf20Sopenharmony_ci BIT_SET(val, ISPCCP2_LCx_CTRL_CRC_SHIFT_15_0, 3078c2ecf20Sopenharmony_ci ISPCCP2_LCx_CTRL_CRC_MASK, 3088c2ecf20Sopenharmony_ci config->crc); 3098c2ecf20Sopenharmony_ci /* Format = RAW10+VP or RAW8+DPCM10+VP*/ 3108c2ecf20Sopenharmony_ci BIT_SET(val, ISPCCP2_LCx_CTRL_FORMAT_SHIFT_15_0, 3118c2ecf20Sopenharmony_ci ISPCCP2_LCx_CTRL_FORMAT_MASK_15_0, format); 3128c2ecf20Sopenharmony_ci } else { 3138c2ecf20Sopenharmony_ci BIT_SET(val, ISPCCP2_LCx_CTRL_CRC_SHIFT, 3148c2ecf20Sopenharmony_ci ISPCCP2_LCx_CTRL_CRC_MASK, 3158c2ecf20Sopenharmony_ci config->crc); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci BIT_SET(val, ISPCCP2_LCx_CTRL_FORMAT_SHIFT, 3188c2ecf20Sopenharmony_ci ISPCCP2_LCx_CTRL_FORMAT_MASK, format); 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_CTRL(0)); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* ISPCCP2_DAT_START for logical channel #0 */ 3238c2ecf20Sopenharmony_ci isp_reg_writel(isp, config->data_start << ISPCCP2_LCx_DAT_SHIFT, 3248c2ecf20Sopenharmony_ci OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_DAT_START(0)); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* ISPCCP2_DAT_SIZE for logical channel #0 */ 3278c2ecf20Sopenharmony_ci isp_reg_writel(isp, config->data_size << ISPCCP2_LCx_DAT_SHIFT, 3288c2ecf20Sopenharmony_ci OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCx_DAT_SIZE(0)); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* Enable error IRQs for logical channel #0 */ 3318c2ecf20Sopenharmony_ci val = ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ | 3328c2ecf20Sopenharmony_ci ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ | 3338c2ecf20Sopenharmony_ci ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ | 3348c2ecf20Sopenharmony_ci ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ | 3358c2ecf20Sopenharmony_ci ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ | 3368c2ecf20Sopenharmony_ci ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQSTATUS); 3398c2ecf20Sopenharmony_ci isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LC01_IRQENABLE, val); 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci/* 3438c2ecf20Sopenharmony_ci * ccp2_if_configure - Configure ccp2 with data from sensor 3448c2ecf20Sopenharmony_ci * @ccp2: Pointer to ISP CCP2 device 3458c2ecf20Sopenharmony_ci * 3468c2ecf20Sopenharmony_ci * Return 0 on success or a negative error code 3478c2ecf20Sopenharmony_ci */ 3488c2ecf20Sopenharmony_cistatic int ccp2_if_configure(struct isp_ccp2_device *ccp2) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); 3518c2ecf20Sopenharmony_ci const struct isp_bus_cfg *buscfg; 3528c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *format; 3538c2ecf20Sopenharmony_ci struct media_pad *pad; 3548c2ecf20Sopenharmony_ci struct v4l2_subdev *sensor; 3558c2ecf20Sopenharmony_ci u32 lines = 0; 3568c2ecf20Sopenharmony_ci int ret; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci ccp2_pwr_cfg(ccp2); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci pad = media_entity_remote_pad(&ccp2->pads[CCP2_PAD_SINK]); 3618c2ecf20Sopenharmony_ci sensor = media_entity_to_v4l2_subdev(pad->entity); 3628c2ecf20Sopenharmony_ci buscfg = v4l2_subdev_to_bus_cfg(pipe->external); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci ret = ccp2_phyif_config(ccp2, &buscfg->bus.ccp2); 3658c2ecf20Sopenharmony_ci if (ret < 0) 3668c2ecf20Sopenharmony_ci return ret; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci ccp2_vp_config(ccp2, buscfg->bus.ccp2.vpclk_div + 1); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci v4l2_subdev_call(sensor, sensor, g_skip_top_lines, &lines); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci format = &ccp2->formats[CCP2_PAD_SINK]; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci ccp2->if_cfg.data_start = lines; 3758c2ecf20Sopenharmony_ci ccp2->if_cfg.crc = buscfg->bus.ccp2.crc; 3768c2ecf20Sopenharmony_ci ccp2->if_cfg.format = format->code; 3778c2ecf20Sopenharmony_ci ccp2->if_cfg.data_size = format->height; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci ccp2_lcx_config(ccp2, &ccp2->if_cfg); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci return 0; 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cistatic int ccp2_adjust_bandwidth(struct isp_ccp2_device *ccp2) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); 3878c2ecf20Sopenharmony_ci struct isp_device *isp = to_isp_device(ccp2); 3888c2ecf20Sopenharmony_ci const struct v4l2_mbus_framefmt *ofmt = &ccp2->formats[CCP2_PAD_SOURCE]; 3898c2ecf20Sopenharmony_ci unsigned long l3_ick = pipe->l3_ick; 3908c2ecf20Sopenharmony_ci struct v4l2_fract *timeperframe; 3918c2ecf20Sopenharmony_ci unsigned int vpclk_div = 2; 3928c2ecf20Sopenharmony_ci unsigned int value; 3938c2ecf20Sopenharmony_ci u64 bound; 3948c2ecf20Sopenharmony_ci u64 area; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci /* Compute the minimum clock divisor, based on the pipeline maximum 3978c2ecf20Sopenharmony_ci * data rate. This is an absolute lower bound if we don't want SBL 3988c2ecf20Sopenharmony_ci * overflows, so round the value up. 3998c2ecf20Sopenharmony_ci */ 4008c2ecf20Sopenharmony_ci vpclk_div = max_t(unsigned int, DIV_ROUND_UP(l3_ick, pipe->max_rate), 4018c2ecf20Sopenharmony_ci vpclk_div); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci /* Compute the maximum clock divisor, based on the requested frame rate. 4048c2ecf20Sopenharmony_ci * This is a soft lower bound to achieve a frame rate equal or higher 4058c2ecf20Sopenharmony_ci * than the requested value, so round the value down. 4068c2ecf20Sopenharmony_ci */ 4078c2ecf20Sopenharmony_ci timeperframe = &pipe->max_timeperframe; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (timeperframe->numerator) { 4108c2ecf20Sopenharmony_ci area = ofmt->width * ofmt->height; 4118c2ecf20Sopenharmony_ci bound = div_u64(area * timeperframe->denominator, 4128c2ecf20Sopenharmony_ci timeperframe->numerator); 4138c2ecf20Sopenharmony_ci value = min_t(u64, bound, l3_ick); 4148c2ecf20Sopenharmony_ci vpclk_div = max_t(unsigned int, l3_ick / value, vpclk_div); 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci dev_dbg(isp->dev, "%s: minimum clock divisor = %u\n", __func__, 4188c2ecf20Sopenharmony_ci vpclk_div); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci return vpclk_div; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci/* 4248c2ecf20Sopenharmony_ci * ccp2_mem_configure - Initialize CCP2 memory input/output interface 4258c2ecf20Sopenharmony_ci * @ccp2: Pointer to ISP CCP2 device 4268c2ecf20Sopenharmony_ci * @config: Pointer to ISP mem interface config structure 4278c2ecf20Sopenharmony_ci * 4288c2ecf20Sopenharmony_ci * This will analyze the parameters passed by the interface config 4298c2ecf20Sopenharmony_ci * structure, and configure the respective registers for proper 4308c2ecf20Sopenharmony_ci * CSI1/CCP2 memory input. 4318c2ecf20Sopenharmony_ci */ 4328c2ecf20Sopenharmony_cistatic void ccp2_mem_configure(struct isp_ccp2_device *ccp2, 4338c2ecf20Sopenharmony_ci struct isp_interface_mem_config *config) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci struct isp_device *isp = to_isp_device(ccp2); 4368c2ecf20Sopenharmony_ci u32 sink_pixcode = ccp2->formats[CCP2_PAD_SINK].code; 4378c2ecf20Sopenharmony_ci u32 source_pixcode = ccp2->formats[CCP2_PAD_SOURCE].code; 4388c2ecf20Sopenharmony_ci unsigned int dpcm_decompress = 0; 4398c2ecf20Sopenharmony_ci u32 val, hwords; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci if (sink_pixcode != source_pixcode && 4428c2ecf20Sopenharmony_ci sink_pixcode == MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8) 4438c2ecf20Sopenharmony_ci dpcm_decompress = 1; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci ccp2_pwr_cfg(ccp2); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* Hsize, Skip */ 4488c2ecf20Sopenharmony_ci isp_reg_writel(isp, ISPCCP2_LCM_HSIZE_SKIP_MIN | 4498c2ecf20Sopenharmony_ci (config->hsize_count << ISPCCP2_LCM_HSIZE_SHIFT), 4508c2ecf20Sopenharmony_ci OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_HSIZE); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci /* Vsize, no. of lines */ 4538c2ecf20Sopenharmony_ci isp_reg_writel(isp, config->vsize_count << ISPCCP2_LCM_VSIZE_SHIFT, 4548c2ecf20Sopenharmony_ci OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_VSIZE); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (ccp2->video_in.bpl_padding == 0) 4578c2ecf20Sopenharmony_ci config->src_ofst = 0; 4588c2ecf20Sopenharmony_ci else 4598c2ecf20Sopenharmony_ci config->src_ofst = ccp2->video_in.bpl_value; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci isp_reg_writel(isp, config->src_ofst, OMAP3_ISP_IOMEM_CCP2, 4628c2ecf20Sopenharmony_ci ISPCCP2_LCM_SRC_OFST); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* Source and Destination formats */ 4658c2ecf20Sopenharmony_ci val = ISPCCP2_LCM_CTRL_DST_FORMAT_RAW10 << 4668c2ecf20Sopenharmony_ci ISPCCP2_LCM_CTRL_DST_FORMAT_SHIFT; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci if (dpcm_decompress) { 4698c2ecf20Sopenharmony_ci /* source format is RAW8 */ 4708c2ecf20Sopenharmony_ci val |= ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW8 << 4718c2ecf20Sopenharmony_ci ISPCCP2_LCM_CTRL_SRC_FORMAT_SHIFT; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci /* RAW8 + DPCM10 - simple predictor */ 4748c2ecf20Sopenharmony_ci val |= ISPCCP2_LCM_CTRL_SRC_DPCM_PRED; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* enable source DPCM decompression */ 4778c2ecf20Sopenharmony_ci val |= ISPCCP2_LCM_CTRL_SRC_DECOMPR_DPCM10 << 4788c2ecf20Sopenharmony_ci ISPCCP2_LCM_CTRL_SRC_DECOMPR_SHIFT; 4798c2ecf20Sopenharmony_ci } else { 4808c2ecf20Sopenharmony_ci /* source format is RAW10 */ 4818c2ecf20Sopenharmony_ci val |= ISPCCP2_LCM_CTRL_SRC_FORMAT_RAW10 << 4828c2ecf20Sopenharmony_ci ISPCCP2_LCM_CTRL_SRC_FORMAT_SHIFT; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci /* Burst size to 32x64 */ 4868c2ecf20Sopenharmony_ci val |= ISPCCP2_LCM_CTRL_BURST_SIZE_32X << 4878c2ecf20Sopenharmony_ci ISPCCP2_LCM_CTRL_BURST_SIZE_SHIFT; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_CTRL); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci /* Prefetch setup */ 4928c2ecf20Sopenharmony_ci if (dpcm_decompress) 4938c2ecf20Sopenharmony_ci hwords = (ISPCCP2_LCM_HSIZE_SKIP_MIN + 4948c2ecf20Sopenharmony_ci config->hsize_count) >> 3; 4958c2ecf20Sopenharmony_ci else 4968c2ecf20Sopenharmony_ci hwords = (ISPCCP2_LCM_HSIZE_SKIP_MIN + 4978c2ecf20Sopenharmony_ci config->hsize_count) >> 2; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci isp_reg_writel(isp, hwords << ISPCCP2_LCM_PREFETCH_SHIFT, 5008c2ecf20Sopenharmony_ci OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_PREFETCH); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* Video port */ 5038c2ecf20Sopenharmony_ci isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_CTRL, 5048c2ecf20Sopenharmony_ci ISPCCP2_CTRL_IO_OUT_SEL | ISPCCP2_CTRL_MODE); 5058c2ecf20Sopenharmony_ci ccp2_vp_config(ccp2, ccp2_adjust_bandwidth(ccp2)); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci /* Clear LCM interrupts */ 5088c2ecf20Sopenharmony_ci isp_reg_writel(isp, ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ | 5098c2ecf20Sopenharmony_ci ISPCCP2_LCM_IRQSTATUS_EOF_IRQ, 5108c2ecf20Sopenharmony_ci OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_IRQSTATUS); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci /* Enable LCM interrupts */ 5138c2ecf20Sopenharmony_ci isp_reg_set(isp, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_IRQENABLE, 5148c2ecf20Sopenharmony_ci ISPCCP2_LCM_IRQSTATUS_EOF_IRQ | 5158c2ecf20Sopenharmony_ci ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ); 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci/* 5198c2ecf20Sopenharmony_ci * ccp2_set_inaddr - Sets memory address of input frame. 5208c2ecf20Sopenharmony_ci * @ccp2: Pointer to ISP CCP2 device 5218c2ecf20Sopenharmony_ci * @addr: 32bit memory address aligned on 32byte boundary. 5228c2ecf20Sopenharmony_ci * 5238c2ecf20Sopenharmony_ci * Configures the memory address from which the input frame is to be read. 5248c2ecf20Sopenharmony_ci */ 5258c2ecf20Sopenharmony_cistatic void ccp2_set_inaddr(struct isp_ccp2_device *ccp2, u32 addr) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci struct isp_device *isp = to_isp_device(ccp2); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci isp_reg_writel(isp, addr, OMAP3_ISP_IOMEM_CCP2, ISPCCP2_LCM_SRC_ADDR); 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 5338c2ecf20Sopenharmony_ci * Interrupt handling 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic void ccp2_isr_buffer(struct isp_ccp2_device *ccp2) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); 5398c2ecf20Sopenharmony_ci struct isp_buffer *buffer; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci buffer = omap3isp_video_buffer_next(&ccp2->video_in); 5428c2ecf20Sopenharmony_ci if (buffer != NULL) 5438c2ecf20Sopenharmony_ci ccp2_set_inaddr(ccp2, buffer->dma); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci pipe->state |= ISP_PIPELINE_IDLE_INPUT; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci if (ccp2->state == ISP_PIPELINE_STREAM_SINGLESHOT) { 5488c2ecf20Sopenharmony_ci if (isp_pipeline_ready(pipe)) 5498c2ecf20Sopenharmony_ci omap3isp_pipeline_set_stream(pipe, 5508c2ecf20Sopenharmony_ci ISP_PIPELINE_STREAM_SINGLESHOT); 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci/* 5558c2ecf20Sopenharmony_ci * omap3isp_ccp2_isr - Handle ISP CCP2 interrupts 5568c2ecf20Sopenharmony_ci * @ccp2: Pointer to ISP CCP2 device 5578c2ecf20Sopenharmony_ci * 5588c2ecf20Sopenharmony_ci * This will handle the CCP2 interrupts 5598c2ecf20Sopenharmony_ci */ 5608c2ecf20Sopenharmony_civoid omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci struct isp_pipeline *pipe = to_isp_pipeline(&ccp2->subdev.entity); 5638c2ecf20Sopenharmony_ci struct isp_device *isp = to_isp_device(ccp2); 5648c2ecf20Sopenharmony_ci static const u32 ISPCCP2_LC01_ERROR = 5658c2ecf20Sopenharmony_ci ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ | 5668c2ecf20Sopenharmony_ci ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ | 5678c2ecf20Sopenharmony_ci ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ | 5688c2ecf20Sopenharmony_ci ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ | 5698c2ecf20Sopenharmony_ci ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ | 5708c2ecf20Sopenharmony_ci ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ; 5718c2ecf20Sopenharmony_ci u32 lcx_irqstatus, lcm_irqstatus; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* First clear the interrupts */ 5748c2ecf20Sopenharmony_ci lcx_irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, 5758c2ecf20Sopenharmony_ci ISPCCP2_LC01_IRQSTATUS); 5768c2ecf20Sopenharmony_ci isp_reg_writel(isp, lcx_irqstatus, OMAP3_ISP_IOMEM_CCP2, 5778c2ecf20Sopenharmony_ci ISPCCP2_LC01_IRQSTATUS); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci lcm_irqstatus = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCP2, 5808c2ecf20Sopenharmony_ci ISPCCP2_LCM_IRQSTATUS); 5818c2ecf20Sopenharmony_ci isp_reg_writel(isp, lcm_irqstatus, OMAP3_ISP_IOMEM_CCP2, 5828c2ecf20Sopenharmony_ci ISPCCP2_LCM_IRQSTATUS); 5838c2ecf20Sopenharmony_ci /* Errors */ 5848c2ecf20Sopenharmony_ci if (lcx_irqstatus & ISPCCP2_LC01_ERROR) { 5858c2ecf20Sopenharmony_ci pipe->error = true; 5868c2ecf20Sopenharmony_ci dev_dbg(isp->dev, "CCP2 err:%x\n", lcx_irqstatus); 5878c2ecf20Sopenharmony_ci return; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ) { 5918c2ecf20Sopenharmony_ci pipe->error = true; 5928c2ecf20Sopenharmony_ci dev_dbg(isp->dev, "CCP2 OCP err:%x\n", lcm_irqstatus); 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci if (omap3isp_module_sync_is_stopping(&ccp2->wait, &ccp2->stopping)) 5968c2ecf20Sopenharmony_ci return; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci /* Handle queued buffers on frame end interrupts */ 5998c2ecf20Sopenharmony_ci if (lcm_irqstatus & ISPCCP2_LCM_IRQSTATUS_EOF_IRQ) 6008c2ecf20Sopenharmony_ci ccp2_isr_buffer(ccp2); 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 6048c2ecf20Sopenharmony_ci * V4L2 subdev operations 6058c2ecf20Sopenharmony_ci */ 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic const unsigned int ccp2_fmts[] = { 6088c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGRBG10_1X10, 6098c2ecf20Sopenharmony_ci MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, 6108c2ecf20Sopenharmony_ci}; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci/* 6138c2ecf20Sopenharmony_ci * __ccp2_get_format - helper function for getting ccp2 format 6148c2ecf20Sopenharmony_ci * @ccp2 : Pointer to ISP CCP2 device 6158c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration 6168c2ecf20Sopenharmony_ci * @pad : pad number 6178c2ecf20Sopenharmony_ci * @which : wanted subdev format 6188c2ecf20Sopenharmony_ci * return format structure or NULL on error 6198c2ecf20Sopenharmony_ci */ 6208c2ecf20Sopenharmony_cistatic struct v4l2_mbus_framefmt * 6218c2ecf20Sopenharmony_ci__ccp2_get_format(struct isp_ccp2_device *ccp2, struct v4l2_subdev_pad_config *cfg, 6228c2ecf20Sopenharmony_ci unsigned int pad, enum v4l2_subdev_format_whence which) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci if (which == V4L2_SUBDEV_FORMAT_TRY) 6258c2ecf20Sopenharmony_ci return v4l2_subdev_get_try_format(&ccp2->subdev, cfg, pad); 6268c2ecf20Sopenharmony_ci else 6278c2ecf20Sopenharmony_ci return &ccp2->formats[pad]; 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci/* 6318c2ecf20Sopenharmony_ci * ccp2_try_format - Handle try format by pad subdev method 6328c2ecf20Sopenharmony_ci * @ccp2 : Pointer to ISP CCP2 device 6338c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration 6348c2ecf20Sopenharmony_ci * @pad : pad num 6358c2ecf20Sopenharmony_ci * @fmt : pointer to v4l2 mbus format structure 6368c2ecf20Sopenharmony_ci * @which : wanted subdev format 6378c2ecf20Sopenharmony_ci */ 6388c2ecf20Sopenharmony_cistatic void ccp2_try_format(struct isp_ccp2_device *ccp2, 6398c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, unsigned int pad, 6408c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *fmt, 6418c2ecf20Sopenharmony_ci enum v4l2_subdev_format_whence which) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *format; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci switch (pad) { 6468c2ecf20Sopenharmony_ci case CCP2_PAD_SINK: 6478c2ecf20Sopenharmony_ci if (fmt->code != MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8) 6488c2ecf20Sopenharmony_ci fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci if (ccp2->input == CCP2_INPUT_SENSOR) { 6518c2ecf20Sopenharmony_ci fmt->width = clamp_t(u32, fmt->width, 6528c2ecf20Sopenharmony_ci ISPCCP2_DAT_START_MIN, 6538c2ecf20Sopenharmony_ci ISPCCP2_DAT_START_MAX); 6548c2ecf20Sopenharmony_ci fmt->height = clamp_t(u32, fmt->height, 6558c2ecf20Sopenharmony_ci ISPCCP2_DAT_SIZE_MIN, 6568c2ecf20Sopenharmony_ci ISPCCP2_DAT_SIZE_MAX); 6578c2ecf20Sopenharmony_ci } else if (ccp2->input == CCP2_INPUT_MEMORY) { 6588c2ecf20Sopenharmony_ci fmt->width = clamp_t(u32, fmt->width, 6598c2ecf20Sopenharmony_ci ISPCCP2_LCM_HSIZE_COUNT_MIN, 6608c2ecf20Sopenharmony_ci ISPCCP2_LCM_HSIZE_COUNT_MAX); 6618c2ecf20Sopenharmony_ci fmt->height = clamp_t(u32, fmt->height, 6628c2ecf20Sopenharmony_ci ISPCCP2_LCM_VSIZE_MIN, 6638c2ecf20Sopenharmony_ci ISPCCP2_LCM_VSIZE_MAX); 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci break; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci case CCP2_PAD_SOURCE: 6688c2ecf20Sopenharmony_ci /* Source format - copy sink format and change pixel code 6698c2ecf20Sopenharmony_ci * to SGRBG10_1X10 as we don't support CCP2 write to memory. 6708c2ecf20Sopenharmony_ci * When CCP2 write to memory feature will be added this 6718c2ecf20Sopenharmony_ci * should be changed properly. 6728c2ecf20Sopenharmony_ci */ 6738c2ecf20Sopenharmony_ci format = __ccp2_get_format(ccp2, cfg, CCP2_PAD_SINK, which); 6748c2ecf20Sopenharmony_ci memcpy(fmt, format, sizeof(*fmt)); 6758c2ecf20Sopenharmony_ci fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; 6768c2ecf20Sopenharmony_ci break; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci fmt->field = V4L2_FIELD_NONE; 6808c2ecf20Sopenharmony_ci fmt->colorspace = V4L2_COLORSPACE_SRGB; 6818c2ecf20Sopenharmony_ci} 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci/* 6848c2ecf20Sopenharmony_ci * ccp2_enum_mbus_code - Handle pixel format enumeration 6858c2ecf20Sopenharmony_ci * @sd : pointer to v4l2 subdev structure 6868c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration 6878c2ecf20Sopenharmony_ci * @code : pointer to v4l2_subdev_mbus_code_enum structure 6888c2ecf20Sopenharmony_ci * return -EINVAL or zero on success 6898c2ecf20Sopenharmony_ci */ 6908c2ecf20Sopenharmony_cistatic int ccp2_enum_mbus_code(struct v4l2_subdev *sd, 6918c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 6928c2ecf20Sopenharmony_ci struct v4l2_subdev_mbus_code_enum *code) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); 6958c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *format; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci if (code->pad == CCP2_PAD_SINK) { 6988c2ecf20Sopenharmony_ci if (code->index >= ARRAY_SIZE(ccp2_fmts)) 6998c2ecf20Sopenharmony_ci return -EINVAL; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci code->code = ccp2_fmts[code->index]; 7028c2ecf20Sopenharmony_ci } else { 7038c2ecf20Sopenharmony_ci if (code->index != 0) 7048c2ecf20Sopenharmony_ci return -EINVAL; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci format = __ccp2_get_format(ccp2, cfg, CCP2_PAD_SINK, 7078c2ecf20Sopenharmony_ci code->which); 7088c2ecf20Sopenharmony_ci code->code = format->code; 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci return 0; 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_cistatic int ccp2_enum_frame_size(struct v4l2_subdev *sd, 7158c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 7168c2ecf20Sopenharmony_ci struct v4l2_subdev_frame_size_enum *fse) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); 7198c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt format; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (fse->index != 0) 7228c2ecf20Sopenharmony_ci return -EINVAL; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci format.code = fse->code; 7258c2ecf20Sopenharmony_ci format.width = 1; 7268c2ecf20Sopenharmony_ci format.height = 1; 7278c2ecf20Sopenharmony_ci ccp2_try_format(ccp2, cfg, fse->pad, &format, fse->which); 7288c2ecf20Sopenharmony_ci fse->min_width = format.width; 7298c2ecf20Sopenharmony_ci fse->min_height = format.height; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if (format.code != fse->code) 7328c2ecf20Sopenharmony_ci return -EINVAL; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci format.code = fse->code; 7358c2ecf20Sopenharmony_ci format.width = -1; 7368c2ecf20Sopenharmony_ci format.height = -1; 7378c2ecf20Sopenharmony_ci ccp2_try_format(ccp2, cfg, fse->pad, &format, fse->which); 7388c2ecf20Sopenharmony_ci fse->max_width = format.width; 7398c2ecf20Sopenharmony_ci fse->max_height = format.height; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci return 0; 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci/* 7458c2ecf20Sopenharmony_ci * ccp2_get_format - Handle get format by pads subdev method 7468c2ecf20Sopenharmony_ci * @sd : pointer to v4l2 subdev structure 7478c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration 7488c2ecf20Sopenharmony_ci * @fmt : pointer to v4l2 subdev format structure 7498c2ecf20Sopenharmony_ci * return -EINVAL or zero on success 7508c2ecf20Sopenharmony_ci */ 7518c2ecf20Sopenharmony_cistatic int ccp2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, 7528c2ecf20Sopenharmony_ci struct v4l2_subdev_format *fmt) 7538c2ecf20Sopenharmony_ci{ 7548c2ecf20Sopenharmony_ci struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); 7558c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *format; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci format = __ccp2_get_format(ccp2, cfg, fmt->pad, fmt->which); 7588c2ecf20Sopenharmony_ci if (format == NULL) 7598c2ecf20Sopenharmony_ci return -EINVAL; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci fmt->format = *format; 7628c2ecf20Sopenharmony_ci return 0; 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci/* 7668c2ecf20Sopenharmony_ci * ccp2_set_format - Handle set format by pads subdev method 7678c2ecf20Sopenharmony_ci * @sd : pointer to v4l2 subdev structure 7688c2ecf20Sopenharmony_ci * @cfg: V4L2 subdev pad configuration 7698c2ecf20Sopenharmony_ci * @fmt : pointer to v4l2 subdev format structure 7708c2ecf20Sopenharmony_ci * returns zero 7718c2ecf20Sopenharmony_ci */ 7728c2ecf20Sopenharmony_cistatic int ccp2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, 7738c2ecf20Sopenharmony_ci struct v4l2_subdev_format *fmt) 7748c2ecf20Sopenharmony_ci{ 7758c2ecf20Sopenharmony_ci struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); 7768c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *format; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci format = __ccp2_get_format(ccp2, cfg, fmt->pad, fmt->which); 7798c2ecf20Sopenharmony_ci if (format == NULL) 7808c2ecf20Sopenharmony_ci return -EINVAL; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci ccp2_try_format(ccp2, cfg, fmt->pad, &fmt->format, fmt->which); 7838c2ecf20Sopenharmony_ci *format = fmt->format; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci /* Propagate the format from sink to source */ 7868c2ecf20Sopenharmony_ci if (fmt->pad == CCP2_PAD_SINK) { 7878c2ecf20Sopenharmony_ci format = __ccp2_get_format(ccp2, cfg, CCP2_PAD_SOURCE, 7888c2ecf20Sopenharmony_ci fmt->which); 7898c2ecf20Sopenharmony_ci *format = fmt->format; 7908c2ecf20Sopenharmony_ci ccp2_try_format(ccp2, cfg, CCP2_PAD_SOURCE, format, fmt->which); 7918c2ecf20Sopenharmony_ci } 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci return 0; 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci/* 7978c2ecf20Sopenharmony_ci * ccp2_init_formats - Initialize formats on all pads 7988c2ecf20Sopenharmony_ci * @sd: ISP CCP2 V4L2 subdevice 7998c2ecf20Sopenharmony_ci * @fh: V4L2 subdev file handle 8008c2ecf20Sopenharmony_ci * 8018c2ecf20Sopenharmony_ci * Initialize all pad formats with default values. If fh is not NULL, try 8028c2ecf20Sopenharmony_ci * formats are initialized on the file handle. Otherwise active formats are 8038c2ecf20Sopenharmony_ci * initialized on the device. 8048c2ecf20Sopenharmony_ci */ 8058c2ecf20Sopenharmony_cistatic int ccp2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 8068c2ecf20Sopenharmony_ci{ 8078c2ecf20Sopenharmony_ci struct v4l2_subdev_format format; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci memset(&format, 0, sizeof(format)); 8108c2ecf20Sopenharmony_ci format.pad = CCP2_PAD_SINK; 8118c2ecf20Sopenharmony_ci format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; 8128c2ecf20Sopenharmony_ci format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10; 8138c2ecf20Sopenharmony_ci format.format.width = 4096; 8148c2ecf20Sopenharmony_ci format.format.height = 4096; 8158c2ecf20Sopenharmony_ci ccp2_set_format(sd, fh ? fh->pad : NULL, &format); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci return 0; 8188c2ecf20Sopenharmony_ci} 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci/* 8218c2ecf20Sopenharmony_ci * ccp2_s_stream - Enable/Disable streaming on ccp2 subdev 8228c2ecf20Sopenharmony_ci * @sd : pointer to v4l2 subdev structure 8238c2ecf20Sopenharmony_ci * @enable: 1 == Enable, 0 == Disable 8248c2ecf20Sopenharmony_ci * return zero 8258c2ecf20Sopenharmony_ci */ 8268c2ecf20Sopenharmony_cistatic int ccp2_s_stream(struct v4l2_subdev *sd, int enable) 8278c2ecf20Sopenharmony_ci{ 8288c2ecf20Sopenharmony_ci struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); 8298c2ecf20Sopenharmony_ci struct isp_device *isp = to_isp_device(ccp2); 8308c2ecf20Sopenharmony_ci struct device *dev = to_device(ccp2); 8318c2ecf20Sopenharmony_ci int ret; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci if (ccp2->state == ISP_PIPELINE_STREAM_STOPPED) { 8348c2ecf20Sopenharmony_ci if (enable == ISP_PIPELINE_STREAM_STOPPED) 8358c2ecf20Sopenharmony_ci return 0; 8368c2ecf20Sopenharmony_ci atomic_set(&ccp2->stopping, 0); 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci switch (enable) { 8408c2ecf20Sopenharmony_ci case ISP_PIPELINE_STREAM_CONTINUOUS: 8418c2ecf20Sopenharmony_ci if (ccp2->phy) { 8428c2ecf20Sopenharmony_ci ret = omap3isp_csiphy_acquire(ccp2->phy, &sd->entity); 8438c2ecf20Sopenharmony_ci if (ret < 0) 8448c2ecf20Sopenharmony_ci return ret; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci ccp2_if_configure(ccp2); 8488c2ecf20Sopenharmony_ci ccp2_print_status(ccp2); 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci /* Enable CSI1/CCP2 interface */ 8518c2ecf20Sopenharmony_ci ret = ccp2_if_enable(ccp2, 1); 8528c2ecf20Sopenharmony_ci if (ret < 0) { 8538c2ecf20Sopenharmony_ci if (ccp2->phy) 8548c2ecf20Sopenharmony_ci omap3isp_csiphy_release(ccp2->phy); 8558c2ecf20Sopenharmony_ci return ret; 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci break; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci case ISP_PIPELINE_STREAM_SINGLESHOT: 8608c2ecf20Sopenharmony_ci if (ccp2->state != ISP_PIPELINE_STREAM_SINGLESHOT) { 8618c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *format; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci format = &ccp2->formats[CCP2_PAD_SINK]; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci ccp2->mem_cfg.hsize_count = format->width; 8668c2ecf20Sopenharmony_ci ccp2->mem_cfg.vsize_count = format->height; 8678c2ecf20Sopenharmony_ci ccp2->mem_cfg.src_ofst = 0; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci ccp2_mem_configure(ccp2, &ccp2->mem_cfg); 8708c2ecf20Sopenharmony_ci omap3isp_sbl_enable(isp, OMAP3_ISP_SBL_CSI1_READ); 8718c2ecf20Sopenharmony_ci ccp2_print_status(ccp2); 8728c2ecf20Sopenharmony_ci } 8738c2ecf20Sopenharmony_ci ccp2_mem_enable(ccp2, 1); 8748c2ecf20Sopenharmony_ci break; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci case ISP_PIPELINE_STREAM_STOPPED: 8778c2ecf20Sopenharmony_ci if (omap3isp_module_sync_idle(&sd->entity, &ccp2->wait, 8788c2ecf20Sopenharmony_ci &ccp2->stopping)) 8798c2ecf20Sopenharmony_ci dev_dbg(dev, "%s: module stop timeout.\n", sd->name); 8808c2ecf20Sopenharmony_ci if (ccp2->input == CCP2_INPUT_MEMORY) { 8818c2ecf20Sopenharmony_ci ccp2_mem_enable(ccp2, 0); 8828c2ecf20Sopenharmony_ci omap3isp_sbl_disable(isp, OMAP3_ISP_SBL_CSI1_READ); 8838c2ecf20Sopenharmony_ci } else if (ccp2->input == CCP2_INPUT_SENSOR) { 8848c2ecf20Sopenharmony_ci /* Disable CSI1/CCP2 interface */ 8858c2ecf20Sopenharmony_ci ccp2_if_enable(ccp2, 0); 8868c2ecf20Sopenharmony_ci if (ccp2->phy) 8878c2ecf20Sopenharmony_ci omap3isp_csiphy_release(ccp2->phy); 8888c2ecf20Sopenharmony_ci } 8898c2ecf20Sopenharmony_ci break; 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci ccp2->state = enable; 8938c2ecf20Sopenharmony_ci return 0; 8948c2ecf20Sopenharmony_ci} 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci/* subdev video operations */ 8978c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_video_ops ccp2_sd_video_ops = { 8988c2ecf20Sopenharmony_ci .s_stream = ccp2_s_stream, 8998c2ecf20Sopenharmony_ci}; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci/* subdev pad operations */ 9028c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_pad_ops ccp2_sd_pad_ops = { 9038c2ecf20Sopenharmony_ci .enum_mbus_code = ccp2_enum_mbus_code, 9048c2ecf20Sopenharmony_ci .enum_frame_size = ccp2_enum_frame_size, 9058c2ecf20Sopenharmony_ci .get_fmt = ccp2_get_format, 9068c2ecf20Sopenharmony_ci .set_fmt = ccp2_set_format, 9078c2ecf20Sopenharmony_ci}; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci/* subdev operations */ 9108c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops ccp2_sd_ops = { 9118c2ecf20Sopenharmony_ci .video = &ccp2_sd_video_ops, 9128c2ecf20Sopenharmony_ci .pad = &ccp2_sd_pad_ops, 9138c2ecf20Sopenharmony_ci}; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci/* subdev internal operations */ 9168c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_internal_ops ccp2_sd_internal_ops = { 9178c2ecf20Sopenharmony_ci .open = ccp2_init_formats, 9188c2ecf20Sopenharmony_ci}; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci/* -------------------------------------------------------------------------- 9218c2ecf20Sopenharmony_ci * ISP ccp2 video device node 9228c2ecf20Sopenharmony_ci */ 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci/* 9258c2ecf20Sopenharmony_ci * ccp2_video_queue - Queue video buffer. 9268c2ecf20Sopenharmony_ci * @video : Pointer to isp video structure 9278c2ecf20Sopenharmony_ci * @buffer: Pointer to isp_buffer structure 9288c2ecf20Sopenharmony_ci * return -EIO or zero on success 9298c2ecf20Sopenharmony_ci */ 9308c2ecf20Sopenharmony_cistatic int ccp2_video_queue(struct isp_video *video, struct isp_buffer *buffer) 9318c2ecf20Sopenharmony_ci{ 9328c2ecf20Sopenharmony_ci struct isp_ccp2_device *ccp2 = &video->isp->isp_ccp2; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci ccp2_set_inaddr(ccp2, buffer->dma); 9358c2ecf20Sopenharmony_ci return 0; 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_cistatic const struct isp_video_operations ccp2_video_ops = { 9398c2ecf20Sopenharmony_ci .queue = ccp2_video_queue, 9408c2ecf20Sopenharmony_ci}; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 9438c2ecf20Sopenharmony_ci * Media entity operations 9448c2ecf20Sopenharmony_ci */ 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci/* 9478c2ecf20Sopenharmony_ci * ccp2_link_setup - Setup ccp2 connections. 9488c2ecf20Sopenharmony_ci * @entity : Pointer to media entity structure 9498c2ecf20Sopenharmony_ci * @local : Pointer to local pad array 9508c2ecf20Sopenharmony_ci * @remote : Pointer to remote pad array 9518c2ecf20Sopenharmony_ci * @flags : Link flags 9528c2ecf20Sopenharmony_ci * return -EINVAL on error or zero on success 9538c2ecf20Sopenharmony_ci */ 9548c2ecf20Sopenharmony_cistatic int ccp2_link_setup(struct media_entity *entity, 9558c2ecf20Sopenharmony_ci const struct media_pad *local, 9568c2ecf20Sopenharmony_ci const struct media_pad *remote, u32 flags) 9578c2ecf20Sopenharmony_ci{ 9588c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); 9598c2ecf20Sopenharmony_ci struct isp_ccp2_device *ccp2 = v4l2_get_subdevdata(sd); 9608c2ecf20Sopenharmony_ci unsigned int index = local->index; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci /* FIXME: this is actually a hack! */ 9638c2ecf20Sopenharmony_ci if (is_media_entity_v4l2_subdev(remote->entity)) 9648c2ecf20Sopenharmony_ci index |= 2 << 16; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci switch (index) { 9678c2ecf20Sopenharmony_ci case CCP2_PAD_SINK: 9688c2ecf20Sopenharmony_ci /* read from memory */ 9698c2ecf20Sopenharmony_ci if (flags & MEDIA_LNK_FL_ENABLED) { 9708c2ecf20Sopenharmony_ci if (ccp2->input == CCP2_INPUT_SENSOR) 9718c2ecf20Sopenharmony_ci return -EBUSY; 9728c2ecf20Sopenharmony_ci ccp2->input = CCP2_INPUT_MEMORY; 9738c2ecf20Sopenharmony_ci } else { 9748c2ecf20Sopenharmony_ci if (ccp2->input == CCP2_INPUT_MEMORY) 9758c2ecf20Sopenharmony_ci ccp2->input = CCP2_INPUT_NONE; 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci break; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci case CCP2_PAD_SINK | 2 << 16: 9808c2ecf20Sopenharmony_ci /* read from sensor/phy */ 9818c2ecf20Sopenharmony_ci if (flags & MEDIA_LNK_FL_ENABLED) { 9828c2ecf20Sopenharmony_ci if (ccp2->input == CCP2_INPUT_MEMORY) 9838c2ecf20Sopenharmony_ci return -EBUSY; 9848c2ecf20Sopenharmony_ci ccp2->input = CCP2_INPUT_SENSOR; 9858c2ecf20Sopenharmony_ci } else { 9868c2ecf20Sopenharmony_ci if (ccp2->input == CCP2_INPUT_SENSOR) 9878c2ecf20Sopenharmony_ci ccp2->input = CCP2_INPUT_NONE; 9888c2ecf20Sopenharmony_ci } break; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci case CCP2_PAD_SOURCE | 2 << 16: 9918c2ecf20Sopenharmony_ci /* write to video port/ccdc */ 9928c2ecf20Sopenharmony_ci if (flags & MEDIA_LNK_FL_ENABLED) 9938c2ecf20Sopenharmony_ci ccp2->output = CCP2_OUTPUT_CCDC; 9948c2ecf20Sopenharmony_ci else 9958c2ecf20Sopenharmony_ci ccp2->output = CCP2_OUTPUT_NONE; 9968c2ecf20Sopenharmony_ci break; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci default: 9998c2ecf20Sopenharmony_ci return -EINVAL; 10008c2ecf20Sopenharmony_ci } 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci return 0; 10038c2ecf20Sopenharmony_ci} 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci/* media operations */ 10068c2ecf20Sopenharmony_cistatic const struct media_entity_operations ccp2_media_ops = { 10078c2ecf20Sopenharmony_ci .link_setup = ccp2_link_setup, 10088c2ecf20Sopenharmony_ci .link_validate = v4l2_subdev_link_validate, 10098c2ecf20Sopenharmony_ci}; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci/* 10128c2ecf20Sopenharmony_ci * omap3isp_ccp2_unregister_entities - Unregister media entities: subdev 10138c2ecf20Sopenharmony_ci * @ccp2: Pointer to ISP CCP2 device 10148c2ecf20Sopenharmony_ci */ 10158c2ecf20Sopenharmony_civoid omap3isp_ccp2_unregister_entities(struct isp_ccp2_device *ccp2) 10168c2ecf20Sopenharmony_ci{ 10178c2ecf20Sopenharmony_ci v4l2_device_unregister_subdev(&ccp2->subdev); 10188c2ecf20Sopenharmony_ci omap3isp_video_unregister(&ccp2->video_in); 10198c2ecf20Sopenharmony_ci} 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci/* 10228c2ecf20Sopenharmony_ci * omap3isp_ccp2_register_entities - Register the subdev media entity 10238c2ecf20Sopenharmony_ci * @ccp2: Pointer to ISP CCP2 device 10248c2ecf20Sopenharmony_ci * @vdev: Pointer to v4l device 10258c2ecf20Sopenharmony_ci * return negative error code or zero on success 10268c2ecf20Sopenharmony_ci */ 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ciint omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2, 10298c2ecf20Sopenharmony_ci struct v4l2_device *vdev) 10308c2ecf20Sopenharmony_ci{ 10318c2ecf20Sopenharmony_ci int ret; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci /* Register the subdev and video nodes. */ 10348c2ecf20Sopenharmony_ci ccp2->subdev.dev = vdev->mdev->dev; 10358c2ecf20Sopenharmony_ci ret = v4l2_device_register_subdev(vdev, &ccp2->subdev); 10368c2ecf20Sopenharmony_ci if (ret < 0) 10378c2ecf20Sopenharmony_ci goto error; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci ret = omap3isp_video_register(&ccp2->video_in, vdev); 10408c2ecf20Sopenharmony_ci if (ret < 0) 10418c2ecf20Sopenharmony_ci goto error; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci return 0; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_cierror: 10468c2ecf20Sopenharmony_ci omap3isp_ccp2_unregister_entities(ccp2); 10478c2ecf20Sopenharmony_ci return ret; 10488c2ecf20Sopenharmony_ci} 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 10518c2ecf20Sopenharmony_ci * ISP ccp2 initialisation and cleanup 10528c2ecf20Sopenharmony_ci */ 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci/* 10558c2ecf20Sopenharmony_ci * ccp2_init_entities - Initialize ccp2 subdev and media entity. 10568c2ecf20Sopenharmony_ci * @ccp2: Pointer to ISP CCP2 device 10578c2ecf20Sopenharmony_ci * return negative error code or zero on success 10588c2ecf20Sopenharmony_ci */ 10598c2ecf20Sopenharmony_cistatic int ccp2_init_entities(struct isp_ccp2_device *ccp2) 10608c2ecf20Sopenharmony_ci{ 10618c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = &ccp2->subdev; 10628c2ecf20Sopenharmony_ci struct media_pad *pads = ccp2->pads; 10638c2ecf20Sopenharmony_ci struct media_entity *me = &sd->entity; 10648c2ecf20Sopenharmony_ci int ret; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci ccp2->input = CCP2_INPUT_NONE; 10678c2ecf20Sopenharmony_ci ccp2->output = CCP2_OUTPUT_NONE; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci v4l2_subdev_init(sd, &ccp2_sd_ops); 10708c2ecf20Sopenharmony_ci sd->internal_ops = &ccp2_sd_internal_ops; 10718c2ecf20Sopenharmony_ci strscpy(sd->name, "OMAP3 ISP CCP2", sizeof(sd->name)); 10728c2ecf20Sopenharmony_ci sd->grp_id = 1 << 16; /* group ID for isp subdevs */ 10738c2ecf20Sopenharmony_ci v4l2_set_subdevdata(sd, ccp2); 10748c2ecf20Sopenharmony_ci sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci pads[CCP2_PAD_SINK].flags = MEDIA_PAD_FL_SINK 10778c2ecf20Sopenharmony_ci | MEDIA_PAD_FL_MUST_CONNECT; 10788c2ecf20Sopenharmony_ci pads[CCP2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci me->ops = &ccp2_media_ops; 10818c2ecf20Sopenharmony_ci ret = media_entity_pads_init(me, CCP2_PADS_NUM, pads); 10828c2ecf20Sopenharmony_ci if (ret < 0) 10838c2ecf20Sopenharmony_ci return ret; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci ccp2_init_formats(sd, NULL); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci /* 10888c2ecf20Sopenharmony_ci * The CCP2 has weird line alignment requirements, possibly caused by 10898c2ecf20Sopenharmony_ci * DPCM8 decompression. Line length for data read from memory must be a 10908c2ecf20Sopenharmony_ci * multiple of 128 bits (16 bytes) in continuous mode (when no padding 10918c2ecf20Sopenharmony_ci * is present at end of lines). Additionally, if padding is used, the 10928c2ecf20Sopenharmony_ci * padded line length must be a multiple of 32 bytes. To simplify the 10938c2ecf20Sopenharmony_ci * implementation we use a fixed 32 bytes alignment regardless of the 10948c2ecf20Sopenharmony_ci * input format and width. If strict 128 bits alignment support is 10958c2ecf20Sopenharmony_ci * required ispvideo will need to be made aware of this special dual 10968c2ecf20Sopenharmony_ci * alignment requirements. 10978c2ecf20Sopenharmony_ci */ 10988c2ecf20Sopenharmony_ci ccp2->video_in.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; 10998c2ecf20Sopenharmony_ci ccp2->video_in.bpl_alignment = 32; 11008c2ecf20Sopenharmony_ci ccp2->video_in.bpl_max = 0xffffffe0; 11018c2ecf20Sopenharmony_ci ccp2->video_in.isp = to_isp_device(ccp2); 11028c2ecf20Sopenharmony_ci ccp2->video_in.ops = &ccp2_video_ops; 11038c2ecf20Sopenharmony_ci ccp2->video_in.capture_mem = PAGE_ALIGN(4096 * 4096) * 3; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci ret = omap3isp_video_init(&ccp2->video_in, "CCP2"); 11068c2ecf20Sopenharmony_ci if (ret < 0) 11078c2ecf20Sopenharmony_ci goto error; 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci return 0; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_cierror: 11128c2ecf20Sopenharmony_ci media_entity_cleanup(&ccp2->subdev.entity); 11138c2ecf20Sopenharmony_ci return ret; 11148c2ecf20Sopenharmony_ci} 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci/* 11178c2ecf20Sopenharmony_ci * omap3isp_ccp2_init - CCP2 initialization. 11188c2ecf20Sopenharmony_ci * @isp : Pointer to ISP device 11198c2ecf20Sopenharmony_ci * return negative error code or zero on success 11208c2ecf20Sopenharmony_ci */ 11218c2ecf20Sopenharmony_ciint omap3isp_ccp2_init(struct isp_device *isp) 11228c2ecf20Sopenharmony_ci{ 11238c2ecf20Sopenharmony_ci struct isp_ccp2_device *ccp2 = &isp->isp_ccp2; 11248c2ecf20Sopenharmony_ci int ret; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci init_waitqueue_head(&ccp2->wait); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci /* 11298c2ecf20Sopenharmony_ci * On the OMAP34xx the CSI1 receiver is operated in the CSIb IO 11308c2ecf20Sopenharmony_ci * complex, which is powered by vdds_csib power rail. Hence the 11318c2ecf20Sopenharmony_ci * request for the regulator. 11328c2ecf20Sopenharmony_ci * 11338c2ecf20Sopenharmony_ci * On the OMAP36xx, the CCP2 uses the CSI PHY1 or PHY2, shared with 11348c2ecf20Sopenharmony_ci * the CSI2c or CSI2a receivers. The PHY then needs to be explicitly 11358c2ecf20Sopenharmony_ci * configured. 11368c2ecf20Sopenharmony_ci * 11378c2ecf20Sopenharmony_ci * TODO: Don't hardcode the usage of PHY1 (shared with CSI2c). 11388c2ecf20Sopenharmony_ci */ 11398c2ecf20Sopenharmony_ci if (isp->revision == ISP_REVISION_2_0) { 11408c2ecf20Sopenharmony_ci ccp2->vdds_csib = devm_regulator_get(isp->dev, "vdds_csib"); 11418c2ecf20Sopenharmony_ci if (IS_ERR(ccp2->vdds_csib)) { 11428c2ecf20Sopenharmony_ci if (PTR_ERR(ccp2->vdds_csib) == -EPROBE_DEFER) { 11438c2ecf20Sopenharmony_ci dev_dbg(isp->dev, 11448c2ecf20Sopenharmony_ci "Can't get regulator vdds_csib, deferring probing\n"); 11458c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 11468c2ecf20Sopenharmony_ci } 11478c2ecf20Sopenharmony_ci dev_dbg(isp->dev, 11488c2ecf20Sopenharmony_ci "Could not get regulator vdds_csib\n"); 11498c2ecf20Sopenharmony_ci ccp2->vdds_csib = NULL; 11508c2ecf20Sopenharmony_ci } 11518c2ecf20Sopenharmony_ci ccp2->phy = &isp->isp_csiphy2; 11528c2ecf20Sopenharmony_ci } else if (isp->revision == ISP_REVISION_15_0) { 11538c2ecf20Sopenharmony_ci ccp2->phy = &isp->isp_csiphy1; 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci ret = ccp2_init_entities(ccp2); 11578c2ecf20Sopenharmony_ci if (ret < 0) 11588c2ecf20Sopenharmony_ci return ret; 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci ccp2_reset(ccp2); 11618c2ecf20Sopenharmony_ci return 0; 11628c2ecf20Sopenharmony_ci} 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci/* 11658c2ecf20Sopenharmony_ci * omap3isp_ccp2_cleanup - CCP2 un-initialization 11668c2ecf20Sopenharmony_ci * @isp : Pointer to ISP device 11678c2ecf20Sopenharmony_ci */ 11688c2ecf20Sopenharmony_civoid omap3isp_ccp2_cleanup(struct isp_device *isp) 11698c2ecf20Sopenharmony_ci{ 11708c2ecf20Sopenharmony_ci struct isp_ccp2_device *ccp2 = &isp->isp_ccp2; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci omap3isp_video_cleanup(&ccp2->video_in); 11738c2ecf20Sopenharmony_ci media_entity_cleanup(&ccp2->subdev.entity); 11748c2ecf20Sopenharmony_ci} 1175