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