| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828 |
- // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
- /*
- * Rockchip ISP1 Driver - Base driver
- *
- * Copyright (C) 2019 Collabora, Ltd.
- *
- * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd.
- * Copyright (C) 2017 Rockchip Electronics Co., Ltd.
- */
- #include <linux/build_bug.h>
- #include <linux/clk.h>
- #include <linux/interrupt.h>
- #include <linux/mfd/syscon.h>
- #include <linux/module.h>
- #include <linux/of.h>
- #include <linux/of_graph.h>
- #include <linux/platform_device.h>
- #include <linux/pinctrl/consumer.h>
- #include <linux/pm_domain.h>
- #include <linux/pm_runtime.h>
- #include <media/v4l2-fwnode.h>
- #include <media/v4l2-mc.h>
- #include "rkisp1-common.h"
- #include "rkisp1-csi.h"
- /*
- * ISP Details
- * -----------
- *
- * ISP Comprises with:
- * MIPI serial camera interface
- * Image Signal Processing
- * Many Image Enhancement Blocks
- * Crop
- * Resizer
- * RBG display ready image
- * Image Rotation
- *
- * ISP Block Diagram
- * -----------------
- * rkisp1-resizer.c rkisp1-capture.c
- * |====================| |=======================|
- * rkisp1-isp.c Main Picture Path
- * |==========================| |===============================================|
- * +-----------+ +--+--+--+--+ +--------+ +--------+ +-----------+
- * | | | | | | | | | | | | |
- * +--------+ |\ | | | | | | | -->| Crop |->| RSZ |------------->| |
- * | MIPI |--->| \ | | | | | | | | | | | | | |
- * +--------+ | | | | |IE|IE|IE|IE| | +--------+ +--------+ | Memory |
- * |MUX|--->| ISP |->|0 |1 |2 |3 |---+ | Interface |
- * +--------+ | | | | | | | | | | +--------+ +--------+ +--------+ | |
- * |Parallel|--->| / | | | | | | | | | | | | | | | |
- * +--------+ |/ | | | | | | | -->| Crop |->| RSZ |->| RGB |->| |
- * | | | | | | | | | | | | Rotate | | |
- * +-----------+ +--+--+--+--+ +--------+ +--------+ +--------+ +-----------+
- * ^
- * +--------+ | |===============================================|
- * | DMA |------------------------------------+ Self Picture Path
- * +--------+
- *
- * rkisp1-stats.c rkisp1-params.c
- * |===============| |===============|
- * +---------------+ +---------------+
- * | | | |
- * | ISP | | ISP |
- * | | | |
- * +---------------+ +---------------+
- *
- *
- * Media Topology
- * --------------
- *
- * +----------+ +----------+
- * | Sensor 1 | | Sensor X |
- * ------------ ... ------------
- * | 0 | | 0 |
- * +----------+ +----------+
- * | |
- * \----\ /----/
- * | |
- * v v
- * +-------------+
- * | 0 |
- * ---------------
- * | CSI-2 RX |
- * --------------- +-----------+
- * | 1 | | params |
- * +-------------+ | (output) |
- * | +-----------+
- * v |
- * +------+------+ |
- * | 0 | 1 |<---------+
- * |------+------|
- * | ISP |
- * |------+------|
- * +-------------| 2 | 3 |----------+
- * | +------+------+ |
- * | | |
- * v v v
- * +- ---------+ +-----------+ +-----------+
- * | 0 | | 0 | | stats |
- * ------------- ------------- | (capture) |
- * | Resizer | | Resizer | +-----------+
- * ------------| ------------|
- * | 1 | | 1 |
- * +-----------+ +-----------+
- * | |
- * v v
- * +-----------+ +-----------+
- * | selfpath | | mainpath |
- * | (capture) | | (capture) |
- * +-----------+ +-----------+
- */
- struct rkisp1_isr_data {
- const char *name;
- irqreturn_t (*isr)(int irq, void *ctx);
- u32 line_mask;
- };
- /* ----------------------------------------------------------------------------
- * Sensor DT bindings
- */
- static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier,
- struct v4l2_subdev *sd,
- struct v4l2_async_connection *asc)
- {
- struct rkisp1_device *rkisp1 =
- container_of(notifier, struct rkisp1_device, notifier);
- struct rkisp1_sensor_async *s_asd =
- container_of(asc, struct rkisp1_sensor_async, asd);
- int source_pad;
- int ret;
- s_asd->sd = sd;
- source_pad = media_entity_get_fwnode_pad(&sd->entity, s_asd->source_ep,
- MEDIA_PAD_FL_SOURCE);
- if (source_pad < 0) {
- dev_err(rkisp1->dev, "failed to find source pad for %s\n",
- sd->name);
- return source_pad;
- }
- if (s_asd->port == 0)
- return rkisp1_csi_link_sensor(rkisp1, sd, s_asd, source_pad);
- ret = media_create_pad_link(&sd->entity, source_pad,
- &rkisp1->isp.sd.entity,
- RKISP1_ISP_PAD_SINK_VIDEO,
- !s_asd->index ? MEDIA_LNK_FL_ENABLED : 0);
- if (ret) {
- dev_err(rkisp1->dev, "failed to link source pad of %s\n",
- sd->name);
- return ret;
- }
- return 0;
- }
- static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier)
- {
- struct rkisp1_device *rkisp1 =
- container_of(notifier, struct rkisp1_device, notifier);
- return v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev);
- }
- static void rkisp1_subdev_notifier_destroy(struct v4l2_async_connection *asc)
- {
- struct rkisp1_sensor_async *rk_asd =
- container_of(asc, struct rkisp1_sensor_async, asd);
- fwnode_handle_put(rk_asd->source_ep);
- }
- static const struct v4l2_async_notifier_operations rkisp1_subdev_notifier_ops = {
- .bound = rkisp1_subdev_notifier_bound,
- .complete = rkisp1_subdev_notifier_complete,
- .destroy = rkisp1_subdev_notifier_destroy,
- };
- static int rkisp1_subdev_notifier_register(struct rkisp1_device *rkisp1)
- {
- struct v4l2_async_notifier *ntf = &rkisp1->notifier;
- struct fwnode_handle *fwnode = dev_fwnode(rkisp1->dev);
- struct fwnode_handle *ep;
- unsigned int index = 0;
- int ret = 0;
- v4l2_async_nf_init(ntf, &rkisp1->v4l2_dev);
- ntf->ops = &rkisp1_subdev_notifier_ops;
- fwnode_graph_for_each_endpoint(fwnode, ep) {
- struct fwnode_handle *port;
- struct v4l2_fwnode_endpoint vep = { };
- struct rkisp1_sensor_async *rk_asd;
- struct fwnode_handle *source;
- u32 reg = 0;
- /* Select the bus type based on the port. */
- port = fwnode_get_parent(ep);
- fwnode_property_read_u32(port, "reg", ®);
- fwnode_handle_put(port);
- switch (reg) {
- case 0:
- /* MIPI CSI-2 port */
- if (!rkisp1_has_feature(rkisp1, MIPI_CSI2)) {
- dev_err(rkisp1->dev,
- "internal CSI must be available for port 0\n");
- ret = -EINVAL;
- break;
- }
- vep.bus_type = V4L2_MBUS_CSI2_DPHY;
- break;
- case 1:
- /*
- * Parallel port. The bus-type property in DT is
- * mandatory for port 1, it will be used to determine if
- * it's PARALLEL or BT656.
- */
- vep.bus_type = V4L2_MBUS_UNKNOWN;
- break;
- }
- if (ret)
- break;
- /* Parse the endpoint and validate the bus type. */
- ret = v4l2_fwnode_endpoint_parse(ep, &vep);
- if (ret) {
- dev_err(rkisp1->dev, "failed to parse endpoint %pfw\n",
- ep);
- break;
- }
- if (vep.base.port == 1) {
- if (vep.bus_type != V4L2_MBUS_PARALLEL &&
- vep.bus_type != V4L2_MBUS_BT656) {
- dev_err(rkisp1->dev,
- "port 1 must be parallel or BT656\n");
- ret = -EINVAL;
- break;
- }
- }
- /* Add the async subdev to the notifier. */
- source = fwnode_graph_get_remote_endpoint(ep);
- if (!source) {
- dev_err(rkisp1->dev,
- "endpoint %pfw has no remote endpoint\n",
- ep);
- ret = -ENODEV;
- break;
- }
- rk_asd = v4l2_async_nf_add_fwnode(ntf, source,
- struct rkisp1_sensor_async);
- if (IS_ERR(rk_asd)) {
- fwnode_handle_put(source);
- ret = PTR_ERR(rk_asd);
- break;
- }
- rk_asd->index = index++;
- rk_asd->source_ep = source;
- rk_asd->mbus_type = vep.bus_type;
- rk_asd->port = vep.base.port;
- if (vep.bus_type == V4L2_MBUS_CSI2_DPHY) {
- rk_asd->mbus_flags = vep.bus.mipi_csi2.flags;
- rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes;
- } else {
- rk_asd->mbus_flags = vep.bus.parallel.flags;
- }
- dev_dbg(rkisp1->dev, "registered ep id %d, bus type %u, %u lanes\n",
- vep.base.id, rk_asd->mbus_type, rk_asd->lanes);
- }
- if (ret) {
- fwnode_handle_put(ep);
- v4l2_async_nf_cleanup(ntf);
- return ret;
- }
- if (!index)
- dev_dbg(rkisp1->dev, "no remote subdevice found\n");
- ret = v4l2_async_nf_register(ntf);
- if (ret) {
- v4l2_async_nf_cleanup(ntf);
- return ret;
- }
- return 0;
- }
- /* ----------------------------------------------------------------------------
- * Power
- */
- static int __maybe_unused rkisp1_runtime_suspend(struct device *dev)
- {
- struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
- rkisp1->irqs_enabled = false;
- /* Make sure the IRQ handler will see the above */
- mb();
- /*
- * Wait until any running IRQ handler has returned. The IRQ handler
- * may get called even after this (as it's a shared interrupt line)
- * but the 'irqs_enabled' flag will make the handler return immediately.
- */
- for (unsigned int il = 0; il < ARRAY_SIZE(rkisp1->irqs); ++il) {
- if (rkisp1->irqs[il] == -1)
- continue;
- /* Skip if the irq line is the same as previous */
- if (il == 0 || rkisp1->irqs[il - 1] != rkisp1->irqs[il])
- synchronize_irq(rkisp1->irqs[il]);
- }
- clk_bulk_disable_unprepare(rkisp1->clk_size, rkisp1->clks);
- return pinctrl_pm_select_sleep_state(dev);
- }
- static int __maybe_unused rkisp1_runtime_resume(struct device *dev)
- {
- struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
- int ret;
- ret = pinctrl_pm_select_default_state(dev);
- if (ret)
- return ret;
- ret = clk_bulk_prepare_enable(rkisp1->clk_size, rkisp1->clks);
- if (ret)
- return ret;
- rkisp1->irqs_enabled = true;
- /* Make sure the IRQ handler will see the above */
- mb();
- return 0;
- }
- static const struct dev_pm_ops rkisp1_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
- SET_RUNTIME_PM_OPS(rkisp1_runtime_suspend, rkisp1_runtime_resume, NULL)
- };
- /* ----------------------------------------------------------------------------
- * Core
- */
- static int rkisp1_create_links(struct rkisp1_device *rkisp1)
- {
- unsigned int dev_count = rkisp1_path_count(rkisp1);
- unsigned int i;
- int ret;
- if (rkisp1_has_feature(rkisp1, MIPI_CSI2)) {
- /* Link the CSI receiver to the ISP. */
- ret = media_create_pad_link(&rkisp1->csi.sd.entity,
- RKISP1_CSI_PAD_SRC,
- &rkisp1->isp.sd.entity,
- RKISP1_ISP_PAD_SINK_VIDEO,
- MEDIA_LNK_FL_ENABLED);
- if (ret)
- return ret;
- }
- /* create ISP->RSZ->CAP links */
- for (i = 0; i < dev_count; i++) {
- struct media_entity *resizer =
- &rkisp1->resizer_devs[i].sd.entity;
- struct media_entity *capture =
- &rkisp1->capture_devs[i].vnode.vdev.entity;
- ret = media_create_pad_link(&rkisp1->isp.sd.entity,
- RKISP1_ISP_PAD_SOURCE_VIDEO,
- resizer, RKISP1_RSZ_PAD_SINK,
- MEDIA_LNK_FL_ENABLED);
- if (ret)
- return ret;
- ret = media_create_pad_link(resizer, RKISP1_RSZ_PAD_SRC,
- capture, 0,
- MEDIA_LNK_FL_ENABLED |
- MEDIA_LNK_FL_IMMUTABLE);
- if (ret)
- return ret;
- }
- /* params links */
- ret = media_create_pad_link(&rkisp1->params.vnode.vdev.entity, 0,
- &rkisp1->isp.sd.entity,
- RKISP1_ISP_PAD_SINK_PARAMS,
- MEDIA_LNK_FL_ENABLED |
- MEDIA_LNK_FL_IMMUTABLE);
- if (ret)
- return ret;
- /* 3A stats links */
- return media_create_pad_link(&rkisp1->isp.sd.entity,
- RKISP1_ISP_PAD_SOURCE_STATS,
- &rkisp1->stats.vnode.vdev.entity, 0,
- MEDIA_LNK_FL_ENABLED |
- MEDIA_LNK_FL_IMMUTABLE);
- }
- static void rkisp1_entities_unregister(struct rkisp1_device *rkisp1)
- {
- if (rkisp1_has_feature(rkisp1, MIPI_CSI2))
- rkisp1_csi_unregister(rkisp1);
- rkisp1_params_unregister(rkisp1);
- rkisp1_stats_unregister(rkisp1);
- rkisp1_capture_devs_unregister(rkisp1);
- rkisp1_resizer_devs_unregister(rkisp1);
- rkisp1_isp_unregister(rkisp1);
- }
- static int rkisp1_entities_register(struct rkisp1_device *rkisp1)
- {
- int ret;
- ret = rkisp1_isp_register(rkisp1);
- if (ret)
- goto error;
- ret = rkisp1_resizer_devs_register(rkisp1);
- if (ret)
- goto error;
- ret = rkisp1_capture_devs_register(rkisp1);
- if (ret)
- goto error;
- ret = rkisp1_stats_register(rkisp1);
- if (ret)
- goto error;
- ret = rkisp1_params_register(rkisp1);
- if (ret)
- goto error;
- if (rkisp1_has_feature(rkisp1, MIPI_CSI2)) {
- ret = rkisp1_csi_register(rkisp1);
- if (ret)
- goto error;
- }
- ret = rkisp1_create_links(rkisp1);
- if (ret)
- goto error;
- return 0;
- error:
- rkisp1_entities_unregister(rkisp1);
- return ret;
- }
- static irqreturn_t rkisp1_isr(int irq, void *ctx)
- {
- irqreturn_t ret = IRQ_NONE;
- /*
- * Call rkisp1_capture_isr() first to handle the frame that
- * potentially completed using the current frame_sequence number before
- * it is potentially incremented by rkisp1_isp_isr() in the vertical
- * sync.
- */
- if (rkisp1_capture_isr(irq, ctx) == IRQ_HANDLED)
- ret = IRQ_HANDLED;
- if (rkisp1_isp_isr(irq, ctx) == IRQ_HANDLED)
- ret = IRQ_HANDLED;
- if (rkisp1_csi_isr(irq, ctx) == IRQ_HANDLED)
- ret = IRQ_HANDLED;
- return ret;
- }
- static const struct rkisp1_isr_data px30_isp_isrs[] = {
- { "isp", rkisp1_isp_isr, BIT(RKISP1_IRQ_ISP) },
- { "mi", rkisp1_capture_isr, BIT(RKISP1_IRQ_MI) },
- { "mipi", rkisp1_csi_isr, BIT(RKISP1_IRQ_MIPI) },
- };
- static const struct rkisp1_info px30_isp_info = {
- .num_clocks = 4,
- .isrs = px30_isp_isrs,
- .isr_size = ARRAY_SIZE(px30_isp_isrs),
- .isp_ver = RKISP1_V12,
- .features = RKISP1_FEATURE_MIPI_CSI2
- | RKISP1_FEATURE_SELF_PATH
- | RKISP1_FEATURE_DUAL_CROP
- | RKISP1_FEATURE_BLS,
- .max_width = 3264,
- .max_height = 2448,
- };
- static const struct rkisp1_isr_data rk3399_isp_isrs[] = {
- { NULL, rkisp1_isr, BIT(RKISP1_IRQ_ISP) | BIT(RKISP1_IRQ_MI) | BIT(RKISP1_IRQ_MIPI) },
- };
- static const struct rkisp1_info rk3399_isp_info = {
- .num_clocks = 3,
- .isrs = rk3399_isp_isrs,
- .isr_size = ARRAY_SIZE(rk3399_isp_isrs),
- .isp_ver = RKISP1_V10,
- .features = RKISP1_FEATURE_MIPI_CSI2
- | RKISP1_FEATURE_SELF_PATH
- | RKISP1_FEATURE_DUAL_CROP
- | RKISP1_FEATURE_BLS,
- .max_width = 4416,
- .max_height = 3312,
- };
- static const struct rkisp1_isr_data imx8mp_isp_isrs[] = {
- { NULL, rkisp1_isr, BIT(RKISP1_IRQ_ISP) | BIT(RKISP1_IRQ_MI) },
- };
- static const char * const imx8mp_isp_pm_domains[] = {
- "isp",
- "csi2",
- };
- static const struct rkisp1_info imx8mp_isp_info = {
- .num_clocks = 3,
- .isrs = imx8mp_isp_isrs,
- .isr_size = ARRAY_SIZE(imx8mp_isp_isrs),
- .isp_ver = RKISP1_V_IMX8MP,
- .features = RKISP1_FEATURE_MAIN_STRIDE
- | RKISP1_FEATURE_DMA_34BIT
- | RKISP1_FEATURE_COMPAND,
- .max_width = 4096,
- .max_height = 3072,
- .pm_domains = {
- .names = imx8mp_isp_pm_domains,
- .count = ARRAY_SIZE(imx8mp_isp_pm_domains),
- },
- };
- static const struct of_device_id rkisp1_of_match[] = {
- {
- .compatible = "rockchip,px30-cif-isp",
- .data = &px30_isp_info,
- },
- {
- .compatible = "rockchip,rk3399-cif-isp",
- .data = &rk3399_isp_info,
- },
- {
- .compatible = "fsl,imx8mp-isp",
- .data = &imx8mp_isp_info,
- },
- {},
- };
- MODULE_DEVICE_TABLE(of, rkisp1_of_match);
- static const char * const rkisp1_clk_names[] = {
- "isp",
- "aclk",
- "hclk",
- "pclk",
- };
- static int rkisp1_init_clocks(struct rkisp1_device *rkisp1)
- {
- const struct rkisp1_info *info = rkisp1->info;
- unsigned int i;
- int ret;
- static_assert(ARRAY_SIZE(rkisp1_clk_names) == ARRAY_SIZE(rkisp1->clks));
- for (i = 0; i < info->num_clocks; i++)
- rkisp1->clks[i].id = rkisp1_clk_names[i];
- ret = devm_clk_bulk_get(rkisp1->dev, info->num_clocks, rkisp1->clks);
- if (ret)
- return ret;
- rkisp1->clk_size = info->num_clocks;
- /*
- * On i.MX8MP the pclk clock is needed to access the HDR stitching
- * registers, but wasn't required by DT bindings. Try to acquire it as
- * an optional clock to avoid breaking backward compatibility.
- */
- if (info->isp_ver == RKISP1_V_IMX8MP) {
- struct clk *clk;
- clk = devm_clk_get_optional(rkisp1->dev, "pclk");
- if (IS_ERR(clk))
- return dev_err_probe(rkisp1->dev, PTR_ERR(clk),
- "Failed to acquire pclk clock\n");
- if (clk)
- rkisp1->clks[rkisp1->clk_size++].clk = clk;
- }
- return 0;
- }
- static int rkisp1_init_pm_domains(struct rkisp1_device *rkisp1)
- {
- const struct rkisp1_info *info = rkisp1->info;
- struct dev_pm_domain_attach_data pm_domain_data = {
- .pd_names = info->pm_domains.names,
- .num_pd_names = info->pm_domains.count,
- };
- int ret;
- /*
- * Most platforms have a single power domain, which the PM domain core
- * automatically attaches at probe time. When that's the case there's
- * nothing to do here.
- */
- if (rkisp1->dev->pm_domain)
- return 0;
- if (!pm_domain_data.num_pd_names)
- return 0;
- ret = devm_pm_domain_attach_list(rkisp1->dev, &pm_domain_data,
- &rkisp1->pm_domains);
- if (ret < 0) {
- dev_err_probe(rkisp1->dev, ret,
- "Failed to attach power domains\n");
- return ret;
- }
- return 0;
- }
- static int rkisp1_probe(struct platform_device *pdev)
- {
- const struct rkisp1_info *info;
- struct device *dev = &pdev->dev;
- struct rkisp1_device *rkisp1;
- struct v4l2_device *v4l2_dev;
- unsigned int i;
- u64 dma_mask;
- int ret, irq;
- u32 cif_id;
- rkisp1 = devm_kzalloc(dev, sizeof(*rkisp1), GFP_KERNEL);
- if (!rkisp1)
- return -ENOMEM;
- info = of_device_get_match_data(dev);
- rkisp1->info = info;
- dev_set_drvdata(dev, rkisp1);
- rkisp1->dev = dev;
- dma_mask = rkisp1_has_feature(rkisp1, DMA_34BIT) ? DMA_BIT_MASK(34) :
- DMA_BIT_MASK(32);
- ret = dma_set_mask_and_coherent(dev, dma_mask);
- if (ret)
- return ret;
- mutex_init(&rkisp1->stream_lock);
- rkisp1->base_addr = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(rkisp1->base_addr))
- return PTR_ERR(rkisp1->base_addr);
- for (unsigned int il = 0; il < ARRAY_SIZE(rkisp1->irqs); ++il)
- rkisp1->irqs[il] = -1;
- for (i = 0; i < info->isr_size; i++) {
- irq = info->isrs[i].name
- ? platform_get_irq_byname(pdev, info->isrs[i].name)
- : platform_get_irq(pdev, i);
- if (irq < 0)
- return irq;
- for (unsigned int il = 0; il < ARRAY_SIZE(rkisp1->irqs); ++il) {
- if (info->isrs[i].line_mask & BIT(il))
- rkisp1->irqs[il] = irq;
- }
- ret = devm_request_irq(dev, irq, info->isrs[i].isr, IRQF_SHARED,
- dev_driver_string(dev), dev);
- if (ret) {
- dev_err(dev, "request irq failed: %d\n", ret);
- return ret;
- }
- }
- ret = rkisp1_init_clocks(rkisp1);
- if (ret)
- return ret;
- ret = rkisp1_init_pm_domains(rkisp1);
- if (ret)
- return ret;
- if (info->isp_ver == RKISP1_V_IMX8MP) {
- unsigned int id;
- rkisp1->gasket = syscon_regmap_lookup_by_phandle_args(dev->of_node,
- "fsl,blk-ctrl",
- 1, &id);
- if (IS_ERR(rkisp1->gasket)) {
- ret = PTR_ERR(rkisp1->gasket);
- dev_err(dev, "failed to get gasket: %d\n", ret);
- return ret;
- }
- rkisp1->gasket_id = id;
- }
- pm_runtime_enable(&pdev->dev);
- ret = pm_runtime_resume_and_get(&pdev->dev);
- if (ret)
- goto err_pm_runtime_disable;
- cif_id = rkisp1_read(rkisp1, RKISP1_CIF_VI_ID);
- dev_dbg(rkisp1->dev, "CIF_ID 0x%08x\n", cif_id);
- pm_runtime_put(&pdev->dev);
- rkisp1->media_dev.hw_revision = info->isp_ver;
- strscpy(rkisp1->media_dev.model, RKISP1_DRIVER_NAME,
- sizeof(rkisp1->media_dev.model));
- rkisp1->media_dev.dev = &pdev->dev;
- strscpy(rkisp1->media_dev.bus_info, RKISP1_BUS_INFO,
- sizeof(rkisp1->media_dev.bus_info));
- media_device_init(&rkisp1->media_dev);
- v4l2_dev = &rkisp1->v4l2_dev;
- v4l2_dev->mdev = &rkisp1->media_dev;
- strscpy(v4l2_dev->name, RKISP1_DRIVER_NAME, sizeof(v4l2_dev->name));
- ret = v4l2_device_register(rkisp1->dev, &rkisp1->v4l2_dev);
- if (ret)
- goto err_media_dev_cleanup;
- ret = media_device_register(&rkisp1->media_dev);
- if (ret) {
- dev_err(dev, "Failed to register media device: %d\n", ret);
- goto err_unreg_v4l2_dev;
- }
- if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) {
- ret = rkisp1_csi_init(rkisp1);
- if (ret)
- goto err_unreg_media_dev;
- }
- ret = rkisp1_entities_register(rkisp1);
- if (ret)
- goto err_cleanup_csi;
- ret = rkisp1_subdev_notifier_register(rkisp1);
- if (ret)
- goto err_unreg_entities;
- rkisp1_debug_init(rkisp1);
- return 0;
- err_unreg_entities:
- rkisp1_entities_unregister(rkisp1);
- err_cleanup_csi:
- if (rkisp1_has_feature(rkisp1, MIPI_CSI2))
- rkisp1_csi_cleanup(rkisp1);
- err_unreg_media_dev:
- media_device_unregister(&rkisp1->media_dev);
- err_unreg_v4l2_dev:
- v4l2_device_unregister(&rkisp1->v4l2_dev);
- err_media_dev_cleanup:
- media_device_cleanup(&rkisp1->media_dev);
- err_pm_runtime_disable:
- pm_runtime_disable(&pdev->dev);
- return ret;
- }
- static void rkisp1_remove(struct platform_device *pdev)
- {
- struct rkisp1_device *rkisp1 = platform_get_drvdata(pdev);
- v4l2_async_nf_unregister(&rkisp1->notifier);
- v4l2_async_nf_cleanup(&rkisp1->notifier);
- rkisp1_entities_unregister(rkisp1);
- if (rkisp1_has_feature(rkisp1, MIPI_CSI2))
- rkisp1_csi_cleanup(rkisp1);
- rkisp1_debug_cleanup(rkisp1);
- media_device_unregister(&rkisp1->media_dev);
- v4l2_device_unregister(&rkisp1->v4l2_dev);
- media_device_cleanup(&rkisp1->media_dev);
- pm_runtime_disable(&pdev->dev);
- }
- static struct platform_driver rkisp1_drv = {
- .driver = {
- .name = RKISP1_DRIVER_NAME,
- .of_match_table = of_match_ptr(rkisp1_of_match),
- .pm = &rkisp1_pm_ops,
- },
- .probe = rkisp1_probe,
- .remove = rkisp1_remove,
- };
- module_platform_driver(rkisp1_drv);
- MODULE_DESCRIPTION("Rockchip ISP1 platform driver");
- MODULE_LICENSE("Dual MIT/GPL");
|