162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * V4L2 Driver for PXA camera host 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2006, Sascha Hauer, Pengutronix 662306a36Sopenharmony_ci * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> 762306a36Sopenharmony_ci * Copyright (C) 2016, Robert Jarzmik <robert.jarzmik@free.fr> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/io.h> 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/device.h> 1562306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1662306a36Sopenharmony_ci#include <linux/err.h> 1762306a36Sopenharmony_ci#include <linux/errno.h> 1862306a36Sopenharmony_ci#include <linux/fs.h> 1962306a36Sopenharmony_ci#include <linux/interrupt.h> 2062306a36Sopenharmony_ci#include <linux/kernel.h> 2162306a36Sopenharmony_ci#include <linux/mm.h> 2262306a36Sopenharmony_ci#include <linux/moduleparam.h> 2362306a36Sopenharmony_ci#include <linux/of.h> 2462306a36Sopenharmony_ci#include <linux/of_graph.h> 2562306a36Sopenharmony_ci#include <linux/time.h> 2662306a36Sopenharmony_ci#include <linux/platform_device.h> 2762306a36Sopenharmony_ci#include <linux/clk.h> 2862306a36Sopenharmony_ci#include <linux/sched.h> 2962306a36Sopenharmony_ci#include <linux/slab.h> 3062306a36Sopenharmony_ci#include <linux/dmaengine.h> 3162306a36Sopenharmony_ci#include <linux/dma/pxa-dma.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <media/v4l2-async.h> 3462306a36Sopenharmony_ci#include <media/v4l2-common.h> 3562306a36Sopenharmony_ci#include <media/v4l2-ctrls.h> 3662306a36Sopenharmony_ci#include <media/v4l2-device.h> 3762306a36Sopenharmony_ci#include <media/v4l2-event.h> 3862306a36Sopenharmony_ci#include <media/v4l2-ioctl.h> 3962306a36Sopenharmony_ci#include <media/v4l2-fwnode.h> 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#include <media/videobuf2-dma-sg.h> 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#include <linux/videodev2.h> 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#include <linux/platform_data/media/camera-pxa.h> 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define PXA_CAM_VERSION "0.0.6" 4862306a36Sopenharmony_ci#define PXA_CAM_DRV_NAME "pxa27x-camera" 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define DEFAULT_WIDTH 640 5162306a36Sopenharmony_ci#define DEFAULT_HEIGHT 480 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* Camera Interface */ 5462306a36Sopenharmony_ci#define CICR0 0x0000 5562306a36Sopenharmony_ci#define CICR1 0x0004 5662306a36Sopenharmony_ci#define CICR2 0x0008 5762306a36Sopenharmony_ci#define CICR3 0x000C 5862306a36Sopenharmony_ci#define CICR4 0x0010 5962306a36Sopenharmony_ci#define CISR 0x0014 6062306a36Sopenharmony_ci#define CIFR 0x0018 6162306a36Sopenharmony_ci#define CITOR 0x001C 6262306a36Sopenharmony_ci#define CIBR0 0x0028 6362306a36Sopenharmony_ci#define CIBR1 0x0030 6462306a36Sopenharmony_ci#define CIBR2 0x0038 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define CICR0_DMAEN (1UL << 31) /* DMA request enable */ 6762306a36Sopenharmony_ci#define CICR0_PAR_EN (1 << 30) /* Parity enable */ 6862306a36Sopenharmony_ci#define CICR0_SL_CAP_EN (1 << 29) /* Capture enable for slave mode */ 6962306a36Sopenharmony_ci#define CICR0_ENB (1 << 28) /* Camera interface enable */ 7062306a36Sopenharmony_ci#define CICR0_DIS (1 << 27) /* Camera interface disable */ 7162306a36Sopenharmony_ci#define CICR0_SIM (0x7 << 24) /* Sensor interface mode mask */ 7262306a36Sopenharmony_ci#define CICR0_TOM (1 << 9) /* Time-out mask */ 7362306a36Sopenharmony_ci#define CICR0_RDAVM (1 << 8) /* Receive-data-available mask */ 7462306a36Sopenharmony_ci#define CICR0_FEM (1 << 7) /* FIFO-empty mask */ 7562306a36Sopenharmony_ci#define CICR0_EOLM (1 << 6) /* End-of-line mask */ 7662306a36Sopenharmony_ci#define CICR0_PERRM (1 << 5) /* Parity-error mask */ 7762306a36Sopenharmony_ci#define CICR0_QDM (1 << 4) /* Quick-disable mask */ 7862306a36Sopenharmony_ci#define CICR0_CDM (1 << 3) /* Disable-done mask */ 7962306a36Sopenharmony_ci#define CICR0_SOFM (1 << 2) /* Start-of-frame mask */ 8062306a36Sopenharmony_ci#define CICR0_EOFM (1 << 1) /* End-of-frame mask */ 8162306a36Sopenharmony_ci#define CICR0_FOM (1 << 0) /* FIFO-overrun mask */ 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#define CICR1_TBIT (1UL << 31) /* Transparency bit */ 8462306a36Sopenharmony_ci#define CICR1_RGBT_CONV (0x3 << 29) /* RGBT conversion mask */ 8562306a36Sopenharmony_ci#define CICR1_PPL (0x7ff << 15) /* Pixels per line mask */ 8662306a36Sopenharmony_ci#define CICR1_RGB_CONV (0x7 << 12) /* RGB conversion mask */ 8762306a36Sopenharmony_ci#define CICR1_RGB_F (1 << 11) /* RGB format */ 8862306a36Sopenharmony_ci#define CICR1_YCBCR_F (1 << 10) /* YCbCr format */ 8962306a36Sopenharmony_ci#define CICR1_RGB_BPP (0x7 << 7) /* RGB bis per pixel mask */ 9062306a36Sopenharmony_ci#define CICR1_RAW_BPP (0x3 << 5) /* Raw bis per pixel mask */ 9162306a36Sopenharmony_ci#define CICR1_COLOR_SP (0x3 << 3) /* Color space mask */ 9262306a36Sopenharmony_ci#define CICR1_DW (0x7 << 0) /* Data width mask */ 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci#define CICR2_BLW (0xff << 24) /* Beginning-of-line pixel clock 9562306a36Sopenharmony_ci wait count mask */ 9662306a36Sopenharmony_ci#define CICR2_ELW (0xff << 16) /* End-of-line pixel clock 9762306a36Sopenharmony_ci wait count mask */ 9862306a36Sopenharmony_ci#define CICR2_HSW (0x3f << 10) /* Horizontal sync pulse width mask */ 9962306a36Sopenharmony_ci#define CICR2_BFPW (0x3f << 3) /* Beginning-of-frame pixel clock 10062306a36Sopenharmony_ci wait count mask */ 10162306a36Sopenharmony_ci#define CICR2_FSW (0x7 << 0) /* Frame stabilization 10262306a36Sopenharmony_ci wait count mask */ 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci#define CICR3_BFW (0xff << 24) /* Beginning-of-frame line clock 10562306a36Sopenharmony_ci wait count mask */ 10662306a36Sopenharmony_ci#define CICR3_EFW (0xff << 16) /* End-of-frame line clock 10762306a36Sopenharmony_ci wait count mask */ 10862306a36Sopenharmony_ci#define CICR3_VSW (0x3f << 10) /* Vertical sync pulse width mask */ 10962306a36Sopenharmony_ci#define CICR3_BFPW (0x3f << 3) /* Beginning-of-frame pixel clock 11062306a36Sopenharmony_ci wait count mask */ 11162306a36Sopenharmony_ci#define CICR3_LPF (0x7ff << 0) /* Lines per frame mask */ 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci#define CICR4_MCLK_DLY (0x3 << 24) /* MCLK Data Capture Delay mask */ 11462306a36Sopenharmony_ci#define CICR4_PCLK_EN (1 << 23) /* Pixel clock enable */ 11562306a36Sopenharmony_ci#define CICR4_PCP (1 << 22) /* Pixel clock polarity */ 11662306a36Sopenharmony_ci#define CICR4_HSP (1 << 21) /* Horizontal sync polarity */ 11762306a36Sopenharmony_ci#define CICR4_VSP (1 << 20) /* Vertical sync polarity */ 11862306a36Sopenharmony_ci#define CICR4_MCLK_EN (1 << 19) /* MCLK enable */ 11962306a36Sopenharmony_ci#define CICR4_FR_RATE (0x7 << 8) /* Frame rate mask */ 12062306a36Sopenharmony_ci#define CICR4_DIV (0xff << 0) /* Clock divisor mask */ 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci#define CISR_FTO (1 << 15) /* FIFO time-out */ 12362306a36Sopenharmony_ci#define CISR_RDAV_2 (1 << 14) /* Channel 2 receive data available */ 12462306a36Sopenharmony_ci#define CISR_RDAV_1 (1 << 13) /* Channel 1 receive data available */ 12562306a36Sopenharmony_ci#define CISR_RDAV_0 (1 << 12) /* Channel 0 receive data available */ 12662306a36Sopenharmony_ci#define CISR_FEMPTY_2 (1 << 11) /* Channel 2 FIFO empty */ 12762306a36Sopenharmony_ci#define CISR_FEMPTY_1 (1 << 10) /* Channel 1 FIFO empty */ 12862306a36Sopenharmony_ci#define CISR_FEMPTY_0 (1 << 9) /* Channel 0 FIFO empty */ 12962306a36Sopenharmony_ci#define CISR_EOL (1 << 8) /* End of line */ 13062306a36Sopenharmony_ci#define CISR_PAR_ERR (1 << 7) /* Parity error */ 13162306a36Sopenharmony_ci#define CISR_CQD (1 << 6) /* Camera interface quick disable */ 13262306a36Sopenharmony_ci#define CISR_CDD (1 << 5) /* Camera interface disable done */ 13362306a36Sopenharmony_ci#define CISR_SOF (1 << 4) /* Start of frame */ 13462306a36Sopenharmony_ci#define CISR_EOF (1 << 3) /* End of frame */ 13562306a36Sopenharmony_ci#define CISR_IFO_2 (1 << 2) /* FIFO overrun for Channel 2 */ 13662306a36Sopenharmony_ci#define CISR_IFO_1 (1 << 1) /* FIFO overrun for Channel 1 */ 13762306a36Sopenharmony_ci#define CISR_IFO_0 (1 << 0) /* FIFO overrun for Channel 0 */ 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci#define CIFR_FLVL2 (0x7f << 23) /* FIFO 2 level mask */ 14062306a36Sopenharmony_ci#define CIFR_FLVL1 (0x7f << 16) /* FIFO 1 level mask */ 14162306a36Sopenharmony_ci#define CIFR_FLVL0 (0xff << 8) /* FIFO 0 level mask */ 14262306a36Sopenharmony_ci#define CIFR_THL_0 (0x3 << 4) /* Threshold Level for Channel 0 FIFO */ 14362306a36Sopenharmony_ci#define CIFR_RESET_F (1 << 3) /* Reset input FIFOs */ 14462306a36Sopenharmony_ci#define CIFR_FEN2 (1 << 2) /* FIFO enable for channel 2 */ 14562306a36Sopenharmony_ci#define CIFR_FEN1 (1 << 1) /* FIFO enable for channel 1 */ 14662306a36Sopenharmony_ci#define CIFR_FEN0 (1 << 0) /* FIFO enable for channel 0 */ 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci#define CICR0_SIM_MP (0 << 24) 14962306a36Sopenharmony_ci#define CICR0_SIM_SP (1 << 24) 15062306a36Sopenharmony_ci#define CICR0_SIM_MS (2 << 24) 15162306a36Sopenharmony_ci#define CICR0_SIM_EP (3 << 24) 15262306a36Sopenharmony_ci#define CICR0_SIM_ES (4 << 24) 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci#define CICR1_DW_VAL(x) ((x) & CICR1_DW) /* Data bus width */ 15562306a36Sopenharmony_ci#define CICR1_PPL_VAL(x) (((x) << 15) & CICR1_PPL) /* Pixels per line */ 15662306a36Sopenharmony_ci#define CICR1_COLOR_SP_VAL(x) (((x) << 3) & CICR1_COLOR_SP) /* color space */ 15762306a36Sopenharmony_ci#define CICR1_RGB_BPP_VAL(x) (((x) << 7) & CICR1_RGB_BPP) /* bpp for rgb */ 15862306a36Sopenharmony_ci#define CICR1_RGBT_CONV_VAL(x) (((x) << 29) & CICR1_RGBT_CONV) /* rgbt conv */ 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci#define CICR2_BLW_VAL(x) (((x) << 24) & CICR2_BLW) /* Beginning-of-line pixel clock wait count */ 16162306a36Sopenharmony_ci#define CICR2_ELW_VAL(x) (((x) << 16) & CICR2_ELW) /* End-of-line pixel clock wait count */ 16262306a36Sopenharmony_ci#define CICR2_HSW_VAL(x) (((x) << 10) & CICR2_HSW) /* Horizontal sync pulse width */ 16362306a36Sopenharmony_ci#define CICR2_BFPW_VAL(x) (((x) << 3) & CICR2_BFPW) /* Beginning-of-frame pixel clock wait count */ 16462306a36Sopenharmony_ci#define CICR2_FSW_VAL(x) (((x) << 0) & CICR2_FSW) /* Frame stabilization wait count */ 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci#define CICR3_BFW_VAL(x) (((x) << 24) & CICR3_BFW) /* Beginning-of-frame line clock wait count */ 16762306a36Sopenharmony_ci#define CICR3_EFW_VAL(x) (((x) << 16) & CICR3_EFW) /* End-of-frame line clock wait count */ 16862306a36Sopenharmony_ci#define CICR3_VSW_VAL(x) (((x) << 11) & CICR3_VSW) /* Vertical sync pulse width */ 16962306a36Sopenharmony_ci#define CICR3_LPF_VAL(x) (((x) << 0) & CICR3_LPF) /* Lines per frame */ 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci#define CICR0_IRQ_MASK (CICR0_TOM | CICR0_RDAVM | CICR0_FEM | CICR0_EOLM | \ 17262306a36Sopenharmony_ci CICR0_PERRM | CICR0_QDM | CICR0_CDM | CICR0_SOFM | \ 17362306a36Sopenharmony_ci CICR0_EOFM | CICR0_FOM) 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci#define sensor_call(cam, o, f, args...) \ 17662306a36Sopenharmony_ci v4l2_subdev_call(cam->sensor, o, f, ##args) 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/* 17962306a36Sopenharmony_ci * Format handling 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/** 18362306a36Sopenharmony_ci * enum pxa_mbus_packing - data packing types on the media-bus 18462306a36Sopenharmony_ci * @PXA_MBUS_PACKING_NONE: no packing, bit-for-bit transfer to RAM, one 18562306a36Sopenharmony_ci * sample represents one pixel 18662306a36Sopenharmony_ci * @PXA_MBUS_PACKING_2X8_PADHI: 16 bits transferred in 2 8-bit samples, in the 18762306a36Sopenharmony_ci * possibly incomplete byte high bits are padding 18862306a36Sopenharmony_ci * @PXA_MBUS_PACKING_EXTEND16: sample width (e.g., 10 bits) has to be extended 18962306a36Sopenharmony_ci * to 16 bits 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_cienum pxa_mbus_packing { 19262306a36Sopenharmony_ci PXA_MBUS_PACKING_NONE, 19362306a36Sopenharmony_ci PXA_MBUS_PACKING_2X8_PADHI, 19462306a36Sopenharmony_ci PXA_MBUS_PACKING_EXTEND16, 19562306a36Sopenharmony_ci}; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci/** 19862306a36Sopenharmony_ci * enum pxa_mbus_order - sample order on the media bus 19962306a36Sopenharmony_ci * @PXA_MBUS_ORDER_LE: least significant sample first 20062306a36Sopenharmony_ci * @PXA_MBUS_ORDER_BE: most significant sample first 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_cienum pxa_mbus_order { 20362306a36Sopenharmony_ci PXA_MBUS_ORDER_LE, 20462306a36Sopenharmony_ci PXA_MBUS_ORDER_BE, 20562306a36Sopenharmony_ci}; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci/** 20862306a36Sopenharmony_ci * enum pxa_mbus_layout - planes layout in memory 20962306a36Sopenharmony_ci * @PXA_MBUS_LAYOUT_PACKED: color components packed 21062306a36Sopenharmony_ci * @PXA_MBUS_LAYOUT_PLANAR_2Y_U_V: YUV components stored in 3 planes (4:2:2) 21162306a36Sopenharmony_ci * @PXA_MBUS_LAYOUT_PLANAR_2Y_C: YUV components stored in a luma and a 21262306a36Sopenharmony_ci * chroma plane (C plane is half the size 21362306a36Sopenharmony_ci * of Y plane) 21462306a36Sopenharmony_ci * @PXA_MBUS_LAYOUT_PLANAR_Y_C: YUV components stored in a luma and a 21562306a36Sopenharmony_ci * chroma plane (C plane is the same size 21662306a36Sopenharmony_ci * as Y plane) 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_cienum pxa_mbus_layout { 21962306a36Sopenharmony_ci PXA_MBUS_LAYOUT_PACKED = 0, 22062306a36Sopenharmony_ci PXA_MBUS_LAYOUT_PLANAR_2Y_U_V, 22162306a36Sopenharmony_ci PXA_MBUS_LAYOUT_PLANAR_2Y_C, 22262306a36Sopenharmony_ci PXA_MBUS_LAYOUT_PLANAR_Y_C, 22362306a36Sopenharmony_ci}; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci/** 22662306a36Sopenharmony_ci * struct pxa_mbus_pixelfmt - Data format on the media bus 22762306a36Sopenharmony_ci * @name: Name of the format 22862306a36Sopenharmony_ci * @fourcc: Fourcc code, that will be obtained if the data is 22962306a36Sopenharmony_ci * stored in memory in the following way: 23062306a36Sopenharmony_ci * @packing: Type of sample-packing, that has to be used 23162306a36Sopenharmony_ci * @order: Sample order when storing in memory 23262306a36Sopenharmony_ci * @layout: Planes layout in memory 23362306a36Sopenharmony_ci * @bits_per_sample: How many bits the bridge has to sample 23462306a36Sopenharmony_ci */ 23562306a36Sopenharmony_cistruct pxa_mbus_pixelfmt { 23662306a36Sopenharmony_ci const char *name; 23762306a36Sopenharmony_ci u32 fourcc; 23862306a36Sopenharmony_ci enum pxa_mbus_packing packing; 23962306a36Sopenharmony_ci enum pxa_mbus_order order; 24062306a36Sopenharmony_ci enum pxa_mbus_layout layout; 24162306a36Sopenharmony_ci u8 bits_per_sample; 24262306a36Sopenharmony_ci}; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci/** 24562306a36Sopenharmony_ci * struct pxa_mbus_lookup - Lookup FOURCC IDs by mediabus codes for pass-through 24662306a36Sopenharmony_ci * @code: mediabus pixel-code 24762306a36Sopenharmony_ci * @fmt: pixel format description 24862306a36Sopenharmony_ci */ 24962306a36Sopenharmony_cistruct pxa_mbus_lookup { 25062306a36Sopenharmony_ci u32 code; 25162306a36Sopenharmony_ci struct pxa_mbus_pixelfmt fmt; 25262306a36Sopenharmony_ci}; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic const struct pxa_mbus_lookup mbus_fmt[] = { 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_YUYV8_2X8, 25762306a36Sopenharmony_ci .fmt = { 25862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_YUYV, 25962306a36Sopenharmony_ci .name = "YUYV", 26062306a36Sopenharmony_ci .bits_per_sample = 8, 26162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_2X8_PADHI, 26262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 26362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 26462306a36Sopenharmony_ci }, 26562306a36Sopenharmony_ci}, { 26662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_YVYU8_2X8, 26762306a36Sopenharmony_ci .fmt = { 26862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_YVYU, 26962306a36Sopenharmony_ci .name = "YVYU", 27062306a36Sopenharmony_ci .bits_per_sample = 8, 27162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_2X8_PADHI, 27262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 27362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 27462306a36Sopenharmony_ci }, 27562306a36Sopenharmony_ci}, { 27662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_UYVY8_2X8, 27762306a36Sopenharmony_ci .fmt = { 27862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_UYVY, 27962306a36Sopenharmony_ci .name = "UYVY", 28062306a36Sopenharmony_ci .bits_per_sample = 8, 28162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_2X8_PADHI, 28262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 28362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 28462306a36Sopenharmony_ci }, 28562306a36Sopenharmony_ci}, { 28662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_VYUY8_2X8, 28762306a36Sopenharmony_ci .fmt = { 28862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_VYUY, 28962306a36Sopenharmony_ci .name = "VYUY", 29062306a36Sopenharmony_ci .bits_per_sample = 8, 29162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_2X8_PADHI, 29262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 29362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 29462306a36Sopenharmony_ci }, 29562306a36Sopenharmony_ci}, { 29662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, 29762306a36Sopenharmony_ci .fmt = { 29862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_RGB555, 29962306a36Sopenharmony_ci .name = "RGB555", 30062306a36Sopenharmony_ci .bits_per_sample = 8, 30162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_2X8_PADHI, 30262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 30362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 30462306a36Sopenharmony_ci }, 30562306a36Sopenharmony_ci}, { 30662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, 30762306a36Sopenharmony_ci .fmt = { 30862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_RGB555X, 30962306a36Sopenharmony_ci .name = "RGB555X", 31062306a36Sopenharmony_ci .bits_per_sample = 8, 31162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_2X8_PADHI, 31262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_BE, 31362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 31462306a36Sopenharmony_ci }, 31562306a36Sopenharmony_ci}, { 31662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_RGB565_2X8_LE, 31762306a36Sopenharmony_ci .fmt = { 31862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_RGB565, 31962306a36Sopenharmony_ci .name = "RGB565", 32062306a36Sopenharmony_ci .bits_per_sample = 8, 32162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_2X8_PADHI, 32262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 32362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 32462306a36Sopenharmony_ci }, 32562306a36Sopenharmony_ci}, { 32662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_RGB565_2X8_BE, 32762306a36Sopenharmony_ci .fmt = { 32862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_RGB565X, 32962306a36Sopenharmony_ci .name = "RGB565X", 33062306a36Sopenharmony_ci .bits_per_sample = 8, 33162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_2X8_PADHI, 33262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_BE, 33362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 33462306a36Sopenharmony_ci }, 33562306a36Sopenharmony_ci}, { 33662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_SBGGR8_1X8, 33762306a36Sopenharmony_ci .fmt = { 33862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SBGGR8, 33962306a36Sopenharmony_ci .name = "Bayer 8 BGGR", 34062306a36Sopenharmony_ci .bits_per_sample = 8, 34162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_NONE, 34262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 34362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 34462306a36Sopenharmony_ci }, 34562306a36Sopenharmony_ci}, { 34662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_SGBRG8_1X8, 34762306a36Sopenharmony_ci .fmt = { 34862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SGBRG8, 34962306a36Sopenharmony_ci .name = "Bayer 8 GBRG", 35062306a36Sopenharmony_ci .bits_per_sample = 8, 35162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_NONE, 35262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 35362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 35462306a36Sopenharmony_ci }, 35562306a36Sopenharmony_ci}, { 35662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_SGRBG8_1X8, 35762306a36Sopenharmony_ci .fmt = { 35862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SGRBG8, 35962306a36Sopenharmony_ci .name = "Bayer 8 GRBG", 36062306a36Sopenharmony_ci .bits_per_sample = 8, 36162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_NONE, 36262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 36362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 36462306a36Sopenharmony_ci }, 36562306a36Sopenharmony_ci}, { 36662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_SRGGB8_1X8, 36762306a36Sopenharmony_ci .fmt = { 36862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SRGGB8, 36962306a36Sopenharmony_ci .name = "Bayer 8 RGGB", 37062306a36Sopenharmony_ci .bits_per_sample = 8, 37162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_NONE, 37262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 37362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 37462306a36Sopenharmony_ci }, 37562306a36Sopenharmony_ci}, { 37662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_SBGGR10_1X10, 37762306a36Sopenharmony_ci .fmt = { 37862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SBGGR10, 37962306a36Sopenharmony_ci .name = "Bayer 10 BGGR", 38062306a36Sopenharmony_ci .bits_per_sample = 10, 38162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_EXTEND16, 38262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 38362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 38462306a36Sopenharmony_ci }, 38562306a36Sopenharmony_ci}, { 38662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_Y8_1X8, 38762306a36Sopenharmony_ci .fmt = { 38862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_GREY, 38962306a36Sopenharmony_ci .name = "Grey", 39062306a36Sopenharmony_ci .bits_per_sample = 8, 39162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_NONE, 39262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 39362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 39462306a36Sopenharmony_ci }, 39562306a36Sopenharmony_ci}, { 39662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_Y10_1X10, 39762306a36Sopenharmony_ci .fmt = { 39862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_Y10, 39962306a36Sopenharmony_ci .name = "Grey 10bit", 40062306a36Sopenharmony_ci .bits_per_sample = 10, 40162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_EXTEND16, 40262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 40362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 40462306a36Sopenharmony_ci }, 40562306a36Sopenharmony_ci}, { 40662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, 40762306a36Sopenharmony_ci .fmt = { 40862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SBGGR10, 40962306a36Sopenharmony_ci .name = "Bayer 10 BGGR", 41062306a36Sopenharmony_ci .bits_per_sample = 8, 41162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_2X8_PADHI, 41262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 41362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 41462306a36Sopenharmony_ci }, 41562306a36Sopenharmony_ci}, { 41662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE, 41762306a36Sopenharmony_ci .fmt = { 41862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SBGGR10, 41962306a36Sopenharmony_ci .name = "Bayer 10 BGGR", 42062306a36Sopenharmony_ci .bits_per_sample = 8, 42162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_2X8_PADHI, 42262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_BE, 42362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 42462306a36Sopenharmony_ci }, 42562306a36Sopenharmony_ci}, { 42662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE, 42762306a36Sopenharmony_ci .fmt = { 42862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_RGB444, 42962306a36Sopenharmony_ci .name = "RGB444", 43062306a36Sopenharmony_ci .bits_per_sample = 8, 43162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_2X8_PADHI, 43262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_BE, 43362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 43462306a36Sopenharmony_ci }, 43562306a36Sopenharmony_ci}, { 43662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_UYVY8_1X16, 43762306a36Sopenharmony_ci .fmt = { 43862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_UYVY, 43962306a36Sopenharmony_ci .name = "UYVY 16bit", 44062306a36Sopenharmony_ci .bits_per_sample = 16, 44162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_EXTEND16, 44262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 44362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 44462306a36Sopenharmony_ci }, 44562306a36Sopenharmony_ci}, { 44662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_VYUY8_1X16, 44762306a36Sopenharmony_ci .fmt = { 44862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_VYUY, 44962306a36Sopenharmony_ci .name = "VYUY 16bit", 45062306a36Sopenharmony_ci .bits_per_sample = 16, 45162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_EXTEND16, 45262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 45362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 45462306a36Sopenharmony_ci }, 45562306a36Sopenharmony_ci}, { 45662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_YUYV8_1X16, 45762306a36Sopenharmony_ci .fmt = { 45862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_YUYV, 45962306a36Sopenharmony_ci .name = "YUYV 16bit", 46062306a36Sopenharmony_ci .bits_per_sample = 16, 46162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_EXTEND16, 46262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 46362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 46462306a36Sopenharmony_ci }, 46562306a36Sopenharmony_ci}, { 46662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_YVYU8_1X16, 46762306a36Sopenharmony_ci .fmt = { 46862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_YVYU, 46962306a36Sopenharmony_ci .name = "YVYU 16bit", 47062306a36Sopenharmony_ci .bits_per_sample = 16, 47162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_EXTEND16, 47262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 47362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 47462306a36Sopenharmony_ci }, 47562306a36Sopenharmony_ci}, { 47662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, 47762306a36Sopenharmony_ci .fmt = { 47862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SGRBG10DPCM8, 47962306a36Sopenharmony_ci .name = "Bayer 10 BGGR DPCM 8", 48062306a36Sopenharmony_ci .bits_per_sample = 8, 48162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_NONE, 48262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 48362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 48462306a36Sopenharmony_ci }, 48562306a36Sopenharmony_ci}, { 48662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_SGBRG10_1X10, 48762306a36Sopenharmony_ci .fmt = { 48862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SGBRG10, 48962306a36Sopenharmony_ci .name = "Bayer 10 GBRG", 49062306a36Sopenharmony_ci .bits_per_sample = 10, 49162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_EXTEND16, 49262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 49362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 49462306a36Sopenharmony_ci }, 49562306a36Sopenharmony_ci}, { 49662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_SGRBG10_1X10, 49762306a36Sopenharmony_ci .fmt = { 49862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SGRBG10, 49962306a36Sopenharmony_ci .name = "Bayer 10 GRBG", 50062306a36Sopenharmony_ci .bits_per_sample = 10, 50162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_EXTEND16, 50262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 50362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 50462306a36Sopenharmony_ci }, 50562306a36Sopenharmony_ci}, { 50662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_SRGGB10_1X10, 50762306a36Sopenharmony_ci .fmt = { 50862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SRGGB10, 50962306a36Sopenharmony_ci .name = "Bayer 10 RGGB", 51062306a36Sopenharmony_ci .bits_per_sample = 10, 51162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_EXTEND16, 51262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 51362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 51462306a36Sopenharmony_ci }, 51562306a36Sopenharmony_ci}, { 51662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_SBGGR12_1X12, 51762306a36Sopenharmony_ci .fmt = { 51862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SBGGR12, 51962306a36Sopenharmony_ci .name = "Bayer 12 BGGR", 52062306a36Sopenharmony_ci .bits_per_sample = 12, 52162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_EXTEND16, 52262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 52362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 52462306a36Sopenharmony_ci }, 52562306a36Sopenharmony_ci}, { 52662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_SGBRG12_1X12, 52762306a36Sopenharmony_ci .fmt = { 52862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SGBRG12, 52962306a36Sopenharmony_ci .name = "Bayer 12 GBRG", 53062306a36Sopenharmony_ci .bits_per_sample = 12, 53162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_EXTEND16, 53262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 53362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 53462306a36Sopenharmony_ci }, 53562306a36Sopenharmony_ci}, { 53662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_SGRBG12_1X12, 53762306a36Sopenharmony_ci .fmt = { 53862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SGRBG12, 53962306a36Sopenharmony_ci .name = "Bayer 12 GRBG", 54062306a36Sopenharmony_ci .bits_per_sample = 12, 54162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_EXTEND16, 54262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 54362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 54462306a36Sopenharmony_ci }, 54562306a36Sopenharmony_ci}, { 54662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_SRGGB12_1X12, 54762306a36Sopenharmony_ci .fmt = { 54862306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_SRGGB12, 54962306a36Sopenharmony_ci .name = "Bayer 12 RGGB", 55062306a36Sopenharmony_ci .bits_per_sample = 12, 55162306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_EXTEND16, 55262306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 55362306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PACKED, 55462306a36Sopenharmony_ci }, 55562306a36Sopenharmony_ci}, 55662306a36Sopenharmony_ci}; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic s32 pxa_mbus_bytes_per_line(u32 width, const struct pxa_mbus_pixelfmt *mf) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci if (mf->layout != PXA_MBUS_LAYOUT_PACKED) 56162306a36Sopenharmony_ci return width * mf->bits_per_sample / 8; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci switch (mf->packing) { 56462306a36Sopenharmony_ci case PXA_MBUS_PACKING_NONE: 56562306a36Sopenharmony_ci return width * mf->bits_per_sample / 8; 56662306a36Sopenharmony_ci case PXA_MBUS_PACKING_2X8_PADHI: 56762306a36Sopenharmony_ci case PXA_MBUS_PACKING_EXTEND16: 56862306a36Sopenharmony_ci return width * 2; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci return -EINVAL; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistatic s32 pxa_mbus_image_size(const struct pxa_mbus_pixelfmt *mf, 57462306a36Sopenharmony_ci u32 bytes_per_line, u32 height) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci if (mf->layout == PXA_MBUS_LAYOUT_PACKED) 57762306a36Sopenharmony_ci return bytes_per_line * height; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci switch (mf->packing) { 58062306a36Sopenharmony_ci case PXA_MBUS_PACKING_2X8_PADHI: 58162306a36Sopenharmony_ci return bytes_per_line * height * 2; 58262306a36Sopenharmony_ci default: 58362306a36Sopenharmony_ci return -EINVAL; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistatic const struct pxa_mbus_pixelfmt *pxa_mbus_find_fmtdesc( 58862306a36Sopenharmony_ci u32 code, 58962306a36Sopenharmony_ci const struct pxa_mbus_lookup *lookup, 59062306a36Sopenharmony_ci int n) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci int i; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci for (i = 0; i < n; i++) 59562306a36Sopenharmony_ci if (lookup[i].code == code) 59662306a36Sopenharmony_ci return &lookup[i].fmt; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci return NULL; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic const struct pxa_mbus_pixelfmt *pxa_mbus_get_fmtdesc( 60262306a36Sopenharmony_ci u32 code) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci return pxa_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt)); 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci/** 60862306a36Sopenharmony_ci * struct pxa_camera_format_xlate - match between host and sensor formats 60962306a36Sopenharmony_ci * @code: code of a sensor provided format 61062306a36Sopenharmony_ci * @host_fmt: host format after host translation from code 61162306a36Sopenharmony_ci * 61262306a36Sopenharmony_ci * Host and sensor translation structure. Used in table of host and sensor 61362306a36Sopenharmony_ci * formats matchings in pxa_camera_device. A host can override the generic list 61462306a36Sopenharmony_ci * generation by implementing get_formats(), and use it for format checks and 61562306a36Sopenharmony_ci * format setup. 61662306a36Sopenharmony_ci */ 61762306a36Sopenharmony_cistruct pxa_camera_format_xlate { 61862306a36Sopenharmony_ci u32 code; 61962306a36Sopenharmony_ci const struct pxa_mbus_pixelfmt *host_fmt; 62062306a36Sopenharmony_ci}; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci/* 62362306a36Sopenharmony_ci * Structures 62462306a36Sopenharmony_ci */ 62562306a36Sopenharmony_cienum pxa_camera_active_dma { 62662306a36Sopenharmony_ci DMA_Y = 0x1, 62762306a36Sopenharmony_ci DMA_U = 0x2, 62862306a36Sopenharmony_ci DMA_V = 0x4, 62962306a36Sopenharmony_ci}; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci/* buffer for one video frame */ 63262306a36Sopenharmony_cistruct pxa_buffer { 63362306a36Sopenharmony_ci /* common v4l buffer stuff -- must be first */ 63462306a36Sopenharmony_ci struct vb2_v4l2_buffer vbuf; 63562306a36Sopenharmony_ci struct list_head queue; 63662306a36Sopenharmony_ci u32 code; 63762306a36Sopenharmony_ci int nb_planes; 63862306a36Sopenharmony_ci /* our descriptor lists for Y, U and V channels */ 63962306a36Sopenharmony_ci struct dma_async_tx_descriptor *descs[3]; 64062306a36Sopenharmony_ci dma_cookie_t cookie[3]; 64162306a36Sopenharmony_ci struct scatterlist *sg[3]; 64262306a36Sopenharmony_ci int sg_len[3]; 64362306a36Sopenharmony_ci size_t plane_sizes[3]; 64462306a36Sopenharmony_ci int inwork; 64562306a36Sopenharmony_ci enum pxa_camera_active_dma active_dma; 64662306a36Sopenharmony_ci}; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistruct pxa_camera_dev { 64962306a36Sopenharmony_ci struct v4l2_device v4l2_dev; 65062306a36Sopenharmony_ci struct video_device vdev; 65162306a36Sopenharmony_ci struct v4l2_async_notifier notifier; 65262306a36Sopenharmony_ci struct vb2_queue vb2_vq; 65362306a36Sopenharmony_ci struct v4l2_subdev *sensor; 65462306a36Sopenharmony_ci struct pxa_camera_format_xlate *user_formats; 65562306a36Sopenharmony_ci const struct pxa_camera_format_xlate *current_fmt; 65662306a36Sopenharmony_ci struct v4l2_pix_format current_pix; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci /* 65962306a36Sopenharmony_ci * PXA27x is only supposed to handle one camera on its Quick Capture 66062306a36Sopenharmony_ci * interface. If anyone ever builds hardware to enable more than 66162306a36Sopenharmony_ci * one camera, they will have to modify this driver too 66262306a36Sopenharmony_ci */ 66362306a36Sopenharmony_ci struct clk *clk; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci unsigned int irq; 66662306a36Sopenharmony_ci void __iomem *base; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci int channels; 66962306a36Sopenharmony_ci struct dma_chan *dma_chans[3]; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci struct pxacamera_platform_data *pdata; 67262306a36Sopenharmony_ci struct resource *res; 67362306a36Sopenharmony_ci unsigned long platform_flags; 67462306a36Sopenharmony_ci unsigned long ciclk; 67562306a36Sopenharmony_ci unsigned long mclk; 67662306a36Sopenharmony_ci u32 mclk_divisor; 67762306a36Sopenharmony_ci u16 width_flags; /* max 10 bits */ 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci struct list_head capture; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci spinlock_t lock; 68262306a36Sopenharmony_ci struct mutex mlock; 68362306a36Sopenharmony_ci unsigned int buf_sequence; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci struct pxa_buffer *active; 68662306a36Sopenharmony_ci struct tasklet_struct task_eof; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci u32 save_cicr[5]; 68962306a36Sopenharmony_ci}; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistruct pxa_cam { 69262306a36Sopenharmony_ci unsigned long flags; 69362306a36Sopenharmony_ci}; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cistatic const char *pxa_cam_driver_description = "PXA_Camera"; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci/* 69862306a36Sopenharmony_ci * Format translation functions 69962306a36Sopenharmony_ci */ 70062306a36Sopenharmony_cistatic const struct pxa_camera_format_xlate 70162306a36Sopenharmony_ci*pxa_mbus_xlate_by_fourcc(struct pxa_camera_format_xlate *user_formats, 70262306a36Sopenharmony_ci unsigned int fourcc) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci unsigned int i; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci for (i = 0; user_formats[i].code; i++) 70762306a36Sopenharmony_ci if (user_formats[i].host_fmt->fourcc == fourcc) 70862306a36Sopenharmony_ci return user_formats + i; 70962306a36Sopenharmony_ci return NULL; 71062306a36Sopenharmony_ci} 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_cistatic struct pxa_camera_format_xlate *pxa_mbus_build_fmts_xlate( 71362306a36Sopenharmony_ci struct v4l2_device *v4l2_dev, struct v4l2_subdev *subdev, 71462306a36Sopenharmony_ci int (*get_formats)(struct v4l2_device *, unsigned int, 71562306a36Sopenharmony_ci struct pxa_camera_format_xlate *xlate)) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci unsigned int i, fmts = 0, raw_fmts = 0; 71862306a36Sopenharmony_ci int ret; 71962306a36Sopenharmony_ci struct v4l2_subdev_mbus_code_enum code = { 72062306a36Sopenharmony_ci .which = V4L2_SUBDEV_FORMAT_ACTIVE, 72162306a36Sopenharmony_ci }; 72262306a36Sopenharmony_ci struct pxa_camera_format_xlate *user_formats; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci while (!v4l2_subdev_call(subdev, pad, enum_mbus_code, NULL, &code)) { 72562306a36Sopenharmony_ci raw_fmts++; 72662306a36Sopenharmony_ci code.index++; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci /* 73062306a36Sopenharmony_ci * First pass - only count formats this host-sensor 73162306a36Sopenharmony_ci * configuration can provide 73262306a36Sopenharmony_ci */ 73362306a36Sopenharmony_ci for (i = 0; i < raw_fmts; i++) { 73462306a36Sopenharmony_ci ret = get_formats(v4l2_dev, i, NULL); 73562306a36Sopenharmony_ci if (ret < 0) 73662306a36Sopenharmony_ci return ERR_PTR(ret); 73762306a36Sopenharmony_ci fmts += ret; 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (!fmts) 74162306a36Sopenharmony_ci return ERR_PTR(-ENXIO); 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci user_formats = kcalloc(fmts + 1, sizeof(*user_formats), GFP_KERNEL); 74462306a36Sopenharmony_ci if (!user_formats) 74562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci /* Second pass - actually fill data formats */ 74862306a36Sopenharmony_ci fmts = 0; 74962306a36Sopenharmony_ci for (i = 0; i < raw_fmts; i++) { 75062306a36Sopenharmony_ci ret = get_formats(v4l2_dev, i, user_formats + fmts); 75162306a36Sopenharmony_ci if (ret < 0) 75262306a36Sopenharmony_ci goto egfmt; 75362306a36Sopenharmony_ci fmts += ret; 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci user_formats[fmts].code = 0; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci return user_formats; 75862306a36Sopenharmony_ciegfmt: 75962306a36Sopenharmony_ci kfree(user_formats); 76062306a36Sopenharmony_ci return ERR_PTR(ret); 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci/* 76462306a36Sopenharmony_ci * Videobuf operations 76562306a36Sopenharmony_ci */ 76662306a36Sopenharmony_cistatic struct pxa_buffer *vb2_to_pxa_buffer(struct vb2_buffer *vb) 76762306a36Sopenharmony_ci{ 76862306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci return container_of(vbuf, struct pxa_buffer, vbuf); 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cistatic struct device *pcdev_to_dev(struct pxa_camera_dev *pcdev) 77462306a36Sopenharmony_ci{ 77562306a36Sopenharmony_ci return pcdev->v4l2_dev.dev; 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cistatic struct pxa_camera_dev *v4l2_dev_to_pcdev(struct v4l2_device *v4l2_dev) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci return container_of(v4l2_dev, struct pxa_camera_dev, v4l2_dev); 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_cistatic void pxa_camera_dma_irq(struct pxa_camera_dev *pcdev, 78462306a36Sopenharmony_ci enum pxa_camera_active_dma act_dma); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_cistatic void pxa_camera_dma_irq_y(void *data) 78762306a36Sopenharmony_ci{ 78862306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = data; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci pxa_camera_dma_irq(pcdev, DMA_Y); 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistatic void pxa_camera_dma_irq_u(void *data) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = data; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci pxa_camera_dma_irq(pcdev, DMA_U); 79862306a36Sopenharmony_ci} 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_cistatic void pxa_camera_dma_irq_v(void *data) 80162306a36Sopenharmony_ci{ 80262306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = data; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci pxa_camera_dma_irq(pcdev, DMA_V); 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci/** 80862306a36Sopenharmony_ci * pxa_init_dma_channel - init dma descriptors 80962306a36Sopenharmony_ci * @pcdev: pxa camera device 81062306a36Sopenharmony_ci * @buf: pxa camera buffer 81162306a36Sopenharmony_ci * @channel: dma channel (0 => 'Y', 1 => 'U', 2 => 'V') 81262306a36Sopenharmony_ci * @sg: dma scatter list 81362306a36Sopenharmony_ci * @sglen: dma scatter list length 81462306a36Sopenharmony_ci * 81562306a36Sopenharmony_ci * Prepares the pxa dma descriptors to transfer one camera channel. 81662306a36Sopenharmony_ci * 81762306a36Sopenharmony_ci * Returns 0 if success or -ENOMEM if no memory is available 81862306a36Sopenharmony_ci */ 81962306a36Sopenharmony_cistatic int pxa_init_dma_channel(struct pxa_camera_dev *pcdev, 82062306a36Sopenharmony_ci struct pxa_buffer *buf, int channel, 82162306a36Sopenharmony_ci struct scatterlist *sg, int sglen) 82262306a36Sopenharmony_ci{ 82362306a36Sopenharmony_ci struct dma_chan *dma_chan = pcdev->dma_chans[channel]; 82462306a36Sopenharmony_ci struct dma_async_tx_descriptor *tx; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci tx = dmaengine_prep_slave_sg(dma_chan, sg, sglen, DMA_DEV_TO_MEM, 82762306a36Sopenharmony_ci DMA_PREP_INTERRUPT | DMA_CTRL_REUSE); 82862306a36Sopenharmony_ci if (!tx) { 82962306a36Sopenharmony_ci dev_err(pcdev_to_dev(pcdev), 83062306a36Sopenharmony_ci "dmaengine_prep_slave_sg failed\n"); 83162306a36Sopenharmony_ci goto fail; 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci tx->callback_param = pcdev; 83562306a36Sopenharmony_ci switch (channel) { 83662306a36Sopenharmony_ci case 0: 83762306a36Sopenharmony_ci tx->callback = pxa_camera_dma_irq_y; 83862306a36Sopenharmony_ci break; 83962306a36Sopenharmony_ci case 1: 84062306a36Sopenharmony_ci tx->callback = pxa_camera_dma_irq_u; 84162306a36Sopenharmony_ci break; 84262306a36Sopenharmony_ci case 2: 84362306a36Sopenharmony_ci tx->callback = pxa_camera_dma_irq_v; 84462306a36Sopenharmony_ci break; 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci buf->descs[channel] = tx; 84862306a36Sopenharmony_ci return 0; 84962306a36Sopenharmony_cifail: 85062306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), 85162306a36Sopenharmony_ci "%s (vb=%p) dma_tx=%p\n", 85262306a36Sopenharmony_ci __func__, buf, tx); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci return -ENOMEM; 85562306a36Sopenharmony_ci} 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_cistatic void pxa_video_buf_set_actdma(struct pxa_camera_dev *pcdev, 85862306a36Sopenharmony_ci struct pxa_buffer *buf) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci buf->active_dma = DMA_Y; 86162306a36Sopenharmony_ci if (buf->nb_planes == 3) 86262306a36Sopenharmony_ci buf->active_dma |= DMA_U | DMA_V; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci/** 86662306a36Sopenharmony_ci * pxa_dma_start_channels - start DMA channel for active buffer 86762306a36Sopenharmony_ci * @pcdev: pxa camera device 86862306a36Sopenharmony_ci * 86962306a36Sopenharmony_ci * Initialize DMA channels to the beginning of the active video buffer, and 87062306a36Sopenharmony_ci * start these channels. 87162306a36Sopenharmony_ci */ 87262306a36Sopenharmony_cistatic void pxa_dma_start_channels(struct pxa_camera_dev *pcdev) 87362306a36Sopenharmony_ci{ 87462306a36Sopenharmony_ci int i; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci for (i = 0; i < pcdev->channels; i++) { 87762306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), 87862306a36Sopenharmony_ci "%s (channel=%d)\n", __func__, i); 87962306a36Sopenharmony_ci dma_async_issue_pending(pcdev->dma_chans[i]); 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci} 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_cistatic void pxa_dma_stop_channels(struct pxa_camera_dev *pcdev) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci int i; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci for (i = 0; i < pcdev->channels; i++) { 88862306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), 88962306a36Sopenharmony_ci "%s (channel=%d)\n", __func__, i); 89062306a36Sopenharmony_ci dmaengine_terminate_all(pcdev->dma_chans[i]); 89162306a36Sopenharmony_ci } 89262306a36Sopenharmony_ci} 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_cistatic void pxa_dma_add_tail_buf(struct pxa_camera_dev *pcdev, 89562306a36Sopenharmony_ci struct pxa_buffer *buf) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci int i; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci for (i = 0; i < pcdev->channels; i++) { 90062306a36Sopenharmony_ci buf->cookie[i] = dmaengine_submit(buf->descs[i]); 90162306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), 90262306a36Sopenharmony_ci "%s (channel=%d) : submit vb=%p cookie=%d\n", 90362306a36Sopenharmony_ci __func__, i, buf, buf->descs[i]->cookie); 90462306a36Sopenharmony_ci } 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci/** 90862306a36Sopenharmony_ci * pxa_camera_start_capture - start video capturing 90962306a36Sopenharmony_ci * @pcdev: camera device 91062306a36Sopenharmony_ci * 91162306a36Sopenharmony_ci * Launch capturing. DMA channels should not be active yet. They should get 91262306a36Sopenharmony_ci * activated at the end of frame interrupt, to capture only whole frames, and 91362306a36Sopenharmony_ci * never begin the capture of a partial frame. 91462306a36Sopenharmony_ci */ 91562306a36Sopenharmony_cistatic void pxa_camera_start_capture(struct pxa_camera_dev *pcdev) 91662306a36Sopenharmony_ci{ 91762306a36Sopenharmony_ci unsigned long cicr0; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), "%s\n", __func__); 92062306a36Sopenharmony_ci __raw_writel(__raw_readl(pcdev->base + CISR), pcdev->base + CISR); 92162306a36Sopenharmony_ci /* Enable End-Of-Frame Interrupt */ 92262306a36Sopenharmony_ci cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_ENB; 92362306a36Sopenharmony_ci cicr0 &= ~CICR0_EOFM; 92462306a36Sopenharmony_ci __raw_writel(cicr0, pcdev->base + CICR0); 92562306a36Sopenharmony_ci} 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_cistatic void pxa_camera_stop_capture(struct pxa_camera_dev *pcdev) 92862306a36Sopenharmony_ci{ 92962306a36Sopenharmony_ci unsigned long cicr0; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci pxa_dma_stop_channels(pcdev); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci cicr0 = __raw_readl(pcdev->base + CICR0) & ~CICR0_ENB; 93462306a36Sopenharmony_ci __raw_writel(cicr0, pcdev->base + CICR0); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci pcdev->active = NULL; 93762306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), "%s\n", __func__); 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cistatic void pxa_camera_wakeup(struct pxa_camera_dev *pcdev, 94162306a36Sopenharmony_ci struct pxa_buffer *buf, 94262306a36Sopenharmony_ci enum vb2_buffer_state state) 94362306a36Sopenharmony_ci{ 94462306a36Sopenharmony_ci struct vb2_buffer *vb = &buf->vbuf.vb2_buf; 94562306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci /* _init is used to debug races, see comment in pxa_camera_reqbufs() */ 94862306a36Sopenharmony_ci list_del_init(&buf->queue); 94962306a36Sopenharmony_ci vb->timestamp = ktime_get_ns(); 95062306a36Sopenharmony_ci vbuf->sequence = pcdev->buf_sequence++; 95162306a36Sopenharmony_ci vbuf->field = V4L2_FIELD_NONE; 95262306a36Sopenharmony_ci vb2_buffer_done(vb, VB2_BUF_STATE_DONE); 95362306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), "%s dequeued buffer (buf=0x%p)\n", 95462306a36Sopenharmony_ci __func__, buf); 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci if (list_empty(&pcdev->capture)) { 95762306a36Sopenharmony_ci pxa_camera_stop_capture(pcdev); 95862306a36Sopenharmony_ci return; 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci pcdev->active = list_entry(pcdev->capture.next, 96262306a36Sopenharmony_ci struct pxa_buffer, queue); 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci/** 96662306a36Sopenharmony_ci * pxa_camera_check_link_miss - check missed DMA linking 96762306a36Sopenharmony_ci * @pcdev: camera device 96862306a36Sopenharmony_ci * @last_submitted: an opaque DMA cookie for last submitted 96962306a36Sopenharmony_ci * @last_issued: an opaque DMA cookie for last issued 97062306a36Sopenharmony_ci * 97162306a36Sopenharmony_ci * The DMA chaining is done with DMA running. This means a tiny temporal window 97262306a36Sopenharmony_ci * remains, where a buffer is queued on the chain, while the chain is already 97362306a36Sopenharmony_ci * stopped. This means the tailed buffer would never be transferred by DMA. 97462306a36Sopenharmony_ci * This function restarts the capture for this corner case, where : 97562306a36Sopenharmony_ci * - DADR() == DADDR_STOP 97662306a36Sopenharmony_ci * - a video buffer is queued on the pcdev->capture list 97762306a36Sopenharmony_ci * 97862306a36Sopenharmony_ci * Please check the "DMA hot chaining timeslice issue" in 97962306a36Sopenharmony_ci * Documentation/driver-api/media/drivers/pxa_camera.rst 98062306a36Sopenharmony_ci * 98162306a36Sopenharmony_ci * Context: should only be called within the dma irq handler 98262306a36Sopenharmony_ci */ 98362306a36Sopenharmony_cistatic void pxa_camera_check_link_miss(struct pxa_camera_dev *pcdev, 98462306a36Sopenharmony_ci dma_cookie_t last_submitted, 98562306a36Sopenharmony_ci dma_cookie_t last_issued) 98662306a36Sopenharmony_ci{ 98762306a36Sopenharmony_ci bool is_dma_stopped = last_submitted != last_issued; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), 99062306a36Sopenharmony_ci "%s : top queued buffer=%p, is_dma_stopped=%d\n", 99162306a36Sopenharmony_ci __func__, pcdev->active, is_dma_stopped); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci if (pcdev->active && is_dma_stopped) 99462306a36Sopenharmony_ci pxa_camera_start_capture(pcdev); 99562306a36Sopenharmony_ci} 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_cistatic void pxa_camera_dma_irq(struct pxa_camera_dev *pcdev, 99862306a36Sopenharmony_ci enum pxa_camera_active_dma act_dma) 99962306a36Sopenharmony_ci{ 100062306a36Sopenharmony_ci struct pxa_buffer *buf, *last_buf; 100162306a36Sopenharmony_ci unsigned long flags; 100262306a36Sopenharmony_ci u32 camera_status, overrun; 100362306a36Sopenharmony_ci int chan; 100462306a36Sopenharmony_ci enum dma_status last_status; 100562306a36Sopenharmony_ci dma_cookie_t last_issued; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci spin_lock_irqsave(&pcdev->lock, flags); 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci camera_status = __raw_readl(pcdev->base + CISR); 101062306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), "camera dma irq, cisr=0x%x dma=%d\n", 101162306a36Sopenharmony_ci camera_status, act_dma); 101262306a36Sopenharmony_ci overrun = CISR_IFO_0; 101362306a36Sopenharmony_ci if (pcdev->channels == 3) 101462306a36Sopenharmony_ci overrun |= CISR_IFO_1 | CISR_IFO_2; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci /* 101762306a36Sopenharmony_ci * pcdev->active should not be NULL in DMA irq handler. 101862306a36Sopenharmony_ci * 101962306a36Sopenharmony_ci * But there is one corner case : if capture was stopped due to an 102062306a36Sopenharmony_ci * overrun of channel 1, and at that same channel 2 was completed. 102162306a36Sopenharmony_ci * 102262306a36Sopenharmony_ci * When handling the overrun in DMA irq for channel 1, we'll stop the 102362306a36Sopenharmony_ci * capture and restart it (and thus set pcdev->active to NULL). But the 102462306a36Sopenharmony_ci * DMA irq handler will already be pending for channel 2. So on entering 102562306a36Sopenharmony_ci * the DMA irq handler for channel 2 there will be no active buffer, yet 102662306a36Sopenharmony_ci * that is normal. 102762306a36Sopenharmony_ci */ 102862306a36Sopenharmony_ci if (!pcdev->active) 102962306a36Sopenharmony_ci goto out; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci buf = pcdev->active; 103262306a36Sopenharmony_ci WARN_ON(buf->inwork || list_empty(&buf->queue)); 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci /* 103562306a36Sopenharmony_ci * It's normal if the last frame creates an overrun, as there 103662306a36Sopenharmony_ci * are no more DMA descriptors to fetch from QCI fifos 103762306a36Sopenharmony_ci */ 103862306a36Sopenharmony_ci switch (act_dma) { 103962306a36Sopenharmony_ci case DMA_U: 104062306a36Sopenharmony_ci chan = 1; 104162306a36Sopenharmony_ci break; 104262306a36Sopenharmony_ci case DMA_V: 104362306a36Sopenharmony_ci chan = 2; 104462306a36Sopenharmony_ci break; 104562306a36Sopenharmony_ci default: 104662306a36Sopenharmony_ci chan = 0; 104762306a36Sopenharmony_ci break; 104862306a36Sopenharmony_ci } 104962306a36Sopenharmony_ci last_buf = list_entry(pcdev->capture.prev, 105062306a36Sopenharmony_ci struct pxa_buffer, queue); 105162306a36Sopenharmony_ci last_status = dma_async_is_tx_complete(pcdev->dma_chans[chan], 105262306a36Sopenharmony_ci last_buf->cookie[chan], 105362306a36Sopenharmony_ci NULL, &last_issued); 105462306a36Sopenharmony_ci if (camera_status & overrun && 105562306a36Sopenharmony_ci last_status != DMA_COMPLETE) { 105662306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), "FIFO overrun! CISR: %x\n", 105762306a36Sopenharmony_ci camera_status); 105862306a36Sopenharmony_ci pxa_camera_stop_capture(pcdev); 105962306a36Sopenharmony_ci list_for_each_entry(buf, &pcdev->capture, queue) 106062306a36Sopenharmony_ci pxa_dma_add_tail_buf(pcdev, buf); 106162306a36Sopenharmony_ci pxa_camera_start_capture(pcdev); 106262306a36Sopenharmony_ci goto out; 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci buf->active_dma &= ~act_dma; 106562306a36Sopenharmony_ci if (!buf->active_dma) { 106662306a36Sopenharmony_ci pxa_camera_wakeup(pcdev, buf, VB2_BUF_STATE_DONE); 106762306a36Sopenharmony_ci pxa_camera_check_link_miss(pcdev, last_buf->cookie[chan], 106862306a36Sopenharmony_ci last_issued); 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ciout: 107262306a36Sopenharmony_ci spin_unlock_irqrestore(&pcdev->lock, flags); 107362306a36Sopenharmony_ci} 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_cistatic u32 mclk_get_divisor(struct platform_device *pdev, 107662306a36Sopenharmony_ci struct pxa_camera_dev *pcdev) 107762306a36Sopenharmony_ci{ 107862306a36Sopenharmony_ci unsigned long mclk = pcdev->mclk; 107962306a36Sopenharmony_ci u32 div; 108062306a36Sopenharmony_ci unsigned long lcdclk; 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci lcdclk = clk_get_rate(pcdev->clk); 108362306a36Sopenharmony_ci pcdev->ciclk = lcdclk; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci /* mclk <= ciclk / 4 (27.4.2) */ 108662306a36Sopenharmony_ci if (mclk > lcdclk / 4) { 108762306a36Sopenharmony_ci mclk = lcdclk / 4; 108862306a36Sopenharmony_ci dev_warn(&pdev->dev, 108962306a36Sopenharmony_ci "Limiting master clock to %lu\n", mclk); 109062306a36Sopenharmony_ci } 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci /* We verify mclk != 0, so if anyone breaks it, here comes their Oops */ 109362306a36Sopenharmony_ci div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci /* If we're not supplying MCLK, leave it at 0 */ 109662306a36Sopenharmony_ci if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) 109762306a36Sopenharmony_ci pcdev->mclk = lcdclk / (2 * (div + 1)); 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci dev_dbg(&pdev->dev, "LCD clock %luHz, target freq %luHz, divisor %u\n", 110062306a36Sopenharmony_ci lcdclk, mclk, div); 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci return div; 110362306a36Sopenharmony_ci} 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_cistatic void recalculate_fifo_timeout(struct pxa_camera_dev *pcdev, 110662306a36Sopenharmony_ci unsigned long pclk) 110762306a36Sopenharmony_ci{ 110862306a36Sopenharmony_ci /* We want a timeout > 1 pixel time, not ">=" */ 110962306a36Sopenharmony_ci u32 ciclk_per_pixel = pcdev->ciclk / pclk + 1; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci __raw_writel(ciclk_per_pixel, pcdev->base + CITOR); 111262306a36Sopenharmony_ci} 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_cistatic void pxa_camera_activate(struct pxa_camera_dev *pcdev) 111562306a36Sopenharmony_ci{ 111662306a36Sopenharmony_ci u32 cicr4 = 0; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci /* disable all interrupts */ 111962306a36Sopenharmony_ci __raw_writel(0x3ff, pcdev->base + CICR0); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) 112262306a36Sopenharmony_ci cicr4 |= CICR4_PCLK_EN; 112362306a36Sopenharmony_ci if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) 112462306a36Sopenharmony_ci cicr4 |= CICR4_MCLK_EN; 112562306a36Sopenharmony_ci if (pcdev->platform_flags & PXA_CAMERA_PCP) 112662306a36Sopenharmony_ci cicr4 |= CICR4_PCP; 112762306a36Sopenharmony_ci if (pcdev->platform_flags & PXA_CAMERA_HSP) 112862306a36Sopenharmony_ci cicr4 |= CICR4_HSP; 112962306a36Sopenharmony_ci if (pcdev->platform_flags & PXA_CAMERA_VSP) 113062306a36Sopenharmony_ci cicr4 |= CICR4_VSP; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci __raw_writel(pcdev->mclk_divisor | cicr4, pcdev->base + CICR4); 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) 113562306a36Sopenharmony_ci /* Initialise the timeout under the assumption pclk = mclk */ 113662306a36Sopenharmony_ci recalculate_fifo_timeout(pcdev, pcdev->mclk); 113762306a36Sopenharmony_ci else 113862306a36Sopenharmony_ci /* "Safe default" - 13MHz */ 113962306a36Sopenharmony_ci recalculate_fifo_timeout(pcdev, 13000000); 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci clk_prepare_enable(pcdev->clk); 114262306a36Sopenharmony_ci} 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_cistatic void pxa_camera_deactivate(struct pxa_camera_dev *pcdev) 114562306a36Sopenharmony_ci{ 114662306a36Sopenharmony_ci clk_disable_unprepare(pcdev->clk); 114762306a36Sopenharmony_ci} 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_cistatic void pxa_camera_eof(struct tasklet_struct *t) 115062306a36Sopenharmony_ci{ 115162306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = from_tasklet(pcdev, t, task_eof); 115262306a36Sopenharmony_ci unsigned long cifr; 115362306a36Sopenharmony_ci struct pxa_buffer *buf; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), 115662306a36Sopenharmony_ci "Camera interrupt status 0x%x\n", 115762306a36Sopenharmony_ci __raw_readl(pcdev->base + CISR)); 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci /* Reset the FIFOs */ 116062306a36Sopenharmony_ci cifr = __raw_readl(pcdev->base + CIFR) | CIFR_RESET_F; 116162306a36Sopenharmony_ci __raw_writel(cifr, pcdev->base + CIFR); 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci pcdev->active = list_first_entry(&pcdev->capture, 116462306a36Sopenharmony_ci struct pxa_buffer, queue); 116562306a36Sopenharmony_ci buf = pcdev->active; 116662306a36Sopenharmony_ci pxa_video_buf_set_actdma(pcdev, buf); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci pxa_dma_start_channels(pcdev); 116962306a36Sopenharmony_ci} 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_cistatic irqreturn_t pxa_camera_irq(int irq, void *data) 117262306a36Sopenharmony_ci{ 117362306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = data; 117462306a36Sopenharmony_ci unsigned long status, cicr0; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci status = __raw_readl(pcdev->base + CISR); 117762306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), 117862306a36Sopenharmony_ci "Camera interrupt status 0x%lx\n", status); 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci if (!status) 118162306a36Sopenharmony_ci return IRQ_NONE; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci __raw_writel(status, pcdev->base + CISR); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci if (status & CISR_EOF) { 118662306a36Sopenharmony_ci cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_EOFM; 118762306a36Sopenharmony_ci __raw_writel(cicr0, pcdev->base + CICR0); 118862306a36Sopenharmony_ci tasklet_schedule(&pcdev->task_eof); 118962306a36Sopenharmony_ci } 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci return IRQ_HANDLED; 119262306a36Sopenharmony_ci} 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_cistatic void pxa_camera_setup_cicr(struct pxa_camera_dev *pcdev, 119562306a36Sopenharmony_ci unsigned long flags, __u32 pixfmt) 119662306a36Sopenharmony_ci{ 119762306a36Sopenharmony_ci unsigned long dw, bpp; 119862306a36Sopenharmony_ci u32 cicr0, cicr1, cicr2, cicr3, cicr4 = 0, y_skip_top; 119962306a36Sopenharmony_ci int ret = sensor_call(pcdev, sensor, g_skip_top_lines, &y_skip_top); 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci if (ret < 0) 120262306a36Sopenharmony_ci y_skip_top = 0; 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci /* 120562306a36Sopenharmony_ci * Datawidth is now guaranteed to be equal to one of the three values. 120662306a36Sopenharmony_ci * We fix bit-per-pixel equal to data-width... 120762306a36Sopenharmony_ci */ 120862306a36Sopenharmony_ci switch (pcdev->current_fmt->host_fmt->bits_per_sample) { 120962306a36Sopenharmony_ci case 10: 121062306a36Sopenharmony_ci dw = 4; 121162306a36Sopenharmony_ci bpp = 0x40; 121262306a36Sopenharmony_ci break; 121362306a36Sopenharmony_ci case 9: 121462306a36Sopenharmony_ci dw = 3; 121562306a36Sopenharmony_ci bpp = 0x20; 121662306a36Sopenharmony_ci break; 121762306a36Sopenharmony_ci default: 121862306a36Sopenharmony_ci /* 121962306a36Sopenharmony_ci * Actually it can only be 8 now, 122062306a36Sopenharmony_ci * default is just to silence compiler warnings 122162306a36Sopenharmony_ci */ 122262306a36Sopenharmony_ci case 8: 122362306a36Sopenharmony_ci dw = 2; 122462306a36Sopenharmony_ci bpp = 0; 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) 122862306a36Sopenharmony_ci cicr4 |= CICR4_PCLK_EN; 122962306a36Sopenharmony_ci if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN) 123062306a36Sopenharmony_ci cicr4 |= CICR4_MCLK_EN; 123162306a36Sopenharmony_ci if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) 123262306a36Sopenharmony_ci cicr4 |= CICR4_PCP; 123362306a36Sopenharmony_ci if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) 123462306a36Sopenharmony_ci cicr4 |= CICR4_HSP; 123562306a36Sopenharmony_ci if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) 123662306a36Sopenharmony_ci cicr4 |= CICR4_VSP; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci cicr0 = __raw_readl(pcdev->base + CICR0); 123962306a36Sopenharmony_ci if (cicr0 & CICR0_ENB) 124062306a36Sopenharmony_ci __raw_writel(cicr0 & ~CICR0_ENB, pcdev->base + CICR0); 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci cicr1 = CICR1_PPL_VAL(pcdev->current_pix.width - 1) | bpp | dw; 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci switch (pixfmt) { 124562306a36Sopenharmony_ci case V4L2_PIX_FMT_YUV422P: 124662306a36Sopenharmony_ci pcdev->channels = 3; 124762306a36Sopenharmony_ci cicr1 |= CICR1_YCBCR_F; 124862306a36Sopenharmony_ci /* 124962306a36Sopenharmony_ci * Normally, pxa bus wants as input UYVY format. We allow all 125062306a36Sopenharmony_ci * reorderings of the YUV422 format, as no processing is done, 125162306a36Sopenharmony_ci * and the YUV stream is just passed through without any 125262306a36Sopenharmony_ci * transformation. Note that UYVY is the only format that 125362306a36Sopenharmony_ci * should be used if pxa framebuffer Overlay2 is used. 125462306a36Sopenharmony_ci */ 125562306a36Sopenharmony_ci fallthrough; 125662306a36Sopenharmony_ci case V4L2_PIX_FMT_UYVY: 125762306a36Sopenharmony_ci case V4L2_PIX_FMT_VYUY: 125862306a36Sopenharmony_ci case V4L2_PIX_FMT_YUYV: 125962306a36Sopenharmony_ci case V4L2_PIX_FMT_YVYU: 126062306a36Sopenharmony_ci cicr1 |= CICR1_COLOR_SP_VAL(2); 126162306a36Sopenharmony_ci break; 126262306a36Sopenharmony_ci case V4L2_PIX_FMT_RGB555: 126362306a36Sopenharmony_ci cicr1 |= CICR1_RGB_BPP_VAL(1) | CICR1_RGBT_CONV_VAL(2) | 126462306a36Sopenharmony_ci CICR1_TBIT | CICR1_COLOR_SP_VAL(1); 126562306a36Sopenharmony_ci break; 126662306a36Sopenharmony_ci case V4L2_PIX_FMT_RGB565: 126762306a36Sopenharmony_ci cicr1 |= CICR1_COLOR_SP_VAL(1) | CICR1_RGB_BPP_VAL(2); 126862306a36Sopenharmony_ci break; 126962306a36Sopenharmony_ci } 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci cicr2 = 0; 127262306a36Sopenharmony_ci cicr3 = CICR3_LPF_VAL(pcdev->current_pix.height - 1) | 127362306a36Sopenharmony_ci CICR3_BFW_VAL(min((u32)255, y_skip_top)); 127462306a36Sopenharmony_ci cicr4 |= pcdev->mclk_divisor; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci __raw_writel(cicr1, pcdev->base + CICR1); 127762306a36Sopenharmony_ci __raw_writel(cicr2, pcdev->base + CICR2); 127862306a36Sopenharmony_ci __raw_writel(cicr3, pcdev->base + CICR3); 127962306a36Sopenharmony_ci __raw_writel(cicr4, pcdev->base + CICR4); 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci /* CIF interrupts are not used, only DMA */ 128262306a36Sopenharmony_ci cicr0 = (cicr0 & CICR0_ENB) | (pcdev->platform_flags & PXA_CAMERA_MASTER ? 128362306a36Sopenharmony_ci CICR0_SIM_MP : (CICR0_SL_CAP_EN | CICR0_SIM_SP)); 128462306a36Sopenharmony_ci cicr0 |= CICR0_DMAEN | CICR0_IRQ_MASK; 128562306a36Sopenharmony_ci __raw_writel(cicr0, pcdev->base + CICR0); 128662306a36Sopenharmony_ci} 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci/* 128962306a36Sopenharmony_ci * Videobuf2 section 129062306a36Sopenharmony_ci */ 129162306a36Sopenharmony_cistatic void pxa_buffer_cleanup(struct pxa_buffer *buf) 129262306a36Sopenharmony_ci{ 129362306a36Sopenharmony_ci int i; 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci for (i = 0; i < 3 && buf->descs[i]; i++) { 129662306a36Sopenharmony_ci dmaengine_desc_free(buf->descs[i]); 129762306a36Sopenharmony_ci kfree(buf->sg[i]); 129862306a36Sopenharmony_ci buf->descs[i] = NULL; 129962306a36Sopenharmony_ci buf->sg[i] = NULL; 130062306a36Sopenharmony_ci buf->sg_len[i] = 0; 130162306a36Sopenharmony_ci buf->plane_sizes[i] = 0; 130262306a36Sopenharmony_ci } 130362306a36Sopenharmony_ci buf->nb_planes = 0; 130462306a36Sopenharmony_ci} 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_cistatic int pxa_buffer_init(struct pxa_camera_dev *pcdev, 130762306a36Sopenharmony_ci struct pxa_buffer *buf) 130862306a36Sopenharmony_ci{ 130962306a36Sopenharmony_ci struct vb2_buffer *vb = &buf->vbuf.vb2_buf; 131062306a36Sopenharmony_ci struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); 131162306a36Sopenharmony_ci int nb_channels = pcdev->channels; 131262306a36Sopenharmony_ci int i, ret = 0; 131362306a36Sopenharmony_ci unsigned long size = vb2_plane_size(vb, 0); 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci switch (nb_channels) { 131662306a36Sopenharmony_ci case 1: 131762306a36Sopenharmony_ci buf->plane_sizes[0] = size; 131862306a36Sopenharmony_ci break; 131962306a36Sopenharmony_ci case 3: 132062306a36Sopenharmony_ci buf->plane_sizes[0] = size / 2; 132162306a36Sopenharmony_ci buf->plane_sizes[1] = size / 4; 132262306a36Sopenharmony_ci buf->plane_sizes[2] = size / 4; 132362306a36Sopenharmony_ci break; 132462306a36Sopenharmony_ci default: 132562306a36Sopenharmony_ci return -EINVAL; 132662306a36Sopenharmony_ci } 132762306a36Sopenharmony_ci buf->nb_planes = nb_channels; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci ret = sg_split(sgt->sgl, sgt->nents, 0, nb_channels, 133062306a36Sopenharmony_ci buf->plane_sizes, buf->sg, buf->sg_len, GFP_KERNEL); 133162306a36Sopenharmony_ci if (ret < 0) { 133262306a36Sopenharmony_ci dev_err(pcdev_to_dev(pcdev), 133362306a36Sopenharmony_ci "sg_split failed: %d\n", ret); 133462306a36Sopenharmony_ci return ret; 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci for (i = 0; i < nb_channels; i++) { 133762306a36Sopenharmony_ci ret = pxa_init_dma_channel(pcdev, buf, i, 133862306a36Sopenharmony_ci buf->sg[i], buf->sg_len[i]); 133962306a36Sopenharmony_ci if (ret) { 134062306a36Sopenharmony_ci pxa_buffer_cleanup(buf); 134162306a36Sopenharmony_ci return ret; 134262306a36Sopenharmony_ci } 134362306a36Sopenharmony_ci } 134462306a36Sopenharmony_ci INIT_LIST_HEAD(&buf->queue); 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci return ret; 134762306a36Sopenharmony_ci} 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_cistatic void pxac_vb2_cleanup(struct vb2_buffer *vb) 135062306a36Sopenharmony_ci{ 135162306a36Sopenharmony_ci struct pxa_buffer *buf = vb2_to_pxa_buffer(vb); 135262306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = vb2_get_drv_priv(vb->vb2_queue); 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), 135562306a36Sopenharmony_ci "%s(vb=%p)\n", __func__, vb); 135662306a36Sopenharmony_ci pxa_buffer_cleanup(buf); 135762306a36Sopenharmony_ci} 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_cistatic void pxac_vb2_queue(struct vb2_buffer *vb) 136062306a36Sopenharmony_ci{ 136162306a36Sopenharmony_ci struct pxa_buffer *buf = vb2_to_pxa_buffer(vb); 136262306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = vb2_get_drv_priv(vb->vb2_queue); 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), 136562306a36Sopenharmony_ci "%s(vb=%p) nb_channels=%d size=%lu active=%p\n", 136662306a36Sopenharmony_ci __func__, vb, pcdev->channels, vb2_get_plane_payload(vb, 0), 136762306a36Sopenharmony_ci pcdev->active); 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci list_add_tail(&buf->queue, &pcdev->capture); 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci pxa_dma_add_tail_buf(pcdev, buf); 137262306a36Sopenharmony_ci} 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci/* 137562306a36Sopenharmony_ci * Please check the DMA prepared buffer structure in : 137662306a36Sopenharmony_ci * Documentation/driver-api/media/drivers/pxa_camera.rst 137762306a36Sopenharmony_ci * Please check also in pxa_camera_check_link_miss() to understand why DMA chain 137862306a36Sopenharmony_ci * modification while DMA chain is running will work anyway. 137962306a36Sopenharmony_ci */ 138062306a36Sopenharmony_cistatic int pxac_vb2_prepare(struct vb2_buffer *vb) 138162306a36Sopenharmony_ci{ 138262306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = vb2_get_drv_priv(vb->vb2_queue); 138362306a36Sopenharmony_ci struct pxa_buffer *buf = vb2_to_pxa_buffer(vb); 138462306a36Sopenharmony_ci int ret = 0; 138562306a36Sopenharmony_ci#ifdef DEBUG 138662306a36Sopenharmony_ci int i; 138762306a36Sopenharmony_ci#endif 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci switch (pcdev->channels) { 139062306a36Sopenharmony_ci case 1: 139162306a36Sopenharmony_ci case 3: 139262306a36Sopenharmony_ci vb2_set_plane_payload(vb, 0, pcdev->current_pix.sizeimage); 139362306a36Sopenharmony_ci break; 139462306a36Sopenharmony_ci default: 139562306a36Sopenharmony_ci return -EINVAL; 139662306a36Sopenharmony_ci } 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), 139962306a36Sopenharmony_ci "%s (vb=%p) nb_channels=%d size=%lu\n", 140062306a36Sopenharmony_ci __func__, vb, pcdev->channels, vb2_get_plane_payload(vb, 0)); 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci WARN_ON(!pcdev->current_fmt); 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci#ifdef DEBUG 140562306a36Sopenharmony_ci /* 140662306a36Sopenharmony_ci * This can be useful if you want to see if we actually fill 140762306a36Sopenharmony_ci * the buffer with something 140862306a36Sopenharmony_ci */ 140962306a36Sopenharmony_ci for (i = 0; i < vb->num_planes; i++) 141062306a36Sopenharmony_ci memset((void *)vb2_plane_vaddr(vb, i), 141162306a36Sopenharmony_ci 0xaa, vb2_get_plane_payload(vb, i)); 141262306a36Sopenharmony_ci#endif 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci /* 141562306a36Sopenharmony_ci * I think, in buf_prepare you only have to protect global data, 141662306a36Sopenharmony_ci * the actual buffer is yours 141762306a36Sopenharmony_ci */ 141862306a36Sopenharmony_ci buf->inwork = 0; 141962306a36Sopenharmony_ci pxa_video_buf_set_actdma(pcdev, buf); 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci return ret; 142262306a36Sopenharmony_ci} 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_cistatic int pxac_vb2_init(struct vb2_buffer *vb) 142562306a36Sopenharmony_ci{ 142662306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = vb2_get_drv_priv(vb->vb2_queue); 142762306a36Sopenharmony_ci struct pxa_buffer *buf = vb2_to_pxa_buffer(vb); 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), 143062306a36Sopenharmony_ci "%s(nb_channels=%d)\n", 143162306a36Sopenharmony_ci __func__, pcdev->channels); 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci return pxa_buffer_init(pcdev, buf); 143462306a36Sopenharmony_ci} 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_cistatic int pxac_vb2_queue_setup(struct vb2_queue *vq, 143762306a36Sopenharmony_ci unsigned int *nbufs, 143862306a36Sopenharmony_ci unsigned int *num_planes, unsigned int sizes[], 143962306a36Sopenharmony_ci struct device *alloc_devs[]) 144062306a36Sopenharmony_ci{ 144162306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = vb2_get_drv_priv(vq); 144262306a36Sopenharmony_ci int size = pcdev->current_pix.sizeimage; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), 144562306a36Sopenharmony_ci "%s(vq=%p nbufs=%d num_planes=%d size=%d)\n", 144662306a36Sopenharmony_ci __func__, vq, *nbufs, *num_planes, size); 144762306a36Sopenharmony_ci /* 144862306a36Sopenharmony_ci * Called from VIDIOC_REQBUFS or in compatibility mode For YUV422P 144962306a36Sopenharmony_ci * format, even if there are 3 planes Y, U and V, we reply there is only 145062306a36Sopenharmony_ci * one plane, containing Y, U and V data, one after the other. 145162306a36Sopenharmony_ci */ 145262306a36Sopenharmony_ci if (*num_planes) 145362306a36Sopenharmony_ci return sizes[0] < size ? -EINVAL : 0; 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci *num_planes = 1; 145662306a36Sopenharmony_ci switch (pcdev->channels) { 145762306a36Sopenharmony_ci case 1: 145862306a36Sopenharmony_ci case 3: 145962306a36Sopenharmony_ci sizes[0] = size; 146062306a36Sopenharmony_ci break; 146162306a36Sopenharmony_ci default: 146262306a36Sopenharmony_ci return -EINVAL; 146362306a36Sopenharmony_ci } 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci if (!*nbufs) 146662306a36Sopenharmony_ci *nbufs = 1; 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci return 0; 146962306a36Sopenharmony_ci} 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_cistatic int pxac_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) 147262306a36Sopenharmony_ci{ 147362306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = vb2_get_drv_priv(vq); 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), "%s(count=%d) active=%p\n", 147662306a36Sopenharmony_ci __func__, count, pcdev->active); 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci pcdev->buf_sequence = 0; 147962306a36Sopenharmony_ci if (!pcdev->active) 148062306a36Sopenharmony_ci pxa_camera_start_capture(pcdev); 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci return 0; 148362306a36Sopenharmony_ci} 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_cistatic void pxac_vb2_stop_streaming(struct vb2_queue *vq) 148662306a36Sopenharmony_ci{ 148762306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = vb2_get_drv_priv(vq); 148862306a36Sopenharmony_ci struct pxa_buffer *buf, *tmp; 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), "%s active=%p\n", 149162306a36Sopenharmony_ci __func__, pcdev->active); 149262306a36Sopenharmony_ci pxa_camera_stop_capture(pcdev); 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci list_for_each_entry_safe(buf, tmp, &pcdev->capture, queue) 149562306a36Sopenharmony_ci pxa_camera_wakeup(pcdev, buf, VB2_BUF_STATE_ERROR); 149662306a36Sopenharmony_ci} 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_cistatic const struct vb2_ops pxac_vb2_ops = { 149962306a36Sopenharmony_ci .queue_setup = pxac_vb2_queue_setup, 150062306a36Sopenharmony_ci .buf_init = pxac_vb2_init, 150162306a36Sopenharmony_ci .buf_prepare = pxac_vb2_prepare, 150262306a36Sopenharmony_ci .buf_queue = pxac_vb2_queue, 150362306a36Sopenharmony_ci .buf_cleanup = pxac_vb2_cleanup, 150462306a36Sopenharmony_ci .start_streaming = pxac_vb2_start_streaming, 150562306a36Sopenharmony_ci .stop_streaming = pxac_vb2_stop_streaming, 150662306a36Sopenharmony_ci .wait_prepare = vb2_ops_wait_prepare, 150762306a36Sopenharmony_ci .wait_finish = vb2_ops_wait_finish, 150862306a36Sopenharmony_ci}; 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_cistatic int pxa_camera_init_videobuf2(struct pxa_camera_dev *pcdev) 151162306a36Sopenharmony_ci{ 151262306a36Sopenharmony_ci int ret; 151362306a36Sopenharmony_ci struct vb2_queue *vq = &pcdev->vb2_vq; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci memset(vq, 0, sizeof(*vq)); 151662306a36Sopenharmony_ci vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 151762306a36Sopenharmony_ci vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; 151862306a36Sopenharmony_ci vq->drv_priv = pcdev; 151962306a36Sopenharmony_ci vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; 152062306a36Sopenharmony_ci vq->buf_struct_size = sizeof(struct pxa_buffer); 152162306a36Sopenharmony_ci vq->dev = pcdev->v4l2_dev.dev; 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci vq->ops = &pxac_vb2_ops; 152462306a36Sopenharmony_ci vq->mem_ops = &vb2_dma_sg_memops; 152562306a36Sopenharmony_ci vq->lock = &pcdev->mlock; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci ret = vb2_queue_init(vq); 152862306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), 152962306a36Sopenharmony_ci "vb2_queue_init(vq=%p): %d\n", vq, ret); 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci return ret; 153262306a36Sopenharmony_ci} 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci/* 153562306a36Sopenharmony_ci * Video ioctls section 153662306a36Sopenharmony_ci */ 153762306a36Sopenharmony_cistatic int pxa_camera_set_bus_param(struct pxa_camera_dev *pcdev) 153862306a36Sopenharmony_ci{ 153962306a36Sopenharmony_ci unsigned int bus_width = pcdev->current_fmt->host_fmt->bits_per_sample; 154062306a36Sopenharmony_ci struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; 154162306a36Sopenharmony_ci u32 pixfmt = pcdev->current_fmt->host_fmt->fourcc; 154262306a36Sopenharmony_ci int mbus_config; 154362306a36Sopenharmony_ci int ret; 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci if (!((1 << (bus_width - 1)) & pcdev->width_flags)) { 154662306a36Sopenharmony_ci dev_err(pcdev_to_dev(pcdev), "Unsupported bus width %u", 154762306a36Sopenharmony_ci bus_width); 154862306a36Sopenharmony_ci return -EINVAL; 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci pcdev->channels = 1; 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci /* Make choices, based on platform preferences */ 155462306a36Sopenharmony_ci mbus_config = 0; 155562306a36Sopenharmony_ci if (pcdev->platform_flags & PXA_CAMERA_MASTER) 155662306a36Sopenharmony_ci mbus_config |= V4L2_MBUS_MASTER; 155762306a36Sopenharmony_ci else 155862306a36Sopenharmony_ci mbus_config |= V4L2_MBUS_SLAVE; 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci if (pcdev->platform_flags & PXA_CAMERA_HSP) 156162306a36Sopenharmony_ci mbus_config |= V4L2_MBUS_HSYNC_ACTIVE_HIGH; 156262306a36Sopenharmony_ci else 156362306a36Sopenharmony_ci mbus_config |= V4L2_MBUS_HSYNC_ACTIVE_LOW; 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci if (pcdev->platform_flags & PXA_CAMERA_VSP) 156662306a36Sopenharmony_ci mbus_config |= V4L2_MBUS_VSYNC_ACTIVE_HIGH; 156762306a36Sopenharmony_ci else 156862306a36Sopenharmony_ci mbus_config |= V4L2_MBUS_VSYNC_ACTIVE_LOW; 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci if (pcdev->platform_flags & PXA_CAMERA_PCP) 157162306a36Sopenharmony_ci mbus_config |= V4L2_MBUS_PCLK_SAMPLE_RISING; 157262306a36Sopenharmony_ci else 157362306a36Sopenharmony_ci mbus_config |= V4L2_MBUS_PCLK_SAMPLE_FALLING; 157462306a36Sopenharmony_ci mbus_config |= V4L2_MBUS_DATA_ACTIVE_HIGH; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci ret = sensor_call(pcdev, pad, get_mbus_config, 0, &cfg); 157762306a36Sopenharmony_ci if (ret < 0 && ret != -ENOIOCTLCMD) { 157862306a36Sopenharmony_ci dev_err(pcdev_to_dev(pcdev), 157962306a36Sopenharmony_ci "Failed to call get_mbus_config: %d\n", ret); 158062306a36Sopenharmony_ci return ret; 158162306a36Sopenharmony_ci } 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci /* 158462306a36Sopenharmony_ci * If the media bus configuration of the sensor differs, make sure it 158562306a36Sopenharmony_ci * is supported by the platform. 158662306a36Sopenharmony_ci * 158762306a36Sopenharmony_ci * PXA does not support V4L2_MBUS_DATA_ACTIVE_LOW and the bus mastering 158862306a36Sopenharmony_ci * roles should match. 158962306a36Sopenharmony_ci */ 159062306a36Sopenharmony_ci if (cfg.bus.parallel.flags != mbus_config) { 159162306a36Sopenharmony_ci unsigned int pxa_mbus_role = mbus_config & (V4L2_MBUS_MASTER | 159262306a36Sopenharmony_ci V4L2_MBUS_SLAVE); 159362306a36Sopenharmony_ci unsigned int flags = cfg.bus.parallel.flags; 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci if (pxa_mbus_role != (flags & (V4L2_MBUS_MASTER | 159662306a36Sopenharmony_ci V4L2_MBUS_SLAVE))) { 159762306a36Sopenharmony_ci dev_err(pcdev_to_dev(pcdev), 159862306a36Sopenharmony_ci "Unsupported mbus configuration: bus mastering\n"); 159962306a36Sopenharmony_ci return -EINVAL; 160062306a36Sopenharmony_ci } 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci if (flags & V4L2_MBUS_DATA_ACTIVE_LOW) { 160362306a36Sopenharmony_ci dev_err(pcdev_to_dev(pcdev), 160462306a36Sopenharmony_ci "Unsupported mbus configuration: DATA_ACTIVE_LOW\n"); 160562306a36Sopenharmony_ci return -EINVAL; 160662306a36Sopenharmony_ci } 160762306a36Sopenharmony_ci } 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci pxa_camera_setup_cicr(pcdev, cfg.bus.parallel.flags, pixfmt); 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci return 0; 161262306a36Sopenharmony_ci} 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_cistatic const struct pxa_mbus_pixelfmt pxa_camera_formats[] = { 161562306a36Sopenharmony_ci { 161662306a36Sopenharmony_ci .fourcc = V4L2_PIX_FMT_YUV422P, 161762306a36Sopenharmony_ci .name = "Planar YUV422 16 bit", 161862306a36Sopenharmony_ci .bits_per_sample = 8, 161962306a36Sopenharmony_ci .packing = PXA_MBUS_PACKING_2X8_PADHI, 162062306a36Sopenharmony_ci .order = PXA_MBUS_ORDER_LE, 162162306a36Sopenharmony_ci .layout = PXA_MBUS_LAYOUT_PLANAR_2Y_U_V, 162262306a36Sopenharmony_ci }, 162362306a36Sopenharmony_ci}; 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci/* This will be corrected as we get more formats */ 162662306a36Sopenharmony_cistatic bool pxa_camera_packing_supported(const struct pxa_mbus_pixelfmt *fmt) 162762306a36Sopenharmony_ci{ 162862306a36Sopenharmony_ci return fmt->packing == PXA_MBUS_PACKING_NONE || 162962306a36Sopenharmony_ci (fmt->bits_per_sample == 8 && 163062306a36Sopenharmony_ci fmt->packing == PXA_MBUS_PACKING_2X8_PADHI) || 163162306a36Sopenharmony_ci (fmt->bits_per_sample > 8 && 163262306a36Sopenharmony_ci fmt->packing == PXA_MBUS_PACKING_EXTEND16); 163362306a36Sopenharmony_ci} 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_cistatic int pxa_camera_get_formats(struct v4l2_device *v4l2_dev, 163662306a36Sopenharmony_ci unsigned int idx, 163762306a36Sopenharmony_ci struct pxa_camera_format_xlate *xlate) 163862306a36Sopenharmony_ci{ 163962306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = v4l2_dev_to_pcdev(v4l2_dev); 164062306a36Sopenharmony_ci int formats = 0, ret; 164162306a36Sopenharmony_ci struct v4l2_subdev_mbus_code_enum code = { 164262306a36Sopenharmony_ci .which = V4L2_SUBDEV_FORMAT_ACTIVE, 164362306a36Sopenharmony_ci .index = idx, 164462306a36Sopenharmony_ci }; 164562306a36Sopenharmony_ci const struct pxa_mbus_pixelfmt *fmt; 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci ret = sensor_call(pcdev, pad, enum_mbus_code, NULL, &code); 164862306a36Sopenharmony_ci if (ret < 0) 164962306a36Sopenharmony_ci /* No more formats */ 165062306a36Sopenharmony_ci return 0; 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci fmt = pxa_mbus_get_fmtdesc(code.code); 165362306a36Sopenharmony_ci if (!fmt) { 165462306a36Sopenharmony_ci dev_err(pcdev_to_dev(pcdev), 165562306a36Sopenharmony_ci "Invalid format code #%u: %d\n", idx, code.code); 165662306a36Sopenharmony_ci return 0; 165762306a36Sopenharmony_ci } 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci switch (code.code) { 166062306a36Sopenharmony_ci case MEDIA_BUS_FMT_UYVY8_2X8: 166162306a36Sopenharmony_ci formats++; 166262306a36Sopenharmony_ci if (xlate) { 166362306a36Sopenharmony_ci xlate->host_fmt = &pxa_camera_formats[0]; 166462306a36Sopenharmony_ci xlate->code = code.code; 166562306a36Sopenharmony_ci xlate++; 166662306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), 166762306a36Sopenharmony_ci "Providing format %s using code %d\n", 166862306a36Sopenharmony_ci pxa_camera_formats[0].name, code.code); 166962306a36Sopenharmony_ci } 167062306a36Sopenharmony_ci fallthrough; 167162306a36Sopenharmony_ci case MEDIA_BUS_FMT_VYUY8_2X8: 167262306a36Sopenharmony_ci case MEDIA_BUS_FMT_YUYV8_2X8: 167362306a36Sopenharmony_ci case MEDIA_BUS_FMT_YVYU8_2X8: 167462306a36Sopenharmony_ci case MEDIA_BUS_FMT_RGB565_2X8_LE: 167562306a36Sopenharmony_ci case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE: 167662306a36Sopenharmony_ci if (xlate) 167762306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), 167862306a36Sopenharmony_ci "Providing format %s packed\n", 167962306a36Sopenharmony_ci fmt->name); 168062306a36Sopenharmony_ci break; 168162306a36Sopenharmony_ci default: 168262306a36Sopenharmony_ci if (!pxa_camera_packing_supported(fmt)) 168362306a36Sopenharmony_ci return 0; 168462306a36Sopenharmony_ci if (xlate) 168562306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), 168662306a36Sopenharmony_ci "Providing format %s in pass-through mode\n", 168762306a36Sopenharmony_ci fmt->name); 168862306a36Sopenharmony_ci break; 168962306a36Sopenharmony_ci } 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci /* Generic pass-through */ 169262306a36Sopenharmony_ci formats++; 169362306a36Sopenharmony_ci if (xlate) { 169462306a36Sopenharmony_ci xlate->host_fmt = fmt; 169562306a36Sopenharmony_ci xlate->code = code.code; 169662306a36Sopenharmony_ci xlate++; 169762306a36Sopenharmony_ci } 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci return formats; 170062306a36Sopenharmony_ci} 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_cistatic int pxa_camera_build_formats(struct pxa_camera_dev *pcdev) 170362306a36Sopenharmony_ci{ 170462306a36Sopenharmony_ci struct pxa_camera_format_xlate *xlate; 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci xlate = pxa_mbus_build_fmts_xlate(&pcdev->v4l2_dev, pcdev->sensor, 170762306a36Sopenharmony_ci pxa_camera_get_formats); 170862306a36Sopenharmony_ci if (IS_ERR(xlate)) 170962306a36Sopenharmony_ci return PTR_ERR(xlate); 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci pcdev->user_formats = xlate; 171262306a36Sopenharmony_ci return 0; 171362306a36Sopenharmony_ci} 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_cistatic void pxa_camera_destroy_formats(struct pxa_camera_dev *pcdev) 171662306a36Sopenharmony_ci{ 171762306a36Sopenharmony_ci kfree(pcdev->user_formats); 171862306a36Sopenharmony_ci} 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_cistatic int pxa_camera_check_frame(u32 width, u32 height) 172162306a36Sopenharmony_ci{ 172262306a36Sopenharmony_ci /* limit to pxa hardware capabilities */ 172362306a36Sopenharmony_ci return height < 32 || height > 2048 || width < 48 || width > 2048 || 172462306a36Sopenharmony_ci (width & 0x01); 172562306a36Sopenharmony_ci} 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG 172862306a36Sopenharmony_cistatic int pxac_vidioc_g_register(struct file *file, void *priv, 172962306a36Sopenharmony_ci struct v4l2_dbg_register *reg) 173062306a36Sopenharmony_ci{ 173162306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = video_drvdata(file); 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci if (reg->reg > CIBR2) 173462306a36Sopenharmony_ci return -ERANGE; 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci reg->val = __raw_readl(pcdev->base + reg->reg); 173762306a36Sopenharmony_ci reg->size = sizeof(__u32); 173862306a36Sopenharmony_ci return 0; 173962306a36Sopenharmony_ci} 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_cistatic int pxac_vidioc_s_register(struct file *file, void *priv, 174262306a36Sopenharmony_ci const struct v4l2_dbg_register *reg) 174362306a36Sopenharmony_ci{ 174462306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = video_drvdata(file); 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci if (reg->reg > CIBR2) 174762306a36Sopenharmony_ci return -ERANGE; 174862306a36Sopenharmony_ci if (reg->size != sizeof(__u32)) 174962306a36Sopenharmony_ci return -EINVAL; 175062306a36Sopenharmony_ci __raw_writel(reg->val, pcdev->base + reg->reg); 175162306a36Sopenharmony_ci return 0; 175262306a36Sopenharmony_ci} 175362306a36Sopenharmony_ci#endif 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_cistatic int pxac_vidioc_enum_fmt_vid_cap(struct file *filp, void *priv, 175662306a36Sopenharmony_ci struct v4l2_fmtdesc *f) 175762306a36Sopenharmony_ci{ 175862306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = video_drvdata(filp); 175962306a36Sopenharmony_ci const struct pxa_mbus_pixelfmt *format; 176062306a36Sopenharmony_ci unsigned int idx; 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci for (idx = 0; pcdev->user_formats[idx].code; idx++); 176362306a36Sopenharmony_ci if (f->index >= idx) 176462306a36Sopenharmony_ci return -EINVAL; 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci format = pcdev->user_formats[f->index].host_fmt; 176762306a36Sopenharmony_ci f->pixelformat = format->fourcc; 176862306a36Sopenharmony_ci return 0; 176962306a36Sopenharmony_ci} 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_cistatic int pxac_vidioc_g_fmt_vid_cap(struct file *filp, void *priv, 177262306a36Sopenharmony_ci struct v4l2_format *f) 177362306a36Sopenharmony_ci{ 177462306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = video_drvdata(filp); 177562306a36Sopenharmony_ci struct v4l2_pix_format *pix = &f->fmt.pix; 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci pix->width = pcdev->current_pix.width; 177862306a36Sopenharmony_ci pix->height = pcdev->current_pix.height; 177962306a36Sopenharmony_ci pix->bytesperline = pcdev->current_pix.bytesperline; 178062306a36Sopenharmony_ci pix->sizeimage = pcdev->current_pix.sizeimage; 178162306a36Sopenharmony_ci pix->field = pcdev->current_pix.field; 178262306a36Sopenharmony_ci pix->pixelformat = pcdev->current_fmt->host_fmt->fourcc; 178362306a36Sopenharmony_ci pix->colorspace = pcdev->current_pix.colorspace; 178462306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), "current_fmt->fourcc: 0x%08x\n", 178562306a36Sopenharmony_ci pcdev->current_fmt->host_fmt->fourcc); 178662306a36Sopenharmony_ci return 0; 178762306a36Sopenharmony_ci} 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_cistatic int pxac_vidioc_try_fmt_vid_cap(struct file *filp, void *priv, 179062306a36Sopenharmony_ci struct v4l2_format *f) 179162306a36Sopenharmony_ci{ 179262306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = video_drvdata(filp); 179362306a36Sopenharmony_ci const struct pxa_camera_format_xlate *xlate; 179462306a36Sopenharmony_ci struct v4l2_pix_format *pix = &f->fmt.pix; 179562306a36Sopenharmony_ci struct v4l2_subdev_pad_config pad_cfg; 179662306a36Sopenharmony_ci struct v4l2_subdev_state pad_state = { 179762306a36Sopenharmony_ci .pads = &pad_cfg, 179862306a36Sopenharmony_ci }; 179962306a36Sopenharmony_ci struct v4l2_subdev_format format = { 180062306a36Sopenharmony_ci .which = V4L2_SUBDEV_FORMAT_TRY, 180162306a36Sopenharmony_ci }; 180262306a36Sopenharmony_ci struct v4l2_mbus_framefmt *mf = &format.format; 180362306a36Sopenharmony_ci __u32 pixfmt = pix->pixelformat; 180462306a36Sopenharmony_ci int ret; 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci xlate = pxa_mbus_xlate_by_fourcc(pcdev->user_formats, pixfmt); 180762306a36Sopenharmony_ci if (!xlate) { 180862306a36Sopenharmony_ci dev_warn(pcdev_to_dev(pcdev), "Format %x not found\n", pixfmt); 180962306a36Sopenharmony_ci return -EINVAL; 181062306a36Sopenharmony_ci } 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci /* 181362306a36Sopenharmony_ci * Limit to pxa hardware capabilities. YUV422P planar format requires 181462306a36Sopenharmony_ci * images size to be a multiple of 16 bytes. If not, zeros will be 181562306a36Sopenharmony_ci * inserted between Y and U planes, and U and V planes, which violates 181662306a36Sopenharmony_ci * the YUV422P standard. 181762306a36Sopenharmony_ci */ 181862306a36Sopenharmony_ci v4l_bound_align_image(&pix->width, 48, 2048, 1, 181962306a36Sopenharmony_ci &pix->height, 32, 2048, 0, 182062306a36Sopenharmony_ci pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0); 182162306a36Sopenharmony_ci 182262306a36Sopenharmony_ci v4l2_fill_mbus_format(mf, pix, xlate->code); 182362306a36Sopenharmony_ci ret = sensor_call(pcdev, pad, set_fmt, &pad_state, &format); 182462306a36Sopenharmony_ci if (ret < 0) 182562306a36Sopenharmony_ci return ret; 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci v4l2_fill_pix_format(pix, mf); 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ci /* Only progressive video supported so far */ 183062306a36Sopenharmony_ci switch (mf->field) { 183162306a36Sopenharmony_ci case V4L2_FIELD_ANY: 183262306a36Sopenharmony_ci case V4L2_FIELD_NONE: 183362306a36Sopenharmony_ci pix->field = V4L2_FIELD_NONE; 183462306a36Sopenharmony_ci break; 183562306a36Sopenharmony_ci default: 183662306a36Sopenharmony_ci /* TODO: support interlaced at least in pass-through mode */ 183762306a36Sopenharmony_ci dev_err(pcdev_to_dev(pcdev), "Field type %d unsupported.\n", 183862306a36Sopenharmony_ci mf->field); 183962306a36Sopenharmony_ci return -EINVAL; 184062306a36Sopenharmony_ci } 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci ret = pxa_mbus_bytes_per_line(pix->width, xlate->host_fmt); 184362306a36Sopenharmony_ci if (ret < 0) 184462306a36Sopenharmony_ci return ret; 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci pix->bytesperline = ret; 184762306a36Sopenharmony_ci ret = pxa_mbus_image_size(xlate->host_fmt, pix->bytesperline, 184862306a36Sopenharmony_ci pix->height); 184962306a36Sopenharmony_ci if (ret < 0) 185062306a36Sopenharmony_ci return ret; 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci pix->sizeimage = ret; 185362306a36Sopenharmony_ci return 0; 185462306a36Sopenharmony_ci} 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_cistatic int pxac_vidioc_s_fmt_vid_cap(struct file *filp, void *priv, 185762306a36Sopenharmony_ci struct v4l2_format *f) 185862306a36Sopenharmony_ci{ 185962306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = video_drvdata(filp); 186062306a36Sopenharmony_ci const struct pxa_camera_format_xlate *xlate; 186162306a36Sopenharmony_ci struct v4l2_pix_format *pix = &f->fmt.pix; 186262306a36Sopenharmony_ci struct v4l2_subdev_format format = { 186362306a36Sopenharmony_ci .which = V4L2_SUBDEV_FORMAT_ACTIVE, 186462306a36Sopenharmony_ci }; 186562306a36Sopenharmony_ci unsigned long flags; 186662306a36Sopenharmony_ci int ret, is_busy; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci dev_dbg(pcdev_to_dev(pcdev), 186962306a36Sopenharmony_ci "s_fmt_vid_cap(pix=%dx%d:%x)\n", 187062306a36Sopenharmony_ci pix->width, pix->height, pix->pixelformat); 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_ci spin_lock_irqsave(&pcdev->lock, flags); 187362306a36Sopenharmony_ci is_busy = pcdev->active || vb2_is_busy(&pcdev->vb2_vq); 187462306a36Sopenharmony_ci spin_unlock_irqrestore(&pcdev->lock, flags); 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci if (is_busy) 187762306a36Sopenharmony_ci return -EBUSY; 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci ret = pxac_vidioc_try_fmt_vid_cap(filp, priv, f); 188062306a36Sopenharmony_ci if (ret) 188162306a36Sopenharmony_ci return ret; 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci xlate = pxa_mbus_xlate_by_fourcc(pcdev->user_formats, 188462306a36Sopenharmony_ci pix->pixelformat); 188562306a36Sopenharmony_ci v4l2_fill_mbus_format(&format.format, pix, xlate->code); 188662306a36Sopenharmony_ci ret = sensor_call(pcdev, pad, set_fmt, NULL, &format); 188762306a36Sopenharmony_ci if (ret < 0) { 188862306a36Sopenharmony_ci dev_warn(pcdev_to_dev(pcdev), 188962306a36Sopenharmony_ci "Failed to configure for format %x\n", 189062306a36Sopenharmony_ci pix->pixelformat); 189162306a36Sopenharmony_ci } else if (pxa_camera_check_frame(pix->width, pix->height)) { 189262306a36Sopenharmony_ci dev_warn(pcdev_to_dev(pcdev), 189362306a36Sopenharmony_ci "Camera driver produced an unsupported frame %dx%d\n", 189462306a36Sopenharmony_ci pix->width, pix->height); 189562306a36Sopenharmony_ci return -EINVAL; 189662306a36Sopenharmony_ci } 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci pcdev->current_fmt = xlate; 189962306a36Sopenharmony_ci pcdev->current_pix = *pix; 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci ret = pxa_camera_set_bus_param(pcdev); 190262306a36Sopenharmony_ci return ret; 190362306a36Sopenharmony_ci} 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_cistatic int pxac_vidioc_querycap(struct file *file, void *priv, 190662306a36Sopenharmony_ci struct v4l2_capability *cap) 190762306a36Sopenharmony_ci{ 190862306a36Sopenharmony_ci strscpy(cap->bus_info, "platform:pxa-camera", sizeof(cap->bus_info)); 190962306a36Sopenharmony_ci strscpy(cap->driver, PXA_CAM_DRV_NAME, sizeof(cap->driver)); 191062306a36Sopenharmony_ci strscpy(cap->card, pxa_cam_driver_description, sizeof(cap->card)); 191162306a36Sopenharmony_ci return 0; 191262306a36Sopenharmony_ci} 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_cistatic int pxac_vidioc_enum_input(struct file *file, void *priv, 191562306a36Sopenharmony_ci struct v4l2_input *i) 191662306a36Sopenharmony_ci{ 191762306a36Sopenharmony_ci if (i->index > 0) 191862306a36Sopenharmony_ci return -EINVAL; 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci i->type = V4L2_INPUT_TYPE_CAMERA; 192162306a36Sopenharmony_ci strscpy(i->name, "Camera", sizeof(i->name)); 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci return 0; 192462306a36Sopenharmony_ci} 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_cistatic int pxac_vidioc_g_input(struct file *file, void *priv, unsigned int *i) 192762306a36Sopenharmony_ci{ 192862306a36Sopenharmony_ci *i = 0; 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci return 0; 193162306a36Sopenharmony_ci} 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_cistatic int pxac_vidioc_s_input(struct file *file, void *priv, unsigned int i) 193462306a36Sopenharmony_ci{ 193562306a36Sopenharmony_ci if (i > 0) 193662306a36Sopenharmony_ci return -EINVAL; 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci return 0; 193962306a36Sopenharmony_ci} 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_cistatic int pxac_sensor_set_power(struct pxa_camera_dev *pcdev, int on) 194262306a36Sopenharmony_ci{ 194362306a36Sopenharmony_ci int ret; 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci ret = sensor_call(pcdev, core, s_power, on); 194662306a36Sopenharmony_ci if (ret == -ENOIOCTLCMD) 194762306a36Sopenharmony_ci ret = 0; 194862306a36Sopenharmony_ci if (ret) { 194962306a36Sopenharmony_ci dev_warn(pcdev_to_dev(pcdev), 195062306a36Sopenharmony_ci "Failed to put subdevice in %s mode: %d\n", 195162306a36Sopenharmony_ci on ? "normal operation" : "power saving", ret); 195262306a36Sopenharmony_ci } 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_ci return ret; 195562306a36Sopenharmony_ci} 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_cistatic int pxac_fops_camera_open(struct file *filp) 195862306a36Sopenharmony_ci{ 195962306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = video_drvdata(filp); 196062306a36Sopenharmony_ci int ret; 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ci mutex_lock(&pcdev->mlock); 196362306a36Sopenharmony_ci ret = v4l2_fh_open(filp); 196462306a36Sopenharmony_ci if (ret < 0) 196562306a36Sopenharmony_ci goto out; 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci if (!v4l2_fh_is_singular_file(filp)) 196862306a36Sopenharmony_ci goto out; 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci ret = pxac_sensor_set_power(pcdev, 1); 197162306a36Sopenharmony_ci if (ret) 197262306a36Sopenharmony_ci v4l2_fh_release(filp); 197362306a36Sopenharmony_ciout: 197462306a36Sopenharmony_ci mutex_unlock(&pcdev->mlock); 197562306a36Sopenharmony_ci return ret; 197662306a36Sopenharmony_ci} 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_cistatic int pxac_fops_camera_release(struct file *filp) 197962306a36Sopenharmony_ci{ 198062306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = video_drvdata(filp); 198162306a36Sopenharmony_ci int ret; 198262306a36Sopenharmony_ci bool fh_singular; 198362306a36Sopenharmony_ci 198462306a36Sopenharmony_ci mutex_lock(&pcdev->mlock); 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci fh_singular = v4l2_fh_is_singular_file(filp); 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci ret = _vb2_fop_release(filp, NULL); 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci if (fh_singular) 199162306a36Sopenharmony_ci ret = pxac_sensor_set_power(pcdev, 0); 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci mutex_unlock(&pcdev->mlock); 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ci return ret; 199662306a36Sopenharmony_ci} 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_cistatic const struct v4l2_file_operations pxa_camera_fops = { 199962306a36Sopenharmony_ci .owner = THIS_MODULE, 200062306a36Sopenharmony_ci .open = pxac_fops_camera_open, 200162306a36Sopenharmony_ci .release = pxac_fops_camera_release, 200262306a36Sopenharmony_ci .read = vb2_fop_read, 200362306a36Sopenharmony_ci .poll = vb2_fop_poll, 200462306a36Sopenharmony_ci .mmap = vb2_fop_mmap, 200562306a36Sopenharmony_ci .unlocked_ioctl = video_ioctl2, 200662306a36Sopenharmony_ci}; 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_cistatic const struct v4l2_ioctl_ops pxa_camera_ioctl_ops = { 200962306a36Sopenharmony_ci .vidioc_querycap = pxac_vidioc_querycap, 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci .vidioc_enum_input = pxac_vidioc_enum_input, 201262306a36Sopenharmony_ci .vidioc_g_input = pxac_vidioc_g_input, 201362306a36Sopenharmony_ci .vidioc_s_input = pxac_vidioc_s_input, 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ci .vidioc_enum_fmt_vid_cap = pxac_vidioc_enum_fmt_vid_cap, 201662306a36Sopenharmony_ci .vidioc_g_fmt_vid_cap = pxac_vidioc_g_fmt_vid_cap, 201762306a36Sopenharmony_ci .vidioc_s_fmt_vid_cap = pxac_vidioc_s_fmt_vid_cap, 201862306a36Sopenharmony_ci .vidioc_try_fmt_vid_cap = pxac_vidioc_try_fmt_vid_cap, 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci .vidioc_reqbufs = vb2_ioctl_reqbufs, 202162306a36Sopenharmony_ci .vidioc_create_bufs = vb2_ioctl_create_bufs, 202262306a36Sopenharmony_ci .vidioc_querybuf = vb2_ioctl_querybuf, 202362306a36Sopenharmony_ci .vidioc_qbuf = vb2_ioctl_qbuf, 202462306a36Sopenharmony_ci .vidioc_dqbuf = vb2_ioctl_dqbuf, 202562306a36Sopenharmony_ci .vidioc_expbuf = vb2_ioctl_expbuf, 202662306a36Sopenharmony_ci .vidioc_streamon = vb2_ioctl_streamon, 202762306a36Sopenharmony_ci .vidioc_streamoff = vb2_ioctl_streamoff, 202862306a36Sopenharmony_ci#ifdef CONFIG_VIDEO_ADV_DEBUG 202962306a36Sopenharmony_ci .vidioc_g_register = pxac_vidioc_g_register, 203062306a36Sopenharmony_ci .vidioc_s_register = pxac_vidioc_s_register, 203162306a36Sopenharmony_ci#endif 203262306a36Sopenharmony_ci .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 203362306a36Sopenharmony_ci .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 203462306a36Sopenharmony_ci}; 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_cistatic const struct video_device pxa_camera_videodev_template = { 203762306a36Sopenharmony_ci .name = "pxa-camera", 203862306a36Sopenharmony_ci .minor = -1, 203962306a36Sopenharmony_ci .fops = &pxa_camera_fops, 204062306a36Sopenharmony_ci .ioctl_ops = &pxa_camera_ioctl_ops, 204162306a36Sopenharmony_ci .release = video_device_release_empty, 204262306a36Sopenharmony_ci .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING, 204362306a36Sopenharmony_ci}; 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_cistatic int pxa_camera_sensor_bound(struct v4l2_async_notifier *notifier, 204662306a36Sopenharmony_ci struct v4l2_subdev *subdev, 204762306a36Sopenharmony_ci struct v4l2_async_connection *asd) 204862306a36Sopenharmony_ci{ 204962306a36Sopenharmony_ci int err; 205062306a36Sopenharmony_ci struct v4l2_device *v4l2_dev = notifier->v4l2_dev; 205162306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = v4l2_dev_to_pcdev(v4l2_dev); 205262306a36Sopenharmony_ci struct video_device *vdev = &pcdev->vdev; 205362306a36Sopenharmony_ci struct v4l2_pix_format *pix = &pcdev->current_pix; 205462306a36Sopenharmony_ci struct v4l2_subdev_format format = { 205562306a36Sopenharmony_ci .which = V4L2_SUBDEV_FORMAT_ACTIVE, 205662306a36Sopenharmony_ci }; 205762306a36Sopenharmony_ci struct v4l2_mbus_framefmt *mf = &format.format; 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci dev_info(pcdev_to_dev(pcdev), "%s(): trying to bind a device\n", 206062306a36Sopenharmony_ci __func__); 206162306a36Sopenharmony_ci mutex_lock(&pcdev->mlock); 206262306a36Sopenharmony_ci *vdev = pxa_camera_videodev_template; 206362306a36Sopenharmony_ci vdev->v4l2_dev = v4l2_dev; 206462306a36Sopenharmony_ci vdev->lock = &pcdev->mlock; 206562306a36Sopenharmony_ci pcdev->sensor = subdev; 206662306a36Sopenharmony_ci pcdev->vdev.queue = &pcdev->vb2_vq; 206762306a36Sopenharmony_ci pcdev->vdev.v4l2_dev = &pcdev->v4l2_dev; 206862306a36Sopenharmony_ci pcdev->vdev.ctrl_handler = subdev->ctrl_handler; 206962306a36Sopenharmony_ci video_set_drvdata(&pcdev->vdev, pcdev); 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci err = pxa_camera_build_formats(pcdev); 207262306a36Sopenharmony_ci if (err) { 207362306a36Sopenharmony_ci dev_err(pcdev_to_dev(pcdev), "building formats failed: %d\n", 207462306a36Sopenharmony_ci err); 207562306a36Sopenharmony_ci goto out; 207662306a36Sopenharmony_ci } 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci pcdev->current_fmt = pcdev->user_formats; 207962306a36Sopenharmony_ci pix->field = V4L2_FIELD_NONE; 208062306a36Sopenharmony_ci pix->width = DEFAULT_WIDTH; 208162306a36Sopenharmony_ci pix->height = DEFAULT_HEIGHT; 208262306a36Sopenharmony_ci pix->bytesperline = 208362306a36Sopenharmony_ci pxa_mbus_bytes_per_line(pix->width, 208462306a36Sopenharmony_ci pcdev->current_fmt->host_fmt); 208562306a36Sopenharmony_ci pix->sizeimage = 208662306a36Sopenharmony_ci pxa_mbus_image_size(pcdev->current_fmt->host_fmt, 208762306a36Sopenharmony_ci pix->bytesperline, pix->height); 208862306a36Sopenharmony_ci pix->pixelformat = pcdev->current_fmt->host_fmt->fourcc; 208962306a36Sopenharmony_ci v4l2_fill_mbus_format(mf, pix, pcdev->current_fmt->code); 209062306a36Sopenharmony_ci 209162306a36Sopenharmony_ci err = pxac_sensor_set_power(pcdev, 1); 209262306a36Sopenharmony_ci if (err) 209362306a36Sopenharmony_ci goto out; 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_ci err = sensor_call(pcdev, pad, set_fmt, NULL, &format); 209662306a36Sopenharmony_ci if (err) 209762306a36Sopenharmony_ci goto out_sensor_poweroff; 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci v4l2_fill_pix_format(pix, mf); 210062306a36Sopenharmony_ci pr_info("%s(): colorspace=0x%x pixfmt=0x%x\n", 210162306a36Sopenharmony_ci __func__, pix->colorspace, pix->pixelformat); 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci err = pxa_camera_init_videobuf2(pcdev); 210462306a36Sopenharmony_ci if (err) 210562306a36Sopenharmony_ci goto out_sensor_poweroff; 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci err = video_register_device(&pcdev->vdev, VFL_TYPE_VIDEO, -1); 210862306a36Sopenharmony_ci if (err) { 210962306a36Sopenharmony_ci v4l2_err(v4l2_dev, "register video device failed: %d\n", err); 211062306a36Sopenharmony_ci pcdev->sensor = NULL; 211162306a36Sopenharmony_ci } else { 211262306a36Sopenharmony_ci dev_info(pcdev_to_dev(pcdev), 211362306a36Sopenharmony_ci "PXA Camera driver attached to camera %s\n", 211462306a36Sopenharmony_ci subdev->name); 211562306a36Sopenharmony_ci } 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ciout_sensor_poweroff: 211862306a36Sopenharmony_ci err = pxac_sensor_set_power(pcdev, 0); 211962306a36Sopenharmony_ciout: 212062306a36Sopenharmony_ci mutex_unlock(&pcdev->mlock); 212162306a36Sopenharmony_ci return err; 212262306a36Sopenharmony_ci} 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_cistatic void pxa_camera_sensor_unbind(struct v4l2_async_notifier *notifier, 212562306a36Sopenharmony_ci struct v4l2_subdev *subdev, 212662306a36Sopenharmony_ci struct v4l2_async_connection *asd) 212762306a36Sopenharmony_ci{ 212862306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = v4l2_dev_to_pcdev(notifier->v4l2_dev); 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci mutex_lock(&pcdev->mlock); 213162306a36Sopenharmony_ci dev_info(pcdev_to_dev(pcdev), 213262306a36Sopenharmony_ci "PXA Camera driver detached from camera %s\n", 213362306a36Sopenharmony_ci subdev->name); 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ci /* disable capture, disable interrupts */ 213662306a36Sopenharmony_ci __raw_writel(0x3ff, pcdev->base + CICR0); 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_ci /* Stop DMA engine */ 213962306a36Sopenharmony_ci pxa_dma_stop_channels(pcdev); 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci pxa_camera_destroy_formats(pcdev); 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci video_unregister_device(&pcdev->vdev); 214462306a36Sopenharmony_ci pcdev->sensor = NULL; 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci mutex_unlock(&pcdev->mlock); 214762306a36Sopenharmony_ci} 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_cistatic const struct v4l2_async_notifier_operations pxa_camera_sensor_ops = { 215062306a36Sopenharmony_ci .bound = pxa_camera_sensor_bound, 215162306a36Sopenharmony_ci .unbind = pxa_camera_sensor_unbind, 215262306a36Sopenharmony_ci}; 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci/* 215562306a36Sopenharmony_ci * Driver probe, remove, suspend and resume operations 215662306a36Sopenharmony_ci */ 215762306a36Sopenharmony_cistatic int pxa_camera_suspend(struct device *dev) 215862306a36Sopenharmony_ci{ 215962306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = dev_get_drvdata(dev); 216062306a36Sopenharmony_ci int i = 0, ret = 0; 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR0); 216362306a36Sopenharmony_ci pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR1); 216462306a36Sopenharmony_ci pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR2); 216562306a36Sopenharmony_ci pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR3); 216662306a36Sopenharmony_ci pcdev->save_cicr[i++] = __raw_readl(pcdev->base + CICR4); 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci if (pcdev->sensor) 216962306a36Sopenharmony_ci ret = pxac_sensor_set_power(pcdev, 0); 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci return ret; 217262306a36Sopenharmony_ci} 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_cistatic int pxa_camera_resume(struct device *dev) 217562306a36Sopenharmony_ci{ 217662306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = dev_get_drvdata(dev); 217762306a36Sopenharmony_ci int i = 0, ret = 0; 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_ci __raw_writel(pcdev->save_cicr[i++] & ~CICR0_ENB, pcdev->base + CICR0); 218062306a36Sopenharmony_ci __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR1); 218162306a36Sopenharmony_ci __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR2); 218262306a36Sopenharmony_ci __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR3); 218362306a36Sopenharmony_ci __raw_writel(pcdev->save_cicr[i++], pcdev->base + CICR4); 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci if (pcdev->sensor) { 218662306a36Sopenharmony_ci ret = pxac_sensor_set_power(pcdev, 1); 218762306a36Sopenharmony_ci } 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci /* Restart frame capture if active buffer exists */ 219062306a36Sopenharmony_ci if (!ret && pcdev->active) 219162306a36Sopenharmony_ci pxa_camera_start_capture(pcdev); 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci return ret; 219462306a36Sopenharmony_ci} 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_cistatic int pxa_camera_pdata_from_dt(struct device *dev, 219762306a36Sopenharmony_ci struct pxa_camera_dev *pcdev) 219862306a36Sopenharmony_ci{ 219962306a36Sopenharmony_ci u32 mclk_rate; 220062306a36Sopenharmony_ci struct v4l2_async_connection *asd; 220162306a36Sopenharmony_ci struct device_node *np = dev->of_node; 220262306a36Sopenharmony_ci struct v4l2_fwnode_endpoint ep = { .bus_type = 0 }; 220362306a36Sopenharmony_ci int err = of_property_read_u32(np, "clock-frequency", 220462306a36Sopenharmony_ci &mclk_rate); 220562306a36Sopenharmony_ci if (!err) { 220662306a36Sopenharmony_ci pcdev->platform_flags |= PXA_CAMERA_MCLK_EN; 220762306a36Sopenharmony_ci pcdev->mclk = mclk_rate; 220862306a36Sopenharmony_ci } 220962306a36Sopenharmony_ci 221062306a36Sopenharmony_ci np = of_graph_get_next_endpoint(np, NULL); 221162306a36Sopenharmony_ci if (!np) { 221262306a36Sopenharmony_ci dev_err(dev, "could not find endpoint\n"); 221362306a36Sopenharmony_ci return -EINVAL; 221462306a36Sopenharmony_ci } 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_ci err = v4l2_fwnode_endpoint_parse(of_fwnode_handle(np), &ep); 221762306a36Sopenharmony_ci if (err) { 221862306a36Sopenharmony_ci dev_err(dev, "could not parse endpoint\n"); 221962306a36Sopenharmony_ci goto out; 222062306a36Sopenharmony_ci } 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci switch (ep.bus.parallel.bus_width) { 222362306a36Sopenharmony_ci case 4: 222462306a36Sopenharmony_ci pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_4; 222562306a36Sopenharmony_ci break; 222662306a36Sopenharmony_ci case 5: 222762306a36Sopenharmony_ci pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_5; 222862306a36Sopenharmony_ci break; 222962306a36Sopenharmony_ci case 8: 223062306a36Sopenharmony_ci pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_8; 223162306a36Sopenharmony_ci break; 223262306a36Sopenharmony_ci case 9: 223362306a36Sopenharmony_ci pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_9; 223462306a36Sopenharmony_ci break; 223562306a36Sopenharmony_ci case 10: 223662306a36Sopenharmony_ci pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10; 223762306a36Sopenharmony_ci break; 223862306a36Sopenharmony_ci default: 223962306a36Sopenharmony_ci break; 224062306a36Sopenharmony_ci } 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci if (ep.bus.parallel.flags & V4L2_MBUS_MASTER) 224362306a36Sopenharmony_ci pcdev->platform_flags |= PXA_CAMERA_MASTER; 224462306a36Sopenharmony_ci if (ep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) 224562306a36Sopenharmony_ci pcdev->platform_flags |= PXA_CAMERA_HSP; 224662306a36Sopenharmony_ci if (ep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) 224762306a36Sopenharmony_ci pcdev->platform_flags |= PXA_CAMERA_VSP; 224862306a36Sopenharmony_ci if (ep.bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_RISING) 224962306a36Sopenharmony_ci pcdev->platform_flags |= PXA_CAMERA_PCLK_EN | PXA_CAMERA_PCP; 225062306a36Sopenharmony_ci if (ep.bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) 225162306a36Sopenharmony_ci pcdev->platform_flags |= PXA_CAMERA_PCLK_EN; 225262306a36Sopenharmony_ci 225362306a36Sopenharmony_ci asd = v4l2_async_nf_add_fwnode_remote(&pcdev->notifier, 225462306a36Sopenharmony_ci of_fwnode_handle(np), 225562306a36Sopenharmony_ci struct v4l2_async_connection); 225662306a36Sopenharmony_ci if (IS_ERR(asd)) 225762306a36Sopenharmony_ci err = PTR_ERR(asd); 225862306a36Sopenharmony_ciout: 225962306a36Sopenharmony_ci of_node_put(np); 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_ci return err; 226262306a36Sopenharmony_ci} 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_cistatic int pxa_camera_probe(struct platform_device *pdev) 226562306a36Sopenharmony_ci{ 226662306a36Sopenharmony_ci struct pxa_camera_dev *pcdev; 226762306a36Sopenharmony_ci struct resource *res; 226862306a36Sopenharmony_ci void __iomem *base; 226962306a36Sopenharmony_ci struct dma_slave_config config = { 227062306a36Sopenharmony_ci .src_addr_width = 0, 227162306a36Sopenharmony_ci .src_maxburst = 8, 227262306a36Sopenharmony_ci .direction = DMA_DEV_TO_MEM, 227362306a36Sopenharmony_ci }; 227462306a36Sopenharmony_ci int irq; 227562306a36Sopenharmony_ci int err = 0, i; 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 227862306a36Sopenharmony_ci if (irq < 0) 227962306a36Sopenharmony_ci return -ENODEV; 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci pcdev = devm_kzalloc(&pdev->dev, sizeof(*pcdev), GFP_KERNEL); 228262306a36Sopenharmony_ci if (!pcdev) { 228362306a36Sopenharmony_ci dev_err(&pdev->dev, "Could not allocate pcdev\n"); 228462306a36Sopenharmony_ci return -ENOMEM; 228562306a36Sopenharmony_ci } 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci pcdev->clk = devm_clk_get(&pdev->dev, NULL); 228862306a36Sopenharmony_ci if (IS_ERR(pcdev->clk)) 228962306a36Sopenharmony_ci return PTR_ERR(pcdev->clk); 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_ci /* 229262306a36Sopenharmony_ci * Request the regions. 229362306a36Sopenharmony_ci */ 229462306a36Sopenharmony_ci base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 229562306a36Sopenharmony_ci if (IS_ERR(base)) 229662306a36Sopenharmony_ci return PTR_ERR(base); 229762306a36Sopenharmony_ci 229862306a36Sopenharmony_ci pcdev->irq = irq; 229962306a36Sopenharmony_ci pcdev->base = base; 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_ci err = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev); 230262306a36Sopenharmony_ci if (err) 230362306a36Sopenharmony_ci return err; 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_ci v4l2_async_nf_init(&pcdev->notifier, &pcdev->v4l2_dev); 230662306a36Sopenharmony_ci pcdev->res = res; 230762306a36Sopenharmony_ci pcdev->pdata = pdev->dev.platform_data; 230862306a36Sopenharmony_ci if (pcdev->pdata) { 230962306a36Sopenharmony_ci struct v4l2_async_connection *asd; 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_ci pcdev->platform_flags = pcdev->pdata->flags; 231262306a36Sopenharmony_ci pcdev->mclk = pcdev->pdata->mclk_10khz * 10000; 231362306a36Sopenharmony_ci asd = v4l2_async_nf_add_i2c(&pcdev->notifier, 231462306a36Sopenharmony_ci pcdev->pdata->sensor_i2c_adapter_id, 231562306a36Sopenharmony_ci pcdev->pdata->sensor_i2c_address, 231662306a36Sopenharmony_ci struct v4l2_async_connection); 231762306a36Sopenharmony_ci if (IS_ERR(asd)) 231862306a36Sopenharmony_ci err = PTR_ERR(asd); 231962306a36Sopenharmony_ci } else if (pdev->dev.of_node) { 232062306a36Sopenharmony_ci err = pxa_camera_pdata_from_dt(&pdev->dev, pcdev); 232162306a36Sopenharmony_ci } else { 232262306a36Sopenharmony_ci err = -ENODEV; 232362306a36Sopenharmony_ci } 232462306a36Sopenharmony_ci if (err < 0) 232562306a36Sopenharmony_ci goto exit_v4l2_device_unregister; 232662306a36Sopenharmony_ci 232762306a36Sopenharmony_ci if (!(pcdev->platform_flags & (PXA_CAMERA_DATAWIDTH_8 | 232862306a36Sopenharmony_ci PXA_CAMERA_DATAWIDTH_9 | PXA_CAMERA_DATAWIDTH_10))) { 232962306a36Sopenharmony_ci /* 233062306a36Sopenharmony_ci * Platform hasn't set available data widths. This is bad. 233162306a36Sopenharmony_ci * Warn and use a default. 233262306a36Sopenharmony_ci */ 233362306a36Sopenharmony_ci dev_warn(&pdev->dev, "WARNING! Platform hasn't set available data widths, using default 10 bit\n"); 233462306a36Sopenharmony_ci pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10; 233562306a36Sopenharmony_ci } 233662306a36Sopenharmony_ci if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8) 233762306a36Sopenharmony_ci pcdev->width_flags = 1 << 7; 233862306a36Sopenharmony_ci if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9) 233962306a36Sopenharmony_ci pcdev->width_flags |= 1 << 8; 234062306a36Sopenharmony_ci if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10) 234162306a36Sopenharmony_ci pcdev->width_flags |= 1 << 9; 234262306a36Sopenharmony_ci if (!pcdev->mclk) { 234362306a36Sopenharmony_ci dev_warn(&pdev->dev, 234462306a36Sopenharmony_ci "mclk == 0! Please, fix your platform data. Using default 20MHz\n"); 234562306a36Sopenharmony_ci pcdev->mclk = 20000000; 234662306a36Sopenharmony_ci } 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ci pcdev->mclk_divisor = mclk_get_divisor(pdev, pcdev); 234962306a36Sopenharmony_ci 235062306a36Sopenharmony_ci INIT_LIST_HEAD(&pcdev->capture); 235162306a36Sopenharmony_ci spin_lock_init(&pcdev->lock); 235262306a36Sopenharmony_ci mutex_init(&pcdev->mlock); 235362306a36Sopenharmony_ci 235462306a36Sopenharmony_ci /* request dma */ 235562306a36Sopenharmony_ci pcdev->dma_chans[0] = dma_request_chan(&pdev->dev, "CI_Y"); 235662306a36Sopenharmony_ci if (IS_ERR(pcdev->dma_chans[0])) { 235762306a36Sopenharmony_ci dev_err(&pdev->dev, "Can't request DMA for Y\n"); 235862306a36Sopenharmony_ci err = PTR_ERR(pcdev->dma_chans[0]); 235962306a36Sopenharmony_ci goto exit_notifier_cleanup; 236062306a36Sopenharmony_ci } 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci pcdev->dma_chans[1] = dma_request_chan(&pdev->dev, "CI_U"); 236362306a36Sopenharmony_ci if (IS_ERR(pcdev->dma_chans[1])) { 236462306a36Sopenharmony_ci dev_err(&pdev->dev, "Can't request DMA for U\n"); 236562306a36Sopenharmony_ci err = PTR_ERR(pcdev->dma_chans[1]); 236662306a36Sopenharmony_ci goto exit_free_dma_y; 236762306a36Sopenharmony_ci } 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci pcdev->dma_chans[2] = dma_request_chan(&pdev->dev, "CI_V"); 237062306a36Sopenharmony_ci if (IS_ERR(pcdev->dma_chans[2])) { 237162306a36Sopenharmony_ci dev_err(&pdev->dev, "Can't request DMA for V\n"); 237262306a36Sopenharmony_ci err = PTR_ERR(pcdev->dma_chans[2]); 237362306a36Sopenharmony_ci goto exit_free_dma_u; 237462306a36Sopenharmony_ci } 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci for (i = 0; i < 3; i++) { 237762306a36Sopenharmony_ci config.src_addr = pcdev->res->start + CIBR0 + i * 8; 237862306a36Sopenharmony_ci err = dmaengine_slave_config(pcdev->dma_chans[i], &config); 237962306a36Sopenharmony_ci if (err < 0) { 238062306a36Sopenharmony_ci dev_err(&pdev->dev, "dma slave config failed: %d\n", 238162306a36Sopenharmony_ci err); 238262306a36Sopenharmony_ci goto exit_free_dma; 238362306a36Sopenharmony_ci } 238462306a36Sopenharmony_ci } 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci tasklet_setup(&pcdev->task_eof, pxa_camera_eof); 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci pxa_camera_activate(pcdev); 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci platform_set_drvdata(pdev, pcdev); 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_ci err = pxa_camera_init_videobuf2(pcdev); 239362306a36Sopenharmony_ci if (err) 239462306a36Sopenharmony_ci goto exit_deactivate; 239562306a36Sopenharmony_ci 239662306a36Sopenharmony_ci /* request irq */ 239762306a36Sopenharmony_ci err = devm_request_irq(&pdev->dev, pcdev->irq, pxa_camera_irq, 0, 239862306a36Sopenharmony_ci PXA_CAM_DRV_NAME, pcdev); 239962306a36Sopenharmony_ci if (err) { 240062306a36Sopenharmony_ci dev_err(&pdev->dev, "Camera interrupt register failed\n"); 240162306a36Sopenharmony_ci goto exit_deactivate; 240262306a36Sopenharmony_ci } 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_ci pcdev->notifier.ops = &pxa_camera_sensor_ops; 240562306a36Sopenharmony_ci err = v4l2_async_nf_register(&pcdev->notifier); 240662306a36Sopenharmony_ci if (err) 240762306a36Sopenharmony_ci goto exit_deactivate; 240862306a36Sopenharmony_ci 240962306a36Sopenharmony_ci return 0; 241062306a36Sopenharmony_ciexit_deactivate: 241162306a36Sopenharmony_ci pxa_camera_deactivate(pcdev); 241262306a36Sopenharmony_ci tasklet_kill(&pcdev->task_eof); 241362306a36Sopenharmony_ciexit_free_dma: 241462306a36Sopenharmony_ci dma_release_channel(pcdev->dma_chans[2]); 241562306a36Sopenharmony_ciexit_free_dma_u: 241662306a36Sopenharmony_ci dma_release_channel(pcdev->dma_chans[1]); 241762306a36Sopenharmony_ciexit_free_dma_y: 241862306a36Sopenharmony_ci dma_release_channel(pcdev->dma_chans[0]); 241962306a36Sopenharmony_ciexit_notifier_cleanup: 242062306a36Sopenharmony_ci v4l2_async_nf_cleanup(&pcdev->notifier); 242162306a36Sopenharmony_ciexit_v4l2_device_unregister: 242262306a36Sopenharmony_ci v4l2_device_unregister(&pcdev->v4l2_dev); 242362306a36Sopenharmony_ci return err; 242462306a36Sopenharmony_ci} 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_cistatic void pxa_camera_remove(struct platform_device *pdev) 242762306a36Sopenharmony_ci{ 242862306a36Sopenharmony_ci struct pxa_camera_dev *pcdev = platform_get_drvdata(pdev); 242962306a36Sopenharmony_ci 243062306a36Sopenharmony_ci pxa_camera_deactivate(pcdev); 243162306a36Sopenharmony_ci tasklet_kill(&pcdev->task_eof); 243262306a36Sopenharmony_ci dma_release_channel(pcdev->dma_chans[0]); 243362306a36Sopenharmony_ci dma_release_channel(pcdev->dma_chans[1]); 243462306a36Sopenharmony_ci dma_release_channel(pcdev->dma_chans[2]); 243562306a36Sopenharmony_ci 243662306a36Sopenharmony_ci v4l2_async_nf_unregister(&pcdev->notifier); 243762306a36Sopenharmony_ci v4l2_async_nf_cleanup(&pcdev->notifier); 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci v4l2_device_unregister(&pcdev->v4l2_dev); 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci dev_info(&pdev->dev, "PXA Camera driver unloaded\n"); 244262306a36Sopenharmony_ci} 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_cistatic const struct dev_pm_ops pxa_camera_pm = { 244562306a36Sopenharmony_ci .suspend = pxa_camera_suspend, 244662306a36Sopenharmony_ci .resume = pxa_camera_resume, 244762306a36Sopenharmony_ci}; 244862306a36Sopenharmony_ci 244962306a36Sopenharmony_cistatic const struct of_device_id pxa_camera_of_match[] = { 245062306a36Sopenharmony_ci { .compatible = "marvell,pxa270-qci", }, 245162306a36Sopenharmony_ci {}, 245262306a36Sopenharmony_ci}; 245362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, pxa_camera_of_match); 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_cistatic struct platform_driver pxa_camera_driver = { 245662306a36Sopenharmony_ci .driver = { 245762306a36Sopenharmony_ci .name = PXA_CAM_DRV_NAME, 245862306a36Sopenharmony_ci .pm = &pxa_camera_pm, 245962306a36Sopenharmony_ci .of_match_table = pxa_camera_of_match, 246062306a36Sopenharmony_ci }, 246162306a36Sopenharmony_ci .probe = pxa_camera_probe, 246262306a36Sopenharmony_ci .remove_new = pxa_camera_remove, 246362306a36Sopenharmony_ci}; 246462306a36Sopenharmony_ci 246562306a36Sopenharmony_cimodule_platform_driver(pxa_camera_driver); 246662306a36Sopenharmony_ci 246762306a36Sopenharmony_ciMODULE_DESCRIPTION("PXA27x Camera Driver"); 246862306a36Sopenharmony_ciMODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>"); 246962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 247062306a36Sopenharmony_ciMODULE_VERSION(PXA_CAM_VERSION); 247162306a36Sopenharmony_ciMODULE_ALIAS("platform:" PXA_CAM_DRV_NAME); 2472