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