Lines Matching +full:csis +full:- +full:hs +full:- +full:settle

1 // SPDX-License-Identifier: GPL-2.0-only
3 * Samsung S5P/EXYNOS SoC series MIPI-CSI receiver driver
5 * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd.
29 #include <media/drv-intf/exynos-fimc.h>
30 #include <media/v4l2-fwnode.h>
31 #include <media/v4l2-subdev.h>
33 #include "mipi-csis.h"
37 MODULE_PARM_DESC(debug, "Debug level (0-2)");
41 /* CSIS global control */
51 /* D-PHY control */
62 #define S5PCSIS_CFG_FMT_USER(x) ((0x30 + x - 1) << 2)
109 /* Non-image packet data buffers */
121 [CSIS_CLK_GATE] = "csis",
127 "vddcore", /* CSIS Core (1.0V, 1.1V or 1.2V) supply */
128 "vddio", /* CSIS I/O and PLL (1.8V) supply */
153 /* Non-image data receive events */
154 { S5PCSIS_INTSRC_EVEN_BEFORE, "Non-image data before even frame" },
155 { S5PCSIS_INTSRC_EVEN_AFTER, "Non-image data after even frame" },
156 { S5PCSIS_INTSRC_ODD_BEFORE, "Non-image data before odd frame" },
157 { S5PCSIS_INTSRC_ODD_AFTER, "Non-image data after odd frame" },
175 * struct csis_state - the driver's internal state data structure
178 * @pads: CSIS pads array
179 * @sd: v4l2_subdev associated with CSIS device instance
181 * @pdev: CSIS platform device
182 * @phy: pointer to the CSIS generic PHY
184 * @supplies: CSIS regulator supplies
185 * @clock: CSIS clocks
186 * @irq: requested s5p-mipi-csis irq number
190 * @hs_settle: HS-RX settle time
191 * @num_lanes: number of MIPI-CSI data lanes used
192 * @max_num_lanes: maximum number of MIPI-CSI data lanes supported
193 * @wclk_ext: CSI wrapper clock: 0 - bus clock, 1 - external SCLK_CAM
194 * @csis_fmt: current CSIS pixel format
197 * @pkt_buf: the frame embedded (non-image) data buffer
198 * @events: MIPI-CSIS event (error) counters
229 * struct csis_pix_format - CSIS pixel format description
234 * @data_alignment: MIPI-CSI data alignment in bits
271 #define s5pcsis_write(__csis, __r, __v) writel(__v, __csis->regs + __r)
272 #define s5pcsis_read(__csis, __r) readl(__csis->regs + __r)
285 if (mf->code == s5pcsis_formats[i].code) in find_csis_format()
294 val |= state->interrupt_mask; in s5pcsis_enable_interrupts()
296 val &= ~state->interrupt_mask; in s5pcsis_enable_interrupts()
322 mask = (1 << (state->num_lanes + 1)) - 1; in s5pcsis_system_enable()
331 struct v4l2_mbus_framefmt *mf = &state->format; in __s5pcsis_set_format()
334 v4l2_dbg(1, debug, &state->sd, "fmt: %#x, %d x %d\n", in __s5pcsis_set_format()
335 mf->code, mf->width, mf->height); in __s5pcsis_set_format()
339 val = (val & ~S5PCSIS_CFG_FMT_MASK) | state->csis_fmt->fmt_reg; in __s5pcsis_set_format()
343 val = (mf->width << 16) | mf->height; in __s5pcsis_set_format()
347 static void s5pcsis_set_hsync_settle(struct csis_state *state, int settle) in s5pcsis_set_hsync_settle() argument
351 val = (val & ~S5PCSIS_DPHYCTRL_HSS_MASK) | (settle << 27); in s5pcsis_set_hsync_settle()
360 val = (val & ~S5PCSIS_CFG_NR_LANE_MASK) | (state->num_lanes - 1); in s5pcsis_set_params()
364 s5pcsis_set_hsync_settle(state, state->hs_settle); in s5pcsis_set_params()
367 if (state->csis_fmt->data_alignment == 32) in s5pcsis_set_params()
369 else /* 24-bits */ in s5pcsis_set_params()
373 if (state->wclk_ext) in s5pcsis_set_params()
387 if (IS_ERR(state->clock[i])) in s5pcsis_clk_put()
389 clk_unprepare(state->clock[i]); in s5pcsis_clk_put()
390 clk_put(state->clock[i]); in s5pcsis_clk_put()
391 state->clock[i] = ERR_PTR(-EINVAL); in s5pcsis_clk_put()
397 struct device *dev = &state->pdev->dev; in s5pcsis_clk_get()
401 state->clock[i] = ERR_PTR(-EINVAL); in s5pcsis_clk_get()
404 state->clock[i] = clk_get(dev, csi_clock_name[i]); in s5pcsis_clk_get()
405 if (IS_ERR(state->clock[i])) { in s5pcsis_clk_get()
406 ret = PTR_ERR(state->clock[i]); in s5pcsis_clk_get()
409 ret = clk_prepare(state->clock[i]); in s5pcsis_clk_get()
411 clk_put(state->clock[i]); in s5pcsis_clk_get()
412 state->clock[i] = ERR_PTR(-EINVAL); in s5pcsis_clk_get()
439 v4l2_info(&state->sd, "--- %s ---\n", label); in dump_regs()
443 v4l2_info(&state->sd, "%10s: 0x%08x\n", registers[i].name, cfg); in dump_regs()
466 spin_lock_irqsave(&state->slock, flags); in s5pcsis_clear_counters()
468 state->events[i].counter = 0; in s5pcsis_clear_counters()
469 spin_unlock_irqrestore(&state->slock, flags); in s5pcsis_clear_counters()
474 int i = non_errors ? S5PCSIS_NUM_EVENTS : S5PCSIS_NUM_EVENTS - 4; in s5pcsis_log_counters()
477 spin_lock_irqsave(&state->slock, flags); in s5pcsis_log_counters()
479 for (i--; i >= 0; i--) { in s5pcsis_log_counters()
480 if (state->events[i].counter > 0 || debug) in s5pcsis_log_counters()
481 v4l2_info(&state->sd, "%s events: %d\n", in s5pcsis_log_counters()
482 state->events[i].name, in s5pcsis_log_counters()
483 state->events[i].counter); in s5pcsis_log_counters()
485 spin_unlock_irqrestore(&state->slock, flags); in s5pcsis_log_counters()
494 struct device *dev = &state->pdev->dev; in s5pcsis_s_power()
508 __func__, enable, state->flags); in s5pcsis_s_stream()
512 ret = pm_runtime_resume_and_get(&state->pdev->dev); in s5pcsis_s_stream()
517 mutex_lock(&state->lock); in s5pcsis_s_stream()
519 if (state->flags & ST_SUSPENDED) { in s5pcsis_s_stream()
520 ret = -EBUSY; in s5pcsis_s_stream()
524 state->flags |= ST_STREAMING; in s5pcsis_s_stream()
527 state->flags &= ~ST_STREAMING; in s5pcsis_s_stream()
532 mutex_unlock(&state->lock); in s5pcsis_s_stream()
534 pm_runtime_put(&state->pdev->dev); in s5pcsis_s_stream()
543 if (code->index >= ARRAY_SIZE(s5pcsis_formats)) in s5pcsis_enum_mbus_code()
544 return -EINVAL; in s5pcsis_enum_mbus_code()
546 code->code = s5pcsis_formats[code->index].code; in s5pcsis_enum_mbus_code()
559 mf->code = csis_fmt->code; in s5pcsis_try_format()
560 v4l_bound_align_image(&mf->width, 1, CSIS_MAX_PIX_WIDTH, in s5pcsis_try_format()
561 csis_fmt->pix_width_alignment, in s5pcsis_try_format()
562 &mf->height, 1, CSIS_MAX_PIX_HEIGHT, 1, in s5pcsis_try_format()
574 return &state->format; in __s5pcsis_get_format()
585 mf = __s5pcsis_get_format(state, sd_state, fmt->which); in s5pcsis_set_fmt()
587 if (fmt->pad == CSIS_PAD_SOURCE) { in s5pcsis_set_fmt()
589 mutex_lock(&state->lock); in s5pcsis_set_fmt()
590 fmt->format = *mf; in s5pcsis_set_fmt()
591 mutex_unlock(&state->lock); in s5pcsis_set_fmt()
595 csis_fmt = s5pcsis_try_format(&fmt->format); in s5pcsis_set_fmt()
597 mutex_lock(&state->lock); in s5pcsis_set_fmt()
598 *mf = fmt->format; in s5pcsis_set_fmt()
599 if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) in s5pcsis_set_fmt()
600 state->csis_fmt = csis_fmt; in s5pcsis_set_fmt()
601 mutex_unlock(&state->lock); in s5pcsis_set_fmt()
613 mf = __s5pcsis_get_format(state, sd_state, fmt->which); in s5pcsis_get_fmt()
615 return -EINVAL; in s5pcsis_get_fmt()
617 mutex_lock(&state->lock); in s5pcsis_get_fmt()
618 fmt->format = *mf; in s5pcsis_get_fmt()
619 mutex_unlock(&state->lock); in s5pcsis_get_fmt()
631 spin_lock_irqsave(&state->slock, flags); in s5pcsis_s_rx_buffer()
632 state->pkt_buf.data = buf; in s5pcsis_s_rx_buffer()
633 state->pkt_buf.len = *size; in s5pcsis_s_rx_buffer()
634 spin_unlock_irqrestore(&state->slock, flags); in s5pcsis_s_rx_buffer()
643 mutex_lock(&state->lock); in s5pcsis_log_status()
645 if (debug && (state->flags & ST_POWERED)) in s5pcsis_log_status()
647 mutex_unlock(&state->lock); in s5pcsis_log_status()
676 struct csis_pktbuf *pktbuf = &state->pkt_buf; in s5pcsis_irq_handler()
681 spin_lock_irqsave(&state->slock, flags); in s5pcsis_irq_handler()
683 if ((status & S5PCSIS_INTSRC_NON_IMAGE_DATA) && pktbuf->data) { in s5pcsis_irq_handler()
691 memcpy(pktbuf->data, (u8 __force *)state->regs + offset, in s5pcsis_irq_handler()
692 pktbuf->len); in s5pcsis_irq_handler()
693 pktbuf->data = NULL; in s5pcsis_irq_handler()
701 if (!(status & state->events[i].mask)) in s5pcsis_irq_handler()
703 state->events[i].counter++; in s5pcsis_irq_handler()
704 v4l2_dbg(2, debug, &state->sd, "%s: %d\n", in s5pcsis_irq_handler()
705 state->events[i].name, in s5pcsis_irq_handler()
706 state->events[i].counter); in s5pcsis_irq_handler()
708 v4l2_dbg(2, debug, &state->sd, "status: %08x\n", status); in s5pcsis_irq_handler()
710 spin_unlock_irqrestore(&state->slock, flags); in s5pcsis_irq_handler()
719 struct device_node *node = pdev->dev.of_node; in s5pcsis_parse_dt()
723 if (of_property_read_u32(node, "clock-frequency", in s5pcsis_parse_dt()
724 &state->clk_frequency)) in s5pcsis_parse_dt()
725 state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ; in s5pcsis_parse_dt()
726 if (of_property_read_u32(node, "bus-width", in s5pcsis_parse_dt()
727 &state->max_num_lanes)) in s5pcsis_parse_dt()
728 return -EINVAL; in s5pcsis_parse_dt()
731 node = of_graph_get_endpoint_by_regs(node, -1, -1); in s5pcsis_parse_dt()
733 dev_err(&pdev->dev, "No port node at %pOF\n", in s5pcsis_parse_dt()
734 pdev->dev.of_node); in s5pcsis_parse_dt()
735 return -EINVAL; in s5pcsis_parse_dt()
737 /* Get port node and validate MIPI-CSI channel id. */ in s5pcsis_parse_dt()
742 state->index = endpoint.base.port - FIMC_INPUT_MIPI_CSI2_0; in s5pcsis_parse_dt()
743 if (state->index >= CSIS_MAX_ENTITIES) { in s5pcsis_parse_dt()
744 ret = -ENXIO; in s5pcsis_parse_dt()
748 /* Get MIPI CSI-2 bus configuration from the endpoint node. */ in s5pcsis_parse_dt()
749 of_property_read_u32(node, "samsung,csis-hs-settle", in s5pcsis_parse_dt()
750 &state->hs_settle); in s5pcsis_parse_dt()
751 state->wclk_ext = of_property_read_bool(node, in s5pcsis_parse_dt()
752 "samsung,csis-wclk"); in s5pcsis_parse_dt()
754 state->num_lanes = endpoint.bus.mipi_csi2.num_data_lanes; in s5pcsis_parse_dt()
768 struct device *dev = &pdev->dev; in s5pcsis_probe()
770 int ret = -ENOMEM; in s5pcsis_probe()
775 return -ENOMEM; in s5pcsis_probe()
777 mutex_init(&state->lock); in s5pcsis_probe()
778 spin_lock_init(&state->slock); in s5pcsis_probe()
779 state->pdev = pdev; in s5pcsis_probe()
781 of_id = of_match_node(s5pcsis_of_match, dev->of_node); in s5pcsis_probe()
783 return -EINVAL; in s5pcsis_probe()
785 drv_data = of_id->data; in s5pcsis_probe()
786 state->interrupt_mask = drv_data->interrupt_mask; in s5pcsis_probe()
792 if (state->num_lanes == 0 || state->num_lanes > state->max_num_lanes) { in s5pcsis_probe()
794 state->num_lanes, state->max_num_lanes); in s5pcsis_probe()
795 return -EINVAL; in s5pcsis_probe()
798 state->phy = devm_phy_get(dev, "csis"); in s5pcsis_probe()
799 if (IS_ERR(state->phy)) in s5pcsis_probe()
800 return PTR_ERR(state->phy); in s5pcsis_probe()
802 state->regs = devm_platform_ioremap_resource(pdev, 0); in s5pcsis_probe()
803 if (IS_ERR(state->regs)) in s5pcsis_probe()
804 return PTR_ERR(state->regs); in s5pcsis_probe()
806 state->irq = platform_get_irq(pdev, 0); in s5pcsis_probe()
807 if (state->irq < 0) in s5pcsis_probe()
808 return state->irq; in s5pcsis_probe()
811 state->supplies[i].supply = csis_supply_name[i]; in s5pcsis_probe()
814 state->supplies); in s5pcsis_probe()
822 if (state->clk_frequency) in s5pcsis_probe()
823 ret = clk_set_rate(state->clock[CSIS_CLK_MUX], in s5pcsis_probe()
824 state->clk_frequency); in s5pcsis_probe()
830 ret = clk_enable(state->clock[CSIS_CLK_MUX]); in s5pcsis_probe()
834 ret = devm_request_irq(dev, state->irq, s5pcsis_irq_handler, in s5pcsis_probe()
841 v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops); in s5pcsis_probe()
842 state->sd.owner = THIS_MODULE; in s5pcsis_probe()
843 snprintf(state->sd.name, sizeof(state->sd.name), "%s.%d", in s5pcsis_probe()
844 CSIS_SUBDEV_NAME, state->index); in s5pcsis_probe()
845 state->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; in s5pcsis_probe()
846 state->csis_fmt = &s5pcsis_formats[0]; in s5pcsis_probe()
848 state->format.code = s5pcsis_formats[0].code; in s5pcsis_probe()
849 state->format.width = S5PCSIS_DEF_PIX_WIDTH; in s5pcsis_probe()
850 state->format.height = S5PCSIS_DEF_PIX_HEIGHT; in s5pcsis_probe()
852 state->sd.entity.function = MEDIA_ENT_F_IO_V4L; in s5pcsis_probe()
853 state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK; in s5pcsis_probe()
854 state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; in s5pcsis_probe()
855 ret = media_entity_pads_init(&state->sd.entity, in s5pcsis_probe()
856 CSIS_PADS_NUM, state->pads); in s5pcsis_probe()
861 v4l2_set_subdevdata(&state->sd, pdev); in s5pcsis_probe()
864 platform_set_drvdata(pdev, &state->sd); in s5pcsis_probe()
865 memcpy(state->events, s5pcsis_events, sizeof(state->events)); in s5pcsis_probe()
874 dev_info(&pdev->dev, "lanes: %d, hs_settle: %d, wclk: %d, freq: %u\n", in s5pcsis_probe()
875 state->num_lanes, state->hs_settle, state->wclk_ext, in s5pcsis_probe()
876 state->clk_frequency); in s5pcsis_probe()
880 media_entity_cleanup(&state->sd.entity); in s5pcsis_probe()
882 clk_disable(state->clock[CSIS_CLK_MUX]); in s5pcsis_probe()
895 __func__, state->flags); in s5pcsis_pm_suspend()
897 mutex_lock(&state->lock); in s5pcsis_pm_suspend()
898 if (state->flags & ST_POWERED) { in s5pcsis_pm_suspend()
900 ret = phy_power_off(state->phy); in s5pcsis_pm_suspend()
904 state->supplies); in s5pcsis_pm_suspend()
907 clk_disable(state->clock[CSIS_CLK_GATE]); in s5pcsis_pm_suspend()
908 state->flags &= ~ST_POWERED; in s5pcsis_pm_suspend()
910 state->flags |= ST_SUSPENDED; in s5pcsis_pm_suspend()
913 mutex_unlock(&state->lock); in s5pcsis_pm_suspend()
914 return ret ? -EAGAIN : 0; in s5pcsis_pm_suspend()
924 __func__, state->flags); in s5pcsis_pm_resume()
926 mutex_lock(&state->lock); in s5pcsis_pm_resume()
927 if (!runtime && !(state->flags & ST_SUSPENDED)) in s5pcsis_pm_resume()
930 if (!(state->flags & ST_POWERED)) { in s5pcsis_pm_resume()
932 state->supplies); in s5pcsis_pm_resume()
935 ret = phy_power_on(state->phy); in s5pcsis_pm_resume()
937 state->flags |= ST_POWERED; in s5pcsis_pm_resume()
940 state->supplies); in s5pcsis_pm_resume()
943 clk_enable(state->clock[CSIS_CLK_GATE]); in s5pcsis_pm_resume()
945 if (state->flags & ST_STREAMING) in s5pcsis_pm_resume()
948 state->flags &= ~ST_SUSPENDED; in s5pcsis_pm_resume()
950 mutex_unlock(&state->lock); in s5pcsis_pm_resume()
951 return ret ? -EAGAIN : 0; in s5pcsis_pm_resume()
983 pm_runtime_disable(&pdev->dev); in s5pcsis_remove()
984 s5pcsis_pm_suspend(&pdev->dev, true); in s5pcsis_remove()
985 clk_disable(state->clock[CSIS_CLK_MUX]); in s5pcsis_remove()
986 pm_runtime_set_suspended(&pdev->dev); in s5pcsis_remove()
989 media_entity_cleanup(&state->sd.entity); in s5pcsis_remove()
1008 .compatible = "samsung,s5pv210-csis",
1011 .compatible = "samsung,exynos4210-csis",
1014 .compatible = "samsung,exynos5250-csis",
1034 MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC MIPI-CSI2 receiver driver");