6
6
7
7
#define DT_DRV_COMPAT nxp_mipi_csi2rx
8
8
9
+ #include <zephyr/drivers/clock_control.h>
9
10
#include <zephyr/drivers/video.h>
10
11
#include <zephyr/kernel.h>
11
12
#include <zephyr/logging/log.h>
13
+ #include <soc.h>
12
14
13
15
#include <fsl_mipi_csi2rx.h>
14
16
15
17
LOG_MODULE_REGISTER (video_mipi_csi2rx , CONFIG_VIDEO_LOG_LEVEL );
16
18
17
- #define DEFAULT_CAMERA_FRAME_RATE 30
19
+ #define MAX_SUPPORTED_PIXEL_RATE MHZ(96)
20
+
21
+ #define ABS (a , b ) (a > b ? a - b : b - a)
18
22
19
23
#define DEVICE_DT_INST_GET_SENSOR_DEV (n ) \
20
24
DEVICE_DT_GET(DT_GPARENT(DT_NODELABEL( \
@@ -28,100 +32,106 @@ struct mipi_csi2rx_config {
28
32
29
33
struct mipi_csi2rx_data {
30
34
csi2rx_config_t csi2rxConfig ;
35
+ const struct device * clock_dev ;
36
+ clock_control_subsys_t clock_root ;
37
+ clock_control_subsys_t clock_ui ;
38
+ clock_control_subsys_t clock_esc ;
31
39
};
32
40
33
- static int mipi_csi2rx_set_fmt (const struct device * dev , enum video_endpoint_id ep ,
34
- struct video_format * fmt )
41
+ struct mipi_csi2rx_tHsSettleEscClk_config {
42
+ uint64_t pixel_rate ;
43
+ uint8_t tHsSettle_EscClk ;
44
+ };
45
+
46
+ /* Must be in pixel rate ascending order */
47
+ const struct mipi_csi2rx_tHsSettleEscClk_config tHsSettleEscClk_configs [] = {
48
+ {MHZ (24 ), 0x24 },
49
+ {MHZ (48 ), 0x12 },
50
+ {MHZ (96 ), 0x09 },
51
+ };
52
+
53
+ static int mipi_csi2rx_update_settings (const struct device * dev , enum video_endpoint_id ep )
35
54
{
36
55
const struct mipi_csi2rx_config * config = dev -> config ;
37
56
struct mipi_csi2rx_data * drv_data = dev -> data ;
38
- csi2rx_config_t csi2rxConfig = {0 };
39
- uint8_t i = 0 ;
57
+ uint8_t bpp ;
58
+ uint64_t sensor_pixel_rate ;
59
+ uint32_t root_clk_rate , ui_clk_rate , sensor_byte_clk , best_match ;
60
+ int ret , ind = 0 ;
61
+ struct video_format fmt ;
62
+
63
+ ret = video_get_format (config -> sensor_dev , ep , & fmt );
64
+ if (ret ) {
65
+ LOG_ERR ("Cannot get sensor_dev pixel format" );
66
+ return ret ;
67
+ }
40
68
41
- /*
42
- * Initialize the MIPI CSI2
43
- *
44
- * From D-PHY specification, the T-HSSETTLE should in the range of 85ns+6*UI to 145ns+10*UI
45
- * UI is Unit Interval, equal to the duration of any HS state on the Clock Lane
46
- *
47
- * T-HSSETTLE = csi2rxConfig.tHsSettle_EscClk * (Tperiod of RxClkInEsc)
48
- *
49
- * csi2rxConfig.tHsSettle_EscClk setting for camera:
50
- *
51
- * Resolution | frame rate | T_HS_SETTLE
52
- * =============================================
53
- * 720P | 30 | 0x12
54
- * ---------------------------------------------
55
- * 720P | 15 | 0x17
56
- * ---------------------------------------------
57
- * VGA | 30 | 0x1F
58
- * ---------------------------------------------
59
- * VGA | 15 | 0x24
60
- * ---------------------------------------------
61
- * QVGA | 30 | 0x1F
62
- * ---------------------------------------------
63
- * QVGA | 15 | 0x24
64
- * ---------------------------------------------
65
- */
66
- static const uint32_t csi2rxHsSettle [][4 ] = {
67
- {
68
- 1280 ,
69
- 720 ,
70
- 30 ,
71
- 0x12 ,
72
- },
73
- {
74
- 1280 ,
75
- 720 ,
76
- 15 ,
77
- 0x17 ,
78
- },
79
- {
80
- 640 ,
81
- 480 ,
82
- 30 ,
83
- 0x1F ,
84
- },
85
- {
86
- 640 ,
87
- 480 ,
88
- 15 ,
89
- 0x24 ,
90
- },
91
- {
92
- 320 ,
93
- 240 ,
94
- 30 ,
95
- 0x1F ,
96
- },
97
- {
98
- 320 ,
99
- 240 ,
100
- 15 ,
101
- 0x24 ,
102
- },
103
- };
104
-
105
- for (i = 0 ; i < ARRAY_SIZE (csi2rxHsSettle ); i ++ ) {
106
- if ((fmt -> width == csi2rxHsSettle [i ][0 ]) && (fmt -> height == csi2rxHsSettle [i ][1 ]) &&
107
- (DEFAULT_CAMERA_FRAME_RATE == csi2rxHsSettle [i ][2 ])) {
108
- csi2rxConfig .tHsSettle_EscClk = csi2rxHsSettle [i ][3 ];
109
- break ;
110
- }
69
+ ret = video_get_ctrl (config -> sensor_dev , VIDEO_CID_PIXEL_RATE , & sensor_pixel_rate );
70
+ if (ret ) {
71
+ LOG_ERR ("Can not get sensor_dev pixel rate" );
72
+ return ret ;
111
73
}
112
74
113
- if (i == ARRAY_SIZE ( csi2rxHsSettle ) ) {
114
- LOG_ERR ("Unsupported resolution " );
75
+ if (sensor_pixel_rate > MAX_SUPPORTED_PIXEL_RATE ) {
76
+ LOG_ERR ("Sensor pixel rate is not supported " );
115
77
return - ENOTSUP ;
116
78
}
117
79
118
- drv_data -> csi2rxConfig = csi2rxConfig ;
80
+ bpp = video_pix_fmt_bpp (fmt .pixelformat ) * 8 ;
81
+ sensor_byte_clk = sensor_pixel_rate * bpp / drv_data -> csi2rxConfig .laneNum / 8 ;
82
+
83
+ ret = clock_control_get_rate (drv_data -> clock_dev , drv_data -> clock_root , & root_clk_rate );
84
+ if (ret ) {
85
+ return ret ;
86
+ }
87
+
88
+ if (sensor_byte_clk > root_clk_rate ) {
89
+ ret = clock_control_set_rate (drv_data -> clock_dev , drv_data -> clock_root ,
90
+ (clock_control_subsys_rate_t )sensor_byte_clk );
91
+ if (ret ) {
92
+ return ret ;
93
+ }
94
+ }
95
+
96
+ ret = clock_control_get_rate (drv_data -> clock_dev , drv_data -> clock_ui , & ui_clk_rate );
97
+ if (ret ) {
98
+ return ret ;
99
+ }
100
+
101
+ if (sensor_pixel_rate > ui_clk_rate ) {
102
+ ret = clock_control_set_rate (
103
+ drv_data -> clock_dev , drv_data -> clock_ui ,
104
+ (clock_control_subsys_rate_t )(uint32_t )sensor_pixel_rate );
105
+ if (ret ) {
106
+ return ret ;
107
+ }
108
+ }
109
+
110
+ /* Find the supported sensor_pixel_rate closest to the desired one */
111
+ best_match = tHsSettleEscClk_configs [ind ].pixel_rate ;
112
+ for (uint8_t i = 0 ; i < ARRAY_SIZE (tHsSettleEscClk_configs ); i ++ ) {
113
+ if (ABS (tHsSettleEscClk_configs [i ].pixel_rate , sensor_pixel_rate ) <
114
+ ABS (tHsSettleEscClk_configs [i ].pixel_rate , best_match )) {
115
+ best_match = tHsSettleEscClk_configs [i ].pixel_rate ;
116
+ ind = i ;
117
+ }
118
+ }
119
+
120
+ drv_data -> csi2rxConfig .tHsSettle_EscClk = tHsSettleEscClk_configs [ind ].tHsSettle_EscClk ;
121
+
122
+ return ret ;
123
+ }
124
+
125
+ static int mipi_csi2rx_set_fmt (const struct device * dev , enum video_endpoint_id ep ,
126
+ struct video_format * fmt )
127
+ {
128
+ const struct mipi_csi2rx_config * config = dev -> config ;
119
129
120
130
if (video_set_format (config -> sensor_dev , ep , fmt )) {
121
131
return - EIO ;
122
132
}
123
133
124
- return 0 ;
134
+ return mipi_csi2rx_update_settings ( dev , ep ) ;
125
135
}
126
136
127
137
static int mipi_csi2rx_get_fmt (const struct device * dev , enum video_endpoint_id ep ,
@@ -203,20 +213,36 @@ static const struct video_driver_api mipi_csi2rx_driver_api = {
203
213
static int mipi_csi2rx_init (const struct device * dev )
204
214
{
205
215
const struct mipi_csi2rx_config * config = dev -> config ;
216
+ struct mipi_csi2rx_data * drv_data = dev -> data ;
217
+ int ret ;
206
218
207
219
/* Check if there is any sensor device */
208
220
if (!device_is_ready (config -> sensor_dev )) {
209
221
return - ENODEV ;
210
222
}
211
223
212
- return 0 ;
224
+ /*
225
+ * CSI2 escape clock should be in the range [60, 80] Mhz. We set it
226
+ * to 60 Mhz.
227
+ */
228
+ ret = clock_control_set_rate (drv_data -> clock_dev , drv_data -> clock_esc ,
229
+ (clock_control_subsys_rate_t )MHZ (60 ));
230
+ if (ret ) {
231
+ return ret ;
232
+ }
233
+
234
+ return mipi_csi2rx_update_settings (dev , VIDEO_EP_ALL );
213
235
}
214
236
215
237
#define MIPI_CSI2RX_INIT (n ) \
216
238
static struct mipi_csi2rx_data mipi_csi2rx_data_##n = { \
217
239
.csi2rxConfig.laneNum = \
218
240
DT_PROP_LEN(DT_CHILD(DT_CHILD(DT_INST_CHILD(n, ports), port_1), endpoint), \
219
241
data_lanes), \
242
+ .clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \
243
+ .clock_root = (clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_IDX(n, 0, name), \
244
+ .clock_ui = (clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_IDX(n, 1, name), \
245
+ .clock_esc = (clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_IDX(n, 2, name), \
220
246
}; \
221
247
\
222
248
static const struct mipi_csi2rx_config mipi_csi2rx_config_##n = { \
0 commit comments