• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Rockchip MIPI CSI2 DPHY driver
4  *
5  * Copyright (C) 2022 Rockchip Electronics Co., Ltd.
6  */
7 
8 #include <linux/clk.h>
9 #include <linux/delay.h>
10 #include <linux/io.h>
11 #include <linux/module.h>
12 #include <linux/of.h>
13 #include <linux/of_graph.h>
14 #include <linux/of_platform.h>
15 #include <linux/platform_device.h>
16 #include <linux/pm_runtime.h>
17 #include <linux/regmap.h>
18 #include <linux/mfd/syscon.h>
19 #include <media/media-entity.h>
20 #include <media/v4l2-ctrls.h>
21 #include <media/v4l2-fwnode.h>
22 #include <media/v4l2-subdev.h>
23 #include <media/v4l2-device.h>
24 #include "phy-rockchip-csi2-dphy-common.h"
25 
26 struct sensor_async_subdev {
27     struct v4l2_async_subdev asd;
28     struct v4l2_mbus_config mbus;
29     int lanes;
30 };
31 
32 static LIST_HEAD(csi2dphy_device_list);
33 
to_csi2_dphy(struct v4l2_subdev * subdev)34 static inline struct csi2_dphy *to_csi2_dphy(struct v4l2_subdev *subdev)
35 {
36     return container_of(subdev, struct csi2_dphy, sd);
37 }
38 
get_remote_sensor(struct v4l2_subdev * sd)39 static struct v4l2_subdev *get_remote_sensor(struct v4l2_subdev *sd)
40 {
41     struct media_pad *local, *remote;
42     struct media_entity *sensor_me;
43 
44     local = &sd->entity.pads[CSI2_DPHY_RX_PAD_SINK];
45     remote = media_entity_remote_pad(local);
46     if (!remote) {
47         v4l2_warn(sd, "No link between dphy and sensor\n");
48         return NULL;
49     }
50 
51     sensor_me = media_entity_remote_pad(local)->entity;
52     return media_entity_to_v4l2_subdev(sensor_me);
53 }
54 
sd_to_sensor(struct csi2_dphy * dphy,struct v4l2_subdev * sd)55 static struct csi2_sensor *sd_to_sensor(struct csi2_dphy *dphy, struct v4l2_subdev *sd)
56 {
57     int i;
58 
59     for (i = 0; i < dphy->num_sensors; ++i) {
60         if (dphy->sensors[i].sd == sd) {
61             return &dphy->sensors[i];
62         }
63     }
64 
65     return NULL;
66 }
67 
csi2_dphy_get_sensor_data_rate(struct v4l2_subdev * sd)68 static int csi2_dphy_get_sensor_data_rate(struct v4l2_subdev *sd)
69 {
70     struct csi2_dphy *dphy = to_csi2_dphy(sd);
71     struct v4l2_subdev *sensor_sd = get_remote_sensor(sd);
72     struct v4l2_ctrl *link_freq;
73     struct v4l2_querymenu qm = {
74         .id = V4L2_CID_LINK_FREQ,
75     };
76     int ret;
77 
78     link_freq = v4l2_ctrl_find(sensor_sd->ctrl_handler, V4L2_CID_LINK_FREQ);
79     if (!link_freq) {
80         v4l2_warn(sd, "No pixel rate control in subdev\n");
81         return -EPIPE;
82     }
83 
84     qm.index = v4l2_ctrl_g_ctrl(link_freq);
85     ret = v4l2_querymenu(sensor_sd->ctrl_handler, &qm);
86     if (ret < 0) {
87         v4l2_err(sd, "Failed to get menu item\n");
88         return ret;
89     }
90 
91     if (!qm.value) {
92         v4l2_err(sd, "Invalid link_freq\n");
93         return -EINVAL;
94     }
95     dphy->data_rate_mbps = qm.value * 0x02;
96     do_div(dphy->data_rate_mbps, 0x3E8 * 0x3E8);
97     v4l2_info(sd, "dphy%d, data_rate_mbps %lld\n", dphy->phy_index, dphy->data_rate_mbps);
98     return 0;
99 }
100 
csi2_dphy_update_sensor_mbus(struct v4l2_subdev * sd)101 static int csi2_dphy_update_sensor_mbus(struct v4l2_subdev *sd)
102 {
103     struct csi2_dphy *dphy = to_csi2_dphy(sd);
104     struct v4l2_subdev *sensor_sd = get_remote_sensor(sd);
105     struct csi2_sensor *sensor = sd_to_sensor(dphy, sensor_sd);
106     struct v4l2_mbus_config mbus;
107     int ret;
108 
109     ret = v4l2_subdev_call(sensor_sd, pad, get_mbus_config, 0, &mbus);
110     if (ret) {
111         return ret;
112     }
113 
114     sensor->mbus = mbus;
115     switch (mbus.flags & V4L2_MBUS_CSI2_LANES) {
116         case V4L2_MBUS_CSI2_1_LANE:
117             sensor->lanes = 1;
118             break;
119         case V4L2_MBUS_CSI2_2_LANE:
120             sensor->lanes = 0x02;
121             break;
122         case V4L2_MBUS_CSI2_3_LANE:
123             sensor->lanes = 0x03;
124             break;
125         case V4L2_MBUS_CSI2_4_LANE:
126             sensor->lanes = 0x04;
127             break;
128         default:
129             return -EINVAL;
130     }
131 
132     return 0;
133 }
134 
csi2_dphy_s_stream_start(struct v4l2_subdev * sd)135 static int csi2_dphy_s_stream_start(struct v4l2_subdev *sd)
136 {
137     struct csi2_dphy *dphy = to_csi2_dphy(sd);
138     struct csi2_dphy_hw *hw = dphy->dphy_hw;
139     int ret = 0;
140 
141     if (dphy->is_streaming) {
142         return 0;
143     }
144 
145     ret = csi2_dphy_get_sensor_data_rate(sd);
146     if (ret < 0) {
147         return ret;
148     }
149 
150     csi2_dphy_update_sensor_mbus(sd);
151 
152     if (hw->stream_on) {
153         hw->stream_on(dphy, sd);
154     }
155 
156     dphy->is_streaming = true;
157 
158     return 0;
159 }
160 
csi2_dphy_s_stream_stop(struct v4l2_subdev * sd)161 static int csi2_dphy_s_stream_stop(struct v4l2_subdev *sd)
162 {
163     struct csi2_dphy *dphy = to_csi2_dphy(sd);
164     struct csi2_dphy_hw *hw = dphy->dphy_hw;
165 
166     if (!dphy->is_streaming) {
167         return 0;
168     }
169 
170     if (hw->stream_off) {
171         hw->stream_off(dphy, sd);
172     }
173 
174     dphy->is_streaming = false;
175 
176     dev_info(dphy->dev, "%s stream stop, dphy%d\n", __func__, dphy->phy_index);
177 
178     return 0;
179 }
180 
csi2_dphy_s_stream(struct v4l2_subdev * sd,int on)181 static int csi2_dphy_s_stream(struct v4l2_subdev *sd, int on)
182 {
183     struct csi2_dphy *dphy = to_csi2_dphy(sd);
184     int ret = 0;
185 
186     mutex_lock(&dphy->mutex);
187     if (on) {
188         ret = csi2_dphy_s_stream_start(sd);
189     } else {
190         ret = csi2_dphy_s_stream_stop(sd);
191     }
192     mutex_unlock(&dphy->mutex);
193 
194     dev_info(dphy->dev, "%s stream on:%d, dphy%d\n", __func__, on, dphy->phy_index);
195 
196     return ret;
197 }
198 
csi2_dphy_g_frame_interval(struct v4l2_subdev * sd,struct v4l2_subdev_frame_interval * fi)199 static int csi2_dphy_g_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *fi)
200 {
201     struct v4l2_subdev *sensor = get_remote_sensor(sd);
202 
203     if (sensor) {
204         return v4l2_subdev_call(sensor, video, g_frame_interval, fi);
205     }
206 
207     return -EINVAL;
208 }
209 
csi2_dphy_g_mbus_config(struct v4l2_subdev * sd,unsigned int pad_id,struct v4l2_mbus_config * config)210 static int csi2_dphy_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id, struct v4l2_mbus_config *config)
211 {
212     struct csi2_dphy *dphy = to_csi2_dphy(sd);
213     struct v4l2_subdev *sensor_sd = get_remote_sensor(sd);
214     struct csi2_sensor *sensor;
215 
216     if (!sensor_sd) {
217         return -ENODEV;
218     }
219     sensor = sd_to_sensor(dphy, sensor_sd);
220     csi2_dphy_update_sensor_mbus(sd);
221     *config = sensor->mbus;
222 
223     return 0;
224 }
225 
csi2_dphy_s_power(struct v4l2_subdev * sd,int on)226 static int csi2_dphy_s_power(struct v4l2_subdev *sd, int on)
227 {
228     struct csi2_dphy *dphy = to_csi2_dphy(sd);
229 
230     if (on) {
231         return pm_runtime_get_sync(dphy->dev);
232     } else {
233         return pm_runtime_put(dphy->dev);
234     }
235 }
236 
csi2_dphy_runtime_suspend(struct device * dev)237 static __maybe_unused int csi2_dphy_runtime_suspend(struct device *dev)
238 {
239     struct media_entity *me = dev_get_drvdata(dev);
240     struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(me);
241     struct csi2_dphy *dphy = to_csi2_dphy(sd);
242     struct csi2_dphy_hw *hw = dphy->dphy_hw;
243 
244     if (hw) {
245         clk_bulk_disable_unprepare(hw->num_clks, hw->clks_bulk);
246     }
247 
248     return 0;
249 }
250 
csi2_dphy_runtime_resume(struct device * dev)251 static __maybe_unused int csi2_dphy_runtime_resume(struct device *dev)
252 {
253     struct media_entity *me = dev_get_drvdata(dev);
254     struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(me);
255     struct csi2_dphy *dphy = to_csi2_dphy(sd);
256     struct csi2_dphy_hw *hw = dphy->dphy_hw;
257     int ret;
258 
259     if (hw) {
260         ret = clk_bulk_prepare_enable(hw->num_clks, hw->clks_bulk);
261         if (ret) {
262             dev_err(hw->dev, "failed to enable clks\n");
263             return ret;
264         }
265     }
266 
267     return 0;
268 }
269 
270 /* dphy accepts all fmt/size from sensor */
csi2_dphy_get_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)271 static int csi2_dphy_get_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
272                                  struct v4l2_subdev_format *fmt)
273 {
274     struct csi2_dphy *dphy = to_csi2_dphy(sd);
275     struct v4l2_subdev *sensor_sd = get_remote_sensor(sd);
276     struct csi2_sensor *sensor = sd_to_sensor(dphy, sensor_sd);
277     int ret;
278     /*
279      * Do not allow format changes and just relay whatever
280      * set currently in the sensor.
281      */
282     if (!sensor_sd) {
283         return -ENODEV;
284     }
285     ret = v4l2_subdev_call(sensor_sd, pad, get_fmt, NULL, fmt);
286     if (!ret && fmt->pad == 0) {
287         sensor->format = fmt->format;
288     }
289     return ret;
290 }
291 
csi2_dphy_get_selection(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_selection * sel)292 static int csi2_dphy_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
293                                    struct v4l2_subdev_selection *sel)
294 {
295     struct v4l2_subdev *sensor = get_remote_sensor(sd);
296 
297     return v4l2_subdev_call(sensor, pad, get_selection, NULL, sel);
298 }
299 
300 static const struct v4l2_subdev_core_ops csi2_dphy_core_ops = {
301     .s_power = csi2_dphy_s_power,
302 };
303 
304 static const struct v4l2_subdev_video_ops csi2_dphy_video_ops = {
305     .g_frame_interval = csi2_dphy_g_frame_interval,
306     .s_stream = csi2_dphy_s_stream,
307 };
308 
309 static const struct v4l2_subdev_pad_ops csi2_dphy_subdev_pad_ops = {
310     .set_fmt = csi2_dphy_get_set_fmt,
311     .get_fmt = csi2_dphy_get_set_fmt,
312     .get_selection = csi2_dphy_get_selection,
313     .get_mbus_config = csi2_dphy_g_mbus_config,
314 };
315 
316 static const struct v4l2_subdev_ops csi2_dphy_subdev_ops = {
317     .core = &csi2_dphy_core_ops,
318     .video = &csi2_dphy_video_ops,
319     .pad = &csi2_dphy_subdev_pad_ops,
320 };
321 
322 /* The .bound() notifier callback when a match is found */
rockchip_csi2_dphy_notifier_bound(struct v4l2_async_notifier * notifier,struct v4l2_subdev * sd,struct v4l2_async_subdev * asd)323 static int rockchip_csi2_dphy_notifier_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd,
324                                              struct v4l2_async_subdev *asd)
325 {
326     struct csi2_dphy *dphy = container_of(notifier, struct csi2_dphy, notifier);
327     struct sensor_async_subdev *s_asd = container_of(asd, struct sensor_async_subdev, asd);
328     struct csi2_sensor *sensor;
329     unsigned int pad, ret;
330 
331     if (dphy->num_sensors == ARRAY_SIZE(dphy->sensors)) {
332         return -EBUSY;
333     }
334 
335     sensor = &dphy->sensors[dphy->num_sensors++];
336     sensor->lanes = s_asd->lanes;
337     sensor->mbus = s_asd->mbus;
338     sensor->sd = sd;
339 
340     dev_info(dphy->dev, "dphy%d matches %s:bus type %d\n", dphy->phy_index, sd->name, s_asd->mbus.type);
341 
342     for (pad = 0; pad < sensor->sd->entity.num_pads; pad++) {
343         if (sensor->sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE) {
344             break;
345         }
346     }
347 
348     if (pad == sensor->sd->entity.num_pads) {
349         dev_err(dphy->dev, "failed to find src pad for %s\n", sensor->sd->name);
350 
351         return -ENXIO;
352     }
353 
354     ret = media_create_pad_link(&sensor->sd->entity, pad, &dphy->sd.entity, CSI2_DPHY_RX_PAD_SINK,
355                                 dphy->num_sensors != 1 ? 0 : MEDIA_LNK_FL_ENABLED);
356     if (ret) {
357         dev_err(dphy->dev, "failed to create link for %s\n", sensor->sd->name);
358         return ret;
359     }
360 
361     return 0;
362 }
363 
364 /* The .unbind callback */
rockchip_csi2_dphy_notifier_unbind(struct v4l2_async_notifier * notifier,struct v4l2_subdev * sd,struct v4l2_async_subdev * asd)365 static void rockchip_csi2_dphy_notifier_unbind(struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd,
366                                                struct v4l2_async_subdev *asd)
367 {
368     struct csi2_dphy *dphy = container_of(notifier, struct csi2_dphy, notifier);
369     struct csi2_sensor *sensor = sd_to_sensor(dphy, sd);
370 
371     sensor->sd = NULL;
372 }
373 
374 static const struct v4l2_async_notifier_operations rockchip_csi2_dphy_async_ops = {
375     .bound = rockchip_csi2_dphy_notifier_bound,
376     .unbind = rockchip_csi2_dphy_notifier_unbind,
377 };
378 
rockchip_csi2_dphy_fwnode_parse(struct device * dev,struct v4l2_fwnode_endpoint * vep,struct v4l2_async_subdev * asd)379 static int rockchip_csi2_dphy_fwnode_parse(struct device *dev, struct v4l2_fwnode_endpoint *vep,
380                                            struct v4l2_async_subdev *asd)
381 {
382     struct sensor_async_subdev *s_asd = container_of(asd, struct sensor_async_subdev, asd);
383     struct v4l2_mbus_config *config = &s_asd->mbus;
384 
385     if (vep->base.port != 0) {
386         dev_err(dev, "The PHY has only port 0\n");
387         return -EINVAL;
388     }
389 
390     if (vep->bus_type == V4L2_MBUS_CSI2_DPHY) {
391         config->type = V4L2_MBUS_CSI2_DPHY;
392         config->flags = vep->bus.mipi_csi2.flags;
393         s_asd->lanes = vep->bus.mipi_csi2.num_data_lanes;
394     } else {
395         dev_err(dev, "Only CSI2 type is currently supported\n");
396         return -EINVAL;
397     }
398 
399     switch (s_asd->lanes) {
400         case 1:
401             config->flags |= V4L2_MBUS_CSI2_1_LANE;
402             break;
403         case 0x02:
404             config->flags |= V4L2_MBUS_CSI2_2_LANE;
405             break;
406         case 0x03:
407             config->flags |= V4L2_MBUS_CSI2_3_LANE;
408             break;
409         case 0x04:
410             config->flags |= V4L2_MBUS_CSI2_4_LANE;
411             break;
412         default:
413             return -EINVAL;
414     }
415 
416     return 0;
417 }
418 
rockchip_csi2dphy_media_init(struct csi2_dphy * dphy)419 static int rockchip_csi2dphy_media_init(struct csi2_dphy *dphy)
420 {
421     int ret;
422 
423     dphy->pads[CSI2_DPHY_RX_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT;
424     dphy->pads[CSI2_DPHY_RX_PAD_SINK].flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
425     dphy->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
426     ret = media_entity_pads_init(&dphy->sd.entity, CSI2_DPHY_RX_PADS_NUM, dphy->pads);
427     if (ret < 0) {
428         return ret;
429     }
430 
431     v4l2_async_notifier_init(&dphy->notifier);
432 
433     ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(
434         dphy->dev, &dphy->notifier, sizeof(struct sensor_async_subdev), 0, rockchip_csi2_dphy_fwnode_parse);
435     if (ret < 0) {
436         return ret;
437     }
438 
439     dphy->sd.subdev_notifier = &dphy->notifier;
440     dphy->notifier.ops = &rockchip_csi2_dphy_async_ops;
441     ret = v4l2_async_subdev_notifier_register(&dphy->sd, &dphy->notifier);
442     if (ret) {
443         dev_err(dphy->dev, "failed to register async notifier : %d\n", ret);
444         v4l2_async_notifier_cleanup(&dphy->notifier);
445         return ret;
446     }
447 
448     return v4l2_async_register_subdev(&dphy->sd);
449 }
450 
rockchip_csi2_dphy_attach_hw(struct csi2_dphy * dphy)451 static int rockchip_csi2_dphy_attach_hw(struct csi2_dphy *dphy)
452 {
453     struct platform_device *plat_dev;
454     struct device *dev = dphy->dev;
455     struct csi2_dphy_hw *dphy_hw;
456     struct device_node *np;
457     enum csi2_dphy_lane_mode target_mode;
458     int i;
459 
460     if (dphy->phy_index % 3 == 0) {
461         target_mode = LANE_MODE_FULL;
462     } else {
463         target_mode = LANE_MODE_SPLIT;
464     }
465 
466     np = of_parse_phandle(dev->of_node, "rockchip,hw", 0);
467     if (!np || !of_device_is_available(np)) {
468         dev_err(dphy->dev, "failed to get dphy%d hw node\n", dphy->phy_index);
469         return -ENODEV;
470     }
471 
472     plat_dev = of_find_device_by_node(np);
473     of_node_put(np);
474     if (!plat_dev) {
475         dev_err(dphy->dev, "failed to get dphy%d hw from node\n", dphy->phy_index);
476         return -ENODEV;
477     }
478 
479     dphy_hw = platform_get_drvdata(plat_dev);
480     if (!dphy_hw) {
481         dev_err(dphy->dev, "failed attach dphy%d hw\n", dphy->phy_index);
482         return -EINVAL;
483     }
484 
485     if (dphy_hw->lane_mode == LANE_MODE_UNDEF) {
486         dphy_hw->lane_mode = target_mode;
487     } else {
488         struct csi2_dphy *phy = dphy_hw->dphy_dev[0];
489 
490         for (i = 0; i < dphy_hw->dphy_dev_num; i++) {
491             if (dphy_hw->dphy_dev[i]->lane_mode == dphy_hw->lane_mode) {
492                 phy = dphy_hw->dphy_dev[i];
493                 break;
494             }
495         }
496 
497         if (target_mode != dphy_hw->lane_mode) {
498             dev_err(dphy->dev, "Err:csi2 dphy hw has been set as %s mode by phy%d, target mode is:%s\n",
499                     dphy_hw->lane_mode == LANE_MODE_FULL ? "full" : "split", phy->phy_index,
500                     target_mode == LANE_MODE_FULL ? "full" : "split");
501             return -ENODEV;
502         }
503     }
504 
505     dphy_hw->dphy_dev[dphy_hw->dphy_dev_num] = dphy;
506     dphy_hw->dphy_dev_num++;
507     dphy->dphy_hw = dphy_hw;
508 
509     return 0;
510 }
511 
rockchip_csi2_dphy_detach_hw(struct csi2_dphy * dphy)512 static int rockchip_csi2_dphy_detach_hw(struct csi2_dphy *dphy)
513 {
514     struct csi2_dphy_hw *dphy_hw = dphy->dphy_hw;
515     struct csi2_dphy *csi2_dphy = NULL;
516     int i;
517 
518     for (i = 0; i < dphy_hw->dphy_dev_num; i++) {
519         csi2_dphy = dphy_hw->dphy_dev[i];
520         if (csi2_dphy && csi2_dphy->phy_index == dphy->phy_index) {
521             dphy_hw->dphy_dev[i] = NULL;
522             dphy_hw->dphy_dev_num--;
523             break;
524         }
525     }
526 
527     return 0;
528 }
529 
530 static struct dphy_drv_data r3568_dphy_drv_data = {
531     .dev_name = "csi2dphy",
532 };
533 
534 static struct dphy_drv_data r3588_dcphy_drv_data = {
535     .dev_name = "csi2dcphy",
536 };
537 
538 static const struct of_device_id rockchip_csi2_dphy_match_id[] = {{
539     .compatible = "rockchip,rk3568-csi2-dphy",
540     .data = &r3568_dphy_drv_data,
541 }, {
542     .compatible = "rockchip,rk3588-csi2-dcphy",
543     .data = &r3588_dcphy_drv_data,
544 }, {
545 }};
546 MODULE_DEVICE_TABLE(of, rockchip_csi2_dphy_match_id);
547 
rockchip_csi2_dphy_probe(struct platform_device * pdev)548 static int rockchip_csi2_dphy_probe(struct platform_device *pdev)
549 {
550     struct device *dev = &pdev->dev;
551     const struct of_device_id *of_id;
552     struct csi2_dphy *csi2dphy;
553     struct v4l2_subdev *sd;
554     const struct dphy_drv_data *drv_data;
555     int ret;
556 
557     csi2dphy = devm_kzalloc(dev, sizeof(*csi2dphy), GFP_KERNEL);
558     if (!csi2dphy) {
559         return -ENOMEM;
560     }
561     csi2dphy->dev = dev;
562 
563     of_id = of_match_device(rockchip_csi2_dphy_match_id, dev);
564     if (!of_id) {
565         return -EINVAL;
566     }
567     drv_data = of_id->data;
568     csi2dphy->drv_data = drv_data;
569     csi2dphy->phy_index = of_alias_get_id(dev->of_node, drv_data->dev_name);
570     if (csi2dphy->phy_index < 0 || csi2dphy->phy_index >= PHY_MAX) {
571         csi2dphy->phy_index = 0;
572     }
573     ret = rockchip_csi2_dphy_attach_hw(csi2dphy);
574     if (ret) {
575         dev_err(dev, "csi2 dphy hw can't be attached, register dphy%d failed!\n", csi2dphy->phy_index);
576         return -ENODEV;
577     }
578 
579     sd = &csi2dphy->sd;
580     mutex_init(&csi2dphy->mutex);
581     v4l2_subdev_init(sd, &csi2_dphy_subdev_ops);
582     sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
583     snprintf(sd->name, sizeof(sd->name), "rockchip-csi2-dphy%d", csi2dphy->phy_index);
584     sd->dev = dev;
585 
586     platform_set_drvdata(pdev, &sd->entity);
587 
588     ret = rockchip_csi2dphy_media_init(csi2dphy);
589     if (ret < 0) {
590         goto detach_hw;
591     }
592 
593     pm_runtime_enable(&pdev->dev);
594 
595     dev_info(dev, "csi2 dphy%d probe successfully!\n", csi2dphy->phy_index);
596 
597     return 0;
598 
599 detach_hw:
600     mutex_destroy(&csi2dphy->mutex);
601     rockchip_csi2_dphy_detach_hw(csi2dphy);
602 
603     return 0;
604 }
605 
rockchip_csi2_dphy_remove(struct platform_device * pdev)606 static int rockchip_csi2_dphy_remove(struct platform_device *pdev)
607 {
608     struct media_entity *me = platform_get_drvdata(pdev);
609     struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(me);
610     struct csi2_dphy *dphy = to_csi2_dphy(sd);
611 
612     media_entity_cleanup(&sd->entity);
613 
614     pm_runtime_disable(&pdev->dev);
615     mutex_destroy(&dphy->mutex);
616     return 0;
617 }
618 
619 static const struct dev_pm_ops rockchip_csi2_dphy_pm_ops = {
620     SET_RUNTIME_PM_OPS(csi2_dphy_runtime_suspend, csi2_dphy_runtime_resume, NULL)};
621 
622 struct platform_driver rockchip_csi2_dphy_driver = {
623     .probe = rockchip_csi2_dphy_probe,
624     .remove = rockchip_csi2_dphy_remove,
625     .driver =
626         {
627             .name = "rockchip-csi2-dphy",
628             .pm = &rockchip_csi2_dphy_pm_ops,
629             .of_match_table = rockchip_csi2_dphy_match_id,
630         },
631 };
632 module_platform_driver(rockchip_csi2_dphy_driver);
633 
634 MODULE_AUTHOR("Rockchip Camera/ISP team");
635 MODULE_DESCRIPTION("Rockchip MIPI CSI2 DPHY driver");
636 MODULE_LICENSE("GPL v2");
637