162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Rockchip ISP1 Driver - Base driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2019 Collabora, Ltd.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd.
862306a36Sopenharmony_ci * Copyright (C) 2017 Rockchip Electronics Co., Ltd.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/clk.h>
1262306a36Sopenharmony_ci#include <linux/interrupt.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/of.h>
1562306a36Sopenharmony_ci#include <linux/of_graph.h>
1662306a36Sopenharmony_ci#include <linux/platform_device.h>
1762306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h>
1862306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1962306a36Sopenharmony_ci#include <media/v4l2-fwnode.h>
2062306a36Sopenharmony_ci#include <media/v4l2-mc.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include "rkisp1-common.h"
2362306a36Sopenharmony_ci#include "rkisp1-csi.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/*
2662306a36Sopenharmony_ci * ISP Details
2762306a36Sopenharmony_ci * -----------
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * ISP Comprises with:
3062306a36Sopenharmony_ci *	MIPI serial camera interface
3162306a36Sopenharmony_ci *	Image Signal Processing
3262306a36Sopenharmony_ci *	Many Image Enhancement Blocks
3362306a36Sopenharmony_ci *	Crop
3462306a36Sopenharmony_ci *	Resizer
3562306a36Sopenharmony_ci *	RBG display ready image
3662306a36Sopenharmony_ci *	Image Rotation
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci * ISP Block Diagram
3962306a36Sopenharmony_ci * -----------------
4062306a36Sopenharmony_ci *                                                             rkisp1-resizer.c          rkisp1-capture.c
4162306a36Sopenharmony_ci *                                                          |====================|  |=======================|
4262306a36Sopenharmony_ci *                                rkisp1-isp.c                              Main Picture Path
4362306a36Sopenharmony_ci *                        |==========================|      |===============================================|
4462306a36Sopenharmony_ci *                        +-----------+  +--+--+--+--+      +--------+  +--------+              +-----------+
4562306a36Sopenharmony_ci *                        |           |  |  |  |  |  |      |        |  |        |              |           |
4662306a36Sopenharmony_ci * +--------+    |\       |           |  |  |  |  |  |   -->|  Crop  |->|  RSZ   |------------->|           |
4762306a36Sopenharmony_ci * |  MIPI  |--->|  \     |           |  |  |  |  |  |   |  |        |  |        |              |           |
4862306a36Sopenharmony_ci * +--------+    |   |    |           |  |IE|IE|IE|IE|   |  +--------+  +--------+              |  Memory   |
4962306a36Sopenharmony_ci *               |MUX|--->|    ISP    |->|0 |1 |2 |3 |---+                                      | Interface |
5062306a36Sopenharmony_ci * +--------+    |   |    |           |  |  |  |  |  |   |  +--------+  +--------+  +--------+  |           |
5162306a36Sopenharmony_ci * |Parallel|--->|  /     |           |  |  |  |  |  |   |  |        |  |        |  |        |  |           |
5262306a36Sopenharmony_ci * +--------+    |/       |           |  |  |  |  |  |   -->|  Crop  |->|  RSZ   |->|  RGB   |->|           |
5362306a36Sopenharmony_ci *                        |           |  |  |  |  |  |      |        |  |        |  | Rotate |  |           |
5462306a36Sopenharmony_ci *                        +-----------+  +--+--+--+--+      +--------+  +--------+  +--------+  +-----------+
5562306a36Sopenharmony_ci *                                               ^
5662306a36Sopenharmony_ci * +--------+                                    |          |===============================================|
5762306a36Sopenharmony_ci * |  DMA   |------------------------------------+                          Self Picture Path
5862306a36Sopenharmony_ci * +--------+
5962306a36Sopenharmony_ci *
6062306a36Sopenharmony_ci *         rkisp1-stats.c        rkisp1-params.c
6162306a36Sopenharmony_ci *       |===============|      |===============|
6262306a36Sopenharmony_ci *       +---------------+      +---------------+
6362306a36Sopenharmony_ci *       |               |      |               |
6462306a36Sopenharmony_ci *       |      ISP      |      |      ISP      |
6562306a36Sopenharmony_ci *       |               |      |               |
6662306a36Sopenharmony_ci *       +---------------+      +---------------+
6762306a36Sopenharmony_ci *
6862306a36Sopenharmony_ci *
6962306a36Sopenharmony_ci * Media Topology
7062306a36Sopenharmony_ci * --------------
7162306a36Sopenharmony_ci *
7262306a36Sopenharmony_ci *          +----------+       +----------+
7362306a36Sopenharmony_ci *          | Sensor 1 |       | Sensor X |
7462306a36Sopenharmony_ci *          ------------  ...  ------------
7562306a36Sopenharmony_ci *          |    0     |       |    0     |
7662306a36Sopenharmony_ci *          +----------+       +----------+
7762306a36Sopenharmony_ci *               |                  |
7862306a36Sopenharmony_ci *                \----\       /----/
7962306a36Sopenharmony_ci *                     |       |
8062306a36Sopenharmony_ci *                     v       v
8162306a36Sopenharmony_ci *                  +-------------+
8262306a36Sopenharmony_ci *                  |      0      |
8362306a36Sopenharmony_ci *                  ---------------
8462306a36Sopenharmony_ci *                  |  CSI-2 RX   |
8562306a36Sopenharmony_ci *                  ---------------         +-----------+
8662306a36Sopenharmony_ci *                  |      1      |         |  params   |
8762306a36Sopenharmony_ci *                  +-------------+         | (output)  |
8862306a36Sopenharmony_ci *                         |               +-----------+
8962306a36Sopenharmony_ci *                         v                     |
9062306a36Sopenharmony_ci *                      +------+------+          |
9162306a36Sopenharmony_ci *                      |  0   |  1   |<---------+
9262306a36Sopenharmony_ci *                      |------+------|
9362306a36Sopenharmony_ci *                      |     ISP     |
9462306a36Sopenharmony_ci *                      |------+------|
9562306a36Sopenharmony_ci *        +-------------|  2   |  3   |----------+
9662306a36Sopenharmony_ci *        |             +------+------+          |
9762306a36Sopenharmony_ci *        |                |                     |
9862306a36Sopenharmony_ci *        v                v                     v
9962306a36Sopenharmony_ci *  +- ---------+    +-----------+         +-----------+
10062306a36Sopenharmony_ci *  |     0     |    |     0     |         |   stats   |
10162306a36Sopenharmony_ci *  -------------    -------------         | (capture) |
10262306a36Sopenharmony_ci *  |  Resizer  |    |  Resizer  |         +-----------+
10362306a36Sopenharmony_ci *  ------------|    ------------|
10462306a36Sopenharmony_ci *  |     1     |    |     1     |
10562306a36Sopenharmony_ci *  +-----------+    +-----------+
10662306a36Sopenharmony_ci *        |                |
10762306a36Sopenharmony_ci *        v                v
10862306a36Sopenharmony_ci *  +-----------+    +-----------+
10962306a36Sopenharmony_ci *  | selfpath  |    | mainpath  |
11062306a36Sopenharmony_ci *  | (capture) |    | (capture) |
11162306a36Sopenharmony_ci *  +-----------+    +-----------+
11262306a36Sopenharmony_ci */
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistruct rkisp1_isr_data {
11562306a36Sopenharmony_ci	const char *name;
11662306a36Sopenharmony_ci	irqreturn_t (*isr)(int irq, void *ctx);
11762306a36Sopenharmony_ci	u32 line_mask;
11862306a36Sopenharmony_ci};
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci/* ----------------------------------------------------------------------------
12162306a36Sopenharmony_ci * Sensor DT bindings
12262306a36Sopenharmony_ci */
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier,
12562306a36Sopenharmony_ci					struct v4l2_subdev *sd,
12662306a36Sopenharmony_ci					struct v4l2_async_connection *asc)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	struct rkisp1_device *rkisp1 =
12962306a36Sopenharmony_ci		container_of(notifier, struct rkisp1_device, notifier);
13062306a36Sopenharmony_ci	struct rkisp1_sensor_async *s_asd =
13162306a36Sopenharmony_ci		container_of(asc, struct rkisp1_sensor_async, asd);
13262306a36Sopenharmony_ci	int source_pad;
13362306a36Sopenharmony_ci	int ret;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	s_asd->sd = sd;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	source_pad = media_entity_get_fwnode_pad(&sd->entity, s_asd->source_ep,
13862306a36Sopenharmony_ci						 MEDIA_PAD_FL_SOURCE);
13962306a36Sopenharmony_ci	if (source_pad < 0) {
14062306a36Sopenharmony_ci		dev_err(rkisp1->dev, "failed to find source pad for %s\n",
14162306a36Sopenharmony_ci			sd->name);
14262306a36Sopenharmony_ci		return source_pad;
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	if (s_asd->port == 0)
14662306a36Sopenharmony_ci		return rkisp1_csi_link_sensor(rkisp1, sd, s_asd, source_pad);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	ret = media_create_pad_link(&sd->entity, source_pad,
14962306a36Sopenharmony_ci				    &rkisp1->isp.sd.entity,
15062306a36Sopenharmony_ci				    RKISP1_ISP_PAD_SINK_VIDEO,
15162306a36Sopenharmony_ci				    !s_asd->index ? MEDIA_LNK_FL_ENABLED : 0);
15262306a36Sopenharmony_ci	if (ret) {
15362306a36Sopenharmony_ci		dev_err(rkisp1->dev, "failed to link source pad of %s\n",
15462306a36Sopenharmony_ci			sd->name);
15562306a36Sopenharmony_ci		return ret;
15662306a36Sopenharmony_ci	}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	return 0;
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	struct rkisp1_device *rkisp1 =
16462306a36Sopenharmony_ci		container_of(notifier, struct rkisp1_device, notifier);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	return v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev);
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic void rkisp1_subdev_notifier_destroy(struct v4l2_async_connection *asc)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	struct rkisp1_sensor_async *rk_asd =
17262306a36Sopenharmony_ci		container_of(asc, struct rkisp1_sensor_async, asd);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	fwnode_handle_put(rk_asd->source_ep);
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic const struct v4l2_async_notifier_operations rkisp1_subdev_notifier_ops = {
17862306a36Sopenharmony_ci	.bound = rkisp1_subdev_notifier_bound,
17962306a36Sopenharmony_ci	.complete = rkisp1_subdev_notifier_complete,
18062306a36Sopenharmony_ci	.destroy = rkisp1_subdev_notifier_destroy,
18162306a36Sopenharmony_ci};
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic int rkisp1_subdev_notifier_register(struct rkisp1_device *rkisp1)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	struct v4l2_async_notifier *ntf = &rkisp1->notifier;
18662306a36Sopenharmony_ci	struct fwnode_handle *fwnode = dev_fwnode(rkisp1->dev);
18762306a36Sopenharmony_ci	struct fwnode_handle *ep;
18862306a36Sopenharmony_ci	unsigned int index = 0;
18962306a36Sopenharmony_ci	int ret = 0;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	v4l2_async_nf_init(ntf, &rkisp1->v4l2_dev);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	ntf->ops = &rkisp1_subdev_notifier_ops;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	fwnode_graph_for_each_endpoint(fwnode, ep) {
19662306a36Sopenharmony_ci		struct fwnode_handle *port;
19762306a36Sopenharmony_ci		struct v4l2_fwnode_endpoint vep = { };
19862306a36Sopenharmony_ci		struct rkisp1_sensor_async *rk_asd;
19962306a36Sopenharmony_ci		struct fwnode_handle *source;
20062306a36Sopenharmony_ci		u32 reg = 0;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci		/* Select the bus type based on the port. */
20362306a36Sopenharmony_ci		port = fwnode_get_parent(ep);
20462306a36Sopenharmony_ci		fwnode_property_read_u32(port, "reg", &reg);
20562306a36Sopenharmony_ci		fwnode_handle_put(port);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci		switch (reg) {
20862306a36Sopenharmony_ci		case 0:
20962306a36Sopenharmony_ci			/* MIPI CSI-2 port */
21062306a36Sopenharmony_ci			if (!(rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2)) {
21162306a36Sopenharmony_ci				dev_err(rkisp1->dev,
21262306a36Sopenharmony_ci					"internal CSI must be available for port 0\n");
21362306a36Sopenharmony_ci				ret = -EINVAL;
21462306a36Sopenharmony_ci				break;
21562306a36Sopenharmony_ci			}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci			vep.bus_type = V4L2_MBUS_CSI2_DPHY;
21862306a36Sopenharmony_ci			break;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci		case 1:
22162306a36Sopenharmony_ci			/*
22262306a36Sopenharmony_ci			 * Parallel port. The bus-type property in DT is
22362306a36Sopenharmony_ci			 * mandatory for port 1, it will be used to determine if
22462306a36Sopenharmony_ci			 * it's PARALLEL or BT656.
22562306a36Sopenharmony_ci			 */
22662306a36Sopenharmony_ci			vep.bus_type = V4L2_MBUS_UNKNOWN;
22762306a36Sopenharmony_ci			break;
22862306a36Sopenharmony_ci		}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci		/* Parse the endpoint and validate the bus type. */
23162306a36Sopenharmony_ci		ret = v4l2_fwnode_endpoint_parse(ep, &vep);
23262306a36Sopenharmony_ci		if (ret) {
23362306a36Sopenharmony_ci			dev_err(rkisp1->dev, "failed to parse endpoint %pfw\n",
23462306a36Sopenharmony_ci				ep);
23562306a36Sopenharmony_ci			break;
23662306a36Sopenharmony_ci		}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci		if (vep.base.port == 1) {
23962306a36Sopenharmony_ci			if (vep.bus_type != V4L2_MBUS_PARALLEL &&
24062306a36Sopenharmony_ci			    vep.bus_type != V4L2_MBUS_BT656) {
24162306a36Sopenharmony_ci				dev_err(rkisp1->dev,
24262306a36Sopenharmony_ci					"port 1 must be parallel or BT656\n");
24362306a36Sopenharmony_ci				ret = -EINVAL;
24462306a36Sopenharmony_ci				break;
24562306a36Sopenharmony_ci			}
24662306a36Sopenharmony_ci		}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci		/* Add the async subdev to the notifier. */
24962306a36Sopenharmony_ci		source = fwnode_graph_get_remote_endpoint(ep);
25062306a36Sopenharmony_ci		if (!source) {
25162306a36Sopenharmony_ci			dev_err(rkisp1->dev,
25262306a36Sopenharmony_ci				"endpoint %pfw has no remote endpoint\n",
25362306a36Sopenharmony_ci				ep);
25462306a36Sopenharmony_ci			ret = -ENODEV;
25562306a36Sopenharmony_ci			break;
25662306a36Sopenharmony_ci		}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci		rk_asd = v4l2_async_nf_add_fwnode(ntf, source,
25962306a36Sopenharmony_ci						  struct rkisp1_sensor_async);
26062306a36Sopenharmony_ci		if (IS_ERR(rk_asd)) {
26162306a36Sopenharmony_ci			fwnode_handle_put(source);
26262306a36Sopenharmony_ci			ret = PTR_ERR(rk_asd);
26362306a36Sopenharmony_ci			break;
26462306a36Sopenharmony_ci		}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci		rk_asd->index = index++;
26762306a36Sopenharmony_ci		rk_asd->source_ep = source;
26862306a36Sopenharmony_ci		rk_asd->mbus_type = vep.bus_type;
26962306a36Sopenharmony_ci		rk_asd->port = vep.base.port;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci		if (vep.bus_type == V4L2_MBUS_CSI2_DPHY) {
27262306a36Sopenharmony_ci			rk_asd->mbus_flags = vep.bus.mipi_csi2.flags;
27362306a36Sopenharmony_ci			rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes;
27462306a36Sopenharmony_ci		} else {
27562306a36Sopenharmony_ci			rk_asd->mbus_flags = vep.bus.parallel.flags;
27662306a36Sopenharmony_ci		}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci		dev_dbg(rkisp1->dev, "registered ep id %d, bus type %u, %u lanes\n",
27962306a36Sopenharmony_ci			vep.base.id, rk_asd->mbus_type, rk_asd->lanes);
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	if (ret) {
28362306a36Sopenharmony_ci		fwnode_handle_put(ep);
28462306a36Sopenharmony_ci		v4l2_async_nf_cleanup(ntf);
28562306a36Sopenharmony_ci		return ret;
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	if (!index)
28962306a36Sopenharmony_ci		dev_dbg(rkisp1->dev, "no remote subdevice found\n");
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	ret = v4l2_async_nf_register(ntf);
29262306a36Sopenharmony_ci	if (ret) {
29362306a36Sopenharmony_ci		v4l2_async_nf_cleanup(ntf);
29462306a36Sopenharmony_ci		return ret;
29562306a36Sopenharmony_ci	}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	return 0;
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci/* ----------------------------------------------------------------------------
30162306a36Sopenharmony_ci * Power
30262306a36Sopenharmony_ci */
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic int __maybe_unused rkisp1_runtime_suspend(struct device *dev)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	rkisp1->irqs_enabled = false;
30962306a36Sopenharmony_ci	/* Make sure the IRQ handler will see the above */
31062306a36Sopenharmony_ci	mb();
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	/*
31362306a36Sopenharmony_ci	 * Wait until any running IRQ handler has returned. The IRQ handler
31462306a36Sopenharmony_ci	 * may get called even after this (as it's a shared interrupt line)
31562306a36Sopenharmony_ci	 * but the 'irqs_enabled' flag will make the handler return immediately.
31662306a36Sopenharmony_ci	 */
31762306a36Sopenharmony_ci	for (unsigned int il = 0; il < ARRAY_SIZE(rkisp1->irqs); ++il) {
31862306a36Sopenharmony_ci		if (rkisp1->irqs[il] == -1)
31962306a36Sopenharmony_ci			continue;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci		/* Skip if the irq line is the same as previous */
32262306a36Sopenharmony_ci		if (il == 0 || rkisp1->irqs[il - 1] != rkisp1->irqs[il])
32362306a36Sopenharmony_ci			synchronize_irq(rkisp1->irqs[il]);
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	clk_bulk_disable_unprepare(rkisp1->clk_size, rkisp1->clks);
32762306a36Sopenharmony_ci	return pinctrl_pm_select_sleep_state(dev);
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_cistatic int __maybe_unused rkisp1_runtime_resume(struct device *dev)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
33362306a36Sopenharmony_ci	int ret;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	ret = pinctrl_pm_select_default_state(dev);
33662306a36Sopenharmony_ci	if (ret)
33762306a36Sopenharmony_ci		return ret;
33862306a36Sopenharmony_ci	ret = clk_bulk_prepare_enable(rkisp1->clk_size, rkisp1->clks);
33962306a36Sopenharmony_ci	if (ret)
34062306a36Sopenharmony_ci		return ret;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	rkisp1->irqs_enabled = true;
34362306a36Sopenharmony_ci	/* Make sure the IRQ handler will see the above */
34462306a36Sopenharmony_ci	mb();
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	return 0;
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistatic const struct dev_pm_ops rkisp1_pm_ops = {
35062306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
35162306a36Sopenharmony_ci				pm_runtime_force_resume)
35262306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(rkisp1_runtime_suspend, rkisp1_runtime_resume, NULL)
35362306a36Sopenharmony_ci};
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci/* ----------------------------------------------------------------------------
35662306a36Sopenharmony_ci * Core
35762306a36Sopenharmony_ci */
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistatic int rkisp1_create_links(struct rkisp1_device *rkisp1)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	unsigned int i;
36262306a36Sopenharmony_ci	int ret;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) {
36562306a36Sopenharmony_ci		/* Link the CSI receiver to the ISP. */
36662306a36Sopenharmony_ci		ret = media_create_pad_link(&rkisp1->csi.sd.entity,
36762306a36Sopenharmony_ci					    RKISP1_CSI_PAD_SRC,
36862306a36Sopenharmony_ci					    &rkisp1->isp.sd.entity,
36962306a36Sopenharmony_ci					    RKISP1_ISP_PAD_SINK_VIDEO,
37062306a36Sopenharmony_ci					    MEDIA_LNK_FL_ENABLED);
37162306a36Sopenharmony_ci		if (ret)
37262306a36Sopenharmony_ci			return ret;
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	/* create ISP->RSZ->CAP links */
37662306a36Sopenharmony_ci	for (i = 0; i < 2; i++) {
37762306a36Sopenharmony_ci		struct media_entity *resizer =
37862306a36Sopenharmony_ci			&rkisp1->resizer_devs[i].sd.entity;
37962306a36Sopenharmony_ci		struct media_entity *capture =
38062306a36Sopenharmony_ci			&rkisp1->capture_devs[i].vnode.vdev.entity;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci		ret = media_create_pad_link(&rkisp1->isp.sd.entity,
38362306a36Sopenharmony_ci					    RKISP1_ISP_PAD_SOURCE_VIDEO,
38462306a36Sopenharmony_ci					    resizer, RKISP1_RSZ_PAD_SINK,
38562306a36Sopenharmony_ci					    MEDIA_LNK_FL_ENABLED);
38662306a36Sopenharmony_ci		if (ret)
38762306a36Sopenharmony_ci			return ret;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci		ret = media_create_pad_link(resizer, RKISP1_RSZ_PAD_SRC,
39062306a36Sopenharmony_ci					    capture, 0,
39162306a36Sopenharmony_ci					    MEDIA_LNK_FL_ENABLED |
39262306a36Sopenharmony_ci					    MEDIA_LNK_FL_IMMUTABLE);
39362306a36Sopenharmony_ci		if (ret)
39462306a36Sopenharmony_ci			return ret;
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	/* params links */
39862306a36Sopenharmony_ci	ret = media_create_pad_link(&rkisp1->params.vnode.vdev.entity, 0,
39962306a36Sopenharmony_ci				    &rkisp1->isp.sd.entity,
40062306a36Sopenharmony_ci				    RKISP1_ISP_PAD_SINK_PARAMS,
40162306a36Sopenharmony_ci				    MEDIA_LNK_FL_ENABLED |
40262306a36Sopenharmony_ci				    MEDIA_LNK_FL_IMMUTABLE);
40362306a36Sopenharmony_ci	if (ret)
40462306a36Sopenharmony_ci		return ret;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	/* 3A stats links */
40762306a36Sopenharmony_ci	return media_create_pad_link(&rkisp1->isp.sd.entity,
40862306a36Sopenharmony_ci				     RKISP1_ISP_PAD_SOURCE_STATS,
40962306a36Sopenharmony_ci				     &rkisp1->stats.vnode.vdev.entity, 0,
41062306a36Sopenharmony_ci				     MEDIA_LNK_FL_ENABLED |
41162306a36Sopenharmony_ci				     MEDIA_LNK_FL_IMMUTABLE);
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_cistatic void rkisp1_entities_unregister(struct rkisp1_device *rkisp1)
41562306a36Sopenharmony_ci{
41662306a36Sopenharmony_ci	if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2)
41762306a36Sopenharmony_ci		rkisp1_csi_unregister(rkisp1);
41862306a36Sopenharmony_ci	rkisp1_params_unregister(rkisp1);
41962306a36Sopenharmony_ci	rkisp1_stats_unregister(rkisp1);
42062306a36Sopenharmony_ci	rkisp1_capture_devs_unregister(rkisp1);
42162306a36Sopenharmony_ci	rkisp1_resizer_devs_unregister(rkisp1);
42262306a36Sopenharmony_ci	rkisp1_isp_unregister(rkisp1);
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic int rkisp1_entities_register(struct rkisp1_device *rkisp1)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	int ret;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	ret = rkisp1_isp_register(rkisp1);
43062306a36Sopenharmony_ci	if (ret)
43162306a36Sopenharmony_ci		goto error;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	ret = rkisp1_resizer_devs_register(rkisp1);
43462306a36Sopenharmony_ci	if (ret)
43562306a36Sopenharmony_ci		goto error;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	ret = rkisp1_capture_devs_register(rkisp1);
43862306a36Sopenharmony_ci	if (ret)
43962306a36Sopenharmony_ci		goto error;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	ret = rkisp1_stats_register(rkisp1);
44262306a36Sopenharmony_ci	if (ret)
44362306a36Sopenharmony_ci		goto error;
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	ret = rkisp1_params_register(rkisp1);
44662306a36Sopenharmony_ci	if (ret)
44762306a36Sopenharmony_ci		goto error;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) {
45062306a36Sopenharmony_ci		ret = rkisp1_csi_register(rkisp1);
45162306a36Sopenharmony_ci		if (ret)
45262306a36Sopenharmony_ci			goto error;
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	ret = rkisp1_create_links(rkisp1);
45662306a36Sopenharmony_ci	if (ret)
45762306a36Sopenharmony_ci		goto error;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	return 0;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cierror:
46262306a36Sopenharmony_ci	rkisp1_entities_unregister(rkisp1);
46362306a36Sopenharmony_ci	return ret;
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic irqreturn_t rkisp1_isr(int irq, void *ctx)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	irqreturn_t ret = IRQ_NONE;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	/*
47162306a36Sopenharmony_ci	 * Call rkisp1_capture_isr() first to handle the frame that
47262306a36Sopenharmony_ci	 * potentially completed using the current frame_sequence number before
47362306a36Sopenharmony_ci	 * it is potentially incremented by rkisp1_isp_isr() in the vertical
47462306a36Sopenharmony_ci	 * sync.
47562306a36Sopenharmony_ci	 */
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	if (rkisp1_capture_isr(irq, ctx) == IRQ_HANDLED)
47862306a36Sopenharmony_ci		ret = IRQ_HANDLED;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	if (rkisp1_isp_isr(irq, ctx) == IRQ_HANDLED)
48162306a36Sopenharmony_ci		ret = IRQ_HANDLED;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	if (rkisp1_csi_isr(irq, ctx) == IRQ_HANDLED)
48462306a36Sopenharmony_ci		ret = IRQ_HANDLED;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	return ret;
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_cistatic const char * const px30_isp_clks[] = {
49062306a36Sopenharmony_ci	"isp",
49162306a36Sopenharmony_ci	"aclk",
49262306a36Sopenharmony_ci	"hclk",
49362306a36Sopenharmony_ci	"pclk",
49462306a36Sopenharmony_ci};
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cistatic const struct rkisp1_isr_data px30_isp_isrs[] = {
49762306a36Sopenharmony_ci	{ "isp", rkisp1_isp_isr, BIT(RKISP1_IRQ_ISP) },
49862306a36Sopenharmony_ci	{ "mi", rkisp1_capture_isr, BIT(RKISP1_IRQ_MI) },
49962306a36Sopenharmony_ci	{ "mipi", rkisp1_csi_isr, BIT(RKISP1_IRQ_MIPI) },
50062306a36Sopenharmony_ci};
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_cistatic const struct rkisp1_info px30_isp_info = {
50362306a36Sopenharmony_ci	.clks = px30_isp_clks,
50462306a36Sopenharmony_ci	.clk_size = ARRAY_SIZE(px30_isp_clks),
50562306a36Sopenharmony_ci	.isrs = px30_isp_isrs,
50662306a36Sopenharmony_ci	.isr_size = ARRAY_SIZE(px30_isp_isrs),
50762306a36Sopenharmony_ci	.isp_ver = RKISP1_V12,
50862306a36Sopenharmony_ci	.features = RKISP1_FEATURE_MIPI_CSI2,
50962306a36Sopenharmony_ci};
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cistatic const char * const rk3399_isp_clks[] = {
51262306a36Sopenharmony_ci	"isp",
51362306a36Sopenharmony_ci	"aclk",
51462306a36Sopenharmony_ci	"hclk",
51562306a36Sopenharmony_ci};
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_cistatic const struct rkisp1_isr_data rk3399_isp_isrs[] = {
51862306a36Sopenharmony_ci	{ NULL, rkisp1_isr, BIT(RKISP1_IRQ_ISP) | BIT(RKISP1_IRQ_MI) | BIT(RKISP1_IRQ_MIPI) },
51962306a36Sopenharmony_ci};
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_cistatic const struct rkisp1_info rk3399_isp_info = {
52262306a36Sopenharmony_ci	.clks = rk3399_isp_clks,
52362306a36Sopenharmony_ci	.clk_size = ARRAY_SIZE(rk3399_isp_clks),
52462306a36Sopenharmony_ci	.isrs = rk3399_isp_isrs,
52562306a36Sopenharmony_ci	.isr_size = ARRAY_SIZE(rk3399_isp_isrs),
52662306a36Sopenharmony_ci	.isp_ver = RKISP1_V10,
52762306a36Sopenharmony_ci	.features = RKISP1_FEATURE_MIPI_CSI2,
52862306a36Sopenharmony_ci};
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cistatic const struct of_device_id rkisp1_of_match[] = {
53162306a36Sopenharmony_ci	{
53262306a36Sopenharmony_ci		.compatible = "rockchip,px30-cif-isp",
53362306a36Sopenharmony_ci		.data = &px30_isp_info,
53462306a36Sopenharmony_ci	},
53562306a36Sopenharmony_ci	{
53662306a36Sopenharmony_ci		.compatible = "rockchip,rk3399-cif-isp",
53762306a36Sopenharmony_ci		.data = &rk3399_isp_info,
53862306a36Sopenharmony_ci	},
53962306a36Sopenharmony_ci	{},
54062306a36Sopenharmony_ci};
54162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rkisp1_of_match);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic int rkisp1_probe(struct platform_device *pdev)
54462306a36Sopenharmony_ci{
54562306a36Sopenharmony_ci	const struct rkisp1_info *info;
54662306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
54762306a36Sopenharmony_ci	struct rkisp1_device *rkisp1;
54862306a36Sopenharmony_ci	struct v4l2_device *v4l2_dev;
54962306a36Sopenharmony_ci	unsigned int i;
55062306a36Sopenharmony_ci	int ret, irq;
55162306a36Sopenharmony_ci	u32 cif_id;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	rkisp1 = devm_kzalloc(dev, sizeof(*rkisp1), GFP_KERNEL);
55462306a36Sopenharmony_ci	if (!rkisp1)
55562306a36Sopenharmony_ci		return -ENOMEM;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	info = of_device_get_match_data(dev);
55862306a36Sopenharmony_ci	rkisp1->info = info;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	dev_set_drvdata(dev, rkisp1);
56162306a36Sopenharmony_ci	rkisp1->dev = dev;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	mutex_init(&rkisp1->stream_lock);
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	rkisp1->base_addr = devm_platform_ioremap_resource(pdev, 0);
56662306a36Sopenharmony_ci	if (IS_ERR(rkisp1->base_addr))
56762306a36Sopenharmony_ci		return PTR_ERR(rkisp1->base_addr);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	for (unsigned int il = 0; il < ARRAY_SIZE(rkisp1->irqs); ++il)
57062306a36Sopenharmony_ci		rkisp1->irqs[il] = -1;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	for (i = 0; i < info->isr_size; i++) {
57362306a36Sopenharmony_ci		irq = info->isrs[i].name
57462306a36Sopenharmony_ci		    ? platform_get_irq_byname(pdev, info->isrs[i].name)
57562306a36Sopenharmony_ci		    : platform_get_irq(pdev, i);
57662306a36Sopenharmony_ci		if (irq < 0)
57762306a36Sopenharmony_ci			return irq;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci		for (unsigned int il = 0; il < ARRAY_SIZE(rkisp1->irqs); ++il) {
58062306a36Sopenharmony_ci			if (info->isrs[i].line_mask & BIT(il))
58162306a36Sopenharmony_ci				rkisp1->irqs[il] = irq;
58262306a36Sopenharmony_ci		}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci		ret = devm_request_irq(dev, irq, info->isrs[i].isr, IRQF_SHARED,
58562306a36Sopenharmony_ci				       dev_driver_string(dev), dev);
58662306a36Sopenharmony_ci		if (ret) {
58762306a36Sopenharmony_ci			dev_err(dev, "request irq failed: %d\n", ret);
58862306a36Sopenharmony_ci			return ret;
58962306a36Sopenharmony_ci		}
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	for (i = 0; i < info->clk_size; i++)
59362306a36Sopenharmony_ci		rkisp1->clks[i].id = info->clks[i];
59462306a36Sopenharmony_ci	ret = devm_clk_bulk_get(dev, info->clk_size, rkisp1->clks);
59562306a36Sopenharmony_ci	if (ret)
59662306a36Sopenharmony_ci		return ret;
59762306a36Sopenharmony_ci	rkisp1->clk_size = info->clk_size;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	ret = pm_runtime_resume_and_get(&pdev->dev);
60262306a36Sopenharmony_ci	if (ret)
60362306a36Sopenharmony_ci		goto err_pm_runtime_disable;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	cif_id = rkisp1_read(rkisp1, RKISP1_CIF_VI_ID);
60662306a36Sopenharmony_ci	dev_dbg(rkisp1->dev, "CIF_ID 0x%08x\n", cif_id);
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	pm_runtime_put(&pdev->dev);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	rkisp1->media_dev.hw_revision = info->isp_ver;
61162306a36Sopenharmony_ci	strscpy(rkisp1->media_dev.model, RKISP1_DRIVER_NAME,
61262306a36Sopenharmony_ci		sizeof(rkisp1->media_dev.model));
61362306a36Sopenharmony_ci	rkisp1->media_dev.dev = &pdev->dev;
61462306a36Sopenharmony_ci	strscpy(rkisp1->media_dev.bus_info, RKISP1_BUS_INFO,
61562306a36Sopenharmony_ci		sizeof(rkisp1->media_dev.bus_info));
61662306a36Sopenharmony_ci	media_device_init(&rkisp1->media_dev);
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	v4l2_dev = &rkisp1->v4l2_dev;
61962306a36Sopenharmony_ci	v4l2_dev->mdev = &rkisp1->media_dev;
62062306a36Sopenharmony_ci	strscpy(v4l2_dev->name, RKISP1_DRIVER_NAME, sizeof(v4l2_dev->name));
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	ret = v4l2_device_register(rkisp1->dev, &rkisp1->v4l2_dev);
62362306a36Sopenharmony_ci	if (ret)
62462306a36Sopenharmony_ci		goto err_media_dev_cleanup;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	ret = media_device_register(&rkisp1->media_dev);
62762306a36Sopenharmony_ci	if (ret) {
62862306a36Sopenharmony_ci		dev_err(dev, "Failed to register media device: %d\n", ret);
62962306a36Sopenharmony_ci		goto err_unreg_v4l2_dev;
63062306a36Sopenharmony_ci	}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) {
63362306a36Sopenharmony_ci		ret = rkisp1_csi_init(rkisp1);
63462306a36Sopenharmony_ci		if (ret)
63562306a36Sopenharmony_ci			goto err_unreg_media_dev;
63662306a36Sopenharmony_ci	}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	ret = rkisp1_entities_register(rkisp1);
63962306a36Sopenharmony_ci	if (ret)
64062306a36Sopenharmony_ci		goto err_cleanup_csi;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	ret = rkisp1_subdev_notifier_register(rkisp1);
64362306a36Sopenharmony_ci	if (ret)
64462306a36Sopenharmony_ci		goto err_unreg_entities;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	rkisp1_debug_init(rkisp1);
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	return 0;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_cierr_unreg_entities:
65162306a36Sopenharmony_ci	rkisp1_entities_unregister(rkisp1);
65262306a36Sopenharmony_cierr_cleanup_csi:
65362306a36Sopenharmony_ci	if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2)
65462306a36Sopenharmony_ci		rkisp1_csi_cleanup(rkisp1);
65562306a36Sopenharmony_cierr_unreg_media_dev:
65662306a36Sopenharmony_ci	media_device_unregister(&rkisp1->media_dev);
65762306a36Sopenharmony_cierr_unreg_v4l2_dev:
65862306a36Sopenharmony_ci	v4l2_device_unregister(&rkisp1->v4l2_dev);
65962306a36Sopenharmony_cierr_media_dev_cleanup:
66062306a36Sopenharmony_ci	media_device_cleanup(&rkisp1->media_dev);
66162306a36Sopenharmony_cierr_pm_runtime_disable:
66262306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
66362306a36Sopenharmony_ci	return ret;
66462306a36Sopenharmony_ci}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_cistatic void rkisp1_remove(struct platform_device *pdev)
66762306a36Sopenharmony_ci{
66862306a36Sopenharmony_ci	struct rkisp1_device *rkisp1 = platform_get_drvdata(pdev);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	v4l2_async_nf_unregister(&rkisp1->notifier);
67162306a36Sopenharmony_ci	v4l2_async_nf_cleanup(&rkisp1->notifier);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	rkisp1_entities_unregister(rkisp1);
67462306a36Sopenharmony_ci	if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2)
67562306a36Sopenharmony_ci		rkisp1_csi_cleanup(rkisp1);
67662306a36Sopenharmony_ci	rkisp1_debug_cleanup(rkisp1);
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	media_device_unregister(&rkisp1->media_dev);
67962306a36Sopenharmony_ci	v4l2_device_unregister(&rkisp1->v4l2_dev);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	media_device_cleanup(&rkisp1->media_dev);
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
68462306a36Sopenharmony_ci}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_cistatic struct platform_driver rkisp1_drv = {
68762306a36Sopenharmony_ci	.driver = {
68862306a36Sopenharmony_ci		.name = RKISP1_DRIVER_NAME,
68962306a36Sopenharmony_ci		.of_match_table = of_match_ptr(rkisp1_of_match),
69062306a36Sopenharmony_ci		.pm = &rkisp1_pm_ops,
69162306a36Sopenharmony_ci	},
69262306a36Sopenharmony_ci	.probe = rkisp1_probe,
69362306a36Sopenharmony_ci	.remove_new = rkisp1_remove,
69462306a36Sopenharmony_ci};
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_cimodule_platform_driver(rkisp1_drv);
69762306a36Sopenharmony_ciMODULE_DESCRIPTION("Rockchip ISP1 platform driver");
69862306a36Sopenharmony_ciMODULE_LICENSE("Dual MIT/GPL");
699