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