xref: /linux/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c (revision cdce5b957d5ea5b10251de4d47e2e3d4ff474c58)
1e6938cc1SHelen Koike // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2e6938cc1SHelen Koike /*
3e6938cc1SHelen Koike  * Rockchip ISP1 Driver - Base driver
4e6938cc1SHelen Koike  *
5e6938cc1SHelen Koike  * Copyright (C) 2019 Collabora, Ltd.
6e6938cc1SHelen Koike  *
7e6938cc1SHelen Koike  * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd.
8e6938cc1SHelen Koike  * Copyright (C) 2017 Rockchip Electronics Co., Ltd.
9e6938cc1SHelen Koike  */
10e6938cc1SHelen Koike 
11e6938cc1SHelen Koike #include <linux/clk.h>
12e6938cc1SHelen Koike #include <linux/interrupt.h>
13e6938cc1SHelen Koike #include <linux/module.h>
14e6938cc1SHelen Koike #include <linux/of.h>
15e6938cc1SHelen Koike #include <linux/of_graph.h>
16e6938cc1SHelen Koike #include <linux/of_platform.h>
17e6938cc1SHelen Koike #include <linux/pinctrl/consumer.h>
18e6938cc1SHelen Koike #include <linux/phy/phy.h>
19e6938cc1SHelen Koike #include <linux/phy/phy-mipi-dphy.h>
20e6938cc1SHelen Koike #include <media/v4l2-fwnode.h>
21e6938cc1SHelen Koike 
22e6938cc1SHelen Koike #include "rkisp1-common.h"
23e6938cc1SHelen Koike 
24e6938cc1SHelen Koike /*
25e6938cc1SHelen Koike  * ISP Details
26e6938cc1SHelen Koike  * -----------
27e6938cc1SHelen Koike  *
28e6938cc1SHelen Koike  * ISP Comprises with:
29e6938cc1SHelen Koike  *	MIPI serial camera interface
30e6938cc1SHelen Koike  *	Image Signal Processing
31e6938cc1SHelen Koike  *	Many Image Enhancement Blocks
32e6938cc1SHelen Koike  *	Crop
33e6938cc1SHelen Koike  *	Resizer
34e6938cc1SHelen Koike  *	RBG display ready image
35e6938cc1SHelen Koike  *	Image Rotation
36e6938cc1SHelen Koike  *
37e6938cc1SHelen Koike  * ISP Block Diagram
38e6938cc1SHelen Koike  * -----------------
39e6938cc1SHelen Koike  *                                                             rkisp1-resizer.c          rkisp1-capture.c
40e6938cc1SHelen Koike  *                                                          |====================|  |=======================|
41e6938cc1SHelen Koike  *                                rkisp1-isp.c                              Main Picture Path
42e6938cc1SHelen Koike  *                        |==========================|      |===============================================|
43e6938cc1SHelen Koike  *                        +-----------+  +--+--+--+--+      +--------+  +--------+              +-----------+
44e6938cc1SHelen Koike  *                        |           |  |  |  |  |  |      |        |  |        |              |           |
45e6938cc1SHelen Koike  * +--------+    |\       |           |  |  |  |  |  |   -->|  Crop  |->|  RSZ   |------------->|           |
46e6938cc1SHelen Koike  * |  MIPI  |--->|  \     |           |  |  |  |  |  |   |  |        |  |        |              |           |
47e6938cc1SHelen Koike  * +--------+    |   |    |           |  |IE|IE|IE|IE|   |  +--------+  +--------+              |  Memory   |
48e6938cc1SHelen Koike  *               |MUX|--->|    ISP    |->|0 |1 |2 |3 |---+                                      | Interface |
49e6938cc1SHelen Koike  * +--------+    |   |    |           |  |  |  |  |  |   |  +--------+  +--------+  +--------+  |           |
50e6938cc1SHelen Koike  * |Parallel|--->|  /     |           |  |  |  |  |  |   |  |        |  |        |  |        |  |           |
51e6938cc1SHelen Koike  * +--------+    |/       |           |  |  |  |  |  |   -->|  Crop  |->|  RSZ   |->|  RGB   |->|           |
52e6938cc1SHelen Koike  *                        |           |  |  |  |  |  |      |        |  |        |  | Rotate |  |           |
53e6938cc1SHelen Koike  *                        +-----------+  +--+--+--+--+      +--------+  +--------+  +--------+  +-----------+
54e6938cc1SHelen Koike  *                                               ^
55e6938cc1SHelen Koike  * +--------+                                    |          |===============================================|
56e6938cc1SHelen Koike  * |  DMA   |------------------------------------+                          Self Picture Path
57e6938cc1SHelen Koike  * +--------+
58e6938cc1SHelen Koike  *
59e6938cc1SHelen Koike  *         rkisp1-stats.c        rkisp1-params.c
60e6938cc1SHelen Koike  *       |===============|      |===============|
61e6938cc1SHelen Koike  *       +---------------+      +---------------+
62e6938cc1SHelen Koike  *       |               |      |               |
63e6938cc1SHelen Koike  *       |      ISP      |      |      ISP      |
64e6938cc1SHelen Koike  *       |               |      |               |
65e6938cc1SHelen Koike  *       +---------------+      +---------------+
66e6938cc1SHelen Koike  *
67e6938cc1SHelen Koike  *
68e6938cc1SHelen Koike  * Media Topology
69e6938cc1SHelen Koike  * --------------
70e6938cc1SHelen Koike  *      +----------+     +----------+
71e6938cc1SHelen Koike  *      | Sensor 2 |     | Sensor X |
72e6938cc1SHelen Koike  *      ------------ ... ------------
73e6938cc1SHelen Koike  *      |    0     |     |    0     |
74e6938cc1SHelen Koike  *      +----------+     +----------+      +-----------+
75e6938cc1SHelen Koike  *                  \      |               |  params   |
76e6938cc1SHelen Koike  *                   \     |               | (output)  |
77e6938cc1SHelen Koike  *    +----------+    \    |               +-----------+
78e6938cc1SHelen Koike  *    | Sensor 1 |     v   v                     |
79e6938cc1SHelen Koike  *    ------------      +------+------+          |
80e6938cc1SHelen Koike  *    |    0     |----->|  0   |  1   |<---------+
81e6938cc1SHelen Koike  *    +----------+      |------+------|
82e6938cc1SHelen Koike  *                      |     ISP     |
83e6938cc1SHelen Koike  *                      |------+------|
84e6938cc1SHelen Koike  *        +-------------|  2   |  3   |----------+
85e6938cc1SHelen Koike  *        |             +------+------+          |
86e6938cc1SHelen Koike  *        |                |                     |
87e6938cc1SHelen Koike  *        v                v                     v
88e6938cc1SHelen Koike  *  +- ---------+    +-----------+         +-----------+
89e6938cc1SHelen Koike  *  |     0     |    |     0     |         |   stats   |
90e6938cc1SHelen Koike  *  -------------    -------------         | (capture) |
91e6938cc1SHelen Koike  *  |  Resizer  |    |  Resizer  |         +-----------+
92e6938cc1SHelen Koike  *  ------------|    ------------|
93e6938cc1SHelen Koike  *  |     1     |    |     1     |
94e6938cc1SHelen Koike  *  +-----------+    +-----------+
95e6938cc1SHelen Koike  *        |                |
96e6938cc1SHelen Koike  *        v                v
97e6938cc1SHelen Koike  *  +-----------+    +-----------+
98e6938cc1SHelen Koike  *  | selfpath  |    | mainpath  |
99e6938cc1SHelen Koike  *  | (capture) |    | (capture) |
100e6938cc1SHelen Koike  *  +-----------+    +-----------+
101e6938cc1SHelen Koike  */
102e6938cc1SHelen Koike 
10308818e6aSHeiko Stuebner struct rkisp1_isr_data {
10408818e6aSHeiko Stuebner 	const char *name;
10508818e6aSHeiko Stuebner 	irqreturn_t (*isr)(int irq, void *ctx);
10608818e6aSHeiko Stuebner };
10708818e6aSHeiko Stuebner 
108*cdce5b95SLaurent Pinchart struct rkisp1_info {
109e6938cc1SHelen Koike 	const char * const *clks;
11008818e6aSHeiko Stuebner 	unsigned int clk_size;
11108818e6aSHeiko Stuebner 	const struct rkisp1_isr_data *isrs;
11208818e6aSHeiko Stuebner 	unsigned int isr_size;
113fc672d80SHeiko Stuebner 	enum rkisp1_cif_isp_version isp_ver;
114e6938cc1SHelen Koike };
115e6938cc1SHelen Koike 
116e6938cc1SHelen Koike /* ----------------------------------------------------------------------------
117e6938cc1SHelen Koike  * Sensor DT bindings
118e6938cc1SHelen Koike  */
119e6938cc1SHelen Koike 
120e6938cc1SHelen Koike static int rkisp1_create_links(struct rkisp1_device *rkisp1)
121e6938cc1SHelen Koike {
122e6938cc1SHelen Koike 	struct media_entity *source, *sink;
123e6938cc1SHelen Koike 	unsigned int flags, source_pad;
124e6938cc1SHelen Koike 	struct v4l2_subdev *sd;
125e6938cc1SHelen Koike 	unsigned int i;
126e6938cc1SHelen Koike 	int ret;
127e6938cc1SHelen Koike 
128e6938cc1SHelen Koike 	/* sensor links */
129e6938cc1SHelen Koike 	flags = MEDIA_LNK_FL_ENABLED;
130e6938cc1SHelen Koike 	list_for_each_entry(sd, &rkisp1->v4l2_dev.subdevs, list) {
131e6938cc1SHelen Koike 		if (sd == &rkisp1->isp.sd ||
132e6938cc1SHelen Koike 		    sd == &rkisp1->resizer_devs[RKISP1_MAINPATH].sd ||
133e6938cc1SHelen Koike 		    sd == &rkisp1->resizer_devs[RKISP1_SELFPATH].sd)
134e6938cc1SHelen Koike 			continue;
135e6938cc1SHelen Koike 
136e6938cc1SHelen Koike 		ret = media_entity_get_fwnode_pad(&sd->entity, sd->fwnode,
137e6938cc1SHelen Koike 						  MEDIA_PAD_FL_SOURCE);
138e6938cc1SHelen Koike 		if (ret < 0) {
139e6938cc1SHelen Koike 			dev_err(rkisp1->dev, "failed to find src pad for %s\n",
140e6938cc1SHelen Koike 				sd->name);
141e6938cc1SHelen Koike 			return ret;
142e6938cc1SHelen Koike 		}
143e6938cc1SHelen Koike 		source_pad = ret;
144e6938cc1SHelen Koike 
145e6938cc1SHelen Koike 		ret = media_create_pad_link(&sd->entity, source_pad,
146e6938cc1SHelen Koike 					    &rkisp1->isp.sd.entity,
147e6938cc1SHelen Koike 					    RKISP1_ISP_PAD_SINK_VIDEO,
148e6938cc1SHelen Koike 					    flags);
149e6938cc1SHelen Koike 		if (ret)
150e6938cc1SHelen Koike 			return ret;
151e6938cc1SHelen Koike 
152e6938cc1SHelen Koike 		flags = 0;
153e6938cc1SHelen Koike 	}
154e6938cc1SHelen Koike 
155e6938cc1SHelen Koike 	flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE;
156e6938cc1SHelen Koike 
157e6938cc1SHelen Koike 	/* create ISP->RSZ->CAP links */
158e6938cc1SHelen Koike 	for (i = 0; i < 2; i++) {
159e6938cc1SHelen Koike 		source = &rkisp1->isp.sd.entity;
160e6938cc1SHelen Koike 		sink = &rkisp1->resizer_devs[i].sd.entity;
161e6938cc1SHelen Koike 		ret = media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_VIDEO,
162e6938cc1SHelen Koike 					    sink, RKISP1_RSZ_PAD_SINK,
163e6938cc1SHelen Koike 					    MEDIA_LNK_FL_ENABLED);
164e6938cc1SHelen Koike 		if (ret)
165e6938cc1SHelen Koike 			return ret;
166e6938cc1SHelen Koike 
167e6938cc1SHelen Koike 		source = sink;
168e6938cc1SHelen Koike 		sink = &rkisp1->capture_devs[i].vnode.vdev.entity;
169e6938cc1SHelen Koike 		ret = media_create_pad_link(source, RKISP1_RSZ_PAD_SRC,
170e6938cc1SHelen Koike 					    sink, 0, flags);
171e6938cc1SHelen Koike 		if (ret)
172e6938cc1SHelen Koike 			return ret;
173e6938cc1SHelen Koike 	}
174e6938cc1SHelen Koike 
175e6938cc1SHelen Koike 	/* params links */
176e6938cc1SHelen Koike 	source = &rkisp1->params.vnode.vdev.entity;
177e6938cc1SHelen Koike 	sink = &rkisp1->isp.sd.entity;
178e6938cc1SHelen Koike 	ret = media_create_pad_link(source, 0, sink,
179e6938cc1SHelen Koike 				    RKISP1_ISP_PAD_SINK_PARAMS, flags);
180e6938cc1SHelen Koike 	if (ret)
181e6938cc1SHelen Koike 		return ret;
182e6938cc1SHelen Koike 
183e6938cc1SHelen Koike 	/* 3A stats links */
184e6938cc1SHelen Koike 	source = &rkisp1->isp.sd.entity;
185e6938cc1SHelen Koike 	sink = &rkisp1->stats.vnode.vdev.entity;
186e6938cc1SHelen Koike 	return media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_STATS,
187e6938cc1SHelen Koike 				     sink, 0, flags);
188e6938cc1SHelen Koike }
189e6938cc1SHelen Koike 
190e6938cc1SHelen Koike static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier,
191e6938cc1SHelen Koike 					struct v4l2_subdev *sd,
192e6938cc1SHelen Koike 					struct v4l2_async_subdev *asd)
193e6938cc1SHelen Koike {
194e6938cc1SHelen Koike 	struct rkisp1_device *rkisp1 =
195e6938cc1SHelen Koike 		container_of(notifier, struct rkisp1_device, notifier);
196e6938cc1SHelen Koike 	struct rkisp1_sensor_async *s_asd =
197e6938cc1SHelen Koike 		container_of(asd, struct rkisp1_sensor_async, asd);
198e6938cc1SHelen Koike 
199e6938cc1SHelen Koike 	s_asd->pixel_rate_ctrl = v4l2_ctrl_find(sd->ctrl_handler,
200e6938cc1SHelen Koike 						V4L2_CID_PIXEL_RATE);
201e6938cc1SHelen Koike 	s_asd->sd = sd;
202e6938cc1SHelen Koike 	s_asd->dphy = devm_phy_get(rkisp1->dev, "dphy");
203e6938cc1SHelen Koike 	if (IS_ERR(s_asd->dphy)) {
204e6938cc1SHelen Koike 		if (PTR_ERR(s_asd->dphy) != -EPROBE_DEFER)
205e6938cc1SHelen Koike 			dev_err(rkisp1->dev, "Couldn't get the MIPI D-PHY\n");
206e6938cc1SHelen Koike 		return PTR_ERR(s_asd->dphy);
207e6938cc1SHelen Koike 	}
208e6938cc1SHelen Koike 
209e6938cc1SHelen Koike 	phy_init(s_asd->dphy);
210e6938cc1SHelen Koike 
211e6938cc1SHelen Koike 	return 0;
212e6938cc1SHelen Koike }
213e6938cc1SHelen Koike 
214e6938cc1SHelen Koike static void rkisp1_subdev_notifier_unbind(struct v4l2_async_notifier *notifier,
215e6938cc1SHelen Koike 					  struct v4l2_subdev *sd,
216e6938cc1SHelen Koike 					  struct v4l2_async_subdev *asd)
217e6938cc1SHelen Koike {
218e6938cc1SHelen Koike 	struct rkisp1_sensor_async *s_asd =
219e6938cc1SHelen Koike 		container_of(asd, struct rkisp1_sensor_async, asd);
220e6938cc1SHelen Koike 
221e6938cc1SHelen Koike 	phy_exit(s_asd->dphy);
222e6938cc1SHelen Koike }
223e6938cc1SHelen Koike 
224e6938cc1SHelen Koike static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier)
225e6938cc1SHelen Koike {
226e6938cc1SHelen Koike 	struct rkisp1_device *rkisp1 =
227e6938cc1SHelen Koike 		container_of(notifier, struct rkisp1_device, notifier);
228e6938cc1SHelen Koike 	int ret;
229e6938cc1SHelen Koike 
230e6938cc1SHelen Koike 	ret = rkisp1_create_links(rkisp1);
231e6938cc1SHelen Koike 	if (ret)
232e6938cc1SHelen Koike 		return ret;
233e6938cc1SHelen Koike 
234e6938cc1SHelen Koike 	ret = v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev);
235e6938cc1SHelen Koike 	if (ret)
236e6938cc1SHelen Koike 		return ret;
237e6938cc1SHelen Koike 
238e6938cc1SHelen Koike 	dev_dbg(rkisp1->dev, "Async subdev notifier completed\n");
239e6938cc1SHelen Koike 
240e6938cc1SHelen Koike 	return 0;
241e6938cc1SHelen Koike }
242e6938cc1SHelen Koike 
243e6938cc1SHelen Koike static const struct v4l2_async_notifier_operations rkisp1_subdev_notifier_ops = {
244e6938cc1SHelen Koike 	.bound = rkisp1_subdev_notifier_bound,
245e6938cc1SHelen Koike 	.unbind = rkisp1_subdev_notifier_unbind,
246e6938cc1SHelen Koike 	.complete = rkisp1_subdev_notifier_complete,
247e6938cc1SHelen Koike };
248e6938cc1SHelen Koike 
249e6938cc1SHelen Koike static int rkisp1_subdev_notifier(struct rkisp1_device *rkisp1)
250e6938cc1SHelen Koike {
251e6938cc1SHelen Koike 	struct v4l2_async_notifier *ntf = &rkisp1->notifier;
252e6938cc1SHelen Koike 	unsigned int next_id = 0;
253e6938cc1SHelen Koike 	int ret;
254e6938cc1SHelen Koike 
2553c8c1539SSakari Ailus 	v4l2_async_nf_init(ntf);
256e6938cc1SHelen Koike 
257e6938cc1SHelen Koike 	while (1) {
258e6938cc1SHelen Koike 		struct v4l2_fwnode_endpoint vep = {
259e6938cc1SHelen Koike 			.bus_type = V4L2_MBUS_CSI2_DPHY
260e6938cc1SHelen Koike 		};
261b01edcbdSLaurent Pinchart 		struct rkisp1_sensor_async *rk_asd;
262e6938cc1SHelen Koike 		struct fwnode_handle *ep;
263e6938cc1SHelen Koike 
264e6938cc1SHelen Koike 		ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(rkisp1->dev),
265e6938cc1SHelen Koike 						     0, next_id,
266e6938cc1SHelen Koike 						     FWNODE_GRAPH_ENDPOINT_NEXT);
267e6938cc1SHelen Koike 		if (!ep)
268e6938cc1SHelen Koike 			break;
269e6938cc1SHelen Koike 
270e6938cc1SHelen Koike 		ret = v4l2_fwnode_endpoint_parse(ep, &vep);
271e6938cc1SHelen Koike 		if (ret)
272e6938cc1SHelen Koike 			goto err_parse;
273e6938cc1SHelen Koike 
2743c8c1539SSakari Ailus 		rk_asd = v4l2_async_nf_add_fwnode_remote(ntf, ep,
2753c8c1539SSakari Ailus 							 struct
2763c8c1539SSakari Ailus 							 rkisp1_sensor_async);
277b01edcbdSLaurent Pinchart 		if (IS_ERR(rk_asd)) {
278b01edcbdSLaurent Pinchart 			ret = PTR_ERR(rk_asd);
279e6938cc1SHelen Koike 			goto err_parse;
280e6938cc1SHelen Koike 		}
281e6938cc1SHelen Koike 
282e6938cc1SHelen Koike 		rk_asd->mbus_type = vep.bus_type;
283e6938cc1SHelen Koike 		rk_asd->mbus_flags = vep.bus.mipi_csi2.flags;
284e6938cc1SHelen Koike 		rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes;
285e6938cc1SHelen Koike 
286e6938cc1SHelen Koike 		dev_dbg(rkisp1->dev, "registered ep id %d with %d lanes\n",
287e6938cc1SHelen Koike 			vep.base.id, rk_asd->lanes);
288e6938cc1SHelen Koike 
289e6938cc1SHelen Koike 		next_id = vep.base.id + 1;
290e6938cc1SHelen Koike 
291e6938cc1SHelen Koike 		fwnode_handle_put(ep);
292e6938cc1SHelen Koike 
293e6938cc1SHelen Koike 		continue;
294e6938cc1SHelen Koike err_parse:
295e6938cc1SHelen Koike 		fwnode_handle_put(ep);
2963c8c1539SSakari Ailus 		v4l2_async_nf_cleanup(ntf);
297e6938cc1SHelen Koike 		return ret;
298e6938cc1SHelen Koike 	}
299e6938cc1SHelen Koike 
300e6938cc1SHelen Koike 	if (next_id == 0)
301e6938cc1SHelen Koike 		dev_dbg(rkisp1->dev, "no remote subdevice found\n");
302e6938cc1SHelen Koike 	ntf->ops = &rkisp1_subdev_notifier_ops;
3033c8c1539SSakari Ailus 	ret = v4l2_async_nf_register(&rkisp1->v4l2_dev, ntf);
304e6938cc1SHelen Koike 	if (ret) {
3053c8c1539SSakari Ailus 		v4l2_async_nf_cleanup(ntf);
306e6938cc1SHelen Koike 		return ret;
307e6938cc1SHelen Koike 	}
308e6938cc1SHelen Koike 	return 0;
309e6938cc1SHelen Koike }
310e6938cc1SHelen Koike 
311e6938cc1SHelen Koike /* ----------------------------------------------------------------------------
312e6938cc1SHelen Koike  * Power
313e6938cc1SHelen Koike  */
314e6938cc1SHelen Koike 
315e6938cc1SHelen Koike static int __maybe_unused rkisp1_runtime_suspend(struct device *dev)
316e6938cc1SHelen Koike {
317e6938cc1SHelen Koike 	struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
318e6938cc1SHelen Koike 
319e6938cc1SHelen Koike 	clk_bulk_disable_unprepare(rkisp1->clk_size, rkisp1->clks);
320e6938cc1SHelen Koike 	return pinctrl_pm_select_sleep_state(dev);
321e6938cc1SHelen Koike }
322e6938cc1SHelen Koike 
323e6938cc1SHelen Koike static int __maybe_unused rkisp1_runtime_resume(struct device *dev)
324e6938cc1SHelen Koike {
325e6938cc1SHelen Koike 	struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
326e6938cc1SHelen Koike 	int ret;
327e6938cc1SHelen Koike 
328e6938cc1SHelen Koike 	ret = pinctrl_pm_select_default_state(dev);
329e6938cc1SHelen Koike 	if (ret)
330e6938cc1SHelen Koike 		return ret;
331e6938cc1SHelen Koike 	ret = clk_bulk_prepare_enable(rkisp1->clk_size, rkisp1->clks);
332e6938cc1SHelen Koike 	if (ret)
333e6938cc1SHelen Koike 		return ret;
334e6938cc1SHelen Koike 
335e6938cc1SHelen Koike 	return 0;
336e6938cc1SHelen Koike }
337e6938cc1SHelen Koike 
338e6938cc1SHelen Koike static const struct dev_pm_ops rkisp1_pm_ops = {
339e6938cc1SHelen Koike 	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
340e6938cc1SHelen Koike 				pm_runtime_force_resume)
341e6938cc1SHelen Koike 	SET_RUNTIME_PM_OPS(rkisp1_runtime_suspend, rkisp1_runtime_resume, NULL)
342e6938cc1SHelen Koike };
343e6938cc1SHelen Koike 
344e6938cc1SHelen Koike /* ----------------------------------------------------------------------------
345e6938cc1SHelen Koike  * Core
346e6938cc1SHelen Koike  */
347e6938cc1SHelen Koike 
3486ff02276SLaurent Pinchart static void rkisp1_entities_unregister(struct rkisp1_device *rkisp1)
3496ff02276SLaurent Pinchart {
3506ff02276SLaurent Pinchart 	rkisp1_params_unregister(rkisp1);
3516ff02276SLaurent Pinchart 	rkisp1_stats_unregister(rkisp1);
3526ff02276SLaurent Pinchart 	rkisp1_capture_devs_unregister(rkisp1);
3536ff02276SLaurent Pinchart 	rkisp1_resizer_devs_unregister(rkisp1);
3546ff02276SLaurent Pinchart 	rkisp1_isp_unregister(rkisp1);
3556ff02276SLaurent Pinchart }
3566ff02276SLaurent Pinchart 
357e6938cc1SHelen Koike static int rkisp1_entities_register(struct rkisp1_device *rkisp1)
358e6938cc1SHelen Koike {
359e6938cc1SHelen Koike 	int ret;
360e6938cc1SHelen Koike 
361e6938cc1SHelen Koike 	ret = rkisp1_isp_register(rkisp1);
362e6938cc1SHelen Koike 	if (ret)
3636ff02276SLaurent Pinchart 		goto error;
364e6938cc1SHelen Koike 
365e6938cc1SHelen Koike 	ret = rkisp1_resizer_devs_register(rkisp1);
366e6938cc1SHelen Koike 	if (ret)
3676ff02276SLaurent Pinchart 		goto error;
368e6938cc1SHelen Koike 
369e6938cc1SHelen Koike 	ret = rkisp1_capture_devs_register(rkisp1);
370e6938cc1SHelen Koike 	if (ret)
3716ff02276SLaurent Pinchart 		goto error;
372e6938cc1SHelen Koike 
373e6938cc1SHelen Koike 	ret = rkisp1_stats_register(rkisp1);
374e6938cc1SHelen Koike 	if (ret)
3756ff02276SLaurent Pinchart 		goto error;
376e6938cc1SHelen Koike 
377e6938cc1SHelen Koike 	ret = rkisp1_params_register(rkisp1);
378e6938cc1SHelen Koike 	if (ret)
3796ff02276SLaurent Pinchart 		goto error;
380e6938cc1SHelen Koike 
381e6938cc1SHelen Koike 	ret = rkisp1_subdev_notifier(rkisp1);
382e6938cc1SHelen Koike 	if (ret) {
383e6938cc1SHelen Koike 		dev_err(rkisp1->dev,
384e6938cc1SHelen Koike 			"Failed to register subdev notifier(%d)\n", ret);
3856ff02276SLaurent Pinchart 		goto error;
386e6938cc1SHelen Koike 	}
387e6938cc1SHelen Koike 
388e6938cc1SHelen Koike 	return 0;
3896ff02276SLaurent Pinchart 
3906ff02276SLaurent Pinchart error:
3916ff02276SLaurent Pinchart 	rkisp1_entities_unregister(rkisp1);
392e6938cc1SHelen Koike 	return ret;
393e6938cc1SHelen Koike }
394e6938cc1SHelen Koike 
395e6938cc1SHelen Koike static irqreturn_t rkisp1_isr(int irq, void *ctx)
396e6938cc1SHelen Koike {
397e6938cc1SHelen Koike 	/*
398e6938cc1SHelen Koike 	 * Call rkisp1_capture_isr() first to handle the frame that
399e6938cc1SHelen Koike 	 * potentially completed using the current frame_sequence number before
400e6938cc1SHelen Koike 	 * it is potentially incremented by rkisp1_isp_isr() in the vertical
401e6938cc1SHelen Koike 	 * sync.
402e6938cc1SHelen Koike 	 */
40308818e6aSHeiko Stuebner 	rkisp1_capture_isr(irq, ctx);
40408818e6aSHeiko Stuebner 	rkisp1_isp_isr(irq, ctx);
40508818e6aSHeiko Stuebner 	rkisp1_mipi_isr(irq, ctx);
406e6938cc1SHelen Koike 
407e6938cc1SHelen Koike 	return IRQ_HANDLED;
408e6938cc1SHelen Koike }
409e6938cc1SHelen Koike 
410ecf8d36fSHeiko Stuebner static const char * const px30_isp_clks[] = {
411ecf8d36fSHeiko Stuebner 	"isp",
412ecf8d36fSHeiko Stuebner 	"aclk",
413ecf8d36fSHeiko Stuebner 	"hclk",
414ecf8d36fSHeiko Stuebner 	"pclk",
415ecf8d36fSHeiko Stuebner };
416ecf8d36fSHeiko Stuebner 
417ecf8d36fSHeiko Stuebner static const struct rkisp1_isr_data px30_isp_isrs[] = {
418ecf8d36fSHeiko Stuebner 	{ "isp", rkisp1_isp_isr },
419ecf8d36fSHeiko Stuebner 	{ "mi", rkisp1_capture_isr },
420ecf8d36fSHeiko Stuebner 	{ "mipi", rkisp1_mipi_isr },
421ecf8d36fSHeiko Stuebner };
422ecf8d36fSHeiko Stuebner 
423*cdce5b95SLaurent Pinchart static const struct rkisp1_info px30_isp_info = {
424ecf8d36fSHeiko Stuebner 	.clks = px30_isp_clks,
425ecf8d36fSHeiko Stuebner 	.clk_size = ARRAY_SIZE(px30_isp_clks),
426ecf8d36fSHeiko Stuebner 	.isrs = px30_isp_isrs,
427ecf8d36fSHeiko Stuebner 	.isr_size = ARRAY_SIZE(px30_isp_isrs),
428ecf8d36fSHeiko Stuebner 	.isp_ver = RKISP1_V12,
429ecf8d36fSHeiko Stuebner };
430ecf8d36fSHeiko Stuebner 
431e6938cc1SHelen Koike static const char * const rk3399_isp_clks[] = {
432e6938cc1SHelen Koike 	"isp",
433e6938cc1SHelen Koike 	"aclk",
434e6938cc1SHelen Koike 	"hclk",
435e6938cc1SHelen Koike };
436e6938cc1SHelen Koike 
43708818e6aSHeiko Stuebner static const struct rkisp1_isr_data rk3399_isp_isrs[] = {
43808818e6aSHeiko Stuebner 	{ NULL, rkisp1_isr },
43908818e6aSHeiko Stuebner };
44008818e6aSHeiko Stuebner 
441*cdce5b95SLaurent Pinchart static const struct rkisp1_info rk3399_isp_info = {
442e6938cc1SHelen Koike 	.clks = rk3399_isp_clks,
44308818e6aSHeiko Stuebner 	.clk_size = ARRAY_SIZE(rk3399_isp_clks),
44408818e6aSHeiko Stuebner 	.isrs = rk3399_isp_isrs,
44508818e6aSHeiko Stuebner 	.isr_size = ARRAY_SIZE(rk3399_isp_isrs),
446fc672d80SHeiko Stuebner 	.isp_ver = RKISP1_V10,
447e6938cc1SHelen Koike };
448e6938cc1SHelen Koike 
449e6938cc1SHelen Koike static const struct of_device_id rkisp1_of_match[] = {
450e6938cc1SHelen Koike 	{
451ecf8d36fSHeiko Stuebner 		.compatible = "rockchip,px30-cif-isp",
452*cdce5b95SLaurent Pinchart 		.data = &px30_isp_info,
453ecf8d36fSHeiko Stuebner 	},
454ecf8d36fSHeiko Stuebner 	{
455e6938cc1SHelen Koike 		.compatible = "rockchip,rk3399-cif-isp",
456*cdce5b95SLaurent Pinchart 		.data = &rk3399_isp_info,
457e6938cc1SHelen Koike 	},
458e6938cc1SHelen Koike 	{},
459e6938cc1SHelen Koike };
460e6938cc1SHelen Koike MODULE_DEVICE_TABLE(of, rkisp1_of_match);
461e6938cc1SHelen Koike 
462e6938cc1SHelen Koike static int rkisp1_probe(struct platform_device *pdev)
463e6938cc1SHelen Koike {
464*cdce5b95SLaurent Pinchart 	const struct rkisp1_info *info;
465e6938cc1SHelen Koike 	struct device *dev = &pdev->dev;
466e6938cc1SHelen Koike 	struct rkisp1_device *rkisp1;
467e6938cc1SHelen Koike 	struct v4l2_device *v4l2_dev;
468e6938cc1SHelen Koike 	unsigned int i;
469e6938cc1SHelen Koike 	int ret, irq;
470196179c5SLaurent Pinchart 	u32 cif_id;
471e6938cc1SHelen Koike 
472*cdce5b95SLaurent Pinchart 	info = of_device_get_match_data(&pdev->dev);
473*cdce5b95SLaurent Pinchart 	if (!info)
474e6938cc1SHelen Koike 		return -ENODEV;
475e6938cc1SHelen Koike 
476e6938cc1SHelen Koike 	rkisp1 = devm_kzalloc(dev, sizeof(*rkisp1), GFP_KERNEL);
477e6938cc1SHelen Koike 	if (!rkisp1)
478e6938cc1SHelen Koike 		return -ENOMEM;
479e6938cc1SHelen Koike 
480e6938cc1SHelen Koike 	dev_set_drvdata(dev, rkisp1);
481e6938cc1SHelen Koike 	rkisp1->dev = dev;
482e6938cc1SHelen Koike 
483e6938cc1SHelen Koike 	mutex_init(&rkisp1->stream_lock);
484e6938cc1SHelen Koike 
485e6938cc1SHelen Koike 	rkisp1->base_addr = devm_platform_ioremap_resource(pdev, 0);
486e6938cc1SHelen Koike 	if (IS_ERR(rkisp1->base_addr))
487e6938cc1SHelen Koike 		return PTR_ERR(rkisp1->base_addr);
488e6938cc1SHelen Koike 
489*cdce5b95SLaurent Pinchart 	for (i = 0; i < info->isr_size; i++) {
490*cdce5b95SLaurent Pinchart 		irq = info->isrs[i].name
491*cdce5b95SLaurent Pinchart 		    ? platform_get_irq_byname(pdev, info->isrs[i].name)
492fd83ef8fSLaurent Pinchart 		    : platform_get_irq(pdev, i);
493e6938cc1SHelen Koike 		if (irq < 0)
494e6938cc1SHelen Koike 			return irq;
495e6938cc1SHelen Koike 
496*cdce5b95SLaurent Pinchart 		ret = devm_request_irq(dev, irq, info->isrs[i].isr, IRQF_SHARED,
497e6938cc1SHelen Koike 				       dev_driver_string(dev), dev);
498e6938cc1SHelen Koike 		if (ret) {
499e6938cc1SHelen Koike 			dev_err(dev, "request irq failed: %d\n", ret);
500e6938cc1SHelen Koike 			return ret;
501e6938cc1SHelen Koike 		}
50208818e6aSHeiko Stuebner 	}
503e6938cc1SHelen Koike 
504*cdce5b95SLaurent Pinchart 	for (i = 0; i < info->clk_size; i++)
505*cdce5b95SLaurent Pinchart 		rkisp1->clks[i].id = info->clks[i];
506*cdce5b95SLaurent Pinchart 	ret = devm_clk_bulk_get(dev, info->clk_size, rkisp1->clks);
507e6938cc1SHelen Koike 	if (ret)
508e6938cc1SHelen Koike 		return ret;
509*cdce5b95SLaurent Pinchart 	rkisp1->clk_size = info->clk_size;
510e6938cc1SHelen Koike 
511e6938cc1SHelen Koike 	pm_runtime_enable(&pdev->dev);
512e6938cc1SHelen Koike 
513196179c5SLaurent Pinchart 	ret = pm_runtime_resume_and_get(&pdev->dev);
514196179c5SLaurent Pinchart 	if (ret)
515196179c5SLaurent Pinchart 		goto err_pm_runtime_disable;
516196179c5SLaurent Pinchart 
517196179c5SLaurent Pinchart 	cif_id = rkisp1_read(rkisp1, RKISP1_CIF_VI_ID);
518196179c5SLaurent Pinchart 	dev_dbg(rkisp1->dev, "CIF_ID 0x%08x\n", cif_id);
519196179c5SLaurent Pinchart 
520196179c5SLaurent Pinchart 	pm_runtime_put(&pdev->dev);
521196179c5SLaurent Pinchart 
522*cdce5b95SLaurent Pinchart 	rkisp1->media_dev.hw_revision = info->isp_ver;
523e6938cc1SHelen Koike 	strscpy(rkisp1->media_dev.model, RKISP1_DRIVER_NAME,
524e6938cc1SHelen Koike 		sizeof(rkisp1->media_dev.model));
525e6938cc1SHelen Koike 	rkisp1->media_dev.dev = &pdev->dev;
526e6938cc1SHelen Koike 	strscpy(rkisp1->media_dev.bus_info, RKISP1_BUS_INFO,
527e6938cc1SHelen Koike 		sizeof(rkisp1->media_dev.bus_info));
528e6938cc1SHelen Koike 	media_device_init(&rkisp1->media_dev);
529e6938cc1SHelen Koike 
530e6938cc1SHelen Koike 	v4l2_dev = &rkisp1->v4l2_dev;
531e6938cc1SHelen Koike 	v4l2_dev->mdev = &rkisp1->media_dev;
532e6938cc1SHelen Koike 	strscpy(v4l2_dev->name, RKISP1_DRIVER_NAME, sizeof(v4l2_dev->name));
533e6938cc1SHelen Koike 
534e6938cc1SHelen Koike 	ret = v4l2_device_register(rkisp1->dev, &rkisp1->v4l2_dev);
535e6938cc1SHelen Koike 	if (ret)
53613c98102SLaurent Pinchart 		goto err_pm_runtime_disable;
537e6938cc1SHelen Koike 
538e6938cc1SHelen Koike 	ret = media_device_register(&rkisp1->media_dev);
539e6938cc1SHelen Koike 	if (ret) {
540e6938cc1SHelen Koike 		dev_err(dev, "Failed to register media device: %d\n", ret);
541e6938cc1SHelen Koike 		goto err_unreg_v4l2_dev;
542e6938cc1SHelen Koike 	}
543e6938cc1SHelen Koike 
544e6938cc1SHelen Koike 	ret = rkisp1_entities_register(rkisp1);
545e6938cc1SHelen Koike 	if (ret)
546e6938cc1SHelen Koike 		goto err_unreg_media_dev;
547e6938cc1SHelen Koike 
548e6938cc1SHelen Koike 	rkisp1_debug_init(rkisp1);
549e6938cc1SHelen Koike 
550e6938cc1SHelen Koike 	return 0;
551e6938cc1SHelen Koike 
552e6938cc1SHelen Koike err_unreg_media_dev:
553e6938cc1SHelen Koike 	media_device_unregister(&rkisp1->media_dev);
554e6938cc1SHelen Koike err_unreg_v4l2_dev:
555e6938cc1SHelen Koike 	v4l2_device_unregister(&rkisp1->v4l2_dev);
55613c98102SLaurent Pinchart err_pm_runtime_disable:
557e6938cc1SHelen Koike 	pm_runtime_disable(&pdev->dev);
558e6938cc1SHelen Koike 	return ret;
559e6938cc1SHelen Koike }
560e6938cc1SHelen Koike 
561e6938cc1SHelen Koike static int rkisp1_remove(struct platform_device *pdev)
562e6938cc1SHelen Koike {
563e6938cc1SHelen Koike 	struct rkisp1_device *rkisp1 = platform_get_drvdata(pdev);
564e6938cc1SHelen Koike 
5653c8c1539SSakari Ailus 	v4l2_async_nf_unregister(&rkisp1->notifier);
5663c8c1539SSakari Ailus 	v4l2_async_nf_cleanup(&rkisp1->notifier);
567e6938cc1SHelen Koike 
5686ff02276SLaurent Pinchart 	rkisp1_entities_unregister(rkisp1);
5698682037dSLaurent Pinchart 	rkisp1_debug_cleanup(rkisp1);
570e6938cc1SHelen Koike 
571e6938cc1SHelen Koike 	media_device_unregister(&rkisp1->media_dev);
572e6938cc1SHelen Koike 	v4l2_device_unregister(&rkisp1->v4l2_dev);
573e6938cc1SHelen Koike 
574e6938cc1SHelen Koike 	pm_runtime_disable(&pdev->dev);
575e6938cc1SHelen Koike 
576e6938cc1SHelen Koike 	return 0;
577e6938cc1SHelen Koike }
578e6938cc1SHelen Koike 
579e6938cc1SHelen Koike static struct platform_driver rkisp1_drv = {
580e6938cc1SHelen Koike 	.driver = {
581e6938cc1SHelen Koike 		.name = RKISP1_DRIVER_NAME,
582e6938cc1SHelen Koike 		.of_match_table = of_match_ptr(rkisp1_of_match),
583e6938cc1SHelen Koike 		.pm = &rkisp1_pm_ops,
584e6938cc1SHelen Koike 	},
585e6938cc1SHelen Koike 	.probe = rkisp1_probe,
586e6938cc1SHelen Koike 	.remove = rkisp1_remove,
587e6938cc1SHelen Koike };
588e6938cc1SHelen Koike 
589e6938cc1SHelen Koike module_platform_driver(rkisp1_drv);
590e6938cc1SHelen Koike MODULE_DESCRIPTION("Rockchip ISP1 platform driver");
591e6938cc1SHelen Koike MODULE_LICENSE("Dual MIT/GPL");
592