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