18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for Renesas R-Car MIPI CSI-2 Receiver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2018 Renesas Electronics Corp. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/delay.h> 98c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 108c2ecf20Sopenharmony_ci#include <linux/io.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/of.h> 138c2ecf20Sopenharmony_ci#include <linux/of_device.h> 148c2ecf20Sopenharmony_ci#include <linux/of_graph.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 178c2ecf20Sopenharmony_ci#include <linux/reset.h> 188c2ecf20Sopenharmony_ci#include <linux/sys_soc.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <media/v4l2-ctrls.h> 218c2ecf20Sopenharmony_ci#include <media/v4l2-device.h> 228c2ecf20Sopenharmony_ci#include <media/v4l2-fwnode.h> 238c2ecf20Sopenharmony_ci#include <media/v4l2-mc.h> 248c2ecf20Sopenharmony_ci#include <media/v4l2-subdev.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistruct rcar_csi2; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* Register offsets and bits */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* Control Timing Select */ 318c2ecf20Sopenharmony_ci#define TREF_REG 0x00 328c2ecf20Sopenharmony_ci#define TREF_TREF BIT(0) 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* Software Reset */ 358c2ecf20Sopenharmony_ci#define SRST_REG 0x04 368c2ecf20Sopenharmony_ci#define SRST_SRST BIT(0) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* PHY Operation Control */ 398c2ecf20Sopenharmony_ci#define PHYCNT_REG 0x08 408c2ecf20Sopenharmony_ci#define PHYCNT_SHUTDOWNZ BIT(17) 418c2ecf20Sopenharmony_ci#define PHYCNT_RSTZ BIT(16) 428c2ecf20Sopenharmony_ci#define PHYCNT_ENABLECLK BIT(4) 438c2ecf20Sopenharmony_ci#define PHYCNT_ENABLE_3 BIT(3) 448c2ecf20Sopenharmony_ci#define PHYCNT_ENABLE_2 BIT(2) 458c2ecf20Sopenharmony_ci#define PHYCNT_ENABLE_1 BIT(1) 468c2ecf20Sopenharmony_ci#define PHYCNT_ENABLE_0 BIT(0) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* Checksum Control */ 498c2ecf20Sopenharmony_ci#define CHKSUM_REG 0x0c 508c2ecf20Sopenharmony_ci#define CHKSUM_ECC_EN BIT(1) 518c2ecf20Sopenharmony_ci#define CHKSUM_CRC_EN BIT(0) 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* 548c2ecf20Sopenharmony_ci * Channel Data Type Select 558c2ecf20Sopenharmony_ci * VCDT[0-15]: Channel 0 VCDT[16-31]: Channel 1 568c2ecf20Sopenharmony_ci * VCDT2[0-15]: Channel 2 VCDT2[16-31]: Channel 3 578c2ecf20Sopenharmony_ci */ 588c2ecf20Sopenharmony_ci#define VCDT_REG 0x10 598c2ecf20Sopenharmony_ci#define VCDT2_REG 0x14 608c2ecf20Sopenharmony_ci#define VCDT_VCDTN_EN BIT(15) 618c2ecf20Sopenharmony_ci#define VCDT_SEL_VC(n) (((n) & 0x3) << 8) 628c2ecf20Sopenharmony_ci#define VCDT_SEL_DTN_ON BIT(6) 638c2ecf20Sopenharmony_ci#define VCDT_SEL_DT(n) (((n) & 0x3f) << 0) 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* Frame Data Type Select */ 668c2ecf20Sopenharmony_ci#define FRDT_REG 0x18 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* Field Detection Control */ 698c2ecf20Sopenharmony_ci#define FLD_REG 0x1c 708c2ecf20Sopenharmony_ci#define FLD_FLD_NUM(n) (((n) & 0xff) << 16) 718c2ecf20Sopenharmony_ci#define FLD_DET_SEL(n) (((n) & 0x3) << 4) 728c2ecf20Sopenharmony_ci#define FLD_FLD_EN4 BIT(3) 738c2ecf20Sopenharmony_ci#define FLD_FLD_EN3 BIT(2) 748c2ecf20Sopenharmony_ci#define FLD_FLD_EN2 BIT(1) 758c2ecf20Sopenharmony_ci#define FLD_FLD_EN BIT(0) 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* Automatic Standby Control */ 788c2ecf20Sopenharmony_ci#define ASTBY_REG 0x20 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* Long Data Type Setting 0 */ 818c2ecf20Sopenharmony_ci#define LNGDT0_REG 0x28 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* Long Data Type Setting 1 */ 848c2ecf20Sopenharmony_ci#define LNGDT1_REG 0x2c 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/* Interrupt Enable */ 878c2ecf20Sopenharmony_ci#define INTEN_REG 0x30 888c2ecf20Sopenharmony_ci#define INTEN_INT_AFIFO_OF BIT(27) 898c2ecf20Sopenharmony_ci#define INTEN_INT_ERRSOTHS BIT(4) 908c2ecf20Sopenharmony_ci#define INTEN_INT_ERRSOTSYNCHS BIT(3) 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* Interrupt Source Mask */ 938c2ecf20Sopenharmony_ci#define INTCLOSE_REG 0x34 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci/* Interrupt Status Monitor */ 968c2ecf20Sopenharmony_ci#define INTSTATE_REG 0x38 978c2ecf20Sopenharmony_ci#define INTSTATE_INT_ULPS_START BIT(7) 988c2ecf20Sopenharmony_ci#define INTSTATE_INT_ULPS_END BIT(6) 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/* Interrupt Error Status Monitor */ 1018c2ecf20Sopenharmony_ci#define INTERRSTATE_REG 0x3c 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/* Short Packet Data */ 1048c2ecf20Sopenharmony_ci#define SHPDAT_REG 0x40 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* Short Packet Count */ 1078c2ecf20Sopenharmony_ci#define SHPCNT_REG 0x44 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/* LINK Operation Control */ 1108c2ecf20Sopenharmony_ci#define LINKCNT_REG 0x48 1118c2ecf20Sopenharmony_ci#define LINKCNT_MONITOR_EN BIT(31) 1128c2ecf20Sopenharmony_ci#define LINKCNT_REG_MONI_PACT_EN BIT(25) 1138c2ecf20Sopenharmony_ci#define LINKCNT_ICLK_NONSTOP BIT(24) 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* Lane Swap */ 1168c2ecf20Sopenharmony_ci#define LSWAP_REG 0x4c 1178c2ecf20Sopenharmony_ci#define LSWAP_L3SEL(n) (((n) & 0x3) << 6) 1188c2ecf20Sopenharmony_ci#define LSWAP_L2SEL(n) (((n) & 0x3) << 4) 1198c2ecf20Sopenharmony_ci#define LSWAP_L1SEL(n) (((n) & 0x3) << 2) 1208c2ecf20Sopenharmony_ci#define LSWAP_L0SEL(n) (((n) & 0x3) << 0) 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/* PHY Test Interface Write Register */ 1238c2ecf20Sopenharmony_ci#define PHTW_REG 0x50 1248c2ecf20Sopenharmony_ci#define PHTW_DWEN BIT(24) 1258c2ecf20Sopenharmony_ci#define PHTW_TESTDIN_DATA(n) (((n & 0xff)) << 16) 1268c2ecf20Sopenharmony_ci#define PHTW_CWEN BIT(8) 1278c2ecf20Sopenharmony_ci#define PHTW_TESTDIN_CODE(n) ((n & 0xff)) 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistruct phtw_value { 1308c2ecf20Sopenharmony_ci u16 data; 1318c2ecf20Sopenharmony_ci u16 code; 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistruct rcsi2_mbps_reg { 1358c2ecf20Sopenharmony_ci u16 mbps; 1368c2ecf20Sopenharmony_ci u16 reg; 1378c2ecf20Sopenharmony_ci}; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic const struct rcsi2_mbps_reg phtw_mbps_h3_v3h_m3n[] = { 1408c2ecf20Sopenharmony_ci { .mbps = 80, .reg = 0x86 }, 1418c2ecf20Sopenharmony_ci { .mbps = 90, .reg = 0x86 }, 1428c2ecf20Sopenharmony_ci { .mbps = 100, .reg = 0x87 }, 1438c2ecf20Sopenharmony_ci { .mbps = 110, .reg = 0x87 }, 1448c2ecf20Sopenharmony_ci { .mbps = 120, .reg = 0x88 }, 1458c2ecf20Sopenharmony_ci { .mbps = 130, .reg = 0x88 }, 1468c2ecf20Sopenharmony_ci { .mbps = 140, .reg = 0x89 }, 1478c2ecf20Sopenharmony_ci { .mbps = 150, .reg = 0x89 }, 1488c2ecf20Sopenharmony_ci { .mbps = 160, .reg = 0x8a }, 1498c2ecf20Sopenharmony_ci { .mbps = 170, .reg = 0x8a }, 1508c2ecf20Sopenharmony_ci { .mbps = 180, .reg = 0x8b }, 1518c2ecf20Sopenharmony_ci { .mbps = 190, .reg = 0x8b }, 1528c2ecf20Sopenharmony_ci { .mbps = 205, .reg = 0x8c }, 1538c2ecf20Sopenharmony_ci { .mbps = 220, .reg = 0x8d }, 1548c2ecf20Sopenharmony_ci { .mbps = 235, .reg = 0x8e }, 1558c2ecf20Sopenharmony_ci { .mbps = 250, .reg = 0x8e }, 1568c2ecf20Sopenharmony_ci { /* sentinel */ }, 1578c2ecf20Sopenharmony_ci}; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cistatic const struct rcsi2_mbps_reg phtw_mbps_v3m_e3[] = { 1608c2ecf20Sopenharmony_ci { .mbps = 80, .reg = 0x00 }, 1618c2ecf20Sopenharmony_ci { .mbps = 90, .reg = 0x20 }, 1628c2ecf20Sopenharmony_ci { .mbps = 100, .reg = 0x40 }, 1638c2ecf20Sopenharmony_ci { .mbps = 110, .reg = 0x02 }, 1648c2ecf20Sopenharmony_ci { .mbps = 130, .reg = 0x22 }, 1658c2ecf20Sopenharmony_ci { .mbps = 140, .reg = 0x42 }, 1668c2ecf20Sopenharmony_ci { .mbps = 150, .reg = 0x04 }, 1678c2ecf20Sopenharmony_ci { .mbps = 170, .reg = 0x24 }, 1688c2ecf20Sopenharmony_ci { .mbps = 180, .reg = 0x44 }, 1698c2ecf20Sopenharmony_ci { .mbps = 200, .reg = 0x06 }, 1708c2ecf20Sopenharmony_ci { .mbps = 220, .reg = 0x26 }, 1718c2ecf20Sopenharmony_ci { .mbps = 240, .reg = 0x46 }, 1728c2ecf20Sopenharmony_ci { .mbps = 250, .reg = 0x08 }, 1738c2ecf20Sopenharmony_ci { .mbps = 270, .reg = 0x28 }, 1748c2ecf20Sopenharmony_ci { .mbps = 300, .reg = 0x0a }, 1758c2ecf20Sopenharmony_ci { .mbps = 330, .reg = 0x2a }, 1768c2ecf20Sopenharmony_ci { .mbps = 360, .reg = 0x4a }, 1778c2ecf20Sopenharmony_ci { .mbps = 400, .reg = 0x0c }, 1788c2ecf20Sopenharmony_ci { .mbps = 450, .reg = 0x2c }, 1798c2ecf20Sopenharmony_ci { .mbps = 500, .reg = 0x0e }, 1808c2ecf20Sopenharmony_ci { .mbps = 550, .reg = 0x2e }, 1818c2ecf20Sopenharmony_ci { .mbps = 600, .reg = 0x10 }, 1828c2ecf20Sopenharmony_ci { .mbps = 650, .reg = 0x30 }, 1838c2ecf20Sopenharmony_ci { .mbps = 700, .reg = 0x12 }, 1848c2ecf20Sopenharmony_ci { .mbps = 750, .reg = 0x32 }, 1858c2ecf20Sopenharmony_ci { .mbps = 800, .reg = 0x52 }, 1868c2ecf20Sopenharmony_ci { .mbps = 850, .reg = 0x72 }, 1878c2ecf20Sopenharmony_ci { .mbps = 900, .reg = 0x14 }, 1888c2ecf20Sopenharmony_ci { .mbps = 950, .reg = 0x34 }, 1898c2ecf20Sopenharmony_ci { .mbps = 1000, .reg = 0x54 }, 1908c2ecf20Sopenharmony_ci { .mbps = 1050, .reg = 0x74 }, 1918c2ecf20Sopenharmony_ci { .mbps = 1125, .reg = 0x16 }, 1928c2ecf20Sopenharmony_ci { /* sentinel */ }, 1938c2ecf20Sopenharmony_ci}; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci/* PHY Test Interface Clear */ 1968c2ecf20Sopenharmony_ci#define PHTC_REG 0x58 1978c2ecf20Sopenharmony_ci#define PHTC_TESTCLR BIT(0) 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci/* PHY Frequency Control */ 2008c2ecf20Sopenharmony_ci#define PHYPLL_REG 0x68 2018c2ecf20Sopenharmony_ci#define PHYPLL_HSFREQRANGE(n) ((n) << 16) 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic const struct rcsi2_mbps_reg hsfreqrange_h3_v3h_m3n[] = { 2048c2ecf20Sopenharmony_ci { .mbps = 80, .reg = 0x00 }, 2058c2ecf20Sopenharmony_ci { .mbps = 90, .reg = 0x10 }, 2068c2ecf20Sopenharmony_ci { .mbps = 100, .reg = 0x20 }, 2078c2ecf20Sopenharmony_ci { .mbps = 110, .reg = 0x30 }, 2088c2ecf20Sopenharmony_ci { .mbps = 120, .reg = 0x01 }, 2098c2ecf20Sopenharmony_ci { .mbps = 130, .reg = 0x11 }, 2108c2ecf20Sopenharmony_ci { .mbps = 140, .reg = 0x21 }, 2118c2ecf20Sopenharmony_ci { .mbps = 150, .reg = 0x31 }, 2128c2ecf20Sopenharmony_ci { .mbps = 160, .reg = 0x02 }, 2138c2ecf20Sopenharmony_ci { .mbps = 170, .reg = 0x12 }, 2148c2ecf20Sopenharmony_ci { .mbps = 180, .reg = 0x22 }, 2158c2ecf20Sopenharmony_ci { .mbps = 190, .reg = 0x32 }, 2168c2ecf20Sopenharmony_ci { .mbps = 205, .reg = 0x03 }, 2178c2ecf20Sopenharmony_ci { .mbps = 220, .reg = 0x13 }, 2188c2ecf20Sopenharmony_ci { .mbps = 235, .reg = 0x23 }, 2198c2ecf20Sopenharmony_ci { .mbps = 250, .reg = 0x33 }, 2208c2ecf20Sopenharmony_ci { .mbps = 275, .reg = 0x04 }, 2218c2ecf20Sopenharmony_ci { .mbps = 300, .reg = 0x14 }, 2228c2ecf20Sopenharmony_ci { .mbps = 325, .reg = 0x25 }, 2238c2ecf20Sopenharmony_ci { .mbps = 350, .reg = 0x35 }, 2248c2ecf20Sopenharmony_ci { .mbps = 400, .reg = 0x05 }, 2258c2ecf20Sopenharmony_ci { .mbps = 450, .reg = 0x16 }, 2268c2ecf20Sopenharmony_ci { .mbps = 500, .reg = 0x26 }, 2278c2ecf20Sopenharmony_ci { .mbps = 550, .reg = 0x37 }, 2288c2ecf20Sopenharmony_ci { .mbps = 600, .reg = 0x07 }, 2298c2ecf20Sopenharmony_ci { .mbps = 650, .reg = 0x18 }, 2308c2ecf20Sopenharmony_ci { .mbps = 700, .reg = 0x28 }, 2318c2ecf20Sopenharmony_ci { .mbps = 750, .reg = 0x39 }, 2328c2ecf20Sopenharmony_ci { .mbps = 800, .reg = 0x09 }, 2338c2ecf20Sopenharmony_ci { .mbps = 850, .reg = 0x19 }, 2348c2ecf20Sopenharmony_ci { .mbps = 900, .reg = 0x29 }, 2358c2ecf20Sopenharmony_ci { .mbps = 950, .reg = 0x3a }, 2368c2ecf20Sopenharmony_ci { .mbps = 1000, .reg = 0x0a }, 2378c2ecf20Sopenharmony_ci { .mbps = 1050, .reg = 0x1a }, 2388c2ecf20Sopenharmony_ci { .mbps = 1100, .reg = 0x2a }, 2398c2ecf20Sopenharmony_ci { .mbps = 1150, .reg = 0x3b }, 2408c2ecf20Sopenharmony_ci { .mbps = 1200, .reg = 0x0b }, 2418c2ecf20Sopenharmony_ci { .mbps = 1250, .reg = 0x1b }, 2428c2ecf20Sopenharmony_ci { .mbps = 1300, .reg = 0x2b }, 2438c2ecf20Sopenharmony_ci { .mbps = 1350, .reg = 0x3c }, 2448c2ecf20Sopenharmony_ci { .mbps = 1400, .reg = 0x0c }, 2458c2ecf20Sopenharmony_ci { .mbps = 1450, .reg = 0x1c }, 2468c2ecf20Sopenharmony_ci { .mbps = 1500, .reg = 0x2c }, 2478c2ecf20Sopenharmony_ci { /* sentinel */ }, 2488c2ecf20Sopenharmony_ci}; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic const struct rcsi2_mbps_reg hsfreqrange_m3w_h3es1[] = { 2518c2ecf20Sopenharmony_ci { .mbps = 80, .reg = 0x00 }, 2528c2ecf20Sopenharmony_ci { .mbps = 90, .reg = 0x10 }, 2538c2ecf20Sopenharmony_ci { .mbps = 100, .reg = 0x20 }, 2548c2ecf20Sopenharmony_ci { .mbps = 110, .reg = 0x30 }, 2558c2ecf20Sopenharmony_ci { .mbps = 120, .reg = 0x01 }, 2568c2ecf20Sopenharmony_ci { .mbps = 130, .reg = 0x11 }, 2578c2ecf20Sopenharmony_ci { .mbps = 140, .reg = 0x21 }, 2588c2ecf20Sopenharmony_ci { .mbps = 150, .reg = 0x31 }, 2598c2ecf20Sopenharmony_ci { .mbps = 160, .reg = 0x02 }, 2608c2ecf20Sopenharmony_ci { .mbps = 170, .reg = 0x12 }, 2618c2ecf20Sopenharmony_ci { .mbps = 180, .reg = 0x22 }, 2628c2ecf20Sopenharmony_ci { .mbps = 190, .reg = 0x32 }, 2638c2ecf20Sopenharmony_ci { .mbps = 205, .reg = 0x03 }, 2648c2ecf20Sopenharmony_ci { .mbps = 220, .reg = 0x13 }, 2658c2ecf20Sopenharmony_ci { .mbps = 235, .reg = 0x23 }, 2668c2ecf20Sopenharmony_ci { .mbps = 250, .reg = 0x33 }, 2678c2ecf20Sopenharmony_ci { .mbps = 275, .reg = 0x04 }, 2688c2ecf20Sopenharmony_ci { .mbps = 300, .reg = 0x14 }, 2698c2ecf20Sopenharmony_ci { .mbps = 325, .reg = 0x05 }, 2708c2ecf20Sopenharmony_ci { .mbps = 350, .reg = 0x15 }, 2718c2ecf20Sopenharmony_ci { .mbps = 400, .reg = 0x25 }, 2728c2ecf20Sopenharmony_ci { .mbps = 450, .reg = 0x06 }, 2738c2ecf20Sopenharmony_ci { .mbps = 500, .reg = 0x16 }, 2748c2ecf20Sopenharmony_ci { .mbps = 550, .reg = 0x07 }, 2758c2ecf20Sopenharmony_ci { .mbps = 600, .reg = 0x17 }, 2768c2ecf20Sopenharmony_ci { .mbps = 650, .reg = 0x08 }, 2778c2ecf20Sopenharmony_ci { .mbps = 700, .reg = 0x18 }, 2788c2ecf20Sopenharmony_ci { .mbps = 750, .reg = 0x09 }, 2798c2ecf20Sopenharmony_ci { .mbps = 800, .reg = 0x19 }, 2808c2ecf20Sopenharmony_ci { .mbps = 850, .reg = 0x29 }, 2818c2ecf20Sopenharmony_ci { .mbps = 900, .reg = 0x39 }, 2828c2ecf20Sopenharmony_ci { .mbps = 950, .reg = 0x0a }, 2838c2ecf20Sopenharmony_ci { .mbps = 1000, .reg = 0x1a }, 2848c2ecf20Sopenharmony_ci { .mbps = 1050, .reg = 0x2a }, 2858c2ecf20Sopenharmony_ci { .mbps = 1100, .reg = 0x3a }, 2868c2ecf20Sopenharmony_ci { .mbps = 1150, .reg = 0x0b }, 2878c2ecf20Sopenharmony_ci { .mbps = 1200, .reg = 0x1b }, 2888c2ecf20Sopenharmony_ci { .mbps = 1250, .reg = 0x2b }, 2898c2ecf20Sopenharmony_ci { .mbps = 1300, .reg = 0x3b }, 2908c2ecf20Sopenharmony_ci { .mbps = 1350, .reg = 0x0c }, 2918c2ecf20Sopenharmony_ci { .mbps = 1400, .reg = 0x1c }, 2928c2ecf20Sopenharmony_ci { .mbps = 1450, .reg = 0x2c }, 2938c2ecf20Sopenharmony_ci { .mbps = 1500, .reg = 0x3c }, 2948c2ecf20Sopenharmony_ci { /* sentinel */ }, 2958c2ecf20Sopenharmony_ci}; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci/* PHY ESC Error Monitor */ 2988c2ecf20Sopenharmony_ci#define PHEERM_REG 0x74 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci/* PHY Clock Lane Monitor */ 3018c2ecf20Sopenharmony_ci#define PHCLM_REG 0x78 3028c2ecf20Sopenharmony_ci#define PHCLM_STOPSTATECKL BIT(0) 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci/* PHY Data Lane Monitor */ 3058c2ecf20Sopenharmony_ci#define PHDLM_REG 0x7c 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci/* CSI0CLK Frequency Configuration Preset Register */ 3088c2ecf20Sopenharmony_ci#define CSI0CLKFCPR_REG 0x260 3098c2ecf20Sopenharmony_ci#define CSI0CLKFREQRANGE(n) ((n & 0x3f) << 16) 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistruct rcar_csi2_format { 3128c2ecf20Sopenharmony_ci u32 code; 3138c2ecf20Sopenharmony_ci unsigned int datatype; 3148c2ecf20Sopenharmony_ci unsigned int bpp; 3158c2ecf20Sopenharmony_ci}; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic const struct rcar_csi2_format rcar_csi2_formats[] = { 3188c2ecf20Sopenharmony_ci { .code = MEDIA_BUS_FMT_RGB888_1X24, .datatype = 0x24, .bpp = 24 }, 3198c2ecf20Sopenharmony_ci { .code = MEDIA_BUS_FMT_UYVY8_1X16, .datatype = 0x1e, .bpp = 16 }, 3208c2ecf20Sopenharmony_ci { .code = MEDIA_BUS_FMT_YUYV8_1X16, .datatype = 0x1e, .bpp = 16 }, 3218c2ecf20Sopenharmony_ci { .code = MEDIA_BUS_FMT_UYVY8_2X8, .datatype = 0x1e, .bpp = 16 }, 3228c2ecf20Sopenharmony_ci { .code = MEDIA_BUS_FMT_YUYV10_2X10, .datatype = 0x1e, .bpp = 20 }, 3238c2ecf20Sopenharmony_ci { .code = MEDIA_BUS_FMT_SBGGR8_1X8, .datatype = 0x2a, .bpp = 8 }, 3248c2ecf20Sopenharmony_ci { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .datatype = 0x2a, .bpp = 8 }, 3258c2ecf20Sopenharmony_ci { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .datatype = 0x2a, .bpp = 8 }, 3268c2ecf20Sopenharmony_ci { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .datatype = 0x2a, .bpp = 8 }, 3278c2ecf20Sopenharmony_ci}; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic const struct rcar_csi2_format *rcsi2_code_to_fmt(unsigned int code) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci unsigned int i; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rcar_csi2_formats); i++) 3348c2ecf20Sopenharmony_ci if (rcar_csi2_formats[i].code == code) 3358c2ecf20Sopenharmony_ci return &rcar_csi2_formats[i]; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci return NULL; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cienum rcar_csi2_pads { 3418c2ecf20Sopenharmony_ci RCAR_CSI2_SINK, 3428c2ecf20Sopenharmony_ci RCAR_CSI2_SOURCE_VC0, 3438c2ecf20Sopenharmony_ci RCAR_CSI2_SOURCE_VC1, 3448c2ecf20Sopenharmony_ci RCAR_CSI2_SOURCE_VC2, 3458c2ecf20Sopenharmony_ci RCAR_CSI2_SOURCE_VC3, 3468c2ecf20Sopenharmony_ci NR_OF_RCAR_CSI2_PAD, 3478c2ecf20Sopenharmony_ci}; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistruct rcar_csi2_info { 3508c2ecf20Sopenharmony_ci int (*init_phtw)(struct rcar_csi2 *priv, unsigned int mbps); 3518c2ecf20Sopenharmony_ci int (*phy_post_init)(struct rcar_csi2 *priv); 3528c2ecf20Sopenharmony_ci const struct rcsi2_mbps_reg *hsfreqrange; 3538c2ecf20Sopenharmony_ci unsigned int csi0clkfreqrange; 3548c2ecf20Sopenharmony_ci unsigned int num_channels; 3558c2ecf20Sopenharmony_ci bool clear_ulps; 3568c2ecf20Sopenharmony_ci}; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistruct rcar_csi2 { 3598c2ecf20Sopenharmony_ci struct device *dev; 3608c2ecf20Sopenharmony_ci void __iomem *base; 3618c2ecf20Sopenharmony_ci const struct rcar_csi2_info *info; 3628c2ecf20Sopenharmony_ci struct reset_control *rstc; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci struct v4l2_subdev subdev; 3658c2ecf20Sopenharmony_ci struct media_pad pads[NR_OF_RCAR_CSI2_PAD]; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci struct v4l2_async_notifier notifier; 3688c2ecf20Sopenharmony_ci struct v4l2_subdev *remote; 3698c2ecf20Sopenharmony_ci unsigned int remote_pad; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt mf; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci struct mutex lock; 3748c2ecf20Sopenharmony_ci int stream_count; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci unsigned short lanes; 3778c2ecf20Sopenharmony_ci unsigned char lane_swap[4]; 3788c2ecf20Sopenharmony_ci}; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic inline struct rcar_csi2 *sd_to_csi2(struct v4l2_subdev *sd) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci return container_of(sd, struct rcar_csi2, subdev); 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic inline struct rcar_csi2 *notifier_to_csi2(struct v4l2_async_notifier *n) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci return container_of(n, struct rcar_csi2, notifier); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic u32 rcsi2_read(struct rcar_csi2 *priv, unsigned int reg) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci return ioread32(priv->base + reg); 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic void rcsi2_write(struct rcar_csi2 *priv, unsigned int reg, u32 data) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci iowrite32(data, priv->base + reg); 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic void rcsi2_enter_standby(struct rcar_csi2 *priv) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci rcsi2_write(priv, PHYCNT_REG, 0); 4038c2ecf20Sopenharmony_ci rcsi2_write(priv, PHTC_REG, PHTC_TESTCLR); 4048c2ecf20Sopenharmony_ci reset_control_assert(priv->rstc); 4058c2ecf20Sopenharmony_ci usleep_range(100, 150); 4068c2ecf20Sopenharmony_ci pm_runtime_put(priv->dev); 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic void rcsi2_exit_standby(struct rcar_csi2 *priv) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci pm_runtime_get_sync(priv->dev); 4128c2ecf20Sopenharmony_ci reset_control_deassert(priv->rstc); 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic int rcsi2_wait_phy_start(struct rcar_csi2 *priv, 4168c2ecf20Sopenharmony_ci unsigned int lanes) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci unsigned int timeout; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci /* Wait for the clock and data lanes to enter LP-11 state. */ 4218c2ecf20Sopenharmony_ci for (timeout = 0; timeout <= 20; timeout++) { 4228c2ecf20Sopenharmony_ci const u32 lane_mask = (1 << lanes) - 1; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci if ((rcsi2_read(priv, PHCLM_REG) & PHCLM_STOPSTATECKL) && 4258c2ecf20Sopenharmony_ci (rcsi2_read(priv, PHDLM_REG) & lane_mask) == lane_mask) 4268c2ecf20Sopenharmony_ci return 0; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci dev_err(priv->dev, "Timeout waiting for LP-11 state\n"); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci return -ETIMEDOUT; 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic int rcsi2_set_phypll(struct rcar_csi2 *priv, unsigned int mbps) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci const struct rcsi2_mbps_reg *hsfreq; 4398c2ecf20Sopenharmony_ci const struct rcsi2_mbps_reg *hsfreq_prev = NULL; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci for (hsfreq = priv->info->hsfreqrange; hsfreq->mbps != 0; hsfreq++) { 4428c2ecf20Sopenharmony_ci if (hsfreq->mbps >= mbps) 4438c2ecf20Sopenharmony_ci break; 4448c2ecf20Sopenharmony_ci hsfreq_prev = hsfreq; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (!hsfreq->mbps) { 4488c2ecf20Sopenharmony_ci dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps); 4498c2ecf20Sopenharmony_ci return -ERANGE; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (hsfreq_prev && 4538c2ecf20Sopenharmony_ci ((mbps - hsfreq_prev->mbps) <= (hsfreq->mbps - mbps))) 4548c2ecf20Sopenharmony_ci hsfreq = hsfreq_prev; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci rcsi2_write(priv, PHYPLL_REG, PHYPLL_HSFREQRANGE(hsfreq->reg)); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci return 0; 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp, 4628c2ecf20Sopenharmony_ci unsigned int lanes) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci struct v4l2_subdev *source; 4658c2ecf20Sopenharmony_ci struct v4l2_ctrl *ctrl; 4668c2ecf20Sopenharmony_ci u64 mbps; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci if (!priv->remote) 4698c2ecf20Sopenharmony_ci return -ENODEV; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci source = priv->remote; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci /* Read the pixel rate control from remote. */ 4748c2ecf20Sopenharmony_ci ctrl = v4l2_ctrl_find(source->ctrl_handler, V4L2_CID_PIXEL_RATE); 4758c2ecf20Sopenharmony_ci if (!ctrl) { 4768c2ecf20Sopenharmony_ci dev_err(priv->dev, "no pixel rate control in subdev %s\n", 4778c2ecf20Sopenharmony_ci source->name); 4788c2ecf20Sopenharmony_ci return -EINVAL; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci /* 4828c2ecf20Sopenharmony_ci * Calculate the phypll in mbps. 4838c2ecf20Sopenharmony_ci * link_freq = (pixel_rate * bits_per_sample) / (2 * nr_of_lanes) 4848c2ecf20Sopenharmony_ci * bps = link_freq * 2 4858c2ecf20Sopenharmony_ci */ 4868c2ecf20Sopenharmony_ci mbps = v4l2_ctrl_g_ctrl_int64(ctrl) * bpp; 4878c2ecf20Sopenharmony_ci do_div(mbps, lanes * 1000000); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci return mbps; 4908c2ecf20Sopenharmony_ci} 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_cistatic int rcsi2_get_active_lanes(struct rcar_csi2 *priv, 4938c2ecf20Sopenharmony_ci unsigned int *lanes) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci struct v4l2_mbus_config mbus_config = { 0 }; 4968c2ecf20Sopenharmony_ci unsigned int num_lanes = UINT_MAX; 4978c2ecf20Sopenharmony_ci int ret; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci *lanes = priv->lanes; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci ret = v4l2_subdev_call(priv->remote, pad, get_mbus_config, 5028c2ecf20Sopenharmony_ci priv->remote_pad, &mbus_config); 5038c2ecf20Sopenharmony_ci if (ret == -ENOIOCTLCMD) { 5048c2ecf20Sopenharmony_ci dev_dbg(priv->dev, "No remote mbus configuration available\n"); 5058c2ecf20Sopenharmony_ci return 0; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci if (ret) { 5098c2ecf20Sopenharmony_ci dev_err(priv->dev, "Failed to get remote mbus configuration\n"); 5108c2ecf20Sopenharmony_ci return ret; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (mbus_config.type != V4L2_MBUS_CSI2_DPHY) { 5148c2ecf20Sopenharmony_ci dev_err(priv->dev, "Unsupported media bus type %u\n", 5158c2ecf20Sopenharmony_ci mbus_config.type); 5168c2ecf20Sopenharmony_ci return -EINVAL; 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (mbus_config.flags & V4L2_MBUS_CSI2_1_LANE) 5208c2ecf20Sopenharmony_ci num_lanes = 1; 5218c2ecf20Sopenharmony_ci else if (mbus_config.flags & V4L2_MBUS_CSI2_2_LANE) 5228c2ecf20Sopenharmony_ci num_lanes = 2; 5238c2ecf20Sopenharmony_ci else if (mbus_config.flags & V4L2_MBUS_CSI2_3_LANE) 5248c2ecf20Sopenharmony_ci num_lanes = 3; 5258c2ecf20Sopenharmony_ci else if (mbus_config.flags & V4L2_MBUS_CSI2_4_LANE) 5268c2ecf20Sopenharmony_ci num_lanes = 4; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci if (num_lanes > priv->lanes) { 5298c2ecf20Sopenharmony_ci dev_err(priv->dev, 5308c2ecf20Sopenharmony_ci "Unsupported mbus config: too many data lanes %u\n", 5318c2ecf20Sopenharmony_ci num_lanes); 5328c2ecf20Sopenharmony_ci return -EINVAL; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci *lanes = num_lanes; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci return 0; 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic int rcsi2_start_receiver(struct rcar_csi2 *priv) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci const struct rcar_csi2_format *format; 5438c2ecf20Sopenharmony_ci u32 phycnt, vcdt = 0, vcdt2 = 0, fld = 0; 5448c2ecf20Sopenharmony_ci unsigned int lanes; 5458c2ecf20Sopenharmony_ci unsigned int i; 5468c2ecf20Sopenharmony_ci int mbps, ret; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci dev_dbg(priv->dev, "Input size (%ux%u%c)\n", 5498c2ecf20Sopenharmony_ci priv->mf.width, priv->mf.height, 5508c2ecf20Sopenharmony_ci priv->mf.field == V4L2_FIELD_NONE ? 'p' : 'i'); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci /* Code is validated in set_fmt. */ 5538c2ecf20Sopenharmony_ci format = rcsi2_code_to_fmt(priv->mf.code); 5548c2ecf20Sopenharmony_ci if (!format) 5558c2ecf20Sopenharmony_ci return -EINVAL; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* 5588c2ecf20Sopenharmony_ci * Enable all supported CSI-2 channels with virtual channel and 5598c2ecf20Sopenharmony_ci * data type matching. 5608c2ecf20Sopenharmony_ci * 5618c2ecf20Sopenharmony_ci * NOTE: It's not possible to get individual datatype for each 5628c2ecf20Sopenharmony_ci * source virtual channel. Once this is possible in V4L2 5638c2ecf20Sopenharmony_ci * it should be used here. 5648c2ecf20Sopenharmony_ci */ 5658c2ecf20Sopenharmony_ci for (i = 0; i < priv->info->num_channels; i++) { 5668c2ecf20Sopenharmony_ci u32 vcdt_part; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci vcdt_part = VCDT_SEL_VC(i) | VCDT_VCDTN_EN | VCDT_SEL_DTN_ON | 5698c2ecf20Sopenharmony_ci VCDT_SEL_DT(format->datatype); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci /* Store in correct reg and offset. */ 5728c2ecf20Sopenharmony_ci if (i < 2) 5738c2ecf20Sopenharmony_ci vcdt |= vcdt_part << ((i % 2) * 16); 5748c2ecf20Sopenharmony_ci else 5758c2ecf20Sopenharmony_ci vcdt2 |= vcdt_part << ((i % 2) * 16); 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci if (priv->mf.field == V4L2_FIELD_ALTERNATE) { 5798c2ecf20Sopenharmony_ci fld = FLD_DET_SEL(1) | FLD_FLD_EN4 | FLD_FLD_EN3 | FLD_FLD_EN2 5808c2ecf20Sopenharmony_ci | FLD_FLD_EN; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci if (priv->mf.height == 240) 5838c2ecf20Sopenharmony_ci fld |= FLD_FLD_NUM(0); 5848c2ecf20Sopenharmony_ci else 5858c2ecf20Sopenharmony_ci fld |= FLD_FLD_NUM(1); 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci /* 5898c2ecf20Sopenharmony_ci * Get the number of active data lanes inspecting the remote mbus 5908c2ecf20Sopenharmony_ci * configuration. 5918c2ecf20Sopenharmony_ci */ 5928c2ecf20Sopenharmony_ci ret = rcsi2_get_active_lanes(priv, &lanes); 5938c2ecf20Sopenharmony_ci if (ret) 5948c2ecf20Sopenharmony_ci return ret; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci phycnt = PHYCNT_ENABLECLK; 5978c2ecf20Sopenharmony_ci phycnt |= (1 << lanes) - 1; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci mbps = rcsi2_calc_mbps(priv, format->bpp, lanes); 6008c2ecf20Sopenharmony_ci if (mbps < 0) 6018c2ecf20Sopenharmony_ci return mbps; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci /* Enable interrupts. */ 6048c2ecf20Sopenharmony_ci rcsi2_write(priv, INTEN_REG, INTEN_INT_AFIFO_OF | INTEN_INT_ERRSOTHS 6058c2ecf20Sopenharmony_ci | INTEN_INT_ERRSOTSYNCHS); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci /* Init */ 6088c2ecf20Sopenharmony_ci rcsi2_write(priv, TREF_REG, TREF_TREF); 6098c2ecf20Sopenharmony_ci rcsi2_write(priv, PHTC_REG, 0); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci /* Configure */ 6128c2ecf20Sopenharmony_ci rcsi2_write(priv, VCDT_REG, vcdt); 6138c2ecf20Sopenharmony_ci if (vcdt2) 6148c2ecf20Sopenharmony_ci rcsi2_write(priv, VCDT2_REG, vcdt2); 6158c2ecf20Sopenharmony_ci /* Lanes are zero indexed. */ 6168c2ecf20Sopenharmony_ci rcsi2_write(priv, LSWAP_REG, 6178c2ecf20Sopenharmony_ci LSWAP_L0SEL(priv->lane_swap[0] - 1) | 6188c2ecf20Sopenharmony_ci LSWAP_L1SEL(priv->lane_swap[1] - 1) | 6198c2ecf20Sopenharmony_ci LSWAP_L2SEL(priv->lane_swap[2] - 1) | 6208c2ecf20Sopenharmony_ci LSWAP_L3SEL(priv->lane_swap[3] - 1)); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci /* Start */ 6238c2ecf20Sopenharmony_ci if (priv->info->init_phtw) { 6248c2ecf20Sopenharmony_ci ret = priv->info->init_phtw(priv, mbps); 6258c2ecf20Sopenharmony_ci if (ret) 6268c2ecf20Sopenharmony_ci return ret; 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (priv->info->hsfreqrange) { 6308c2ecf20Sopenharmony_ci ret = rcsi2_set_phypll(priv, mbps); 6318c2ecf20Sopenharmony_ci if (ret) 6328c2ecf20Sopenharmony_ci return ret; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci if (priv->info->csi0clkfreqrange) 6368c2ecf20Sopenharmony_ci rcsi2_write(priv, CSI0CLKFCPR_REG, 6378c2ecf20Sopenharmony_ci CSI0CLKFREQRANGE(priv->info->csi0clkfreqrange)); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci rcsi2_write(priv, PHYCNT_REG, phycnt); 6408c2ecf20Sopenharmony_ci rcsi2_write(priv, LINKCNT_REG, LINKCNT_MONITOR_EN | 6418c2ecf20Sopenharmony_ci LINKCNT_REG_MONI_PACT_EN | LINKCNT_ICLK_NONSTOP); 6428c2ecf20Sopenharmony_ci rcsi2_write(priv, FLD_REG, fld); 6438c2ecf20Sopenharmony_ci rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ); 6448c2ecf20Sopenharmony_ci rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ | PHYCNT_RSTZ); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci ret = rcsi2_wait_phy_start(priv, lanes); 6478c2ecf20Sopenharmony_ci if (ret) 6488c2ecf20Sopenharmony_ci return ret; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci /* Run post PHY start initialization, if needed. */ 6518c2ecf20Sopenharmony_ci if (priv->info->phy_post_init) { 6528c2ecf20Sopenharmony_ci ret = priv->info->phy_post_init(priv); 6538c2ecf20Sopenharmony_ci if (ret) 6548c2ecf20Sopenharmony_ci return ret; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci /* Clear Ultra Low Power interrupt. */ 6588c2ecf20Sopenharmony_ci if (priv->info->clear_ulps) 6598c2ecf20Sopenharmony_ci rcsi2_write(priv, INTSTATE_REG, 6608c2ecf20Sopenharmony_ci INTSTATE_INT_ULPS_START | 6618c2ecf20Sopenharmony_ci INTSTATE_INT_ULPS_END); 6628c2ecf20Sopenharmony_ci return 0; 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_cistatic int rcsi2_start(struct rcar_csi2 *priv) 6668c2ecf20Sopenharmony_ci{ 6678c2ecf20Sopenharmony_ci int ret; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci rcsi2_exit_standby(priv); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci ret = rcsi2_start_receiver(priv); 6728c2ecf20Sopenharmony_ci if (ret) { 6738c2ecf20Sopenharmony_ci rcsi2_enter_standby(priv); 6748c2ecf20Sopenharmony_ci return ret; 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci ret = v4l2_subdev_call(priv->remote, video, s_stream, 1); 6788c2ecf20Sopenharmony_ci if (ret) { 6798c2ecf20Sopenharmony_ci rcsi2_enter_standby(priv); 6808c2ecf20Sopenharmony_ci return ret; 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci return 0; 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_cistatic void rcsi2_stop(struct rcar_csi2 *priv) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci rcsi2_enter_standby(priv); 6898c2ecf20Sopenharmony_ci v4l2_subdev_call(priv->remote, video, s_stream, 0); 6908c2ecf20Sopenharmony_ci} 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_cistatic int rcsi2_s_stream(struct v4l2_subdev *sd, int enable) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci struct rcar_csi2 *priv = sd_to_csi2(sd); 6958c2ecf20Sopenharmony_ci int ret = 0; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci if (!priv->remote) { 7008c2ecf20Sopenharmony_ci ret = -ENODEV; 7018c2ecf20Sopenharmony_ci goto out; 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci if (enable && priv->stream_count == 0) { 7058c2ecf20Sopenharmony_ci ret = rcsi2_start(priv); 7068c2ecf20Sopenharmony_ci if (ret) 7078c2ecf20Sopenharmony_ci goto out; 7088c2ecf20Sopenharmony_ci } else if (!enable && priv->stream_count == 1) { 7098c2ecf20Sopenharmony_ci rcsi2_stop(priv); 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci priv->stream_count += enable ? 1 : -1; 7138c2ecf20Sopenharmony_ciout: 7148c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci return ret; 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_cistatic int rcsi2_set_pad_format(struct v4l2_subdev *sd, 7208c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 7218c2ecf20Sopenharmony_ci struct v4l2_subdev_format *format) 7228c2ecf20Sopenharmony_ci{ 7238c2ecf20Sopenharmony_ci struct rcar_csi2 *priv = sd_to_csi2(sd); 7248c2ecf20Sopenharmony_ci struct v4l2_mbus_framefmt *framefmt; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci if (!rcsi2_code_to_fmt(format->format.code)) 7278c2ecf20Sopenharmony_ci format->format.code = rcar_csi2_formats[0].code; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { 7308c2ecf20Sopenharmony_ci priv->mf = format->format; 7318c2ecf20Sopenharmony_ci } else { 7328c2ecf20Sopenharmony_ci framefmt = v4l2_subdev_get_try_format(sd, cfg, 0); 7338c2ecf20Sopenharmony_ci *framefmt = format->format; 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci return 0; 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cistatic int rcsi2_get_pad_format(struct v4l2_subdev *sd, 7408c2ecf20Sopenharmony_ci struct v4l2_subdev_pad_config *cfg, 7418c2ecf20Sopenharmony_ci struct v4l2_subdev_format *format) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci struct rcar_csi2 *priv = sd_to_csi2(sd); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) 7468c2ecf20Sopenharmony_ci format->format = priv->mf; 7478c2ecf20Sopenharmony_ci else 7488c2ecf20Sopenharmony_ci format->format = *v4l2_subdev_get_try_format(sd, cfg, 0); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci return 0; 7518c2ecf20Sopenharmony_ci} 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_video_ops rcar_csi2_video_ops = { 7548c2ecf20Sopenharmony_ci .s_stream = rcsi2_s_stream, 7558c2ecf20Sopenharmony_ci}; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_pad_ops rcar_csi2_pad_ops = { 7588c2ecf20Sopenharmony_ci .set_fmt = rcsi2_set_pad_format, 7598c2ecf20Sopenharmony_ci .get_fmt = rcsi2_get_pad_format, 7608c2ecf20Sopenharmony_ci}; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops rcar_csi2_subdev_ops = { 7638c2ecf20Sopenharmony_ci .video = &rcar_csi2_video_ops, 7648c2ecf20Sopenharmony_ci .pad = &rcar_csi2_pad_ops, 7658c2ecf20Sopenharmony_ci}; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_cistatic irqreturn_t rcsi2_irq(int irq, void *data) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci struct rcar_csi2 *priv = data; 7708c2ecf20Sopenharmony_ci u32 status, err_status; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci status = rcsi2_read(priv, INTSTATE_REG); 7738c2ecf20Sopenharmony_ci err_status = rcsi2_read(priv, INTERRSTATE_REG); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (!status) 7768c2ecf20Sopenharmony_ci return IRQ_HANDLED; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci rcsi2_write(priv, INTSTATE_REG, status); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci if (!err_status) 7818c2ecf20Sopenharmony_ci return IRQ_HANDLED; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci rcsi2_write(priv, INTERRSTATE_REG, err_status); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci dev_info(priv->dev, "Transfer error, restarting CSI-2 receiver\n"); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci return IRQ_WAKE_THREAD; 7888c2ecf20Sopenharmony_ci} 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_cistatic irqreturn_t rcsi2_irq_thread(int irq, void *data) 7918c2ecf20Sopenharmony_ci{ 7928c2ecf20Sopenharmony_ci struct rcar_csi2 *priv = data; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 7958c2ecf20Sopenharmony_ci rcsi2_stop(priv); 7968c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 7978c2ecf20Sopenharmony_ci if (rcsi2_start(priv)) 7988c2ecf20Sopenharmony_ci dev_warn(priv->dev, "Failed to restart CSI-2 receiver\n"); 7998c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci return IRQ_HANDLED; 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 8058c2ecf20Sopenharmony_ci * Async handling and registration of subdevices and links. 8068c2ecf20Sopenharmony_ci */ 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_cistatic int rcsi2_notify_bound(struct v4l2_async_notifier *notifier, 8098c2ecf20Sopenharmony_ci struct v4l2_subdev *subdev, 8108c2ecf20Sopenharmony_ci struct v4l2_async_subdev *asd) 8118c2ecf20Sopenharmony_ci{ 8128c2ecf20Sopenharmony_ci struct rcar_csi2 *priv = notifier_to_csi2(notifier); 8138c2ecf20Sopenharmony_ci int pad; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci pad = media_entity_get_fwnode_pad(&subdev->entity, asd->match.fwnode, 8168c2ecf20Sopenharmony_ci MEDIA_PAD_FL_SOURCE); 8178c2ecf20Sopenharmony_ci if (pad < 0) { 8188c2ecf20Sopenharmony_ci dev_err(priv->dev, "Failed to find pad for %s\n", subdev->name); 8198c2ecf20Sopenharmony_ci return pad; 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci priv->remote = subdev; 8238c2ecf20Sopenharmony_ci priv->remote_pad = pad; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci dev_dbg(priv->dev, "Bound %s pad: %d\n", subdev->name, pad); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci return media_create_pad_link(&subdev->entity, pad, 8288c2ecf20Sopenharmony_ci &priv->subdev.entity, 0, 8298c2ecf20Sopenharmony_ci MEDIA_LNK_FL_ENABLED | 8308c2ecf20Sopenharmony_ci MEDIA_LNK_FL_IMMUTABLE); 8318c2ecf20Sopenharmony_ci} 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_cistatic void rcsi2_notify_unbind(struct v4l2_async_notifier *notifier, 8348c2ecf20Sopenharmony_ci struct v4l2_subdev *subdev, 8358c2ecf20Sopenharmony_ci struct v4l2_async_subdev *asd) 8368c2ecf20Sopenharmony_ci{ 8378c2ecf20Sopenharmony_ci struct rcar_csi2 *priv = notifier_to_csi2(notifier); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci priv->remote = NULL; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci dev_dbg(priv->dev, "Unbind %s\n", subdev->name); 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_cistatic const struct v4l2_async_notifier_operations rcar_csi2_notify_ops = { 8458c2ecf20Sopenharmony_ci .bound = rcsi2_notify_bound, 8468c2ecf20Sopenharmony_ci .unbind = rcsi2_notify_unbind, 8478c2ecf20Sopenharmony_ci}; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_cistatic int rcsi2_parse_v4l2(struct rcar_csi2 *priv, 8508c2ecf20Sopenharmony_ci struct v4l2_fwnode_endpoint *vep) 8518c2ecf20Sopenharmony_ci{ 8528c2ecf20Sopenharmony_ci unsigned int i; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci /* Only port 0 endpoint 0 is valid. */ 8558c2ecf20Sopenharmony_ci if (vep->base.port || vep->base.id) 8568c2ecf20Sopenharmony_ci return -ENOTCONN; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci if (vep->bus_type != V4L2_MBUS_CSI2_DPHY) { 8598c2ecf20Sopenharmony_ci dev_err(priv->dev, "Unsupported bus: %u\n", vep->bus_type); 8608c2ecf20Sopenharmony_ci return -EINVAL; 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci priv->lanes = vep->bus.mipi_csi2.num_data_lanes; 8648c2ecf20Sopenharmony_ci if (priv->lanes != 1 && priv->lanes != 2 && priv->lanes != 4) { 8658c2ecf20Sopenharmony_ci dev_err(priv->dev, "Unsupported number of data-lanes: %u\n", 8668c2ecf20Sopenharmony_ci priv->lanes); 8678c2ecf20Sopenharmony_ci return -EINVAL; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(priv->lane_swap); i++) { 8718c2ecf20Sopenharmony_ci priv->lane_swap[i] = i < priv->lanes ? 8728c2ecf20Sopenharmony_ci vep->bus.mipi_csi2.data_lanes[i] : i; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci /* Check for valid lane number. */ 8758c2ecf20Sopenharmony_ci if (priv->lane_swap[i] < 1 || priv->lane_swap[i] > 4) { 8768c2ecf20Sopenharmony_ci dev_err(priv->dev, "data-lanes must be in 1-4 range\n"); 8778c2ecf20Sopenharmony_ci return -EINVAL; 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci return 0; 8828c2ecf20Sopenharmony_ci} 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_cistatic int rcsi2_parse_dt(struct rcar_csi2 *priv) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci struct v4l2_async_subdev *asd; 8878c2ecf20Sopenharmony_ci struct fwnode_handle *fwnode; 8888c2ecf20Sopenharmony_ci struct device_node *ep; 8898c2ecf20Sopenharmony_ci struct v4l2_fwnode_endpoint v4l2_ep = { .bus_type = 0 }; 8908c2ecf20Sopenharmony_ci int ret; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci ep = of_graph_get_endpoint_by_regs(priv->dev->of_node, 0, 0); 8938c2ecf20Sopenharmony_ci if (!ep) { 8948c2ecf20Sopenharmony_ci dev_err(priv->dev, "Not connected to subdevice\n"); 8958c2ecf20Sopenharmony_ci return -EINVAL; 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &v4l2_ep); 8998c2ecf20Sopenharmony_ci if (ret) { 9008c2ecf20Sopenharmony_ci dev_err(priv->dev, "Could not parse v4l2 endpoint\n"); 9018c2ecf20Sopenharmony_ci of_node_put(ep); 9028c2ecf20Sopenharmony_ci return -EINVAL; 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci ret = rcsi2_parse_v4l2(priv, &v4l2_ep); 9068c2ecf20Sopenharmony_ci if (ret) { 9078c2ecf20Sopenharmony_ci of_node_put(ep); 9088c2ecf20Sopenharmony_ci return ret; 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci fwnode = fwnode_graph_get_remote_endpoint(of_fwnode_handle(ep)); 9128c2ecf20Sopenharmony_ci of_node_put(ep); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci dev_dbg(priv->dev, "Found '%pOF'\n", to_of_node(fwnode)); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci v4l2_async_notifier_init(&priv->notifier); 9178c2ecf20Sopenharmony_ci priv->notifier.ops = &rcar_csi2_notify_ops; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci asd = v4l2_async_notifier_add_fwnode_subdev(&priv->notifier, fwnode, 9208c2ecf20Sopenharmony_ci sizeof(*asd)); 9218c2ecf20Sopenharmony_ci fwnode_handle_put(fwnode); 9228c2ecf20Sopenharmony_ci if (IS_ERR(asd)) 9238c2ecf20Sopenharmony_ci return PTR_ERR(asd); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci ret = v4l2_async_subdev_notifier_register(&priv->subdev, 9268c2ecf20Sopenharmony_ci &priv->notifier); 9278c2ecf20Sopenharmony_ci if (ret) 9288c2ecf20Sopenharmony_ci v4l2_async_notifier_cleanup(&priv->notifier); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci return ret; 9318c2ecf20Sopenharmony_ci} 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 9348c2ecf20Sopenharmony_ci * PHTW initialization sequences. 9358c2ecf20Sopenharmony_ci * 9368c2ecf20Sopenharmony_ci * NOTE: Magic values are from the datasheet and lack documentation. 9378c2ecf20Sopenharmony_ci */ 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_cistatic int rcsi2_phtw_write(struct rcar_csi2 *priv, u16 data, u16 code) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci unsigned int timeout; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci rcsi2_write(priv, PHTW_REG, 9448c2ecf20Sopenharmony_ci PHTW_DWEN | PHTW_TESTDIN_DATA(data) | 9458c2ecf20Sopenharmony_ci PHTW_CWEN | PHTW_TESTDIN_CODE(code)); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci /* Wait for DWEN and CWEN to be cleared by hardware. */ 9488c2ecf20Sopenharmony_ci for (timeout = 0; timeout <= 20; timeout++) { 9498c2ecf20Sopenharmony_ci if (!(rcsi2_read(priv, PHTW_REG) & (PHTW_DWEN | PHTW_CWEN))) 9508c2ecf20Sopenharmony_ci return 0; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 9538c2ecf20Sopenharmony_ci } 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci dev_err(priv->dev, "Timeout waiting for PHTW_DWEN and/or PHTW_CWEN\n"); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci return -ETIMEDOUT; 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_cistatic int rcsi2_phtw_write_array(struct rcar_csi2 *priv, 9618c2ecf20Sopenharmony_ci const struct phtw_value *values) 9628c2ecf20Sopenharmony_ci{ 9638c2ecf20Sopenharmony_ci const struct phtw_value *value; 9648c2ecf20Sopenharmony_ci int ret; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci for (value = values; value->data || value->code; value++) { 9678c2ecf20Sopenharmony_ci ret = rcsi2_phtw_write(priv, value->data, value->code); 9688c2ecf20Sopenharmony_ci if (ret) 9698c2ecf20Sopenharmony_ci return ret; 9708c2ecf20Sopenharmony_ci } 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci return 0; 9738c2ecf20Sopenharmony_ci} 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_cistatic int rcsi2_phtw_write_mbps(struct rcar_csi2 *priv, unsigned int mbps, 9768c2ecf20Sopenharmony_ci const struct rcsi2_mbps_reg *values, u16 code) 9778c2ecf20Sopenharmony_ci{ 9788c2ecf20Sopenharmony_ci const struct rcsi2_mbps_reg *value; 9798c2ecf20Sopenharmony_ci const struct rcsi2_mbps_reg *prev_value = NULL; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci for (value = values; value->mbps; value++) { 9828c2ecf20Sopenharmony_ci if (value->mbps >= mbps) 9838c2ecf20Sopenharmony_ci break; 9848c2ecf20Sopenharmony_ci prev_value = value; 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci if (prev_value && 9888c2ecf20Sopenharmony_ci ((mbps - prev_value->mbps) <= (value->mbps - mbps))) 9898c2ecf20Sopenharmony_ci value = prev_value; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci if (!value->mbps) { 9928c2ecf20Sopenharmony_ci dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps); 9938c2ecf20Sopenharmony_ci return -ERANGE; 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci return rcsi2_phtw_write(priv, value->reg, code); 9978c2ecf20Sopenharmony_ci} 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_cistatic int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, 10008c2ecf20Sopenharmony_ci unsigned int mbps) 10018c2ecf20Sopenharmony_ci{ 10028c2ecf20Sopenharmony_ci static const struct phtw_value step1[] = { 10038c2ecf20Sopenharmony_ci { .data = 0xcc, .code = 0xe2 }, 10048c2ecf20Sopenharmony_ci { .data = 0x01, .code = 0xe3 }, 10058c2ecf20Sopenharmony_ci { .data = 0x11, .code = 0xe4 }, 10068c2ecf20Sopenharmony_ci { .data = 0x01, .code = 0xe5 }, 10078c2ecf20Sopenharmony_ci { .data = 0x10, .code = 0x04 }, 10088c2ecf20Sopenharmony_ci { /* sentinel */ }, 10098c2ecf20Sopenharmony_ci }; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci static const struct phtw_value step2[] = { 10128c2ecf20Sopenharmony_ci { .data = 0x38, .code = 0x08 }, 10138c2ecf20Sopenharmony_ci { .data = 0x01, .code = 0x00 }, 10148c2ecf20Sopenharmony_ci { .data = 0x4b, .code = 0xac }, 10158c2ecf20Sopenharmony_ci { .data = 0x03, .code = 0x00 }, 10168c2ecf20Sopenharmony_ci { .data = 0x80, .code = 0x07 }, 10178c2ecf20Sopenharmony_ci { /* sentinel */ }, 10188c2ecf20Sopenharmony_ci }; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci int ret; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci ret = rcsi2_phtw_write_array(priv, step1); 10238c2ecf20Sopenharmony_ci if (ret) 10248c2ecf20Sopenharmony_ci return ret; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci if (mbps != 0 && mbps <= 250) { 10278c2ecf20Sopenharmony_ci ret = rcsi2_phtw_write(priv, 0x39, 0x05); 10288c2ecf20Sopenharmony_ci if (ret) 10298c2ecf20Sopenharmony_ci return ret; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci ret = rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_h3_v3h_m3n, 10328c2ecf20Sopenharmony_ci 0xf1); 10338c2ecf20Sopenharmony_ci if (ret) 10348c2ecf20Sopenharmony_ci return ret; 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci return rcsi2_phtw_write_array(priv, step2); 10388c2ecf20Sopenharmony_ci} 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_cistatic int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps) 10418c2ecf20Sopenharmony_ci{ 10428c2ecf20Sopenharmony_ci return __rcsi2_init_phtw_h3_v3h_m3n(priv, mbps); 10438c2ecf20Sopenharmony_ci} 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_cistatic int rcsi2_init_phtw_h3es2(struct rcar_csi2 *priv, unsigned int mbps) 10468c2ecf20Sopenharmony_ci{ 10478c2ecf20Sopenharmony_ci return __rcsi2_init_phtw_h3_v3h_m3n(priv, 0); 10488c2ecf20Sopenharmony_ci} 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_cistatic int rcsi2_init_phtw_v3m_e3(struct rcar_csi2 *priv, unsigned int mbps) 10518c2ecf20Sopenharmony_ci{ 10528c2ecf20Sopenharmony_ci return rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_v3m_e3, 0x44); 10538c2ecf20Sopenharmony_ci} 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_cistatic int rcsi2_phy_post_init_v3m_e3(struct rcar_csi2 *priv) 10568c2ecf20Sopenharmony_ci{ 10578c2ecf20Sopenharmony_ci static const struct phtw_value step1[] = { 10588c2ecf20Sopenharmony_ci { .data = 0xee, .code = 0x34 }, 10598c2ecf20Sopenharmony_ci { .data = 0xee, .code = 0x44 }, 10608c2ecf20Sopenharmony_ci { .data = 0xee, .code = 0x54 }, 10618c2ecf20Sopenharmony_ci { .data = 0xee, .code = 0x84 }, 10628c2ecf20Sopenharmony_ci { .data = 0xee, .code = 0x94 }, 10638c2ecf20Sopenharmony_ci { /* sentinel */ }, 10648c2ecf20Sopenharmony_ci }; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci return rcsi2_phtw_write_array(priv, step1); 10678c2ecf20Sopenharmony_ci} 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci/* ----------------------------------------------------------------------------- 10708c2ecf20Sopenharmony_ci * Platform Device Driver. 10718c2ecf20Sopenharmony_ci */ 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_cistatic const struct media_entity_operations rcar_csi2_entity_ops = { 10748c2ecf20Sopenharmony_ci .link_validate = v4l2_subdev_link_validate, 10758c2ecf20Sopenharmony_ci}; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_cistatic int rcsi2_probe_resources(struct rcar_csi2 *priv, 10788c2ecf20Sopenharmony_ci struct platform_device *pdev) 10798c2ecf20Sopenharmony_ci{ 10808c2ecf20Sopenharmony_ci struct resource *res; 10818c2ecf20Sopenharmony_ci int irq, ret; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 10848c2ecf20Sopenharmony_ci priv->base = devm_ioremap_resource(&pdev->dev, res); 10858c2ecf20Sopenharmony_ci if (IS_ERR(priv->base)) 10868c2ecf20Sopenharmony_ci return PTR_ERR(priv->base); 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 10898c2ecf20Sopenharmony_ci if (irq < 0) 10908c2ecf20Sopenharmony_ci return irq; 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci ret = devm_request_threaded_irq(&pdev->dev, irq, rcsi2_irq, 10938c2ecf20Sopenharmony_ci rcsi2_irq_thread, IRQF_SHARED, 10948c2ecf20Sopenharmony_ci KBUILD_MODNAME, priv); 10958c2ecf20Sopenharmony_ci if (ret) 10968c2ecf20Sopenharmony_ci return ret; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci priv->rstc = devm_reset_control_get(&pdev->dev, NULL); 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(priv->rstc); 11018c2ecf20Sopenharmony_ci} 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_cistatic const struct rcar_csi2_info rcar_csi2_info_r8a7795 = { 11048c2ecf20Sopenharmony_ci .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, 11058c2ecf20Sopenharmony_ci .hsfreqrange = hsfreqrange_h3_v3h_m3n, 11068c2ecf20Sopenharmony_ci .csi0clkfreqrange = 0x20, 11078c2ecf20Sopenharmony_ci .num_channels = 4, 11088c2ecf20Sopenharmony_ci .clear_ulps = true, 11098c2ecf20Sopenharmony_ci}; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_cistatic const struct rcar_csi2_info rcar_csi2_info_r8a7795es1 = { 11128c2ecf20Sopenharmony_ci .hsfreqrange = hsfreqrange_m3w_h3es1, 11138c2ecf20Sopenharmony_ci .num_channels = 4, 11148c2ecf20Sopenharmony_ci}; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_cistatic const struct rcar_csi2_info rcar_csi2_info_r8a7795es2 = { 11178c2ecf20Sopenharmony_ci .init_phtw = rcsi2_init_phtw_h3es2, 11188c2ecf20Sopenharmony_ci .hsfreqrange = hsfreqrange_h3_v3h_m3n, 11198c2ecf20Sopenharmony_ci .csi0clkfreqrange = 0x20, 11208c2ecf20Sopenharmony_ci .num_channels = 4, 11218c2ecf20Sopenharmony_ci .clear_ulps = true, 11228c2ecf20Sopenharmony_ci}; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_cistatic const struct rcar_csi2_info rcar_csi2_info_r8a7796 = { 11258c2ecf20Sopenharmony_ci .hsfreqrange = hsfreqrange_m3w_h3es1, 11268c2ecf20Sopenharmony_ci .num_channels = 4, 11278c2ecf20Sopenharmony_ci}; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_cistatic const struct rcar_csi2_info rcar_csi2_info_r8a77965 = { 11308c2ecf20Sopenharmony_ci .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, 11318c2ecf20Sopenharmony_ci .hsfreqrange = hsfreqrange_h3_v3h_m3n, 11328c2ecf20Sopenharmony_ci .csi0clkfreqrange = 0x20, 11338c2ecf20Sopenharmony_ci .num_channels = 4, 11348c2ecf20Sopenharmony_ci .clear_ulps = true, 11358c2ecf20Sopenharmony_ci}; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_cistatic const struct rcar_csi2_info rcar_csi2_info_r8a77970 = { 11388c2ecf20Sopenharmony_ci .init_phtw = rcsi2_init_phtw_v3m_e3, 11398c2ecf20Sopenharmony_ci .phy_post_init = rcsi2_phy_post_init_v3m_e3, 11408c2ecf20Sopenharmony_ci .num_channels = 4, 11418c2ecf20Sopenharmony_ci}; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_cistatic const struct rcar_csi2_info rcar_csi2_info_r8a77980 = { 11448c2ecf20Sopenharmony_ci .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, 11458c2ecf20Sopenharmony_ci .hsfreqrange = hsfreqrange_h3_v3h_m3n, 11468c2ecf20Sopenharmony_ci .csi0clkfreqrange = 0x20, 11478c2ecf20Sopenharmony_ci .clear_ulps = true, 11488c2ecf20Sopenharmony_ci}; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_cistatic const struct rcar_csi2_info rcar_csi2_info_r8a77990 = { 11518c2ecf20Sopenharmony_ci .init_phtw = rcsi2_init_phtw_v3m_e3, 11528c2ecf20Sopenharmony_ci .phy_post_init = rcsi2_phy_post_init_v3m_e3, 11538c2ecf20Sopenharmony_ci .num_channels = 2, 11548c2ecf20Sopenharmony_ci}; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_cistatic const struct of_device_id rcar_csi2_of_table[] = { 11578c2ecf20Sopenharmony_ci { 11588c2ecf20Sopenharmony_ci .compatible = "renesas,r8a774a1-csi2", 11598c2ecf20Sopenharmony_ci .data = &rcar_csi2_info_r8a7796, 11608c2ecf20Sopenharmony_ci }, 11618c2ecf20Sopenharmony_ci { 11628c2ecf20Sopenharmony_ci .compatible = "renesas,r8a774b1-csi2", 11638c2ecf20Sopenharmony_ci .data = &rcar_csi2_info_r8a77965, 11648c2ecf20Sopenharmony_ci }, 11658c2ecf20Sopenharmony_ci { 11668c2ecf20Sopenharmony_ci .compatible = "renesas,r8a774c0-csi2", 11678c2ecf20Sopenharmony_ci .data = &rcar_csi2_info_r8a77990, 11688c2ecf20Sopenharmony_ci }, 11698c2ecf20Sopenharmony_ci { 11708c2ecf20Sopenharmony_ci .compatible = "renesas,r8a774e1-csi2", 11718c2ecf20Sopenharmony_ci .data = &rcar_csi2_info_r8a7795, 11728c2ecf20Sopenharmony_ci }, 11738c2ecf20Sopenharmony_ci { 11748c2ecf20Sopenharmony_ci .compatible = "renesas,r8a7795-csi2", 11758c2ecf20Sopenharmony_ci .data = &rcar_csi2_info_r8a7795, 11768c2ecf20Sopenharmony_ci }, 11778c2ecf20Sopenharmony_ci { 11788c2ecf20Sopenharmony_ci .compatible = "renesas,r8a7796-csi2", 11798c2ecf20Sopenharmony_ci .data = &rcar_csi2_info_r8a7796, 11808c2ecf20Sopenharmony_ci }, 11818c2ecf20Sopenharmony_ci { 11828c2ecf20Sopenharmony_ci .compatible = "renesas,r8a77965-csi2", 11838c2ecf20Sopenharmony_ci .data = &rcar_csi2_info_r8a77965, 11848c2ecf20Sopenharmony_ci }, 11858c2ecf20Sopenharmony_ci { 11868c2ecf20Sopenharmony_ci .compatible = "renesas,r8a77970-csi2", 11878c2ecf20Sopenharmony_ci .data = &rcar_csi2_info_r8a77970, 11888c2ecf20Sopenharmony_ci }, 11898c2ecf20Sopenharmony_ci { 11908c2ecf20Sopenharmony_ci .compatible = "renesas,r8a77980-csi2", 11918c2ecf20Sopenharmony_ci .data = &rcar_csi2_info_r8a77980, 11928c2ecf20Sopenharmony_ci }, 11938c2ecf20Sopenharmony_ci { 11948c2ecf20Sopenharmony_ci .compatible = "renesas,r8a77990-csi2", 11958c2ecf20Sopenharmony_ci .data = &rcar_csi2_info_r8a77990, 11968c2ecf20Sopenharmony_ci }, 11978c2ecf20Sopenharmony_ci { /* sentinel */ }, 11988c2ecf20Sopenharmony_ci}; 11998c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, rcar_csi2_of_table); 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_cistatic const struct soc_device_attribute r8a7795[] = { 12028c2ecf20Sopenharmony_ci { 12038c2ecf20Sopenharmony_ci .soc_id = "r8a7795", .revision = "ES1.*", 12048c2ecf20Sopenharmony_ci .data = &rcar_csi2_info_r8a7795es1, 12058c2ecf20Sopenharmony_ci }, 12068c2ecf20Sopenharmony_ci { 12078c2ecf20Sopenharmony_ci .soc_id = "r8a7795", .revision = "ES2.*", 12088c2ecf20Sopenharmony_ci .data = &rcar_csi2_info_r8a7795es2, 12098c2ecf20Sopenharmony_ci }, 12108c2ecf20Sopenharmony_ci { /* sentinel */ }, 12118c2ecf20Sopenharmony_ci}; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_cistatic int rcsi2_probe(struct platform_device *pdev) 12148c2ecf20Sopenharmony_ci{ 12158c2ecf20Sopenharmony_ci const struct soc_device_attribute *attr; 12168c2ecf20Sopenharmony_ci struct rcar_csi2 *priv; 12178c2ecf20Sopenharmony_ci unsigned int i; 12188c2ecf20Sopenharmony_ci int ret; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 12218c2ecf20Sopenharmony_ci if (!priv) 12228c2ecf20Sopenharmony_ci return -ENOMEM; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci priv->info = of_device_get_match_data(&pdev->dev); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci /* 12278c2ecf20Sopenharmony_ci * The different ES versions of r8a7795 (H3) behave differently but 12288c2ecf20Sopenharmony_ci * share the same compatible string. 12298c2ecf20Sopenharmony_ci */ 12308c2ecf20Sopenharmony_ci attr = soc_device_match(r8a7795); 12318c2ecf20Sopenharmony_ci if (attr) 12328c2ecf20Sopenharmony_ci priv->info = attr->data; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci priv->dev = &pdev->dev; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci mutex_init(&priv->lock); 12378c2ecf20Sopenharmony_ci priv->stream_count = 0; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci ret = rcsi2_probe_resources(priv, pdev); 12408c2ecf20Sopenharmony_ci if (ret) { 12418c2ecf20Sopenharmony_ci dev_err(priv->dev, "Failed to get resources\n"); 12428c2ecf20Sopenharmony_ci return ret; 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, priv); 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci ret = rcsi2_parse_dt(priv); 12488c2ecf20Sopenharmony_ci if (ret) 12498c2ecf20Sopenharmony_ci return ret; 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci priv->subdev.owner = THIS_MODULE; 12528c2ecf20Sopenharmony_ci priv->subdev.dev = &pdev->dev; 12538c2ecf20Sopenharmony_ci v4l2_subdev_init(&priv->subdev, &rcar_csi2_subdev_ops); 12548c2ecf20Sopenharmony_ci v4l2_set_subdevdata(&priv->subdev, &pdev->dev); 12558c2ecf20Sopenharmony_ci snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s %s", 12568c2ecf20Sopenharmony_ci KBUILD_MODNAME, dev_name(&pdev->dev)); 12578c2ecf20Sopenharmony_ci priv->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci priv->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; 12608c2ecf20Sopenharmony_ci priv->subdev.entity.ops = &rcar_csi2_entity_ops; 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci priv->pads[RCAR_CSI2_SINK].flags = MEDIA_PAD_FL_SINK; 12638c2ecf20Sopenharmony_ci for (i = RCAR_CSI2_SOURCE_VC0; i < NR_OF_RCAR_CSI2_PAD; i++) 12648c2ecf20Sopenharmony_ci priv->pads[i].flags = MEDIA_PAD_FL_SOURCE; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci ret = media_entity_pads_init(&priv->subdev.entity, NR_OF_RCAR_CSI2_PAD, 12678c2ecf20Sopenharmony_ci priv->pads); 12688c2ecf20Sopenharmony_ci if (ret) 12698c2ecf20Sopenharmony_ci goto error; 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci pm_runtime_enable(&pdev->dev); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci ret = v4l2_async_register_subdev(&priv->subdev); 12748c2ecf20Sopenharmony_ci if (ret < 0) 12758c2ecf20Sopenharmony_ci goto error; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci dev_info(priv->dev, "%d lanes found\n", priv->lanes); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci return 0; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_cierror: 12828c2ecf20Sopenharmony_ci v4l2_async_notifier_unregister(&priv->notifier); 12838c2ecf20Sopenharmony_ci v4l2_async_notifier_cleanup(&priv->notifier); 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci return ret; 12868c2ecf20Sopenharmony_ci} 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_cistatic int rcsi2_remove(struct platform_device *pdev) 12898c2ecf20Sopenharmony_ci{ 12908c2ecf20Sopenharmony_ci struct rcar_csi2 *priv = platform_get_drvdata(pdev); 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci v4l2_async_notifier_unregister(&priv->notifier); 12938c2ecf20Sopenharmony_ci v4l2_async_notifier_cleanup(&priv->notifier); 12948c2ecf20Sopenharmony_ci v4l2_async_unregister_subdev(&priv->subdev); 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci return 0; 12998c2ecf20Sopenharmony_ci} 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_cistatic struct platform_driver rcar_csi2_pdrv = { 13028c2ecf20Sopenharmony_ci .remove = rcsi2_remove, 13038c2ecf20Sopenharmony_ci .probe = rcsi2_probe, 13048c2ecf20Sopenharmony_ci .driver = { 13058c2ecf20Sopenharmony_ci .name = "rcar-csi2", 13068c2ecf20Sopenharmony_ci .of_match_table = rcar_csi2_of_table, 13078c2ecf20Sopenharmony_ci }, 13088c2ecf20Sopenharmony_ci}; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_cimodule_platform_driver(rcar_csi2_pdrv); 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ciMODULE_AUTHOR("Niklas Söderlund <niklas.soderlund@ragnatech.se>"); 13138c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Renesas R-Car MIPI CSI-2 receiver driver"); 13148c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1315