Lines Matching +full:imx7 +full:- +full:reset

1 // SPDX-License-Identifier: GPL-2.0
3 * NXP i.MX8MQ SoC series MIPI-CSI2 receiver driver
9 #include <linux/clk-provider.h>
24 #include <linux/reset.h>
27 #include <media/v4l2-common.h>
28 #include <media/v4l2-device.h>
29 #include <media/v4l2-fwnode.h>
30 #include <media/v4l2-mc.h>
31 #include <media/v4l2-subdev.h>
33 #define MIPI_CSI2_DRIVER_NAME "imx8mq-mipi-csi2"
45 /* i.MX8MQ CSI-2 controller CSR */
96 * which the sensor transfers data to the CSI-2 Controller and the user
99 * The calculation is the classical rate-in rate-out type of problem: If the
131 /* -----------------------------------------------------------------------------
220 /* -----------------------------------------------------------------------------
226 writel(val, state->regs + reg); in imx8mq_mipi_csi_write()
234 * these are most likely self-clearing reset bits. to make it in imx8mq_mipi_csi_sw_reset()
235 * more clear, the reset-imx7 driver should implement the in imx8mq_mipi_csi_sw_reset()
236 * .reset() operation. in imx8mq_mipi_csi_sw_reset()
238 ret = reset_control_assert(state->rst); in imx8mq_mipi_csi_sw_reset()
240 dev_err(state->dev, "Failed to assert resets: %d\n", ret); in imx8mq_mipi_csi_sw_reset()
249 int lanes = state->bus.num_data_lanes; in imx8mq_mipi_csi_set_params()
251 imx8mq_mipi_csi_write(state, CSI2RX_CFG_NUM_LANES, lanes - 1); in imx8mq_mipi_csi_set_params()
268 return clk_bulk_prepare_enable(CSI2_NUM_CLKS, state->clks); in imx8mq_mipi_csi_clk_enable()
273 clk_bulk_disable_unprepare(CSI2_NUM_CLKS, state->clks); in imx8mq_mipi_csi_clk_disable()
281 state->clks[i].id = imx8mq_mipi_csi_clk_id[i]; in imx8mq_mipi_csi_clk_get()
283 return devm_clk_bulk_get(state->dev, CSI2_NUM_CLKS, state->clks); in imx8mq_mipi_csi_clk_get()
300 csi2_fmt = find_csi2_format(fmt->code); in imx8mq_mipi_csi_calc_hs_settle()
302 link_freq = v4l2_get_link_freq(state->src_sd->ctrl_handler, in imx8mq_mipi_csi_calc_hs_settle()
303 csi2_fmt->width, in imx8mq_mipi_csi_calc_hs_settle()
304 state->bus.num_data_lanes * 2); in imx8mq_mipi_csi_calc_hs_settle()
306 dev_err(state->dev, "Unable to obtain link frequency: %d\n", in imx8mq_mipi_csi_calc_hs_settle()
313 dev_dbg(state->dev, "Out-of-bound lane rate %u\n", lane_rate); in imx8mq_mipi_csi_calc_hs_settle()
314 return -EINVAL; in imx8mq_mipi_csi_calc_hs_settle()
318 * The D-PHY specification requires Ths-settle to be in the range in imx8mq_mipi_csi_calc_hs_settle()
322 * The Ths-settle value is expressed in the hardware as a multiple of in imx8mq_mipi_csi_calc_hs_settle()
325 * Ths-settle = (PRG_RXHS_SETTLE + 1) * Tperiod of RxClkInEsc in imx8mq_mipi_csi_calc_hs_settle()
331 esc_clk_rate = clk_get_rate(state->clks[CSI2_CLK_ESC].clk); in imx8mq_mipi_csi_calc_hs_settle()
333 dev_err(state->dev, "Could not get esc clock rate.\n"); in imx8mq_mipi_csi_calc_hs_settle()
334 return -EINVAL; in imx8mq_mipi_csi_calc_hs_settle()
337 dev_dbg(state->dev, "esc clk rate: %lu\n", esc_clk_rate); in imx8mq_mipi_csi_calc_hs_settle()
344 *hs_settle = ths_settle_ns / esc_clk_period_ns - 1; in imx8mq_mipi_csi_calc_hs_settle()
346 dev_dbg(state->dev, "lane rate %u Ths_settle %u hs_settle %u\n", in imx8mq_mipi_csi_calc_hs_settle()
367 regmap_update_bits(state->phy_gpr, in imx8mq_mipi_csi_start_stream()
368 state->phy_gpr_reg, in imx8mq_mipi_csi_start_stream()
384 /* -----------------------------------------------------------------------------
400 ret = pm_runtime_resume_and_get(state->dev); in imx8mq_mipi_csi_s_stream()
405 mutex_lock(&state->lock); in imx8mq_mipi_csi_s_stream()
408 if (state->state & ST_SUSPENDED) { in imx8mq_mipi_csi_s_stream()
409 ret = -EBUSY; in imx8mq_mipi_csi_s_stream()
420 ret = v4l2_subdev_call(state->src_sd, video, s_stream, 1); in imx8mq_mipi_csi_s_stream()
424 state->state |= ST_STREAMING; in imx8mq_mipi_csi_s_stream()
426 v4l2_subdev_call(state->src_sd, video, s_stream, 0); in imx8mq_mipi_csi_s_stream()
428 state->state &= ~ST_STREAMING; in imx8mq_mipi_csi_s_stream()
432 mutex_unlock(&state->lock); in imx8mq_mipi_csi_s_stream()
435 pm_runtime_put(state->dev); in imx8mq_mipi_csi_s_stream()
450 fmt_sink->code = MEDIA_BUS_FMT_SGBRG10_1X10; in imx8mq_mipi_csi_init_state()
451 fmt_sink->width = MIPI_CSI2_DEF_PIX_WIDTH; in imx8mq_mipi_csi_init_state()
452 fmt_sink->height = MIPI_CSI2_DEF_PIX_HEIGHT; in imx8mq_mipi_csi_init_state()
453 fmt_sink->field = V4L2_FIELD_NONE; in imx8mq_mipi_csi_init_state()
455 fmt_sink->colorspace = V4L2_COLORSPACE_RAW; in imx8mq_mipi_csi_init_state()
456 fmt_sink->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt_sink->colorspace); in imx8mq_mipi_csi_init_state()
457 fmt_sink->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt_sink->colorspace); in imx8mq_mipi_csi_init_state()
458 fmt_sink->quantization = in imx8mq_mipi_csi_init_state()
459 V4L2_MAP_QUANTIZATION_DEFAULT(false, fmt_sink->colorspace, in imx8mq_mipi_csi_init_state()
460 fmt_sink->ycbcr_enc); in imx8mq_mipi_csi_init_state()
475 if (code->pad == MIPI_CSI2_PAD_SOURCE) { in imx8mq_mipi_csi_enum_mbus_code()
478 if (code->index > 0) in imx8mq_mipi_csi_enum_mbus_code()
479 return -EINVAL; in imx8mq_mipi_csi_enum_mbus_code()
481 fmt = v4l2_subdev_state_get_format(sd_state, code->pad); in imx8mq_mipi_csi_enum_mbus_code()
482 code->code = fmt->code; in imx8mq_mipi_csi_enum_mbus_code()
486 if (code->pad != MIPI_CSI2_PAD_SINK) in imx8mq_mipi_csi_enum_mbus_code()
487 return -EINVAL; in imx8mq_mipi_csi_enum_mbus_code()
489 if (code->index >= ARRAY_SIZE(imx8mq_mipi_csi_formats)) in imx8mq_mipi_csi_enum_mbus_code()
490 return -EINVAL; in imx8mq_mipi_csi_enum_mbus_code()
492 code->code = imx8mq_mipi_csi_formats[code->index].code; in imx8mq_mipi_csi_enum_mbus_code()
508 if (sdformat->pad == MIPI_CSI2_PAD_SOURCE) in imx8mq_mipi_csi_set_fmt()
511 if (sdformat->pad != MIPI_CSI2_PAD_SINK) in imx8mq_mipi_csi_set_fmt()
512 return -EINVAL; in imx8mq_mipi_csi_set_fmt()
514 csi2_fmt = find_csi2_format(sdformat->format.code); in imx8mq_mipi_csi_set_fmt()
518 fmt = v4l2_subdev_state_get_format(sd_state, sdformat->pad); in imx8mq_mipi_csi_set_fmt()
520 fmt->code = csi2_fmt->code; in imx8mq_mipi_csi_set_fmt()
521 fmt->width = sdformat->format.width; in imx8mq_mipi_csi_set_fmt()
522 fmt->height = sdformat->format.height; in imx8mq_mipi_csi_set_fmt()
524 sdformat->format = *fmt; in imx8mq_mipi_csi_set_fmt()
528 *fmt = sdformat->format; in imx8mq_mipi_csi_set_fmt()
552 /* -----------------------------------------------------------------------------
561 /* -----------------------------------------------------------------------------
576 struct media_pad *sink = &state->sd.entity.pads[MIPI_CSI2_PAD_SINK]; in imx8mq_mipi_csi_notify_bound()
578 state->src_sd = sd; in imx8mq_mipi_csi_notify_bound()
598 v4l2_async_subdev_nf_init(&state->notifier, &state->sd); in imx8mq_mipi_csi_async_register()
600 ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(state->dev), 0, 0, in imx8mq_mipi_csi_async_register()
603 return -ENOTCONN; in imx8mq_mipi_csi_async_register()
611 dev_err(state->dev, in imx8mq_mipi_csi_async_register()
613 ret = -EINVAL; in imx8mq_mipi_csi_async_register()
618 state->bus = vep.bus.mipi_csi2; in imx8mq_mipi_csi_async_register()
620 dev_dbg(state->dev, "data lanes: %d flags: 0x%08x\n", in imx8mq_mipi_csi_async_register()
621 state->bus.num_data_lanes, in imx8mq_mipi_csi_async_register()
622 state->bus.flags); in imx8mq_mipi_csi_async_register()
624 asd = v4l2_async_nf_add_fwnode_remote(&state->notifier, ep, in imx8mq_mipi_csi_async_register()
633 state->notifier.ops = &imx8mq_mipi_csi_notify_ops; in imx8mq_mipi_csi_async_register()
635 ret = v4l2_async_nf_register(&state->notifier); in imx8mq_mipi_csi_async_register()
639 return v4l2_async_register_subdev(&state->sd); in imx8mq_mipi_csi_async_register()
647 /* -----------------------------------------------------------------------------
656 mutex_lock(&state->lock); in imx8mq_mipi_csi_pm_suspend()
658 if (state->state & ST_POWERED) { in imx8mq_mipi_csi_pm_suspend()
661 state->state &= ~ST_POWERED; in imx8mq_mipi_csi_pm_suspend()
664 mutex_unlock(&state->lock); in imx8mq_mipi_csi_pm_suspend()
674 mutex_lock(&state->lock); in imx8mq_mipi_csi_pm_resume()
676 if (!(state->state & ST_POWERED)) { in imx8mq_mipi_csi_pm_resume()
677 state->state |= ST_POWERED; in imx8mq_mipi_csi_pm_resume()
680 if (state->state & ST_STREAMING) { in imx8mq_mipi_csi_pm_resume()
688 state->state &= ~ST_SUSPENDED; in imx8mq_mipi_csi_pm_resume()
691 mutex_unlock(&state->lock); in imx8mq_mipi_csi_pm_resume()
693 return ret ? -EAGAIN : 0; in imx8mq_mipi_csi_pm_resume()
703 state->state |= ST_SUSPENDED; in imx8mq_mipi_csi_suspend()
713 if (!(state->state & ST_SUSPENDED)) in imx8mq_mipi_csi_resume()
727 ret = icc_set_bw(state->icc_path, 0, 0); in imx8mq_mipi_csi_runtime_suspend()
740 ret = icc_set_bw(state->icc_path, 0, state->icc_path_bw); in imx8mq_mipi_csi_runtime_resume()
755 /* -----------------------------------------------------------------------------
761 struct v4l2_subdev *sd = &state->sd; in imx8mq_mipi_csi_subdev_init()
765 sd->internal_ops = &imx8mq_mipi_csi_internal_ops; in imx8mq_mipi_csi_subdev_init()
766 sd->owner = THIS_MODULE; in imx8mq_mipi_csi_subdev_init()
767 snprintf(sd->name, sizeof(sd->name), "%s %s", in imx8mq_mipi_csi_subdev_init()
768 MIPI_CSI2_SUBDEV_NAME, dev_name(state->dev)); in imx8mq_mipi_csi_subdev_init()
770 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; in imx8mq_mipi_csi_subdev_init()
772 sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; in imx8mq_mipi_csi_subdev_init()
773 sd->entity.ops = &imx8mq_mipi_csi_entity_ops; in imx8mq_mipi_csi_subdev_init()
775 sd->dev = state->dev; in imx8mq_mipi_csi_subdev_init()
777 state->pads[MIPI_CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK in imx8mq_mipi_csi_subdev_init()
779 state->pads[MIPI_CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE in imx8mq_mipi_csi_subdev_init()
781 ret = media_entity_pads_init(&sd->entity, MIPI_CSI2_PADS_NUM, in imx8mq_mipi_csi_subdev_init()
782 state->pads); in imx8mq_mipi_csi_subdev_init()
788 media_entity_cleanup(&sd->entity); in imx8mq_mipi_csi_subdev_init()
797 struct v4l2_subdev *sd = dev_get_drvdata(&pdev->dev); in imx8mq_mipi_csi_release_icc()
800 icc_put(state->icc_path); in imx8mq_mipi_csi_release_icc()
805 struct v4l2_subdev *sd = dev_get_drvdata(&pdev->dev); in imx8mq_mipi_csi_init_icc()
809 state->icc_path = of_icc_get(&pdev->dev, "dram"); in imx8mq_mipi_csi_init_icc()
810 if (IS_ERR_OR_NULL(state->icc_path)) in imx8mq_mipi_csi_init_icc()
811 return PTR_ERR_OR_ZERO(state->icc_path); in imx8mq_mipi_csi_init_icc()
813 state->icc_path_bw = MBps_to_icc(700); in imx8mq_mipi_csi_init_icc()
820 struct device *dev = state->dev; in imx8mq_mipi_csi_parse_dt()
821 struct device_node *np = state->dev->of_node; in imx8mq_mipi_csi_parse_dt()
827 state->rst = devm_reset_control_array_get_exclusive(dev); in imx8mq_mipi_csi_parse_dt()
828 if (IS_ERR(state->rst)) { in imx8mq_mipi_csi_parse_dt()
829 dev_err(dev, "Failed to get reset: %pe\n", state->rst); in imx8mq_mipi_csi_parse_dt()
830 return PTR_ERR(state->rst); in imx8mq_mipi_csi_parse_dt()
833 ret = of_property_read_u32_array(np, "fsl,mipi-phy-gpr", out_val, in imx8mq_mipi_csi_parse_dt()
836 dev_err(dev, "no fsl,mipi-phy-gpr property found: %d\n", ret); in imx8mq_mipi_csi_parse_dt()
845 return -ENODEV; in imx8mq_mipi_csi_parse_dt()
847 state->phy_gpr = syscon_node_to_regmap(node); in imx8mq_mipi_csi_parse_dt()
849 if (IS_ERR(state->phy_gpr)) { in imx8mq_mipi_csi_parse_dt()
850 dev_err(dev, "failed to get gpr regmap: %pe\n", state->phy_gpr); in imx8mq_mipi_csi_parse_dt()
851 return PTR_ERR(state->phy_gpr); in imx8mq_mipi_csi_parse_dt()
854 state->phy_gpr_reg = out_val[1]; in imx8mq_mipi_csi_parse_dt()
855 dev_dbg(dev, "phy gpr register set to 0x%x\n", state->phy_gpr_reg); in imx8mq_mipi_csi_parse_dt()
862 struct device *dev = &pdev->dev; in imx8mq_mipi_csi_probe()
868 return -ENOMEM; in imx8mq_mipi_csi_probe()
870 state->dev = dev; in imx8mq_mipi_csi_probe()
879 state->regs = devm_platform_ioremap_resource(pdev, 0); in imx8mq_mipi_csi_probe()
880 if (IS_ERR(state->regs)) in imx8mq_mipi_csi_probe()
881 return PTR_ERR(state->regs); in imx8mq_mipi_csi_probe()
887 platform_set_drvdata(pdev, &state->sd); in imx8mq_mipi_csi_probe()
889 mutex_init(&state->lock); in imx8mq_mipi_csi_probe()
914 pm_runtime_disable(&pdev->dev); in imx8mq_mipi_csi_probe()
915 imx8mq_mipi_csi_runtime_suspend(&pdev->dev); in imx8mq_mipi_csi_probe()
917 media_entity_cleanup(&state->sd.entity); in imx8mq_mipi_csi_probe()
918 v4l2_subdev_cleanup(&state->sd); in imx8mq_mipi_csi_probe()
919 v4l2_async_nf_unregister(&state->notifier); in imx8mq_mipi_csi_probe()
920 v4l2_async_nf_cleanup(&state->notifier); in imx8mq_mipi_csi_probe()
921 v4l2_async_unregister_subdev(&state->sd); in imx8mq_mipi_csi_probe()
925 mutex_destroy(&state->lock); in imx8mq_mipi_csi_probe()
935 v4l2_async_nf_unregister(&state->notifier); in imx8mq_mipi_csi_remove()
936 v4l2_async_nf_cleanup(&state->notifier); in imx8mq_mipi_csi_remove()
937 v4l2_async_unregister_subdev(&state->sd); in imx8mq_mipi_csi_remove()
939 pm_runtime_disable(&pdev->dev); in imx8mq_mipi_csi_remove()
940 imx8mq_mipi_csi_runtime_suspend(&pdev->dev); in imx8mq_mipi_csi_remove()
941 media_entity_cleanup(&state->sd.entity); in imx8mq_mipi_csi_remove()
942 v4l2_subdev_cleanup(&state->sd); in imx8mq_mipi_csi_remove()
943 mutex_destroy(&state->lock); in imx8mq_mipi_csi_remove()
944 pm_runtime_set_suspended(&pdev->dev); in imx8mq_mipi_csi_remove()
949 { .compatible = "fsl,imx8mq-mipi-csi2", },
966 MODULE_DESCRIPTION("i.MX8MQ MIPI CSI-2 receiver driver");
969 MODULE_ALIAS("platform:imx8mq-mipi-csi2");