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