1afe267f2STomi Valkeinen // SPDX-License-Identifier: GPL-2.0 2afe267f2STomi Valkeinen /* 3afe267f2STomi Valkeinen * Driver for the Texas Instruments DS90UB960-Q1 video deserializer 4afe267f2STomi Valkeinen * 5afe267f2STomi Valkeinen * Copyright (c) 2019 Luca Ceresoli <luca@lucaceresoli.net> 6afe267f2STomi Valkeinen * Copyright (c) 2023 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> 7afe267f2STomi Valkeinen */ 8afe267f2STomi Valkeinen 9afe267f2STomi Valkeinen /* 10afe267f2STomi Valkeinen * (Possible) TODOs: 11afe267f2STomi Valkeinen * 12afe267f2STomi Valkeinen * - PM for serializer and remote peripherals. We need to manage: 13afe267f2STomi Valkeinen * - VPOC 14afe267f2STomi Valkeinen * - Power domain? Regulator? Somehow any remote device should be able to 15afe267f2STomi Valkeinen * cause the VPOC to be turned on. 16afe267f2STomi Valkeinen * - Link between the deserializer and the serializer 17afe267f2STomi Valkeinen * - Related to VPOC management. We probably always want to turn on the VPOC 18afe267f2STomi Valkeinen * and then enable the link. 19afe267f2STomi Valkeinen * - Serializer's services: i2c, gpios, power 20afe267f2STomi Valkeinen * - The serializer needs to resume before the remote peripherals can 21afe267f2STomi Valkeinen * e.g. use the i2c. 22afe267f2STomi Valkeinen * - How to handle gpios? Reserving a gpio essentially keeps the provider 23afe267f2STomi Valkeinen * (serializer) always powered on. 24afe267f2STomi Valkeinen * - Do we need a new bus for the FPD-Link? At the moment the serializers 25afe267f2STomi Valkeinen * are children of the same i2c-adapter where the deserializer resides. 26afe267f2STomi Valkeinen * - i2c-atr could be made embeddable instead of allocatable. 27afe267f2STomi Valkeinen */ 28afe267f2STomi Valkeinen 29afe267f2STomi Valkeinen #include <linux/bitops.h> 30afe267f2STomi Valkeinen #include <linux/clk.h> 31afe267f2STomi Valkeinen #include <linux/delay.h> 32afe267f2STomi Valkeinen #include <linux/fwnode.h> 33afe267f2STomi Valkeinen #include <linux/gpio/consumer.h> 34afe267f2STomi Valkeinen #include <linux/i2c-atr.h> 35afe267f2STomi Valkeinen #include <linux/i2c.h> 36afe267f2STomi Valkeinen #include <linux/init.h> 37afe267f2STomi Valkeinen #include <linux/interrupt.h> 38afe267f2STomi Valkeinen #include <linux/kernel.h> 39afe267f2STomi Valkeinen #include <linux/kthread.h> 40afe267f2STomi Valkeinen #include <linux/module.h> 41afe267f2STomi Valkeinen #include <linux/mutex.h> 42afe267f2STomi Valkeinen #include <linux/property.h> 43afe267f2STomi Valkeinen #include <linux/regmap.h> 44afe267f2STomi Valkeinen #include <linux/regulator/consumer.h> 45afe267f2STomi Valkeinen #include <linux/slab.h> 46afe267f2STomi Valkeinen #include <linux/workqueue.h> 47afe267f2STomi Valkeinen 48afe267f2STomi Valkeinen #include <media/i2c/ds90ub9xx.h> 49afe267f2STomi Valkeinen #include <media/mipi-csi2.h> 50afe267f2STomi Valkeinen #include <media/v4l2-ctrls.h> 51afe267f2STomi Valkeinen #include <media/v4l2-event.h> 52afe267f2STomi Valkeinen #include <media/v4l2-fwnode.h> 53afe267f2STomi Valkeinen #include <media/v4l2-subdev.h> 54afe267f2STomi Valkeinen 55afe267f2STomi Valkeinen #define MHZ(v) ((u32)((v) * 1000000U)) 56afe267f2STomi Valkeinen 57afe267f2STomi Valkeinen #define UB960_POLL_TIME_MS 500 58afe267f2STomi Valkeinen 59afe267f2STomi Valkeinen #define UB960_MAX_RX_NPORTS 4 60afe267f2STomi Valkeinen #define UB960_MAX_TX_NPORTS 2 61afe267f2STomi Valkeinen #define UB960_MAX_NPORTS (UB960_MAX_RX_NPORTS + UB960_MAX_TX_NPORTS) 62afe267f2STomi Valkeinen 63afe267f2STomi Valkeinen #define UB960_MAX_PORT_ALIASES 8 64afe267f2STomi Valkeinen 65afe267f2STomi Valkeinen #define UB960_NUM_BC_GPIOS 4 66afe267f2STomi Valkeinen 67afe267f2STomi Valkeinen /* 68afe267f2STomi Valkeinen * Register map 69afe267f2STomi Valkeinen * 70afe267f2STomi Valkeinen * 0x00-0x32 Shared (UB960_SR) 71afe267f2STomi Valkeinen * 0x33-0x3a CSI-2 TX (per-port paged on DS90UB960, shared on 954) (UB960_TR) 72afe267f2STomi Valkeinen * 0x4c Shared (UB960_SR) 73afe267f2STomi Valkeinen * 0x4d-0x7f FPD-Link RX, per-port paged (UB960_RR) 74afe267f2STomi Valkeinen * 0xb0-0xbf Shared (UB960_SR) 75afe267f2STomi Valkeinen * 0xd0-0xdf FPD-Link RX, per-port paged (UB960_RR) 76afe267f2STomi Valkeinen * 0xf0-0xf5 Shared (UB960_SR) 77afe267f2STomi Valkeinen * 0xf8-0xfb Shared (UB960_SR) 78afe267f2STomi Valkeinen * All others Reserved 79afe267f2STomi Valkeinen * 80afe267f2STomi Valkeinen * Register prefixes: 81afe267f2STomi Valkeinen * UB960_SR_* = Shared register 82afe267f2STomi Valkeinen * UB960_RR_* = FPD-Link RX, per-port paged register 83afe267f2STomi Valkeinen * UB960_TR_* = CSI-2 TX, per-port paged register 84afe267f2STomi Valkeinen * UB960_XR_* = Reserved register 85afe267f2STomi Valkeinen * UB960_IR_* = Indirect register 86afe267f2STomi Valkeinen */ 87afe267f2STomi Valkeinen 88afe267f2STomi Valkeinen #define UB960_SR_I2C_DEV_ID 0x00 89afe267f2STomi Valkeinen #define UB960_SR_RESET 0x01 90afe267f2STomi Valkeinen #define UB960_SR_RESET_DIGITAL_RESET1 BIT(1) 91afe267f2STomi Valkeinen #define UB960_SR_RESET_DIGITAL_RESET0 BIT(0) 92afe267f2STomi Valkeinen #define UB960_SR_RESET_GPIO_LOCK_RELEASE BIT(5) 93afe267f2STomi Valkeinen 94afe267f2STomi Valkeinen #define UB960_SR_GEN_CONFIG 0x02 95afe267f2STomi Valkeinen #define UB960_SR_REV_MASK 0x03 96afe267f2STomi Valkeinen #define UB960_SR_DEVICE_STS 0x04 97afe267f2STomi Valkeinen #define UB960_SR_PAR_ERR_THOLD_HI 0x05 98afe267f2STomi Valkeinen #define UB960_SR_PAR_ERR_THOLD_LO 0x06 99afe267f2STomi Valkeinen #define UB960_SR_BCC_WDOG_CTL 0x07 100afe267f2STomi Valkeinen #define UB960_SR_I2C_CTL1 0x08 101afe267f2STomi Valkeinen #define UB960_SR_I2C_CTL2 0x09 102afe267f2STomi Valkeinen #define UB960_SR_SCL_HIGH_TIME 0x0a 103afe267f2STomi Valkeinen #define UB960_SR_SCL_LOW_TIME 0x0b 104afe267f2STomi Valkeinen #define UB960_SR_RX_PORT_CTL 0x0c 105afe267f2STomi Valkeinen #define UB960_SR_IO_CTL 0x0d 106afe267f2STomi Valkeinen #define UB960_SR_GPIO_PIN_STS 0x0e 107afe267f2STomi Valkeinen #define UB960_SR_GPIO_INPUT_CTL 0x0f 108afe267f2STomi Valkeinen #define UB960_SR_GPIO_PIN_CTL(n) (0x10 + (n)) /* n < UB960_NUM_GPIOS */ 109afe267f2STomi Valkeinen #define UB960_SR_GPIO_PIN_CTL_GPIO_OUT_SEL 5 110afe267f2STomi Valkeinen #define UB960_SR_GPIO_PIN_CTL_GPIO_OUT_SRC_SHIFT 2 111afe267f2STomi Valkeinen #define UB960_SR_GPIO_PIN_CTL_GPIO_OUT_EN BIT(0) 112afe267f2STomi Valkeinen 113afe267f2STomi Valkeinen #define UB960_SR_FS_CTL 0x18 114afe267f2STomi Valkeinen #define UB960_SR_FS_HIGH_TIME_1 0x19 115afe267f2STomi Valkeinen #define UB960_SR_FS_HIGH_TIME_0 0x1a 116afe267f2STomi Valkeinen #define UB960_SR_FS_LOW_TIME_1 0x1b 117afe267f2STomi Valkeinen #define UB960_SR_FS_LOW_TIME_0 0x1c 118afe267f2STomi Valkeinen #define UB960_SR_MAX_FRM_HI 0x1d 119afe267f2STomi Valkeinen #define UB960_SR_MAX_FRM_LO 0x1e 120afe267f2STomi Valkeinen #define UB960_SR_CSI_PLL_CTL 0x1f 121afe267f2STomi Valkeinen 122afe267f2STomi Valkeinen #define UB960_SR_FWD_CTL1 0x20 123afe267f2STomi Valkeinen #define UB960_SR_FWD_CTL1_PORT_DIS(n) BIT((n) + 4) 124afe267f2STomi Valkeinen 125afe267f2STomi Valkeinen #define UB960_SR_FWD_CTL2 0x21 126afe267f2STomi Valkeinen #define UB960_SR_FWD_STS 0x22 127afe267f2STomi Valkeinen 128afe267f2STomi Valkeinen #define UB960_SR_INTERRUPT_CTL 0x23 129afe267f2STomi Valkeinen #define UB960_SR_INTERRUPT_CTL_INT_EN BIT(7) 130afe267f2STomi Valkeinen #define UB960_SR_INTERRUPT_CTL_IE_CSI_TX0 BIT(4) 131afe267f2STomi Valkeinen #define UB960_SR_INTERRUPT_CTL_IE_RX(n) BIT((n)) /* rxport[n] IRQ */ 132afe267f2STomi Valkeinen 133afe267f2STomi Valkeinen #define UB960_SR_INTERRUPT_STS 0x24 134afe267f2STomi Valkeinen #define UB960_SR_INTERRUPT_STS_INT BIT(7) 135afe267f2STomi Valkeinen #define UB960_SR_INTERRUPT_STS_IS_CSI_TX(n) BIT(4 + (n)) /* txport[n] IRQ */ 136afe267f2STomi Valkeinen #define UB960_SR_INTERRUPT_STS_IS_RX(n) BIT((n)) /* rxport[n] IRQ */ 137afe267f2STomi Valkeinen 138afe267f2STomi Valkeinen #define UB960_SR_TS_CONFIG 0x25 139afe267f2STomi Valkeinen #define UB960_SR_TS_CONTROL 0x26 140afe267f2STomi Valkeinen #define UB960_SR_TS_LINE_HI 0x27 141afe267f2STomi Valkeinen #define UB960_SR_TS_LINE_LO 0x28 142afe267f2STomi Valkeinen #define UB960_SR_TS_STATUS 0x29 143afe267f2STomi Valkeinen #define UB960_SR_TIMESTAMP_P0_HI 0x2a 144afe267f2STomi Valkeinen #define UB960_SR_TIMESTAMP_P0_LO 0x2b 145afe267f2STomi Valkeinen #define UB960_SR_TIMESTAMP_P1_HI 0x2c 146afe267f2STomi Valkeinen #define UB960_SR_TIMESTAMP_P1_LO 0x2d 147afe267f2STomi Valkeinen 148afe267f2STomi Valkeinen #define UB960_SR_CSI_PORT_SEL 0x32 149afe267f2STomi Valkeinen 150afe267f2STomi Valkeinen #define UB960_TR_CSI_CTL 0x33 151afe267f2STomi Valkeinen #define UB960_TR_CSI_CTL_CSI_CAL_EN BIT(6) 152afe267f2STomi Valkeinen #define UB960_TR_CSI_CTL_CSI_ENABLE BIT(0) 153afe267f2STomi Valkeinen 154afe267f2STomi Valkeinen #define UB960_TR_CSI_CTL2 0x34 155afe267f2STomi Valkeinen #define UB960_TR_CSI_STS 0x35 156afe267f2STomi Valkeinen #define UB960_TR_CSI_TX_ICR 0x36 157afe267f2STomi Valkeinen 158afe267f2STomi Valkeinen #define UB960_TR_CSI_TX_ISR 0x37 159afe267f2STomi Valkeinen #define UB960_TR_CSI_TX_ISR_IS_CSI_SYNC_ERROR BIT(3) 160afe267f2STomi Valkeinen #define UB960_TR_CSI_TX_ISR_IS_CSI_PASS_ERROR BIT(1) 161afe267f2STomi Valkeinen 162afe267f2STomi Valkeinen #define UB960_TR_CSI_TEST_CTL 0x38 163afe267f2STomi Valkeinen #define UB960_TR_CSI_TEST_PATT_HI 0x39 164afe267f2STomi Valkeinen #define UB960_TR_CSI_TEST_PATT_LO 0x3a 165afe267f2STomi Valkeinen 166afe267f2STomi Valkeinen #define UB960_XR_SFILTER_CFG 0x41 167afe267f2STomi Valkeinen #define UB960_XR_SFILTER_CFG_SFILTER_MAX_SHIFT 4 168afe267f2STomi Valkeinen #define UB960_XR_SFILTER_CFG_SFILTER_MIN_SHIFT 0 169afe267f2STomi Valkeinen 170afe267f2STomi Valkeinen #define UB960_XR_AEQ_CTL1 0x42 171afe267f2STomi Valkeinen #define UB960_XR_AEQ_CTL1_AEQ_ERR_CTL_FPD_CLK BIT(6) 172afe267f2STomi Valkeinen #define UB960_XR_AEQ_CTL1_AEQ_ERR_CTL_ENCODING BIT(5) 173afe267f2STomi Valkeinen #define UB960_XR_AEQ_CTL1_AEQ_ERR_CTL_PARITY BIT(4) 174afe267f2STomi Valkeinen #define UB960_XR_AEQ_CTL1_AEQ_ERR_CTL_MASK \ 175afe267f2STomi Valkeinen (UB960_XR_AEQ_CTL1_AEQ_ERR_CTL_FPD_CLK | \ 176afe267f2STomi Valkeinen UB960_XR_AEQ_CTL1_AEQ_ERR_CTL_ENCODING | \ 177afe267f2STomi Valkeinen UB960_XR_AEQ_CTL1_AEQ_ERR_CTL_PARITY) 178afe267f2STomi Valkeinen #define UB960_XR_AEQ_CTL1_AEQ_SFILTER_EN BIT(0) 179afe267f2STomi Valkeinen 180afe267f2STomi Valkeinen #define UB960_XR_AEQ_ERR_THOLD 0x43 181afe267f2STomi Valkeinen 182afe267f2STomi Valkeinen #define UB960_RR_BCC_ERR_CTL 0x46 183afe267f2STomi Valkeinen #define UB960_RR_BCC_STATUS 0x47 184afe267f2STomi Valkeinen #define UB960_RR_BCC_STATUS_SEQ_ERROR BIT(5) 185afe267f2STomi Valkeinen #define UB960_RR_BCC_STATUS_MASTER_ERR BIT(4) 186afe267f2STomi Valkeinen #define UB960_RR_BCC_STATUS_MASTER_TO BIT(3) 187afe267f2STomi Valkeinen #define UB960_RR_BCC_STATUS_SLAVE_ERR BIT(2) 188afe267f2STomi Valkeinen #define UB960_RR_BCC_STATUS_SLAVE_TO BIT(1) 189afe267f2STomi Valkeinen #define UB960_RR_BCC_STATUS_RESP_ERR BIT(0) 190afe267f2STomi Valkeinen #define UB960_RR_BCC_STATUS_ERROR_MASK \ 191afe267f2STomi Valkeinen (UB960_RR_BCC_STATUS_SEQ_ERROR | UB960_RR_BCC_STATUS_MASTER_ERR | \ 192afe267f2STomi Valkeinen UB960_RR_BCC_STATUS_MASTER_TO | UB960_RR_BCC_STATUS_SLAVE_ERR | \ 193afe267f2STomi Valkeinen UB960_RR_BCC_STATUS_SLAVE_TO | UB960_RR_BCC_STATUS_RESP_ERR) 194afe267f2STomi Valkeinen 195afe267f2STomi Valkeinen #define UB960_RR_FPD3_CAP 0x4a 196afe267f2STomi Valkeinen #define UB960_RR_RAW_EMBED_DTYPE 0x4b 197afe267f2STomi Valkeinen #define UB960_RR_RAW_EMBED_DTYPE_LINES_SHIFT 6 198afe267f2STomi Valkeinen 199afe267f2STomi Valkeinen #define UB960_SR_FPD3_PORT_SEL 0x4c 200afe267f2STomi Valkeinen 201afe267f2STomi Valkeinen #define UB960_RR_RX_PORT_STS1 0x4d 202afe267f2STomi Valkeinen #define UB960_RR_RX_PORT_STS1_BCC_CRC_ERROR BIT(5) 203afe267f2STomi Valkeinen #define UB960_RR_RX_PORT_STS1_LOCK_STS_CHG BIT(4) 204afe267f2STomi Valkeinen #define UB960_RR_RX_PORT_STS1_BCC_SEQ_ERROR BIT(3) 205afe267f2STomi Valkeinen #define UB960_RR_RX_PORT_STS1_PARITY_ERROR BIT(2) 206afe267f2STomi Valkeinen #define UB960_RR_RX_PORT_STS1_PORT_PASS BIT(1) 207afe267f2STomi Valkeinen #define UB960_RR_RX_PORT_STS1_LOCK_STS BIT(0) 208afe267f2STomi Valkeinen #define UB960_RR_RX_PORT_STS1_ERROR_MASK \ 209afe267f2STomi Valkeinen (UB960_RR_RX_PORT_STS1_BCC_CRC_ERROR | \ 210afe267f2STomi Valkeinen UB960_RR_RX_PORT_STS1_BCC_SEQ_ERROR | \ 211afe267f2STomi Valkeinen UB960_RR_RX_PORT_STS1_PARITY_ERROR) 212afe267f2STomi Valkeinen 213afe267f2STomi Valkeinen #define UB960_RR_RX_PORT_STS2 0x4e 214afe267f2STomi Valkeinen #define UB960_RR_RX_PORT_STS2_LINE_LEN_UNSTABLE BIT(7) 215afe267f2STomi Valkeinen #define UB960_RR_RX_PORT_STS2_LINE_LEN_CHG BIT(6) 216afe267f2STomi Valkeinen #define UB960_RR_RX_PORT_STS2_FPD3_ENCODE_ERROR BIT(5) 217afe267f2STomi Valkeinen #define UB960_RR_RX_PORT_STS2_BUFFER_ERROR BIT(4) 218afe267f2STomi Valkeinen #define UB960_RR_RX_PORT_STS2_CSI_ERROR BIT(3) 219afe267f2STomi Valkeinen #define UB960_RR_RX_PORT_STS2_FREQ_STABLE BIT(2) 220afe267f2STomi Valkeinen #define UB960_RR_RX_PORT_STS2_CABLE_FAULT BIT(1) 221afe267f2STomi Valkeinen #define UB960_RR_RX_PORT_STS2_LINE_CNT_CHG BIT(0) 222afe267f2STomi Valkeinen #define UB960_RR_RX_PORT_STS2_ERROR_MASK \ 223afe267f2STomi Valkeinen UB960_RR_RX_PORT_STS2_BUFFER_ERROR 224afe267f2STomi Valkeinen 225afe267f2STomi Valkeinen #define UB960_RR_RX_FREQ_HIGH 0x4f 226afe267f2STomi Valkeinen #define UB960_RR_RX_FREQ_LOW 0x50 227afe267f2STomi Valkeinen #define UB960_RR_SENSOR_STS_0 0x51 228afe267f2STomi Valkeinen #define UB960_RR_SENSOR_STS_1 0x52 229afe267f2STomi Valkeinen #define UB960_RR_SENSOR_STS_2 0x53 230afe267f2STomi Valkeinen #define UB960_RR_SENSOR_STS_3 0x54 231afe267f2STomi Valkeinen #define UB960_RR_RX_PAR_ERR_HI 0x55 232afe267f2STomi Valkeinen #define UB960_RR_RX_PAR_ERR_LO 0x56 233afe267f2STomi Valkeinen #define UB960_RR_BIST_ERR_COUNT 0x57 234afe267f2STomi Valkeinen 235afe267f2STomi Valkeinen #define UB960_RR_BCC_CONFIG 0x58 236afe267f2STomi Valkeinen #define UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH BIT(6) 237afe267f2STomi Valkeinen #define UB960_RR_BCC_CONFIG_BC_FREQ_SEL_MASK GENMASK(2, 0) 238afe267f2STomi Valkeinen 239afe267f2STomi Valkeinen #define UB960_RR_DATAPATH_CTL1 0x59 240afe267f2STomi Valkeinen #define UB960_RR_DATAPATH_CTL2 0x5a 241afe267f2STomi Valkeinen #define UB960_RR_SER_ID 0x5b 242afe267f2STomi Valkeinen #define UB960_RR_SER_ALIAS_ID 0x5c 243afe267f2STomi Valkeinen 244afe267f2STomi Valkeinen /* For these two register sets: n < UB960_MAX_PORT_ALIASES */ 245afe267f2STomi Valkeinen #define UB960_RR_SLAVE_ID(n) (0x5d + (n)) 246afe267f2STomi Valkeinen #define UB960_RR_SLAVE_ALIAS(n) (0x65 + (n)) 247afe267f2STomi Valkeinen 248afe267f2STomi Valkeinen #define UB960_RR_PORT_CONFIG 0x6d 249afe267f2STomi Valkeinen #define UB960_RR_PORT_CONFIG_FPD3_MODE_MASK GENMASK(1, 0) 250afe267f2STomi Valkeinen 251afe267f2STomi Valkeinen #define UB960_RR_BC_GPIO_CTL(n) (0x6e + (n)) /* n < 2 */ 252afe267f2STomi Valkeinen #define UB960_RR_RAW10_ID 0x70 253afe267f2STomi Valkeinen #define UB960_RR_RAW10_ID_VC_SHIFT 6 254afe267f2STomi Valkeinen #define UB960_RR_RAW10_ID_DT_SHIFT 0 255afe267f2STomi Valkeinen 256afe267f2STomi Valkeinen #define UB960_RR_RAW12_ID 0x71 257afe267f2STomi Valkeinen #define UB960_RR_CSI_VC_MAP 0x72 258afe267f2STomi Valkeinen #define UB960_RR_CSI_VC_MAP_SHIFT(x) ((x) * 2) 259afe267f2STomi Valkeinen 260afe267f2STomi Valkeinen #define UB960_RR_LINE_COUNT_HI 0x73 261afe267f2STomi Valkeinen #define UB960_RR_LINE_COUNT_LO 0x74 262afe267f2STomi Valkeinen #define UB960_RR_LINE_LEN_1 0x75 263afe267f2STomi Valkeinen #define UB960_RR_LINE_LEN_0 0x76 264afe267f2STomi Valkeinen #define UB960_RR_FREQ_DET_CTL 0x77 265afe267f2STomi Valkeinen #define UB960_RR_MAILBOX_1 0x78 266afe267f2STomi Valkeinen #define UB960_RR_MAILBOX_2 0x79 267afe267f2STomi Valkeinen 268afe267f2STomi Valkeinen #define UB960_RR_CSI_RX_STS 0x7a 269afe267f2STomi Valkeinen #define UB960_RR_CSI_RX_STS_LENGTH_ERR BIT(3) 270afe267f2STomi Valkeinen #define UB960_RR_CSI_RX_STS_CKSUM_ERR BIT(2) 271afe267f2STomi Valkeinen #define UB960_RR_CSI_RX_STS_ECC2_ERR BIT(1) 272afe267f2STomi Valkeinen #define UB960_RR_CSI_RX_STS_ECC1_ERR BIT(0) 273afe267f2STomi Valkeinen #define UB960_RR_CSI_RX_STS_ERROR_MASK \ 274afe267f2STomi Valkeinen (UB960_RR_CSI_RX_STS_LENGTH_ERR | UB960_RR_CSI_RX_STS_CKSUM_ERR | \ 275afe267f2STomi Valkeinen UB960_RR_CSI_RX_STS_ECC2_ERR | UB960_RR_CSI_RX_STS_ECC1_ERR) 276afe267f2STomi Valkeinen 277afe267f2STomi Valkeinen #define UB960_RR_CSI_ERR_COUNTER 0x7b 278afe267f2STomi Valkeinen #define UB960_RR_PORT_CONFIG2 0x7c 279afe267f2STomi Valkeinen #define UB960_RR_PORT_CONFIG2_RAW10_8BIT_CTL_MASK GENMASK(7, 6) 280afe267f2STomi Valkeinen #define UB960_RR_PORT_CONFIG2_RAW10_8BIT_CTL_SHIFT 6 281afe267f2STomi Valkeinen 282afe267f2STomi Valkeinen #define UB960_RR_PORT_CONFIG2_LV_POL_LOW BIT(1) 283afe267f2STomi Valkeinen #define UB960_RR_PORT_CONFIG2_FV_POL_LOW BIT(0) 284afe267f2STomi Valkeinen 285afe267f2STomi Valkeinen #define UB960_RR_PORT_PASS_CTL 0x7d 286afe267f2STomi Valkeinen #define UB960_RR_SEN_INT_RISE_CTL 0x7e 287afe267f2STomi Valkeinen #define UB960_RR_SEN_INT_FALL_CTL 0x7f 288afe267f2STomi Valkeinen 289afe267f2STomi Valkeinen #define UB960_SR_CSI_FRAME_COUNT_HI(n) (0x90 + 8 * (n)) 290afe267f2STomi Valkeinen #define UB960_SR_CSI_FRAME_COUNT_LO(n) (0x91 + 8 * (n)) 291afe267f2STomi Valkeinen #define UB960_SR_CSI_FRAME_ERR_COUNT_HI(n) (0x92 + 8 * (n)) 292afe267f2STomi Valkeinen #define UB960_SR_CSI_FRAME_ERR_COUNT_LO(n) (0x93 + 8 * (n)) 293afe267f2STomi Valkeinen #define UB960_SR_CSI_LINE_COUNT_HI(n) (0x94 + 8 * (n)) 294afe267f2STomi Valkeinen #define UB960_SR_CSI_LINE_COUNT_LO(n) (0x95 + 8 * (n)) 295afe267f2STomi Valkeinen #define UB960_SR_CSI_LINE_ERR_COUNT_HI(n) (0x96 + 8 * (n)) 296afe267f2STomi Valkeinen #define UB960_SR_CSI_LINE_ERR_COUNT_LO(n) (0x97 + 8 * (n)) 297afe267f2STomi Valkeinen 298afe267f2STomi Valkeinen #define UB960_XR_REFCLK_FREQ 0xa5 /* UB960 */ 299afe267f2STomi Valkeinen 300afe267f2STomi Valkeinen #define UB960_RR_VC_ID_MAP(x) (0xa0 + (x)) /* UB9702 */ 301afe267f2STomi Valkeinen 302afe267f2STomi Valkeinen #define UB960_SR_IND_ACC_CTL 0xb0 303afe267f2STomi Valkeinen #define UB960_SR_IND_ACC_CTL_IA_AUTO_INC BIT(1) 304afe267f2STomi Valkeinen 305afe267f2STomi Valkeinen #define UB960_SR_IND_ACC_ADDR 0xb1 306afe267f2STomi Valkeinen #define UB960_SR_IND_ACC_DATA 0xb2 307afe267f2STomi Valkeinen #define UB960_SR_BIST_CONTROL 0xb3 308afe267f2STomi Valkeinen #define UB960_SR_MODE_IDX_STS 0xb8 309afe267f2STomi Valkeinen #define UB960_SR_LINK_ERROR_COUNT 0xb9 310afe267f2STomi Valkeinen #define UB960_SR_FPD3_ENC_CTL 0xba 311afe267f2STomi Valkeinen #define UB960_SR_FV_MIN_TIME 0xbc 312afe267f2STomi Valkeinen #define UB960_SR_GPIO_PD_CTL 0xbe 313afe267f2STomi Valkeinen 314afe267f2STomi Valkeinen #define UB960_SR_FPD_RATE_CFG 0xc2 /* UB9702 */ 315afe267f2STomi Valkeinen #define UB960_SR_CSI_PLL_DIV 0xc9 /* UB9702 */ 316afe267f2STomi Valkeinen 317afe267f2STomi Valkeinen #define UB960_RR_PORT_DEBUG 0xd0 318afe267f2STomi Valkeinen #define UB960_RR_AEQ_CTL2 0xd2 319afe267f2STomi Valkeinen #define UB960_RR_AEQ_CTL2_SET_AEQ_FLOOR BIT(2) 320afe267f2STomi Valkeinen 321afe267f2STomi Valkeinen #define UB960_RR_AEQ_STATUS 0xd3 322afe267f2STomi Valkeinen #define UB960_RR_AEQ_STATUS_STATUS_2 GENMASK(5, 3) 323afe267f2STomi Valkeinen #define UB960_RR_AEQ_STATUS_STATUS_1 GENMASK(2, 0) 324afe267f2STomi Valkeinen 325afe267f2STomi Valkeinen #define UB960_RR_AEQ_BYPASS 0xd4 326afe267f2STomi Valkeinen #define UB960_RR_AEQ_BYPASS_EQ_STAGE1_VALUE_SHIFT 5 327afe267f2STomi Valkeinen #define UB960_RR_AEQ_BYPASS_EQ_STAGE1_VALUE_MASK GENMASK(7, 5) 328afe267f2STomi Valkeinen #define UB960_RR_AEQ_BYPASS_EQ_STAGE2_VALUE_SHIFT 1 329afe267f2STomi Valkeinen #define UB960_RR_AEQ_BYPASS_EQ_STAGE2_VALUE_MASK GENMASK(3, 1) 330afe267f2STomi Valkeinen #define UB960_RR_AEQ_BYPASS_ENABLE BIT(0) 331afe267f2STomi Valkeinen 332afe267f2STomi Valkeinen #define UB960_RR_AEQ_MIN_MAX 0xd5 333afe267f2STomi Valkeinen #define UB960_RR_AEQ_MIN_MAX_AEQ_MAX_SHIFT 4 334afe267f2STomi Valkeinen #define UB960_RR_AEQ_MIN_MAX_AEQ_FLOOR_SHIFT 0 335afe267f2STomi Valkeinen 336afe267f2STomi Valkeinen #define UB960_RR_SFILTER_STS_0 0xd6 337afe267f2STomi Valkeinen #define UB960_RR_SFILTER_STS_1 0xd7 338afe267f2STomi Valkeinen #define UB960_RR_PORT_ICR_HI 0xd8 339afe267f2STomi Valkeinen #define UB960_RR_PORT_ICR_LO 0xd9 340afe267f2STomi Valkeinen #define UB960_RR_PORT_ISR_HI 0xda 341afe267f2STomi Valkeinen #define UB960_RR_PORT_ISR_LO 0xdb 342afe267f2STomi Valkeinen #define UB960_RR_FC_GPIO_STS 0xdc 343afe267f2STomi Valkeinen #define UB960_RR_FC_GPIO_ICR 0xdd 344afe267f2STomi Valkeinen #define UB960_RR_SEN_INT_RISE_STS 0xde 345afe267f2STomi Valkeinen #define UB960_RR_SEN_INT_FALL_STS 0xdf 346afe267f2STomi Valkeinen 347afe267f2STomi Valkeinen #define UB960_RR_CHANNEL_MODE 0xe4 /* UB9702 */ 348afe267f2STomi Valkeinen 349afe267f2STomi Valkeinen #define UB960_SR_FPD3_RX_ID(n) (0xf0 + (n)) 350afe267f2STomi Valkeinen #define UB960_SR_FPD3_RX_ID_LEN 6 351afe267f2STomi Valkeinen 352afe267f2STomi Valkeinen #define UB960_SR_I2C_RX_ID(n) (0xf8 + (n)) /* < UB960_FPD_RX_NPORTS */ 353afe267f2STomi Valkeinen 354afe267f2STomi Valkeinen /* Indirect register blocks */ 355afe267f2STomi Valkeinen #define UB960_IND_TARGET_PAT_GEN 0x00 356afe267f2STomi Valkeinen #define UB960_IND_TARGET_RX_ANA(n) (0x01 + (n)) 357afe267f2STomi Valkeinen #define UB960_IND_TARGET_CSI_CSIPLL_REG_1 0x92 /* UB9702 */ 358afe267f2STomi Valkeinen #define UB960_IND_TARGET_CSI_ANA 0x07 359afe267f2STomi Valkeinen 360afe267f2STomi Valkeinen /* UB960_IR_PGEN_*: Indirect Registers for Test Pattern Generator */ 361afe267f2STomi Valkeinen 362afe267f2STomi Valkeinen #define UB960_IR_PGEN_CTL 0x01 363afe267f2STomi Valkeinen #define UB960_IR_PGEN_CTL_PGEN_ENABLE BIT(0) 364afe267f2STomi Valkeinen 365afe267f2STomi Valkeinen #define UB960_IR_PGEN_CFG 0x02 366afe267f2STomi Valkeinen #define UB960_IR_PGEN_CSI_DI 0x03 367afe267f2STomi Valkeinen #define UB960_IR_PGEN_LINE_SIZE1 0x04 368afe267f2STomi Valkeinen #define UB960_IR_PGEN_LINE_SIZE0 0x05 369afe267f2STomi Valkeinen #define UB960_IR_PGEN_BAR_SIZE1 0x06 370afe267f2STomi Valkeinen #define UB960_IR_PGEN_BAR_SIZE0 0x07 371afe267f2STomi Valkeinen #define UB960_IR_PGEN_ACT_LPF1 0x08 372afe267f2STomi Valkeinen #define UB960_IR_PGEN_ACT_LPF0 0x09 373afe267f2STomi Valkeinen #define UB960_IR_PGEN_TOT_LPF1 0x0a 374afe267f2STomi Valkeinen #define UB960_IR_PGEN_TOT_LPF0 0x0b 375afe267f2STomi Valkeinen #define UB960_IR_PGEN_LINE_PD1 0x0c 376afe267f2STomi Valkeinen #define UB960_IR_PGEN_LINE_PD0 0x0d 377afe267f2STomi Valkeinen #define UB960_IR_PGEN_VBP 0x0e 378afe267f2STomi Valkeinen #define UB960_IR_PGEN_VFP 0x0f 379afe267f2STomi Valkeinen #define UB960_IR_PGEN_COLOR(n) (0x10 + (n)) /* n < 15 */ 380afe267f2STomi Valkeinen 381afe267f2STomi Valkeinen #define UB960_IR_RX_ANA_STROBE_SET_CLK 0x08 382afe267f2STomi Valkeinen #define UB960_IR_RX_ANA_STROBE_SET_CLK_NO_EXTRA_DELAY BIT(3) 383afe267f2STomi Valkeinen #define UB960_IR_RX_ANA_STROBE_SET_CLK_DELAY_MASK GENMASK(2, 0) 384afe267f2STomi Valkeinen 385afe267f2STomi Valkeinen #define UB960_IR_RX_ANA_STROBE_SET_DATA 0x09 386afe267f2STomi Valkeinen #define UB960_IR_RX_ANA_STROBE_SET_DATA_NO_EXTRA_DELAY BIT(3) 387afe267f2STomi Valkeinen #define UB960_IR_RX_ANA_STROBE_SET_DATA_DELAY_MASK GENMASK(2, 0) 388afe267f2STomi Valkeinen 389afe267f2STomi Valkeinen /* EQ related */ 390afe267f2STomi Valkeinen 391afe267f2STomi Valkeinen #define UB960_MIN_AEQ_STROBE_POS -7 392afe267f2STomi Valkeinen #define UB960_MAX_AEQ_STROBE_POS 7 393afe267f2STomi Valkeinen 394afe267f2STomi Valkeinen #define UB960_MANUAL_STROBE_EXTRA_DELAY 6 395afe267f2STomi Valkeinen 396afe267f2STomi Valkeinen #define UB960_MIN_MANUAL_STROBE_POS -(7 + UB960_MANUAL_STROBE_EXTRA_DELAY) 397afe267f2STomi Valkeinen #define UB960_MAX_MANUAL_STROBE_POS (7 + UB960_MANUAL_STROBE_EXTRA_DELAY) 398afe267f2STomi Valkeinen #define UB960_NUM_MANUAL_STROBE_POS (UB960_MAX_MANUAL_STROBE_POS - UB960_MIN_MANUAL_STROBE_POS + 1) 399afe267f2STomi Valkeinen 400afe267f2STomi Valkeinen #define UB960_MIN_EQ_LEVEL 0 401afe267f2STomi Valkeinen #define UB960_MAX_EQ_LEVEL 14 402afe267f2STomi Valkeinen #define UB960_NUM_EQ_LEVELS (UB960_MAX_EQ_LEVEL - UB960_MIN_EQ_LEVEL + 1) 403afe267f2STomi Valkeinen 404afe267f2STomi Valkeinen struct ub960_hw_data { 405afe267f2STomi Valkeinen const char *model; 406afe267f2STomi Valkeinen u8 num_rxports; 407afe267f2STomi Valkeinen u8 num_txports; 408afe267f2STomi Valkeinen bool is_ub9702; 409afe267f2STomi Valkeinen bool is_fpdlink4; 410afe267f2STomi Valkeinen }; 411afe267f2STomi Valkeinen 412afe267f2STomi Valkeinen enum ub960_rxport_mode { 413afe267f2STomi Valkeinen RXPORT_MODE_RAW10 = 0, 414afe267f2STomi Valkeinen RXPORT_MODE_RAW12_HF = 1, 415afe267f2STomi Valkeinen RXPORT_MODE_RAW12_LF = 2, 416afe267f2STomi Valkeinen RXPORT_MODE_CSI2_SYNC = 3, 417afe267f2STomi Valkeinen RXPORT_MODE_CSI2_ASYNC = 4, 418afe267f2STomi Valkeinen RXPORT_MODE_LAST = RXPORT_MODE_CSI2_ASYNC, 419afe267f2STomi Valkeinen }; 420afe267f2STomi Valkeinen 421afe267f2STomi Valkeinen enum ub960_rxport_cdr { 422afe267f2STomi Valkeinen RXPORT_CDR_FPD3 = 0, 423afe267f2STomi Valkeinen RXPORT_CDR_FPD4 = 1, 424afe267f2STomi Valkeinen RXPORT_CDR_LAST = RXPORT_CDR_FPD4, 425afe267f2STomi Valkeinen }; 426afe267f2STomi Valkeinen 427afe267f2STomi Valkeinen struct ub960_rxport { 428afe267f2STomi Valkeinen struct ub960_data *priv; 429afe267f2STomi Valkeinen u8 nport; /* RX port number, and index in priv->rxport[] */ 430afe267f2STomi Valkeinen 431afe267f2STomi Valkeinen struct { 432afe267f2STomi Valkeinen struct v4l2_subdev *sd; 433afe267f2STomi Valkeinen u16 pad; 434afe267f2STomi Valkeinen struct fwnode_handle *ep_fwnode; 435afe267f2STomi Valkeinen } source; 436afe267f2STomi Valkeinen 437afe267f2STomi Valkeinen /* Serializer */ 438afe267f2STomi Valkeinen struct { 439afe267f2STomi Valkeinen struct fwnode_handle *fwnode; 440afe267f2STomi Valkeinen struct i2c_client *client; 441afe267f2STomi Valkeinen unsigned short alias; /* I2C alias (lower 7 bits) */ 442afe267f2STomi Valkeinen struct ds90ub9xx_platform_data pdata; 443afe267f2STomi Valkeinen } ser; 444afe267f2STomi Valkeinen 445afe267f2STomi Valkeinen enum ub960_rxport_mode rx_mode; 446afe267f2STomi Valkeinen enum ub960_rxport_cdr cdr_mode; 447afe267f2STomi Valkeinen 448afe267f2STomi Valkeinen u8 lv_fv_pol; /* LV and FV polarities */ 449afe267f2STomi Valkeinen 450afe267f2STomi Valkeinen struct regulator *vpoc; 451afe267f2STomi Valkeinen 452afe267f2STomi Valkeinen /* EQ settings */ 453afe267f2STomi Valkeinen struct { 454afe267f2STomi Valkeinen bool manual_eq; 455afe267f2STomi Valkeinen 456afe267f2STomi Valkeinen s8 strobe_pos; 457afe267f2STomi Valkeinen 458afe267f2STomi Valkeinen union { 459afe267f2STomi Valkeinen struct { 460afe267f2STomi Valkeinen u8 eq_level_min; 461afe267f2STomi Valkeinen u8 eq_level_max; 462afe267f2STomi Valkeinen } aeq; 463afe267f2STomi Valkeinen 464afe267f2STomi Valkeinen struct { 465afe267f2STomi Valkeinen u8 eq_level; 466afe267f2STomi Valkeinen } manual; 467afe267f2STomi Valkeinen }; 468afe267f2STomi Valkeinen } eq; 469afe267f2STomi Valkeinen 470afe267f2STomi Valkeinen const struct i2c_client *aliased_clients[UB960_MAX_PORT_ALIASES]; 471afe267f2STomi Valkeinen }; 472afe267f2STomi Valkeinen 473afe267f2STomi Valkeinen struct ub960_asd { 474*adb2dcd5SSakari Ailus struct v4l2_async_connection base; 475afe267f2STomi Valkeinen struct ub960_rxport *rxport; 476afe267f2STomi Valkeinen }; 477afe267f2STomi Valkeinen 478*adb2dcd5SSakari Ailus static inline struct ub960_asd *to_ub960_asd(struct v4l2_async_connection *asd) 479afe267f2STomi Valkeinen { 480afe267f2STomi Valkeinen return container_of(asd, struct ub960_asd, base); 481afe267f2STomi Valkeinen } 482afe267f2STomi Valkeinen 483afe267f2STomi Valkeinen struct ub960_txport { 484afe267f2STomi Valkeinen struct ub960_data *priv; 485afe267f2STomi Valkeinen u8 nport; /* TX port number, and index in priv->txport[] */ 486afe267f2STomi Valkeinen 487afe267f2STomi Valkeinen u32 num_data_lanes; 488afe267f2STomi Valkeinen }; 489afe267f2STomi Valkeinen 490afe267f2STomi Valkeinen struct ub960_data { 491afe267f2STomi Valkeinen const struct ub960_hw_data *hw_data; 492afe267f2STomi Valkeinen struct i2c_client *client; /* for shared local registers */ 493afe267f2STomi Valkeinen struct regmap *regmap; 494afe267f2STomi Valkeinen 495afe267f2STomi Valkeinen /* lock for register access */ 496afe267f2STomi Valkeinen struct mutex reg_lock; 497afe267f2STomi Valkeinen 498afe267f2STomi Valkeinen struct clk *refclk; 499afe267f2STomi Valkeinen 500afe267f2STomi Valkeinen struct regulator *vddio; 501afe267f2STomi Valkeinen 502afe267f2STomi Valkeinen struct gpio_desc *pd_gpio; 503afe267f2STomi Valkeinen struct delayed_work poll_work; 504afe267f2STomi Valkeinen struct ub960_rxport *rxports[UB960_MAX_RX_NPORTS]; 505afe267f2STomi Valkeinen struct ub960_txport *txports[UB960_MAX_TX_NPORTS]; 506afe267f2STomi Valkeinen 507afe267f2STomi Valkeinen struct v4l2_subdev sd; 508afe267f2STomi Valkeinen struct media_pad pads[UB960_MAX_NPORTS]; 509afe267f2STomi Valkeinen 510afe267f2STomi Valkeinen struct v4l2_ctrl_handler ctrl_handler; 511afe267f2STomi Valkeinen struct v4l2_async_notifier notifier; 512afe267f2STomi Valkeinen 513afe267f2STomi Valkeinen u32 tx_data_rate; /* Nominal data rate (Gb/s) */ 514afe267f2STomi Valkeinen s64 tx_link_freq[1]; 515afe267f2STomi Valkeinen 516afe267f2STomi Valkeinen struct i2c_atr *atr; 517afe267f2STomi Valkeinen 518afe267f2STomi Valkeinen struct { 519afe267f2STomi Valkeinen u8 rxport; 520afe267f2STomi Valkeinen u8 txport; 521afe267f2STomi Valkeinen u8 indirect_target; 522afe267f2STomi Valkeinen } reg_current; 523afe267f2STomi Valkeinen 524afe267f2STomi Valkeinen bool streaming; 525afe267f2STomi Valkeinen 526afe267f2STomi Valkeinen u8 stored_fwd_ctl; 527afe267f2STomi Valkeinen 528afe267f2STomi Valkeinen u64 stream_enable_mask[UB960_MAX_NPORTS]; 529afe267f2STomi Valkeinen 530afe267f2STomi Valkeinen /* These are common to all ports */ 531afe267f2STomi Valkeinen struct { 532afe267f2STomi Valkeinen bool manual; 533afe267f2STomi Valkeinen 534afe267f2STomi Valkeinen s8 min; 535afe267f2STomi Valkeinen s8 max; 536afe267f2STomi Valkeinen } strobe; 537afe267f2STomi Valkeinen }; 538afe267f2STomi Valkeinen 539afe267f2STomi Valkeinen static inline struct ub960_data *sd_to_ub960(struct v4l2_subdev *sd) 540afe267f2STomi Valkeinen { 541afe267f2STomi Valkeinen return container_of(sd, struct ub960_data, sd); 542afe267f2STomi Valkeinen } 543afe267f2STomi Valkeinen 544afe267f2STomi Valkeinen static inline bool ub960_pad_is_sink(struct ub960_data *priv, u32 pad) 545afe267f2STomi Valkeinen { 546afe267f2STomi Valkeinen return pad < priv->hw_data->num_rxports; 547afe267f2STomi Valkeinen } 548afe267f2STomi Valkeinen 549afe267f2STomi Valkeinen static inline bool ub960_pad_is_source(struct ub960_data *priv, u32 pad) 550afe267f2STomi Valkeinen { 551afe267f2STomi Valkeinen return pad >= priv->hw_data->num_rxports; 552afe267f2STomi Valkeinen } 553afe267f2STomi Valkeinen 554afe267f2STomi Valkeinen static inline unsigned int ub960_pad_to_port(struct ub960_data *priv, u32 pad) 555afe267f2STomi Valkeinen { 556afe267f2STomi Valkeinen if (ub960_pad_is_sink(priv, pad)) 557afe267f2STomi Valkeinen return pad; 558afe267f2STomi Valkeinen else 559afe267f2STomi Valkeinen return pad - priv->hw_data->num_rxports; 560afe267f2STomi Valkeinen } 561afe267f2STomi Valkeinen 562afe267f2STomi Valkeinen struct ub960_format_info { 563afe267f2STomi Valkeinen u32 code; 564afe267f2STomi Valkeinen u32 bpp; 565afe267f2STomi Valkeinen u8 datatype; 566afe267f2STomi Valkeinen bool meta; 567afe267f2STomi Valkeinen }; 568afe267f2STomi Valkeinen 569afe267f2STomi Valkeinen static const struct ub960_format_info ub960_formats[] = { 570afe267f2STomi Valkeinen { .code = MEDIA_BUS_FMT_YUYV8_1X16, .bpp = 16, .datatype = MIPI_CSI2_DT_YUV422_8B, }, 571afe267f2STomi Valkeinen { .code = MEDIA_BUS_FMT_UYVY8_1X16, .bpp = 16, .datatype = MIPI_CSI2_DT_YUV422_8B, }, 572afe267f2STomi Valkeinen { .code = MEDIA_BUS_FMT_VYUY8_1X16, .bpp = 16, .datatype = MIPI_CSI2_DT_YUV422_8B, }, 573afe267f2STomi Valkeinen { .code = MEDIA_BUS_FMT_YVYU8_1X16, .bpp = 16, .datatype = MIPI_CSI2_DT_YUV422_8B, }, 574afe267f2STomi Valkeinen 575afe267f2STomi Valkeinen { .code = MEDIA_BUS_FMT_SBGGR12_1X12, .bpp = 12, .datatype = MIPI_CSI2_DT_RAW12, }, 576afe267f2STomi Valkeinen { .code = MEDIA_BUS_FMT_SGBRG12_1X12, .bpp = 12, .datatype = MIPI_CSI2_DT_RAW12, }, 577afe267f2STomi Valkeinen { .code = MEDIA_BUS_FMT_SGRBG12_1X12, .bpp = 12, .datatype = MIPI_CSI2_DT_RAW12, }, 578afe267f2STomi Valkeinen { .code = MEDIA_BUS_FMT_SRGGB12_1X12, .bpp = 12, .datatype = MIPI_CSI2_DT_RAW12, }, 579afe267f2STomi Valkeinen }; 580afe267f2STomi Valkeinen 581afe267f2STomi Valkeinen static const struct ub960_format_info *ub960_find_format(u32 code) 582afe267f2STomi Valkeinen { 583afe267f2STomi Valkeinen unsigned int i; 584afe267f2STomi Valkeinen 585afe267f2STomi Valkeinen for (i = 0; i < ARRAY_SIZE(ub960_formats); i++) { 586afe267f2STomi Valkeinen if (ub960_formats[i].code == code) 587afe267f2STomi Valkeinen return &ub960_formats[i]; 588afe267f2STomi Valkeinen } 589afe267f2STomi Valkeinen 590afe267f2STomi Valkeinen return NULL; 591afe267f2STomi Valkeinen } 592afe267f2STomi Valkeinen 593afe267f2STomi Valkeinen /* ----------------------------------------------------------------------------- 594afe267f2STomi Valkeinen * Basic device access 595afe267f2STomi Valkeinen */ 596afe267f2STomi Valkeinen 597afe267f2STomi Valkeinen static int ub960_read(struct ub960_data *priv, u8 reg, u8 *val) 598afe267f2STomi Valkeinen { 599afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 600afe267f2STomi Valkeinen unsigned int v; 601afe267f2STomi Valkeinen int ret; 602afe267f2STomi Valkeinen 603afe267f2STomi Valkeinen mutex_lock(&priv->reg_lock); 604afe267f2STomi Valkeinen 605afe267f2STomi Valkeinen ret = regmap_read(priv->regmap, reg, &v); 606afe267f2STomi Valkeinen if (ret) { 607afe267f2STomi Valkeinen dev_err(dev, "%s: cannot read register 0x%02x (%d)!\n", 608afe267f2STomi Valkeinen __func__, reg, ret); 609afe267f2STomi Valkeinen goto out_unlock; 610afe267f2STomi Valkeinen } 611afe267f2STomi Valkeinen 612afe267f2STomi Valkeinen *val = v; 613afe267f2STomi Valkeinen 614afe267f2STomi Valkeinen out_unlock: 615afe267f2STomi Valkeinen mutex_unlock(&priv->reg_lock); 616afe267f2STomi Valkeinen 617afe267f2STomi Valkeinen return ret; 618afe267f2STomi Valkeinen } 619afe267f2STomi Valkeinen 620afe267f2STomi Valkeinen static int ub960_write(struct ub960_data *priv, u8 reg, u8 val) 621afe267f2STomi Valkeinen { 622afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 623afe267f2STomi Valkeinen int ret; 624afe267f2STomi Valkeinen 625afe267f2STomi Valkeinen mutex_lock(&priv->reg_lock); 626afe267f2STomi Valkeinen 627afe267f2STomi Valkeinen ret = regmap_write(priv->regmap, reg, val); 628afe267f2STomi Valkeinen if (ret) 629afe267f2STomi Valkeinen dev_err(dev, "%s: cannot write register 0x%02x (%d)!\n", 630afe267f2STomi Valkeinen __func__, reg, ret); 631afe267f2STomi Valkeinen 632afe267f2STomi Valkeinen mutex_unlock(&priv->reg_lock); 633afe267f2STomi Valkeinen 634afe267f2STomi Valkeinen return ret; 635afe267f2STomi Valkeinen } 636afe267f2STomi Valkeinen 637afe267f2STomi Valkeinen static int ub960_update_bits(struct ub960_data *priv, u8 reg, u8 mask, u8 val) 638afe267f2STomi Valkeinen { 639afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 640afe267f2STomi Valkeinen int ret; 641afe267f2STomi Valkeinen 642afe267f2STomi Valkeinen mutex_lock(&priv->reg_lock); 643afe267f2STomi Valkeinen 644afe267f2STomi Valkeinen ret = regmap_update_bits(priv->regmap, reg, mask, val); 645afe267f2STomi Valkeinen if (ret) 646afe267f2STomi Valkeinen dev_err(dev, "%s: cannot update register 0x%02x (%d)!\n", 647afe267f2STomi Valkeinen __func__, reg, ret); 648afe267f2STomi Valkeinen 649afe267f2STomi Valkeinen mutex_unlock(&priv->reg_lock); 650afe267f2STomi Valkeinen 651afe267f2STomi Valkeinen return ret; 652afe267f2STomi Valkeinen } 653afe267f2STomi Valkeinen 654afe267f2STomi Valkeinen static int ub960_read16(struct ub960_data *priv, u8 reg, u16 *val) 655afe267f2STomi Valkeinen { 656afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 657afe267f2STomi Valkeinen __be16 __v; 658afe267f2STomi Valkeinen int ret; 659afe267f2STomi Valkeinen 660afe267f2STomi Valkeinen mutex_lock(&priv->reg_lock); 661afe267f2STomi Valkeinen 662afe267f2STomi Valkeinen ret = regmap_bulk_read(priv->regmap, reg, &__v, sizeof(__v)); 663afe267f2STomi Valkeinen if (ret) { 664afe267f2STomi Valkeinen dev_err(dev, "%s: cannot read register 0x%02x (%d)!\n", 665afe267f2STomi Valkeinen __func__, reg, ret); 666afe267f2STomi Valkeinen goto out_unlock; 667afe267f2STomi Valkeinen } 668afe267f2STomi Valkeinen 669afe267f2STomi Valkeinen *val = be16_to_cpu(__v); 670afe267f2STomi Valkeinen 671afe267f2STomi Valkeinen out_unlock: 672afe267f2STomi Valkeinen mutex_unlock(&priv->reg_lock); 673afe267f2STomi Valkeinen 674afe267f2STomi Valkeinen return ret; 675afe267f2STomi Valkeinen } 676afe267f2STomi Valkeinen 677afe267f2STomi Valkeinen static int ub960_rxport_select(struct ub960_data *priv, u8 nport) 678afe267f2STomi Valkeinen { 679afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 680afe267f2STomi Valkeinen int ret; 681afe267f2STomi Valkeinen 682afe267f2STomi Valkeinen lockdep_assert_held(&priv->reg_lock); 683afe267f2STomi Valkeinen 684afe267f2STomi Valkeinen if (priv->reg_current.rxport == nport) 685afe267f2STomi Valkeinen return 0; 686afe267f2STomi Valkeinen 687afe267f2STomi Valkeinen ret = regmap_write(priv->regmap, UB960_SR_FPD3_PORT_SEL, 688afe267f2STomi Valkeinen (nport << 4) | BIT(nport)); 689afe267f2STomi Valkeinen if (ret) { 690afe267f2STomi Valkeinen dev_err(dev, "%s: cannot select rxport %d (%d)!\n", __func__, 691afe267f2STomi Valkeinen nport, ret); 692afe267f2STomi Valkeinen return ret; 693afe267f2STomi Valkeinen } 694afe267f2STomi Valkeinen 695afe267f2STomi Valkeinen priv->reg_current.rxport = nport; 696afe267f2STomi Valkeinen 697afe267f2STomi Valkeinen return 0; 698afe267f2STomi Valkeinen } 699afe267f2STomi Valkeinen 700afe267f2STomi Valkeinen static int ub960_rxport_read(struct ub960_data *priv, u8 nport, u8 reg, u8 *val) 701afe267f2STomi Valkeinen { 702afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 703afe267f2STomi Valkeinen unsigned int v; 704afe267f2STomi Valkeinen int ret; 705afe267f2STomi Valkeinen 706afe267f2STomi Valkeinen mutex_lock(&priv->reg_lock); 707afe267f2STomi Valkeinen 708afe267f2STomi Valkeinen ret = ub960_rxport_select(priv, nport); 709afe267f2STomi Valkeinen if (ret) 710afe267f2STomi Valkeinen goto out_unlock; 711afe267f2STomi Valkeinen 712afe267f2STomi Valkeinen ret = regmap_read(priv->regmap, reg, &v); 713afe267f2STomi Valkeinen if (ret) { 714afe267f2STomi Valkeinen dev_err(dev, "%s: cannot read register 0x%02x (%d)!\n", 715afe267f2STomi Valkeinen __func__, reg, ret); 716afe267f2STomi Valkeinen goto out_unlock; 717afe267f2STomi Valkeinen } 718afe267f2STomi Valkeinen 719afe267f2STomi Valkeinen *val = v; 720afe267f2STomi Valkeinen 721afe267f2STomi Valkeinen out_unlock: 722afe267f2STomi Valkeinen mutex_unlock(&priv->reg_lock); 723afe267f2STomi Valkeinen 724afe267f2STomi Valkeinen return ret; 725afe267f2STomi Valkeinen } 726afe267f2STomi Valkeinen 727afe267f2STomi Valkeinen static int ub960_rxport_write(struct ub960_data *priv, u8 nport, u8 reg, u8 val) 728afe267f2STomi Valkeinen { 729afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 730afe267f2STomi Valkeinen int ret; 731afe267f2STomi Valkeinen 732afe267f2STomi Valkeinen mutex_lock(&priv->reg_lock); 733afe267f2STomi Valkeinen 734afe267f2STomi Valkeinen ret = ub960_rxport_select(priv, nport); 735afe267f2STomi Valkeinen if (ret) 736afe267f2STomi Valkeinen goto out_unlock; 737afe267f2STomi Valkeinen 738afe267f2STomi Valkeinen ret = regmap_write(priv->regmap, reg, val); 739afe267f2STomi Valkeinen if (ret) 740afe267f2STomi Valkeinen dev_err(dev, "%s: cannot write register 0x%02x (%d)!\n", 741afe267f2STomi Valkeinen __func__, reg, ret); 742afe267f2STomi Valkeinen 743afe267f2STomi Valkeinen out_unlock: 744afe267f2STomi Valkeinen mutex_unlock(&priv->reg_lock); 745afe267f2STomi Valkeinen 746afe267f2STomi Valkeinen return ret; 747afe267f2STomi Valkeinen } 748afe267f2STomi Valkeinen 749afe267f2STomi Valkeinen static int ub960_rxport_update_bits(struct ub960_data *priv, u8 nport, u8 reg, 750afe267f2STomi Valkeinen u8 mask, u8 val) 751afe267f2STomi Valkeinen { 752afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 753afe267f2STomi Valkeinen int ret; 754afe267f2STomi Valkeinen 755afe267f2STomi Valkeinen mutex_lock(&priv->reg_lock); 756afe267f2STomi Valkeinen 757afe267f2STomi Valkeinen ret = ub960_rxport_select(priv, nport); 758afe267f2STomi Valkeinen if (ret) 759afe267f2STomi Valkeinen goto out_unlock; 760afe267f2STomi Valkeinen 761afe267f2STomi Valkeinen ret = regmap_update_bits(priv->regmap, reg, mask, val); 762afe267f2STomi Valkeinen if (ret) 763afe267f2STomi Valkeinen dev_err(dev, "%s: cannot update register 0x%02x (%d)!\n", 764afe267f2STomi Valkeinen __func__, reg, ret); 765afe267f2STomi Valkeinen 766afe267f2STomi Valkeinen out_unlock: 767afe267f2STomi Valkeinen mutex_unlock(&priv->reg_lock); 768afe267f2STomi Valkeinen 769afe267f2STomi Valkeinen return ret; 770afe267f2STomi Valkeinen } 771afe267f2STomi Valkeinen 772afe267f2STomi Valkeinen static int ub960_rxport_read16(struct ub960_data *priv, u8 nport, u8 reg, 773afe267f2STomi Valkeinen u16 *val) 774afe267f2STomi Valkeinen { 775afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 776afe267f2STomi Valkeinen __be16 __v; 777afe267f2STomi Valkeinen int ret; 778afe267f2STomi Valkeinen 779afe267f2STomi Valkeinen mutex_lock(&priv->reg_lock); 780afe267f2STomi Valkeinen 781afe267f2STomi Valkeinen ret = ub960_rxport_select(priv, nport); 782afe267f2STomi Valkeinen if (ret) 783afe267f2STomi Valkeinen goto out_unlock; 784afe267f2STomi Valkeinen 785afe267f2STomi Valkeinen ret = regmap_bulk_read(priv->regmap, reg, &__v, sizeof(__v)); 786afe267f2STomi Valkeinen if (ret) { 787afe267f2STomi Valkeinen dev_err(dev, "%s: cannot read register 0x%02x (%d)!\n", 788afe267f2STomi Valkeinen __func__, reg, ret); 789afe267f2STomi Valkeinen goto out_unlock; 790afe267f2STomi Valkeinen } 791afe267f2STomi Valkeinen 792afe267f2STomi Valkeinen *val = be16_to_cpu(__v); 793afe267f2STomi Valkeinen 794afe267f2STomi Valkeinen out_unlock: 795afe267f2STomi Valkeinen mutex_unlock(&priv->reg_lock); 796afe267f2STomi Valkeinen 797afe267f2STomi Valkeinen return ret; 798afe267f2STomi Valkeinen } 799afe267f2STomi Valkeinen 800afe267f2STomi Valkeinen static int ub960_txport_select(struct ub960_data *priv, u8 nport) 801afe267f2STomi Valkeinen { 802afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 803afe267f2STomi Valkeinen int ret; 804afe267f2STomi Valkeinen 805afe267f2STomi Valkeinen lockdep_assert_held(&priv->reg_lock); 806afe267f2STomi Valkeinen 807afe267f2STomi Valkeinen if (priv->reg_current.txport == nport) 808afe267f2STomi Valkeinen return 0; 809afe267f2STomi Valkeinen 810afe267f2STomi Valkeinen ret = regmap_write(priv->regmap, UB960_SR_CSI_PORT_SEL, 811afe267f2STomi Valkeinen (nport << 4) | BIT(nport)); 812afe267f2STomi Valkeinen if (ret) { 813afe267f2STomi Valkeinen dev_err(dev, "%s: cannot select tx port %d (%d)!\n", __func__, 814afe267f2STomi Valkeinen nport, ret); 815afe267f2STomi Valkeinen return ret; 816afe267f2STomi Valkeinen } 817afe267f2STomi Valkeinen 818afe267f2STomi Valkeinen priv->reg_current.txport = nport; 819afe267f2STomi Valkeinen 820afe267f2STomi Valkeinen return 0; 821afe267f2STomi Valkeinen } 822afe267f2STomi Valkeinen 823afe267f2STomi Valkeinen static int ub960_txport_read(struct ub960_data *priv, u8 nport, u8 reg, u8 *val) 824afe267f2STomi Valkeinen { 825afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 826afe267f2STomi Valkeinen unsigned int v; 827afe267f2STomi Valkeinen int ret; 828afe267f2STomi Valkeinen 829afe267f2STomi Valkeinen mutex_lock(&priv->reg_lock); 830afe267f2STomi Valkeinen 831afe267f2STomi Valkeinen ret = ub960_txport_select(priv, nport); 832afe267f2STomi Valkeinen if (ret) 833afe267f2STomi Valkeinen goto out_unlock; 834afe267f2STomi Valkeinen 835afe267f2STomi Valkeinen ret = regmap_read(priv->regmap, reg, &v); 836afe267f2STomi Valkeinen if (ret) { 837afe267f2STomi Valkeinen dev_err(dev, "%s: cannot read register 0x%02x (%d)!\n", 838afe267f2STomi Valkeinen __func__, reg, ret); 839afe267f2STomi Valkeinen goto out_unlock; 840afe267f2STomi Valkeinen } 841afe267f2STomi Valkeinen 842afe267f2STomi Valkeinen *val = v; 843afe267f2STomi Valkeinen 844afe267f2STomi Valkeinen out_unlock: 845afe267f2STomi Valkeinen mutex_unlock(&priv->reg_lock); 846afe267f2STomi Valkeinen 847afe267f2STomi Valkeinen return ret; 848afe267f2STomi Valkeinen } 849afe267f2STomi Valkeinen 850afe267f2STomi Valkeinen static int ub960_txport_write(struct ub960_data *priv, u8 nport, u8 reg, u8 val) 851afe267f2STomi Valkeinen { 852afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 853afe267f2STomi Valkeinen int ret; 854afe267f2STomi Valkeinen 855afe267f2STomi Valkeinen mutex_lock(&priv->reg_lock); 856afe267f2STomi Valkeinen 857afe267f2STomi Valkeinen ret = ub960_txport_select(priv, nport); 858afe267f2STomi Valkeinen if (ret) 859afe267f2STomi Valkeinen goto out_unlock; 860afe267f2STomi Valkeinen 861afe267f2STomi Valkeinen ret = regmap_write(priv->regmap, reg, val); 862afe267f2STomi Valkeinen if (ret) 863afe267f2STomi Valkeinen dev_err(dev, "%s: cannot write register 0x%02x (%d)!\n", 864afe267f2STomi Valkeinen __func__, reg, ret); 865afe267f2STomi Valkeinen 866afe267f2STomi Valkeinen out_unlock: 867afe267f2STomi Valkeinen mutex_unlock(&priv->reg_lock); 868afe267f2STomi Valkeinen 869afe267f2STomi Valkeinen return ret; 870afe267f2STomi Valkeinen } 871afe267f2STomi Valkeinen 872afe267f2STomi Valkeinen static int ub960_txport_update_bits(struct ub960_data *priv, u8 nport, u8 reg, 873afe267f2STomi Valkeinen u8 mask, u8 val) 874afe267f2STomi Valkeinen { 875afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 876afe267f2STomi Valkeinen int ret; 877afe267f2STomi Valkeinen 878afe267f2STomi Valkeinen mutex_lock(&priv->reg_lock); 879afe267f2STomi Valkeinen 880afe267f2STomi Valkeinen ret = ub960_txport_select(priv, nport); 881afe267f2STomi Valkeinen if (ret) 882afe267f2STomi Valkeinen goto out_unlock; 883afe267f2STomi Valkeinen 884afe267f2STomi Valkeinen ret = regmap_update_bits(priv->regmap, reg, mask, val); 885afe267f2STomi Valkeinen if (ret) 886afe267f2STomi Valkeinen dev_err(dev, "%s: cannot update register 0x%02x (%d)!\n", 887afe267f2STomi Valkeinen __func__, reg, ret); 888afe267f2STomi Valkeinen 889afe267f2STomi Valkeinen out_unlock: 890afe267f2STomi Valkeinen mutex_unlock(&priv->reg_lock); 891afe267f2STomi Valkeinen 892afe267f2STomi Valkeinen return ret; 893afe267f2STomi Valkeinen } 894afe267f2STomi Valkeinen 895afe267f2STomi Valkeinen static int ub960_select_ind_reg_block(struct ub960_data *priv, u8 block) 896afe267f2STomi Valkeinen { 897afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 898afe267f2STomi Valkeinen int ret; 899afe267f2STomi Valkeinen 900afe267f2STomi Valkeinen lockdep_assert_held(&priv->reg_lock); 901afe267f2STomi Valkeinen 902afe267f2STomi Valkeinen if (priv->reg_current.indirect_target == block) 903afe267f2STomi Valkeinen return 0; 904afe267f2STomi Valkeinen 905afe267f2STomi Valkeinen ret = regmap_write(priv->regmap, UB960_SR_IND_ACC_CTL, block << 2); 906afe267f2STomi Valkeinen if (ret) { 907afe267f2STomi Valkeinen dev_err(dev, "%s: cannot select indirect target %u (%d)!\n", 908afe267f2STomi Valkeinen __func__, block, ret); 909afe267f2STomi Valkeinen return ret; 910afe267f2STomi Valkeinen } 911afe267f2STomi Valkeinen 912afe267f2STomi Valkeinen priv->reg_current.indirect_target = block; 913afe267f2STomi Valkeinen 914afe267f2STomi Valkeinen return 0; 915afe267f2STomi Valkeinen } 916afe267f2STomi Valkeinen 917afe267f2STomi Valkeinen static int ub960_read_ind(struct ub960_data *priv, u8 block, u8 reg, u8 *val) 918afe267f2STomi Valkeinen { 919afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 920afe267f2STomi Valkeinen unsigned int v; 921afe267f2STomi Valkeinen int ret; 922afe267f2STomi Valkeinen 923afe267f2STomi Valkeinen mutex_lock(&priv->reg_lock); 924afe267f2STomi Valkeinen 925afe267f2STomi Valkeinen ret = ub960_select_ind_reg_block(priv, block); 926afe267f2STomi Valkeinen if (ret) 927afe267f2STomi Valkeinen goto out_unlock; 928afe267f2STomi Valkeinen 929afe267f2STomi Valkeinen ret = regmap_write(priv->regmap, UB960_SR_IND_ACC_ADDR, reg); 930afe267f2STomi Valkeinen if (ret) { 931afe267f2STomi Valkeinen dev_err(dev, 932afe267f2STomi Valkeinen "Write to IND_ACC_ADDR failed when reading %u:%x02x: %d\n", 933afe267f2STomi Valkeinen block, reg, ret); 934afe267f2STomi Valkeinen goto out_unlock; 935afe267f2STomi Valkeinen } 936afe267f2STomi Valkeinen 937afe267f2STomi Valkeinen ret = regmap_read(priv->regmap, UB960_SR_IND_ACC_DATA, &v); 938afe267f2STomi Valkeinen if (ret) { 939afe267f2STomi Valkeinen dev_err(dev, 940afe267f2STomi Valkeinen "Write to IND_ACC_DATA failed when reading %u:%x02x: %d\n", 941afe267f2STomi Valkeinen block, reg, ret); 942afe267f2STomi Valkeinen goto out_unlock; 943afe267f2STomi Valkeinen } 944afe267f2STomi Valkeinen 945afe267f2STomi Valkeinen *val = v; 946afe267f2STomi Valkeinen 947afe267f2STomi Valkeinen out_unlock: 948afe267f2STomi Valkeinen mutex_unlock(&priv->reg_lock); 949afe267f2STomi Valkeinen 950afe267f2STomi Valkeinen return ret; 951afe267f2STomi Valkeinen } 952afe267f2STomi Valkeinen 953afe267f2STomi Valkeinen static int ub960_write_ind(struct ub960_data *priv, u8 block, u8 reg, u8 val) 954afe267f2STomi Valkeinen { 955afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 956afe267f2STomi Valkeinen int ret; 957afe267f2STomi Valkeinen 958afe267f2STomi Valkeinen mutex_lock(&priv->reg_lock); 959afe267f2STomi Valkeinen 960afe267f2STomi Valkeinen ret = ub960_select_ind_reg_block(priv, block); 961afe267f2STomi Valkeinen if (ret) 962afe267f2STomi Valkeinen goto out_unlock; 963afe267f2STomi Valkeinen 964afe267f2STomi Valkeinen ret = regmap_write(priv->regmap, UB960_SR_IND_ACC_ADDR, reg); 965afe267f2STomi Valkeinen if (ret) { 966afe267f2STomi Valkeinen dev_err(dev, 967afe267f2STomi Valkeinen "Write to IND_ACC_ADDR failed when writing %u:%x02x: %d\n", 968afe267f2STomi Valkeinen block, reg, ret); 969afe267f2STomi Valkeinen goto out_unlock; 970afe267f2STomi Valkeinen } 971afe267f2STomi Valkeinen 972afe267f2STomi Valkeinen ret = regmap_write(priv->regmap, UB960_SR_IND_ACC_DATA, val); 973afe267f2STomi Valkeinen if (ret) { 974afe267f2STomi Valkeinen dev_err(dev, 975afe267f2STomi Valkeinen "Write to IND_ACC_DATA failed when writing %u:%x02x: %d\n", 976afe267f2STomi Valkeinen block, reg, ret); 977afe267f2STomi Valkeinen goto out_unlock; 978afe267f2STomi Valkeinen } 979afe267f2STomi Valkeinen 980afe267f2STomi Valkeinen out_unlock: 981afe267f2STomi Valkeinen mutex_unlock(&priv->reg_lock); 982afe267f2STomi Valkeinen 983afe267f2STomi Valkeinen return ret; 984afe267f2STomi Valkeinen } 985afe267f2STomi Valkeinen 986afe267f2STomi Valkeinen static int ub960_ind_update_bits(struct ub960_data *priv, u8 block, u8 reg, 987afe267f2STomi Valkeinen u8 mask, u8 val) 988afe267f2STomi Valkeinen { 989afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 990afe267f2STomi Valkeinen int ret; 991afe267f2STomi Valkeinen 992afe267f2STomi Valkeinen mutex_lock(&priv->reg_lock); 993afe267f2STomi Valkeinen 994afe267f2STomi Valkeinen ret = ub960_select_ind_reg_block(priv, block); 995afe267f2STomi Valkeinen if (ret) 996afe267f2STomi Valkeinen goto out_unlock; 997afe267f2STomi Valkeinen 998afe267f2STomi Valkeinen ret = regmap_write(priv->regmap, UB960_SR_IND_ACC_ADDR, reg); 999afe267f2STomi Valkeinen if (ret) { 1000afe267f2STomi Valkeinen dev_err(dev, 1001afe267f2STomi Valkeinen "Write to IND_ACC_ADDR failed when updating %u:%x02x: %d\n", 1002afe267f2STomi Valkeinen block, reg, ret); 1003afe267f2STomi Valkeinen goto out_unlock; 1004afe267f2STomi Valkeinen } 1005afe267f2STomi Valkeinen 1006afe267f2STomi Valkeinen ret = regmap_update_bits(priv->regmap, UB960_SR_IND_ACC_DATA, mask, 1007afe267f2STomi Valkeinen val); 1008afe267f2STomi Valkeinen if (ret) { 1009afe267f2STomi Valkeinen dev_err(dev, 1010afe267f2STomi Valkeinen "Write to IND_ACC_DATA failed when updating %u:%x02x: %d\n", 1011afe267f2STomi Valkeinen block, reg, ret); 1012afe267f2STomi Valkeinen goto out_unlock; 1013afe267f2STomi Valkeinen } 1014afe267f2STomi Valkeinen 1015afe267f2STomi Valkeinen out_unlock: 1016afe267f2STomi Valkeinen mutex_unlock(&priv->reg_lock); 1017afe267f2STomi Valkeinen 1018afe267f2STomi Valkeinen return ret; 1019afe267f2STomi Valkeinen } 1020afe267f2STomi Valkeinen 1021afe267f2STomi Valkeinen /* ----------------------------------------------------------------------------- 1022afe267f2STomi Valkeinen * I2C-ATR (address translator) 1023afe267f2STomi Valkeinen */ 1024afe267f2STomi Valkeinen 1025afe267f2STomi Valkeinen static int ub960_atr_attach_client(struct i2c_atr *atr, u32 chan_id, 1026afe267f2STomi Valkeinen const struct i2c_client *client, u16 alias) 1027afe267f2STomi Valkeinen { 1028afe267f2STomi Valkeinen struct ub960_data *priv = i2c_atr_get_driver_data(atr); 1029afe267f2STomi Valkeinen struct ub960_rxport *rxport = priv->rxports[chan_id]; 1030afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 1031afe267f2STomi Valkeinen unsigned int reg_idx; 1032afe267f2STomi Valkeinen 1033afe267f2STomi Valkeinen for (reg_idx = 0; reg_idx < ARRAY_SIZE(rxport->aliased_clients); reg_idx++) { 1034afe267f2STomi Valkeinen if (!rxport->aliased_clients[reg_idx]) 1035afe267f2STomi Valkeinen break; 1036afe267f2STomi Valkeinen } 1037afe267f2STomi Valkeinen 1038afe267f2STomi Valkeinen if (reg_idx == ARRAY_SIZE(rxport->aliased_clients)) { 1039afe267f2STomi Valkeinen dev_err(dev, "rx%u: alias pool exhausted\n", rxport->nport); 1040afe267f2STomi Valkeinen return -EADDRNOTAVAIL; 1041afe267f2STomi Valkeinen } 1042afe267f2STomi Valkeinen 1043afe267f2STomi Valkeinen rxport->aliased_clients[reg_idx] = client; 1044afe267f2STomi Valkeinen 1045afe267f2STomi Valkeinen ub960_rxport_write(priv, chan_id, UB960_RR_SLAVE_ID(reg_idx), 1046afe267f2STomi Valkeinen client->addr << 1); 1047afe267f2STomi Valkeinen ub960_rxport_write(priv, chan_id, UB960_RR_SLAVE_ALIAS(reg_idx), 1048afe267f2STomi Valkeinen alias << 1); 1049afe267f2STomi Valkeinen 1050afe267f2STomi Valkeinen dev_dbg(dev, "rx%u: client 0x%02x assigned alias 0x%02x at slot %u\n", 1051afe267f2STomi Valkeinen rxport->nport, client->addr, alias, reg_idx); 1052afe267f2STomi Valkeinen 1053afe267f2STomi Valkeinen return 0; 1054afe267f2STomi Valkeinen } 1055afe267f2STomi Valkeinen 1056afe267f2STomi Valkeinen static void ub960_atr_detach_client(struct i2c_atr *atr, u32 chan_id, 1057afe267f2STomi Valkeinen const struct i2c_client *client) 1058afe267f2STomi Valkeinen { 1059afe267f2STomi Valkeinen struct ub960_data *priv = i2c_atr_get_driver_data(atr); 1060afe267f2STomi Valkeinen struct ub960_rxport *rxport = priv->rxports[chan_id]; 1061afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 1062afe267f2STomi Valkeinen unsigned int reg_idx; 1063afe267f2STomi Valkeinen 1064afe267f2STomi Valkeinen for (reg_idx = 0; reg_idx < ARRAY_SIZE(rxport->aliased_clients); reg_idx++) { 1065afe267f2STomi Valkeinen if (rxport->aliased_clients[reg_idx] == client) 1066afe267f2STomi Valkeinen break; 1067afe267f2STomi Valkeinen } 1068afe267f2STomi Valkeinen 1069afe267f2STomi Valkeinen if (reg_idx == ARRAY_SIZE(rxport->aliased_clients)) { 1070afe267f2STomi Valkeinen dev_err(dev, "rx%u: client 0x%02x is not mapped!\n", 1071afe267f2STomi Valkeinen rxport->nport, client->addr); 1072afe267f2STomi Valkeinen return; 1073afe267f2STomi Valkeinen } 1074afe267f2STomi Valkeinen 1075afe267f2STomi Valkeinen rxport->aliased_clients[reg_idx] = NULL; 1076afe267f2STomi Valkeinen 1077afe267f2STomi Valkeinen ub960_rxport_write(priv, chan_id, UB960_RR_SLAVE_ALIAS(reg_idx), 0); 1078afe267f2STomi Valkeinen 1079afe267f2STomi Valkeinen dev_dbg(dev, "rx%u: client 0x%02x released at slot %u\n", rxport->nport, 1080afe267f2STomi Valkeinen client->addr, reg_idx); 1081afe267f2STomi Valkeinen } 1082afe267f2STomi Valkeinen 1083afe267f2STomi Valkeinen static const struct i2c_atr_ops ub960_atr_ops = { 1084afe267f2STomi Valkeinen .attach_client = ub960_atr_attach_client, 1085afe267f2STomi Valkeinen .detach_client = ub960_atr_detach_client, 1086afe267f2STomi Valkeinen }; 1087afe267f2STomi Valkeinen 1088afe267f2STomi Valkeinen static int ub960_init_atr(struct ub960_data *priv) 1089afe267f2STomi Valkeinen { 1090afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 1091afe267f2STomi Valkeinen struct i2c_adapter *parent_adap = priv->client->adapter; 1092afe267f2STomi Valkeinen 1093afe267f2STomi Valkeinen priv->atr = i2c_atr_new(parent_adap, dev, &ub960_atr_ops, 1094afe267f2STomi Valkeinen priv->hw_data->num_rxports); 1095afe267f2STomi Valkeinen if (IS_ERR(priv->atr)) 1096afe267f2STomi Valkeinen return PTR_ERR(priv->atr); 1097afe267f2STomi Valkeinen 1098afe267f2STomi Valkeinen i2c_atr_set_driver_data(priv->atr, priv); 1099afe267f2STomi Valkeinen 1100afe267f2STomi Valkeinen return 0; 1101afe267f2STomi Valkeinen } 1102afe267f2STomi Valkeinen 1103afe267f2STomi Valkeinen static void ub960_uninit_atr(struct ub960_data *priv) 1104afe267f2STomi Valkeinen { 1105afe267f2STomi Valkeinen i2c_atr_delete(priv->atr); 1106afe267f2STomi Valkeinen priv->atr = NULL; 1107afe267f2STomi Valkeinen } 1108afe267f2STomi Valkeinen 1109afe267f2STomi Valkeinen /* ----------------------------------------------------------------------------- 1110afe267f2STomi Valkeinen * TX ports 1111afe267f2STomi Valkeinen */ 1112afe267f2STomi Valkeinen 1113afe267f2STomi Valkeinen static int ub960_parse_dt_txport(struct ub960_data *priv, 1114afe267f2STomi Valkeinen struct fwnode_handle *ep_fwnode, 1115afe267f2STomi Valkeinen u8 nport) 1116afe267f2STomi Valkeinen { 1117afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 1118afe267f2STomi Valkeinen struct v4l2_fwnode_endpoint vep = {}; 1119afe267f2STomi Valkeinen struct ub960_txport *txport; 1120afe267f2STomi Valkeinen int ret; 1121afe267f2STomi Valkeinen 1122afe267f2STomi Valkeinen txport = kzalloc(sizeof(*txport), GFP_KERNEL); 1123afe267f2STomi Valkeinen if (!txport) 1124afe267f2STomi Valkeinen return -ENOMEM; 1125afe267f2STomi Valkeinen 1126afe267f2STomi Valkeinen txport->priv = priv; 1127afe267f2STomi Valkeinen txport->nport = nport; 1128afe267f2STomi Valkeinen 1129afe267f2STomi Valkeinen vep.bus_type = V4L2_MBUS_CSI2_DPHY; 1130afe267f2STomi Valkeinen ret = v4l2_fwnode_endpoint_alloc_parse(ep_fwnode, &vep); 1131afe267f2STomi Valkeinen if (ret) { 1132afe267f2STomi Valkeinen dev_err(dev, "tx%u: failed to parse endpoint data\n", nport); 1133afe267f2STomi Valkeinen goto err_free_txport; 1134afe267f2STomi Valkeinen } 1135afe267f2STomi Valkeinen 1136afe267f2STomi Valkeinen txport->num_data_lanes = vep.bus.mipi_csi2.num_data_lanes; 1137afe267f2STomi Valkeinen 1138afe267f2STomi Valkeinen if (vep.nr_of_link_frequencies != 1) { 1139afe267f2STomi Valkeinen ret = -EINVAL; 1140afe267f2STomi Valkeinen goto err_free_vep; 1141afe267f2STomi Valkeinen } 1142afe267f2STomi Valkeinen 1143afe267f2STomi Valkeinen priv->tx_link_freq[0] = vep.link_frequencies[0]; 1144afe267f2STomi Valkeinen priv->tx_data_rate = priv->tx_link_freq[0] * 2; 1145afe267f2STomi Valkeinen 1146afe267f2STomi Valkeinen if (priv->tx_data_rate != MHZ(1600) && 1147afe267f2STomi Valkeinen priv->tx_data_rate != MHZ(1200) && 1148afe267f2STomi Valkeinen priv->tx_data_rate != MHZ(800) && 1149afe267f2STomi Valkeinen priv->tx_data_rate != MHZ(400)) { 1150afe267f2STomi Valkeinen dev_err(dev, "tx%u: invalid 'link-frequencies' value\n", nport); 1151afe267f2STomi Valkeinen ret = -EINVAL; 1152afe267f2STomi Valkeinen goto err_free_vep; 1153afe267f2STomi Valkeinen } 1154afe267f2STomi Valkeinen 1155afe267f2STomi Valkeinen v4l2_fwnode_endpoint_free(&vep); 1156afe267f2STomi Valkeinen 1157afe267f2STomi Valkeinen priv->txports[nport] = txport; 1158afe267f2STomi Valkeinen 1159afe267f2STomi Valkeinen return 0; 1160afe267f2STomi Valkeinen 1161afe267f2STomi Valkeinen err_free_vep: 1162afe267f2STomi Valkeinen v4l2_fwnode_endpoint_free(&vep); 1163afe267f2STomi Valkeinen err_free_txport: 1164afe267f2STomi Valkeinen kfree(txport); 1165afe267f2STomi Valkeinen 1166afe267f2STomi Valkeinen return ret; 1167afe267f2STomi Valkeinen } 1168afe267f2STomi Valkeinen 1169afe267f2STomi Valkeinen static void ub960_csi_handle_events(struct ub960_data *priv, u8 nport) 1170afe267f2STomi Valkeinen { 1171afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 1172afe267f2STomi Valkeinen u8 csi_tx_isr; 1173afe267f2STomi Valkeinen int ret; 1174afe267f2STomi Valkeinen 1175afe267f2STomi Valkeinen ret = ub960_txport_read(priv, nport, UB960_TR_CSI_TX_ISR, &csi_tx_isr); 1176afe267f2STomi Valkeinen if (ret) 1177afe267f2STomi Valkeinen return; 1178afe267f2STomi Valkeinen 1179afe267f2STomi Valkeinen if (csi_tx_isr & UB960_TR_CSI_TX_ISR_IS_CSI_SYNC_ERROR) 1180afe267f2STomi Valkeinen dev_warn(dev, "TX%u: CSI_SYNC_ERROR\n", nport); 1181afe267f2STomi Valkeinen 1182afe267f2STomi Valkeinen if (csi_tx_isr & UB960_TR_CSI_TX_ISR_IS_CSI_PASS_ERROR) 1183afe267f2STomi Valkeinen dev_warn(dev, "TX%u: CSI_PASS_ERROR\n", nport); 1184afe267f2STomi Valkeinen } 1185afe267f2STomi Valkeinen 1186afe267f2STomi Valkeinen /* ----------------------------------------------------------------------------- 1187afe267f2STomi Valkeinen * RX ports 1188afe267f2STomi Valkeinen */ 1189afe267f2STomi Valkeinen 1190afe267f2STomi Valkeinen static int ub960_rxport_enable_vpocs(struct ub960_data *priv) 1191afe267f2STomi Valkeinen { 1192afe267f2STomi Valkeinen unsigned int nport; 1193afe267f2STomi Valkeinen int ret; 1194afe267f2STomi Valkeinen 1195afe267f2STomi Valkeinen for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { 1196afe267f2STomi Valkeinen struct ub960_rxport *rxport = priv->rxports[nport]; 1197afe267f2STomi Valkeinen 1198afe267f2STomi Valkeinen if (!rxport || !rxport->vpoc) 1199afe267f2STomi Valkeinen continue; 1200afe267f2STomi Valkeinen 1201afe267f2STomi Valkeinen ret = regulator_enable(rxport->vpoc); 1202afe267f2STomi Valkeinen if (ret) 1203afe267f2STomi Valkeinen goto err_disable_vpocs; 1204afe267f2STomi Valkeinen } 1205afe267f2STomi Valkeinen 1206afe267f2STomi Valkeinen return 0; 1207afe267f2STomi Valkeinen 1208afe267f2STomi Valkeinen err_disable_vpocs: 1209afe267f2STomi Valkeinen while (nport--) { 1210afe267f2STomi Valkeinen struct ub960_rxport *rxport = priv->rxports[nport]; 1211afe267f2STomi Valkeinen 1212afe267f2STomi Valkeinen if (!rxport || !rxport->vpoc) 1213afe267f2STomi Valkeinen continue; 1214afe267f2STomi Valkeinen 1215afe267f2STomi Valkeinen regulator_disable(rxport->vpoc); 1216afe267f2STomi Valkeinen } 1217afe267f2STomi Valkeinen 1218afe267f2STomi Valkeinen return ret; 1219afe267f2STomi Valkeinen } 1220afe267f2STomi Valkeinen 1221afe267f2STomi Valkeinen static void ub960_rxport_disable_vpocs(struct ub960_data *priv) 1222afe267f2STomi Valkeinen { 1223afe267f2STomi Valkeinen unsigned int nport; 1224afe267f2STomi Valkeinen 1225afe267f2STomi Valkeinen for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { 1226afe267f2STomi Valkeinen struct ub960_rxport *rxport = priv->rxports[nport]; 1227afe267f2STomi Valkeinen 1228afe267f2STomi Valkeinen if (!rxport || !rxport->vpoc) 1229afe267f2STomi Valkeinen continue; 1230afe267f2STomi Valkeinen 1231afe267f2STomi Valkeinen regulator_disable(rxport->vpoc); 1232afe267f2STomi Valkeinen } 1233afe267f2STomi Valkeinen } 1234afe267f2STomi Valkeinen 1235afe267f2STomi Valkeinen static void ub960_rxport_clear_errors(struct ub960_data *priv, 1236afe267f2STomi Valkeinen unsigned int nport) 1237afe267f2STomi Valkeinen { 1238afe267f2STomi Valkeinen u8 v; 1239afe267f2STomi Valkeinen 1240afe267f2STomi Valkeinen ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, &v); 1241afe267f2STomi Valkeinen ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2, &v); 1242afe267f2STomi Valkeinen ub960_rxport_read(priv, nport, UB960_RR_CSI_RX_STS, &v); 1243afe267f2STomi Valkeinen ub960_rxport_read(priv, nport, UB960_RR_BCC_STATUS, &v); 1244afe267f2STomi Valkeinen 1245afe267f2STomi Valkeinen ub960_rxport_read(priv, nport, UB960_RR_RX_PAR_ERR_HI, &v); 1246afe267f2STomi Valkeinen ub960_rxport_read(priv, nport, UB960_RR_RX_PAR_ERR_LO, &v); 1247afe267f2STomi Valkeinen 1248afe267f2STomi Valkeinen ub960_rxport_read(priv, nport, UB960_RR_CSI_ERR_COUNTER, &v); 1249afe267f2STomi Valkeinen } 1250afe267f2STomi Valkeinen 1251afe267f2STomi Valkeinen static void ub960_clear_rx_errors(struct ub960_data *priv) 1252afe267f2STomi Valkeinen { 1253afe267f2STomi Valkeinen unsigned int nport; 1254afe267f2STomi Valkeinen 1255afe267f2STomi Valkeinen for (nport = 0; nport < priv->hw_data->num_rxports; nport++) 1256afe267f2STomi Valkeinen ub960_rxport_clear_errors(priv, nport); 1257afe267f2STomi Valkeinen } 1258afe267f2STomi Valkeinen 1259afe267f2STomi Valkeinen static int ub960_rxport_get_strobe_pos(struct ub960_data *priv, 1260afe267f2STomi Valkeinen unsigned int nport, s8 *strobe_pos) 1261afe267f2STomi Valkeinen { 1262afe267f2STomi Valkeinen u8 v; 1263afe267f2STomi Valkeinen u8 clk_delay, data_delay; 1264afe267f2STomi Valkeinen int ret; 1265afe267f2STomi Valkeinen 1266afe267f2STomi Valkeinen ub960_read_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 1267afe267f2STomi Valkeinen UB960_IR_RX_ANA_STROBE_SET_CLK, &v); 1268afe267f2STomi Valkeinen 1269afe267f2STomi Valkeinen clk_delay = (v & UB960_IR_RX_ANA_STROBE_SET_CLK_NO_EXTRA_DELAY) ? 1270afe267f2STomi Valkeinen 0 : UB960_MANUAL_STROBE_EXTRA_DELAY; 1271afe267f2STomi Valkeinen 1272afe267f2STomi Valkeinen ub960_read_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 1273afe267f2STomi Valkeinen UB960_IR_RX_ANA_STROBE_SET_DATA, &v); 1274afe267f2STomi Valkeinen 1275afe267f2STomi Valkeinen data_delay = (v & UB960_IR_RX_ANA_STROBE_SET_DATA_NO_EXTRA_DELAY) ? 1276afe267f2STomi Valkeinen 0 : UB960_MANUAL_STROBE_EXTRA_DELAY; 1277afe267f2STomi Valkeinen 1278afe267f2STomi Valkeinen ret = ub960_rxport_read(priv, nport, UB960_RR_SFILTER_STS_0, &v); 1279afe267f2STomi Valkeinen if (ret) 1280afe267f2STomi Valkeinen return ret; 1281afe267f2STomi Valkeinen 1282afe267f2STomi Valkeinen clk_delay += v & UB960_IR_RX_ANA_STROBE_SET_CLK_DELAY_MASK; 1283afe267f2STomi Valkeinen 1284afe267f2STomi Valkeinen ub960_rxport_read(priv, nport, UB960_RR_SFILTER_STS_1, &v); 1285afe267f2STomi Valkeinen if (ret) 1286afe267f2STomi Valkeinen return ret; 1287afe267f2STomi Valkeinen 1288afe267f2STomi Valkeinen data_delay += v & UB960_IR_RX_ANA_STROBE_SET_DATA_DELAY_MASK; 1289afe267f2STomi Valkeinen 1290afe267f2STomi Valkeinen *strobe_pos = data_delay - clk_delay; 1291afe267f2STomi Valkeinen 1292afe267f2STomi Valkeinen return 0; 1293afe267f2STomi Valkeinen } 1294afe267f2STomi Valkeinen 1295afe267f2STomi Valkeinen static void ub960_rxport_set_strobe_pos(struct ub960_data *priv, 1296afe267f2STomi Valkeinen unsigned int nport, s8 strobe_pos) 1297afe267f2STomi Valkeinen { 1298afe267f2STomi Valkeinen u8 clk_delay, data_delay; 1299afe267f2STomi Valkeinen 1300afe267f2STomi Valkeinen clk_delay = UB960_IR_RX_ANA_STROBE_SET_CLK_NO_EXTRA_DELAY; 1301afe267f2STomi Valkeinen data_delay = UB960_IR_RX_ANA_STROBE_SET_DATA_NO_EXTRA_DELAY; 1302afe267f2STomi Valkeinen 1303afe267f2STomi Valkeinen if (strobe_pos < UB960_MIN_AEQ_STROBE_POS) 1304afe267f2STomi Valkeinen clk_delay = abs(strobe_pos) - UB960_MANUAL_STROBE_EXTRA_DELAY; 1305afe267f2STomi Valkeinen else if (strobe_pos > UB960_MAX_AEQ_STROBE_POS) 1306afe267f2STomi Valkeinen data_delay = strobe_pos - UB960_MANUAL_STROBE_EXTRA_DELAY; 1307afe267f2STomi Valkeinen else if (strobe_pos < 0) 1308afe267f2STomi Valkeinen clk_delay = abs(strobe_pos) | UB960_IR_RX_ANA_STROBE_SET_CLK_NO_EXTRA_DELAY; 1309afe267f2STomi Valkeinen else if (strobe_pos > 0) 1310afe267f2STomi Valkeinen data_delay = strobe_pos | UB960_IR_RX_ANA_STROBE_SET_DATA_NO_EXTRA_DELAY; 1311afe267f2STomi Valkeinen 1312afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 1313afe267f2STomi Valkeinen UB960_IR_RX_ANA_STROBE_SET_CLK, clk_delay); 1314afe267f2STomi Valkeinen 1315afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 1316afe267f2STomi Valkeinen UB960_IR_RX_ANA_STROBE_SET_DATA, data_delay); 1317afe267f2STomi Valkeinen } 1318afe267f2STomi Valkeinen 1319afe267f2STomi Valkeinen static void ub960_rxport_set_strobe_range(struct ub960_data *priv, 1320afe267f2STomi Valkeinen s8 strobe_min, s8 strobe_max) 1321afe267f2STomi Valkeinen { 1322afe267f2STomi Valkeinen /* Convert the signed strobe pos to positive zero based value */ 1323afe267f2STomi Valkeinen strobe_min -= UB960_MIN_AEQ_STROBE_POS; 1324afe267f2STomi Valkeinen strobe_max -= UB960_MIN_AEQ_STROBE_POS; 1325afe267f2STomi Valkeinen 1326afe267f2STomi Valkeinen ub960_write(priv, UB960_XR_SFILTER_CFG, 1327afe267f2STomi Valkeinen ((u8)strobe_min << UB960_XR_SFILTER_CFG_SFILTER_MIN_SHIFT) | 1328afe267f2STomi Valkeinen ((u8)strobe_max << UB960_XR_SFILTER_CFG_SFILTER_MAX_SHIFT)); 1329afe267f2STomi Valkeinen } 1330afe267f2STomi Valkeinen 1331afe267f2STomi Valkeinen static int ub960_rxport_get_eq_level(struct ub960_data *priv, 1332afe267f2STomi Valkeinen unsigned int nport, u8 *eq_level) 1333afe267f2STomi Valkeinen { 1334afe267f2STomi Valkeinen int ret; 1335afe267f2STomi Valkeinen u8 v; 1336afe267f2STomi Valkeinen 1337afe267f2STomi Valkeinen ret = ub960_rxport_read(priv, nport, UB960_RR_AEQ_STATUS, &v); 1338afe267f2STomi Valkeinen if (ret) 1339afe267f2STomi Valkeinen return ret; 1340afe267f2STomi Valkeinen 1341afe267f2STomi Valkeinen *eq_level = (v & UB960_RR_AEQ_STATUS_STATUS_1) + 1342afe267f2STomi Valkeinen (v & UB960_RR_AEQ_STATUS_STATUS_2); 1343afe267f2STomi Valkeinen 1344afe267f2STomi Valkeinen return 0; 1345afe267f2STomi Valkeinen } 1346afe267f2STomi Valkeinen 1347afe267f2STomi Valkeinen static void ub960_rxport_set_eq_level(struct ub960_data *priv, 1348afe267f2STomi Valkeinen unsigned int nport, u8 eq_level) 1349afe267f2STomi Valkeinen { 1350afe267f2STomi Valkeinen u8 eq_stage_1_select_value, eq_stage_2_select_value; 1351afe267f2STomi Valkeinen const unsigned int eq_stage_max = 7; 1352afe267f2STomi Valkeinen u8 v; 1353afe267f2STomi Valkeinen 1354afe267f2STomi Valkeinen if (eq_level <= eq_stage_max) { 1355afe267f2STomi Valkeinen eq_stage_1_select_value = eq_level; 1356afe267f2STomi Valkeinen eq_stage_2_select_value = 0; 1357afe267f2STomi Valkeinen } else { 1358afe267f2STomi Valkeinen eq_stage_1_select_value = eq_stage_max; 1359afe267f2STomi Valkeinen eq_stage_2_select_value = eq_level - eq_stage_max; 1360afe267f2STomi Valkeinen } 1361afe267f2STomi Valkeinen 1362afe267f2STomi Valkeinen ub960_rxport_read(priv, nport, UB960_RR_AEQ_BYPASS, &v); 1363afe267f2STomi Valkeinen 1364afe267f2STomi Valkeinen v &= ~(UB960_RR_AEQ_BYPASS_EQ_STAGE1_VALUE_MASK | 1365afe267f2STomi Valkeinen UB960_RR_AEQ_BYPASS_EQ_STAGE2_VALUE_MASK); 1366afe267f2STomi Valkeinen v |= eq_stage_1_select_value << UB960_RR_AEQ_BYPASS_EQ_STAGE1_VALUE_SHIFT; 1367afe267f2STomi Valkeinen v |= eq_stage_2_select_value << UB960_RR_AEQ_BYPASS_EQ_STAGE2_VALUE_SHIFT; 1368afe267f2STomi Valkeinen v |= UB960_RR_AEQ_BYPASS_ENABLE; 1369afe267f2STomi Valkeinen 1370afe267f2STomi Valkeinen ub960_rxport_write(priv, nport, UB960_RR_AEQ_BYPASS, v); 1371afe267f2STomi Valkeinen } 1372afe267f2STomi Valkeinen 1373afe267f2STomi Valkeinen static void ub960_rxport_set_eq_range(struct ub960_data *priv, 1374afe267f2STomi Valkeinen unsigned int nport, u8 eq_min, u8 eq_max) 1375afe267f2STomi Valkeinen { 1376afe267f2STomi Valkeinen ub960_rxport_write(priv, nport, UB960_RR_AEQ_MIN_MAX, 1377afe267f2STomi Valkeinen (eq_min << UB960_RR_AEQ_MIN_MAX_AEQ_FLOOR_SHIFT) | 1378afe267f2STomi Valkeinen (eq_max << UB960_RR_AEQ_MIN_MAX_AEQ_MAX_SHIFT)); 1379afe267f2STomi Valkeinen 1380afe267f2STomi Valkeinen /* Enable AEQ min setting */ 1381afe267f2STomi Valkeinen ub960_rxport_update_bits(priv, nport, UB960_RR_AEQ_CTL2, 1382afe267f2STomi Valkeinen UB960_RR_AEQ_CTL2_SET_AEQ_FLOOR, 1383afe267f2STomi Valkeinen UB960_RR_AEQ_CTL2_SET_AEQ_FLOOR); 1384afe267f2STomi Valkeinen } 1385afe267f2STomi Valkeinen 1386afe267f2STomi Valkeinen static void ub960_rxport_config_eq(struct ub960_data *priv, unsigned int nport) 1387afe267f2STomi Valkeinen { 1388afe267f2STomi Valkeinen struct ub960_rxport *rxport = priv->rxports[nport]; 1389afe267f2STomi Valkeinen 1390afe267f2STomi Valkeinen /* We also set common settings here. Should be moved elsewhere. */ 1391afe267f2STomi Valkeinen 1392afe267f2STomi Valkeinen if (priv->strobe.manual) { 1393afe267f2STomi Valkeinen /* Disable AEQ_SFILTER_EN */ 1394afe267f2STomi Valkeinen ub960_update_bits(priv, UB960_XR_AEQ_CTL1, 1395afe267f2STomi Valkeinen UB960_XR_AEQ_CTL1_AEQ_SFILTER_EN, 0); 1396afe267f2STomi Valkeinen } else { 1397afe267f2STomi Valkeinen /* Enable SFILTER and error control */ 1398afe267f2STomi Valkeinen ub960_write(priv, UB960_XR_AEQ_CTL1, 1399afe267f2STomi Valkeinen UB960_XR_AEQ_CTL1_AEQ_ERR_CTL_MASK | 1400afe267f2STomi Valkeinen UB960_XR_AEQ_CTL1_AEQ_SFILTER_EN); 1401afe267f2STomi Valkeinen 1402afe267f2STomi Valkeinen /* Set AEQ strobe range */ 1403afe267f2STomi Valkeinen ub960_rxport_set_strobe_range(priv, priv->strobe.min, 1404afe267f2STomi Valkeinen priv->strobe.max); 1405afe267f2STomi Valkeinen } 1406afe267f2STomi Valkeinen 1407afe267f2STomi Valkeinen /* The rest are port specific */ 1408afe267f2STomi Valkeinen 1409afe267f2STomi Valkeinen if (priv->strobe.manual) 1410afe267f2STomi Valkeinen ub960_rxport_set_strobe_pos(priv, nport, rxport->eq.strobe_pos); 1411afe267f2STomi Valkeinen else 1412afe267f2STomi Valkeinen ub960_rxport_set_strobe_pos(priv, nport, 0); 1413afe267f2STomi Valkeinen 1414afe267f2STomi Valkeinen if (rxport->eq.manual_eq) { 1415afe267f2STomi Valkeinen ub960_rxport_set_eq_level(priv, nport, 1416afe267f2STomi Valkeinen rxport->eq.manual.eq_level); 1417afe267f2STomi Valkeinen 1418afe267f2STomi Valkeinen /* Enable AEQ Bypass */ 1419afe267f2STomi Valkeinen ub960_rxport_update_bits(priv, nport, UB960_RR_AEQ_BYPASS, 1420afe267f2STomi Valkeinen UB960_RR_AEQ_BYPASS_ENABLE, 1421afe267f2STomi Valkeinen UB960_RR_AEQ_BYPASS_ENABLE); 1422afe267f2STomi Valkeinen } else { 1423afe267f2STomi Valkeinen ub960_rxport_set_eq_range(priv, nport, 1424afe267f2STomi Valkeinen rxport->eq.aeq.eq_level_min, 1425afe267f2STomi Valkeinen rxport->eq.aeq.eq_level_max); 1426afe267f2STomi Valkeinen 1427afe267f2STomi Valkeinen /* Disable AEQ Bypass */ 1428afe267f2STomi Valkeinen ub960_rxport_update_bits(priv, nport, UB960_RR_AEQ_BYPASS, 1429afe267f2STomi Valkeinen UB960_RR_AEQ_BYPASS_ENABLE, 0); 1430afe267f2STomi Valkeinen } 1431afe267f2STomi Valkeinen } 1432afe267f2STomi Valkeinen 1433afe267f2STomi Valkeinen static int ub960_rxport_link_ok(struct ub960_data *priv, unsigned int nport, 1434afe267f2STomi Valkeinen bool *ok) 1435afe267f2STomi Valkeinen { 1436afe267f2STomi Valkeinen u8 rx_port_sts1, rx_port_sts2; 1437afe267f2STomi Valkeinen u16 parity_errors; 1438afe267f2STomi Valkeinen u8 csi_rx_sts; 1439afe267f2STomi Valkeinen u8 csi_err_cnt; 1440afe267f2STomi Valkeinen u8 bcc_sts; 1441afe267f2STomi Valkeinen int ret; 1442afe267f2STomi Valkeinen bool errors; 1443afe267f2STomi Valkeinen 1444afe267f2STomi Valkeinen ret = ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, 1445afe267f2STomi Valkeinen &rx_port_sts1); 1446afe267f2STomi Valkeinen if (ret) 1447afe267f2STomi Valkeinen return ret; 1448afe267f2STomi Valkeinen 1449afe267f2STomi Valkeinen if (!(rx_port_sts1 & UB960_RR_RX_PORT_STS1_LOCK_STS)) { 1450afe267f2STomi Valkeinen *ok = false; 1451afe267f2STomi Valkeinen return 0; 1452afe267f2STomi Valkeinen } 1453afe267f2STomi Valkeinen 1454afe267f2STomi Valkeinen ret = ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2, 1455afe267f2STomi Valkeinen &rx_port_sts2); 1456afe267f2STomi Valkeinen if (ret) 1457afe267f2STomi Valkeinen return ret; 1458afe267f2STomi Valkeinen 1459afe267f2STomi Valkeinen ret = ub960_rxport_read(priv, nport, UB960_RR_CSI_RX_STS, &csi_rx_sts); 1460afe267f2STomi Valkeinen if (ret) 1461afe267f2STomi Valkeinen return ret; 1462afe267f2STomi Valkeinen 1463afe267f2STomi Valkeinen ret = ub960_rxport_read(priv, nport, UB960_RR_CSI_ERR_COUNTER, 1464afe267f2STomi Valkeinen &csi_err_cnt); 1465afe267f2STomi Valkeinen if (ret) 1466afe267f2STomi Valkeinen return ret; 1467afe267f2STomi Valkeinen 1468afe267f2STomi Valkeinen ret = ub960_rxport_read(priv, nport, UB960_RR_BCC_STATUS, &bcc_sts); 1469afe267f2STomi Valkeinen if (ret) 1470afe267f2STomi Valkeinen return ret; 1471afe267f2STomi Valkeinen 1472afe267f2STomi Valkeinen ret = ub960_rxport_read16(priv, nport, UB960_RR_RX_PAR_ERR_HI, 1473afe267f2STomi Valkeinen &parity_errors); 1474afe267f2STomi Valkeinen if (ret) 1475afe267f2STomi Valkeinen return ret; 1476afe267f2STomi Valkeinen 1477afe267f2STomi Valkeinen errors = (rx_port_sts1 & UB960_RR_RX_PORT_STS1_ERROR_MASK) || 1478afe267f2STomi Valkeinen (rx_port_sts2 & UB960_RR_RX_PORT_STS2_ERROR_MASK) || 1479afe267f2STomi Valkeinen (bcc_sts & UB960_RR_BCC_STATUS_ERROR_MASK) || 1480afe267f2STomi Valkeinen (csi_rx_sts & UB960_RR_CSI_RX_STS_ERROR_MASK) || csi_err_cnt || 1481afe267f2STomi Valkeinen parity_errors; 1482afe267f2STomi Valkeinen 1483afe267f2STomi Valkeinen *ok = !errors; 1484afe267f2STomi Valkeinen 1485afe267f2STomi Valkeinen return 0; 1486afe267f2STomi Valkeinen } 1487afe267f2STomi Valkeinen 1488afe267f2STomi Valkeinen /* 1489afe267f2STomi Valkeinen * Wait for the RX ports to lock, have no errors and have stable strobe position 1490afe267f2STomi Valkeinen * and EQ level. 1491afe267f2STomi Valkeinen */ 1492afe267f2STomi Valkeinen static int ub960_rxport_wait_locks(struct ub960_data *priv, 1493afe267f2STomi Valkeinen unsigned long port_mask, 1494afe267f2STomi Valkeinen unsigned int *lock_mask) 1495afe267f2STomi Valkeinen { 1496afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 1497afe267f2STomi Valkeinen unsigned long timeout; 1498afe267f2STomi Valkeinen unsigned int link_ok_mask; 1499afe267f2STomi Valkeinen unsigned int missing; 1500afe267f2STomi Valkeinen unsigned int loops; 1501afe267f2STomi Valkeinen u8 nport; 1502afe267f2STomi Valkeinen int ret; 1503afe267f2STomi Valkeinen 1504afe267f2STomi Valkeinen if (port_mask == 0) { 1505afe267f2STomi Valkeinen if (lock_mask) 1506afe267f2STomi Valkeinen *lock_mask = 0; 1507afe267f2STomi Valkeinen return 0; 1508afe267f2STomi Valkeinen } 1509afe267f2STomi Valkeinen 1510afe267f2STomi Valkeinen if (port_mask >= BIT(priv->hw_data->num_rxports)) 1511afe267f2STomi Valkeinen return -EINVAL; 1512afe267f2STomi Valkeinen 1513afe267f2STomi Valkeinen timeout = jiffies + msecs_to_jiffies(1000); 1514afe267f2STomi Valkeinen loops = 0; 1515afe267f2STomi Valkeinen link_ok_mask = 0; 1516afe267f2STomi Valkeinen 1517afe267f2STomi Valkeinen while (time_before(jiffies, timeout)) { 1518afe267f2STomi Valkeinen missing = 0; 1519afe267f2STomi Valkeinen 1520afe267f2STomi Valkeinen for_each_set_bit(nport, &port_mask, 1521afe267f2STomi Valkeinen priv->hw_data->num_rxports) { 1522afe267f2STomi Valkeinen struct ub960_rxport *rxport = priv->rxports[nport]; 1523afe267f2STomi Valkeinen bool ok; 1524afe267f2STomi Valkeinen 1525afe267f2STomi Valkeinen if (!rxport) 1526afe267f2STomi Valkeinen continue; 1527afe267f2STomi Valkeinen 1528afe267f2STomi Valkeinen ret = ub960_rxport_link_ok(priv, nport, &ok); 1529afe267f2STomi Valkeinen if (ret) 1530afe267f2STomi Valkeinen return ret; 1531afe267f2STomi Valkeinen 1532afe267f2STomi Valkeinen /* 1533afe267f2STomi Valkeinen * We want the link to be ok for two consecutive loops, 1534afe267f2STomi Valkeinen * as a link could get established just before our test 1535afe267f2STomi Valkeinen * and drop soon after. 1536afe267f2STomi Valkeinen */ 1537afe267f2STomi Valkeinen if (!ok || !(link_ok_mask & BIT(nport))) 1538afe267f2STomi Valkeinen missing++; 1539afe267f2STomi Valkeinen 1540afe267f2STomi Valkeinen if (ok) 1541afe267f2STomi Valkeinen link_ok_mask |= BIT(nport); 1542afe267f2STomi Valkeinen else 1543afe267f2STomi Valkeinen link_ok_mask &= ~BIT(nport); 1544afe267f2STomi Valkeinen } 1545afe267f2STomi Valkeinen 1546afe267f2STomi Valkeinen loops++; 1547afe267f2STomi Valkeinen 1548afe267f2STomi Valkeinen if (missing == 0) 1549afe267f2STomi Valkeinen break; 1550afe267f2STomi Valkeinen 1551afe267f2STomi Valkeinen msleep(50); 1552afe267f2STomi Valkeinen } 1553afe267f2STomi Valkeinen 1554afe267f2STomi Valkeinen if (lock_mask) 1555afe267f2STomi Valkeinen *lock_mask = link_ok_mask; 1556afe267f2STomi Valkeinen 1557afe267f2STomi Valkeinen dev_dbg(dev, "Wait locks done in %u loops\n", loops); 1558afe267f2STomi Valkeinen for_each_set_bit(nport, &port_mask, priv->hw_data->num_rxports) { 1559afe267f2STomi Valkeinen struct ub960_rxport *rxport = priv->rxports[nport]; 1560afe267f2STomi Valkeinen s8 strobe_pos, eq_level; 1561afe267f2STomi Valkeinen u16 v; 1562afe267f2STomi Valkeinen 1563afe267f2STomi Valkeinen if (!rxport) 1564afe267f2STomi Valkeinen continue; 1565afe267f2STomi Valkeinen 1566afe267f2STomi Valkeinen if (!(link_ok_mask & BIT(nport))) { 1567afe267f2STomi Valkeinen dev_dbg(dev, "\trx%u: not locked\n", nport); 1568afe267f2STomi Valkeinen continue; 1569afe267f2STomi Valkeinen } 1570afe267f2STomi Valkeinen 1571afe267f2STomi Valkeinen ub960_rxport_read16(priv, nport, UB960_RR_RX_FREQ_HIGH, &v); 1572afe267f2STomi Valkeinen 1573afe267f2STomi Valkeinen ret = ub960_rxport_get_strobe_pos(priv, nport, &strobe_pos); 1574afe267f2STomi Valkeinen if (ret) 1575afe267f2STomi Valkeinen return ret; 1576afe267f2STomi Valkeinen 1577afe267f2STomi Valkeinen ret = ub960_rxport_get_eq_level(priv, nport, &eq_level); 1578afe267f2STomi Valkeinen if (ret) 1579afe267f2STomi Valkeinen return ret; 1580afe267f2STomi Valkeinen 1581afe267f2STomi Valkeinen dev_dbg(dev, "\trx%u: locked, SP: %d, EQ: %u, freq %llu Hz\n", 1582afe267f2STomi Valkeinen nport, strobe_pos, eq_level, (v * 1000000ULL) >> 8); 1583afe267f2STomi Valkeinen } 1584afe267f2STomi Valkeinen 1585afe267f2STomi Valkeinen return 0; 1586afe267f2STomi Valkeinen } 1587afe267f2STomi Valkeinen 1588afe267f2STomi Valkeinen static unsigned long ub960_calc_bc_clk_rate_ub960(struct ub960_data *priv, 1589afe267f2STomi Valkeinen struct ub960_rxport *rxport) 1590afe267f2STomi Valkeinen { 1591afe267f2STomi Valkeinen unsigned int mult; 1592afe267f2STomi Valkeinen unsigned int div; 1593afe267f2STomi Valkeinen 1594afe267f2STomi Valkeinen switch (rxport->rx_mode) { 1595afe267f2STomi Valkeinen case RXPORT_MODE_RAW10: 1596afe267f2STomi Valkeinen case RXPORT_MODE_RAW12_HF: 1597afe267f2STomi Valkeinen case RXPORT_MODE_RAW12_LF: 1598afe267f2STomi Valkeinen mult = 1; 1599afe267f2STomi Valkeinen div = 10; 1600afe267f2STomi Valkeinen break; 1601afe267f2STomi Valkeinen 1602afe267f2STomi Valkeinen case RXPORT_MODE_CSI2_SYNC: 1603afe267f2STomi Valkeinen mult = 2; 1604afe267f2STomi Valkeinen div = 1; 1605afe267f2STomi Valkeinen break; 1606afe267f2STomi Valkeinen 1607afe267f2STomi Valkeinen case RXPORT_MODE_CSI2_ASYNC: 1608afe267f2STomi Valkeinen mult = 2; 1609afe267f2STomi Valkeinen div = 5; 1610afe267f2STomi Valkeinen break; 1611afe267f2STomi Valkeinen 1612afe267f2STomi Valkeinen default: 1613afe267f2STomi Valkeinen return 0; 1614afe267f2STomi Valkeinen } 1615afe267f2STomi Valkeinen 1616afe267f2STomi Valkeinen return clk_get_rate(priv->refclk) * mult / div; 1617afe267f2STomi Valkeinen } 1618afe267f2STomi Valkeinen 1619afe267f2STomi Valkeinen static unsigned long ub960_calc_bc_clk_rate_ub9702(struct ub960_data *priv, 1620afe267f2STomi Valkeinen struct ub960_rxport *rxport) 1621afe267f2STomi Valkeinen { 1622afe267f2STomi Valkeinen switch (rxport->rx_mode) { 1623afe267f2STomi Valkeinen case RXPORT_MODE_RAW10: 1624afe267f2STomi Valkeinen case RXPORT_MODE_RAW12_HF: 1625afe267f2STomi Valkeinen case RXPORT_MODE_RAW12_LF: 1626afe267f2STomi Valkeinen return 2359400; 1627afe267f2STomi Valkeinen 1628afe267f2STomi Valkeinen case RXPORT_MODE_CSI2_SYNC: 1629afe267f2STomi Valkeinen return 47187500; 1630afe267f2STomi Valkeinen 1631afe267f2STomi Valkeinen case RXPORT_MODE_CSI2_ASYNC: 1632afe267f2STomi Valkeinen return 9437500; 1633afe267f2STomi Valkeinen 1634afe267f2STomi Valkeinen default: 1635afe267f2STomi Valkeinen return 0; 1636afe267f2STomi Valkeinen } 1637afe267f2STomi Valkeinen } 1638afe267f2STomi Valkeinen 1639afe267f2STomi Valkeinen static int ub960_rxport_add_serializer(struct ub960_data *priv, u8 nport) 1640afe267f2STomi Valkeinen { 1641afe267f2STomi Valkeinen struct ub960_rxport *rxport = priv->rxports[nport]; 1642afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 1643afe267f2STomi Valkeinen struct ds90ub9xx_platform_data *ser_pdata = &rxport->ser.pdata; 1644afe267f2STomi Valkeinen struct i2c_board_info ser_info = { 1645afe267f2STomi Valkeinen .of_node = to_of_node(rxport->ser.fwnode), 1646afe267f2STomi Valkeinen .fwnode = rxport->ser.fwnode, 1647afe267f2STomi Valkeinen .platform_data = ser_pdata, 1648afe267f2STomi Valkeinen }; 1649afe267f2STomi Valkeinen 1650afe267f2STomi Valkeinen ser_pdata->port = nport; 1651afe267f2STomi Valkeinen ser_pdata->atr = priv->atr; 1652afe267f2STomi Valkeinen if (priv->hw_data->is_ub9702) 1653afe267f2STomi Valkeinen ser_pdata->bc_rate = ub960_calc_bc_clk_rate_ub9702(priv, rxport); 1654afe267f2STomi Valkeinen else 1655afe267f2STomi Valkeinen ser_pdata->bc_rate = ub960_calc_bc_clk_rate_ub960(priv, rxport); 1656afe267f2STomi Valkeinen 1657afe267f2STomi Valkeinen /* 1658afe267f2STomi Valkeinen * The serializer is added under the same i2c adapter as the 1659afe267f2STomi Valkeinen * deserializer. This is not quite right, as the serializer is behind 1660afe267f2STomi Valkeinen * the FPD-Link. 1661afe267f2STomi Valkeinen */ 1662afe267f2STomi Valkeinen ser_info.addr = rxport->ser.alias; 1663afe267f2STomi Valkeinen rxport->ser.client = 1664afe267f2STomi Valkeinen i2c_new_client_device(priv->client->adapter, &ser_info); 16654b9fbbd5SHarshit Mogalapalli if (IS_ERR(rxport->ser.client)) { 1666afe267f2STomi Valkeinen dev_err(dev, "rx%u: cannot add %s i2c device", nport, 1667afe267f2STomi Valkeinen ser_info.type); 16684b9fbbd5SHarshit Mogalapalli return PTR_ERR(rxport->ser.client); 1669afe267f2STomi Valkeinen } 1670afe267f2STomi Valkeinen 1671afe267f2STomi Valkeinen dev_dbg(dev, "rx%u: remote serializer at alias 0x%02x (%u-%04x)\n", 1672afe267f2STomi Valkeinen nport, rxport->ser.client->addr, 1673afe267f2STomi Valkeinen rxport->ser.client->adapter->nr, rxport->ser.client->addr); 1674afe267f2STomi Valkeinen 1675afe267f2STomi Valkeinen return 0; 1676afe267f2STomi Valkeinen } 1677afe267f2STomi Valkeinen 1678afe267f2STomi Valkeinen static void ub960_rxport_remove_serializer(struct ub960_data *priv, u8 nport) 1679afe267f2STomi Valkeinen { 1680afe267f2STomi Valkeinen struct ub960_rxport *rxport = priv->rxports[nport]; 1681afe267f2STomi Valkeinen 1682afe267f2STomi Valkeinen i2c_unregister_device(rxport->ser.client); 1683afe267f2STomi Valkeinen rxport->ser.client = NULL; 1684afe267f2STomi Valkeinen } 1685afe267f2STomi Valkeinen 1686afe267f2STomi Valkeinen /* Add serializer i2c devices for all initialized ports */ 1687afe267f2STomi Valkeinen static int ub960_rxport_add_serializers(struct ub960_data *priv) 1688afe267f2STomi Valkeinen { 1689afe267f2STomi Valkeinen unsigned int nport; 1690afe267f2STomi Valkeinen int ret; 1691afe267f2STomi Valkeinen 1692afe267f2STomi Valkeinen for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { 1693afe267f2STomi Valkeinen struct ub960_rxport *rxport = priv->rxports[nport]; 1694afe267f2STomi Valkeinen 1695afe267f2STomi Valkeinen if (!rxport) 1696afe267f2STomi Valkeinen continue; 1697afe267f2STomi Valkeinen 1698afe267f2STomi Valkeinen ret = ub960_rxport_add_serializer(priv, nport); 1699afe267f2STomi Valkeinen if (ret) 1700afe267f2STomi Valkeinen goto err_remove_sers; 1701afe267f2STomi Valkeinen } 1702afe267f2STomi Valkeinen 1703afe267f2STomi Valkeinen return 0; 1704afe267f2STomi Valkeinen 1705afe267f2STomi Valkeinen err_remove_sers: 1706afe267f2STomi Valkeinen while (nport--) { 1707afe267f2STomi Valkeinen struct ub960_rxport *rxport = priv->rxports[nport]; 1708afe267f2STomi Valkeinen 1709afe267f2STomi Valkeinen if (!rxport) 1710afe267f2STomi Valkeinen continue; 1711afe267f2STomi Valkeinen 1712afe267f2STomi Valkeinen ub960_rxport_remove_serializer(priv, nport); 1713afe267f2STomi Valkeinen } 1714afe267f2STomi Valkeinen 1715afe267f2STomi Valkeinen return ret; 1716afe267f2STomi Valkeinen } 1717afe267f2STomi Valkeinen 1718afe267f2STomi Valkeinen static void ub960_rxport_remove_serializers(struct ub960_data *priv) 1719afe267f2STomi Valkeinen { 1720afe267f2STomi Valkeinen unsigned int nport; 1721afe267f2STomi Valkeinen 1722afe267f2STomi Valkeinen for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { 1723afe267f2STomi Valkeinen struct ub960_rxport *rxport = priv->rxports[nport]; 1724afe267f2STomi Valkeinen 1725afe267f2STomi Valkeinen if (!rxport) 1726afe267f2STomi Valkeinen continue; 1727afe267f2STomi Valkeinen 1728afe267f2STomi Valkeinen ub960_rxport_remove_serializer(priv, nport); 1729afe267f2STomi Valkeinen } 1730afe267f2STomi Valkeinen } 1731afe267f2STomi Valkeinen 1732afe267f2STomi Valkeinen static void ub960_init_tx_port(struct ub960_data *priv, 1733afe267f2STomi Valkeinen struct ub960_txport *txport) 1734afe267f2STomi Valkeinen { 1735afe267f2STomi Valkeinen unsigned int nport = txport->nport; 1736afe267f2STomi Valkeinen u8 csi_ctl = 0; 1737afe267f2STomi Valkeinen 1738afe267f2STomi Valkeinen /* 1739afe267f2STomi Valkeinen * From the datasheet: "initial CSI Skew-Calibration 1740afe267f2STomi Valkeinen * sequence [...] should be set when operating at 1.6 Gbps" 1741afe267f2STomi Valkeinen */ 1742afe267f2STomi Valkeinen if (priv->tx_data_rate == MHZ(1600)) 1743afe267f2STomi Valkeinen csi_ctl |= UB960_TR_CSI_CTL_CSI_CAL_EN; 1744afe267f2STomi Valkeinen 1745afe267f2STomi Valkeinen csi_ctl |= (4 - txport->num_data_lanes) << 4; 1746afe267f2STomi Valkeinen 1747afe267f2STomi Valkeinen ub960_txport_write(priv, nport, UB960_TR_CSI_CTL, csi_ctl); 1748afe267f2STomi Valkeinen } 1749afe267f2STomi Valkeinen 1750afe267f2STomi Valkeinen static int ub960_init_tx_ports(struct ub960_data *priv) 1751afe267f2STomi Valkeinen { 1752afe267f2STomi Valkeinen unsigned int nport; 1753afe267f2STomi Valkeinen u8 speed_select; 1754afe267f2STomi Valkeinen u8 pll_div; 1755afe267f2STomi Valkeinen 1756afe267f2STomi Valkeinen /* TX ports */ 1757afe267f2STomi Valkeinen 1758afe267f2STomi Valkeinen switch (priv->tx_data_rate) { 1759afe267f2STomi Valkeinen case MHZ(1600): 1760afe267f2STomi Valkeinen default: 1761afe267f2STomi Valkeinen speed_select = 0; 1762afe267f2STomi Valkeinen pll_div = 0x10; 1763afe267f2STomi Valkeinen break; 1764afe267f2STomi Valkeinen case MHZ(1200): 1765afe267f2STomi Valkeinen speed_select = 1; 1766afe267f2STomi Valkeinen break; 1767afe267f2STomi Valkeinen case MHZ(800): 1768afe267f2STomi Valkeinen speed_select = 2; 1769afe267f2STomi Valkeinen pll_div = 0x10; 1770afe267f2STomi Valkeinen break; 1771afe267f2STomi Valkeinen case MHZ(400): 1772afe267f2STomi Valkeinen speed_select = 3; 1773afe267f2STomi Valkeinen pll_div = 0x10; 1774afe267f2STomi Valkeinen break; 1775afe267f2STomi Valkeinen } 1776afe267f2STomi Valkeinen 1777afe267f2STomi Valkeinen ub960_write(priv, UB960_SR_CSI_PLL_CTL, speed_select); 1778afe267f2STomi Valkeinen 1779afe267f2STomi Valkeinen if (priv->hw_data->is_ub9702) { 1780afe267f2STomi Valkeinen ub960_write(priv, UB960_SR_CSI_PLL_DIV, pll_div); 1781afe267f2STomi Valkeinen 1782afe267f2STomi Valkeinen switch (priv->tx_data_rate) { 1783afe267f2STomi Valkeinen case MHZ(1600): 1784afe267f2STomi Valkeinen default: 1785afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, 0x80); 1786afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4b, 0x2a); 1787afe267f2STomi Valkeinen break; 1788afe267f2STomi Valkeinen case MHZ(800): 1789afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, 0x90); 1790afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4f, 0x2a); 1791afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4b, 0x2a); 1792afe267f2STomi Valkeinen break; 1793afe267f2STomi Valkeinen case MHZ(400): 1794afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, 0xa0); 1795afe267f2STomi Valkeinen break; 1796afe267f2STomi Valkeinen } 1797afe267f2STomi Valkeinen } 1798afe267f2STomi Valkeinen 1799afe267f2STomi Valkeinen for (nport = 0; nport < priv->hw_data->num_txports; nport++) { 1800afe267f2STomi Valkeinen struct ub960_txport *txport = priv->txports[nport]; 1801afe267f2STomi Valkeinen 1802afe267f2STomi Valkeinen if (!txport) 1803afe267f2STomi Valkeinen continue; 1804afe267f2STomi Valkeinen 1805afe267f2STomi Valkeinen ub960_init_tx_port(priv, txport); 1806afe267f2STomi Valkeinen } 1807afe267f2STomi Valkeinen 1808afe267f2STomi Valkeinen return 0; 1809afe267f2STomi Valkeinen } 1810afe267f2STomi Valkeinen 1811afe267f2STomi Valkeinen static void ub960_init_rx_port_ub960(struct ub960_data *priv, 1812afe267f2STomi Valkeinen struct ub960_rxport *rxport) 1813afe267f2STomi Valkeinen { 1814afe267f2STomi Valkeinen unsigned int nport = rxport->nport; 1815afe267f2STomi Valkeinen u32 bc_freq_val; 1816afe267f2STomi Valkeinen 1817afe267f2STomi Valkeinen /* 1818afe267f2STomi Valkeinen * Back channel frequency select. 1819afe267f2STomi Valkeinen * Override FREQ_SELECT from the strap. 1820afe267f2STomi Valkeinen * 0 - 2.5 Mbps (DS90UB913A-Q1 / DS90UB933-Q1) 1821afe267f2STomi Valkeinen * 2 - 10 Mbps 1822afe267f2STomi Valkeinen * 6 - 50 Mbps (DS90UB953-Q1) 1823afe267f2STomi Valkeinen * 1824afe267f2STomi Valkeinen * Note that changing this setting will result in some errors on the back 1825afe267f2STomi Valkeinen * channel for a short period of time. 1826afe267f2STomi Valkeinen */ 1827afe267f2STomi Valkeinen 1828afe267f2STomi Valkeinen switch (rxport->rx_mode) { 1829afe267f2STomi Valkeinen case RXPORT_MODE_RAW10: 1830afe267f2STomi Valkeinen case RXPORT_MODE_RAW12_HF: 1831afe267f2STomi Valkeinen case RXPORT_MODE_RAW12_LF: 1832afe267f2STomi Valkeinen bc_freq_val = 0; 1833afe267f2STomi Valkeinen break; 1834afe267f2STomi Valkeinen 1835afe267f2STomi Valkeinen case RXPORT_MODE_CSI2_ASYNC: 1836afe267f2STomi Valkeinen bc_freq_val = 2; 1837afe267f2STomi Valkeinen break; 1838afe267f2STomi Valkeinen 1839afe267f2STomi Valkeinen case RXPORT_MODE_CSI2_SYNC: 1840afe267f2STomi Valkeinen bc_freq_val = 6; 1841afe267f2STomi Valkeinen break; 1842afe267f2STomi Valkeinen 1843afe267f2STomi Valkeinen default: 1844afe267f2STomi Valkeinen return; 1845afe267f2STomi Valkeinen } 1846afe267f2STomi Valkeinen 1847afe267f2STomi Valkeinen ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, 1848afe267f2STomi Valkeinen UB960_RR_BCC_CONFIG_BC_FREQ_SEL_MASK, 1849afe267f2STomi Valkeinen bc_freq_val); 1850afe267f2STomi Valkeinen 1851afe267f2STomi Valkeinen switch (rxport->rx_mode) { 1852afe267f2STomi Valkeinen case RXPORT_MODE_RAW10: 1853afe267f2STomi Valkeinen /* FPD3_MODE = RAW10 Mode (DS90UB913A-Q1 / DS90UB933-Q1 compatible) */ 1854afe267f2STomi Valkeinen ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG, 1855afe267f2STomi Valkeinen UB960_RR_PORT_CONFIG_FPD3_MODE_MASK, 1856afe267f2STomi Valkeinen 0x3); 1857afe267f2STomi Valkeinen 1858afe267f2STomi Valkeinen /* 1859afe267f2STomi Valkeinen * RAW10_8BIT_CTL = 0b10 : 8-bit processing using upper 8 bits 1860afe267f2STomi Valkeinen */ 1861afe267f2STomi Valkeinen ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2, 1862afe267f2STomi Valkeinen UB960_RR_PORT_CONFIG2_RAW10_8BIT_CTL_MASK, 1863afe267f2STomi Valkeinen 0x2 << UB960_RR_PORT_CONFIG2_RAW10_8BIT_CTL_SHIFT); 1864afe267f2STomi Valkeinen 1865afe267f2STomi Valkeinen break; 1866afe267f2STomi Valkeinen 1867afe267f2STomi Valkeinen case RXPORT_MODE_RAW12_HF: 1868afe267f2STomi Valkeinen case RXPORT_MODE_RAW12_LF: 1869afe267f2STomi Valkeinen /* Not implemented */ 1870afe267f2STomi Valkeinen return; 1871afe267f2STomi Valkeinen 1872afe267f2STomi Valkeinen case RXPORT_MODE_CSI2_SYNC: 1873afe267f2STomi Valkeinen case RXPORT_MODE_CSI2_ASYNC: 1874afe267f2STomi Valkeinen /* CSI-2 Mode (DS90UB953-Q1 compatible) */ 1875afe267f2STomi Valkeinen ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG, 0x3, 1876afe267f2STomi Valkeinen 0x0); 1877afe267f2STomi Valkeinen 1878afe267f2STomi Valkeinen break; 1879afe267f2STomi Valkeinen } 1880afe267f2STomi Valkeinen 1881afe267f2STomi Valkeinen /* LV_POLARITY & FV_POLARITY */ 1882afe267f2STomi Valkeinen ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2, 0x3, 1883afe267f2STomi Valkeinen rxport->lv_fv_pol); 1884afe267f2STomi Valkeinen 1885afe267f2STomi Valkeinen /* Enable all interrupt sources from this port */ 1886afe267f2STomi Valkeinen ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_HI, 0x07); 1887afe267f2STomi Valkeinen ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_LO, 0x7f); 1888afe267f2STomi Valkeinen 1889afe267f2STomi Valkeinen /* Enable I2C_PASS_THROUGH */ 1890afe267f2STomi Valkeinen ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, 1891afe267f2STomi Valkeinen UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, 1892afe267f2STomi Valkeinen UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH); 1893afe267f2STomi Valkeinen 1894afe267f2STomi Valkeinen /* Enable I2C communication to the serializer via the alias addr */ 1895afe267f2STomi Valkeinen ub960_rxport_write(priv, nport, UB960_RR_SER_ALIAS_ID, 1896afe267f2STomi Valkeinen rxport->ser.alias << 1); 1897afe267f2STomi Valkeinen 1898afe267f2STomi Valkeinen /* Configure EQ related settings */ 1899afe267f2STomi Valkeinen ub960_rxport_config_eq(priv, nport); 1900afe267f2STomi Valkeinen 1901afe267f2STomi Valkeinen /* Enable RX port */ 1902afe267f2STomi Valkeinen ub960_update_bits(priv, UB960_SR_RX_PORT_CTL, BIT(nport), BIT(nport)); 1903afe267f2STomi Valkeinen } 1904afe267f2STomi Valkeinen 1905afe267f2STomi Valkeinen static void ub960_init_rx_port_ub9702_fpd3(struct ub960_data *priv, 1906afe267f2STomi Valkeinen struct ub960_rxport *rxport) 1907afe267f2STomi Valkeinen { 1908afe267f2STomi Valkeinen unsigned int nport = rxport->nport; 1909afe267f2STomi Valkeinen u8 bc_freq_val; 1910afe267f2STomi Valkeinen u8 fpd_func_mode; 1911afe267f2STomi Valkeinen 1912afe267f2STomi Valkeinen switch (rxport->rx_mode) { 1913afe267f2STomi Valkeinen case RXPORT_MODE_RAW10: 1914afe267f2STomi Valkeinen bc_freq_val = 0; 1915afe267f2STomi Valkeinen fpd_func_mode = 5; 1916afe267f2STomi Valkeinen break; 1917afe267f2STomi Valkeinen 1918afe267f2STomi Valkeinen case RXPORT_MODE_RAW12_HF: 1919afe267f2STomi Valkeinen bc_freq_val = 0; 1920afe267f2STomi Valkeinen fpd_func_mode = 4; 1921afe267f2STomi Valkeinen break; 1922afe267f2STomi Valkeinen 1923afe267f2STomi Valkeinen case RXPORT_MODE_RAW12_LF: 1924afe267f2STomi Valkeinen bc_freq_val = 0; 1925afe267f2STomi Valkeinen fpd_func_mode = 6; 1926afe267f2STomi Valkeinen break; 1927afe267f2STomi Valkeinen 1928afe267f2STomi Valkeinen case RXPORT_MODE_CSI2_SYNC: 1929afe267f2STomi Valkeinen bc_freq_val = 6; 1930afe267f2STomi Valkeinen fpd_func_mode = 2; 1931afe267f2STomi Valkeinen break; 1932afe267f2STomi Valkeinen 1933afe267f2STomi Valkeinen case RXPORT_MODE_CSI2_ASYNC: 1934afe267f2STomi Valkeinen bc_freq_val = 2; 1935afe267f2STomi Valkeinen fpd_func_mode = 2; 1936afe267f2STomi Valkeinen break; 1937afe267f2STomi Valkeinen 1938afe267f2STomi Valkeinen default: 1939afe267f2STomi Valkeinen return; 1940afe267f2STomi Valkeinen } 1941afe267f2STomi Valkeinen 1942afe267f2STomi Valkeinen ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, 0x7, 1943afe267f2STomi Valkeinen bc_freq_val); 1944afe267f2STomi Valkeinen ub960_rxport_write(priv, nport, UB960_RR_CHANNEL_MODE, fpd_func_mode); 1945afe267f2STomi Valkeinen 1946afe267f2STomi Valkeinen /* set serdes_eq_mode = 1 */ 1947afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xa8, 0x80); 1948afe267f2STomi Valkeinen 1949afe267f2STomi Valkeinen /* enable serdes driver */ 1950afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x0d, 0x7f); 1951afe267f2STomi Valkeinen 1952afe267f2STomi Valkeinen /* set serdes_eq_offset=4 */ 1953afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2b, 0x04); 1954afe267f2STomi Valkeinen 1955afe267f2STomi Valkeinen /* init default serdes_eq_max in 0xa9 */ 1956afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xa9, 0x23); 1957afe267f2STomi Valkeinen 1958afe267f2STomi Valkeinen /* init serdes_eq_min in 0xaa */ 1959afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xaa, 0); 1960afe267f2STomi Valkeinen 1961afe267f2STomi Valkeinen /* serdes_driver_ctl2 control: DS90UB953-Q1/DS90UB933-Q1/DS90UB913A-Q1 */ 1962afe267f2STomi Valkeinen ub960_ind_update_bits(priv, UB960_IND_TARGET_RX_ANA(nport), 0x1b, 1963afe267f2STomi Valkeinen BIT(3), BIT(3)); 1964afe267f2STomi Valkeinen 1965afe267f2STomi Valkeinen /* RX port to half-rate */ 1966afe267f2STomi Valkeinen ub960_update_bits(priv, UB960_SR_FPD_RATE_CFG, 0x3 << (nport * 2), 1967afe267f2STomi Valkeinen BIT(nport * 2)); 1968afe267f2STomi Valkeinen } 1969afe267f2STomi Valkeinen 1970afe267f2STomi Valkeinen static void ub960_init_rx_port_ub9702_fpd4_aeq(struct ub960_data *priv, 1971afe267f2STomi Valkeinen struct ub960_rxport *rxport) 1972afe267f2STomi Valkeinen { 1973afe267f2STomi Valkeinen unsigned int nport = rxport->nport; 1974afe267f2STomi Valkeinen bool first_time_power_up = true; 1975afe267f2STomi Valkeinen 1976afe267f2STomi Valkeinen if (first_time_power_up) { 1977afe267f2STomi Valkeinen u8 v; 1978afe267f2STomi Valkeinen 1979afe267f2STomi Valkeinen /* AEQ init */ 1980afe267f2STomi Valkeinen ub960_read_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2c, &v); 1981afe267f2STomi Valkeinen 1982afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x27, v); 1983afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x28, v + 1); 1984afe267f2STomi Valkeinen 1985afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2b, 0x00); 1986afe267f2STomi Valkeinen } 1987afe267f2STomi Valkeinen 1988afe267f2STomi Valkeinen /* enable serdes_eq_ctl2 */ 1989afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x9e, 0x00); 1990afe267f2STomi Valkeinen 1991afe267f2STomi Valkeinen /* enable serdes_eq_ctl1 */ 1992afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x90, 0x40); 1993afe267f2STomi Valkeinen 1994afe267f2STomi Valkeinen /* enable serdes_eq_en */ 1995afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2e, 0x40); 1996afe267f2STomi Valkeinen 1997afe267f2STomi Valkeinen /* disable serdes_eq_override */ 1998afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xf0, 0x00); 1999afe267f2STomi Valkeinen 2000afe267f2STomi Valkeinen /* disable serdes_gain_override */ 2001afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x71, 0x00); 2002afe267f2STomi Valkeinen } 2003afe267f2STomi Valkeinen 2004afe267f2STomi Valkeinen static void ub960_init_rx_port_ub9702_fpd4(struct ub960_data *priv, 2005afe267f2STomi Valkeinen struct ub960_rxport *rxport) 2006afe267f2STomi Valkeinen { 2007afe267f2STomi Valkeinen unsigned int nport = rxport->nport; 2008afe267f2STomi Valkeinen u8 bc_freq_val; 2009afe267f2STomi Valkeinen 2010afe267f2STomi Valkeinen switch (rxport->rx_mode) { 2011afe267f2STomi Valkeinen case RXPORT_MODE_RAW10: 2012afe267f2STomi Valkeinen bc_freq_val = 0; 2013afe267f2STomi Valkeinen break; 2014afe267f2STomi Valkeinen 2015afe267f2STomi Valkeinen case RXPORT_MODE_RAW12_HF: 2016afe267f2STomi Valkeinen bc_freq_val = 0; 2017afe267f2STomi Valkeinen break; 2018afe267f2STomi Valkeinen 2019afe267f2STomi Valkeinen case RXPORT_MODE_RAW12_LF: 2020afe267f2STomi Valkeinen bc_freq_val = 0; 2021afe267f2STomi Valkeinen break; 2022afe267f2STomi Valkeinen 2023afe267f2STomi Valkeinen case RXPORT_MODE_CSI2_SYNC: 2024afe267f2STomi Valkeinen bc_freq_val = 6; 2025afe267f2STomi Valkeinen break; 2026afe267f2STomi Valkeinen 2027afe267f2STomi Valkeinen case RXPORT_MODE_CSI2_ASYNC: 2028afe267f2STomi Valkeinen bc_freq_val = 2; 2029afe267f2STomi Valkeinen break; 2030afe267f2STomi Valkeinen 2031afe267f2STomi Valkeinen default: 2032afe267f2STomi Valkeinen return; 2033afe267f2STomi Valkeinen } 2034afe267f2STomi Valkeinen 2035afe267f2STomi Valkeinen ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, 0x7, 2036afe267f2STomi Valkeinen bc_freq_val); 2037afe267f2STomi Valkeinen 2038afe267f2STomi Valkeinen /* FPD4 Sync Mode */ 2039afe267f2STomi Valkeinen ub960_rxport_write(priv, nport, UB960_RR_CHANNEL_MODE, 0); 2040afe267f2STomi Valkeinen 2041afe267f2STomi Valkeinen /* add serdes_eq_offset of 4 */ 2042afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2b, 0x04); 2043afe267f2STomi Valkeinen 2044afe267f2STomi Valkeinen /* FPD4 serdes_start_eq in 0x27: assign default */ 2045afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x27, 0x0); 2046afe267f2STomi Valkeinen /* FPD4 serdes_end_eq in 0x28: assign default */ 2047afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x28, 0x23); 2048afe267f2STomi Valkeinen 2049afe267f2STomi Valkeinen /* set serdes_driver_mode into FPD IV mode */ 2050afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x04, 0x00); 2051afe267f2STomi Valkeinen /* set FPD PBC drv into FPD IV mode */ 2052afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x1b, 0x00); 2053afe267f2STomi Valkeinen 2054afe267f2STomi Valkeinen /* set serdes_system_init to 0x2f */ 2055afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x21, 0x2f); 2056afe267f2STomi Valkeinen /* set serdes_system_rst in reset mode */ 2057afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x25, 0xc1); 2058afe267f2STomi Valkeinen 2059afe267f2STomi Valkeinen /* RX port to 7.55G mode */ 2060afe267f2STomi Valkeinen ub960_update_bits(priv, UB960_SR_FPD_RATE_CFG, 0x3 << (nport * 2), 2061afe267f2STomi Valkeinen 0 << (nport * 2)); 2062afe267f2STomi Valkeinen 2063afe267f2STomi Valkeinen ub960_init_rx_port_ub9702_fpd4_aeq(priv, rxport); 2064afe267f2STomi Valkeinen } 2065afe267f2STomi Valkeinen 2066afe267f2STomi Valkeinen static void ub960_init_rx_port_ub9702(struct ub960_data *priv, 2067afe267f2STomi Valkeinen struct ub960_rxport *rxport) 2068afe267f2STomi Valkeinen { 2069afe267f2STomi Valkeinen unsigned int nport = rxport->nport; 2070afe267f2STomi Valkeinen 2071afe267f2STomi Valkeinen if (rxport->cdr_mode == RXPORT_CDR_FPD3) 2072afe267f2STomi Valkeinen ub960_init_rx_port_ub9702_fpd3(priv, rxport); 2073afe267f2STomi Valkeinen else /* RXPORT_CDR_FPD4 */ 2074afe267f2STomi Valkeinen ub960_init_rx_port_ub9702_fpd4(priv, rxport); 2075afe267f2STomi Valkeinen 2076afe267f2STomi Valkeinen switch (rxport->rx_mode) { 2077afe267f2STomi Valkeinen case RXPORT_MODE_RAW10: 2078afe267f2STomi Valkeinen /* 2079afe267f2STomi Valkeinen * RAW10_8BIT_CTL = 0b11 : 8-bit processing using lower 8 bits 2080afe267f2STomi Valkeinen * 0b10 : 8-bit processing using upper 8 bits 2081afe267f2STomi Valkeinen */ 2082afe267f2STomi Valkeinen ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2, 2083afe267f2STomi Valkeinen 0x3 << 6, 0x2 << 6); 2084afe267f2STomi Valkeinen 2085afe267f2STomi Valkeinen break; 2086afe267f2STomi Valkeinen 2087afe267f2STomi Valkeinen case RXPORT_MODE_RAW12_HF: 2088afe267f2STomi Valkeinen case RXPORT_MODE_RAW12_LF: 2089afe267f2STomi Valkeinen /* Not implemented */ 2090afe267f2STomi Valkeinen return; 2091afe267f2STomi Valkeinen 2092afe267f2STomi Valkeinen case RXPORT_MODE_CSI2_SYNC: 2093afe267f2STomi Valkeinen case RXPORT_MODE_CSI2_ASYNC: 2094afe267f2STomi Valkeinen 2095afe267f2STomi Valkeinen break; 2096afe267f2STomi Valkeinen } 2097afe267f2STomi Valkeinen 2098afe267f2STomi Valkeinen /* LV_POLARITY & FV_POLARITY */ 2099afe267f2STomi Valkeinen ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2, 0x3, 2100afe267f2STomi Valkeinen rxport->lv_fv_pol); 2101afe267f2STomi Valkeinen 2102afe267f2STomi Valkeinen /* Enable all interrupt sources from this port */ 2103afe267f2STomi Valkeinen ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_HI, 0x07); 2104afe267f2STomi Valkeinen ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_LO, 0x7f); 2105afe267f2STomi Valkeinen 2106afe267f2STomi Valkeinen /* Enable I2C_PASS_THROUGH */ 2107afe267f2STomi Valkeinen ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, 2108afe267f2STomi Valkeinen UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, 2109afe267f2STomi Valkeinen UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH); 2110afe267f2STomi Valkeinen 2111afe267f2STomi Valkeinen /* Enable I2C communication to the serializer via the alias addr */ 2112afe267f2STomi Valkeinen ub960_rxport_write(priv, nport, UB960_RR_SER_ALIAS_ID, 2113afe267f2STomi Valkeinen rxport->ser.alias << 1); 2114afe267f2STomi Valkeinen 2115afe267f2STomi Valkeinen /* Enable RX port */ 2116afe267f2STomi Valkeinen ub960_update_bits(priv, UB960_SR_RX_PORT_CTL, BIT(nport), BIT(nport)); 2117afe267f2STomi Valkeinen 2118afe267f2STomi Valkeinen if (rxport->cdr_mode == RXPORT_CDR_FPD4) { 2119afe267f2STomi Valkeinen /* unreset 960 AEQ */ 2120afe267f2STomi Valkeinen ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x25, 0x41); 2121afe267f2STomi Valkeinen } 2122afe267f2STomi Valkeinen } 2123afe267f2STomi Valkeinen 2124afe267f2STomi Valkeinen static int ub960_init_rx_ports(struct ub960_data *priv) 2125afe267f2STomi Valkeinen { 2126afe267f2STomi Valkeinen unsigned int nport; 2127afe267f2STomi Valkeinen 2128afe267f2STomi Valkeinen for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { 2129afe267f2STomi Valkeinen struct ub960_rxport *rxport = priv->rxports[nport]; 2130afe267f2STomi Valkeinen 2131afe267f2STomi Valkeinen if (!rxport) 2132afe267f2STomi Valkeinen continue; 2133afe267f2STomi Valkeinen 2134afe267f2STomi Valkeinen if (priv->hw_data->is_ub9702) 2135afe267f2STomi Valkeinen ub960_init_rx_port_ub9702(priv, rxport); 2136afe267f2STomi Valkeinen else 2137afe267f2STomi Valkeinen ub960_init_rx_port_ub960(priv, rxport); 2138afe267f2STomi Valkeinen } 2139afe267f2STomi Valkeinen 2140afe267f2STomi Valkeinen return 0; 2141afe267f2STomi Valkeinen } 2142afe267f2STomi Valkeinen 2143afe267f2STomi Valkeinen static void ub960_rxport_handle_events(struct ub960_data *priv, u8 nport) 2144afe267f2STomi Valkeinen { 2145afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 2146afe267f2STomi Valkeinen u8 rx_port_sts1; 2147afe267f2STomi Valkeinen u8 rx_port_sts2; 2148afe267f2STomi Valkeinen u8 csi_rx_sts; 2149afe267f2STomi Valkeinen u8 bcc_sts; 2150afe267f2STomi Valkeinen int ret = 0; 2151afe267f2STomi Valkeinen 2152afe267f2STomi Valkeinen /* Read interrupts (also clears most of them) */ 2153afe267f2STomi Valkeinen if (!ret) 2154afe267f2STomi Valkeinen ret = ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, 2155afe267f2STomi Valkeinen &rx_port_sts1); 2156afe267f2STomi Valkeinen if (!ret) 2157afe267f2STomi Valkeinen ret = ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2, 2158afe267f2STomi Valkeinen &rx_port_sts2); 2159afe267f2STomi Valkeinen if (!ret) 2160afe267f2STomi Valkeinen ret = ub960_rxport_read(priv, nport, UB960_RR_CSI_RX_STS, 2161afe267f2STomi Valkeinen &csi_rx_sts); 2162afe267f2STomi Valkeinen if (!ret) 2163afe267f2STomi Valkeinen ret = ub960_rxport_read(priv, nport, UB960_RR_BCC_STATUS, 2164afe267f2STomi Valkeinen &bcc_sts); 2165afe267f2STomi Valkeinen 2166afe267f2STomi Valkeinen if (ret) 2167afe267f2STomi Valkeinen return; 2168afe267f2STomi Valkeinen 2169afe267f2STomi Valkeinen if (rx_port_sts1 & UB960_RR_RX_PORT_STS1_PARITY_ERROR) { 2170afe267f2STomi Valkeinen u16 v; 2171afe267f2STomi Valkeinen 2172afe267f2STomi Valkeinen ret = ub960_rxport_read16(priv, nport, UB960_RR_RX_PAR_ERR_HI, 2173afe267f2STomi Valkeinen &v); 2174afe267f2STomi Valkeinen if (!ret) 2175afe267f2STomi Valkeinen dev_err(dev, "rx%u parity errors: %u\n", nport, v); 2176afe267f2STomi Valkeinen } 2177afe267f2STomi Valkeinen 2178afe267f2STomi Valkeinen if (rx_port_sts1 & UB960_RR_RX_PORT_STS1_BCC_CRC_ERROR) 2179afe267f2STomi Valkeinen dev_err(dev, "rx%u BCC CRC error\n", nport); 2180afe267f2STomi Valkeinen 2181afe267f2STomi Valkeinen if (rx_port_sts1 & UB960_RR_RX_PORT_STS1_BCC_SEQ_ERROR) 2182afe267f2STomi Valkeinen dev_err(dev, "rx%u BCC SEQ error\n", nport); 2183afe267f2STomi Valkeinen 2184afe267f2STomi Valkeinen if (rx_port_sts2 & UB960_RR_RX_PORT_STS2_LINE_LEN_UNSTABLE) 2185afe267f2STomi Valkeinen dev_err(dev, "rx%u line length unstable\n", nport); 2186afe267f2STomi Valkeinen 2187afe267f2STomi Valkeinen if (rx_port_sts2 & UB960_RR_RX_PORT_STS2_FPD3_ENCODE_ERROR) 2188afe267f2STomi Valkeinen dev_err(dev, "rx%u FPD3 encode error\n", nport); 2189afe267f2STomi Valkeinen 2190afe267f2STomi Valkeinen if (rx_port_sts2 & UB960_RR_RX_PORT_STS2_BUFFER_ERROR) 2191afe267f2STomi Valkeinen dev_err(dev, "rx%u buffer error\n", nport); 2192afe267f2STomi Valkeinen 2193afe267f2STomi Valkeinen if (csi_rx_sts) 2194afe267f2STomi Valkeinen dev_err(dev, "rx%u CSI error: %#02x\n", nport, csi_rx_sts); 2195afe267f2STomi Valkeinen 2196afe267f2STomi Valkeinen if (csi_rx_sts & UB960_RR_CSI_RX_STS_ECC1_ERR) 2197afe267f2STomi Valkeinen dev_err(dev, "rx%u CSI ECC1 error\n", nport); 2198afe267f2STomi Valkeinen 2199afe267f2STomi Valkeinen if (csi_rx_sts & UB960_RR_CSI_RX_STS_ECC2_ERR) 2200afe267f2STomi Valkeinen dev_err(dev, "rx%u CSI ECC2 error\n", nport); 2201afe267f2STomi Valkeinen 2202afe267f2STomi Valkeinen if (csi_rx_sts & UB960_RR_CSI_RX_STS_CKSUM_ERR) 2203afe267f2STomi Valkeinen dev_err(dev, "rx%u CSI checksum error\n", nport); 2204afe267f2STomi Valkeinen 2205afe267f2STomi Valkeinen if (csi_rx_sts & UB960_RR_CSI_RX_STS_LENGTH_ERR) 2206afe267f2STomi Valkeinen dev_err(dev, "rx%u CSI length error\n", nport); 2207afe267f2STomi Valkeinen 2208afe267f2STomi Valkeinen if (bcc_sts) 2209afe267f2STomi Valkeinen dev_err(dev, "rx%u BCC error: %#02x\n", nport, bcc_sts); 2210afe267f2STomi Valkeinen 2211afe267f2STomi Valkeinen if (bcc_sts & UB960_RR_BCC_STATUS_RESP_ERR) 2212afe267f2STomi Valkeinen dev_err(dev, "rx%u BCC response error", nport); 2213afe267f2STomi Valkeinen 2214afe267f2STomi Valkeinen if (bcc_sts & UB960_RR_BCC_STATUS_SLAVE_TO) 2215afe267f2STomi Valkeinen dev_err(dev, "rx%u BCC slave timeout", nport); 2216afe267f2STomi Valkeinen 2217afe267f2STomi Valkeinen if (bcc_sts & UB960_RR_BCC_STATUS_SLAVE_ERR) 2218afe267f2STomi Valkeinen dev_err(dev, "rx%u BCC slave error", nport); 2219afe267f2STomi Valkeinen 2220afe267f2STomi Valkeinen if (bcc_sts & UB960_RR_BCC_STATUS_MASTER_TO) 2221afe267f2STomi Valkeinen dev_err(dev, "rx%u BCC master timeout", nport); 2222afe267f2STomi Valkeinen 2223afe267f2STomi Valkeinen if (bcc_sts & UB960_RR_BCC_STATUS_MASTER_ERR) 2224afe267f2STomi Valkeinen dev_err(dev, "rx%u BCC master error", nport); 2225afe267f2STomi Valkeinen 2226afe267f2STomi Valkeinen if (bcc_sts & UB960_RR_BCC_STATUS_SEQ_ERROR) 2227afe267f2STomi Valkeinen dev_err(dev, "rx%u BCC sequence error", nport); 2228afe267f2STomi Valkeinen 2229afe267f2STomi Valkeinen if (rx_port_sts2 & UB960_RR_RX_PORT_STS2_LINE_LEN_CHG) { 2230afe267f2STomi Valkeinen u16 v; 2231afe267f2STomi Valkeinen 2232afe267f2STomi Valkeinen ret = ub960_rxport_read16(priv, nport, UB960_RR_LINE_LEN_1, &v); 2233afe267f2STomi Valkeinen if (!ret) 2234afe267f2STomi Valkeinen dev_dbg(dev, "rx%u line len changed: %u\n", nport, v); 2235afe267f2STomi Valkeinen } 2236afe267f2STomi Valkeinen 2237afe267f2STomi Valkeinen if (rx_port_sts2 & UB960_RR_RX_PORT_STS2_LINE_CNT_CHG) { 2238afe267f2STomi Valkeinen u16 v; 2239afe267f2STomi Valkeinen 2240afe267f2STomi Valkeinen ret = ub960_rxport_read16(priv, nport, UB960_RR_LINE_COUNT_HI, 2241afe267f2STomi Valkeinen &v); 2242afe267f2STomi Valkeinen if (!ret) 2243afe267f2STomi Valkeinen dev_dbg(dev, "rx%u line count changed: %u\n", nport, v); 2244afe267f2STomi Valkeinen } 2245afe267f2STomi Valkeinen 2246afe267f2STomi Valkeinen if (rx_port_sts1 & UB960_RR_RX_PORT_STS1_LOCK_STS_CHG) { 2247afe267f2STomi Valkeinen dev_dbg(dev, "rx%u: %s, %s, %s, %s\n", nport, 2248afe267f2STomi Valkeinen (rx_port_sts1 & UB960_RR_RX_PORT_STS1_LOCK_STS) ? 2249afe267f2STomi Valkeinen "locked" : 2250afe267f2STomi Valkeinen "unlocked", 2251afe267f2STomi Valkeinen (rx_port_sts1 & UB960_RR_RX_PORT_STS1_PORT_PASS) ? 2252afe267f2STomi Valkeinen "passed" : 2253afe267f2STomi Valkeinen "not passed", 2254afe267f2STomi Valkeinen (rx_port_sts2 & UB960_RR_RX_PORT_STS2_CABLE_FAULT) ? 2255afe267f2STomi Valkeinen "no clock" : 2256afe267f2STomi Valkeinen "clock ok", 2257afe267f2STomi Valkeinen (rx_port_sts2 & UB960_RR_RX_PORT_STS2_FREQ_STABLE) ? 2258afe267f2STomi Valkeinen "stable freq" : 2259afe267f2STomi Valkeinen "unstable freq"); 2260afe267f2STomi Valkeinen } 2261afe267f2STomi Valkeinen } 2262afe267f2STomi Valkeinen 2263afe267f2STomi Valkeinen /* ----------------------------------------------------------------------------- 2264afe267f2STomi Valkeinen * V4L2 2265afe267f2STomi Valkeinen */ 2266afe267f2STomi Valkeinen 2267afe267f2STomi Valkeinen /* 2268afe267f2STomi Valkeinen * The current implementation only supports a simple VC mapping, where all VCs 2269afe267f2STomi Valkeinen * from a one RX port will be mapped to the same VC. Also, the hardware 2270afe267f2STomi Valkeinen * dictates that all streams from an RX port must go to a single TX port. 2271afe267f2STomi Valkeinen * 2272afe267f2STomi Valkeinen * This function decides the target VC numbers for each RX port with a simple 2273afe267f2STomi Valkeinen * algorithm, so that for each TX port, we get VC numbers starting from 0, 2274afe267f2STomi Valkeinen * and counting up. 2275afe267f2STomi Valkeinen * 2276afe267f2STomi Valkeinen * E.g. if all four RX ports are in use, of which the first two go to the 2277afe267f2STomi Valkeinen * first TX port and the secont two go to the second TX port, we would get 2278afe267f2STomi Valkeinen * the following VCs for the four RX ports: 0, 1, 0, 1. 2279afe267f2STomi Valkeinen * 2280afe267f2STomi Valkeinen * TODO: implement a more sophisticated VC mapping. As the driver cannot know 2281afe267f2STomi Valkeinen * what VCs the sinks expect (say, an FPGA with hardcoded VC routing), this 2282afe267f2STomi Valkeinen * probably needs to be somehow configurable. Device tree? 2283afe267f2STomi Valkeinen */ 2284afe267f2STomi Valkeinen static void ub960_get_vc_maps(struct ub960_data *priv, 2285afe267f2STomi Valkeinen struct v4l2_subdev_state *state, u8 *vc) 2286afe267f2STomi Valkeinen { 2287afe267f2STomi Valkeinen u8 cur_vc[UB960_MAX_TX_NPORTS] = {}; 2288afe267f2STomi Valkeinen struct v4l2_subdev_route *route; 2289afe267f2STomi Valkeinen u8 handled_mask = 0; 2290afe267f2STomi Valkeinen 2291afe267f2STomi Valkeinen for_each_active_route(&state->routing, route) { 2292afe267f2STomi Valkeinen unsigned int rx, tx; 2293afe267f2STomi Valkeinen 2294afe267f2STomi Valkeinen rx = ub960_pad_to_port(priv, route->sink_pad); 2295afe267f2STomi Valkeinen if (BIT(rx) & handled_mask) 2296afe267f2STomi Valkeinen continue; 2297afe267f2STomi Valkeinen 2298afe267f2STomi Valkeinen tx = ub960_pad_to_port(priv, route->source_pad); 2299afe267f2STomi Valkeinen 2300afe267f2STomi Valkeinen vc[rx] = cur_vc[tx]++; 2301afe267f2STomi Valkeinen handled_mask |= BIT(rx); 2302afe267f2STomi Valkeinen } 2303afe267f2STomi Valkeinen } 2304afe267f2STomi Valkeinen 2305afe267f2STomi Valkeinen static int ub960_enable_tx_port(struct ub960_data *priv, unsigned int nport) 2306afe267f2STomi Valkeinen { 2307afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 2308afe267f2STomi Valkeinen 2309afe267f2STomi Valkeinen dev_dbg(dev, "enable TX port %u\n", nport); 2310afe267f2STomi Valkeinen 2311afe267f2STomi Valkeinen return ub960_txport_update_bits(priv, nport, UB960_TR_CSI_CTL, 2312afe267f2STomi Valkeinen UB960_TR_CSI_CTL_CSI_ENABLE, 2313afe267f2STomi Valkeinen UB960_TR_CSI_CTL_CSI_ENABLE); 2314afe267f2STomi Valkeinen } 2315afe267f2STomi Valkeinen 2316afe267f2STomi Valkeinen static void ub960_disable_tx_port(struct ub960_data *priv, unsigned int nport) 2317afe267f2STomi Valkeinen { 2318afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 2319afe267f2STomi Valkeinen 2320afe267f2STomi Valkeinen dev_dbg(dev, "disable TX port %u\n", nport); 2321afe267f2STomi Valkeinen 2322afe267f2STomi Valkeinen ub960_txport_update_bits(priv, nport, UB960_TR_CSI_CTL, 2323afe267f2STomi Valkeinen UB960_TR_CSI_CTL_CSI_ENABLE, 0); 2324afe267f2STomi Valkeinen } 2325afe267f2STomi Valkeinen 2326afe267f2STomi Valkeinen static int ub960_enable_rx_port(struct ub960_data *priv, unsigned int nport) 2327afe267f2STomi Valkeinen { 2328afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 2329afe267f2STomi Valkeinen 2330afe267f2STomi Valkeinen dev_dbg(dev, "enable RX port %u\n", nport); 2331afe267f2STomi Valkeinen 2332afe267f2STomi Valkeinen /* Enable forwarding */ 2333afe267f2STomi Valkeinen return ub960_update_bits(priv, UB960_SR_FWD_CTL1, 2334afe267f2STomi Valkeinen UB960_SR_FWD_CTL1_PORT_DIS(nport), 0); 2335afe267f2STomi Valkeinen } 2336afe267f2STomi Valkeinen 2337afe267f2STomi Valkeinen static void ub960_disable_rx_port(struct ub960_data *priv, unsigned int nport) 2338afe267f2STomi Valkeinen { 2339afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 2340afe267f2STomi Valkeinen 2341afe267f2STomi Valkeinen dev_dbg(dev, "disable RX port %u\n", nport); 2342afe267f2STomi Valkeinen 2343afe267f2STomi Valkeinen /* Disable forwarding */ 2344afe267f2STomi Valkeinen ub960_update_bits(priv, UB960_SR_FWD_CTL1, 2345afe267f2STomi Valkeinen UB960_SR_FWD_CTL1_PORT_DIS(nport), 2346afe267f2STomi Valkeinen UB960_SR_FWD_CTL1_PORT_DIS(nport)); 2347afe267f2STomi Valkeinen } 2348afe267f2STomi Valkeinen 2349afe267f2STomi Valkeinen /* 2350afe267f2STomi Valkeinen * The driver only supports using a single VC for each source. This function 2351afe267f2STomi Valkeinen * checks that each source only provides streams using a single VC. 2352afe267f2STomi Valkeinen */ 2353afe267f2STomi Valkeinen static int ub960_validate_stream_vcs(struct ub960_data *priv) 2354afe267f2STomi Valkeinen { 2355afe267f2STomi Valkeinen unsigned int nport; 2356afe267f2STomi Valkeinen unsigned int i; 2357afe267f2STomi Valkeinen 2358afe267f2STomi Valkeinen for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { 2359afe267f2STomi Valkeinen struct ub960_rxport *rxport = priv->rxports[nport]; 2360afe267f2STomi Valkeinen struct v4l2_mbus_frame_desc desc; 2361afe267f2STomi Valkeinen int ret; 2362afe267f2STomi Valkeinen u8 vc; 2363afe267f2STomi Valkeinen 2364afe267f2STomi Valkeinen if (!rxport) 2365afe267f2STomi Valkeinen continue; 2366afe267f2STomi Valkeinen 2367afe267f2STomi Valkeinen ret = v4l2_subdev_call(rxport->source.sd, pad, get_frame_desc, 2368afe267f2STomi Valkeinen rxport->source.pad, &desc); 2369afe267f2STomi Valkeinen if (ret) 2370afe267f2STomi Valkeinen return ret; 2371afe267f2STomi Valkeinen 2372afe267f2STomi Valkeinen if (desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) 2373afe267f2STomi Valkeinen continue; 2374afe267f2STomi Valkeinen 2375afe267f2STomi Valkeinen if (desc.num_entries == 0) 2376afe267f2STomi Valkeinen continue; 2377afe267f2STomi Valkeinen 2378afe267f2STomi Valkeinen vc = desc.entry[0].bus.csi2.vc; 2379afe267f2STomi Valkeinen 2380afe267f2STomi Valkeinen for (i = 1; i < desc.num_entries; i++) { 2381afe267f2STomi Valkeinen if (vc == desc.entry[i].bus.csi2.vc) 2382afe267f2STomi Valkeinen continue; 2383afe267f2STomi Valkeinen 2384afe267f2STomi Valkeinen dev_err(&priv->client->dev, 2385afe267f2STomi Valkeinen "rx%u: source with multiple virtual-channels is not supported\n", 2386afe267f2STomi Valkeinen nport); 2387afe267f2STomi Valkeinen return -ENODEV; 2388afe267f2STomi Valkeinen } 2389afe267f2STomi Valkeinen } 2390afe267f2STomi Valkeinen 2391afe267f2STomi Valkeinen return 0; 2392afe267f2STomi Valkeinen } 2393afe267f2STomi Valkeinen 2394afe267f2STomi Valkeinen static int ub960_configure_ports_for_streaming(struct ub960_data *priv, 2395afe267f2STomi Valkeinen struct v4l2_subdev_state *state) 2396afe267f2STomi Valkeinen { 2397afe267f2STomi Valkeinen u8 fwd_ctl; 2398afe267f2STomi Valkeinen struct { 2399afe267f2STomi Valkeinen u32 num_streams; 2400afe267f2STomi Valkeinen u8 pixel_dt; 2401afe267f2STomi Valkeinen u8 meta_dt; 2402afe267f2STomi Valkeinen u32 meta_lines; 2403afe267f2STomi Valkeinen u32 tx_port; 2404afe267f2STomi Valkeinen } rx_data[UB960_MAX_RX_NPORTS] = {}; 2405afe267f2STomi Valkeinen u8 vc_map[UB960_MAX_RX_NPORTS] = {}; 2406afe267f2STomi Valkeinen struct v4l2_subdev_route *route; 2407afe267f2STomi Valkeinen unsigned int nport; 2408afe267f2STomi Valkeinen int ret; 2409afe267f2STomi Valkeinen 2410afe267f2STomi Valkeinen ret = ub960_validate_stream_vcs(priv); 2411afe267f2STomi Valkeinen if (ret) 2412afe267f2STomi Valkeinen return ret; 2413afe267f2STomi Valkeinen 2414afe267f2STomi Valkeinen ub960_get_vc_maps(priv, state, vc_map); 2415afe267f2STomi Valkeinen 2416afe267f2STomi Valkeinen for_each_active_route(&state->routing, route) { 2417afe267f2STomi Valkeinen struct ub960_rxport *rxport; 2418afe267f2STomi Valkeinen struct ub960_txport *txport; 2419afe267f2STomi Valkeinen struct v4l2_mbus_framefmt *fmt; 2420afe267f2STomi Valkeinen const struct ub960_format_info *ub960_fmt; 2421afe267f2STomi Valkeinen unsigned int nport; 2422afe267f2STomi Valkeinen 2423afe267f2STomi Valkeinen nport = ub960_pad_to_port(priv, route->sink_pad); 2424afe267f2STomi Valkeinen 2425afe267f2STomi Valkeinen rxport = priv->rxports[nport]; 2426afe267f2STomi Valkeinen if (!rxport) 2427afe267f2STomi Valkeinen return -EINVAL; 2428afe267f2STomi Valkeinen 2429afe267f2STomi Valkeinen txport = priv->txports[ub960_pad_to_port(priv, route->source_pad)]; 2430afe267f2STomi Valkeinen if (!txport) 2431afe267f2STomi Valkeinen return -EINVAL; 2432afe267f2STomi Valkeinen 2433afe267f2STomi Valkeinen rx_data[nport].tx_port = ub960_pad_to_port(priv, route->source_pad); 2434afe267f2STomi Valkeinen 2435afe267f2STomi Valkeinen rx_data[nport].num_streams++; 2436afe267f2STomi Valkeinen 2437afe267f2STomi Valkeinen /* For the rest, we are only interested in parallel busses */ 2438afe267f2STomi Valkeinen if (rxport->rx_mode == RXPORT_MODE_CSI2_SYNC || 2439afe267f2STomi Valkeinen rxport->rx_mode == RXPORT_MODE_CSI2_ASYNC) 2440afe267f2STomi Valkeinen continue; 2441afe267f2STomi Valkeinen 2442afe267f2STomi Valkeinen if (rx_data[nport].num_streams > 2) 2443afe267f2STomi Valkeinen return -EPIPE; 2444afe267f2STomi Valkeinen 2445afe267f2STomi Valkeinen fmt = v4l2_subdev_state_get_stream_format(state, 2446afe267f2STomi Valkeinen route->sink_pad, 2447afe267f2STomi Valkeinen route->sink_stream); 2448afe267f2STomi Valkeinen if (!fmt) 2449afe267f2STomi Valkeinen return -EPIPE; 2450afe267f2STomi Valkeinen 2451afe267f2STomi Valkeinen ub960_fmt = ub960_find_format(fmt->code); 2452afe267f2STomi Valkeinen if (!ub960_fmt) 2453afe267f2STomi Valkeinen return -EPIPE; 2454afe267f2STomi Valkeinen 2455afe267f2STomi Valkeinen if (ub960_fmt->meta) { 2456afe267f2STomi Valkeinen if (fmt->height > 3) { 2457afe267f2STomi Valkeinen dev_err(&priv->client->dev, 2458afe267f2STomi Valkeinen "rx%u: unsupported metadata height %u\n", 2459afe267f2STomi Valkeinen nport, fmt->height); 2460afe267f2STomi Valkeinen return -EPIPE; 2461afe267f2STomi Valkeinen } 2462afe267f2STomi Valkeinen 2463afe267f2STomi Valkeinen rx_data[nport].meta_dt = ub960_fmt->datatype; 2464afe267f2STomi Valkeinen rx_data[nport].meta_lines = fmt->height; 2465afe267f2STomi Valkeinen } else { 2466afe267f2STomi Valkeinen rx_data[nport].pixel_dt = ub960_fmt->datatype; 2467afe267f2STomi Valkeinen } 2468afe267f2STomi Valkeinen } 2469afe267f2STomi Valkeinen 2470afe267f2STomi Valkeinen /* Configure RX ports */ 2471afe267f2STomi Valkeinen 2472afe267f2STomi Valkeinen /* 2473afe267f2STomi Valkeinen * Keep all port forwardings disabled by default. Forwarding will be 2474afe267f2STomi Valkeinen * enabled in ub960_enable_rx_port. 2475afe267f2STomi Valkeinen */ 2476afe267f2STomi Valkeinen fwd_ctl = GENMASK(7, 4); 2477afe267f2STomi Valkeinen 2478afe267f2STomi Valkeinen for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { 2479afe267f2STomi Valkeinen struct ub960_rxport *rxport = priv->rxports[nport]; 2480afe267f2STomi Valkeinen u8 vc = vc_map[nport]; 2481afe267f2STomi Valkeinen 2482afe267f2STomi Valkeinen if (rx_data[nport].num_streams == 0) 2483afe267f2STomi Valkeinen continue; 2484afe267f2STomi Valkeinen 2485afe267f2STomi Valkeinen switch (rxport->rx_mode) { 2486afe267f2STomi Valkeinen case RXPORT_MODE_RAW10: 2487afe267f2STomi Valkeinen ub960_rxport_write(priv, nport, UB960_RR_RAW10_ID, 2488afe267f2STomi Valkeinen rx_data[nport].pixel_dt | (vc << UB960_RR_RAW10_ID_VC_SHIFT)); 2489afe267f2STomi Valkeinen 2490afe267f2STomi Valkeinen ub960_rxport_write(priv, rxport->nport, 2491afe267f2STomi Valkeinen UB960_RR_RAW_EMBED_DTYPE, 2492afe267f2STomi Valkeinen (rx_data[nport].meta_lines << UB960_RR_RAW_EMBED_DTYPE_LINES_SHIFT) | 2493afe267f2STomi Valkeinen rx_data[nport].meta_dt); 2494afe267f2STomi Valkeinen 2495afe267f2STomi Valkeinen break; 2496afe267f2STomi Valkeinen 2497afe267f2STomi Valkeinen case RXPORT_MODE_RAW12_HF: 2498afe267f2STomi Valkeinen case RXPORT_MODE_RAW12_LF: 2499afe267f2STomi Valkeinen /* Not implemented */ 2500afe267f2STomi Valkeinen break; 2501afe267f2STomi Valkeinen 2502afe267f2STomi Valkeinen case RXPORT_MODE_CSI2_SYNC: 2503afe267f2STomi Valkeinen case RXPORT_MODE_CSI2_ASYNC: 2504afe267f2STomi Valkeinen if (!priv->hw_data->is_ub9702) { 2505afe267f2STomi Valkeinen /* Map all VCs from this port to the same VC */ 2506afe267f2STomi Valkeinen ub960_rxport_write(priv, nport, UB960_RR_CSI_VC_MAP, 2507afe267f2STomi Valkeinen (vc << UB960_RR_CSI_VC_MAP_SHIFT(3)) | 2508afe267f2STomi Valkeinen (vc << UB960_RR_CSI_VC_MAP_SHIFT(2)) | 2509afe267f2STomi Valkeinen (vc << UB960_RR_CSI_VC_MAP_SHIFT(1)) | 2510afe267f2STomi Valkeinen (vc << UB960_RR_CSI_VC_MAP_SHIFT(0))); 2511afe267f2STomi Valkeinen } else { 2512afe267f2STomi Valkeinen unsigned int i; 2513afe267f2STomi Valkeinen 2514afe267f2STomi Valkeinen /* Map all VCs from this port to VC(nport) */ 2515afe267f2STomi Valkeinen for (i = 0; i < 8; i++) 2516afe267f2STomi Valkeinen ub960_rxport_write(priv, nport, 2517afe267f2STomi Valkeinen UB960_RR_VC_ID_MAP(i), 2518afe267f2STomi Valkeinen nport); 2519afe267f2STomi Valkeinen } 2520afe267f2STomi Valkeinen 2521afe267f2STomi Valkeinen break; 2522afe267f2STomi Valkeinen } 2523afe267f2STomi Valkeinen 2524afe267f2STomi Valkeinen if (rx_data[nport].tx_port == 1) 2525afe267f2STomi Valkeinen fwd_ctl |= BIT(nport); /* forward to TX1 */ 2526afe267f2STomi Valkeinen else 2527afe267f2STomi Valkeinen fwd_ctl &= ~BIT(nport); /* forward to TX0 */ 2528afe267f2STomi Valkeinen } 2529afe267f2STomi Valkeinen 2530afe267f2STomi Valkeinen ub960_write(priv, UB960_SR_FWD_CTL1, fwd_ctl); 2531afe267f2STomi Valkeinen 2532afe267f2STomi Valkeinen return 0; 2533afe267f2STomi Valkeinen } 2534afe267f2STomi Valkeinen 2535afe267f2STomi Valkeinen static void ub960_update_streaming_status(struct ub960_data *priv) 2536afe267f2STomi Valkeinen { 2537afe267f2STomi Valkeinen unsigned int i; 2538afe267f2STomi Valkeinen 2539afe267f2STomi Valkeinen for (i = 0; i < UB960_MAX_NPORTS; i++) { 2540afe267f2STomi Valkeinen if (priv->stream_enable_mask[i]) 2541afe267f2STomi Valkeinen break; 2542afe267f2STomi Valkeinen } 2543afe267f2STomi Valkeinen 2544afe267f2STomi Valkeinen priv->streaming = i < UB960_MAX_NPORTS; 2545afe267f2STomi Valkeinen } 2546afe267f2STomi Valkeinen 2547afe267f2STomi Valkeinen static int ub960_enable_streams(struct v4l2_subdev *sd, 2548afe267f2STomi Valkeinen struct v4l2_subdev_state *state, u32 source_pad, 2549afe267f2STomi Valkeinen u64 source_streams_mask) 2550afe267f2STomi Valkeinen { 2551afe267f2STomi Valkeinen struct ub960_data *priv = sd_to_ub960(sd); 2552afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 2553afe267f2STomi Valkeinen u64 sink_streams[UB960_MAX_RX_NPORTS] = {}; 2554afe267f2STomi Valkeinen struct v4l2_subdev_route *route; 2555afe267f2STomi Valkeinen unsigned int failed_port; 2556afe267f2STomi Valkeinen unsigned int nport; 2557afe267f2STomi Valkeinen int ret; 2558afe267f2STomi Valkeinen 2559afe267f2STomi Valkeinen if (!priv->streaming) { 2560afe267f2STomi Valkeinen dev_dbg(dev, "Prepare for streaming\n"); 2561afe267f2STomi Valkeinen ret = ub960_configure_ports_for_streaming(priv, state); 2562afe267f2STomi Valkeinen if (ret) 2563afe267f2STomi Valkeinen return ret; 2564afe267f2STomi Valkeinen } 2565afe267f2STomi Valkeinen 2566afe267f2STomi Valkeinen /* Enable TX port if not yet enabled */ 2567afe267f2STomi Valkeinen if (!priv->stream_enable_mask[source_pad]) { 2568afe267f2STomi Valkeinen ret = ub960_enable_tx_port(priv, 2569afe267f2STomi Valkeinen ub960_pad_to_port(priv, source_pad)); 2570afe267f2STomi Valkeinen if (ret) 2571afe267f2STomi Valkeinen return ret; 2572afe267f2STomi Valkeinen } 2573afe267f2STomi Valkeinen 2574afe267f2STomi Valkeinen priv->stream_enable_mask[source_pad] |= source_streams_mask; 2575afe267f2STomi Valkeinen 2576afe267f2STomi Valkeinen /* Collect sink streams per pad which we need to enable */ 2577afe267f2STomi Valkeinen for_each_active_route(&state->routing, route) { 2578afe267f2STomi Valkeinen if (route->source_pad != source_pad) 2579afe267f2STomi Valkeinen continue; 2580afe267f2STomi Valkeinen 2581afe267f2STomi Valkeinen if (!(source_streams_mask & BIT_ULL(route->source_stream))) 2582afe267f2STomi Valkeinen continue; 2583afe267f2STomi Valkeinen 2584afe267f2STomi Valkeinen nport = ub960_pad_to_port(priv, route->sink_pad); 2585afe267f2STomi Valkeinen 2586afe267f2STomi Valkeinen sink_streams[nport] |= BIT_ULL(route->sink_stream); 2587afe267f2STomi Valkeinen } 2588afe267f2STomi Valkeinen 2589afe267f2STomi Valkeinen for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { 2590afe267f2STomi Valkeinen if (!sink_streams[nport]) 2591afe267f2STomi Valkeinen continue; 2592afe267f2STomi Valkeinen 2593afe267f2STomi Valkeinen /* Enable the RX port if not yet enabled */ 2594afe267f2STomi Valkeinen if (!priv->stream_enable_mask[nport]) { 2595afe267f2STomi Valkeinen ret = ub960_enable_rx_port(priv, nport); 2596afe267f2STomi Valkeinen if (ret) { 2597afe267f2STomi Valkeinen failed_port = nport; 2598afe267f2STomi Valkeinen goto err; 2599afe267f2STomi Valkeinen } 2600afe267f2STomi Valkeinen } 2601afe267f2STomi Valkeinen 2602afe267f2STomi Valkeinen priv->stream_enable_mask[nport] |= sink_streams[nport]; 2603afe267f2STomi Valkeinen 2604afe267f2STomi Valkeinen dev_dbg(dev, "enable RX port %u streams %#llx\n", nport, 2605afe267f2STomi Valkeinen sink_streams[nport]); 2606afe267f2STomi Valkeinen 2607afe267f2STomi Valkeinen ret = v4l2_subdev_enable_streams( 2608afe267f2STomi Valkeinen priv->rxports[nport]->source.sd, 2609afe267f2STomi Valkeinen priv->rxports[nport]->source.pad, 2610afe267f2STomi Valkeinen sink_streams[nport]); 2611afe267f2STomi Valkeinen if (ret) { 2612afe267f2STomi Valkeinen priv->stream_enable_mask[nport] &= ~sink_streams[nport]; 2613afe267f2STomi Valkeinen 2614afe267f2STomi Valkeinen if (!priv->stream_enable_mask[nport]) 2615afe267f2STomi Valkeinen ub960_disable_rx_port(priv, nport); 2616afe267f2STomi Valkeinen 2617afe267f2STomi Valkeinen failed_port = nport; 2618afe267f2STomi Valkeinen goto err; 2619afe267f2STomi Valkeinen } 2620afe267f2STomi Valkeinen } 2621afe267f2STomi Valkeinen 2622afe267f2STomi Valkeinen priv->streaming = true; 2623afe267f2STomi Valkeinen 2624afe267f2STomi Valkeinen return 0; 2625afe267f2STomi Valkeinen 2626afe267f2STomi Valkeinen err: 2627afe267f2STomi Valkeinen for (nport = 0; nport < failed_port; nport++) { 2628afe267f2STomi Valkeinen if (!sink_streams[nport]) 2629afe267f2STomi Valkeinen continue; 2630afe267f2STomi Valkeinen 2631afe267f2STomi Valkeinen dev_dbg(dev, "disable RX port %u streams %#llx\n", nport, 2632afe267f2STomi Valkeinen sink_streams[nport]); 2633afe267f2STomi Valkeinen 2634afe267f2STomi Valkeinen ret = v4l2_subdev_disable_streams( 2635afe267f2STomi Valkeinen priv->rxports[nport]->source.sd, 2636afe267f2STomi Valkeinen priv->rxports[nport]->source.pad, 2637afe267f2STomi Valkeinen sink_streams[nport]); 2638afe267f2STomi Valkeinen if (ret) 2639afe267f2STomi Valkeinen dev_err(dev, "Failed to disable streams: %d\n", ret); 2640afe267f2STomi Valkeinen 2641afe267f2STomi Valkeinen priv->stream_enable_mask[nport] &= ~sink_streams[nport]; 2642afe267f2STomi Valkeinen 2643afe267f2STomi Valkeinen /* Disable RX port if no active streams */ 2644afe267f2STomi Valkeinen if (!priv->stream_enable_mask[nport]) 2645afe267f2STomi Valkeinen ub960_disable_rx_port(priv, nport); 2646afe267f2STomi Valkeinen } 2647afe267f2STomi Valkeinen 2648afe267f2STomi Valkeinen priv->stream_enable_mask[source_pad] &= ~source_streams_mask; 2649afe267f2STomi Valkeinen 2650afe267f2STomi Valkeinen if (!priv->stream_enable_mask[source_pad]) 2651afe267f2STomi Valkeinen ub960_disable_tx_port(priv, 2652afe267f2STomi Valkeinen ub960_pad_to_port(priv, source_pad)); 2653afe267f2STomi Valkeinen 2654afe267f2STomi Valkeinen ub960_update_streaming_status(priv); 2655afe267f2STomi Valkeinen 2656afe267f2STomi Valkeinen return ret; 2657afe267f2STomi Valkeinen } 2658afe267f2STomi Valkeinen 2659afe267f2STomi Valkeinen static int ub960_disable_streams(struct v4l2_subdev *sd, 2660afe267f2STomi Valkeinen struct v4l2_subdev_state *state, 2661afe267f2STomi Valkeinen u32 source_pad, u64 source_streams_mask) 2662afe267f2STomi Valkeinen { 2663afe267f2STomi Valkeinen struct ub960_data *priv = sd_to_ub960(sd); 2664afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 2665afe267f2STomi Valkeinen u64 sink_streams[UB960_MAX_RX_NPORTS] = {}; 2666afe267f2STomi Valkeinen struct v4l2_subdev_route *route; 2667afe267f2STomi Valkeinen unsigned int nport; 2668afe267f2STomi Valkeinen int ret; 2669afe267f2STomi Valkeinen 2670afe267f2STomi Valkeinen /* Collect sink streams per pad which we need to disable */ 2671afe267f2STomi Valkeinen for_each_active_route(&state->routing, route) { 2672afe267f2STomi Valkeinen if (route->source_pad != source_pad) 2673afe267f2STomi Valkeinen continue; 2674afe267f2STomi Valkeinen 2675afe267f2STomi Valkeinen if (!(source_streams_mask & BIT_ULL(route->source_stream))) 2676afe267f2STomi Valkeinen continue; 2677afe267f2STomi Valkeinen 2678afe267f2STomi Valkeinen nport = ub960_pad_to_port(priv, route->sink_pad); 2679afe267f2STomi Valkeinen 2680afe267f2STomi Valkeinen sink_streams[nport] |= BIT_ULL(route->sink_stream); 2681afe267f2STomi Valkeinen } 2682afe267f2STomi Valkeinen 2683afe267f2STomi Valkeinen for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { 2684afe267f2STomi Valkeinen if (!sink_streams[nport]) 2685afe267f2STomi Valkeinen continue; 2686afe267f2STomi Valkeinen 2687afe267f2STomi Valkeinen dev_dbg(dev, "disable RX port %u streams %#llx\n", nport, 2688afe267f2STomi Valkeinen sink_streams[nport]); 2689afe267f2STomi Valkeinen 2690afe267f2STomi Valkeinen ret = v4l2_subdev_disable_streams( 2691afe267f2STomi Valkeinen priv->rxports[nport]->source.sd, 2692afe267f2STomi Valkeinen priv->rxports[nport]->source.pad, 2693afe267f2STomi Valkeinen sink_streams[nport]); 2694afe267f2STomi Valkeinen if (ret) 2695afe267f2STomi Valkeinen dev_err(dev, "Failed to disable streams: %d\n", ret); 2696afe267f2STomi Valkeinen 2697afe267f2STomi Valkeinen priv->stream_enable_mask[nport] &= ~sink_streams[nport]; 2698afe267f2STomi Valkeinen 2699afe267f2STomi Valkeinen /* Disable RX port if no active streams */ 2700afe267f2STomi Valkeinen if (!priv->stream_enable_mask[nport]) 2701afe267f2STomi Valkeinen ub960_disable_rx_port(priv, nport); 2702afe267f2STomi Valkeinen } 2703afe267f2STomi Valkeinen 2704afe267f2STomi Valkeinen /* Disable TX port if no active streams */ 2705afe267f2STomi Valkeinen 2706afe267f2STomi Valkeinen priv->stream_enable_mask[source_pad] &= ~source_streams_mask; 2707afe267f2STomi Valkeinen 2708afe267f2STomi Valkeinen if (!priv->stream_enable_mask[source_pad]) 2709afe267f2STomi Valkeinen ub960_disable_tx_port(priv, 2710afe267f2STomi Valkeinen ub960_pad_to_port(priv, source_pad)); 2711afe267f2STomi Valkeinen 2712afe267f2STomi Valkeinen ub960_update_streaming_status(priv); 2713afe267f2STomi Valkeinen 2714afe267f2STomi Valkeinen return 0; 2715afe267f2STomi Valkeinen } 2716afe267f2STomi Valkeinen 2717afe267f2STomi Valkeinen static int _ub960_set_routing(struct v4l2_subdev *sd, 2718afe267f2STomi Valkeinen struct v4l2_subdev_state *state, 2719afe267f2STomi Valkeinen struct v4l2_subdev_krouting *routing) 2720afe267f2STomi Valkeinen { 2721afe267f2STomi Valkeinen static const struct v4l2_mbus_framefmt format = { 2722afe267f2STomi Valkeinen .width = 640, 2723afe267f2STomi Valkeinen .height = 480, 2724afe267f2STomi Valkeinen .code = MEDIA_BUS_FMT_UYVY8_1X16, 2725afe267f2STomi Valkeinen .field = V4L2_FIELD_NONE, 2726afe267f2STomi Valkeinen .colorspace = V4L2_COLORSPACE_SRGB, 2727afe267f2STomi Valkeinen .ycbcr_enc = V4L2_YCBCR_ENC_601, 2728afe267f2STomi Valkeinen .quantization = V4L2_QUANTIZATION_LIM_RANGE, 2729afe267f2STomi Valkeinen .xfer_func = V4L2_XFER_FUNC_SRGB, 2730afe267f2STomi Valkeinen }; 2731afe267f2STomi Valkeinen int ret; 2732afe267f2STomi Valkeinen 2733afe267f2STomi Valkeinen /* 2734afe267f2STomi Valkeinen * Note: we can only support up to V4L2_FRAME_DESC_ENTRY_MAX, until 2735afe267f2STomi Valkeinen * frame desc is made dynamically allocated. 2736afe267f2STomi Valkeinen */ 2737afe267f2STomi Valkeinen 2738afe267f2STomi Valkeinen if (routing->num_routes > V4L2_FRAME_DESC_ENTRY_MAX) 2739afe267f2STomi Valkeinen return -E2BIG; 2740afe267f2STomi Valkeinen 2741afe267f2STomi Valkeinen ret = v4l2_subdev_routing_validate(sd, routing, 2742afe267f2STomi Valkeinen V4L2_SUBDEV_ROUTING_ONLY_1_TO_1 | 2743afe267f2STomi Valkeinen V4L2_SUBDEV_ROUTING_NO_SINK_STREAM_MIX); 2744afe267f2STomi Valkeinen if (ret) 2745afe267f2STomi Valkeinen return ret; 2746afe267f2STomi Valkeinen 2747afe267f2STomi Valkeinen ret = v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format); 2748afe267f2STomi Valkeinen if (ret) 2749afe267f2STomi Valkeinen return ret; 2750afe267f2STomi Valkeinen 2751afe267f2STomi Valkeinen return 0; 2752afe267f2STomi Valkeinen } 2753afe267f2STomi Valkeinen 2754afe267f2STomi Valkeinen static int ub960_set_routing(struct v4l2_subdev *sd, 2755afe267f2STomi Valkeinen struct v4l2_subdev_state *state, 2756afe267f2STomi Valkeinen enum v4l2_subdev_format_whence which, 2757afe267f2STomi Valkeinen struct v4l2_subdev_krouting *routing) 2758afe267f2STomi Valkeinen { 2759afe267f2STomi Valkeinen struct ub960_data *priv = sd_to_ub960(sd); 2760afe267f2STomi Valkeinen 2761afe267f2STomi Valkeinen if (which == V4L2_SUBDEV_FORMAT_ACTIVE && priv->streaming) 2762afe267f2STomi Valkeinen return -EBUSY; 2763afe267f2STomi Valkeinen 2764afe267f2STomi Valkeinen return _ub960_set_routing(sd, state, routing); 2765afe267f2STomi Valkeinen } 2766afe267f2STomi Valkeinen 2767afe267f2STomi Valkeinen static int ub960_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, 2768afe267f2STomi Valkeinen struct v4l2_mbus_frame_desc *fd) 2769afe267f2STomi Valkeinen { 2770afe267f2STomi Valkeinen struct ub960_data *priv = sd_to_ub960(sd); 2771afe267f2STomi Valkeinen struct v4l2_subdev_route *route; 2772afe267f2STomi Valkeinen struct v4l2_subdev_state *state; 2773afe267f2STomi Valkeinen int ret = 0; 2774afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 2775afe267f2STomi Valkeinen u8 vc_map[UB960_MAX_RX_NPORTS] = {}; 2776afe267f2STomi Valkeinen 2777afe267f2STomi Valkeinen if (!ub960_pad_is_source(priv, pad)) 2778afe267f2STomi Valkeinen return -EINVAL; 2779afe267f2STomi Valkeinen 2780afe267f2STomi Valkeinen memset(fd, 0, sizeof(*fd)); 2781afe267f2STomi Valkeinen 2782afe267f2STomi Valkeinen fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2; 2783afe267f2STomi Valkeinen 2784afe267f2STomi Valkeinen state = v4l2_subdev_lock_and_get_active_state(&priv->sd); 2785afe267f2STomi Valkeinen 2786afe267f2STomi Valkeinen ub960_get_vc_maps(priv, state, vc_map); 2787afe267f2STomi Valkeinen 2788afe267f2STomi Valkeinen for_each_active_route(&state->routing, route) { 2789afe267f2STomi Valkeinen struct v4l2_mbus_frame_desc_entry *source_entry = NULL; 2790afe267f2STomi Valkeinen struct v4l2_mbus_frame_desc source_fd; 2791afe267f2STomi Valkeinen unsigned int nport; 2792afe267f2STomi Valkeinen unsigned int i; 2793afe267f2STomi Valkeinen 2794afe267f2STomi Valkeinen if (route->source_pad != pad) 2795afe267f2STomi Valkeinen continue; 2796afe267f2STomi Valkeinen 2797afe267f2STomi Valkeinen nport = ub960_pad_to_port(priv, route->sink_pad); 2798afe267f2STomi Valkeinen 2799afe267f2STomi Valkeinen ret = v4l2_subdev_call(priv->rxports[nport]->source.sd, pad, 2800afe267f2STomi Valkeinen get_frame_desc, 2801afe267f2STomi Valkeinen priv->rxports[nport]->source.pad, 2802afe267f2STomi Valkeinen &source_fd); 2803afe267f2STomi Valkeinen if (ret) { 2804afe267f2STomi Valkeinen dev_err(dev, 2805afe267f2STomi Valkeinen "Failed to get source frame desc for pad %u\n", 2806afe267f2STomi Valkeinen route->sink_pad); 2807afe267f2STomi Valkeinen goto out_unlock; 2808afe267f2STomi Valkeinen } 2809afe267f2STomi Valkeinen 2810afe267f2STomi Valkeinen for (i = 0; i < source_fd.num_entries; i++) { 2811afe267f2STomi Valkeinen if (source_fd.entry[i].stream == route->sink_stream) { 2812afe267f2STomi Valkeinen source_entry = &source_fd.entry[i]; 2813afe267f2STomi Valkeinen break; 2814afe267f2STomi Valkeinen } 2815afe267f2STomi Valkeinen } 2816afe267f2STomi Valkeinen 2817afe267f2STomi Valkeinen if (!source_entry) { 2818afe267f2STomi Valkeinen dev_err(dev, 2819afe267f2STomi Valkeinen "Failed to find stream from source frame desc\n"); 2820afe267f2STomi Valkeinen ret = -EPIPE; 2821afe267f2STomi Valkeinen goto out_unlock; 2822afe267f2STomi Valkeinen } 2823afe267f2STomi Valkeinen 2824afe267f2STomi Valkeinen fd->entry[fd->num_entries].stream = route->source_stream; 2825afe267f2STomi Valkeinen fd->entry[fd->num_entries].flags = source_entry->flags; 2826afe267f2STomi Valkeinen fd->entry[fd->num_entries].length = source_entry->length; 2827afe267f2STomi Valkeinen fd->entry[fd->num_entries].pixelcode = source_entry->pixelcode; 2828afe267f2STomi Valkeinen 2829afe267f2STomi Valkeinen fd->entry[fd->num_entries].bus.csi2.vc = vc_map[nport]; 2830afe267f2STomi Valkeinen 2831afe267f2STomi Valkeinen if (source_fd.type == V4L2_MBUS_FRAME_DESC_TYPE_CSI2) { 2832afe267f2STomi Valkeinen fd->entry[fd->num_entries].bus.csi2.dt = 2833afe267f2STomi Valkeinen source_entry->bus.csi2.dt; 2834afe267f2STomi Valkeinen } else { 2835afe267f2STomi Valkeinen const struct ub960_format_info *ub960_fmt; 2836afe267f2STomi Valkeinen struct v4l2_mbus_framefmt *fmt; 2837afe267f2STomi Valkeinen 2838afe267f2STomi Valkeinen fmt = v4l2_subdev_state_get_stream_format(state, pad, 2839afe267f2STomi Valkeinen route->source_stream); 2840afe267f2STomi Valkeinen 2841afe267f2STomi Valkeinen if (!fmt) { 2842afe267f2STomi Valkeinen ret = -EINVAL; 2843afe267f2STomi Valkeinen goto out_unlock; 2844afe267f2STomi Valkeinen } 2845afe267f2STomi Valkeinen 2846afe267f2STomi Valkeinen ub960_fmt = ub960_find_format(fmt->code); 2847afe267f2STomi Valkeinen if (!ub960_fmt) { 2848afe267f2STomi Valkeinen dev_err(dev, "Unable to find format\n"); 2849afe267f2STomi Valkeinen ret = -EINVAL; 2850afe267f2STomi Valkeinen goto out_unlock; 2851afe267f2STomi Valkeinen } 2852afe267f2STomi Valkeinen 2853afe267f2STomi Valkeinen fd->entry[fd->num_entries].bus.csi2.dt = 2854afe267f2STomi Valkeinen ub960_fmt->datatype; 2855afe267f2STomi Valkeinen } 2856afe267f2STomi Valkeinen 2857afe267f2STomi Valkeinen fd->num_entries++; 2858afe267f2STomi Valkeinen } 2859afe267f2STomi Valkeinen 2860afe267f2STomi Valkeinen out_unlock: 2861afe267f2STomi Valkeinen v4l2_subdev_unlock_state(state); 2862afe267f2STomi Valkeinen 2863afe267f2STomi Valkeinen return ret; 2864afe267f2STomi Valkeinen } 2865afe267f2STomi Valkeinen 2866afe267f2STomi Valkeinen static int ub960_set_fmt(struct v4l2_subdev *sd, 2867afe267f2STomi Valkeinen struct v4l2_subdev_state *state, 2868afe267f2STomi Valkeinen struct v4l2_subdev_format *format) 2869afe267f2STomi Valkeinen { 2870afe267f2STomi Valkeinen struct ub960_data *priv = sd_to_ub960(sd); 2871afe267f2STomi Valkeinen struct v4l2_mbus_framefmt *fmt; 2872afe267f2STomi Valkeinen 2873afe267f2STomi Valkeinen if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE && priv->streaming) 2874afe267f2STomi Valkeinen return -EBUSY; 2875afe267f2STomi Valkeinen 2876afe267f2STomi Valkeinen /* No transcoding, source and sink formats must match. */ 2877afe267f2STomi Valkeinen if (ub960_pad_is_source(priv, format->pad)) 2878afe267f2STomi Valkeinen return v4l2_subdev_get_fmt(sd, state, format); 2879afe267f2STomi Valkeinen 2880afe267f2STomi Valkeinen /* 2881afe267f2STomi Valkeinen * Default to the first format if the requested media bus code isn't 2882afe267f2STomi Valkeinen * supported. 2883afe267f2STomi Valkeinen */ 2884afe267f2STomi Valkeinen if (!ub960_find_format(format->format.code)) 2885afe267f2STomi Valkeinen format->format.code = ub960_formats[0].code; 2886afe267f2STomi Valkeinen 2887afe267f2STomi Valkeinen fmt = v4l2_subdev_state_get_stream_format(state, format->pad, 2888afe267f2STomi Valkeinen format->stream); 2889afe267f2STomi Valkeinen if (!fmt) 2890afe267f2STomi Valkeinen return -EINVAL; 2891afe267f2STomi Valkeinen 2892afe267f2STomi Valkeinen *fmt = format->format; 2893afe267f2STomi Valkeinen 2894afe267f2STomi Valkeinen fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad, 2895afe267f2STomi Valkeinen format->stream); 2896afe267f2STomi Valkeinen if (!fmt) 2897afe267f2STomi Valkeinen return -EINVAL; 2898afe267f2STomi Valkeinen 2899afe267f2STomi Valkeinen *fmt = format->format; 2900afe267f2STomi Valkeinen 2901afe267f2STomi Valkeinen return 0; 2902afe267f2STomi Valkeinen } 2903afe267f2STomi Valkeinen 2904afe267f2STomi Valkeinen static int ub960_init_cfg(struct v4l2_subdev *sd, 2905afe267f2STomi Valkeinen struct v4l2_subdev_state *state) 2906afe267f2STomi Valkeinen { 2907afe267f2STomi Valkeinen struct ub960_data *priv = sd_to_ub960(sd); 2908afe267f2STomi Valkeinen 2909afe267f2STomi Valkeinen struct v4l2_subdev_route routes[] = { 2910afe267f2STomi Valkeinen { 2911afe267f2STomi Valkeinen .sink_pad = 0, 2912afe267f2STomi Valkeinen .sink_stream = 0, 2913afe267f2STomi Valkeinen .source_pad = priv->hw_data->num_rxports, 2914afe267f2STomi Valkeinen .source_stream = 0, 2915afe267f2STomi Valkeinen .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, 2916afe267f2STomi Valkeinen }, 2917afe267f2STomi Valkeinen }; 2918afe267f2STomi Valkeinen 2919afe267f2STomi Valkeinen struct v4l2_subdev_krouting routing = { 2920afe267f2STomi Valkeinen .num_routes = ARRAY_SIZE(routes), 2921afe267f2STomi Valkeinen .routes = routes, 2922afe267f2STomi Valkeinen }; 2923afe267f2STomi Valkeinen 2924afe267f2STomi Valkeinen return _ub960_set_routing(sd, state, &routing); 2925afe267f2STomi Valkeinen } 2926afe267f2STomi Valkeinen 2927afe267f2STomi Valkeinen static const struct v4l2_subdev_pad_ops ub960_pad_ops = { 2928afe267f2STomi Valkeinen .enable_streams = ub960_enable_streams, 2929afe267f2STomi Valkeinen .disable_streams = ub960_disable_streams, 2930afe267f2STomi Valkeinen 2931afe267f2STomi Valkeinen .set_routing = ub960_set_routing, 2932afe267f2STomi Valkeinen .get_frame_desc = ub960_get_frame_desc, 2933afe267f2STomi Valkeinen 2934afe267f2STomi Valkeinen .get_fmt = v4l2_subdev_get_fmt, 2935afe267f2STomi Valkeinen .set_fmt = ub960_set_fmt, 2936afe267f2STomi Valkeinen 2937afe267f2STomi Valkeinen .init_cfg = ub960_init_cfg, 2938afe267f2STomi Valkeinen }; 2939afe267f2STomi Valkeinen 2940afe267f2STomi Valkeinen static int ub960_log_status(struct v4l2_subdev *sd) 2941afe267f2STomi Valkeinen { 2942afe267f2STomi Valkeinen struct ub960_data *priv = sd_to_ub960(sd); 2943afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 2944afe267f2STomi Valkeinen struct v4l2_subdev_state *state; 2945afe267f2STomi Valkeinen unsigned int nport; 2946afe267f2STomi Valkeinen unsigned int i; 2947afe267f2STomi Valkeinen u16 v16 = 0; 2948afe267f2STomi Valkeinen u8 v = 0; 2949afe267f2STomi Valkeinen u8 id[UB960_SR_FPD3_RX_ID_LEN]; 2950afe267f2STomi Valkeinen 2951afe267f2STomi Valkeinen state = v4l2_subdev_lock_and_get_active_state(sd); 2952afe267f2STomi Valkeinen 2953afe267f2STomi Valkeinen for (i = 0; i < sizeof(id); i++) 2954afe267f2STomi Valkeinen ub960_read(priv, UB960_SR_FPD3_RX_ID(i), &id[i]); 2955afe267f2STomi Valkeinen 2956afe267f2STomi Valkeinen dev_info(dev, "ID '%.*s'\n", (int)sizeof(id), id); 2957afe267f2STomi Valkeinen 2958afe267f2STomi Valkeinen for (nport = 0; nport < priv->hw_data->num_txports; nport++) { 2959afe267f2STomi Valkeinen struct ub960_txport *txport = priv->txports[nport]; 2960afe267f2STomi Valkeinen 2961afe267f2STomi Valkeinen dev_info(dev, "TX %u\n", nport); 2962afe267f2STomi Valkeinen 2963afe267f2STomi Valkeinen if (!txport) { 2964afe267f2STomi Valkeinen dev_info(dev, "\tNot initialized\n"); 2965afe267f2STomi Valkeinen continue; 2966afe267f2STomi Valkeinen } 2967afe267f2STomi Valkeinen 2968afe267f2STomi Valkeinen ub960_txport_read(priv, nport, UB960_TR_CSI_STS, &v); 2969afe267f2STomi Valkeinen dev_info(dev, "\tsync %u, pass %u\n", v & (u8)BIT(1), 2970afe267f2STomi Valkeinen v & (u8)BIT(0)); 2971afe267f2STomi Valkeinen 2972afe267f2STomi Valkeinen ub960_read16(priv, UB960_SR_CSI_FRAME_COUNT_HI(nport), &v16); 2973afe267f2STomi Valkeinen dev_info(dev, "\tframe counter %u\n", v16); 2974afe267f2STomi Valkeinen 2975afe267f2STomi Valkeinen ub960_read16(priv, UB960_SR_CSI_FRAME_ERR_COUNT_HI(nport), &v16); 2976afe267f2STomi Valkeinen dev_info(dev, "\tframe error counter %u\n", v16); 2977afe267f2STomi Valkeinen 2978afe267f2STomi Valkeinen ub960_read16(priv, UB960_SR_CSI_LINE_COUNT_HI(nport), &v16); 2979afe267f2STomi Valkeinen dev_info(dev, "\tline counter %u\n", v16); 2980afe267f2STomi Valkeinen 2981afe267f2STomi Valkeinen ub960_read16(priv, UB960_SR_CSI_LINE_ERR_COUNT_HI(nport), &v16); 2982afe267f2STomi Valkeinen dev_info(dev, "\tline error counter %u\n", v16); 2983afe267f2STomi Valkeinen } 2984afe267f2STomi Valkeinen 2985afe267f2STomi Valkeinen for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { 2986afe267f2STomi Valkeinen struct ub960_rxport *rxport = priv->rxports[nport]; 2987afe267f2STomi Valkeinen u8 eq_level; 2988afe267f2STomi Valkeinen s8 strobe_pos; 2989afe267f2STomi Valkeinen unsigned int i; 2990afe267f2STomi Valkeinen 2991afe267f2STomi Valkeinen dev_info(dev, "RX %u\n", nport); 2992afe267f2STomi Valkeinen 2993afe267f2STomi Valkeinen if (!rxport) { 2994afe267f2STomi Valkeinen dev_info(dev, "\tNot initialized\n"); 2995afe267f2STomi Valkeinen continue; 2996afe267f2STomi Valkeinen } 2997afe267f2STomi Valkeinen 2998afe267f2STomi Valkeinen ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, &v); 2999afe267f2STomi Valkeinen 3000afe267f2STomi Valkeinen if (v & UB960_RR_RX_PORT_STS1_LOCK_STS) 3001afe267f2STomi Valkeinen dev_info(dev, "\tLocked\n"); 3002afe267f2STomi Valkeinen else 3003afe267f2STomi Valkeinen dev_info(dev, "\tNot locked\n"); 3004afe267f2STomi Valkeinen 3005afe267f2STomi Valkeinen dev_info(dev, "\trx_port_sts1 %#02x\n", v); 3006afe267f2STomi Valkeinen ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2, &v); 3007afe267f2STomi Valkeinen dev_info(dev, "\trx_port_sts2 %#02x\n", v); 3008afe267f2STomi Valkeinen 3009afe267f2STomi Valkeinen ub960_rxport_read16(priv, nport, UB960_RR_RX_FREQ_HIGH, &v16); 3010afe267f2STomi Valkeinen dev_info(dev, "\tlink freq %llu Hz\n", (v16 * 1000000ULL) >> 8); 3011afe267f2STomi Valkeinen 3012afe267f2STomi Valkeinen ub960_rxport_read16(priv, nport, UB960_RR_RX_PAR_ERR_HI, &v16); 3013afe267f2STomi Valkeinen dev_info(dev, "\tparity errors %u\n", v16); 3014afe267f2STomi Valkeinen 3015afe267f2STomi Valkeinen ub960_rxport_read16(priv, nport, UB960_RR_LINE_COUNT_HI, &v16); 3016afe267f2STomi Valkeinen dev_info(dev, "\tlines per frame %u\n", v16); 3017afe267f2STomi Valkeinen 3018afe267f2STomi Valkeinen ub960_rxport_read16(priv, nport, UB960_RR_LINE_LEN_1, &v16); 3019afe267f2STomi Valkeinen dev_info(dev, "\tbytes per line %u\n", v16); 3020afe267f2STomi Valkeinen 3021afe267f2STomi Valkeinen ub960_rxport_read(priv, nport, UB960_RR_CSI_ERR_COUNTER, &v); 3022afe267f2STomi Valkeinen dev_info(dev, "\tcsi_err_counter %u\n", v); 3023afe267f2STomi Valkeinen 3024afe267f2STomi Valkeinen /* Strobe */ 3025afe267f2STomi Valkeinen 3026afe267f2STomi Valkeinen ub960_read(priv, UB960_XR_AEQ_CTL1, &v); 3027afe267f2STomi Valkeinen 3028afe267f2STomi Valkeinen dev_info(dev, "\t%s strobe\n", 3029afe267f2STomi Valkeinen (v & UB960_XR_AEQ_CTL1_AEQ_SFILTER_EN) ? "Adaptive" : 3030afe267f2STomi Valkeinen "Manual"); 3031afe267f2STomi Valkeinen 3032afe267f2STomi Valkeinen if (v & UB960_XR_AEQ_CTL1_AEQ_SFILTER_EN) { 3033afe267f2STomi Valkeinen ub960_read(priv, UB960_XR_SFILTER_CFG, &v); 3034afe267f2STomi Valkeinen 3035afe267f2STomi Valkeinen dev_info(dev, "\tStrobe range [%d, %d]\n", 3036afe267f2STomi Valkeinen ((v >> UB960_XR_SFILTER_CFG_SFILTER_MIN_SHIFT) & 0xf) - 7, 3037afe267f2STomi Valkeinen ((v >> UB960_XR_SFILTER_CFG_SFILTER_MAX_SHIFT) & 0xf) - 7); 3038afe267f2STomi Valkeinen } 3039afe267f2STomi Valkeinen 3040afe267f2STomi Valkeinen ub960_rxport_get_strobe_pos(priv, nport, &strobe_pos); 3041afe267f2STomi Valkeinen 3042afe267f2STomi Valkeinen dev_info(dev, "\tStrobe pos %d\n", strobe_pos); 3043afe267f2STomi Valkeinen 3044afe267f2STomi Valkeinen /* EQ */ 3045afe267f2STomi Valkeinen 3046afe267f2STomi Valkeinen ub960_rxport_read(priv, nport, UB960_RR_AEQ_BYPASS, &v); 3047afe267f2STomi Valkeinen 3048afe267f2STomi Valkeinen dev_info(dev, "\t%s EQ\n", 3049afe267f2STomi Valkeinen (v & UB960_RR_AEQ_BYPASS_ENABLE) ? "Manual" : 3050afe267f2STomi Valkeinen "Adaptive"); 3051afe267f2STomi Valkeinen 3052afe267f2STomi Valkeinen if (!(v & UB960_RR_AEQ_BYPASS_ENABLE)) { 3053afe267f2STomi Valkeinen ub960_rxport_read(priv, nport, UB960_RR_AEQ_MIN_MAX, &v); 3054afe267f2STomi Valkeinen 3055afe267f2STomi Valkeinen dev_info(dev, "\tEQ range [%u, %u]\n", 3056afe267f2STomi Valkeinen (v >> UB960_RR_AEQ_MIN_MAX_AEQ_FLOOR_SHIFT) & 0xf, 3057afe267f2STomi Valkeinen (v >> UB960_RR_AEQ_MIN_MAX_AEQ_MAX_SHIFT) & 0xf); 3058afe267f2STomi Valkeinen } 3059afe267f2STomi Valkeinen 3060afe267f2STomi Valkeinen if (ub960_rxport_get_eq_level(priv, nport, &eq_level) == 0) 3061afe267f2STomi Valkeinen dev_info(dev, "\tEQ level %u\n", eq_level); 3062afe267f2STomi Valkeinen 3063afe267f2STomi Valkeinen /* GPIOs */ 3064afe267f2STomi Valkeinen for (i = 0; i < UB960_NUM_BC_GPIOS; i++) { 3065afe267f2STomi Valkeinen u8 ctl_reg; 3066afe267f2STomi Valkeinen u8 ctl_shift; 3067afe267f2STomi Valkeinen 3068afe267f2STomi Valkeinen ctl_reg = UB960_RR_BC_GPIO_CTL(i / 2); 3069afe267f2STomi Valkeinen ctl_shift = (i % 2) * 4; 3070afe267f2STomi Valkeinen 3071afe267f2STomi Valkeinen ub960_rxport_read(priv, nport, ctl_reg, &v); 3072afe267f2STomi Valkeinen 3073afe267f2STomi Valkeinen dev_info(dev, "\tGPIO%u: mode %u\n", i, 3074afe267f2STomi Valkeinen (v >> ctl_shift) & 0xf); 3075afe267f2STomi Valkeinen } 3076afe267f2STomi Valkeinen } 3077afe267f2STomi Valkeinen 3078afe267f2STomi Valkeinen v4l2_subdev_unlock_state(state); 3079afe267f2STomi Valkeinen 3080afe267f2STomi Valkeinen return 0; 3081afe267f2STomi Valkeinen } 3082afe267f2STomi Valkeinen 3083afe267f2STomi Valkeinen static const struct v4l2_subdev_core_ops ub960_subdev_core_ops = { 3084afe267f2STomi Valkeinen .log_status = ub960_log_status, 3085afe267f2STomi Valkeinen .subscribe_event = v4l2_ctrl_subdev_subscribe_event, 3086afe267f2STomi Valkeinen .unsubscribe_event = v4l2_event_subdev_unsubscribe, 3087afe267f2STomi Valkeinen }; 3088afe267f2STomi Valkeinen 3089afe267f2STomi Valkeinen static const struct v4l2_subdev_ops ub960_subdev_ops = { 3090afe267f2STomi Valkeinen .core = &ub960_subdev_core_ops, 3091afe267f2STomi Valkeinen .pad = &ub960_pad_ops, 3092afe267f2STomi Valkeinen }; 3093afe267f2STomi Valkeinen 3094afe267f2STomi Valkeinen static const struct media_entity_operations ub960_entity_ops = { 3095afe267f2STomi Valkeinen .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1, 3096afe267f2STomi Valkeinen .link_validate = v4l2_subdev_link_validate, 3097afe267f2STomi Valkeinen .has_pad_interdep = v4l2_subdev_has_pad_interdep, 3098afe267f2STomi Valkeinen }; 3099afe267f2STomi Valkeinen 3100afe267f2STomi Valkeinen /* ----------------------------------------------------------------------------- 3101afe267f2STomi Valkeinen * Core 3102afe267f2STomi Valkeinen */ 3103afe267f2STomi Valkeinen 3104afe267f2STomi Valkeinen static irqreturn_t ub960_handle_events(int irq, void *arg) 3105afe267f2STomi Valkeinen { 3106afe267f2STomi Valkeinen struct ub960_data *priv = arg; 3107afe267f2STomi Valkeinen unsigned int i; 3108afe267f2STomi Valkeinen u8 int_sts; 3109afe267f2STomi Valkeinen u8 fwd_sts; 3110afe267f2STomi Valkeinen int ret; 3111afe267f2STomi Valkeinen 3112afe267f2STomi Valkeinen ret = ub960_read(priv, UB960_SR_INTERRUPT_STS, &int_sts); 3113afe267f2STomi Valkeinen if (ret || !int_sts) 3114afe267f2STomi Valkeinen return IRQ_NONE; 3115afe267f2STomi Valkeinen 3116afe267f2STomi Valkeinen dev_dbg(&priv->client->dev, "INTERRUPT_STS %x\n", int_sts); 3117afe267f2STomi Valkeinen 3118afe267f2STomi Valkeinen ret = ub960_read(priv, UB960_SR_FWD_STS, &fwd_sts); 3119afe267f2STomi Valkeinen if (ret) 3120afe267f2STomi Valkeinen return IRQ_NONE; 3121afe267f2STomi Valkeinen 3122afe267f2STomi Valkeinen dev_dbg(&priv->client->dev, "FWD_STS %#02x\n", fwd_sts); 3123afe267f2STomi Valkeinen 3124afe267f2STomi Valkeinen for (i = 0; i < priv->hw_data->num_txports; i++) { 3125afe267f2STomi Valkeinen if (int_sts & UB960_SR_INTERRUPT_STS_IS_CSI_TX(i)) 3126afe267f2STomi Valkeinen ub960_csi_handle_events(priv, i); 3127afe267f2STomi Valkeinen } 3128afe267f2STomi Valkeinen 3129afe267f2STomi Valkeinen for (i = 0; i < priv->hw_data->num_rxports; i++) { 3130afe267f2STomi Valkeinen if (!priv->rxports[i]) 3131afe267f2STomi Valkeinen continue; 3132afe267f2STomi Valkeinen 3133afe267f2STomi Valkeinen if (int_sts & UB960_SR_INTERRUPT_STS_IS_RX(i)) 3134afe267f2STomi Valkeinen ub960_rxport_handle_events(priv, i); 3135afe267f2STomi Valkeinen } 3136afe267f2STomi Valkeinen 3137afe267f2STomi Valkeinen return IRQ_HANDLED; 3138afe267f2STomi Valkeinen } 3139afe267f2STomi Valkeinen 3140afe267f2STomi Valkeinen static void ub960_handler_work(struct work_struct *work) 3141afe267f2STomi Valkeinen { 3142afe267f2STomi Valkeinen struct delayed_work *dwork = to_delayed_work(work); 3143afe267f2STomi Valkeinen struct ub960_data *priv = 3144afe267f2STomi Valkeinen container_of(dwork, struct ub960_data, poll_work); 3145afe267f2STomi Valkeinen 3146afe267f2STomi Valkeinen ub960_handle_events(0, priv); 3147afe267f2STomi Valkeinen 3148afe267f2STomi Valkeinen schedule_delayed_work(&priv->poll_work, 3149afe267f2STomi Valkeinen msecs_to_jiffies(UB960_POLL_TIME_MS)); 3150afe267f2STomi Valkeinen } 3151afe267f2STomi Valkeinen 3152afe267f2STomi Valkeinen static void ub960_txport_free_ports(struct ub960_data *priv) 3153afe267f2STomi Valkeinen { 3154afe267f2STomi Valkeinen unsigned int nport; 3155afe267f2STomi Valkeinen 3156afe267f2STomi Valkeinen for (nport = 0; nport < priv->hw_data->num_txports; nport++) { 3157afe267f2STomi Valkeinen struct ub960_txport *txport = priv->txports[nport]; 3158afe267f2STomi Valkeinen 3159afe267f2STomi Valkeinen if (!txport) 3160afe267f2STomi Valkeinen continue; 3161afe267f2STomi Valkeinen 3162afe267f2STomi Valkeinen kfree(txport); 3163afe267f2STomi Valkeinen priv->txports[nport] = NULL; 3164afe267f2STomi Valkeinen } 3165afe267f2STomi Valkeinen } 3166afe267f2STomi Valkeinen 3167afe267f2STomi Valkeinen static void ub960_rxport_free_ports(struct ub960_data *priv) 3168afe267f2STomi Valkeinen { 3169afe267f2STomi Valkeinen unsigned int nport; 3170afe267f2STomi Valkeinen 3171afe267f2STomi Valkeinen for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { 3172afe267f2STomi Valkeinen struct ub960_rxport *rxport = priv->rxports[nport]; 3173afe267f2STomi Valkeinen 3174afe267f2STomi Valkeinen if (!rxport) 3175afe267f2STomi Valkeinen continue; 3176afe267f2STomi Valkeinen 3177afe267f2STomi Valkeinen fwnode_handle_put(rxport->source.ep_fwnode); 3178afe267f2STomi Valkeinen fwnode_handle_put(rxport->ser.fwnode); 3179afe267f2STomi Valkeinen 3180afe267f2STomi Valkeinen kfree(rxport); 3181afe267f2STomi Valkeinen priv->rxports[nport] = NULL; 3182afe267f2STomi Valkeinen } 3183afe267f2STomi Valkeinen } 3184afe267f2STomi Valkeinen 3185afe267f2STomi Valkeinen static int 3186afe267f2STomi Valkeinen ub960_parse_dt_rxport_link_properties(struct ub960_data *priv, 3187afe267f2STomi Valkeinen struct fwnode_handle *link_fwnode, 3188afe267f2STomi Valkeinen struct ub960_rxport *rxport) 3189afe267f2STomi Valkeinen { 3190afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 3191afe267f2STomi Valkeinen unsigned int nport = rxport->nport; 3192afe267f2STomi Valkeinen u32 rx_mode; 3193afe267f2STomi Valkeinen u32 cdr_mode; 3194afe267f2STomi Valkeinen s32 strobe_pos; 3195afe267f2STomi Valkeinen u32 eq_level; 3196afe267f2STomi Valkeinen u32 ser_i2c_alias; 3197afe267f2STomi Valkeinen int ret; 3198afe267f2STomi Valkeinen 3199afe267f2STomi Valkeinen cdr_mode = RXPORT_CDR_FPD3; 3200afe267f2STomi Valkeinen 3201afe267f2STomi Valkeinen ret = fwnode_property_read_u32(link_fwnode, "ti,cdr-mode", &cdr_mode); 3202afe267f2STomi Valkeinen if (ret < 0 && ret != -EINVAL) { 3203afe267f2STomi Valkeinen dev_err(dev, "rx%u: failed to read '%s': %d\n", nport, 3204afe267f2STomi Valkeinen "ti,cdr-mode", ret); 3205afe267f2STomi Valkeinen return ret; 3206afe267f2STomi Valkeinen } 3207afe267f2STomi Valkeinen 3208afe267f2STomi Valkeinen if (cdr_mode > RXPORT_CDR_LAST) { 3209afe267f2STomi Valkeinen dev_err(dev, "rx%u: bad 'ti,cdr-mode' %u\n", nport, cdr_mode); 3210afe267f2STomi Valkeinen return -EINVAL; 3211afe267f2STomi Valkeinen } 3212afe267f2STomi Valkeinen 3213afe267f2STomi Valkeinen if (!priv->hw_data->is_fpdlink4 && cdr_mode == RXPORT_CDR_FPD4) { 3214afe267f2STomi Valkeinen dev_err(dev, "rx%u: FPD-Link 4 CDR not supported\n", nport); 3215afe267f2STomi Valkeinen return -EINVAL; 3216afe267f2STomi Valkeinen } 3217afe267f2STomi Valkeinen 3218afe267f2STomi Valkeinen rxport->cdr_mode = cdr_mode; 3219afe267f2STomi Valkeinen 3220afe267f2STomi Valkeinen ret = fwnode_property_read_u32(link_fwnode, "ti,rx-mode", &rx_mode); 3221afe267f2STomi Valkeinen if (ret < 0) { 3222afe267f2STomi Valkeinen dev_err(dev, "rx%u: failed to read '%s': %d\n", nport, 3223afe267f2STomi Valkeinen "ti,rx-mode", ret); 3224afe267f2STomi Valkeinen return ret; 3225afe267f2STomi Valkeinen } 3226afe267f2STomi Valkeinen 3227afe267f2STomi Valkeinen if (rx_mode > RXPORT_MODE_LAST) { 3228afe267f2STomi Valkeinen dev_err(dev, "rx%u: bad 'ti,rx-mode' %u\n", nport, rx_mode); 3229afe267f2STomi Valkeinen return -EINVAL; 3230afe267f2STomi Valkeinen } 3231afe267f2STomi Valkeinen 3232afe267f2STomi Valkeinen switch (rx_mode) { 3233afe267f2STomi Valkeinen case RXPORT_MODE_RAW12_HF: 3234afe267f2STomi Valkeinen case RXPORT_MODE_RAW12_LF: 3235afe267f2STomi Valkeinen case RXPORT_MODE_CSI2_ASYNC: 3236afe267f2STomi Valkeinen dev_err(dev, "rx%u: unsupported 'ti,rx-mode' %u\n", nport, 3237afe267f2STomi Valkeinen rx_mode); 3238afe267f2STomi Valkeinen return -EINVAL; 3239afe267f2STomi Valkeinen default: 3240afe267f2STomi Valkeinen break; 3241afe267f2STomi Valkeinen } 3242afe267f2STomi Valkeinen 3243afe267f2STomi Valkeinen rxport->rx_mode = rx_mode; 3244afe267f2STomi Valkeinen 3245afe267f2STomi Valkeinen /* EQ & Strobe related */ 3246afe267f2STomi Valkeinen 3247afe267f2STomi Valkeinen /* Defaults */ 3248afe267f2STomi Valkeinen rxport->eq.manual_eq = false; 3249afe267f2STomi Valkeinen rxport->eq.aeq.eq_level_min = UB960_MIN_EQ_LEVEL; 3250afe267f2STomi Valkeinen rxport->eq.aeq.eq_level_max = UB960_MAX_EQ_LEVEL; 3251afe267f2STomi Valkeinen 3252afe267f2STomi Valkeinen ret = fwnode_property_read_u32(link_fwnode, "ti,strobe-pos", 3253afe267f2STomi Valkeinen &strobe_pos); 3254afe267f2STomi Valkeinen if (ret) { 3255afe267f2STomi Valkeinen if (ret != -EINVAL) { 3256afe267f2STomi Valkeinen dev_err(dev, "rx%u: failed to read '%s': %d\n", nport, 3257afe267f2STomi Valkeinen "ti,strobe-pos", ret); 3258afe267f2STomi Valkeinen return ret; 3259afe267f2STomi Valkeinen } 3260afe267f2STomi Valkeinen } else { 3261afe267f2STomi Valkeinen if (strobe_pos < UB960_MIN_MANUAL_STROBE_POS || 3262afe267f2STomi Valkeinen strobe_pos > UB960_MAX_MANUAL_STROBE_POS) { 3263afe267f2STomi Valkeinen dev_err(dev, "rx%u: illegal 'strobe-pos' value: %d\n", 3264afe267f2STomi Valkeinen nport, strobe_pos); 3265afe267f2STomi Valkeinen return -EINVAL; 3266afe267f2STomi Valkeinen } 3267afe267f2STomi Valkeinen 3268afe267f2STomi Valkeinen /* NOTE: ignored unless global manual strobe pos is also set */ 3269afe267f2STomi Valkeinen rxport->eq.strobe_pos = strobe_pos; 3270afe267f2STomi Valkeinen if (!priv->strobe.manual) 3271afe267f2STomi Valkeinen dev_warn(dev, 3272afe267f2STomi Valkeinen "rx%u: 'ti,strobe-pos' ignored as 'ti,manual-strobe' not set\n", 3273afe267f2STomi Valkeinen nport); 3274afe267f2STomi Valkeinen } 3275afe267f2STomi Valkeinen 3276afe267f2STomi Valkeinen ret = fwnode_property_read_u32(link_fwnode, "ti,eq-level", &eq_level); 3277afe267f2STomi Valkeinen if (ret) { 3278afe267f2STomi Valkeinen if (ret != -EINVAL) { 3279afe267f2STomi Valkeinen dev_err(dev, "rx%u: failed to read '%s': %d\n", nport, 3280afe267f2STomi Valkeinen "ti,eq-level", ret); 3281afe267f2STomi Valkeinen return ret; 3282afe267f2STomi Valkeinen } 3283afe267f2STomi Valkeinen } else { 3284afe267f2STomi Valkeinen if (eq_level > UB960_MAX_EQ_LEVEL) { 3285afe267f2STomi Valkeinen dev_err(dev, "rx%u: illegal 'ti,eq-level' value: %d\n", 3286afe267f2STomi Valkeinen nport, eq_level); 3287afe267f2STomi Valkeinen return -EINVAL; 3288afe267f2STomi Valkeinen } 3289afe267f2STomi Valkeinen 3290afe267f2STomi Valkeinen rxport->eq.manual_eq = true; 3291afe267f2STomi Valkeinen rxport->eq.manual.eq_level = eq_level; 3292afe267f2STomi Valkeinen } 3293afe267f2STomi Valkeinen 3294afe267f2STomi Valkeinen ret = fwnode_property_read_u32(link_fwnode, "i2c-alias", 3295afe267f2STomi Valkeinen &ser_i2c_alias); 3296afe267f2STomi Valkeinen if (ret) { 3297afe267f2STomi Valkeinen dev_err(dev, "rx%u: failed to read '%s': %d\n", nport, 3298afe267f2STomi Valkeinen "i2c-alias", ret); 3299afe267f2STomi Valkeinen return ret; 3300afe267f2STomi Valkeinen } 3301afe267f2STomi Valkeinen rxport->ser.alias = ser_i2c_alias; 3302afe267f2STomi Valkeinen 3303afe267f2STomi Valkeinen rxport->ser.fwnode = fwnode_get_named_child_node(link_fwnode, "serializer"); 3304afe267f2STomi Valkeinen if (!rxport->ser.fwnode) { 3305afe267f2STomi Valkeinen dev_err(dev, "rx%u: missing 'serializer' node\n", nport); 3306afe267f2STomi Valkeinen return -EINVAL; 3307afe267f2STomi Valkeinen } 3308afe267f2STomi Valkeinen 3309afe267f2STomi Valkeinen return 0; 3310afe267f2STomi Valkeinen } 3311afe267f2STomi Valkeinen 3312afe267f2STomi Valkeinen static int ub960_parse_dt_rxport_ep_properties(struct ub960_data *priv, 3313afe267f2STomi Valkeinen struct fwnode_handle *ep_fwnode, 3314afe267f2STomi Valkeinen struct ub960_rxport *rxport) 3315afe267f2STomi Valkeinen { 3316afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 3317afe267f2STomi Valkeinen struct v4l2_fwnode_endpoint vep = {}; 3318afe267f2STomi Valkeinen unsigned int nport = rxport->nport; 3319afe267f2STomi Valkeinen bool hsync_hi; 3320afe267f2STomi Valkeinen bool vsync_hi; 3321afe267f2STomi Valkeinen int ret; 3322afe267f2STomi Valkeinen 3323afe267f2STomi Valkeinen rxport->source.ep_fwnode = fwnode_graph_get_remote_endpoint(ep_fwnode); 3324afe267f2STomi Valkeinen if (!rxport->source.ep_fwnode) { 3325afe267f2STomi Valkeinen dev_err(dev, "rx%u: no remote endpoint\n", nport); 3326afe267f2STomi Valkeinen return -ENODEV; 3327afe267f2STomi Valkeinen } 3328afe267f2STomi Valkeinen 3329afe267f2STomi Valkeinen /* We currently have properties only for RAW modes */ 3330afe267f2STomi Valkeinen 3331afe267f2STomi Valkeinen switch (rxport->rx_mode) { 3332afe267f2STomi Valkeinen case RXPORT_MODE_RAW10: 3333afe267f2STomi Valkeinen case RXPORT_MODE_RAW12_HF: 3334afe267f2STomi Valkeinen case RXPORT_MODE_RAW12_LF: 3335afe267f2STomi Valkeinen break; 3336afe267f2STomi Valkeinen default: 3337afe267f2STomi Valkeinen return 0; 3338afe267f2STomi Valkeinen } 3339afe267f2STomi Valkeinen 3340afe267f2STomi Valkeinen vep.bus_type = V4L2_MBUS_PARALLEL; 3341afe267f2STomi Valkeinen ret = v4l2_fwnode_endpoint_parse(ep_fwnode, &vep); 3342afe267f2STomi Valkeinen if (ret) { 3343afe267f2STomi Valkeinen dev_err(dev, "rx%u: failed to parse endpoint data\n", nport); 3344afe267f2STomi Valkeinen goto err_put_source_ep_fwnode; 3345afe267f2STomi Valkeinen } 3346afe267f2STomi Valkeinen 3347afe267f2STomi Valkeinen hsync_hi = !!(vep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH); 3348afe267f2STomi Valkeinen vsync_hi = !!(vep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH); 3349afe267f2STomi Valkeinen 3350afe267f2STomi Valkeinen /* LineValid and FrameValid are inverse to the h/vsync active */ 3351afe267f2STomi Valkeinen rxport->lv_fv_pol = (hsync_hi ? UB960_RR_PORT_CONFIG2_LV_POL_LOW : 0) | 3352afe267f2STomi Valkeinen (vsync_hi ? UB960_RR_PORT_CONFIG2_FV_POL_LOW : 0); 3353afe267f2STomi Valkeinen 3354afe267f2STomi Valkeinen return 0; 3355afe267f2STomi Valkeinen 3356afe267f2STomi Valkeinen err_put_source_ep_fwnode: 3357afe267f2STomi Valkeinen fwnode_handle_put(rxport->source.ep_fwnode); 3358afe267f2STomi Valkeinen return ret; 3359afe267f2STomi Valkeinen } 3360afe267f2STomi Valkeinen 3361afe267f2STomi Valkeinen static int ub960_parse_dt_rxport(struct ub960_data *priv, unsigned int nport, 3362afe267f2STomi Valkeinen struct fwnode_handle *link_fwnode, 3363afe267f2STomi Valkeinen struct fwnode_handle *ep_fwnode) 3364afe267f2STomi Valkeinen { 3365afe267f2STomi Valkeinen static const char *vpoc_names[UB960_MAX_RX_NPORTS] = { 3366afe267f2STomi Valkeinen "vpoc0", "vpoc1", "vpoc2", "vpoc3" 3367afe267f2STomi Valkeinen }; 3368afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 3369afe267f2STomi Valkeinen struct ub960_rxport *rxport; 3370afe267f2STomi Valkeinen int ret; 3371afe267f2STomi Valkeinen 3372afe267f2STomi Valkeinen rxport = kzalloc(sizeof(*rxport), GFP_KERNEL); 3373afe267f2STomi Valkeinen if (!rxport) 3374afe267f2STomi Valkeinen return -ENOMEM; 3375afe267f2STomi Valkeinen 3376afe267f2STomi Valkeinen priv->rxports[nport] = rxport; 3377afe267f2STomi Valkeinen 3378afe267f2STomi Valkeinen rxport->nport = nport; 3379afe267f2STomi Valkeinen rxport->priv = priv; 3380afe267f2STomi Valkeinen 3381afe267f2STomi Valkeinen ret = ub960_parse_dt_rxport_link_properties(priv, link_fwnode, rxport); 3382afe267f2STomi Valkeinen if (ret) 3383afe267f2STomi Valkeinen goto err_free_rxport; 3384afe267f2STomi Valkeinen 3385afe267f2STomi Valkeinen rxport->vpoc = devm_regulator_get_optional(dev, vpoc_names[nport]); 3386afe267f2STomi Valkeinen if (IS_ERR(rxport->vpoc)) { 3387afe267f2STomi Valkeinen ret = PTR_ERR(rxport->vpoc); 3388afe267f2STomi Valkeinen if (ret == -ENODEV) { 3389afe267f2STomi Valkeinen rxport->vpoc = NULL; 3390afe267f2STomi Valkeinen } else { 3391afe267f2STomi Valkeinen dev_err(dev, "rx%u: failed to get VPOC supply: %d\n", 3392afe267f2STomi Valkeinen nport, ret); 3393afe267f2STomi Valkeinen goto err_put_remote_fwnode; 3394afe267f2STomi Valkeinen } 3395afe267f2STomi Valkeinen } 3396afe267f2STomi Valkeinen 3397afe267f2STomi Valkeinen ret = ub960_parse_dt_rxport_ep_properties(priv, ep_fwnode, rxport); 3398afe267f2STomi Valkeinen if (ret) 3399afe267f2STomi Valkeinen goto err_put_remote_fwnode; 3400afe267f2STomi Valkeinen 3401afe267f2STomi Valkeinen return 0; 3402afe267f2STomi Valkeinen 3403afe267f2STomi Valkeinen err_put_remote_fwnode: 3404afe267f2STomi Valkeinen fwnode_handle_put(rxport->ser.fwnode); 3405afe267f2STomi Valkeinen err_free_rxport: 3406afe267f2STomi Valkeinen priv->rxports[nport] = NULL; 3407afe267f2STomi Valkeinen kfree(rxport); 3408afe267f2STomi Valkeinen return ret; 3409afe267f2STomi Valkeinen } 3410afe267f2STomi Valkeinen 3411afe267f2STomi Valkeinen static struct fwnode_handle * 3412afe267f2STomi Valkeinen ub960_fwnode_get_link_by_regs(struct fwnode_handle *links_fwnode, 3413afe267f2STomi Valkeinen unsigned int nport) 3414afe267f2STomi Valkeinen { 3415afe267f2STomi Valkeinen struct fwnode_handle *link_fwnode; 3416afe267f2STomi Valkeinen int ret; 3417afe267f2STomi Valkeinen 3418afe267f2STomi Valkeinen fwnode_for_each_child_node(links_fwnode, link_fwnode) { 3419afe267f2STomi Valkeinen u32 link_num; 3420afe267f2STomi Valkeinen 3421afe267f2STomi Valkeinen if (!str_has_prefix(fwnode_get_name(link_fwnode), "link@")) 3422afe267f2STomi Valkeinen continue; 3423afe267f2STomi Valkeinen 3424afe267f2STomi Valkeinen ret = fwnode_property_read_u32(link_fwnode, "reg", &link_num); 3425afe267f2STomi Valkeinen if (ret) { 3426afe267f2STomi Valkeinen fwnode_handle_put(link_fwnode); 3427afe267f2STomi Valkeinen return NULL; 3428afe267f2STomi Valkeinen } 3429afe267f2STomi Valkeinen 3430afe267f2STomi Valkeinen if (nport == link_num) 3431afe267f2STomi Valkeinen return link_fwnode; 3432afe267f2STomi Valkeinen } 3433afe267f2STomi Valkeinen 3434afe267f2STomi Valkeinen return NULL; 3435afe267f2STomi Valkeinen } 3436afe267f2STomi Valkeinen 3437afe267f2STomi Valkeinen static int ub960_parse_dt_rxports(struct ub960_data *priv) 3438afe267f2STomi Valkeinen { 3439afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 3440afe267f2STomi Valkeinen struct fwnode_handle *links_fwnode; 3441afe267f2STomi Valkeinen unsigned int nport; 3442afe267f2STomi Valkeinen int ret; 3443afe267f2STomi Valkeinen 3444afe267f2STomi Valkeinen links_fwnode = fwnode_get_named_child_node(dev_fwnode(dev), "links"); 3445afe267f2STomi Valkeinen if (!links_fwnode) { 3446afe267f2STomi Valkeinen dev_err(dev, "'links' node missing\n"); 3447afe267f2STomi Valkeinen return -ENODEV; 3448afe267f2STomi Valkeinen } 3449afe267f2STomi Valkeinen 3450afe267f2STomi Valkeinen /* Defaults, recommended by TI */ 3451afe267f2STomi Valkeinen priv->strobe.min = 2; 3452afe267f2STomi Valkeinen priv->strobe.max = 3; 3453afe267f2STomi Valkeinen 3454afe267f2STomi Valkeinen priv->strobe.manual = fwnode_property_read_bool(links_fwnode, "ti,manual-strobe"); 3455afe267f2STomi Valkeinen 3456afe267f2STomi Valkeinen for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { 3457afe267f2STomi Valkeinen struct fwnode_handle *link_fwnode; 3458afe267f2STomi Valkeinen struct fwnode_handle *ep_fwnode; 3459afe267f2STomi Valkeinen 3460afe267f2STomi Valkeinen link_fwnode = ub960_fwnode_get_link_by_regs(links_fwnode, nport); 3461afe267f2STomi Valkeinen if (!link_fwnode) 3462afe267f2STomi Valkeinen continue; 3463afe267f2STomi Valkeinen 3464afe267f2STomi Valkeinen ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 3465afe267f2STomi Valkeinen nport, 0, 0); 3466afe267f2STomi Valkeinen if (!ep_fwnode) { 3467afe267f2STomi Valkeinen fwnode_handle_put(link_fwnode); 3468afe267f2STomi Valkeinen continue; 3469afe267f2STomi Valkeinen } 3470afe267f2STomi Valkeinen 3471afe267f2STomi Valkeinen ret = ub960_parse_dt_rxport(priv, nport, link_fwnode, 3472afe267f2STomi Valkeinen ep_fwnode); 3473afe267f2STomi Valkeinen 3474afe267f2STomi Valkeinen fwnode_handle_put(link_fwnode); 3475afe267f2STomi Valkeinen fwnode_handle_put(ep_fwnode); 3476afe267f2STomi Valkeinen 3477afe267f2STomi Valkeinen if (ret) { 3478afe267f2STomi Valkeinen dev_err(dev, "rx%u: failed to parse RX port\n", nport); 3479afe267f2STomi Valkeinen goto err_put_links; 3480afe267f2STomi Valkeinen } 3481afe267f2STomi Valkeinen } 3482afe267f2STomi Valkeinen 3483afe267f2STomi Valkeinen fwnode_handle_put(links_fwnode); 3484afe267f2STomi Valkeinen 3485afe267f2STomi Valkeinen return 0; 3486afe267f2STomi Valkeinen 3487afe267f2STomi Valkeinen err_put_links: 3488afe267f2STomi Valkeinen fwnode_handle_put(links_fwnode); 3489afe267f2STomi Valkeinen 3490afe267f2STomi Valkeinen return ret; 3491afe267f2STomi Valkeinen } 3492afe267f2STomi Valkeinen 3493afe267f2STomi Valkeinen static int ub960_parse_dt_txports(struct ub960_data *priv) 3494afe267f2STomi Valkeinen { 3495afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 3496afe267f2STomi Valkeinen u32 nport; 3497afe267f2STomi Valkeinen int ret; 3498afe267f2STomi Valkeinen 3499afe267f2STomi Valkeinen for (nport = 0; nport < priv->hw_data->num_txports; nport++) { 3500afe267f2STomi Valkeinen unsigned int port = nport + priv->hw_data->num_rxports; 3501afe267f2STomi Valkeinen struct fwnode_handle *ep_fwnode; 3502afe267f2STomi Valkeinen 3503afe267f2STomi Valkeinen ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 3504afe267f2STomi Valkeinen port, 0, 0); 3505afe267f2STomi Valkeinen if (!ep_fwnode) 3506afe267f2STomi Valkeinen continue; 3507afe267f2STomi Valkeinen 3508afe267f2STomi Valkeinen ret = ub960_parse_dt_txport(priv, ep_fwnode, nport); 3509afe267f2STomi Valkeinen 3510afe267f2STomi Valkeinen fwnode_handle_put(ep_fwnode); 3511afe267f2STomi Valkeinen 3512afe267f2STomi Valkeinen if (ret) 3513afe267f2STomi Valkeinen break; 3514afe267f2STomi Valkeinen } 3515afe267f2STomi Valkeinen 3516afe267f2STomi Valkeinen return 0; 3517afe267f2STomi Valkeinen } 3518afe267f2STomi Valkeinen 3519afe267f2STomi Valkeinen static int ub960_parse_dt(struct ub960_data *priv) 3520afe267f2STomi Valkeinen { 3521afe267f2STomi Valkeinen int ret; 3522afe267f2STomi Valkeinen 3523afe267f2STomi Valkeinen ret = ub960_parse_dt_rxports(priv); 3524afe267f2STomi Valkeinen if (ret) 3525afe267f2STomi Valkeinen return ret; 3526afe267f2STomi Valkeinen 3527afe267f2STomi Valkeinen ret = ub960_parse_dt_txports(priv); 3528afe267f2STomi Valkeinen if (ret) 3529afe267f2STomi Valkeinen goto err_free_rxports; 3530afe267f2STomi Valkeinen 3531afe267f2STomi Valkeinen return 0; 3532afe267f2STomi Valkeinen 3533afe267f2STomi Valkeinen err_free_rxports: 3534afe267f2STomi Valkeinen ub960_rxport_free_ports(priv); 3535afe267f2STomi Valkeinen 3536afe267f2STomi Valkeinen return ret; 3537afe267f2STomi Valkeinen } 3538afe267f2STomi Valkeinen 3539afe267f2STomi Valkeinen static int ub960_notify_bound(struct v4l2_async_notifier *notifier, 3540afe267f2STomi Valkeinen struct v4l2_subdev *subdev, 3541*adb2dcd5SSakari Ailus struct v4l2_async_connection *asd) 3542afe267f2STomi Valkeinen { 3543afe267f2STomi Valkeinen struct ub960_data *priv = sd_to_ub960(notifier->sd); 3544afe267f2STomi Valkeinen struct ub960_rxport *rxport = to_ub960_asd(asd)->rxport; 3545afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 3546afe267f2STomi Valkeinen u8 nport = rxport->nport; 3547afe267f2STomi Valkeinen unsigned int i; 3548afe267f2STomi Valkeinen int ret; 3549afe267f2STomi Valkeinen 3550afe267f2STomi Valkeinen ret = media_entity_get_fwnode_pad(&subdev->entity, 3551afe267f2STomi Valkeinen rxport->source.ep_fwnode, 3552afe267f2STomi Valkeinen MEDIA_PAD_FL_SOURCE); 3553afe267f2STomi Valkeinen if (ret < 0) { 3554afe267f2STomi Valkeinen dev_err(dev, "Failed to find pad for %s\n", subdev->name); 3555afe267f2STomi Valkeinen return ret; 3556afe267f2STomi Valkeinen } 3557afe267f2STomi Valkeinen 3558afe267f2STomi Valkeinen rxport->source.sd = subdev; 3559afe267f2STomi Valkeinen rxport->source.pad = ret; 3560afe267f2STomi Valkeinen 3561afe267f2STomi Valkeinen ret = media_create_pad_link(&rxport->source.sd->entity, 3562afe267f2STomi Valkeinen rxport->source.pad, &priv->sd.entity, nport, 3563afe267f2STomi Valkeinen MEDIA_LNK_FL_ENABLED | 3564afe267f2STomi Valkeinen MEDIA_LNK_FL_IMMUTABLE); 3565afe267f2STomi Valkeinen if (ret) { 3566afe267f2STomi Valkeinen dev_err(dev, "Unable to link %s:%u -> %s:%u\n", 3567afe267f2STomi Valkeinen rxport->source.sd->name, rxport->source.pad, 3568afe267f2STomi Valkeinen priv->sd.name, nport); 3569afe267f2STomi Valkeinen return ret; 3570afe267f2STomi Valkeinen } 3571afe267f2STomi Valkeinen 3572afe267f2STomi Valkeinen for (i = 0; i < priv->hw_data->num_rxports; i++) { 3573afe267f2STomi Valkeinen if (priv->rxports[i] && !priv->rxports[i]->source.sd) { 3574afe267f2STomi Valkeinen dev_dbg(dev, "Waiting for more subdevs to be bound\n"); 3575afe267f2STomi Valkeinen return 0; 3576afe267f2STomi Valkeinen } 3577afe267f2STomi Valkeinen } 3578afe267f2STomi Valkeinen 3579afe267f2STomi Valkeinen return 0; 3580afe267f2STomi Valkeinen } 3581afe267f2STomi Valkeinen 3582afe267f2STomi Valkeinen static void ub960_notify_unbind(struct v4l2_async_notifier *notifier, 3583afe267f2STomi Valkeinen struct v4l2_subdev *subdev, 3584*adb2dcd5SSakari Ailus struct v4l2_async_connection *asd) 3585afe267f2STomi Valkeinen { 3586afe267f2STomi Valkeinen struct ub960_rxport *rxport = to_ub960_asd(asd)->rxport; 3587afe267f2STomi Valkeinen 3588afe267f2STomi Valkeinen rxport->source.sd = NULL; 3589afe267f2STomi Valkeinen } 3590afe267f2STomi Valkeinen 3591afe267f2STomi Valkeinen static const struct v4l2_async_notifier_operations ub960_notify_ops = { 3592afe267f2STomi Valkeinen .bound = ub960_notify_bound, 3593afe267f2STomi Valkeinen .unbind = ub960_notify_unbind, 3594afe267f2STomi Valkeinen }; 3595afe267f2STomi Valkeinen 3596afe267f2STomi Valkeinen static int ub960_v4l2_notifier_register(struct ub960_data *priv) 3597afe267f2STomi Valkeinen { 3598afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 3599afe267f2STomi Valkeinen unsigned int i; 3600afe267f2STomi Valkeinen int ret; 3601afe267f2STomi Valkeinen 3602afe267f2STomi Valkeinen v4l2_async_nf_init(&priv->notifier); 3603afe267f2STomi Valkeinen 3604afe267f2STomi Valkeinen for (i = 0; i < priv->hw_data->num_rxports; i++) { 3605afe267f2STomi Valkeinen struct ub960_rxport *rxport = priv->rxports[i]; 3606afe267f2STomi Valkeinen struct ub960_asd *asd; 3607afe267f2STomi Valkeinen 3608afe267f2STomi Valkeinen if (!rxport) 3609afe267f2STomi Valkeinen continue; 3610afe267f2STomi Valkeinen 3611afe267f2STomi Valkeinen asd = v4l2_async_nf_add_fwnode(&priv->notifier, 3612afe267f2STomi Valkeinen rxport->source.ep_fwnode, 3613afe267f2STomi Valkeinen struct ub960_asd); 3614afe267f2STomi Valkeinen if (IS_ERR(asd)) { 3615afe267f2STomi Valkeinen dev_err(dev, "Failed to add subdev for source %u: %pe", 3616afe267f2STomi Valkeinen i, asd); 3617afe267f2STomi Valkeinen v4l2_async_nf_cleanup(&priv->notifier); 3618afe267f2STomi Valkeinen return PTR_ERR(asd); 3619afe267f2STomi Valkeinen } 3620afe267f2STomi Valkeinen 3621afe267f2STomi Valkeinen asd->rxport = rxport; 3622afe267f2STomi Valkeinen } 3623afe267f2STomi Valkeinen 3624afe267f2STomi Valkeinen priv->notifier.ops = &ub960_notify_ops; 3625afe267f2STomi Valkeinen 3626afe267f2STomi Valkeinen ret = v4l2_async_subdev_nf_register(&priv->sd, &priv->notifier); 3627afe267f2STomi Valkeinen if (ret) { 3628afe267f2STomi Valkeinen dev_err(dev, "Failed to register subdev_notifier"); 3629afe267f2STomi Valkeinen v4l2_async_nf_cleanup(&priv->notifier); 3630afe267f2STomi Valkeinen return ret; 3631afe267f2STomi Valkeinen } 3632afe267f2STomi Valkeinen 3633afe267f2STomi Valkeinen return 0; 3634afe267f2STomi Valkeinen } 3635afe267f2STomi Valkeinen 3636afe267f2STomi Valkeinen static void ub960_v4l2_notifier_unregister(struct ub960_data *priv) 3637afe267f2STomi Valkeinen { 3638afe267f2STomi Valkeinen v4l2_async_nf_unregister(&priv->notifier); 3639afe267f2STomi Valkeinen v4l2_async_nf_cleanup(&priv->notifier); 3640afe267f2STomi Valkeinen } 3641afe267f2STomi Valkeinen 3642afe267f2STomi Valkeinen static int ub960_create_subdev(struct ub960_data *priv) 3643afe267f2STomi Valkeinen { 3644afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 3645afe267f2STomi Valkeinen unsigned int i; 3646afe267f2STomi Valkeinen int ret; 3647afe267f2STomi Valkeinen 3648afe267f2STomi Valkeinen v4l2_i2c_subdev_init(&priv->sd, priv->client, &ub960_subdev_ops); 3649afe267f2STomi Valkeinen 3650afe267f2STomi Valkeinen v4l2_ctrl_handler_init(&priv->ctrl_handler, 1); 3651afe267f2STomi Valkeinen priv->sd.ctrl_handler = &priv->ctrl_handler; 3652afe267f2STomi Valkeinen 3653afe267f2STomi Valkeinen v4l2_ctrl_new_int_menu(&priv->ctrl_handler, NULL, V4L2_CID_LINK_FREQ, 3654afe267f2STomi Valkeinen ARRAY_SIZE(priv->tx_link_freq) - 1, 0, 3655afe267f2STomi Valkeinen priv->tx_link_freq); 3656afe267f2STomi Valkeinen 3657afe267f2STomi Valkeinen if (priv->ctrl_handler.error) { 3658afe267f2STomi Valkeinen ret = priv->ctrl_handler.error; 3659afe267f2STomi Valkeinen goto err_free_ctrl; 3660afe267f2STomi Valkeinen } 3661afe267f2STomi Valkeinen 3662afe267f2STomi Valkeinen priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | 3663afe267f2STomi Valkeinen V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_STREAMS; 3664afe267f2STomi Valkeinen priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; 3665afe267f2STomi Valkeinen priv->sd.entity.ops = &ub960_entity_ops; 3666afe267f2STomi Valkeinen 3667afe267f2STomi Valkeinen for (i = 0; i < priv->hw_data->num_rxports + priv->hw_data->num_txports; i++) { 3668afe267f2STomi Valkeinen priv->pads[i].flags = ub960_pad_is_sink(priv, i) ? 3669afe267f2STomi Valkeinen MEDIA_PAD_FL_SINK : 3670afe267f2STomi Valkeinen MEDIA_PAD_FL_SOURCE; 3671afe267f2STomi Valkeinen } 3672afe267f2STomi Valkeinen 3673afe267f2STomi Valkeinen ret = media_entity_pads_init(&priv->sd.entity, 3674afe267f2STomi Valkeinen priv->hw_data->num_rxports + 3675afe267f2STomi Valkeinen priv->hw_data->num_txports, 3676afe267f2STomi Valkeinen priv->pads); 3677afe267f2STomi Valkeinen if (ret) 3678afe267f2STomi Valkeinen goto err_free_ctrl; 3679afe267f2STomi Valkeinen 3680afe267f2STomi Valkeinen priv->sd.state_lock = priv->sd.ctrl_handler->lock; 3681afe267f2STomi Valkeinen 3682afe267f2STomi Valkeinen ret = v4l2_subdev_init_finalize(&priv->sd); 3683afe267f2STomi Valkeinen if (ret) 3684afe267f2STomi Valkeinen goto err_entity_cleanup; 3685afe267f2STomi Valkeinen 3686afe267f2STomi Valkeinen ret = ub960_v4l2_notifier_register(priv); 3687afe267f2STomi Valkeinen if (ret) { 3688afe267f2STomi Valkeinen dev_err(dev, "v4l2 subdev notifier register failed: %d\n", ret); 3689afe267f2STomi Valkeinen goto err_subdev_cleanup; 3690afe267f2STomi Valkeinen } 3691afe267f2STomi Valkeinen 3692afe267f2STomi Valkeinen ret = v4l2_async_register_subdev(&priv->sd); 3693afe267f2STomi Valkeinen if (ret) { 3694afe267f2STomi Valkeinen dev_err(dev, "v4l2_async_register_subdev error: %d\n", ret); 3695afe267f2STomi Valkeinen goto err_unreg_notif; 3696afe267f2STomi Valkeinen } 3697afe267f2STomi Valkeinen 3698afe267f2STomi Valkeinen return 0; 3699afe267f2STomi Valkeinen 3700afe267f2STomi Valkeinen err_unreg_notif: 3701afe267f2STomi Valkeinen ub960_v4l2_notifier_unregister(priv); 3702afe267f2STomi Valkeinen err_subdev_cleanup: 3703afe267f2STomi Valkeinen v4l2_subdev_cleanup(&priv->sd); 3704afe267f2STomi Valkeinen err_entity_cleanup: 3705afe267f2STomi Valkeinen media_entity_cleanup(&priv->sd.entity); 3706afe267f2STomi Valkeinen err_free_ctrl: 3707afe267f2STomi Valkeinen v4l2_ctrl_handler_free(&priv->ctrl_handler); 3708afe267f2STomi Valkeinen 3709afe267f2STomi Valkeinen return ret; 3710afe267f2STomi Valkeinen } 3711afe267f2STomi Valkeinen 3712afe267f2STomi Valkeinen static void ub960_destroy_subdev(struct ub960_data *priv) 3713afe267f2STomi Valkeinen { 3714afe267f2STomi Valkeinen ub960_v4l2_notifier_unregister(priv); 3715afe267f2STomi Valkeinen v4l2_async_unregister_subdev(&priv->sd); 3716afe267f2STomi Valkeinen 3717afe267f2STomi Valkeinen v4l2_subdev_cleanup(&priv->sd); 3718afe267f2STomi Valkeinen 3719afe267f2STomi Valkeinen media_entity_cleanup(&priv->sd.entity); 3720afe267f2STomi Valkeinen v4l2_ctrl_handler_free(&priv->ctrl_handler); 3721afe267f2STomi Valkeinen } 3722afe267f2STomi Valkeinen 3723afe267f2STomi Valkeinen static const struct regmap_config ub960_regmap_config = { 3724afe267f2STomi Valkeinen .name = "ds90ub960", 3725afe267f2STomi Valkeinen 3726afe267f2STomi Valkeinen .reg_bits = 8, 3727afe267f2STomi Valkeinen .val_bits = 8, 3728afe267f2STomi Valkeinen 3729afe267f2STomi Valkeinen .max_register = 0xff, 3730afe267f2STomi Valkeinen 3731afe267f2STomi Valkeinen /* 3732afe267f2STomi Valkeinen * We do locking in the driver to cover the TX/RX port selection and the 3733afe267f2STomi Valkeinen * indirect register access. 3734afe267f2STomi Valkeinen */ 3735afe267f2STomi Valkeinen .disable_locking = true, 3736afe267f2STomi Valkeinen }; 3737afe267f2STomi Valkeinen 3738afe267f2STomi Valkeinen static void ub960_reset(struct ub960_data *priv, bool reset_regs) 3739afe267f2STomi Valkeinen { 3740afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 3741afe267f2STomi Valkeinen unsigned int v; 3742afe267f2STomi Valkeinen int ret; 3743afe267f2STomi Valkeinen u8 bit; 3744afe267f2STomi Valkeinen 3745afe267f2STomi Valkeinen bit = reset_regs ? UB960_SR_RESET_DIGITAL_RESET1 : 3746afe267f2STomi Valkeinen UB960_SR_RESET_DIGITAL_RESET0; 3747afe267f2STomi Valkeinen 3748afe267f2STomi Valkeinen ub960_write(priv, UB960_SR_RESET, bit); 3749afe267f2STomi Valkeinen 3750afe267f2STomi Valkeinen mutex_lock(&priv->reg_lock); 3751afe267f2STomi Valkeinen 3752afe267f2STomi Valkeinen ret = regmap_read_poll_timeout(priv->regmap, UB960_SR_RESET, v, 3753afe267f2STomi Valkeinen (v & bit) == 0, 2000, 100000); 3754afe267f2STomi Valkeinen 3755afe267f2STomi Valkeinen mutex_unlock(&priv->reg_lock); 3756afe267f2STomi Valkeinen 3757afe267f2STomi Valkeinen if (ret) 3758afe267f2STomi Valkeinen dev_err(dev, "reset failed: %d\n", ret); 3759afe267f2STomi Valkeinen } 3760afe267f2STomi Valkeinen 3761afe267f2STomi Valkeinen static int ub960_get_hw_resources(struct ub960_data *priv) 3762afe267f2STomi Valkeinen { 3763afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 3764afe267f2STomi Valkeinen 3765afe267f2STomi Valkeinen priv->regmap = devm_regmap_init_i2c(priv->client, &ub960_regmap_config); 3766afe267f2STomi Valkeinen if (IS_ERR(priv->regmap)) 3767afe267f2STomi Valkeinen return PTR_ERR(priv->regmap); 3768afe267f2STomi Valkeinen 3769afe267f2STomi Valkeinen priv->vddio = devm_regulator_get(dev, "vddio"); 3770afe267f2STomi Valkeinen if (IS_ERR(priv->vddio)) 3771afe267f2STomi Valkeinen return dev_err_probe(dev, PTR_ERR(priv->vddio), 3772afe267f2STomi Valkeinen "cannot get VDDIO regulator\n"); 3773afe267f2STomi Valkeinen 3774afe267f2STomi Valkeinen /* get power-down pin from DT */ 3775afe267f2STomi Valkeinen priv->pd_gpio = 3776afe267f2STomi Valkeinen devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH); 3777afe267f2STomi Valkeinen if (IS_ERR(priv->pd_gpio)) 3778afe267f2STomi Valkeinen return dev_err_probe(dev, PTR_ERR(priv->pd_gpio), 3779afe267f2STomi Valkeinen "Cannot get powerdown GPIO\n"); 3780afe267f2STomi Valkeinen 3781afe267f2STomi Valkeinen priv->refclk = devm_clk_get(dev, "refclk"); 3782afe267f2STomi Valkeinen if (IS_ERR(priv->refclk)) 3783afe267f2STomi Valkeinen return dev_err_probe(dev, PTR_ERR(priv->refclk), 3784afe267f2STomi Valkeinen "Cannot get REFCLK\n"); 3785afe267f2STomi Valkeinen 3786afe267f2STomi Valkeinen return 0; 3787afe267f2STomi Valkeinen } 3788afe267f2STomi Valkeinen 3789afe267f2STomi Valkeinen static int ub960_enable_core_hw(struct ub960_data *priv) 3790afe267f2STomi Valkeinen { 3791afe267f2STomi Valkeinen struct device *dev = &priv->client->dev; 3792afe267f2STomi Valkeinen u8 rev_mask; 3793afe267f2STomi Valkeinen int ret; 3794afe267f2STomi Valkeinen u8 dev_sts; 3795afe267f2STomi Valkeinen u8 refclk_freq; 3796afe267f2STomi Valkeinen 3797afe267f2STomi Valkeinen ret = regulator_enable(priv->vddio); 3798afe267f2STomi Valkeinen if (ret) 3799afe267f2STomi Valkeinen return dev_err_probe(dev, ret, 3800afe267f2STomi Valkeinen "failed to enable VDDIO regulator\n"); 3801afe267f2STomi Valkeinen 3802afe267f2STomi Valkeinen ret = clk_prepare_enable(priv->refclk); 3803afe267f2STomi Valkeinen if (ret) { 3804afe267f2STomi Valkeinen dev_err_probe(dev, ret, "Failed to enable refclk\n"); 3805afe267f2STomi Valkeinen goto err_disable_vddio; 3806afe267f2STomi Valkeinen } 3807afe267f2STomi Valkeinen 3808afe267f2STomi Valkeinen if (priv->pd_gpio) { 3809afe267f2STomi Valkeinen gpiod_set_value_cansleep(priv->pd_gpio, 1); 3810afe267f2STomi Valkeinen /* wait min 2 ms for reset to complete */ 3811afe267f2STomi Valkeinen fsleep(2000); 3812afe267f2STomi Valkeinen gpiod_set_value_cansleep(priv->pd_gpio, 0); 3813afe267f2STomi Valkeinen /* wait min 2 ms for power up to finish */ 3814afe267f2STomi Valkeinen fsleep(2000); 3815afe267f2STomi Valkeinen } 3816afe267f2STomi Valkeinen 3817afe267f2STomi Valkeinen ub960_reset(priv, true); 3818afe267f2STomi Valkeinen 3819afe267f2STomi Valkeinen /* Runtime check register accessibility */ 3820afe267f2STomi Valkeinen ret = ub960_read(priv, UB960_SR_REV_MASK, &rev_mask); 3821afe267f2STomi Valkeinen if (ret) { 3822afe267f2STomi Valkeinen dev_err_probe(dev, ret, "Cannot read first register, abort\n"); 3823afe267f2STomi Valkeinen goto err_pd_gpio; 3824afe267f2STomi Valkeinen } 3825afe267f2STomi Valkeinen 3826afe267f2STomi Valkeinen dev_dbg(dev, "Found %s (rev/mask %#04x)\n", priv->hw_data->model, 3827afe267f2STomi Valkeinen rev_mask); 3828afe267f2STomi Valkeinen 3829afe267f2STomi Valkeinen ret = ub960_read(priv, UB960_SR_DEVICE_STS, &dev_sts); 3830afe267f2STomi Valkeinen if (ret) 3831afe267f2STomi Valkeinen goto err_pd_gpio; 3832afe267f2STomi Valkeinen 3833afe267f2STomi Valkeinen ret = ub960_read(priv, UB960_XR_REFCLK_FREQ, &refclk_freq); 3834afe267f2STomi Valkeinen if (ret) 3835afe267f2STomi Valkeinen goto err_pd_gpio; 3836afe267f2STomi Valkeinen 3837afe267f2STomi Valkeinen dev_dbg(dev, "refclk valid %u freq %u MHz (clk fw freq %lu MHz)\n", 3838afe267f2STomi Valkeinen !!(dev_sts & BIT(4)), refclk_freq, 3839afe267f2STomi Valkeinen clk_get_rate(priv->refclk) / 1000000); 3840afe267f2STomi Valkeinen 3841afe267f2STomi Valkeinen /* Disable all RX ports by default */ 3842afe267f2STomi Valkeinen ret = ub960_write(priv, UB960_SR_RX_PORT_CTL, 0); 3843afe267f2STomi Valkeinen if (ret) 3844afe267f2STomi Valkeinen goto err_pd_gpio; 3845afe267f2STomi Valkeinen 3846afe267f2STomi Valkeinen /* release GPIO lock */ 3847afe267f2STomi Valkeinen if (priv->hw_data->is_ub9702) { 3848afe267f2STomi Valkeinen ret = ub960_update_bits(priv, UB960_SR_RESET, 3849afe267f2STomi Valkeinen UB960_SR_RESET_GPIO_LOCK_RELEASE, 3850afe267f2STomi Valkeinen UB960_SR_RESET_GPIO_LOCK_RELEASE); 3851afe267f2STomi Valkeinen if (ret) 3852afe267f2STomi Valkeinen goto err_pd_gpio; 3853afe267f2STomi Valkeinen } 3854afe267f2STomi Valkeinen 3855afe267f2STomi Valkeinen return 0; 3856afe267f2STomi Valkeinen 3857afe267f2STomi Valkeinen err_pd_gpio: 3858afe267f2STomi Valkeinen gpiod_set_value_cansleep(priv->pd_gpio, 1); 3859afe267f2STomi Valkeinen clk_disable_unprepare(priv->refclk); 3860afe267f2STomi Valkeinen err_disable_vddio: 3861afe267f2STomi Valkeinen regulator_disable(priv->vddio); 3862afe267f2STomi Valkeinen 3863afe267f2STomi Valkeinen return ret; 3864afe267f2STomi Valkeinen } 3865afe267f2STomi Valkeinen 3866afe267f2STomi Valkeinen static void ub960_disable_core_hw(struct ub960_data *priv) 3867afe267f2STomi Valkeinen { 3868afe267f2STomi Valkeinen gpiod_set_value_cansleep(priv->pd_gpio, 1); 3869afe267f2STomi Valkeinen clk_disable_unprepare(priv->refclk); 3870afe267f2STomi Valkeinen regulator_disable(priv->vddio); 3871afe267f2STomi Valkeinen } 3872afe267f2STomi Valkeinen 3873afe267f2STomi Valkeinen static int ub960_probe(struct i2c_client *client) 3874afe267f2STomi Valkeinen { 3875afe267f2STomi Valkeinen struct device *dev = &client->dev; 3876afe267f2STomi Valkeinen struct ub960_data *priv; 3877afe267f2STomi Valkeinen unsigned int port_lock_mask; 3878afe267f2STomi Valkeinen unsigned int port_mask; 3879afe267f2STomi Valkeinen unsigned int nport; 3880afe267f2STomi Valkeinen int ret; 3881afe267f2STomi Valkeinen 3882afe267f2STomi Valkeinen priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 3883afe267f2STomi Valkeinen if (!priv) 3884afe267f2STomi Valkeinen return -ENOMEM; 3885afe267f2STomi Valkeinen 3886afe267f2STomi Valkeinen priv->client = client; 3887afe267f2STomi Valkeinen 3888afe267f2STomi Valkeinen priv->hw_data = device_get_match_data(dev); 3889afe267f2STomi Valkeinen 3890afe267f2STomi Valkeinen mutex_init(&priv->reg_lock); 3891afe267f2STomi Valkeinen 3892afe267f2STomi Valkeinen INIT_DELAYED_WORK(&priv->poll_work, ub960_handler_work); 3893afe267f2STomi Valkeinen 3894afe267f2STomi Valkeinen /* 3895afe267f2STomi Valkeinen * Initialize these to invalid values so that the first reg writes will 3896afe267f2STomi Valkeinen * configure the target. 3897afe267f2STomi Valkeinen */ 3898afe267f2STomi Valkeinen priv->reg_current.indirect_target = 0xff; 3899afe267f2STomi Valkeinen priv->reg_current.rxport = 0xff; 3900afe267f2STomi Valkeinen priv->reg_current.txport = 0xff; 3901afe267f2STomi Valkeinen 3902afe267f2STomi Valkeinen ret = ub960_get_hw_resources(priv); 3903afe267f2STomi Valkeinen if (ret) 3904afe267f2STomi Valkeinen goto err_mutex_destroy; 3905afe267f2STomi Valkeinen 3906afe267f2STomi Valkeinen ret = ub960_enable_core_hw(priv); 3907afe267f2STomi Valkeinen if (ret) 3908afe267f2STomi Valkeinen goto err_mutex_destroy; 3909afe267f2STomi Valkeinen 3910afe267f2STomi Valkeinen ret = ub960_parse_dt(priv); 3911afe267f2STomi Valkeinen if (ret) 3912afe267f2STomi Valkeinen goto err_disable_core_hw; 3913afe267f2STomi Valkeinen 3914afe267f2STomi Valkeinen ret = ub960_init_tx_ports(priv); 3915afe267f2STomi Valkeinen if (ret) 3916afe267f2STomi Valkeinen goto err_free_ports; 3917afe267f2STomi Valkeinen 3918afe267f2STomi Valkeinen ret = ub960_rxport_enable_vpocs(priv); 3919afe267f2STomi Valkeinen if (ret) 3920afe267f2STomi Valkeinen goto err_free_ports; 3921afe267f2STomi Valkeinen 3922afe267f2STomi Valkeinen ret = ub960_init_rx_ports(priv); 3923afe267f2STomi Valkeinen if (ret) 3924afe267f2STomi Valkeinen goto err_disable_vpocs; 3925afe267f2STomi Valkeinen 3926afe267f2STomi Valkeinen ub960_reset(priv, false); 3927afe267f2STomi Valkeinen 3928afe267f2STomi Valkeinen port_mask = 0; 3929afe267f2STomi Valkeinen 3930afe267f2STomi Valkeinen for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { 3931afe267f2STomi Valkeinen struct ub960_rxport *rxport = priv->rxports[nport]; 3932afe267f2STomi Valkeinen 3933afe267f2STomi Valkeinen if (!rxport) 3934afe267f2STomi Valkeinen continue; 3935afe267f2STomi Valkeinen 3936afe267f2STomi Valkeinen port_mask |= BIT(nport); 3937afe267f2STomi Valkeinen } 3938afe267f2STomi Valkeinen 3939afe267f2STomi Valkeinen ret = ub960_rxport_wait_locks(priv, port_mask, &port_lock_mask); 3940afe267f2STomi Valkeinen if (ret) 3941afe267f2STomi Valkeinen goto err_disable_vpocs; 3942afe267f2STomi Valkeinen 3943afe267f2STomi Valkeinen if (port_mask != port_lock_mask) { 3944afe267f2STomi Valkeinen ret = -EIO; 3945afe267f2STomi Valkeinen dev_err_probe(dev, ret, "Failed to lock all RX ports\n"); 3946afe267f2STomi Valkeinen goto err_disable_vpocs; 3947afe267f2STomi Valkeinen } 3948afe267f2STomi Valkeinen 3949afe267f2STomi Valkeinen /* 3950afe267f2STomi Valkeinen * Clear any errors caused by switching the RX port settings while 3951afe267f2STomi Valkeinen * probing. 3952afe267f2STomi Valkeinen */ 3953afe267f2STomi Valkeinen ub960_clear_rx_errors(priv); 3954afe267f2STomi Valkeinen 3955afe267f2STomi Valkeinen ret = ub960_init_atr(priv); 3956afe267f2STomi Valkeinen if (ret) 3957afe267f2STomi Valkeinen goto err_disable_vpocs; 3958afe267f2STomi Valkeinen 3959afe267f2STomi Valkeinen ret = ub960_rxport_add_serializers(priv); 3960afe267f2STomi Valkeinen if (ret) 3961afe267f2STomi Valkeinen goto err_uninit_atr; 3962afe267f2STomi Valkeinen 3963afe267f2STomi Valkeinen ret = ub960_create_subdev(priv); 3964afe267f2STomi Valkeinen if (ret) 3965afe267f2STomi Valkeinen goto err_free_sers; 3966afe267f2STomi Valkeinen 3967afe267f2STomi Valkeinen if (client->irq) 3968afe267f2STomi Valkeinen dev_warn(dev, "irq support not implemented, using polling\n"); 3969afe267f2STomi Valkeinen 3970afe267f2STomi Valkeinen schedule_delayed_work(&priv->poll_work, 3971afe267f2STomi Valkeinen msecs_to_jiffies(UB960_POLL_TIME_MS)); 3972afe267f2STomi Valkeinen 3973afe267f2STomi Valkeinen return 0; 3974afe267f2STomi Valkeinen 3975afe267f2STomi Valkeinen err_free_sers: 3976afe267f2STomi Valkeinen ub960_rxport_remove_serializers(priv); 3977afe267f2STomi Valkeinen err_uninit_atr: 3978afe267f2STomi Valkeinen ub960_uninit_atr(priv); 3979afe267f2STomi Valkeinen err_disable_vpocs: 3980afe267f2STomi Valkeinen ub960_rxport_disable_vpocs(priv); 3981afe267f2STomi Valkeinen err_free_ports: 3982afe267f2STomi Valkeinen ub960_rxport_free_ports(priv); 3983afe267f2STomi Valkeinen ub960_txport_free_ports(priv); 3984afe267f2STomi Valkeinen err_disable_core_hw: 3985afe267f2STomi Valkeinen ub960_disable_core_hw(priv); 3986afe267f2STomi Valkeinen err_mutex_destroy: 3987afe267f2STomi Valkeinen mutex_destroy(&priv->reg_lock); 3988afe267f2STomi Valkeinen return ret; 3989afe267f2STomi Valkeinen } 3990afe267f2STomi Valkeinen 3991afe267f2STomi Valkeinen static void ub960_remove(struct i2c_client *client) 3992afe267f2STomi Valkeinen { 3993afe267f2STomi Valkeinen struct v4l2_subdev *sd = i2c_get_clientdata(client); 3994afe267f2STomi Valkeinen struct ub960_data *priv = sd_to_ub960(sd); 3995afe267f2STomi Valkeinen 3996afe267f2STomi Valkeinen cancel_delayed_work_sync(&priv->poll_work); 3997afe267f2STomi Valkeinen 3998afe267f2STomi Valkeinen ub960_destroy_subdev(priv); 3999afe267f2STomi Valkeinen ub960_rxport_remove_serializers(priv); 4000afe267f2STomi Valkeinen ub960_uninit_atr(priv); 4001afe267f2STomi Valkeinen ub960_rxport_disable_vpocs(priv); 4002afe267f2STomi Valkeinen ub960_rxport_free_ports(priv); 4003afe267f2STomi Valkeinen ub960_txport_free_ports(priv); 4004afe267f2STomi Valkeinen ub960_disable_core_hw(priv); 4005afe267f2STomi Valkeinen mutex_destroy(&priv->reg_lock); 4006afe267f2STomi Valkeinen } 4007afe267f2STomi Valkeinen 4008afe267f2STomi Valkeinen static const struct ub960_hw_data ds90ub960_hw = { 4009afe267f2STomi Valkeinen .model = "ub960", 4010afe267f2STomi Valkeinen .num_rxports = 4, 4011afe267f2STomi Valkeinen .num_txports = 2, 4012afe267f2STomi Valkeinen }; 4013afe267f2STomi Valkeinen 4014afe267f2STomi Valkeinen static const struct ub960_hw_data ds90ub9702_hw = { 4015afe267f2STomi Valkeinen .model = "ub9702", 4016afe267f2STomi Valkeinen .num_rxports = 4, 4017afe267f2STomi Valkeinen .num_txports = 2, 4018afe267f2STomi Valkeinen .is_ub9702 = true, 4019afe267f2STomi Valkeinen .is_fpdlink4 = true, 4020afe267f2STomi Valkeinen }; 4021afe267f2STomi Valkeinen 4022afe267f2STomi Valkeinen static const struct i2c_device_id ub960_id[] = { 4023afe267f2STomi Valkeinen { "ds90ub960-q1", (kernel_ulong_t)&ds90ub960_hw }, 4024afe267f2STomi Valkeinen { "ds90ub9702-q1", (kernel_ulong_t)&ds90ub9702_hw }, 4025afe267f2STomi Valkeinen {} 4026afe267f2STomi Valkeinen }; 4027afe267f2STomi Valkeinen MODULE_DEVICE_TABLE(i2c, ub960_id); 4028afe267f2STomi Valkeinen 4029afe267f2STomi Valkeinen static const struct of_device_id ub960_dt_ids[] = { 4030afe267f2STomi Valkeinen { .compatible = "ti,ds90ub960-q1", .data = &ds90ub960_hw }, 4031afe267f2STomi Valkeinen { .compatible = "ti,ds90ub9702-q1", .data = &ds90ub9702_hw }, 4032afe267f2STomi Valkeinen {} 4033afe267f2STomi Valkeinen }; 4034afe267f2STomi Valkeinen MODULE_DEVICE_TABLE(of, ub960_dt_ids); 4035afe267f2STomi Valkeinen 4036afe267f2STomi Valkeinen static struct i2c_driver ds90ub960_driver = { 4037f2183847SUwe Kleine-König .probe = ub960_probe, 4038afe267f2STomi Valkeinen .remove = ub960_remove, 4039afe267f2STomi Valkeinen .id_table = ub960_id, 4040afe267f2STomi Valkeinen .driver = { 4041afe267f2STomi Valkeinen .name = "ds90ub960", 4042afe267f2STomi Valkeinen .of_match_table = ub960_dt_ids, 4043afe267f2STomi Valkeinen }, 4044afe267f2STomi Valkeinen }; 4045afe267f2STomi Valkeinen module_i2c_driver(ds90ub960_driver); 4046afe267f2STomi Valkeinen 4047afe267f2STomi Valkeinen MODULE_LICENSE("GPL"); 4048afe267f2STomi Valkeinen MODULE_DESCRIPTION("Texas Instruments FPD-Link III/IV Deserializers Driver"); 4049afe267f2STomi Valkeinen MODULE_AUTHOR("Luca Ceresoli <luca@lucaceresoli.net>"); 4050afe267f2STomi Valkeinen MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>"); 4051afe267f2STomi Valkeinen MODULE_IMPORT_NS(I2C_ATR); 4052