Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Tomi Valkeinen | 16963 | 99.71% | 4 | 33.33% |
Sakari Ailus | 14 | 0.08% | 3 | 25.00% |
Laurent Pinchart | 12 | 0.07% | 1 | 8.33% |
Harshit Mogalapalli | 11 | 0.06% | 1 | 8.33% |
Steve Longerbeam | 11 | 0.06% | 2 | 16.67% |
Uwe Kleine-König | 1 | 0.01% | 1 | 8.33% |
Total | 17012 | 12 |
// SPDX-License-Identifier: GPL-2.0 /* * Driver for the Texas Instruments DS90UB960-Q1 video deserializer * * Copyright (c) 2019 Luca Ceresoli <luca@lucaceresoli.net> * Copyright (c) 2023 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> */ /* * (Possible) TODOs: * * - PM for serializer and remote peripherals. We need to manage: * - VPOC * - Power domain? Regulator? Somehow any remote device should be able to * cause the VPOC to be turned on. * - Link between the deserializer and the serializer * - Related to VPOC management. We probably always want to turn on the VPOC * and then enable the link. * - Serializer's services: i2c, gpios, power * - The serializer needs to resume before the remote peripherals can * e.g. use the i2c. * - How to handle gpios? Reserving a gpio essentially keeps the provider * (serializer) always powered on. * - Do we need a new bus for the FPD-Link? At the moment the serializers * are children of the same i2c-adapter where the deserializer resides. * - i2c-atr could be made embeddable instead of allocatable. */ #include <linux/bitops.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/fwnode.h> #include <linux/gpio/consumer.h> #include <linux/i2c-atr.h> #include <linux/i2c.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/kthread.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/property.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> #include <linux/workqueue.h> #include <media/i2c/ds90ub9xx.h> #include <media/mipi-csi2.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-event.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> #define MHZ(v) ((u32)((v) * 1000000U)) #define UB960_POLL_TIME_MS 500 #define UB960_MAX_RX_NPORTS 4 #define UB960_MAX_TX_NPORTS 2 #define UB960_MAX_NPORTS (UB960_MAX_RX_NPORTS + UB960_MAX_TX_NPORTS) #define UB960_MAX_PORT_ALIASES 8 #define UB960_NUM_BC_GPIOS 4 /* * Register map * * 0x00-0x32 Shared (UB960_SR) * 0x33-0x3a CSI-2 TX (per-port paged on DS90UB960, shared on 954) (UB960_TR) * 0x4c Shared (UB960_SR) * 0x4d-0x7f FPD-Link RX, per-port paged (UB960_RR) * 0xb0-0xbf Shared (UB960_SR) * 0xd0-0xdf FPD-Link RX, per-port paged (UB960_RR) * 0xf0-0xf5 Shared (UB960_SR) * 0xf8-0xfb Shared (UB960_SR) * All others Reserved * * Register prefixes: * UB960_SR_* = Shared register * UB960_RR_* = FPD-Link RX, per-port paged register * UB960_TR_* = CSI-2 TX, per-port paged register * UB960_XR_* = Reserved register * UB960_IR_* = Indirect register */ #define UB960_SR_I2C_DEV_ID 0x00 #define UB960_SR_RESET 0x01 #define UB960_SR_RESET_DIGITAL_RESET1 BIT(1) #define UB960_SR_RESET_DIGITAL_RESET0 BIT(0) #define UB960_SR_RESET_GPIO_LOCK_RELEASE BIT(5) #define UB960_SR_GEN_CONFIG 0x02 #define UB960_SR_REV_MASK 0x03 #define UB960_SR_DEVICE_STS 0x04 #define UB960_SR_PAR_ERR_THOLD_HI 0x05 #define UB960_SR_PAR_ERR_THOLD_LO 0x06 #define UB960_SR_BCC_WDOG_CTL 0x07 #define UB960_SR_I2C_CTL1 0x08 #define UB960_SR_I2C_CTL2 0x09 #define UB960_SR_SCL_HIGH_TIME 0x0a #define UB960_SR_SCL_LOW_TIME 0x0b #define UB960_SR_RX_PORT_CTL 0x0c #define UB960_SR_IO_CTL 0x0d #define UB960_SR_GPIO_PIN_STS 0x0e #define UB960_SR_GPIO_INPUT_CTL 0x0f #define UB960_SR_GPIO_PIN_CTL(n) (0x10 + (n)) /* n < UB960_NUM_GPIOS */ #define UB960_SR_GPIO_PIN_CTL_GPIO_OUT_SEL 5 #define UB960_SR_GPIO_PIN_CTL_GPIO_OUT_SRC_SHIFT 2 #define UB960_SR_GPIO_PIN_CTL_GPIO_OUT_EN BIT(0) #define UB960_SR_FS_CTL 0x18 #define UB960_SR_FS_HIGH_TIME_1 0x19 #define UB960_SR_FS_HIGH_TIME_0 0x1a #define UB960_SR_FS_LOW_TIME_1 0x1b #define UB960_SR_FS_LOW_TIME_0 0x1c #define UB960_SR_MAX_FRM_HI 0x1d #define UB960_SR_MAX_FRM_LO 0x1e #define UB960_SR_CSI_PLL_CTL 0x1f #define UB960_SR_FWD_CTL1 0x20 #define UB960_SR_FWD_CTL1_PORT_DIS(n) BIT((n) + 4) #define UB960_SR_FWD_CTL2 0x21 #define UB960_SR_FWD_STS 0x22 #define UB960_SR_INTERRUPT_CTL 0x23 #define UB960_SR_INTERRUPT_CTL_INT_EN BIT(7) #define UB960_SR_INTERRUPT_CTL_IE_CSI_TX0 BIT(4) #define UB960_SR_INTERRUPT_CTL_IE_RX(n) BIT((n)) /* rxport[n] IRQ */ #define UB960_SR_INTERRUPT_STS 0x24 #define UB960_SR_INTERRUPT_STS_INT BIT(7) #define UB960_SR_INTERRUPT_STS_IS_CSI_TX(n) BIT(4 + (n)) /* txport[n] IRQ */ #define UB960_SR_INTERRUPT_STS_IS_RX(n) BIT((n)) /* rxport[n] IRQ */ #define UB960_SR_TS_CONFIG 0x25 #define UB960_SR_TS_CONTROL 0x26 #define UB960_SR_TS_LINE_HI 0x27 #define UB960_SR_TS_LINE_LO 0x28 #define UB960_SR_TS_STATUS 0x29 #define UB960_SR_TIMESTAMP_P0_HI 0x2a #define UB960_SR_TIMESTAMP_P0_LO 0x2b #define UB960_SR_TIMESTAMP_P1_HI 0x2c #define UB960_SR_TIMESTAMP_P1_LO 0x2d #define UB960_SR_CSI_PORT_SEL 0x32 #define UB960_TR_CSI_CTL 0x33 #define UB960_TR_CSI_CTL_CSI_CAL_EN BIT(6) #define UB960_TR_CSI_CTL_CSI_CONTS_CLOCK BIT(1) #define UB960_TR_CSI_CTL_CSI_ENABLE BIT(0) #define UB960_TR_CSI_CTL2 0x34 #define UB960_TR_CSI_STS 0x35 #define UB960_TR_CSI_TX_ICR 0x36 #define UB960_TR_CSI_TX_ISR 0x37 #define UB960_TR_CSI_TX_ISR_IS_CSI_SYNC_ERROR BIT(3) #define UB960_TR_CSI_TX_ISR_IS_CSI_PASS_ERROR BIT(1) #define UB960_TR_CSI_TEST_CTL 0x38 #define UB960_TR_CSI_TEST_PATT_HI 0x39 #define UB960_TR_CSI_TEST_PATT_LO 0x3a #define UB960_XR_SFILTER_CFG 0x41 #define UB960_XR_SFILTER_CFG_SFILTER_MAX_SHIFT 4 #define UB960_XR_SFILTER_CFG_SFILTER_MIN_SHIFT 0 #define UB960_XR_AEQ_CTL1 0x42 #define UB960_XR_AEQ_CTL1_AEQ_ERR_CTL_FPD_CLK BIT(6) #define UB960_XR_AEQ_CTL1_AEQ_ERR_CTL_ENCODING BIT(5) #define UB960_XR_AEQ_CTL1_AEQ_ERR_CTL_PARITY BIT(4) #define UB960_XR_AEQ_CTL1_AEQ_ERR_CTL_MASK \ (UB960_XR_AEQ_CTL1_AEQ_ERR_CTL_FPD_CLK | \ UB960_XR_AEQ_CTL1_AEQ_ERR_CTL_ENCODING | \ UB960_XR_AEQ_CTL1_AEQ_ERR_CTL_PARITY) #define UB960_XR_AEQ_CTL1_AEQ_SFILTER_EN BIT(0) #define UB960_XR_AEQ_ERR_THOLD 0x43 #define UB960_RR_BCC_ERR_CTL 0x46 #define UB960_RR_BCC_STATUS 0x47 #define UB960_RR_BCC_STATUS_SEQ_ERROR BIT(5) #define UB960_RR_BCC_STATUS_MASTER_ERR BIT(4) #define UB960_RR_BCC_STATUS_MASTER_TO BIT(3) #define UB960_RR_BCC_STATUS_SLAVE_ERR BIT(2) #define UB960_RR_BCC_STATUS_SLAVE_TO BIT(1) #define UB960_RR_BCC_STATUS_RESP_ERR BIT(0) #define UB960_RR_BCC_STATUS_ERROR_MASK \ (UB960_RR_BCC_STATUS_SEQ_ERROR | UB960_RR_BCC_STATUS_MASTER_ERR | \ UB960_RR_BCC_STATUS_MASTER_TO | UB960_RR_BCC_STATUS_SLAVE_ERR | \ UB960_RR_BCC_STATUS_SLAVE_TO | UB960_RR_BCC_STATUS_RESP_ERR) #define UB960_RR_FPD3_CAP 0x4a #define UB960_RR_RAW_EMBED_DTYPE 0x4b #define UB960_RR_RAW_EMBED_DTYPE_LINES_SHIFT 6 #define UB960_SR_FPD3_PORT_SEL 0x4c #define UB960_RR_RX_PORT_STS1 0x4d #define UB960_RR_RX_PORT_STS1_BCC_CRC_ERROR BIT(5) #define UB960_RR_RX_PORT_STS1_LOCK_STS_CHG BIT(4) #define UB960_RR_RX_PORT_STS1_BCC_SEQ_ERROR BIT(3) #define UB960_RR_RX_PORT_STS1_PARITY_ERROR BIT(2) #define UB960_RR_RX_PORT_STS1_PORT_PASS BIT(1) #define UB960_RR_RX_PORT_STS1_LOCK_STS BIT(0) #define UB960_RR_RX_PORT_STS1_ERROR_MASK \ (UB960_RR_RX_PORT_STS1_BCC_CRC_ERROR | \ UB960_RR_RX_PORT_STS1_BCC_SEQ_ERROR | \ UB960_RR_RX_PORT_STS1_PARITY_ERROR) #define UB960_RR_RX_PORT_STS2 0x4e #define UB960_RR_RX_PORT_STS2_LINE_LEN_UNSTABLE BIT(7) #define UB960_RR_RX_PORT_STS2_LINE_LEN_CHG BIT(6) #define UB960_RR_RX_PORT_STS2_FPD3_ENCODE_ERROR BIT(5) #define UB960_RR_RX_PORT_STS2_BUFFER_ERROR BIT(4) #define UB960_RR_RX_PORT_STS2_CSI_ERROR BIT(3) #define UB960_RR_RX_PORT_STS2_FREQ_STABLE BIT(2) #define UB960_RR_RX_PORT_STS2_CABLE_FAULT BIT(1) #define UB960_RR_RX_PORT_STS2_LINE_CNT_CHG BIT(0) #define UB960_RR_RX_PORT_STS2_ERROR_MASK \ UB960_RR_RX_PORT_STS2_BUFFER_ERROR #define UB960_RR_RX_FREQ_HIGH 0x4f #define UB960_RR_RX_FREQ_LOW 0x50 #define UB960_RR_SENSOR_STS_0 0x51 #define UB960_RR_SENSOR_STS_1 0x52 #define UB960_RR_SENSOR_STS_2 0x53 #define UB960_RR_SENSOR_STS_3 0x54 #define UB960_RR_RX_PAR_ERR_HI 0x55 #define UB960_RR_RX_PAR_ERR_LO 0x56 #define UB960_RR_BIST_ERR_COUNT 0x57 #define UB960_RR_BCC_CONFIG 0x58 #define UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH BIT(6) #define UB960_RR_BCC_CONFIG_BC_FREQ_SEL_MASK GENMASK(2, 0) #define UB960_RR_DATAPATH_CTL1 0x59 #define UB960_RR_DATAPATH_CTL2 0x5a #define UB960_RR_SER_ID 0x5b #define UB960_RR_SER_ALIAS_ID 0x5c /* For these two register sets: n < UB960_MAX_PORT_ALIASES */ #define UB960_RR_SLAVE_ID(n) (0x5d + (n)) #define UB960_RR_SLAVE_ALIAS(n) (0x65 + (n)) #define UB960_RR_PORT_CONFIG 0x6d #define UB960_RR_PORT_CONFIG_FPD3_MODE_MASK GENMASK(1, 0) #define UB960_RR_BC_GPIO_CTL(n) (0x6e + (n)) /* n < 2 */ #define UB960_RR_RAW10_ID 0x70 #define UB960_RR_RAW10_ID_VC_SHIFT 6 #define UB960_RR_RAW10_ID_DT_SHIFT 0 #define UB960_RR_RAW12_ID 0x71 #define UB960_RR_CSI_VC_MAP 0x72 #define UB960_RR_CSI_VC_MAP_SHIFT(x) ((x) * 2) #define UB960_RR_LINE_COUNT_HI 0x73 #define UB960_RR_LINE_COUNT_LO 0x74 #define UB960_RR_LINE_LEN_1 0x75 #define UB960_RR_LINE_LEN_0 0x76 #define UB960_RR_FREQ_DET_CTL 0x77 #define UB960_RR_MAILBOX_1 0x78 #define UB960_RR_MAILBOX_2 0x79 #define UB960_RR_CSI_RX_STS 0x7a #define UB960_RR_CSI_RX_STS_LENGTH_ERR BIT(3) #define UB960_RR_CSI_RX_STS_CKSUM_ERR BIT(2) #define UB960_RR_CSI_RX_STS_ECC2_ERR BIT(1) #define UB960_RR_CSI_RX_STS_ECC1_ERR BIT(0) #define UB960_RR_CSI_RX_STS_ERROR_MASK \ (UB960_RR_CSI_RX_STS_LENGTH_ERR | UB960_RR_CSI_RX_STS_CKSUM_ERR | \ UB960_RR_CSI_RX_STS_ECC2_ERR | UB960_RR_CSI_RX_STS_ECC1_ERR) #define UB960_RR_CSI_ERR_COUNTER 0x7b #define UB960_RR_PORT_CONFIG2 0x7c #define UB960_RR_PORT_CONFIG2_RAW10_8BIT_CTL_MASK GENMASK(7, 6) #define UB960_RR_PORT_CONFIG2_RAW10_8BIT_CTL_SHIFT 6 #define UB960_RR_PORT_CONFIG2_LV_POL_LOW BIT(1) #define UB960_RR_PORT_CONFIG2_FV_POL_LOW BIT(0) #define UB960_RR_PORT_PASS_CTL 0x7d #define UB960_RR_SEN_INT_RISE_CTL 0x7e #define UB960_RR_SEN_INT_FALL_CTL 0x7f #define UB960_SR_CSI_FRAME_COUNT_HI(n) (0x90 + 8 * (n)) #define UB960_SR_CSI_FRAME_COUNT_LO(n) (0x91 + 8 * (n)) #define UB960_SR_CSI_FRAME_ERR_COUNT_HI(n) (0x92 + 8 * (n)) #define UB960_SR_CSI_FRAME_ERR_COUNT_LO(n) (0x93 + 8 * (n)) #define UB960_SR_CSI_LINE_COUNT_HI(n) (0x94 + 8 * (n)) #define UB960_SR_CSI_LINE_COUNT_LO(n) (0x95 + 8 * (n)) #define UB960_SR_CSI_LINE_ERR_COUNT_HI(n) (0x96 + 8 * (n)) #define UB960_SR_CSI_LINE_ERR_COUNT_LO(n) (0x97 + 8 * (n)) #define UB960_XR_REFCLK_FREQ 0xa5 /* UB960 */ #define UB960_RR_VC_ID_MAP(x) (0xa0 + (x)) /* UB9702 */ #define UB960_SR_IND_ACC_CTL 0xb0 #define UB960_SR_IND_ACC_CTL_IA_AUTO_INC BIT(1) #define UB960_SR_IND_ACC_ADDR 0xb1 #define UB960_SR_IND_ACC_DATA 0xb2 #define UB960_SR_BIST_CONTROL 0xb3 #define UB960_SR_MODE_IDX_STS 0xb8 #define UB960_SR_LINK_ERROR_COUNT 0xb9 #define UB960_SR_FPD3_ENC_CTL 0xba #define UB960_SR_FV_MIN_TIME 0xbc #define UB960_SR_GPIO_PD_CTL 0xbe #define UB960_SR_FPD_RATE_CFG 0xc2 /* UB9702 */ #define UB960_SR_CSI_PLL_DIV 0xc9 /* UB9702 */ #define UB960_RR_PORT_DEBUG 0xd0 #define UB960_RR_AEQ_CTL2 0xd2 #define UB960_RR_AEQ_CTL2_SET_AEQ_FLOOR BIT(2) #define UB960_RR_AEQ_STATUS 0xd3 #define UB960_RR_AEQ_STATUS_STATUS_2 GENMASK(5, 3) #define UB960_RR_AEQ_STATUS_STATUS_1 GENMASK(2, 0) #define UB960_RR_AEQ_BYPASS 0xd4 #define UB960_RR_AEQ_BYPASS_EQ_STAGE1_VALUE_SHIFT 5 #define UB960_RR_AEQ_BYPASS_EQ_STAGE1_VALUE_MASK GENMASK(7, 5) #define UB960_RR_AEQ_BYPASS_EQ_STAGE2_VALUE_SHIFT 1 #define UB960_RR_AEQ_BYPASS_EQ_STAGE2_VALUE_MASK GENMASK(3, 1) #define UB960_RR_AEQ_BYPASS_ENABLE BIT(0) #define UB960_RR_AEQ_MIN_MAX 0xd5 #define UB960_RR_AEQ_MIN_MAX_AEQ_MAX_SHIFT 4 #define UB960_RR_AEQ_MIN_MAX_AEQ_FLOOR_SHIFT 0 #define UB960_RR_SFILTER_STS_0 0xd6 #define UB960_RR_SFILTER_STS_1 0xd7 #define UB960_RR_PORT_ICR_HI 0xd8 #define UB960_RR_PORT_ICR_LO 0xd9 #define UB960_RR_PORT_ISR_HI 0xda #define UB960_RR_PORT_ISR_LO 0xdb #define UB960_RR_FC_GPIO_STS 0xdc #define UB960_RR_FC_GPIO_ICR 0xdd #define UB960_RR_SEN_INT_RISE_STS 0xde #define UB960_RR_SEN_INT_FALL_STS 0xdf #define UB960_RR_CHANNEL_MODE 0xe4 /* UB9702 */ #define UB960_SR_FPD3_RX_ID(n) (0xf0 + (n)) #define UB960_SR_FPD3_RX_ID_LEN 6 #define UB960_SR_I2C_RX_ID(n) (0xf8 + (n)) /* < UB960_FPD_RX_NPORTS */ /* Indirect register blocks */ #define UB960_IND_TARGET_PAT_GEN 0x00 #define UB960_IND_TARGET_RX_ANA(n) (0x01 + (n)) #define UB960_IND_TARGET_CSI_CSIPLL_REG_1 0x92 /* UB9702 */ #define UB960_IND_TARGET_CSI_ANA 0x07 /* UB960_IR_PGEN_*: Indirect Registers for Test Pattern Generator */ #define UB960_IR_PGEN_CTL 0x01 #define UB960_IR_PGEN_CTL_PGEN_ENABLE BIT(0) #define UB960_IR_PGEN_CFG 0x02 #define UB960_IR_PGEN_CSI_DI 0x03 #define UB960_IR_PGEN_LINE_SIZE1 0x04 #define UB960_IR_PGEN_LINE_SIZE0 0x05 #define UB960_IR_PGEN_BAR_SIZE1 0x06 #define UB960_IR_PGEN_BAR_SIZE0 0x07 #define UB960_IR_PGEN_ACT_LPF1 0x08 #define UB960_IR_PGEN_ACT_LPF0 0x09 #define UB960_IR_PGEN_TOT_LPF1 0x0a #define UB960_IR_PGEN_TOT_LPF0 0x0b #define UB960_IR_PGEN_LINE_PD1 0x0c #define UB960_IR_PGEN_LINE_PD0 0x0d #define UB960_IR_PGEN_VBP 0x0e #define UB960_IR_PGEN_VFP 0x0f #define UB960_IR_PGEN_COLOR(n) (0x10 + (n)) /* n < 15 */ #define UB960_IR_RX_ANA_STROBE_SET_CLK 0x08 #define UB960_IR_RX_ANA_STROBE_SET_CLK_NO_EXTRA_DELAY BIT(3) #define UB960_IR_RX_ANA_STROBE_SET_CLK_DELAY_MASK GENMASK(2, 0) #define UB960_IR_RX_ANA_STROBE_SET_DATA 0x09 #define UB960_IR_RX_ANA_STROBE_SET_DATA_NO_EXTRA_DELAY BIT(3) #define UB960_IR_RX_ANA_STROBE_SET_DATA_DELAY_MASK GENMASK(2, 0) /* EQ related */ #define UB960_MIN_AEQ_STROBE_POS -7 #define UB960_MAX_AEQ_STROBE_POS 7 #define UB960_MANUAL_STROBE_EXTRA_DELAY 6 #define UB960_MIN_MANUAL_STROBE_POS -(7 + UB960_MANUAL_STROBE_EXTRA_DELAY) #define UB960_MAX_MANUAL_STROBE_POS (7 + UB960_MANUAL_STROBE_EXTRA_DELAY) #define UB960_NUM_MANUAL_STROBE_POS (UB960_MAX_MANUAL_STROBE_POS - UB960_MIN_MANUAL_STROBE_POS + 1) #define UB960_MIN_EQ_LEVEL 0 #define UB960_MAX_EQ_LEVEL 14 #define UB960_NUM_EQ_LEVELS (UB960_MAX_EQ_LEVEL - UB960_MIN_EQ_LEVEL + 1) struct ub960_hw_data { const char *model; u8 num_rxports; u8 num_txports; bool is_ub9702; bool is_fpdlink4; }; enum ub960_rxport_mode { RXPORT_MODE_RAW10 = 0, RXPORT_MODE_RAW12_HF = 1, RXPORT_MODE_RAW12_LF = 2, RXPORT_MODE_CSI2_SYNC = 3, RXPORT_MODE_CSI2_NONSYNC = 4, RXPORT_MODE_LAST = RXPORT_MODE_CSI2_NONSYNC, }; enum ub960_rxport_cdr { RXPORT_CDR_FPD3 = 0, RXPORT_CDR_FPD4 = 1, RXPORT_CDR_LAST = RXPORT_CDR_FPD4, }; struct ub960_rxport { struct ub960_data *priv; u8 nport; /* RX port number, and index in priv->rxport[] */ struct { struct v4l2_subdev *sd; u16 pad; struct fwnode_handle *ep_fwnode; } source; /* Serializer */ struct { struct fwnode_handle *fwnode; struct i2c_client *client; unsigned short alias; /* I2C alias (lower 7 bits) */ struct ds90ub9xx_platform_data pdata; } ser; enum ub960_rxport_mode rx_mode; enum ub960_rxport_cdr cdr_mode; u8 lv_fv_pol; /* LV and FV polarities */ struct regulator *vpoc; /* EQ settings */ struct { bool manual_eq; s8 strobe_pos; union { struct { u8 eq_level_min; u8 eq_level_max; } aeq; struct { u8 eq_level; } manual; }; } eq; const struct i2c_client *aliased_clients[UB960_MAX_PORT_ALIASES]; }; struct ub960_asd { struct v4l2_async_connection base; struct ub960_rxport *rxport; }; static inline struct ub960_asd *to_ub960_asd(struct v4l2_async_connection *asd) { return container_of(asd, struct ub960_asd, base); } struct ub960_txport { struct ub960_data *priv; u8 nport; /* TX port number, and index in priv->txport[] */ u32 num_data_lanes; bool non_continous_clk; }; struct ub960_data { const struct ub960_hw_data *hw_data; struct i2c_client *client; /* for shared local registers */ struct regmap *regmap; /* lock for register access */ struct mutex reg_lock; struct clk *refclk; struct regulator *vddio; struct gpio_desc *pd_gpio; struct delayed_work poll_work; struct ub960_rxport *rxports[UB960_MAX_RX_NPORTS]; struct ub960_txport *txports[UB960_MAX_TX_NPORTS]; struct v4l2_subdev sd; struct media_pad pads[UB960_MAX_NPORTS]; struct v4l2_ctrl_handler ctrl_handler; struct v4l2_async_notifier notifier; u32 tx_data_rate; /* Nominal data rate (Gb/s) */ s64 tx_link_freq[1]; struct i2c_atr *atr; struct { u8 rxport; u8 txport; u8 indirect_target; } reg_current; bool streaming; u8 stored_fwd_ctl; u64 stream_enable_mask[UB960_MAX_NPORTS]; /* These are common to all ports */ struct { bool manual; s8 min; s8 max; } strobe; }; static inline struct ub960_data *sd_to_ub960(struct v4l2_subdev *sd) { return container_of(sd, struct ub960_data, sd); } static inline bool ub960_pad_is_sink(struct ub960_data *priv, u32 pad) { return pad < priv->hw_data->num_rxports; } static inline bool ub960_pad_is_source(struct ub960_data *priv, u32 pad) { return pad >= priv->hw_data->num_rxports; } static inline unsigned int ub960_pad_to_port(struct ub960_data *priv, u32 pad) { if (ub960_pad_is_sink(priv, pad)) return pad; else return pad - priv->hw_data->num_rxports; } struct ub960_format_info { u32 code; u32 bpp; u8 datatype; bool meta; }; static const struct ub960_format_info ub960_formats[] = { { .code = MEDIA_BUS_FMT_YUYV8_1X16, .bpp = 16, .datatype = MIPI_CSI2_DT_YUV422_8B, }, { .code = MEDIA_BUS_FMT_UYVY8_1X16, .bpp = 16, .datatype = MIPI_CSI2_DT_YUV422_8B, }, { .code = MEDIA_BUS_FMT_VYUY8_1X16, .bpp = 16, .datatype = MIPI_CSI2_DT_YUV422_8B, }, { .code = MEDIA_BUS_FMT_YVYU8_1X16, .bpp = 16, .datatype = MIPI_CSI2_DT_YUV422_8B, }, { .code = MEDIA_BUS_FMT_SBGGR12_1X12, .bpp = 12, .datatype = MIPI_CSI2_DT_RAW12, }, { .code = MEDIA_BUS_FMT_SGBRG12_1X12, .bpp = 12, .datatype = MIPI_CSI2_DT_RAW12, }, { .code = MEDIA_BUS_FMT_SGRBG12_1X12, .bpp = 12, .datatype = MIPI_CSI2_DT_RAW12, }, { .code = MEDIA_BUS_FMT_SRGGB12_1X12, .bpp = 12, .datatype = MIPI_CSI2_DT_RAW12, }, }; static const struct ub960_format_info *ub960_find_format(u32 code) { unsigned int i; for (i = 0; i < ARRAY_SIZE(ub960_formats); i++) { if (ub960_formats[i].code == code) return &ub960_formats[i]; } return NULL; } /* ----------------------------------------------------------------------------- * Basic device access */ static int ub960_read(struct ub960_data *priv, u8 reg, u8 *val) { struct device *dev = &priv->client->dev; unsigned int v; int ret; mutex_lock(&priv->reg_lock); ret = regmap_read(priv->regmap, reg, &v); if (ret) { dev_err(dev, "%s: cannot read register 0x%02x (%d)!\n", __func__, reg, ret); goto out_unlock; } *val = v; out_unlock: mutex_unlock(&priv->reg_lock); return ret; } static int ub960_write(struct ub960_data *priv, u8 reg, u8 val) { struct device *dev = &priv->client->dev; int ret; mutex_lock(&priv->reg_lock); ret = regmap_write(priv->regmap, reg, val); if (ret) dev_err(dev, "%s: cannot write register 0x%02x (%d)!\n", __func__, reg, ret); mutex_unlock(&priv->reg_lock); return ret; } static int ub960_update_bits(struct ub960_data *priv, u8 reg, u8 mask, u8 val) { struct device *dev = &priv->client->dev; int ret; mutex_lock(&priv->reg_lock); ret = regmap_update_bits(priv->regmap, reg, mask, val); if (ret) dev_err(dev, "%s: cannot update register 0x%02x (%d)!\n", __func__, reg, ret); mutex_unlock(&priv->reg_lock); return ret; } static int ub960_read16(struct ub960_data *priv, u8 reg, u16 *val) { struct device *dev = &priv->client->dev; __be16 __v; int ret; mutex_lock(&priv->reg_lock); ret = regmap_bulk_read(priv->regmap, reg, &__v, sizeof(__v)); if (ret) { dev_err(dev, "%s: cannot read register 0x%02x (%d)!\n", __func__, reg, ret); goto out_unlock; } *val = be16_to_cpu(__v); out_unlock: mutex_unlock(&priv->reg_lock); return ret; } static int ub960_rxport_select(struct ub960_data *priv, u8 nport) { struct device *dev = &priv->client->dev; int ret; lockdep_assert_held(&priv->reg_lock); if (priv->reg_current.rxport == nport) return 0; ret = regmap_write(priv->regmap, UB960_SR_FPD3_PORT_SEL, (nport << 4) | BIT(nport)); if (ret) { dev_err(dev, "%s: cannot select rxport %d (%d)!\n", __func__, nport, ret); return ret; } priv->reg_current.rxport = nport; return 0; } static int ub960_rxport_read(struct ub960_data *priv, u8 nport, u8 reg, u8 *val) { struct device *dev = &priv->client->dev; unsigned int v; int ret; mutex_lock(&priv->reg_lock); ret = ub960_rxport_select(priv, nport); if (ret) goto out_unlock; ret = regmap_read(priv->regmap, reg, &v); if (ret) { dev_err(dev, "%s: cannot read register 0x%02x (%d)!\n", __func__, reg, ret); goto out_unlock; } *val = v; out_unlock: mutex_unlock(&priv->reg_lock); return ret; } static int ub960_rxport_write(struct ub960_data *priv, u8 nport, u8 reg, u8 val) { struct device *dev = &priv->client->dev; int ret; mutex_lock(&priv->reg_lock); ret = ub960_rxport_select(priv, nport); if (ret) goto out_unlock; ret = regmap_write(priv->regmap, reg, val); if (ret) dev_err(dev, "%s: cannot write register 0x%02x (%d)!\n", __func__, reg, ret); out_unlock: mutex_unlock(&priv->reg_lock); return ret; } static int ub960_rxport_update_bits(struct ub960_data *priv, u8 nport, u8 reg, u8 mask, u8 val) { struct device *dev = &priv->client->dev; int ret; mutex_lock(&priv->reg_lock); ret = ub960_rxport_select(priv, nport); if (ret) goto out_unlock; ret = regmap_update_bits(priv->regmap, reg, mask, val); if (ret) dev_err(dev, "%s: cannot update register 0x%02x (%d)!\n", __func__, reg, ret); out_unlock: mutex_unlock(&priv->reg_lock); return ret; } static int ub960_rxport_read16(struct ub960_data *priv, u8 nport, u8 reg, u16 *val) { struct device *dev = &priv->client->dev; __be16 __v; int ret; mutex_lock(&priv->reg_lock); ret = ub960_rxport_select(priv, nport); if (ret) goto out_unlock; ret = regmap_bulk_read(priv->regmap, reg, &__v, sizeof(__v)); if (ret) { dev_err(dev, "%s: cannot read register 0x%02x (%d)!\n", __func__, reg, ret); goto out_unlock; } *val = be16_to_cpu(__v); out_unlock: mutex_unlock(&priv->reg_lock); return ret; } static int ub960_txport_select(struct ub960_data *priv, u8 nport) { struct device *dev = &priv->client->dev; int ret; lockdep_assert_held(&priv->reg_lock); if (priv->reg_current.txport == nport) return 0; ret = regmap_write(priv->regmap, UB960_SR_CSI_PORT_SEL, (nport << 4) | BIT(nport)); if (ret) { dev_err(dev, "%s: cannot select tx port %d (%d)!\n", __func__, nport, ret); return ret; } priv->reg_current.txport = nport; return 0; } static int ub960_txport_read(struct ub960_data *priv, u8 nport, u8 reg, u8 *val) { struct device *dev = &priv->client->dev; unsigned int v; int ret; mutex_lock(&priv->reg_lock); ret = ub960_txport_select(priv, nport); if (ret) goto out_unlock; ret = regmap_read(priv->regmap, reg, &v); if (ret) { dev_err(dev, "%s: cannot read register 0x%02x (%d)!\n", __func__, reg, ret); goto out_unlock; } *val = v; out_unlock: mutex_unlock(&priv->reg_lock); return ret; } static int ub960_txport_write(struct ub960_data *priv, u8 nport, u8 reg, u8 val) { struct device *dev = &priv->client->dev; int ret; mutex_lock(&priv->reg_lock); ret = ub960_txport_select(priv, nport); if (ret) goto out_unlock; ret = regmap_write(priv->regmap, reg, val); if (ret) dev_err(dev, "%s: cannot write register 0x%02x (%d)!\n", __func__, reg, ret); out_unlock: mutex_unlock(&priv->reg_lock); return ret; } static int ub960_txport_update_bits(struct ub960_data *priv, u8 nport, u8 reg, u8 mask, u8 val) { struct device *dev = &priv->client->dev; int ret; mutex_lock(&priv->reg_lock); ret = ub960_txport_select(priv, nport); if (ret) goto out_unlock; ret = regmap_update_bits(priv->regmap, reg, mask, val); if (ret) dev_err(dev, "%s: cannot update register 0x%02x (%d)!\n", __func__, reg, ret); out_unlock: mutex_unlock(&priv->reg_lock); return ret; } static int ub960_select_ind_reg_block(struct ub960_data *priv, u8 block) { struct device *dev = &priv->client->dev; int ret; lockdep_assert_held(&priv->reg_lock); if (priv->reg_current.indirect_target == block) return 0; ret = regmap_write(priv->regmap, UB960_SR_IND_ACC_CTL, block << 2); if (ret) { dev_err(dev, "%s: cannot select indirect target %u (%d)!\n", __func__, block, ret); return ret; } priv->reg_current.indirect_target = block; return 0; } static int ub960_read_ind(struct ub960_data *priv, u8 block, u8 reg, u8 *val) { struct device *dev = &priv->client->dev; unsigned int v; int ret; mutex_lock(&priv->reg_lock); ret = ub960_select_ind_reg_block(priv, block); if (ret) goto out_unlock; ret = regmap_write(priv->regmap, UB960_SR_IND_ACC_ADDR, reg); if (ret) { dev_err(dev, "Write to IND_ACC_ADDR failed when reading %u:%x02x: %d\n", block, reg, ret); goto out_unlock; } ret = regmap_read(priv->regmap, UB960_SR_IND_ACC_DATA, &v); if (ret) { dev_err(dev, "Write to IND_ACC_DATA failed when reading %u:%x02x: %d\n", block, reg, ret); goto out_unlock; } *val = v; out_unlock: mutex_unlock(&priv->reg_lock); return ret; } static int ub960_write_ind(struct ub960_data *priv, u8 block, u8 reg, u8 val) { struct device *dev = &priv->client->dev; int ret; mutex_lock(&priv->reg_lock); ret = ub960_select_ind_reg_block(priv, block); if (ret) goto out_unlock; ret = regmap_write(priv->regmap, UB960_SR_IND_ACC_ADDR, reg); if (ret) { dev_err(dev, "Write to IND_ACC_ADDR failed when writing %u:%x02x: %d\n", block, reg, ret); goto out_unlock; } ret = regmap_write(priv->regmap, UB960_SR_IND_ACC_DATA, val); if (ret) { dev_err(dev, "Write to IND_ACC_DATA failed when writing %u:%x02x: %d\n", block, reg, ret); goto out_unlock; } out_unlock: mutex_unlock(&priv->reg_lock); return ret; } static int ub960_ind_update_bits(struct ub960_data *priv, u8 block, u8 reg, u8 mask, u8 val) { struct device *dev = &priv->client->dev; int ret; mutex_lock(&priv->reg_lock); ret = ub960_select_ind_reg_block(priv, block); if (ret) goto out_unlock; ret = regmap_write(priv->regmap, UB960_SR_IND_ACC_ADDR, reg); if (ret) { dev_err(dev, "Write to IND_ACC_ADDR failed when updating %u:%x02x: %d\n", block, reg, ret); goto out_unlock; } ret = regmap_update_bits(priv->regmap, UB960_SR_IND_ACC_DATA, mask, val); if (ret) { dev_err(dev, "Write to IND_ACC_DATA failed when updating %u:%x02x: %d\n", block, reg, ret); goto out_unlock; } out_unlock: mutex_unlock(&priv->reg_lock); return ret; } /* ----------------------------------------------------------------------------- * I2C-ATR (address translator) */ static int ub960_atr_attach_client(struct i2c_atr *atr, u32 chan_id, const struct i2c_client *client, u16 alias) { struct ub960_data *priv = i2c_atr_get_driver_data(atr); struct ub960_rxport *rxport = priv->rxports[chan_id]; struct device *dev = &priv->client->dev; unsigned int reg_idx; for (reg_idx = 0; reg_idx < ARRAY_SIZE(rxport->aliased_clients); reg_idx++) { if (!rxport->aliased_clients[reg_idx]) break; } if (reg_idx == ARRAY_SIZE(rxport->aliased_clients)) { dev_err(dev, "rx%u: alias pool exhausted\n", rxport->nport); return -EADDRNOTAVAIL; } rxport->aliased_clients[reg_idx] = client; ub960_rxport_write(priv, chan_id, UB960_RR_SLAVE_ID(reg_idx), client->addr << 1); ub960_rxport_write(priv, chan_id, UB960_RR_SLAVE_ALIAS(reg_idx), alias << 1); dev_dbg(dev, "rx%u: client 0x%02x assigned alias 0x%02x at slot %u\n", rxport->nport, client->addr, alias, reg_idx); return 0; } static void ub960_atr_detach_client(struct i2c_atr *atr, u32 chan_id, const struct i2c_client *client) { struct ub960_data *priv = i2c_atr_get_driver_data(atr); struct ub960_rxport *rxport = priv->rxports[chan_id]; struct device *dev = &priv->client->dev; unsigned int reg_idx; for (reg_idx = 0; reg_idx < ARRAY_SIZE(rxport->aliased_clients); reg_idx++) { if (rxport->aliased_clients[reg_idx] == client) break; } if (reg_idx == ARRAY_SIZE(rxport->aliased_clients)) { dev_err(dev, "rx%u: client 0x%02x is not mapped!\n", rxport->nport, client->addr); return; } rxport->aliased_clients[reg_idx] = NULL; ub960_rxport_write(priv, chan_id, UB960_RR_SLAVE_ALIAS(reg_idx), 0); dev_dbg(dev, "rx%u: client 0x%02x released at slot %u\n", rxport->nport, client->addr, reg_idx); } static const struct i2c_atr_ops ub960_atr_ops = { .attach_client = ub960_atr_attach_client, .detach_client = ub960_atr_detach_client, }; static int ub960_init_atr(struct ub960_data *priv) { struct device *dev = &priv->client->dev; struct i2c_adapter *parent_adap = priv->client->adapter; priv->atr = i2c_atr_new(parent_adap, dev, &ub960_atr_ops, priv->hw_data->num_rxports); if (IS_ERR(priv->atr)) return PTR_ERR(priv->atr); i2c_atr_set_driver_data(priv->atr, priv); return 0; } static void ub960_uninit_atr(struct ub960_data *priv) { i2c_atr_delete(priv->atr); priv->atr = NULL; } /* ----------------------------------------------------------------------------- * TX ports */ static int ub960_parse_dt_txport(struct ub960_data *priv, struct fwnode_handle *ep_fwnode, u8 nport) { struct device *dev = &priv->client->dev; struct v4l2_fwnode_endpoint vep = {}; struct ub960_txport *txport; int ret; txport = kzalloc(sizeof(*txport), GFP_KERNEL); if (!txport) return -ENOMEM; txport->priv = priv; txport->nport = nport; vep.bus_type = V4L2_MBUS_CSI2_DPHY; ret = v4l2_fwnode_endpoint_alloc_parse(ep_fwnode, &vep); if (ret) { dev_err(dev, "tx%u: failed to parse endpoint data\n", nport); goto err_free_txport; } txport->non_continous_clk = vep.bus.mipi_csi2.flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK; txport->num_data_lanes = vep.bus.mipi_csi2.num_data_lanes; if (vep.nr_of_link_frequencies != 1) { ret = -EINVAL; goto err_free_vep; } priv->tx_link_freq[0] = vep.link_frequencies[0]; priv->tx_data_rate = priv->tx_link_freq[0] * 2; if (priv->tx_data_rate != MHZ(1600) && priv->tx_data_rate != MHZ(1200) && priv->tx_data_rate != MHZ(800) && priv->tx_data_rate != MHZ(400)) { dev_err(dev, "tx%u: invalid 'link-frequencies' value\n", nport); ret = -EINVAL; goto err_free_vep; } v4l2_fwnode_endpoint_free(&vep); priv->txports[nport] = txport; return 0; err_free_vep: v4l2_fwnode_endpoint_free(&vep); err_free_txport: kfree(txport); return ret; } static void ub960_csi_handle_events(struct ub960_data *priv, u8 nport) { struct device *dev = &priv->client->dev; u8 csi_tx_isr; int ret; ret = ub960_txport_read(priv, nport, UB960_TR_CSI_TX_ISR, &csi_tx_isr); if (ret) return; if (csi_tx_isr & UB960_TR_CSI_TX_ISR_IS_CSI_SYNC_ERROR) dev_warn(dev, "TX%u: CSI_SYNC_ERROR\n", nport); if (csi_tx_isr & UB960_TR_CSI_TX_ISR_IS_CSI_PASS_ERROR) dev_warn(dev, "TX%u: CSI_PASS_ERROR\n", nport); } /* ----------------------------------------------------------------------------- * RX ports */ static int ub960_rxport_enable_vpocs(struct ub960_data *priv) { unsigned int nport; int ret; for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { struct ub960_rxport *rxport = priv->rxports[nport]; if (!rxport || !rxport->vpoc) continue; ret = regulator_enable(rxport->vpoc); if (ret) goto err_disable_vpocs; } return 0; err_disable_vpocs: while (nport--) { struct ub960_rxport *rxport = priv->rxports[nport]; if (!rxport || !rxport->vpoc) continue; regulator_disable(rxport->vpoc); } return ret; } static void ub960_rxport_disable_vpocs(struct ub960_data *priv) { unsigned int nport; for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { struct ub960_rxport *rxport = priv->rxports[nport]; if (!rxport || !rxport->vpoc) continue; regulator_disable(rxport->vpoc); } } static void ub960_rxport_clear_errors(struct ub960_data *priv, unsigned int nport) { u8 v; ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, &v); ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2, &v); ub960_rxport_read(priv, nport, UB960_RR_CSI_RX_STS, &v); ub960_rxport_read(priv, nport, UB960_RR_BCC_STATUS, &v); ub960_rxport_read(priv, nport, UB960_RR_RX_PAR_ERR_HI, &v); ub960_rxport_read(priv, nport, UB960_RR_RX_PAR_ERR_LO, &v); ub960_rxport_read(priv, nport, UB960_RR_CSI_ERR_COUNTER, &v); } static void ub960_clear_rx_errors(struct ub960_data *priv) { unsigned int nport; for (nport = 0; nport < priv->hw_data->num_rxports; nport++) ub960_rxport_clear_errors(priv, nport); } static int ub960_rxport_get_strobe_pos(struct ub960_data *priv, unsigned int nport, s8 *strobe_pos) { u8 v; u8 clk_delay, data_delay; int ret; ub960_read_ind(priv, UB960_IND_TARGET_RX_ANA(nport), UB960_IR_RX_ANA_STROBE_SET_CLK, &v); clk_delay = (v & UB960_IR_RX_ANA_STROBE_SET_CLK_NO_EXTRA_DELAY) ? 0 : UB960_MANUAL_STROBE_EXTRA_DELAY; ub960_read_ind(priv, UB960_IND_TARGET_RX_ANA(nport), UB960_IR_RX_ANA_STROBE_SET_DATA, &v); data_delay = (v & UB960_IR_RX_ANA_STROBE_SET_DATA_NO_EXTRA_DELAY) ? 0 : UB960_MANUAL_STROBE_EXTRA_DELAY; ret = ub960_rxport_read(priv, nport, UB960_RR_SFILTER_STS_0, &v); if (ret) return ret; clk_delay += v & UB960_IR_RX_ANA_STROBE_SET_CLK_DELAY_MASK; ub960_rxport_read(priv, nport, UB960_RR_SFILTER_STS_1, &v); if (ret) return ret; data_delay += v & UB960_IR_RX_ANA_STROBE_SET_DATA_DELAY_MASK; *strobe_pos = data_delay - clk_delay; return 0; } static void ub960_rxport_set_strobe_pos(struct ub960_data *priv, unsigned int nport, s8 strobe_pos) { u8 clk_delay, data_delay; clk_delay = UB960_IR_RX_ANA_STROBE_SET_CLK_NO_EXTRA_DELAY; data_delay = UB960_IR_RX_ANA_STROBE_SET_DATA_NO_EXTRA_DELAY; if (strobe_pos < UB960_MIN_AEQ_STROBE_POS) clk_delay = abs(strobe_pos) - UB960_MANUAL_STROBE_EXTRA_DELAY; else if (strobe_pos > UB960_MAX_AEQ_STROBE_POS) data_delay = strobe_pos - UB960_MANUAL_STROBE_EXTRA_DELAY; else if (strobe_pos < 0) clk_delay = abs(strobe_pos) | UB960_IR_RX_ANA_STROBE_SET_CLK_NO_EXTRA_DELAY; else if (strobe_pos > 0) data_delay = strobe_pos | UB960_IR_RX_ANA_STROBE_SET_DATA_NO_EXTRA_DELAY; ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), UB960_IR_RX_ANA_STROBE_SET_CLK, clk_delay); ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), UB960_IR_RX_ANA_STROBE_SET_DATA, data_delay); } static void ub960_rxport_set_strobe_range(struct ub960_data *priv, s8 strobe_min, s8 strobe_max) { /* Convert the signed strobe pos to positive zero based value */ strobe_min -= UB960_MIN_AEQ_STROBE_POS; strobe_max -= UB960_MIN_AEQ_STROBE_POS; ub960_write(priv, UB960_XR_SFILTER_CFG, ((u8)strobe_min << UB960_XR_SFILTER_CFG_SFILTER_MIN_SHIFT) | ((u8)strobe_max << UB960_XR_SFILTER_CFG_SFILTER_MAX_SHIFT)); } static int ub960_rxport_get_eq_level(struct ub960_data *priv, unsigned int nport, u8 *eq_level) { int ret; u8 v; ret = ub960_rxport_read(priv, nport, UB960_RR_AEQ_STATUS, &v); if (ret) return ret; *eq_level = (v & UB960_RR_AEQ_STATUS_STATUS_1) + (v & UB960_RR_AEQ_STATUS_STATUS_2); return 0; } static void ub960_rxport_set_eq_level(struct ub960_data *priv, unsigned int nport, u8 eq_level) { u8 eq_stage_1_select_value, eq_stage_2_select_value; const unsigned int eq_stage_max = 7; u8 v; if (eq_level <= eq_stage_max) { eq_stage_1_select_value = eq_level; eq_stage_2_select_value = 0; } else { eq_stage_1_select_value = eq_stage_max; eq_stage_2_select_value = eq_level - eq_stage_max; } ub960_rxport_read(priv, nport, UB960_RR_AEQ_BYPASS, &v); v &= ~(UB960_RR_AEQ_BYPASS_EQ_STAGE1_VALUE_MASK | UB960_RR_AEQ_BYPASS_EQ_STAGE2_VALUE_MASK); v |= eq_stage_1_select_value << UB960_RR_AEQ_BYPASS_EQ_STAGE1_VALUE_SHIFT; v |= eq_stage_2_select_value << UB960_RR_AEQ_BYPASS_EQ_STAGE2_VALUE_SHIFT; v |= UB960_RR_AEQ_BYPASS_ENABLE; ub960_rxport_write(priv, nport, UB960_RR_AEQ_BYPASS, v); } static void ub960_rxport_set_eq_range(struct ub960_data *priv, unsigned int nport, u8 eq_min, u8 eq_max) { ub960_rxport_write(priv, nport, UB960_RR_AEQ_MIN_MAX, (eq_min << UB960_RR_AEQ_MIN_MAX_AEQ_FLOOR_SHIFT) | (eq_max << UB960_RR_AEQ_MIN_MAX_AEQ_MAX_SHIFT)); /* Enable AEQ min setting */ ub960_rxport_update_bits(priv, nport, UB960_RR_AEQ_CTL2, UB960_RR_AEQ_CTL2_SET_AEQ_FLOOR, UB960_RR_AEQ_CTL2_SET_AEQ_FLOOR); } static void ub960_rxport_config_eq(struct ub960_data *priv, unsigned int nport) { struct ub960_rxport *rxport = priv->rxports[nport]; /* We also set common settings here. Should be moved elsewhere. */ if (priv->strobe.manual) { /* Disable AEQ_SFILTER_EN */ ub960_update_bits(priv, UB960_XR_AEQ_CTL1, UB960_XR_AEQ_CTL1_AEQ_SFILTER_EN, 0); } else { /* Enable SFILTER and error control */ ub960_write(priv, UB960_XR_AEQ_CTL1, UB960_XR_AEQ_CTL1_AEQ_ERR_CTL_MASK | UB960_XR_AEQ_CTL1_AEQ_SFILTER_EN); /* Set AEQ strobe range */ ub960_rxport_set_strobe_range(priv, priv->strobe.min, priv->strobe.max); } /* The rest are port specific */ if (priv->strobe.manual) ub960_rxport_set_strobe_pos(priv, nport, rxport->eq.strobe_pos); else ub960_rxport_set_strobe_pos(priv, nport, 0); if (rxport->eq.manual_eq) { ub960_rxport_set_eq_level(priv, nport, rxport->eq.manual.eq_level); /* Enable AEQ Bypass */ ub960_rxport_update_bits(priv, nport, UB960_RR_AEQ_BYPASS, UB960_RR_AEQ_BYPASS_ENABLE, UB960_RR_AEQ_BYPASS_ENABLE); } else { ub960_rxport_set_eq_range(priv, nport, rxport->eq.aeq.eq_level_min, rxport->eq.aeq.eq_level_max); /* Disable AEQ Bypass */ ub960_rxport_update_bits(priv, nport, UB960_RR_AEQ_BYPASS, UB960_RR_AEQ_BYPASS_ENABLE, 0); } } static int ub960_rxport_link_ok(struct ub960_data *priv, unsigned int nport, bool *ok) { u8 rx_port_sts1, rx_port_sts2; u16 parity_errors; u8 csi_rx_sts; u8 csi_err_cnt; u8 bcc_sts; int ret; bool errors; ret = ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, &rx_port_sts1); if (ret) return ret; if (!(rx_port_sts1 & UB960_RR_RX_PORT_STS1_LOCK_STS)) { *ok = false; return 0; } ret = ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2, &rx_port_sts2); if (ret) return ret; ret = ub960_rxport_read(priv, nport, UB960_RR_CSI_RX_STS, &csi_rx_sts); if (ret) return ret; ret = ub960_rxport_read(priv, nport, UB960_RR_CSI_ERR_COUNTER, &csi_err_cnt); if (ret) return ret; ret = ub960_rxport_read(priv, nport, UB960_RR_BCC_STATUS, &bcc_sts); if (ret) return ret; ret = ub960_rxport_read16(priv, nport, UB960_RR_RX_PAR_ERR_HI, &parity_errors); if (ret) return ret; errors = (rx_port_sts1 & UB960_RR_RX_PORT_STS1_ERROR_MASK) || (rx_port_sts2 & UB960_RR_RX_PORT_STS2_ERROR_MASK) || (bcc_sts & UB960_RR_BCC_STATUS_ERROR_MASK) || (csi_rx_sts & UB960_RR_CSI_RX_STS_ERROR_MASK) || csi_err_cnt || parity_errors; *ok = !errors; return 0; } /* * Wait for the RX ports to lock, have no errors and have stable strobe position * and EQ level. */ static int ub960_rxport_wait_locks(struct ub960_data *priv, unsigned long port_mask, unsigned int *lock_mask) { struct device *dev = &priv->client->dev; unsigned long timeout; unsigned int link_ok_mask; unsigned int missing; unsigned int loops; u8 nport; int ret; if (port_mask == 0) { if (lock_mask) *lock_mask = 0; return 0; } if (port_mask >= BIT(priv->hw_data->num_rxports)) return -EINVAL; timeout = jiffies + msecs_to_jiffies(1000); loops = 0; link_ok_mask = 0; while (time_before(jiffies, timeout)) { missing = 0; for_each_set_bit(nport, &port_mask, priv->hw_data->num_rxports) { struct ub960_rxport *rxport = priv->rxports[nport]; bool ok; if (!rxport) continue; ret = ub960_rxport_link_ok(priv, nport, &ok); if (ret) return ret; /* * We want the link to be ok for two consecutive loops, * as a link could get established just before our test * and drop soon after. */ if (!ok || !(link_ok_mask & BIT(nport))) missing++; if (ok) link_ok_mask |= BIT(nport); else link_ok_mask &= ~BIT(nport); } loops++; if (missing == 0) break; msleep(50); } if (lock_mask) *lock_mask = link_ok_mask; dev_dbg(dev, "Wait locks done in %u loops\n", loops); for_each_set_bit(nport, &port_mask, priv->hw_data->num_rxports) { struct ub960_rxport *rxport = priv->rxports[nport]; s8 strobe_pos, eq_level; u16 v; if (!rxport) continue; if (!(link_ok_mask & BIT(nport))) { dev_dbg(dev, "\trx%u: not locked\n", nport); continue; } ub960_rxport_read16(priv, nport, UB960_RR_RX_FREQ_HIGH, &v); ret = ub960_rxport_get_strobe_pos(priv, nport, &strobe_pos); if (ret) return ret; ret = ub960_rxport_get_eq_level(priv, nport, &eq_level); if (ret) return ret; dev_dbg(dev, "\trx%u: locked, SP: %d, EQ: %u, freq %llu Hz\n", nport, strobe_pos, eq_level, (v * 1000000ULL) >> 8); } return 0; } static unsigned long ub960_calc_bc_clk_rate_ub960(struct ub960_data *priv, struct ub960_rxport *rxport) { unsigned int mult; unsigned int div; switch (rxport->rx_mode) { case RXPORT_MODE_RAW10: case RXPORT_MODE_RAW12_HF: case RXPORT_MODE_RAW12_LF: mult = 1; div = 10; break; case RXPORT_MODE_CSI2_SYNC: mult = 2; div = 1; break; case RXPORT_MODE_CSI2_NONSYNC: mult = 2; div = 5; break; default: return 0; } return clk_get_rate(priv->refclk) * mult / div; } static unsigned long ub960_calc_bc_clk_rate_ub9702(struct ub960_data *priv, struct ub960_rxport *rxport) { switch (rxport->rx_mode) { case RXPORT_MODE_RAW10: case RXPORT_MODE_RAW12_HF: case RXPORT_MODE_RAW12_LF: return 2359400; case RXPORT_MODE_CSI2_SYNC: return 47187500; case RXPORT_MODE_CSI2_NONSYNC: return 9437500; default: return 0; } } static int ub960_rxport_add_serializer(struct ub960_data *priv, u8 nport) { struct ub960_rxport *rxport = priv->rxports[nport]; struct device *dev = &priv->client->dev; struct ds90ub9xx_platform_data *ser_pdata = &rxport->ser.pdata; struct i2c_board_info ser_info = { .of_node = to_of_node(rxport->ser.fwnode), .fwnode = rxport->ser.fwnode, .platform_data = ser_pdata, }; ser_pdata->port = nport; ser_pdata->atr = priv->atr; if (priv->hw_data->is_ub9702) ser_pdata->bc_rate = ub960_calc_bc_clk_rate_ub9702(priv, rxport); else ser_pdata->bc_rate = ub960_calc_bc_clk_rate_ub960(priv, rxport); /* * The serializer is added under the same i2c adapter as the * deserializer. This is not quite right, as the serializer is behind * the FPD-Link. */ ser_info.addr = rxport->ser.alias; rxport->ser.client = i2c_new_client_device(priv->client->adapter, &ser_info); if (IS_ERR(rxport->ser.client)) { dev_err(dev, "rx%u: cannot add %s i2c device", nport, ser_info.type); return PTR_ERR(rxport->ser.client); } dev_dbg(dev, "rx%u: remote serializer at alias 0x%02x (%u-%04x)\n", nport, rxport->ser.client->addr, rxport->ser.client->adapter->nr, rxport->ser.client->addr); return 0; } static void ub960_rxport_remove_serializer(struct ub960_data *priv, u8 nport) { struct ub960_rxport *rxport = priv->rxports[nport]; i2c_unregister_device(rxport->ser.client); rxport->ser.client = NULL; } /* Add serializer i2c devices for all initialized ports */ static int ub960_rxport_add_serializers(struct ub960_data *priv) { unsigned int nport; int ret; for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { struct ub960_rxport *rxport = priv->rxports[nport]; if (!rxport) continue; ret = ub960_rxport_add_serializer(priv, nport); if (ret) goto err_remove_sers; } return 0; err_remove_sers: while (nport--) { struct ub960_rxport *rxport = priv->rxports[nport]; if (!rxport) continue; ub960_rxport_remove_serializer(priv, nport); } return ret; } static void ub960_rxport_remove_serializers(struct ub960_data *priv) { unsigned int nport; for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { struct ub960_rxport *rxport = priv->rxports[nport]; if (!rxport) continue; ub960_rxport_remove_serializer(priv, nport); } } static void ub960_init_tx_port(struct ub960_data *priv, struct ub960_txport *txport) { unsigned int nport = txport->nport; u8 csi_ctl = 0; /* * From the datasheet: "initial CSI Skew-Calibration * sequence [...] should be set when operating at 1.6 Gbps" */ if (priv->tx_data_rate == MHZ(1600)) csi_ctl |= UB960_TR_CSI_CTL_CSI_CAL_EN; csi_ctl |= (4 - txport->num_data_lanes) << 4; if (!txport->non_continous_clk) csi_ctl |= UB960_TR_CSI_CTL_CSI_CONTS_CLOCK; ub960_txport_write(priv, nport, UB960_TR_CSI_CTL, csi_ctl); } static int ub960_init_tx_ports(struct ub960_data *priv) { unsigned int nport; u8 speed_select; u8 pll_div; /* TX ports */ switch (priv->tx_data_rate) { case MHZ(1600): default: speed_select = 0; pll_div = 0x10; break; case MHZ(1200): speed_select = 1; pll_div = 0x18; break; case MHZ(800): speed_select = 2; pll_div = 0x10; break; case MHZ(400): speed_select = 3; pll_div = 0x10; break; } ub960_write(priv, UB960_SR_CSI_PLL_CTL, speed_select); if (priv->hw_data->is_ub9702) { ub960_write(priv, UB960_SR_CSI_PLL_DIV, pll_div); switch (priv->tx_data_rate) { case MHZ(1600): default: ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, 0x80); ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4b, 0x2a); break; case MHZ(800): ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, 0x90); ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4f, 0x2a); ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x4b, 0x2a); break; case MHZ(400): ub960_write_ind(priv, UB960_IND_TARGET_CSI_ANA, 0x92, 0xa0); break; } } for (nport = 0; nport < priv->hw_data->num_txports; nport++) { struct ub960_txport *txport = priv->txports[nport]; if (!txport) continue; ub960_init_tx_port(priv, txport); } return 0; } static void ub960_init_rx_port_ub960(struct ub960_data *priv, struct ub960_rxport *rxport) { unsigned int nport = rxport->nport; u32 bc_freq_val; /* * Back channel frequency select. * Override FREQ_SELECT from the strap. * 0 - 2.5 Mbps (DS90UB913A-Q1 / DS90UB933-Q1) * 2 - 10 Mbps * 6 - 50 Mbps (DS90UB953-Q1) * * Note that changing this setting will result in some errors on the back * channel for a short period of time. */ switch (rxport->rx_mode) { case RXPORT_MODE_RAW10: case RXPORT_MODE_RAW12_HF: case RXPORT_MODE_RAW12_LF: bc_freq_val = 0; break; case RXPORT_MODE_CSI2_NONSYNC: bc_freq_val = 2; break; case RXPORT_MODE_CSI2_SYNC: bc_freq_val = 6; break; default: return; } ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, UB960_RR_BCC_CONFIG_BC_FREQ_SEL_MASK, bc_freq_val); switch (rxport->rx_mode) { case RXPORT_MODE_RAW10: /* FPD3_MODE = RAW10 Mode (DS90UB913A-Q1 / DS90UB933-Q1 compatible) */ ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG, UB960_RR_PORT_CONFIG_FPD3_MODE_MASK, 0x3); /* * RAW10_8BIT_CTL = 0b10 : 8-bit processing using upper 8 bits */ ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2, UB960_RR_PORT_CONFIG2_RAW10_8BIT_CTL_MASK, 0x2 << UB960_RR_PORT_CONFIG2_RAW10_8BIT_CTL_SHIFT); break; case RXPORT_MODE_RAW12_HF: case RXPORT_MODE_RAW12_LF: /* Not implemented */ return; case RXPORT_MODE_CSI2_SYNC: case RXPORT_MODE_CSI2_NONSYNC: /* CSI-2 Mode (DS90UB953-Q1 compatible) */ ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG, 0x3, 0x0); break; } /* LV_POLARITY & FV_POLARITY */ ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2, 0x3, rxport->lv_fv_pol); /* Enable all interrupt sources from this port */ ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_HI, 0x07); ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_LO, 0x7f); /* Enable I2C_PASS_THROUGH */ ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH); /* Enable I2C communication to the serializer via the alias addr */ ub960_rxport_write(priv, nport, UB960_RR_SER_ALIAS_ID, rxport->ser.alias << 1); /* Configure EQ related settings */ ub960_rxport_config_eq(priv, nport); /* Enable RX port */ ub960_update_bits(priv, UB960_SR_RX_PORT_CTL, BIT(nport), BIT(nport)); } static void ub960_init_rx_port_ub9702_fpd3(struct ub960_data *priv, struct ub960_rxport *rxport) { unsigned int nport = rxport->nport; u8 bc_freq_val; u8 fpd_func_mode; switch (rxport->rx_mode) { case RXPORT_MODE_RAW10: bc_freq_val = 0; fpd_func_mode = 5; break; case RXPORT_MODE_RAW12_HF: bc_freq_val = 0; fpd_func_mode = 4; break; case RXPORT_MODE_RAW12_LF: bc_freq_val = 0; fpd_func_mode = 6; break; case RXPORT_MODE_CSI2_SYNC: bc_freq_val = 6; fpd_func_mode = 2; break; case RXPORT_MODE_CSI2_NONSYNC: bc_freq_val = 2; fpd_func_mode = 2; break; default: return; } ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, 0x7, bc_freq_val); ub960_rxport_write(priv, nport, UB960_RR_CHANNEL_MODE, fpd_func_mode); /* set serdes_eq_mode = 1 */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xa8, 0x80); /* enable serdes driver */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x0d, 0x7f); /* set serdes_eq_offset=4 */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2b, 0x04); /* init default serdes_eq_max in 0xa9 */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xa9, 0x23); /* init serdes_eq_min in 0xaa */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xaa, 0); /* serdes_driver_ctl2 control: DS90UB953-Q1/DS90UB933-Q1/DS90UB913A-Q1 */ ub960_ind_update_bits(priv, UB960_IND_TARGET_RX_ANA(nport), 0x1b, BIT(3), BIT(3)); /* RX port to half-rate */ ub960_update_bits(priv, UB960_SR_FPD_RATE_CFG, 0x3 << (nport * 2), BIT(nport * 2)); } static void ub960_init_rx_port_ub9702_fpd4_aeq(struct ub960_data *priv, struct ub960_rxport *rxport) { unsigned int nport = rxport->nport; bool first_time_power_up = true; if (first_time_power_up) { u8 v; /* AEQ init */ ub960_read_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2c, &v); ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x27, v); ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x28, v + 1); ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2b, 0x00); } /* enable serdes_eq_ctl2 */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x9e, 0x00); /* enable serdes_eq_ctl1 */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x90, 0x40); /* enable serdes_eq_en */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2e, 0x40); /* disable serdes_eq_override */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0xf0, 0x00); /* disable serdes_gain_override */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x71, 0x00); } static void ub960_init_rx_port_ub9702_fpd4(struct ub960_data *priv, struct ub960_rxport *rxport) { unsigned int nport = rxport->nport; u8 bc_freq_val; switch (rxport->rx_mode) { case RXPORT_MODE_RAW10: bc_freq_val = 0; break; case RXPORT_MODE_RAW12_HF: bc_freq_val = 0; break; case RXPORT_MODE_RAW12_LF: bc_freq_val = 0; break; case RXPORT_MODE_CSI2_SYNC: bc_freq_val = 6; break; case RXPORT_MODE_CSI2_NONSYNC: bc_freq_val = 2; break; default: return; } ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, 0x7, bc_freq_val); /* FPD4 Sync Mode */ ub960_rxport_write(priv, nport, UB960_RR_CHANNEL_MODE, 0); /* add serdes_eq_offset of 4 */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x2b, 0x04); /* FPD4 serdes_start_eq in 0x27: assign default */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x27, 0x0); /* FPD4 serdes_end_eq in 0x28: assign default */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x28, 0x23); /* set serdes_driver_mode into FPD IV mode */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x04, 0x00); /* set FPD PBC drv into FPD IV mode */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x1b, 0x00); /* set serdes_system_init to 0x2f */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x21, 0x2f); /* set serdes_system_rst in reset mode */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x25, 0xc1); /* RX port to 7.55G mode */ ub960_update_bits(priv, UB960_SR_FPD_RATE_CFG, 0x3 << (nport * 2), 0 << (nport * 2)); ub960_init_rx_port_ub9702_fpd4_aeq(priv, rxport); } static void ub960_init_rx_port_ub9702(struct ub960_data *priv, struct ub960_rxport *rxport) { unsigned int nport = rxport->nport; if (rxport->cdr_mode == RXPORT_CDR_FPD3) ub960_init_rx_port_ub9702_fpd3(priv, rxport); else /* RXPORT_CDR_FPD4 */ ub960_init_rx_port_ub9702_fpd4(priv, rxport); switch (rxport->rx_mode) { case RXPORT_MODE_RAW10: /* * RAW10_8BIT_CTL = 0b11 : 8-bit processing using lower 8 bits * 0b10 : 8-bit processing using upper 8 bits */ ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2, 0x3 << 6, 0x2 << 6); break; case RXPORT_MODE_RAW12_HF: case RXPORT_MODE_RAW12_LF: /* Not implemented */ return; case RXPORT_MODE_CSI2_SYNC: case RXPORT_MODE_CSI2_NONSYNC: break; } /* LV_POLARITY & FV_POLARITY */ ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2, 0x3, rxport->lv_fv_pol); /* Enable all interrupt sources from this port */ ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_HI, 0x07); ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_LO, 0x7f); /* Enable I2C_PASS_THROUGH */ ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH, UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH); /* Enable I2C communication to the serializer via the alias addr */ ub960_rxport_write(priv, nport, UB960_RR_SER_ALIAS_ID, rxport->ser.alias << 1); /* Enable RX port */ ub960_update_bits(priv, UB960_SR_RX_PORT_CTL, BIT(nport), BIT(nport)); if (rxport->cdr_mode == RXPORT_CDR_FPD4) { /* unreset 960 AEQ */ ub960_write_ind(priv, UB960_IND_TARGET_RX_ANA(nport), 0x25, 0x41); } } static int ub960_init_rx_ports(struct ub960_data *priv) { unsigned int nport; for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { struct ub960_rxport *rxport = priv->rxports[nport]; if (!rxport) continue; if (priv->hw_data->is_ub9702) ub960_init_rx_port_ub9702(priv, rxport); else ub960_init_rx_port_ub960(priv, rxport); } return 0; } static void ub960_rxport_handle_events(struct ub960_data *priv, u8 nport) { struct device *dev = &priv->client->dev; u8 rx_port_sts1; u8 rx_port_sts2; u8 csi_rx_sts; u8 bcc_sts; int ret = 0; /* Read interrupts (also clears most of them) */ if (!ret) ret = ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, &rx_port_sts1); if (!ret) ret = ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2, &rx_port_sts2); if (!ret) ret = ub960_rxport_read(priv, nport, UB960_RR_CSI_RX_STS, &csi_rx_sts); if (!ret) ret = ub960_rxport_read(priv, nport, UB960_RR_BCC_STATUS, &bcc_sts); if (ret) return; if (rx_port_sts1 & UB960_RR_RX_PORT_STS1_PARITY_ERROR) { u16 v; ret = ub960_rxport_read16(priv, nport, UB960_RR_RX_PAR_ERR_HI, &v); if (!ret) dev_err(dev, "rx%u parity errors: %u\n", nport, v); } if (rx_port_sts1 & UB960_RR_RX_PORT_STS1_BCC_CRC_ERROR) dev_err(dev, "rx%u BCC CRC error\n", nport); if (rx_port_sts1 & UB960_RR_RX_PORT_STS1_BCC_SEQ_ERROR) dev_err(dev, "rx%u BCC SEQ error\n", nport); if (rx_port_sts2 & UB960_RR_RX_PORT_STS2_LINE_LEN_UNSTABLE) dev_err(dev, "rx%u line length unstable\n", nport); if (rx_port_sts2 & UB960_RR_RX_PORT_STS2_FPD3_ENCODE_ERROR) dev_err(dev, "rx%u FPD3 encode error\n", nport); if (rx_port_sts2 & UB960_RR_RX_PORT_STS2_BUFFER_ERROR) dev_err(dev, "rx%u buffer error\n", nport); if (csi_rx_sts) dev_err(dev, "rx%u CSI error: %#02x\n", nport, csi_rx_sts); if (csi_rx_sts & UB960_RR_CSI_RX_STS_ECC1_ERR) dev_err(dev, "rx%u CSI ECC1 error\n", nport); if (csi_rx_sts & UB960_RR_CSI_RX_STS_ECC2_ERR) dev_err(dev, "rx%u CSI ECC2 error\n", nport); if (csi_rx_sts & UB960_RR_CSI_RX_STS_CKSUM_ERR) dev_err(dev, "rx%u CSI checksum error\n", nport); if (csi_rx_sts & UB960_RR_CSI_RX_STS_LENGTH_ERR) dev_err(dev, "rx%u CSI length error\n", nport); if (bcc_sts) dev_err(dev, "rx%u BCC error: %#02x\n", nport, bcc_sts); if (bcc_sts & UB960_RR_BCC_STATUS_RESP_ERR) dev_err(dev, "rx%u BCC response error", nport); if (bcc_sts & UB960_RR_BCC_STATUS_SLAVE_TO) dev_err(dev, "rx%u BCC slave timeout", nport); if (bcc_sts & UB960_RR_BCC_STATUS_SLAVE_ERR) dev_err(dev, "rx%u BCC slave error", nport); if (bcc_sts & UB960_RR_BCC_STATUS_MASTER_TO) dev_err(dev, "rx%u BCC master timeout", nport); if (bcc_sts & UB960_RR_BCC_STATUS_MASTER_ERR) dev_err(dev, "rx%u BCC master error", nport); if (bcc_sts & UB960_RR_BCC_STATUS_SEQ_ERROR) dev_err(dev, "rx%u BCC sequence error", nport); if (rx_port_sts2 & UB960_RR_RX_PORT_STS2_LINE_LEN_CHG) { u16 v; ret = ub960_rxport_read16(priv, nport, UB960_RR_LINE_LEN_1, &v); if (!ret) dev_dbg(dev, "rx%u line len changed: %u\n", nport, v); } if (rx_port_sts2 & UB960_RR_RX_PORT_STS2_LINE_CNT_CHG) { u16 v; ret = ub960_rxport_read16(priv, nport, UB960_RR_LINE_COUNT_HI, &v); if (!ret) dev_dbg(dev, "rx%u line count changed: %u\n", nport, v); } if (rx_port_sts1 & UB960_RR_RX_PORT_STS1_LOCK_STS_CHG) { dev_dbg(dev, "rx%u: %s, %s, %s, %s\n", nport, (rx_port_sts1 & UB960_RR_RX_PORT_STS1_LOCK_STS) ? "locked" : "unlocked", (rx_port_sts1 & UB960_RR_RX_PORT_STS1_PORT_PASS) ? "passed" : "not passed", (rx_port_sts2 & UB960_RR_RX_PORT_STS2_CABLE_FAULT) ? "no clock" : "clock ok", (rx_port_sts2 & UB960_RR_RX_PORT_STS2_FREQ_STABLE) ? "stable freq" : "unstable freq"); } } /* ----------------------------------------------------------------------------- * V4L2 */ /* * The current implementation only supports a simple VC mapping, where all VCs * from a one RX port will be mapped to the same VC. Also, the hardware * dictates that all streams from an RX port must go to a single TX port. * * This function decides the target VC numbers for each RX port with a simple * algorithm, so that for each TX port, we get VC numbers starting from 0, * and counting up. * * E.g. if all four RX ports are in use, of which the first two go to the * first TX port and the secont two go to the second TX port, we would get * the following VCs for the four RX ports: 0, 1, 0, 1. * * TODO: implement a more sophisticated VC mapping. As the driver cannot know * what VCs the sinks expect (say, an FPGA with hardcoded VC routing), this * probably needs to be somehow configurable. Device tree? */ static void ub960_get_vc_maps(struct ub960_data *priv, struct v4l2_subdev_state *state, u8 *vc) { u8 cur_vc[UB960_MAX_TX_NPORTS] = {}; struct v4l2_subdev_route *route; u8 handled_mask = 0; for_each_active_route(&state->routing, route) { unsigned int rx, tx; rx = ub960_pad_to_port(priv, route->sink_pad); if (BIT(rx) & handled_mask) continue; tx = ub960_pad_to_port(priv, route->source_pad); vc[rx] = cur_vc[tx]++; handled_mask |= BIT(rx); } } static int ub960_enable_tx_port(struct ub960_data *priv, unsigned int nport) { struct device *dev = &priv->client->dev; dev_dbg(dev, "enable TX port %u\n", nport); return ub960_txport_update_bits(priv, nport, UB960_TR_CSI_CTL, UB960_TR_CSI_CTL_CSI_ENABLE, UB960_TR_CSI_CTL_CSI_ENABLE); } static void ub960_disable_tx_port(struct ub960_data *priv, unsigned int nport) { struct device *dev = &priv->client->dev; dev_dbg(dev, "disable TX port %u\n", nport); ub960_txport_update_bits(priv, nport, UB960_TR_CSI_CTL, UB960_TR_CSI_CTL_CSI_ENABLE, 0); } static int ub960_enable_rx_port(struct ub960_data *priv, unsigned int nport) { struct device *dev = &priv->client->dev; dev_dbg(dev, "enable RX port %u\n", nport); /* Enable forwarding */ return ub960_update_bits(priv, UB960_SR_FWD_CTL1, UB960_SR_FWD_CTL1_PORT_DIS(nport), 0); } static void ub960_disable_rx_port(struct ub960_data *priv, unsigned int nport) { struct device *dev = &priv->client->dev; dev_dbg(dev, "disable RX port %u\n", nport); /* Disable forwarding */ ub960_update_bits(priv, UB960_SR_FWD_CTL1, UB960_SR_FWD_CTL1_PORT_DIS(nport), UB960_SR_FWD_CTL1_PORT_DIS(nport)); } /* * The driver only supports using a single VC for each source. This function * checks that each source only provides streams using a single VC. */ static int ub960_validate_stream_vcs(struct ub960_data *priv) { unsigned int nport; unsigned int i; for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { struct ub960_rxport *rxport = priv->rxports[nport]; struct v4l2_mbus_frame_desc desc; int ret; u8 vc; if (!rxport) continue; ret = v4l2_subdev_call(rxport->source.sd, pad, get_frame_desc, rxport->source.pad, &desc); if (ret) return ret; if (desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) continue; if (desc.num_entries == 0) continue; vc = desc.entry[0].bus.csi2.vc; for (i = 1; i < desc.num_entries; i++) { if (vc == desc.entry[i].bus.csi2.vc) continue; dev_err(&priv->client->dev, "rx%u: source with multiple virtual-channels is not supported\n", nport); return -ENODEV; } } return 0; } static int ub960_configure_ports_for_streaming(struct ub960_data *priv, struct v4l2_subdev_state *state) { u8 fwd_ctl; struct { u32 num_streams; u8 pixel_dt; u8 meta_dt; u32 meta_lines; u32 tx_port; } rx_data[UB960_MAX_RX_NPORTS] = {}; u8 vc_map[UB960_MAX_RX_NPORTS] = {}; struct v4l2_subdev_route *route; unsigned int nport; int ret; ret = ub960_validate_stream_vcs(priv); if (ret) return ret; ub960_get_vc_maps(priv, state, vc_map); for_each_active_route(&state->routing, route) { struct ub960_rxport *rxport; struct ub960_txport *txport; struct v4l2_mbus_framefmt *fmt; const struct ub960_format_info *ub960_fmt; unsigned int nport; nport = ub960_pad_to_port(priv, route->sink_pad); rxport = priv->rxports[nport]; if (!rxport) return -EINVAL; txport = priv->txports[ub960_pad_to_port(priv, route->source_pad)]; if (!txport) return -EINVAL; rx_data[nport].tx_port = ub960_pad_to_port(priv, route->source_pad); rx_data[nport].num_streams++; /* For the rest, we are only interested in parallel busses */ if (rxport->rx_mode == RXPORT_MODE_CSI2_SYNC || rxport->rx_mode == RXPORT_MODE_CSI2_NONSYNC) continue; if (rx_data[nport].num_streams > 2) return -EPIPE; fmt = v4l2_subdev_state_get_format(state, route->sink_pad, route->sink_stream); if (!fmt) return -EPIPE; ub960_fmt = ub960_find_format(fmt->code); if (!ub960_fmt) return -EPIPE; if (ub960_fmt->meta) { if (fmt->height > 3) { dev_err(&priv->client->dev, "rx%u: unsupported metadata height %u\n", nport, fmt->height); return -EPIPE; } rx_data[nport].meta_dt = ub960_fmt->datatype; rx_data[nport].meta_lines = fmt->height; } else { rx_data[nport].pixel_dt = ub960_fmt->datatype; } } /* Configure RX ports */ /* * Keep all port forwardings disabled by default. Forwarding will be * enabled in ub960_enable_rx_port. */ fwd_ctl = GENMASK(7, 4); for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { struct ub960_rxport *rxport = priv->rxports[nport]; u8 vc = vc_map[nport]; if (rx_data[nport].num_streams == 0) continue; switch (rxport->rx_mode) { case RXPORT_MODE_RAW10: ub960_rxport_write(priv, nport, UB960_RR_RAW10_ID, rx_data[nport].pixel_dt | (vc << UB960_RR_RAW10_ID_VC_SHIFT)); ub960_rxport_write(priv, rxport->nport, UB960_RR_RAW_EMBED_DTYPE, (rx_data[nport].meta_lines << UB960_RR_RAW_EMBED_DTYPE_LINES_SHIFT) | rx_data[nport].meta_dt); break; case RXPORT_MODE_RAW12_HF: case RXPORT_MODE_RAW12_LF: /* Not implemented */ break; case RXPORT_MODE_CSI2_SYNC: case RXPORT_MODE_CSI2_NONSYNC: if (!priv->hw_data->is_ub9702) { /* Map all VCs from this port to the same VC */ ub960_rxport_write(priv, nport, UB960_RR_CSI_VC_MAP, (vc << UB960_RR_CSI_VC_MAP_SHIFT(3)) | (vc << UB960_RR_CSI_VC_MAP_SHIFT(2)) | (vc << UB960_RR_CSI_VC_MAP_SHIFT(1)) | (vc << UB960_RR_CSI_VC_MAP_SHIFT(0))); } else { unsigned int i; /* Map all VCs from this port to VC(nport) */ for (i = 0; i < 8; i++) ub960_rxport_write(priv, nport, UB960_RR_VC_ID_MAP(i), nport); } break; } if (rx_data[nport].tx_port == 1) fwd_ctl |= BIT(nport); /* forward to TX1 */ else fwd_ctl &= ~BIT(nport); /* forward to TX0 */ } ub960_write(priv, UB960_SR_FWD_CTL1, fwd_ctl); return 0; } static void ub960_update_streaming_status(struct ub960_data *priv) { unsigned int i; for (i = 0; i < UB960_MAX_NPORTS; i++) { if (priv->stream_enable_mask[i]) break; } priv->streaming = i < UB960_MAX_NPORTS; } static int ub960_enable_streams(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, u32 source_pad, u64 source_streams_mask) { struct ub960_data *priv = sd_to_ub960(sd); struct device *dev = &priv->client->dev; u64 sink_streams[UB960_MAX_RX_NPORTS] = {}; struct v4l2_subdev_route *route; unsigned int failed_port; unsigned int nport; int ret; if (!priv->streaming) { dev_dbg(dev, "Prepare for streaming\n"); ret = ub960_configure_ports_for_streaming(priv, state); if (ret) return ret; } /* Enable TX port if not yet enabled */ if (!priv->stream_enable_mask[source_pad]) { ret = ub960_enable_tx_port(priv, ub960_pad_to_port(priv, source_pad)); if (ret) return ret; } priv->stream_enable_mask[source_pad] |= source_streams_mask; /* Collect sink streams per pad which we need to enable */ for_each_active_route(&state->routing, route) { if (route->source_pad != source_pad) continue; if (!(source_streams_mask & BIT_ULL(route->source_stream))) continue; nport = ub960_pad_to_port(priv, route->sink_pad); sink_streams[nport] |= BIT_ULL(route->sink_stream); } for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { if (!sink_streams[nport]) continue; /* Enable the RX port if not yet enabled */ if (!priv->stream_enable_mask[nport]) { ret = ub960_enable_rx_port(priv, nport); if (ret) { failed_port = nport; goto err; } } priv->stream_enable_mask[nport] |= sink_streams[nport]; dev_dbg(dev, "enable RX port %u streams %#llx\n", nport, sink_streams[nport]); ret = v4l2_subdev_enable_streams( priv->rxports[nport]->source.sd, priv->rxports[nport]->source.pad, sink_streams[nport]); if (ret) { priv->stream_enable_mask[nport] &= ~sink_streams[nport]; if (!priv->stream_enable_mask[nport]) ub960_disable_rx_port(priv, nport); failed_port = nport; goto err; } } priv->streaming = true; return 0; err: for (nport = 0; nport < failed_port; nport++) { if (!sink_streams[nport]) continue; dev_dbg(dev, "disable RX port %u streams %#llx\n", nport, sink_streams[nport]); ret = v4l2_subdev_disable_streams( priv->rxports[nport]->source.sd, priv->rxports[nport]->source.pad, sink_streams[nport]); if (ret) dev_err(dev, "Failed to disable streams: %d\n", ret); priv->stream_enable_mask[nport] &= ~sink_streams[nport]; /* Disable RX port if no active streams */ if (!priv->stream_enable_mask[nport]) ub960_disable_rx_port(priv, nport); } priv->stream_enable_mask[source_pad] &= ~source_streams_mask; if (!priv->stream_enable_mask[source_pad]) ub960_disable_tx_port(priv, ub960_pad_to_port(priv, source_pad)); ub960_update_streaming_status(priv); return ret; } static int ub960_disable_streams(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, u32 source_pad, u64 source_streams_mask) { struct ub960_data *priv = sd_to_ub960(sd); struct device *dev = &priv->client->dev; u64 sink_streams[UB960_MAX_RX_NPORTS] = {}; struct v4l2_subdev_route *route; unsigned int nport; int ret; /* Collect sink streams per pad which we need to disable */ for_each_active_route(&state->routing, route) { if (route->source_pad != source_pad) continue; if (!(source_streams_mask & BIT_ULL(route->source_stream))) continue; nport = ub960_pad_to_port(priv, route->sink_pad); sink_streams[nport] |= BIT_ULL(route->sink_stream); } for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { if (!sink_streams[nport]) continue; dev_dbg(dev, "disable RX port %u streams %#llx\n", nport, sink_streams[nport]); ret = v4l2_subdev_disable_streams( priv->rxports[nport]->source.sd, priv->rxports[nport]->source.pad, sink_streams[nport]); if (ret) dev_err(dev, "Failed to disable streams: %d\n", ret); priv->stream_enable_mask[nport] &= ~sink_streams[nport]; /* Disable RX port if no active streams */ if (!priv->stream_enable_mask[nport]) ub960_disable_rx_port(priv, nport); } /* Disable TX port if no active streams */ priv->stream_enable_mask[source_pad] &= ~source_streams_mask; if (!priv->stream_enable_mask[source_pad]) ub960_disable_tx_port(priv, ub960_pad_to_port(priv, source_pad)); ub960_update_streaming_status(priv); return 0; } static int _ub960_set_routing(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, struct v4l2_subdev_krouting *routing) { static const struct v4l2_mbus_framefmt format = { .width = 640, .height = 480, .code = MEDIA_BUS_FMT_UYVY8_1X16, .field = V4L2_FIELD_NONE, .colorspace = V4L2_COLORSPACE_SRGB, .ycbcr_enc = V4L2_YCBCR_ENC_601, .quantization = V4L2_QUANTIZATION_LIM_RANGE, .xfer_func = V4L2_XFER_FUNC_SRGB, }; int ret; /* * Note: we can only support up to V4L2_FRAME_DESC_ENTRY_MAX, until * frame desc is made dynamically allocated. */ if (routing->num_routes > V4L2_FRAME_DESC_ENTRY_MAX) return -E2BIG; ret = v4l2_subdev_routing_validate(sd, routing, V4L2_SUBDEV_ROUTING_ONLY_1_TO_1 | V4L2_SUBDEV_ROUTING_NO_SINK_STREAM_MIX); if (ret) return ret; ret = v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format); if (ret) return ret; return 0; } static int ub960_set_routing(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, enum v4l2_subdev_format_whence which, struct v4l2_subdev_krouting *routing) { struct ub960_data *priv = sd_to_ub960(sd); if (which == V4L2_SUBDEV_FORMAT_ACTIVE && priv->streaming) return -EBUSY; return _ub960_set_routing(sd, state, routing); } static int ub960_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_mbus_frame_desc *fd) { struct ub960_data *priv = sd_to_ub960(sd); struct v4l2_subdev_route *route; struct v4l2_subdev_state *state; int ret = 0; struct device *dev = &priv->client->dev; u8 vc_map[UB960_MAX_RX_NPORTS] = {}; if (!ub960_pad_is_source(priv, pad)) return -EINVAL; fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2; state = v4l2_subdev_lock_and_get_active_state(&priv->sd); ub960_get_vc_maps(priv, state, vc_map); for_each_active_route(&state->routing, route) { struct v4l2_mbus_frame_desc_entry *source_entry = NULL; struct v4l2_mbus_frame_desc source_fd; unsigned int nport; unsigned int i; if (route->source_pad != pad) continue; nport = ub960_pad_to_port(priv, route->sink_pad); ret = v4l2_subdev_call(priv->rxports[nport]->source.sd, pad, get_frame_desc, priv->rxports[nport]->source.pad, &source_fd); if (ret) { dev_err(dev, "Failed to get source frame desc for pad %u\n", route->sink_pad); goto out_unlock; } for (i = 0; i < source_fd.num_entries; i++) { if (source_fd.entry[i].stream == route->sink_stream) { source_entry = &source_fd.entry[i]; break; } } if (!source_entry) { dev_err(dev, "Failed to find stream from source frame desc\n"); ret = -EPIPE; goto out_unlock; } fd->entry[fd->num_entries].stream = route->source_stream; fd->entry[fd->num_entries].flags = source_entry->flags; fd->entry[fd->num_entries].length = source_entry->length; fd->entry[fd->num_entries].pixelcode = source_entry->pixelcode; fd->entry[fd->num_entries].bus.csi2.vc = vc_map[nport]; if (source_fd.type == V4L2_MBUS_FRAME_DESC_TYPE_CSI2) { fd->entry[fd->num_entries].bus.csi2.dt = source_entry->bus.csi2.dt; } else { const struct ub960_format_info *ub960_fmt; struct v4l2_mbus_framefmt *fmt; fmt = v4l2_subdev_state_get_format(state, pad, route->source_stream); if (!fmt) { ret = -EINVAL; goto out_unlock; } ub960_fmt = ub960_find_format(fmt->code); if (!ub960_fmt) { dev_err(dev, "Unable to find format\n"); ret = -EINVAL; goto out_unlock; } fd->entry[fd->num_entries].bus.csi2.dt = ub960_fmt->datatype; } fd->num_entries++; } out_unlock: v4l2_subdev_unlock_state(state); return ret; } static int ub960_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, struct v4l2_subdev_format *format) { struct ub960_data *priv = sd_to_ub960(sd); struct v4l2_mbus_framefmt *fmt; if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE && priv->streaming) return -EBUSY; /* No transcoding, source and sink formats must match. */ if (ub960_pad_is_source(priv, format->pad)) return v4l2_subdev_get_fmt(sd, state, format); /* * Default to the first format if the requested media bus code isn't * supported. */ if (!ub960_find_format(format->format.code)) format->format.code = ub960_formats[0].code; fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream); if (!fmt) return -EINVAL; *fmt = format->format; fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad, format->stream); if (!fmt) return -EINVAL; *fmt = format->format; return 0; } static int ub960_init_state(struct v4l2_subdev *sd, struct v4l2_subdev_state *state) { struct ub960_data *priv = sd_to_ub960(sd); struct v4l2_subdev_route routes[] = { { .sink_pad = 0, .sink_stream = 0, .source_pad = priv->hw_data->num_rxports, .source_stream = 0, .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, }, }; struct v4l2_subdev_krouting routing = { .num_routes = ARRAY_SIZE(routes), .routes = routes, }; return _ub960_set_routing(sd, state, &routing); } static const struct v4l2_subdev_pad_ops ub960_pad_ops = { .enable_streams = ub960_enable_streams, .disable_streams = ub960_disable_streams, .set_routing = ub960_set_routing, .get_frame_desc = ub960_get_frame_desc, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = ub960_set_fmt, }; static int ub960_log_status(struct v4l2_subdev *sd) { struct ub960_data *priv = sd_to_ub960(sd); struct device *dev = &priv->client->dev; struct v4l2_subdev_state *state; unsigned int nport; unsigned int i; u16 v16 = 0; u8 v = 0; u8 id[UB960_SR_FPD3_RX_ID_LEN]; state = v4l2_subdev_lock_and_get_active_state(sd); for (i = 0; i < sizeof(id); i++) ub960_read(priv, UB960_SR_FPD3_RX_ID(i), &id[i]); dev_info(dev, "ID '%.*s'\n", (int)sizeof(id), id); for (nport = 0; nport < priv->hw_data->num_txports; nport++) { struct ub960_txport *txport = priv->txports[nport]; dev_info(dev, "TX %u\n", nport); if (!txport) { dev_info(dev, "\tNot initialized\n"); continue; } ub960_txport_read(priv, nport, UB960_TR_CSI_STS, &v); dev_info(dev, "\tsync %u, pass %u\n", v & (u8)BIT(1), v & (u8)BIT(0)); ub960_read16(priv, UB960_SR_CSI_FRAME_COUNT_HI(nport), &v16); dev_info(dev, "\tframe counter %u\n", v16); ub960_read16(priv, UB960_SR_CSI_FRAME_ERR_COUNT_HI(nport), &v16); dev_info(dev, "\tframe error counter %u\n", v16); ub960_read16(priv, UB960_SR_CSI_LINE_COUNT_HI(nport), &v16); dev_info(dev, "\tline counter %u\n", v16); ub960_read16(priv, UB960_SR_CSI_LINE_ERR_COUNT_HI(nport), &v16); dev_info(dev, "\tline error counter %u\n", v16); } for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { struct ub960_rxport *rxport = priv->rxports[nport]; u8 eq_level; s8 strobe_pos; unsigned int i; dev_info(dev, "RX %u\n", nport); if (!rxport) { dev_info(dev, "\tNot initialized\n"); continue; } ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, &v); if (v & UB960_RR_RX_PORT_STS1_LOCK_STS) dev_info(dev, "\tLocked\n"); else dev_info(dev, "\tNot locked\n"); dev_info(dev, "\trx_port_sts1 %#02x\n", v); ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2, &v); dev_info(dev, "\trx_port_sts2 %#02x\n", v); ub960_rxport_read16(priv, nport, UB960_RR_RX_FREQ_HIGH, &v16); dev_info(dev, "\tlink freq %llu Hz\n", (v16 * 1000000ULL) >> 8); ub960_rxport_read16(priv, nport, UB960_RR_RX_PAR_ERR_HI, &v16); dev_info(dev, "\tparity errors %u\n", v16); ub960_rxport_read16(priv, nport, UB960_RR_LINE_COUNT_HI, &v16); dev_info(dev, "\tlines per frame %u\n", v16); ub960_rxport_read16(priv, nport, UB960_RR_LINE_LEN_1, &v16); dev_info(dev, "\tbytes per line %u\n", v16); ub960_rxport_read(priv, nport, UB960_RR_CSI_ERR_COUNTER, &v); dev_info(dev, "\tcsi_err_counter %u\n", v); /* Strobe */ ub960_read(priv, UB960_XR_AEQ_CTL1, &v); dev_info(dev, "\t%s strobe\n", (v & UB960_XR_AEQ_CTL1_AEQ_SFILTER_EN) ? "Adaptive" : "Manual"); if (v & UB960_XR_AEQ_CTL1_AEQ_SFILTER_EN) { ub960_read(priv, UB960_XR_SFILTER_CFG, &v); dev_info(dev, "\tStrobe range [%d, %d]\n", ((v >> UB960_XR_SFILTER_CFG_SFILTER_MIN_SHIFT) & 0xf) - 7, ((v >> UB960_XR_SFILTER_CFG_SFILTER_MAX_SHIFT) & 0xf) - 7); } ub960_rxport_get_strobe_pos(priv, nport, &strobe_pos); dev_info(dev, "\tStrobe pos %d\n", strobe_pos); /* EQ */ ub960_rxport_read(priv, nport, UB960_RR_AEQ_BYPASS, &v); dev_info(dev, "\t%s EQ\n", (v & UB960_RR_AEQ_BYPASS_ENABLE) ? "Manual" : "Adaptive"); if (!(v & UB960_RR_AEQ_BYPASS_ENABLE)) { ub960_rxport_read(priv, nport, UB960_RR_AEQ_MIN_MAX, &v); dev_info(dev, "\tEQ range [%u, %u]\n", (v >> UB960_RR_AEQ_MIN_MAX_AEQ_FLOOR_SHIFT) & 0xf, (v >> UB960_RR_AEQ_MIN_MAX_AEQ_MAX_SHIFT) & 0xf); } if (ub960_rxport_get_eq_level(priv, nport, &eq_level) == 0) dev_info(dev, "\tEQ level %u\n", eq_level); /* GPIOs */ for (i = 0; i < UB960_NUM_BC_GPIOS; i++) { u8 ctl_reg; u8 ctl_shift; ctl_reg = UB960_RR_BC_GPIO_CTL(i / 2); ctl_shift = (i % 2) * 4; ub960_rxport_read(priv, nport, ctl_reg, &v); dev_info(dev, "\tGPIO%u: mode %u\n", i, (v >> ctl_shift) & 0xf); } } v4l2_subdev_unlock_state(state); return 0; } static const struct v4l2_subdev_core_ops ub960_subdev_core_ops = { .log_status = ub960_log_status, .subscribe_event = v4l2_ctrl_subdev_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; static const struct v4l2_subdev_internal_ops ub960_internal_ops = { .init_state = ub960_init_state, }; static const struct v4l2_subdev_ops ub960_subdev_ops = { .core = &ub960_subdev_core_ops, .pad = &ub960_pad_ops, }; static const struct media_entity_operations ub960_entity_ops = { .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1, .link_validate = v4l2_subdev_link_validate, .has_pad_interdep = v4l2_subdev_has_pad_interdep, }; /* ----------------------------------------------------------------------------- * Core */ static irqreturn_t ub960_handle_events(int irq, void *arg) { struct ub960_data *priv = arg; unsigned int i; u8 int_sts; u8 fwd_sts; int ret; ret = ub960_read(priv, UB960_SR_INTERRUPT_STS, &int_sts); if (ret || !int_sts) return IRQ_NONE; dev_dbg(&priv->client->dev, "INTERRUPT_STS %x\n", int_sts); ret = ub960_read(priv, UB960_SR_FWD_STS, &fwd_sts); if (ret) return IRQ_NONE; dev_dbg(&priv->client->dev, "FWD_STS %#02x\n", fwd_sts); for (i = 0; i < priv->hw_data->num_txports; i++) { if (int_sts & UB960_SR_INTERRUPT_STS_IS_CSI_TX(i)) ub960_csi_handle_events(priv, i); } for (i = 0; i < priv->hw_data->num_rxports; i++) { if (!priv->rxports[i]) continue; if (int_sts & UB960_SR_INTERRUPT_STS_IS_RX(i)) ub960_rxport_handle_events(priv, i); } return IRQ_HANDLED; } static void ub960_handler_work(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); struct ub960_data *priv = container_of(dwork, struct ub960_data, poll_work); ub960_handle_events(0, priv); schedule_delayed_work(&priv->poll_work, msecs_to_jiffies(UB960_POLL_TIME_MS)); } static void ub960_txport_free_ports(struct ub960_data *priv) { unsigned int nport; for (nport = 0; nport < priv->hw_data->num_txports; nport++) { struct ub960_txport *txport = priv->txports[nport]; if (!txport) continue; kfree(txport); priv->txports[nport] = NULL; } } static void ub960_rxport_free_ports(struct ub960_data *priv) { unsigned int nport; for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { struct ub960_rxport *rxport = priv->rxports[nport]; if (!rxport) continue; fwnode_handle_put(rxport->source.ep_fwnode); fwnode_handle_put(rxport->ser.fwnode); kfree(rxport); priv->rxports[nport] = NULL; } } static int ub960_parse_dt_rxport_link_properties(struct ub960_data *priv, struct fwnode_handle *link_fwnode, struct ub960_rxport *rxport) { struct device *dev = &priv->client->dev; unsigned int nport = rxport->nport; u32 rx_mode; u32 cdr_mode; s32 strobe_pos; u32 eq_level; u32 ser_i2c_alias; int ret; cdr_mode = RXPORT_CDR_FPD3; ret = fwnode_property_read_u32(link_fwnode, "ti,cdr-mode", &cdr_mode); if (ret < 0 && ret != -EINVAL) { dev_err(dev, "rx%u: failed to read '%s': %d\n", nport, "ti,cdr-mode", ret); return ret; } if (cdr_mode > RXPORT_CDR_LAST) { dev_err(dev, "rx%u: bad 'ti,cdr-mode' %u\n", nport, cdr_mode); return -EINVAL; } if (!priv->hw_data->is_fpdlink4 && cdr_mode == RXPORT_CDR_FPD4) { dev_err(dev, "rx%u: FPD-Link 4 CDR not supported\n", nport); return -EINVAL; } rxport->cdr_mode = cdr_mode; ret = fwnode_property_read_u32(link_fwnode, "ti,rx-mode", &rx_mode); if (ret < 0) { dev_err(dev, "rx%u: failed to read '%s': %d\n", nport, "ti,rx-mode", ret); return ret; } if (rx_mode > RXPORT_MODE_LAST) { dev_err(dev, "rx%u: bad 'ti,rx-mode' %u\n", nport, rx_mode); return -EINVAL; } switch (rx_mode) { case RXPORT_MODE_RAW12_HF: case RXPORT_MODE_RAW12_LF: dev_err(dev, "rx%u: unsupported 'ti,rx-mode' %u\n", nport, rx_mode); return -EINVAL; default: break; } rxport->rx_mode = rx_mode; /* EQ & Strobe related */ /* Defaults */ rxport->eq.manual_eq = false; rxport->eq.aeq.eq_level_min = UB960_MIN_EQ_LEVEL; rxport->eq.aeq.eq_level_max = UB960_MAX_EQ_LEVEL; ret = fwnode_property_read_u32(link_fwnode, "ti,strobe-pos", &strobe_pos); if (ret) { if (ret != -EINVAL) { dev_err(dev, "rx%u: failed to read '%s': %d\n", nport, "ti,strobe-pos", ret); return ret; } } else { if (strobe_pos < UB960_MIN_MANUAL_STROBE_POS || strobe_pos > UB960_MAX_MANUAL_STROBE_POS) { dev_err(dev, "rx%u: illegal 'strobe-pos' value: %d\n", nport, strobe_pos); return -EINVAL; } /* NOTE: ignored unless global manual strobe pos is also set */ rxport->eq.strobe_pos = strobe_pos; if (!priv->strobe.manual) dev_warn(dev, "rx%u: 'ti,strobe-pos' ignored as 'ti,manual-strobe' not set\n", nport); } ret = fwnode_property_read_u32(link_fwnode, "ti,eq-level", &eq_level); if (ret) { if (ret != -EINVAL) { dev_err(dev, "rx%u: failed to read '%s': %d\n", nport, "ti,eq-level", ret); return ret; } } else { if (eq_level > UB960_MAX_EQ_LEVEL) { dev_err(dev, "rx%u: illegal 'ti,eq-level' value: %d\n", nport, eq_level); return -EINVAL; } rxport->eq.manual_eq = true; rxport->eq.manual.eq_level = eq_level; } ret = fwnode_property_read_u32(link_fwnode, "i2c-alias", &ser_i2c_alias); if (ret) { dev_err(dev, "rx%u: failed to read '%s': %d\n", nport, "i2c-alias", ret); return ret; } rxport->ser.alias = ser_i2c_alias; rxport->ser.fwnode = fwnode_get_named_child_node(link_fwnode, "serializer"); if (!rxport->ser.fwnode) { dev_err(dev, "rx%u: missing 'serializer' node\n", nport); return -EINVAL; } return 0; } static int ub960_parse_dt_rxport_ep_properties(struct ub960_data *priv, struct fwnode_handle *ep_fwnode, struct ub960_rxport *rxport) { struct device *dev = &priv->client->dev; struct v4l2_fwnode_endpoint vep = {}; unsigned int nport = rxport->nport; bool hsync_hi; bool vsync_hi; int ret; rxport->source.ep_fwnode = fwnode_graph_get_remote_endpoint(ep_fwnode); if (!rxport->source.ep_fwnode) { dev_err(dev, "rx%u: no remote endpoint\n", nport); return -ENODEV; } /* We currently have properties only for RAW modes */ switch (rxport->rx_mode) { case RXPORT_MODE_RAW10: case RXPORT_MODE_RAW12_HF: case RXPORT_MODE_RAW12_LF: break; default: return 0; } vep.bus_type = V4L2_MBUS_PARALLEL; ret = v4l2_fwnode_endpoint_parse(ep_fwnode, &vep); if (ret) { dev_err(dev, "rx%u: failed to parse endpoint data\n", nport); goto err_put_source_ep_fwnode; } hsync_hi = !!(vep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH); vsync_hi = !!(vep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH); /* LineValid and FrameValid are inverse to the h/vsync active */ rxport->lv_fv_pol = (hsync_hi ? UB960_RR_PORT_CONFIG2_LV_POL_LOW : 0) | (vsync_hi ? UB960_RR_PORT_CONFIG2_FV_POL_LOW : 0); return 0; err_put_source_ep_fwnode: fwnode_handle_put(rxport->source.ep_fwnode); return ret; } static int ub960_parse_dt_rxport(struct ub960_data *priv, unsigned int nport, struct fwnode_handle *link_fwnode, struct fwnode_handle *ep_fwnode) { static const char *vpoc_names[UB960_MAX_RX_NPORTS] = { "vpoc0", "vpoc1", "vpoc2", "vpoc3" }; struct device *dev = &priv->client->dev; struct ub960_rxport *rxport; int ret; rxport = kzalloc(sizeof(*rxport), GFP_KERNEL); if (!rxport) return -ENOMEM; priv->rxports[nport] = rxport; rxport->nport = nport; rxport->priv = priv; ret = ub960_parse_dt_rxport_link_properties(priv, link_fwnode, rxport); if (ret) goto err_free_rxport; rxport->vpoc = devm_regulator_get_optional(dev, vpoc_names[nport]); if (IS_ERR(rxport->vpoc)) { ret = PTR_ERR(rxport->vpoc); if (ret == -ENODEV) { rxport->vpoc = NULL; } else { dev_err(dev, "rx%u: failed to get VPOC supply: %d\n", nport, ret); goto err_put_remote_fwnode; } } ret = ub960_parse_dt_rxport_ep_properties(priv, ep_fwnode, rxport); if (ret) goto err_put_remote_fwnode; return 0; err_put_remote_fwnode: fwnode_handle_put(rxport->ser.fwnode); err_free_rxport: priv->rxports[nport] = NULL; kfree(rxport); return ret; } static struct fwnode_handle * ub960_fwnode_get_link_by_regs(struct fwnode_handle *links_fwnode, unsigned int nport) { struct fwnode_handle *link_fwnode; int ret; fwnode_for_each_child_node(links_fwnode, link_fwnode) { u32 link_num; if (!str_has_prefix(fwnode_get_name(link_fwnode), "link@")) continue; ret = fwnode_property_read_u32(link_fwnode, "reg", &link_num); if (ret) { fwnode_handle_put(link_fwnode); return NULL; } if (nport == link_num) return link_fwnode; } return NULL; } static int ub960_parse_dt_rxports(struct ub960_data *priv) { struct device *dev = &priv->client->dev; struct fwnode_handle *links_fwnode; unsigned int nport; int ret; links_fwnode = fwnode_get_named_child_node(dev_fwnode(dev), "links"); if (!links_fwnode) { dev_err(dev, "'links' node missing\n"); return -ENODEV; } /* Defaults, recommended by TI */ priv->strobe.min = 2; priv->strobe.max = 3; priv->strobe.manual = fwnode_property_read_bool(links_fwnode, "ti,manual-strobe"); for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { struct fwnode_handle *link_fwnode; struct fwnode_handle *ep_fwnode; link_fwnode = ub960_fwnode_get_link_by_regs(links_fwnode, nport); if (!link_fwnode) continue; ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), nport, 0, 0); if (!ep_fwnode) { fwnode_handle_put(link_fwnode); continue; } ret = ub960_parse_dt_rxport(priv, nport, link_fwnode, ep_fwnode); fwnode_handle_put(link_fwnode); fwnode_handle_put(ep_fwnode); if (ret) { dev_err(dev, "rx%u: failed to parse RX port\n", nport); goto err_put_links; } } fwnode_handle_put(links_fwnode); return 0; err_put_links: fwnode_handle_put(links_fwnode); return ret; } static int ub960_parse_dt_txports(struct ub960_data *priv) { struct device *dev = &priv->client->dev; u32 nport; int ret; for (nport = 0; nport < priv->hw_data->num_txports; nport++) { unsigned int port = nport + priv->hw_data->num_rxports; struct fwnode_handle *ep_fwnode; ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), port, 0, 0); if (!ep_fwnode) continue; ret = ub960_parse_dt_txport(priv, ep_fwnode, nport); fwnode_handle_put(ep_fwnode); if (ret) break; } return 0; } static int ub960_parse_dt(struct ub960_data *priv) { int ret; ret = ub960_parse_dt_rxports(priv); if (ret) return ret; ret = ub960_parse_dt_txports(priv); if (ret) goto err_free_rxports; return 0; err_free_rxports: ub960_rxport_free_ports(priv); return ret; } static int ub960_notify_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *subdev, struct v4l2_async_connection *asd) { struct ub960_data *priv = sd_to_ub960(notifier->sd); struct ub960_rxport *rxport = to_ub960_asd(asd)->rxport; struct device *dev = &priv->client->dev; u8 nport = rxport->nport; unsigned int i; int ret; ret = media_entity_get_fwnode_pad(&subdev->entity, rxport->source.ep_fwnode, MEDIA_PAD_FL_SOURCE); if (ret < 0) { dev_err(dev, "Failed to find pad for %s\n", subdev->name); return ret; } rxport->source.sd = subdev; rxport->source.pad = ret; ret = media_create_pad_link(&rxport->source.sd->entity, rxport->source.pad, &priv->sd.entity, nport, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); if (ret) { dev_err(dev, "Unable to link %s:%u -> %s:%u\n", rxport->source.sd->name, rxport->source.pad, priv->sd.name, nport); return ret; } for (i = 0; i < priv->hw_data->num_rxports; i++) { if (priv->rxports[i] && !priv->rxports[i]->source.sd) { dev_dbg(dev, "Waiting for more subdevs to be bound\n"); return 0; } } return 0; } static void ub960_notify_unbind(struct v4l2_async_notifier *notifier, struct v4l2_subdev *subdev, struct v4l2_async_connection *asd) { struct ub960_rxport *rxport = to_ub960_asd(asd)->rxport; rxport->source.sd = NULL; } static const struct v4l2_async_notifier_operations ub960_notify_ops = { .bound = ub960_notify_bound, .unbind = ub960_notify_unbind, }; static int ub960_v4l2_notifier_register(struct ub960_data *priv) { struct device *dev = &priv->client->dev; unsigned int i; int ret; v4l2_async_subdev_nf_init(&priv->notifier, &priv->sd); for (i = 0; i < priv->hw_data->num_rxports; i++) { struct ub960_rxport *rxport = priv->rxports[i]; struct ub960_asd *asd; if (!rxport) continue; asd = v4l2_async_nf_add_fwnode(&priv->notifier, rxport->source.ep_fwnode, struct ub960_asd); if (IS_ERR(asd)) { dev_err(dev, "Failed to add subdev for source %u: %pe", i, asd); v4l2_async_nf_cleanup(&priv->notifier); return PTR_ERR(asd); } asd->rxport = rxport; } priv->notifier.ops = &ub960_notify_ops; ret = v4l2_async_nf_register(&priv->notifier); if (ret) { dev_err(dev, "Failed to register subdev_notifier"); v4l2_async_nf_cleanup(&priv->notifier); return ret; } return 0; } static void ub960_v4l2_notifier_unregister(struct ub960_data *priv) { v4l2_async_nf_unregister(&priv->notifier); v4l2_async_nf_cleanup(&priv->notifier); } static int ub960_create_subdev(struct ub960_data *priv) { struct device *dev = &priv->client->dev; unsigned int i; int ret; v4l2_i2c_subdev_init(&priv->sd, priv->client, &ub960_subdev_ops); priv->sd.internal_ops = &ub960_internal_ops; v4l2_ctrl_handler_init(&priv->ctrl_handler, 1); priv->sd.ctrl_handler = &priv->ctrl_handler; v4l2_ctrl_new_int_menu(&priv->ctrl_handler, NULL, V4L2_CID_LINK_FREQ, ARRAY_SIZE(priv->tx_link_freq) - 1, 0, priv->tx_link_freq); if (priv->ctrl_handler.error) { ret = priv->ctrl_handler.error; goto err_free_ctrl; } priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_STREAMS; priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; priv->sd.entity.ops = &ub960_entity_ops; for (i = 0; i < priv->hw_data->num_rxports + priv->hw_data->num_txports; i++) { priv->pads[i].flags = ub960_pad_is_sink(priv, i) ? MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; } ret = media_entity_pads_init(&priv->sd.entity, priv->hw_data->num_rxports + priv->hw_data->num_txports, priv->pads); if (ret) goto err_free_ctrl; priv->sd.state_lock = priv->sd.ctrl_handler->lock; ret = v4l2_subdev_init_finalize(&priv->sd); if (ret) goto err_entity_cleanup; ret = ub960_v4l2_notifier_register(priv); if (ret) { dev_err(dev, "v4l2 subdev notifier register failed: %d\n", ret); goto err_subdev_cleanup; } ret = v4l2_async_register_subdev(&priv->sd); if (ret) { dev_err(dev, "v4l2_async_register_subdev error: %d\n", ret); goto err_unreg_notif; } return 0; err_unreg_notif: ub960_v4l2_notifier_unregister(priv); err_subdev_cleanup: v4l2_subdev_cleanup(&priv->sd); err_entity_cleanup: media_entity_cleanup(&priv->sd.entity); err_free_ctrl: v4l2_ctrl_handler_free(&priv->ctrl_handler); return ret; } static void ub960_destroy_subdev(struct ub960_data *priv) { ub960_v4l2_notifier_unregister(priv); v4l2_async_unregister_subdev(&priv->sd); v4l2_subdev_cleanup(&priv->sd); media_entity_cleanup(&priv->sd.entity); v4l2_ctrl_handler_free(&priv->ctrl_handler); } static const struct regmap_config ub960_regmap_config = { .name = "ds90ub960", .reg_bits = 8, .val_bits = 8, .max_register = 0xff, /* * We do locking in the driver to cover the TX/RX port selection and the * indirect register access. */ .disable_locking = true, }; static void ub960_reset(struct ub960_data *priv, bool reset_regs) { struct device *dev = &priv->client->dev; unsigned int v; int ret; u8 bit; bit = reset_regs ? UB960_SR_RESET_DIGITAL_RESET1 : UB960_SR_RESET_DIGITAL_RESET0; ub960_write(priv, UB960_SR_RESET, bit); mutex_lock(&priv->reg_lock); ret = regmap_read_poll_timeout(priv->regmap, UB960_SR_RESET, v, (v & bit) == 0, 2000, 100000); mutex_unlock(&priv->reg_lock); if (ret) dev_err(dev, "reset failed: %d\n", ret); } static int ub960_get_hw_resources(struct ub960_data *priv) { struct device *dev = &priv->client->dev; priv->regmap = devm_regmap_init_i2c(priv->client, &ub960_regmap_config); if (IS_ERR(priv->regmap)) return PTR_ERR(priv->regmap); priv->vddio = devm_regulator_get(dev, "vddio"); if (IS_ERR(priv->vddio)) return dev_err_probe(dev, PTR_ERR(priv->vddio), "cannot get VDDIO regulator\n"); /* get power-down pin from DT */ priv->pd_gpio = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH); if (IS_ERR(priv->pd_gpio)) return dev_err_probe(dev, PTR_ERR(priv->pd_gpio), "Cannot get powerdown GPIO\n"); priv->refclk = devm_clk_get(dev, "refclk"); if (IS_ERR(priv->refclk)) return dev_err_probe(dev, PTR_ERR(priv->refclk), "Cannot get REFCLK\n"); return 0; } static int ub960_enable_core_hw(struct ub960_data *priv) { struct device *dev = &priv->client->dev; u8 rev_mask; int ret; u8 dev_sts; u8 refclk_freq; ret = regulator_enable(priv->vddio); if (ret) return dev_err_probe(dev, ret, "failed to enable VDDIO regulator\n"); ret = clk_prepare_enable(priv->refclk); if (ret) { dev_err_probe(dev, ret, "Failed to enable refclk\n"); goto err_disable_vddio; } if (priv->pd_gpio) { gpiod_set_value_cansleep(priv->pd_gpio, 1); /* wait min 2 ms for reset to complete */ fsleep(2000); gpiod_set_value_cansleep(priv->pd_gpio, 0); /* wait min 2 ms for power up to finish */ fsleep(2000); } ub960_reset(priv, true); /* Runtime check register accessibility */ ret = ub960_read(priv, UB960_SR_REV_MASK, &rev_mask); if (ret) { dev_err_probe(dev, ret, "Cannot read first register, abort\n"); goto err_pd_gpio; } dev_dbg(dev, "Found %s (rev/mask %#04x)\n", priv->hw_data->model, rev_mask); ret = ub960_read(priv, UB960_SR_DEVICE_STS, &dev_sts); if (ret) goto err_pd_gpio; ret = ub960_read(priv, UB960_XR_REFCLK_FREQ, &refclk_freq); if (ret) goto err_pd_gpio; dev_dbg(dev, "refclk valid %u freq %u MHz (clk fw freq %lu MHz)\n", !!(dev_sts & BIT(4)), refclk_freq, clk_get_rate(priv->refclk) / 1000000); /* Disable all RX ports by default */ ret = ub960_write(priv, UB960_SR_RX_PORT_CTL, 0); if (ret) goto err_pd_gpio; /* release GPIO lock */ if (priv->hw_data->is_ub9702) { ret = ub960_update_bits(priv, UB960_SR_RESET, UB960_SR_RESET_GPIO_LOCK_RELEASE, UB960_SR_RESET_GPIO_LOCK_RELEASE); if (ret) goto err_pd_gpio; } return 0; err_pd_gpio: gpiod_set_value_cansleep(priv->pd_gpio, 1); clk_disable_unprepare(priv->refclk); err_disable_vddio: regulator_disable(priv->vddio); return ret; } static void ub960_disable_core_hw(struct ub960_data *priv) { gpiod_set_value_cansleep(priv->pd_gpio, 1); clk_disable_unprepare(priv->refclk); regulator_disable(priv->vddio); } static int ub960_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ub960_data *priv; unsigned int port_lock_mask; unsigned int port_mask; unsigned int nport; int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; priv->client = client; priv->hw_data = device_get_match_data(dev); mutex_init(&priv->reg_lock); INIT_DELAYED_WORK(&priv->poll_work, ub960_handler_work); /* * Initialize these to invalid values so that the first reg writes will * configure the target. */ priv->reg_current.indirect_target = 0xff; priv->reg_current.rxport = 0xff; priv->reg_current.txport = 0xff; ret = ub960_get_hw_resources(priv); if (ret) goto err_mutex_destroy; ret = ub960_enable_core_hw(priv); if (ret) goto err_mutex_destroy; ret = ub960_parse_dt(priv); if (ret) goto err_disable_core_hw; ret = ub960_init_tx_ports(priv); if (ret) goto err_free_ports; ret = ub960_rxport_enable_vpocs(priv); if (ret) goto err_free_ports; ret = ub960_init_rx_ports(priv); if (ret) goto err_disable_vpocs; ub960_reset(priv, false); port_mask = 0; for (nport = 0; nport < priv->hw_data->num_rxports; nport++) { struct ub960_rxport *rxport = priv->rxports[nport]; if (!rxport) continue; port_mask |= BIT(nport); } ret = ub960_rxport_wait_locks(priv, port_mask, &port_lock_mask); if (ret) goto err_disable_vpocs; if (port_mask != port_lock_mask) { ret = -EIO; dev_err_probe(dev, ret, "Failed to lock all RX ports\n"); goto err_disable_vpocs; } /* * Clear any errors caused by switching the RX port settings while * probing. */ ub960_clear_rx_errors(priv); ret = ub960_init_atr(priv); if (ret) goto err_disable_vpocs; ret = ub960_rxport_add_serializers(priv); if (ret) goto err_uninit_atr; ret = ub960_create_subdev(priv); if (ret) goto err_free_sers; if (client->irq) dev_warn(dev, "irq support not implemented, using polling\n"); schedule_delayed_work(&priv->poll_work, msecs_to_jiffies(UB960_POLL_TIME_MS)); return 0; err_free_sers: ub960_rxport_remove_serializers(priv); err_uninit_atr: ub960_uninit_atr(priv); err_disable_vpocs: ub960_rxport_disable_vpocs(priv); err_free_ports: ub960_rxport_free_ports(priv); ub960_txport_free_ports(priv); err_disable_core_hw: ub960_disable_core_hw(priv); err_mutex_destroy: mutex_destroy(&priv->reg_lock); return ret; } static void ub960_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); struct ub960_data *priv = sd_to_ub960(sd); cancel_delayed_work_sync(&priv->poll_work); ub960_destroy_subdev(priv); ub960_rxport_remove_serializers(priv); ub960_uninit_atr(priv); ub960_rxport_disable_vpocs(priv); ub960_rxport_free_ports(priv); ub960_txport_free_ports(priv); ub960_disable_core_hw(priv); mutex_destroy(&priv->reg_lock); } static const struct ub960_hw_data ds90ub960_hw = { .model = "ub960", .num_rxports = 4, .num_txports = 2, }; static const struct ub960_hw_data ds90ub9702_hw = { .model = "ub9702", .num_rxports = 4, .num_txports = 2, .is_ub9702 = true, .is_fpdlink4 = true, }; static const struct i2c_device_id ub960_id[] = { { "ds90ub960-q1", (kernel_ulong_t)&ds90ub960_hw }, { "ds90ub9702-q1", (kernel_ulong_t)&ds90ub9702_hw }, {} }; MODULE_DEVICE_TABLE(i2c, ub960_id); static const struct of_device_id ub960_dt_ids[] = { { .compatible = "ti,ds90ub960-q1", .data = &ds90ub960_hw }, { .compatible = "ti,ds90ub9702-q1", .data = &ds90ub9702_hw }, {} }; MODULE_DEVICE_TABLE(of, ub960_dt_ids); static struct i2c_driver ds90ub960_driver = { .probe = ub960_probe, .remove = ub960_remove, .id_table = ub960_id, .driver = { .name = "ds90ub960", .of_match_table = ub960_dt_ids, }, }; module_i2c_driver(ds90ub960_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Texas Instruments FPD-Link III/IV Deserializers Driver"); MODULE_AUTHOR("Luca Ceresoli <luca@lucaceresoli.net>"); MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>"); MODULE_IMPORT_NS(I2C_ATR);
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1