linux-surface/patches/5.10/0011-cameras.patch
Maximilian Luz e59f2d0883
Update v5.10 patches
Changes:
 - Rebase onto v5.10.58

Links:
 - kernel: 459bd42a63
2021-08-15 01:46:22 +02:00

11663 lines
347 KiB
Diff

From 9a6d15f78587252049259f4d23d1f3cc5a541997 Mon Sep 17 00:00:00 2001
From: Sakari Ailus <sakari.ailus@linux.intel.com>
Date: Mon, 12 Oct 2020 21:04:11 +0300
Subject: [PATCH] ipu3-cio2: Use unsigned values where appropriate
Use unsigned values for width, height, bit shifts and registers,
effectively for all definitions that are not signed.
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Patchset: cameras
---
drivers/media/pci/intel/ipu3/ipu3-cio2.h | 156 +++++++++++------------
1 file changed, 78 insertions(+), 78 deletions(-)
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.h b/drivers/media/pci/intel/ipu3/ipu3-cio2.h
index 146492383aa5..7650d7998a3f 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.h
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.h
@@ -13,20 +13,20 @@
#define CIO2_PCI_BAR 0
#define CIO2_DMA_MASK DMA_BIT_MASK(39)
-#define CIO2_IMAGE_MAX_WIDTH 4224
-#define CIO2_IMAGE_MAX_LENGTH 3136
+#define CIO2_IMAGE_MAX_WIDTH 4224U
+#define CIO2_IMAGE_MAX_LENGTH 3136U
/* 32MB = 8xFBPT_entry */
#define CIO2_MAX_LOPS 8
#define CIO2_MAX_BUFFERS (PAGE_SIZE / 16 / CIO2_MAX_LOPS)
#define CIO2_LOP_ENTRIES (PAGE_SIZE / sizeof(u32))
-#define CIO2_PAD_SINK 0
-#define CIO2_PAD_SOURCE 1
-#define CIO2_PADS 2
+#define CIO2_PAD_SINK 0U
+#define CIO2_PAD_SOURCE 1U
+#define CIO2_PADS 2U
-#define CIO2_NUM_DMA_CHAN 20
-#define CIO2_NUM_PORTS 4 /* DPHYs */
+#define CIO2_NUM_DMA_CHAN 20U
+#define CIO2_NUM_PORTS 4U /* DPHYs */
/* 1 for each sensor */
#define CIO2_QUEUES CIO2_NUM_PORTS
@@ -66,12 +66,12 @@
#define CIO2_REG_MIPIBE_FORCE_RAW8 (CIO2_REG_MIPIBE_BASE + 0x20)
#define CIO2_REG_MIPIBE_FORCE_RAW8_ENABLE BIT(0)
#define CIO2_REG_MIPIBE_FORCE_RAW8_USE_TYPEID BIT(1)
-#define CIO2_REG_MIPIBE_FORCE_RAW8_TYPEID_SHIFT 2
+#define CIO2_REG_MIPIBE_FORCE_RAW8_TYPEID_SHIFT 2U
#define CIO2_REG_MIPIBE_IRQ_STATUS (CIO2_REG_MIPIBE_BASE + 0x24)
#define CIO2_REG_MIPIBE_IRQ_CLEAR (CIO2_REG_MIPIBE_BASE + 0x28)
#define CIO2_REG_MIPIBE_GLOBAL_LUT_DISREGARD (CIO2_REG_MIPIBE_BASE + 0x68)
-#define CIO2_MIPIBE_GLOBAL_LUT_DISREGARD 1
+#define CIO2_MIPIBE_GLOBAL_LUT_DISREGARD 1U
#define CIO2_REG_MIPIBE_PKT_STALL_STATUS (CIO2_REG_MIPIBE_BASE + 0x6c)
#define CIO2_REG_MIPIBE_PARSE_GSP_THROUGH_LP_LUT_REG_IDX \
(CIO2_REG_MIPIBE_BASE + 0x70)
@@ -79,10 +79,10 @@
(CIO2_REG_MIPIBE_BASE + 0x74 + 4 * (vc))
#define CIO2_REG_MIPIBE_LP_LUT_ENTRY(m) /* m = 0..15 */ \
(CIO2_REG_MIPIBE_BASE + 0x84 + 4 * (m))
-#define CIO2_MIPIBE_LP_LUT_ENTRY_DISREGARD 1
-#define CIO2_MIPIBE_LP_LUT_ENTRY_SID_SHIFT 1
-#define CIO2_MIPIBE_LP_LUT_ENTRY_VC_SHIFT 5
-#define CIO2_MIPIBE_LP_LUT_ENTRY_FORMAT_TYPE_SHIFT 7
+#define CIO2_MIPIBE_LP_LUT_ENTRY_DISREGARD 1U
+#define CIO2_MIPIBE_LP_LUT_ENTRY_SID_SHIFT 1U
+#define CIO2_MIPIBE_LP_LUT_ENTRY_VC_SHIFT 5U
+#define CIO2_MIPIBE_LP_LUT_ENTRY_FORMAT_TYPE_SHIFT 7U
/* base register: CIO2_REG_PIPE_BASE(pipe) * CIO2_REG_IRQCTRL_BASE */
/* IRQ registers are 18-bit wide, see cio2_irq_error for bit definitions */
@@ -113,31 +113,31 @@
#define CIO2_CGC_ROSC_DCGE BIT(12)
#define CIO2_CGC_XOSC_DCGE BIT(13)
#define CIO2_CGC_FLIS_DCGE BIT(14)
-#define CIO2_CGC_CLKGATE_HOLDOFF_SHIFT 20
-#define CIO2_CGC_CSI_CLKGATE_HOLDOFF_SHIFT 24
+#define CIO2_CGC_CLKGATE_HOLDOFF_SHIFT 20U
+#define CIO2_CGC_CSI_CLKGATE_HOLDOFF_SHIFT 24U
#define CIO2_REG_D0I3C 0x1408
#define CIO2_D0I3C_I3 BIT(2) /* Set D0I3 */
#define CIO2_D0I3C_RR BIT(3) /* Restore? */
#define CIO2_REG_SWRESET 0x140c
-#define CIO2_SWRESET_SWRESET 1
+#define CIO2_SWRESET_SWRESET 1U
#define CIO2_REG_SENSOR_ACTIVE 0x1410
#define CIO2_REG_INT_STS 0x1414
#define CIO2_REG_INT_STS_EXT_OE 0x1418
-#define CIO2_INT_EXT_OE_DMAOE_SHIFT 0
+#define CIO2_INT_EXT_OE_DMAOE_SHIFT 0U
#define CIO2_INT_EXT_OE_DMAOE_MASK 0x7ffff
-#define CIO2_INT_EXT_OE_OES_SHIFT 24
+#define CIO2_INT_EXT_OE_OES_SHIFT 24U
#define CIO2_INT_EXT_OE_OES_MASK (0xf << CIO2_INT_EXT_OE_OES_SHIFT)
#define CIO2_REG_INT_EN 0x1420
#define CIO2_REG_INT_EN_IRQ (1 << 24)
-#define CIO2_REG_INT_EN_IOS(dma) (1 << (((dma) >> 1) + 12))
+#define CIO2_REG_INT_EN_IOS(dma) (1U << (((dma) >> 1U) + 12U))
/*
* Interrupt on completion bit, Eg. DMA 0-3 maps to bit 0-3,
* DMA4 & DMA5 map to bit 4 ... DMA18 & DMA19 map to bit 11 Et cetera
*/
-#define CIO2_INT_IOC(dma) (1 << ((dma) < 4 ? (dma) : ((dma) >> 1) + 2))
+#define CIO2_INT_IOC(dma) (1U << ((dma) < 4U ? (dma) : ((dma) >> 1U) + 2U))
#define CIO2_INT_IOC_SHIFT 0
#define CIO2_INT_IOC_MASK (0x7ff << CIO2_INT_IOC_SHIFT)
-#define CIO2_INT_IOS_IOLN(dma) (1 << (((dma) >> 1) + 12))
+#define CIO2_INT_IOS_IOLN(dma) (1U << (((dma) >> 1U) + 12U))
#define CIO2_INT_IOS_IOLN_SHIFT 12
#define CIO2_INT_IOS_IOLN_MASK (0x3ff << CIO2_INT_IOS_IOLN_SHIFT)
#define CIO2_INT_IOIE BIT(22)
@@ -145,32 +145,32 @@
#define CIO2_INT_IOIRQ BIT(24)
#define CIO2_REG_INT_EN_EXT_OE 0x1424
#define CIO2_REG_DMA_DBG 0x1448
-#define CIO2_REG_DMA_DBG_DMA_INDEX_SHIFT 0
+#define CIO2_REG_DMA_DBG_DMA_INDEX_SHIFT 0U
#define CIO2_REG_PBM_ARB_CTRL 0x1460
-#define CIO2_PBM_ARB_CTRL_LANES_DIV 0 /* 4-4-2-2 lanes */
-#define CIO2_PBM_ARB_CTRL_LANES_DIV_SHIFT 0
+#define CIO2_PBM_ARB_CTRL_LANES_DIV 0U /* 4-4-2-2 lanes */
+#define CIO2_PBM_ARB_CTRL_LANES_DIV_SHIFT 0U
#define CIO2_PBM_ARB_CTRL_LE_EN BIT(7)
-#define CIO2_PBM_ARB_CTRL_PLL_POST_SHTDN 2
-#define CIO2_PBM_ARB_CTRL_PLL_POST_SHTDN_SHIFT 8
-#define CIO2_PBM_ARB_CTRL_PLL_AHD_WK_UP 480
-#define CIO2_PBM_ARB_CTRL_PLL_AHD_WK_UP_SHIFT 16
+#define CIO2_PBM_ARB_CTRL_PLL_POST_SHTDN 2U
+#define CIO2_PBM_ARB_CTRL_PLL_POST_SHTDN_SHIFT 8U
+#define CIO2_PBM_ARB_CTRL_PLL_AHD_WK_UP 480U
+#define CIO2_PBM_ARB_CTRL_PLL_AHD_WK_UP_SHIFT 16U
#define CIO2_REG_PBM_WMCTRL1 0x1464
-#define CIO2_PBM_WMCTRL1_MIN_2CK_SHIFT 0
-#define CIO2_PBM_WMCTRL1_MID1_2CK_SHIFT 8
-#define CIO2_PBM_WMCTRL1_MID2_2CK_SHIFT 16
+#define CIO2_PBM_WMCTRL1_MIN_2CK_SHIFT 0U
+#define CIO2_PBM_WMCTRL1_MID1_2CK_SHIFT 8U
+#define CIO2_PBM_WMCTRL1_MID2_2CK_SHIFT 16U
#define CIO2_PBM_WMCTRL1_TS_COUNT_DISABLE BIT(31)
#define CIO2_PBM_WMCTRL1_MIN_2CK (4 << CIO2_PBM_WMCTRL1_MIN_2CK_SHIFT)
#define CIO2_PBM_WMCTRL1_MID1_2CK (16 << CIO2_PBM_WMCTRL1_MID1_2CK_SHIFT)
#define CIO2_PBM_WMCTRL1_MID2_2CK (21 << CIO2_PBM_WMCTRL1_MID2_2CK_SHIFT)
#define CIO2_REG_PBM_WMCTRL2 0x1468
-#define CIO2_PBM_WMCTRL2_HWM_2CK 40
-#define CIO2_PBM_WMCTRL2_HWM_2CK_SHIFT 0
-#define CIO2_PBM_WMCTRL2_LWM_2CK 22
-#define CIO2_PBM_WMCTRL2_LWM_2CK_SHIFT 8
-#define CIO2_PBM_WMCTRL2_OBFFWM_2CK 2
-#define CIO2_PBM_WMCTRL2_OBFFWM_2CK_SHIFT 16
-#define CIO2_PBM_WMCTRL2_TRANSDYN 1
-#define CIO2_PBM_WMCTRL2_TRANSDYN_SHIFT 24
+#define CIO2_PBM_WMCTRL2_HWM_2CK 40U
+#define CIO2_PBM_WMCTRL2_HWM_2CK_SHIFT 0U
+#define CIO2_PBM_WMCTRL2_LWM_2CK 22U
+#define CIO2_PBM_WMCTRL2_LWM_2CK_SHIFT 8U
+#define CIO2_PBM_WMCTRL2_OBFFWM_2CK 2U
+#define CIO2_PBM_WMCTRL2_OBFFWM_2CK_SHIFT 16U
+#define CIO2_PBM_WMCTRL2_TRANSDYN 1U
+#define CIO2_PBM_WMCTRL2_TRANSDYN_SHIFT 24U
#define CIO2_PBM_WMCTRL2_DYNWMEN BIT(28)
#define CIO2_PBM_WMCTRL2_OBFF_MEM_EN BIT(29)
#define CIO2_PBM_WMCTRL2_OBFF_CPU_EN BIT(30)
@@ -178,12 +178,12 @@
#define CIO2_REG_PBM_TS_COUNT 0x146c
#define CIO2_REG_PBM_FOPN_ABORT 0x1474
/* below n = 0..3 */
-#define CIO2_PBM_FOPN_ABORT(n) (0x1 << 8 * (n))
-#define CIO2_PBM_FOPN_FORCE_ABORT(n) (0x2 << 8 * (n))
-#define CIO2_PBM_FOPN_FRAMEOPEN(n) (0x8 << 8 * (n))
+#define CIO2_PBM_FOPN_ABORT(n) (0x1 << 8U * (n))
+#define CIO2_PBM_FOPN_FORCE_ABORT(n) (0x2 << 8U * (n))
+#define CIO2_PBM_FOPN_FRAMEOPEN(n) (0x8 << 8U * (n))
#define CIO2_REG_LTRCTRL 0x1480
#define CIO2_LTRCTRL_LTRDYNEN BIT(16)
-#define CIO2_LTRCTRL_LTRSTABLETIME_SHIFT 8
+#define CIO2_LTRCTRL_LTRSTABLETIME_SHIFT 8U
#define CIO2_LTRCTRL_LTRSTABLETIME_MASK 0xff
#define CIO2_LTRCTRL_LTRSEL1S3 BIT(7)
#define CIO2_LTRCTRL_LTRSEL1S2 BIT(6)
@@ -195,28 +195,28 @@
#define CIO2_LTRCTRL_LTRSEL2S0 BIT(0)
#define CIO2_REG_LTRVAL23 0x1484
#define CIO2_REG_LTRVAL01 0x1488
-#define CIO2_LTRVAL02_VAL_SHIFT 0
-#define CIO2_LTRVAL02_SCALE_SHIFT 10
-#define CIO2_LTRVAL13_VAL_SHIFT 16
-#define CIO2_LTRVAL13_SCALE_SHIFT 26
+#define CIO2_LTRVAL02_VAL_SHIFT 0U
+#define CIO2_LTRVAL02_SCALE_SHIFT 10U
+#define CIO2_LTRVAL13_VAL_SHIFT 16U
+#define CIO2_LTRVAL13_SCALE_SHIFT 26U
-#define CIO2_LTRVAL0_VAL 175
+#define CIO2_LTRVAL0_VAL 175U
/* Value times 1024 ns */
-#define CIO2_LTRVAL0_SCALE 2
-#define CIO2_LTRVAL1_VAL 90
-#define CIO2_LTRVAL1_SCALE 2
-#define CIO2_LTRVAL2_VAL 90
-#define CIO2_LTRVAL2_SCALE 2
-#define CIO2_LTRVAL3_VAL 90
-#define CIO2_LTRVAL3_SCALE 2
+#define CIO2_LTRVAL0_SCALE 2U
+#define CIO2_LTRVAL1_VAL 90U
+#define CIO2_LTRVAL1_SCALE 2U
+#define CIO2_LTRVAL2_VAL 90U
+#define CIO2_LTRVAL2_SCALE 2U
+#define CIO2_LTRVAL3_VAL 90U
+#define CIO2_LTRVAL3_SCALE 2U
#define CIO2_REG_CDMABA(n) (0x1500 + 0x10 * (n)) /* n = 0..19 */
#define CIO2_REG_CDMARI(n) (0x1504 + 0x10 * (n))
-#define CIO2_CDMARI_FBPT_RP_SHIFT 0
+#define CIO2_CDMARI_FBPT_RP_SHIFT 0U
#define CIO2_CDMARI_FBPT_RP_MASK 0xff
#define CIO2_REG_CDMAC0(n) (0x1508 + 0x10 * (n))
-#define CIO2_CDMAC0_FBPT_LEN_SHIFT 0
-#define CIO2_CDMAC0_FBPT_WIDTH_SHIFT 8
+#define CIO2_CDMAC0_FBPT_LEN_SHIFT 0U
+#define CIO2_CDMAC0_FBPT_WIDTH_SHIFT 8U
#define CIO2_CDMAC0_FBPT_NS BIT(25)
#define CIO2_CDMAC0_DMA_INTR_ON_FS BIT(26)
#define CIO2_CDMAC0_DMA_INTR_ON_FE BIT(27)
@@ -225,12 +225,12 @@
#define CIO2_CDMAC0_DMA_EN BIT(30)
#define CIO2_CDMAC0_DMA_HALTED BIT(31)
#define CIO2_REG_CDMAC1(n) (0x150c + 0x10 * (n))
-#define CIO2_CDMAC1_LINENUMINT_SHIFT 0
-#define CIO2_CDMAC1_LINENUMUPDATE_SHIFT 16
+#define CIO2_CDMAC1_LINENUMINT_SHIFT 0U
+#define CIO2_CDMAC1_LINENUMUPDATE_SHIFT 16U
/* n = 0..3 */
#define CIO2_REG_PXM_PXF_FMT_CFG0(n) (0x1700 + 0x30 * (n))
-#define CIO2_PXM_PXF_FMT_CFG_SID0_SHIFT 0
-#define CIO2_PXM_PXF_FMT_CFG_SID1_SHIFT 16
+#define CIO2_PXM_PXF_FMT_CFG_SID0_SHIFT 0U
+#define CIO2_PXM_PXF_FMT_CFG_SID1_SHIFT 16U
#define CIO2_PXM_PXF_FMT_CFG_PCK_64B (0 << 0)
#define CIO2_PXM_PXF_FMT_CFG_PCK_32B (1 << 0)
#define CIO2_PXM_PXF_FMT_CFG_BPP_08 (0 << 2)
@@ -249,27 +249,27 @@
#define CIO2_PXM_PXF_FMT_CFG_PSWAP4_2ND_BD (1 << 10)
#define CIO2_REG_INT_STS_EXT_IE 0x17e4
#define CIO2_REG_INT_EN_EXT_IE 0x17e8
-#define CIO2_INT_EXT_IE_ECC_RE(n) (0x01 << (8 * (n)))
-#define CIO2_INT_EXT_IE_DPHY_NR(n) (0x02 << (8 * (n)))
-#define CIO2_INT_EXT_IE_ECC_NR(n) (0x04 << (8 * (n)))
-#define CIO2_INT_EXT_IE_CRCERR(n) (0x08 << (8 * (n)))
-#define CIO2_INT_EXT_IE_INTERFRAMEDATA(n) (0x10 << (8 * (n)))
-#define CIO2_INT_EXT_IE_PKT2SHORT(n) (0x20 << (8 * (n)))
-#define CIO2_INT_EXT_IE_PKT2LONG(n) (0x40 << (8 * (n)))
-#define CIO2_INT_EXT_IE_IRQ(n) (0x80 << (8 * (n)))
+#define CIO2_INT_EXT_IE_ECC_RE(n) (0x01 << (8U * (n)))
+#define CIO2_INT_EXT_IE_DPHY_NR(n) (0x02 << (8U * (n)))
+#define CIO2_INT_EXT_IE_ECC_NR(n) (0x04 << (8U * (n)))
+#define CIO2_INT_EXT_IE_CRCERR(n) (0x08 << (8U * (n)))
+#define CIO2_INT_EXT_IE_INTERFRAMEDATA(n) (0x10 << (8U * (n)))
+#define CIO2_INT_EXT_IE_PKT2SHORT(n) (0x20 << (8U * (n)))
+#define CIO2_INT_EXT_IE_PKT2LONG(n) (0x40 << (8U * (n)))
+#define CIO2_INT_EXT_IE_IRQ(n) (0x80 << (8U * (n)))
#define CIO2_REG_PXM_FRF_CFG(n) (0x1720 + 0x30 * (n))
#define CIO2_PXM_FRF_CFG_FNSEL BIT(0)
#define CIO2_PXM_FRF_CFG_FN_RST BIT(1)
#define CIO2_PXM_FRF_CFG_ABORT BIT(2)
-#define CIO2_PXM_FRF_CFG_CRC_TH_SHIFT 3
+#define CIO2_PXM_FRF_CFG_CRC_TH_SHIFT 3U
#define CIO2_PXM_FRF_CFG_MSK_ECC_DPHY_NR BIT(8)
#define CIO2_PXM_FRF_CFG_MSK_ECC_RE BIT(9)
#define CIO2_PXM_FRF_CFG_MSK_ECC_DPHY_NE BIT(10)
-#define CIO2_PXM_FRF_CFG_EVEN_ODD_MODE_SHIFT 11
+#define CIO2_PXM_FRF_CFG_EVEN_ODD_MODE_SHIFT 11U
#define CIO2_PXM_FRF_CFG_MASK_CRC_THRES BIT(13)
#define CIO2_PXM_FRF_CFG_MASK_CSI_ACCEPT BIT(14)
#define CIO2_PXM_FRF_CFG_CIOHC_FS_MODE BIT(15)
-#define CIO2_PXM_FRF_CFG_CIOHC_FRST_FRM_SHIFT 16
+#define CIO2_PXM_FRF_CFG_CIOHC_FRST_FRM_SHIFT 16U
#define CIO2_REG_PXM_SID2BID0(n) (0x1724 + 0x30 * (n))
#define CIO2_FB_HPLL_FREQ 0x2
#define CIO2_ISCLK_RATIO 0xc
@@ -278,14 +278,14 @@
#define CIO2_INT_EN_EXT_OE_MASK 0x8f0fffff
-#define CIO2_CGC_CLKGATE_HOLDOFF 3
-#define CIO2_CGC_CSI_CLKGATE_HOLDOFF 5
+#define CIO2_CGC_CLKGATE_HOLDOFF 3U
+#define CIO2_CGC_CSI_CLKGATE_HOLDOFF 5U
#define CIO2_PXM_FRF_CFG_CRC_TH 16
#define CIO2_INT_EN_EXT_IE_MASK 0xffffffff
-#define CIO2_DMA_CHAN 0
+#define CIO2_DMA_CHAN 0U
#define CIO2_CSIRX_DLY_CNT_CLANE_IDX -1
@@ -302,8 +302,8 @@
#define CIO2_CSIRX_DLY_CNT_TERMEN_DEFAULT 0x4
#define CIO2_CSIRX_DLY_CNT_SETTLE_DEFAULT 0x570
-#define CIO2_PMCSR_OFFSET 4
-#define CIO2_PMCSR_D0D3_SHIFT 2
+#define CIO2_PMCSR_OFFSET 4U
+#define CIO2_PMCSR_D0D3_SHIFT 2U
#define CIO2_PMCSR_D3 0x3
struct cio2_csi2_timing {
--
2.32.0
From fdc66426610e43907709183cfe0fe6ec19c8818c Mon Sep 17 00:00:00 2001
From: Sakari Ailus <sakari.ailus@linux.intel.com>
Date: Mon, 12 Oct 2020 21:04:12 +0300
Subject: [PATCH] ipu3-cio2: Remove explicit type from frame size checks
Now that the values are unsigned, we can remove explicit cast to u32.
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Patchset: cameras
---
drivers/media/pci/intel/ipu3/ipu3-cio2.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
index 2fe4a0bd0284..2061d7a50700 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
@@ -1283,9 +1283,8 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd,
}
}
- fmt->format.width = min_t(u32, fmt->format.width, CIO2_IMAGE_MAX_WIDTH);
- fmt->format.height = min_t(u32, fmt->format.height,
- CIO2_IMAGE_MAX_LENGTH);
+ fmt->format.width = min(fmt->format.width, CIO2_IMAGE_MAX_WIDTH);
+ fmt->format.height = min(fmt->format.height, CIO2_IMAGE_MAX_LENGTH);
fmt->format.field = V4L2_FIELD_NONE;
mutex_lock(&q->subdev_lock);
--
2.32.0
From 6a1571be8e3ac8c7b9f9f8a4525f0490c0b4338b Mon Sep 17 00:00:00 2001
From: Sakari Ailus <sakari.ailus@linux.intel.com>
Date: Mon, 12 Oct 2020 21:04:13 +0300
Subject: [PATCH] ipu3-cio2: Rename CIO2_IMAGE_MAX_LENGTH as
CIO2_IMAGE_MAX_HEIGHT
CIO2_IMAGE_MAX_LENGTH is the maximum width of the image. Rename it as
"CIO2_IMAGE_MAX_HEIGHT" in order to better describe what it is.
Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Patchset: cameras
---
drivers/media/pci/intel/ipu3/ipu3-cio2.c | 6 +++---
drivers/media/pci/intel/ipu3/ipu3-cio2.h | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
index 2061d7a50700..a0202166e2b0 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
@@ -1095,8 +1095,8 @@ static int cio2_v4l2_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
/* Only supports up to 4224x3136 */
if (mpix->width > CIO2_IMAGE_MAX_WIDTH)
mpix->width = CIO2_IMAGE_MAX_WIDTH;
- if (mpix->height > CIO2_IMAGE_MAX_LENGTH)
- mpix->height = CIO2_IMAGE_MAX_LENGTH;
+ if (mpix->height > CIO2_IMAGE_MAX_HEIGHT)
+ mpix->height = CIO2_IMAGE_MAX_HEIGHT;
mpix->num_planes = 1;
mpix->pixelformat = fmt->fourcc;
@@ -1284,7 +1284,7 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd,
}
fmt->format.width = min(fmt->format.width, CIO2_IMAGE_MAX_WIDTH);
- fmt->format.height = min(fmt->format.height, CIO2_IMAGE_MAX_LENGTH);
+ fmt->format.height = min(fmt->format.height, CIO2_IMAGE_MAX_HEIGHT);
fmt->format.field = V4L2_FIELD_NONE;
mutex_lock(&q->subdev_lock);
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.h b/drivers/media/pci/intel/ipu3/ipu3-cio2.h
index 7650d7998a3f..ccf0b85ae36f 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.h
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.h
@@ -14,7 +14,7 @@
#define CIO2_DMA_MASK DMA_BIT_MASK(39)
#define CIO2_IMAGE_MAX_WIDTH 4224U
-#define CIO2_IMAGE_MAX_LENGTH 3136U
+#define CIO2_IMAGE_MAX_HEIGHT 3136U
/* 32MB = 8xFBPT_entry */
#define CIO2_MAX_LOPS 8
--
2.32.0
From 809f003a252b57dca13503dbb9c4e05d2e89b629 Mon Sep 17 00:00:00 2001
From: Sakari Ailus <sakari.ailus@xxxxxxxxxxxxxxx>
Date: Tue, 13 Oct 2020 17:25:35 +0300
Subject: [PATCH] ipu3-cio2: Check receved the size against payload size, not
buffer size
Compare the received size of the payload size, not the allocated size of
the buffer that is page aligned. This way also images that aren't aligned
to page size are not warned about.
Also wrap a line over 80 characters.
Suggested-by: Laurent Pinchart <laurent.pinchart@xxxxxxxxxxxxxxxx>
Signed-off-by: Sakari Ailus <sakari.ailus@xxxxxxxxxxxxxxx>
Reviewed-by: Laurent Pinchart <laurent.pinchart@xxxxxxxxxxxxxxxx>
Tested-by: Jean-Michel Hautbois <jeanmichel.hautbois@xxxxxxxxx>
Patchset: cameras
---
drivers/media/pci/intel/ipu3/ipu3-cio2.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
index a0202166e2b0..c0cd4606810c 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
@@ -561,7 +561,9 @@ static void cio2_buffer_done(struct cio2_device *cio2, unsigned int dma_chan)
b = q->bufs[q->bufs_first];
if (b) {
- unsigned int bytes = entry[1].second_entry.num_of_bytes;
+ unsigned int received = entry[1].second_entry.num_of_bytes;
+ unsigned long payload =
+ vb2_get_plane_payload(&b->vbb.vb2_buf, 0);
q->bufs[q->bufs_first] = NULL;
atomic_dec(&q->bufs_queued);
@@ -571,10 +573,10 @@ static void cio2_buffer_done(struct cio2_device *cio2, unsigned int dma_chan)
b->vbb.vb2_buf.timestamp = ns;
b->vbb.field = V4L2_FIELD_NONE;
b->vbb.sequence = atomic_read(&q->frame_sequence);
- if (b->vbb.vb2_buf.planes[0].length != bytes)
- dev_warn(dev, "buffer length is %d received %d\n",
- b->vbb.vb2_buf.planes[0].length,
- bytes);
+ if (payload != received)
+ dev_warn(dev,
+ "payload length is %lu, received %u\n",
+ payload, received);
vb2_buffer_done(&b->vbb.vb2_buf, VB2_BUF_STATE_DONE);
}
atomic_inc(&q->frame_sequence);
--
2.32.0
From 1717324c939e0ffb84cdfc7cb09563d4c2b7ef89 Mon Sep 17 00:00:00 2001
From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Date: Wed, 30 Dec 2020 22:44:05 +0200
Subject: [PATCH] media: ipu3-cio2: Add headers that ipu3-cio2.h is direct user
of
Add headers that ipu3-cio2.h is direct user of.
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Daniel Scally <djrscally@gmail.com>
Tested-by: Daniel Scally <djrscally@gmail.com>
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/pci/intel/ipu3/ipu3-cio2.h | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.h b/drivers/media/pci/intel/ipu3/ipu3-cio2.h
index ccf0b85ae36f..62187ab5ae43 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.h
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.h
@@ -4,8 +4,26 @@
#ifndef __IPU3_CIO2_H
#define __IPU3_CIO2_H
+#include <linux/bits.h>
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
#include <linux/types.h>
+#include <asm/page.h>
+
+#include <media/media-device.h>
+#include <media/media-entity.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-v4l2.h>
+
+struct cio2_fbpt_entry; /* defined here, after the first usage */
+struct pci_dev;
+
#define CIO2_NAME "ipu3-cio2"
#define CIO2_DEVICE_NAME "Intel IPU3 CIO2"
#define CIO2_ENTITY_NAME "ipu3-csi2"
--
2.32.0
From 527ed09188b1a9920ce5ce3a7537a6cdd61777c0 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sat, 24 Oct 2020 22:42:28 +0100
Subject: [PATCH] device property: Return true in fwnode_device_is_available
for NULL ops
Some types of fwnode_handle do not implement the device_is_available()
check, such as those created by software_nodes. There isn't really a
meaningful way to check for the availability of a device that doesn't
actually exist, so if the check isn't implemented just assume that the
"device" is present.
Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/base/property.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 4c43d30145c6..bc9c634df6df 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -785,9 +785,15 @@ EXPORT_SYMBOL_GPL(fwnode_handle_put);
/**
* fwnode_device_is_available - check if a device is available for use
* @fwnode: Pointer to the fwnode of the device.
+ *
+ * For fwnode node types that don't implement the .device_is_available()
+ * operation, this function returns true.
*/
bool fwnode_device_is_available(const struct fwnode_handle *fwnode)
{
+ if (!fwnode_has_op(fwnode, device_is_available))
+ return true;
+
return fwnode_call_bool_op(fwnode, device_is_available);
}
EXPORT_SYMBOL_GPL(fwnode_device_is_available);
--
2.32.0
From 5bfb5edd47de6b12dd982525a7bda28d05389e63 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sat, 21 Nov 2020 22:06:38 +0000
Subject: [PATCH] device property: Call fwnode_graph_get_endpoint_by_id() for
fwnode->secondary
This function is used to find fwnode endpoints against a device. In
some instances those endpoints are software nodes which are children of
fwnode->secondary. Add support to fwnode_graph_get_endpoint_by_id() to
find those endpoints by recursively calling itself passing the ptr to
fwnode->secondary in the event no endpoint is found for the primary.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/base/property.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/base/property.c b/drivers/base/property.c
index bc9c634df6df..ddba75d90af2 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -1163,7 +1163,14 @@ fwnode_graph_get_endpoint_by_id(const struct fwnode_handle *fwnode,
best_ep_id = fwnode_ep.id;
}
- return best_ep;
+ if (best_ep)
+ return best_ep;
+
+ if (fwnode && !IS_ERR_OR_NULL(fwnode->secondary))
+ return fwnode_graph_get_endpoint_by_id(fwnode->secondary, port,
+ endpoint, flags);
+
+ return NULL;
}
EXPORT_SYMBOL_GPL(fwnode_graph_get_endpoint_by_id);
--
2.32.0
From 2846cc36b996c9067529611d94f86d842d758873 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sun, 25 Oct 2020 22:49:08 +0000
Subject: [PATCH] software_node: Enforce parent before child ordering of nodes
arrays
Registering software_nodes with the .parent member set to point to a
currently unregistered software_node has the potential for problems,
so enforce parent -> child ordering in arrays passed in to
software_node_register_nodes().
Software nodes that are children of another software node should be
unregistered before their parent. To allow easy unregistering of an array
of software_nodes ordered parent to child, reverse the order in which
software_node_unregister_nodes() unregisters software_nodes.
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/base/swnode.c | 42 ++++++++++++++++++++++++++++++------------
1 file changed, 30 insertions(+), 12 deletions(-)
diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
index 206bd4d7d7e2..eb89bdb9232c 100644
--- a/drivers/base/swnode.c
+++ b/drivers/base/swnode.c
@@ -692,7 +692,11 @@ swnode_register(const struct software_node *node, struct swnode *parent,
* software_node_register_nodes - Register an array of software nodes
* @nodes: Zero terminated array of software nodes to be registered
*
- * Register multiple software nodes at once.
+ * Register multiple software nodes at once. If any node in the array
+ * has its .parent pointer set (which can only be to another software_node),
+ * then its parent **must** have been registered before it is; either outside
+ * of this function or by ordering the array such that parent comes before
+ * child.
*/
int software_node_register_nodes(const struct software_node *nodes)
{
@@ -700,14 +704,23 @@ int software_node_register_nodes(const struct software_node *nodes)
int i;
for (i = 0; nodes[i].name; i++) {
- ret = software_node_register(&nodes[i]);
- if (ret) {
- software_node_unregister_nodes(nodes);
- return ret;
+ const struct software_node *parent = nodes[i].parent;
+
+ if (parent && !software_node_to_swnode(parent)) {
+ ret = -EINVAL;
+ goto err_unregister_nodes;
}
+
+ ret = software_node_register(&nodes[i]);
+ if (ret)
+ goto err_unregister_nodes;
}
return 0;
+
+err_unregister_nodes:
+ software_node_unregister_nodes(nodes);
+ return ret;
}
EXPORT_SYMBOL_GPL(software_node_register_nodes);
@@ -715,18 +728,23 @@ EXPORT_SYMBOL_GPL(software_node_register_nodes);
* software_node_unregister_nodes - Unregister an array of software nodes
* @nodes: Zero terminated array of software nodes to be unregistered
*
- * Unregister multiple software nodes at once.
+ * Unregister multiple software nodes at once. If parent pointers are set up
+ * in any of the software nodes then the array **must** be ordered such that
+ * parents come before their children.
*
- * NOTE: Be careful using this call if the nodes had parent pointers set up in
- * them before registering. If so, it is wiser to remove the nodes
- * individually, in the correct order (child before parent) instead of relying
- * on the sequential order of the list of nodes in the array.
+ * NOTE: If you are uncertain whether the array is ordered such that
+ * parents will be unregistered before their children, it is wiser to
+ * remove the nodes individually, in the correct order (child before
+ * parent).
*/
void software_node_unregister_nodes(const struct software_node *nodes)
{
- int i;
+ unsigned int i = 0;
+
+ while (nodes[i].name)
+ i++;
- for (i = 0; nodes[i].name; i++)
+ while (i--)
software_node_unregister(&nodes[i]);
}
EXPORT_SYMBOL_GPL(software_node_unregister_nodes);
--
2.32.0
From 47aadb85b2a217e6a2b0c1bea3cfc6c30f96056e Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Wed, 21 Oct 2020 22:25:03 +0100
Subject: [PATCH] software_node: unregister software_nodes in reverse order
To maintain consistency with software_node_unregister_nodes(), reverse
the order in which the software_node_unregister_node_group() function
unregisters nodes.
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/base/swnode.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
index eb89bdb9232c..032b24f60c78 100644
--- a/drivers/base/swnode.c
+++ b/drivers/base/swnode.c
@@ -779,16 +779,23 @@ EXPORT_SYMBOL_GPL(software_node_register_node_group);
* software_node_unregister_node_group - Unregister a group of software nodes
* @node_group: NULL terminated array of software node pointers to be unregistered
*
- * Unregister multiple software nodes at once.
+ * Unregister multiple software nodes at once. The array will be unwound in
+ * reverse order (i.e. last entry first) and thus if any members of the array are
+ * children of another member then the children must appear later in the list such
+ * that they are unregistered first.
*/
-void software_node_unregister_node_group(const struct software_node **node_group)
+void software_node_unregister_node_group(
+ const struct software_node **node_group)
{
- unsigned int i;
+ unsigned int i = 0;
if (!node_group)
return;
- for (i = 0; node_group[i]; i++)
+ while (node_group[i])
+ i++;
+
+ while (i--)
software_node_unregister(node_group[i]);
}
EXPORT_SYMBOL_GPL(software_node_unregister_node_group);
--
2.32.0
From 5bb27047094135a40cdd9ac968d85e2cb4d2dadc Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Tue, 22 Dec 2020 13:09:05 +0000
Subject: [PATCH] device property: Define format macros for ports and endpoints
OF, ACPI and software_nodes all implement graphs including nodes for ports
and endpoints. These are all intended to be named with a common schema,
as "port@n" and "endpoint@n" where n is an unsigned int representing the
index of the node. To ensure commonality across the subsystems, provide a
set of macros to define the format.
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
include/linux/fwnode.h | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h
index 9506f8ec0974..72d36d46287d 100644
--- a/include/linux/fwnode.h
+++ b/include/linux/fwnode.h
@@ -32,6 +32,13 @@ struct fwnode_endpoint {
const struct fwnode_handle *local_fwnode;
};
+/*
+ * ports and endpoints defined as software_nodes should all follow a common
+ * naming scheme; use these macros to ensure commonality.
+ */
+#define SWNODE_GRAPH_PORT_NAME_FMT "port@%u"
+#define SWNODE_GRAPH_ENDPOINT_NAME_FMT "endpoint@%u"
+
#define NR_FWNODE_REFERENCE_ARGS 8
/**
--
2.32.0
From f409a179d1bb38ab411e33ed8645cbc036bc5b27 Mon Sep 17 00:00:00 2001
From: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Date: Tue, 15 Sep 2020 15:47:46 +0100
Subject: [PATCH] software_node: Add support for fwnode_graph*() family of
functions
This implements the remaining .graph_*() callbacks in the fwnode
operations structure for the software nodes. That makes the
fwnode_graph_*() functions available in the drivers also when software
nodes are used.
The implementation tries to mimic the "OF graph" as much as possible, but
there is no support for the "reg" device property. The ports will need to
have the index in their name which starts with "port@" (for example
"port@0", "port@1", ...) and endpoints will use the index of the software
node that is given to them during creation. The port nodes can also be
grouped under a specially named "ports" subnode, just like in DT, if
necessary.
The remote-endpoints are reference properties under the endpoint nodes
that are named "remote-endpoint".
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Co-developed-by: Daniel Scally <djrscally@gmail.com>
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/base/swnode.c | 115 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 114 insertions(+), 1 deletion(-)
diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
index 032b24f60c78..7f056c5e0ed3 100644
--- a/drivers/base/swnode.c
+++ b/drivers/base/swnode.c
@@ -540,6 +540,115 @@ software_node_get_reference_args(const struct fwnode_handle *fwnode,
return 0;
}
+static struct fwnode_handle *
+swnode_graph_find_next_port(const struct fwnode_handle *parent,
+ struct fwnode_handle *port)
+{
+ struct fwnode_handle *old = port;
+
+ while ((port = software_node_get_next_child(parent, old))) {
+ /*
+ * fwnode ports have naming style "port@", so we search for any
+ * children that follow that convention.
+ */
+ if (!strncmp(to_swnode(port)->node->name, "port@",
+ strlen("port@")))
+ return port;
+ old = port;
+ }
+
+ return NULL;
+}
+
+static struct fwnode_handle *
+software_node_graph_get_next_endpoint(const struct fwnode_handle *fwnode,
+ struct fwnode_handle *endpoint)
+{
+ struct swnode *swnode = to_swnode(fwnode);
+ struct fwnode_handle *parent;
+ struct fwnode_handle *port;
+
+ if (!swnode)
+ return NULL;
+
+ if (endpoint) {
+ port = software_node_get_parent(endpoint);
+ parent = software_node_get_parent(port);
+ } else {
+ parent = software_node_get_named_child_node(fwnode, "ports");
+ if (!parent)
+ parent = software_node_get(&swnode->fwnode);
+
+ port = swnode_graph_find_next_port(parent, NULL);
+ }
+
+ for (; port; port = swnode_graph_find_next_port(parent, port)) {
+ endpoint = software_node_get_next_child(port, endpoint);
+ if (endpoint) {
+ fwnode_handle_put(port);
+ break;
+ }
+ }
+
+ fwnode_handle_put(parent);
+
+ return endpoint;
+}
+
+static struct fwnode_handle *
+software_node_graph_get_remote_endpoint(const struct fwnode_handle *fwnode)
+{
+ struct swnode *swnode = to_swnode(fwnode);
+ const struct software_node_ref_args *ref;
+ const struct property_entry *prop;
+
+ if (!swnode)
+ return NULL;
+
+ prop = property_entry_get(swnode->node->properties, "remote-endpoint");
+ if (!prop || prop->type != DEV_PROP_REF || prop->is_inline)
+ return NULL;
+
+ ref = prop->pointer;
+
+ return software_node_get(software_node_fwnode(ref[0].node));
+}
+
+static struct fwnode_handle *
+software_node_graph_get_port_parent(struct fwnode_handle *fwnode)
+{
+ struct swnode *swnode = to_swnode(fwnode);
+
+ swnode = swnode->parent;
+ if (swnode && !strcmp(swnode->node->name, "ports"))
+ swnode = swnode->parent;
+
+ return swnode ? software_node_get(&swnode->fwnode) : NULL;
+}
+
+static int
+software_node_graph_parse_endpoint(const struct fwnode_handle *fwnode,
+ struct fwnode_endpoint *endpoint)
+{
+ struct swnode *swnode = to_swnode(fwnode);
+ const char *parent_name = swnode->parent->node->name;
+ int ret;
+
+ if (strlen("port@") >= strlen(parent_name) ||
+ strncmp(parent_name, "port@", strlen("port@")))
+ return -EINVAL;
+
+ /* Ports have naming style "port@n", we need to select the n */
+ ret = kstrtou32(parent_name + strlen("port@"), 10, &endpoint->port);
+ if (ret)
+ return ret;
+
+ endpoint->id = swnode->id;
+ endpoint->local_fwnode = fwnode;
+
+ return 0;
+}
+
static const struct fwnode_operations software_node_ops = {
.get = software_node_get,
.put = software_node_put,
@@ -551,7 +660,11 @@ static const struct fwnode_operations software_node_ops = {
.get_parent = software_node_get_parent,
.get_next_child_node = software_node_get_next_child,
.get_named_child_node = software_node_get_named_child_node,
- .get_reference_args = software_node_get_reference_args
+ .get_reference_args = software_node_get_reference_args,
+ .graph_get_next_endpoint = software_node_graph_get_next_endpoint,
+ .graph_get_remote_endpoint = software_node_graph_get_remote_endpoint,
+ .graph_get_port_parent = software_node_graph_get_port_parent,
+ .graph_parse_endpoint = software_node_graph_parse_endpoint,
};
/* -------------------------------------------------------------------------- */
--
2.32.0
From 690785d85e5af79509806c7fcd03a25c5f17bb45 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sat, 10 Oct 2020 23:07:22 +0100
Subject: [PATCH] lib/test_printf.c: Use helper function to unwind array of
software_nodes
Use the software_node_unregister_nodes() helper function to unwind this
array in a cleaner way.
Acked-by: Petr Mladek <pmladek@suse.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
lib/test_printf.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/lib/test_printf.c b/lib/test_printf.c
index 7ac87f18a10f..7d60f24240a4 100644
--- a/lib/test_printf.c
+++ b/lib/test_printf.c
@@ -644,9 +644,7 @@ static void __init fwnode_pointer(void)
test(second_name, "%pfwP", software_node_fwnode(&softnodes[1]));
test(third_name, "%pfwP", software_node_fwnode(&softnodes[2]));
- software_node_unregister(&softnodes[2]);
- software_node_unregister(&softnodes[1]);
- software_node_unregister(&softnodes[0]);
+ software_node_unregister_nodes(softnodes);
}
static void __init
--
2.32.0
From 04de95d83711b399d64287ebb9092b29df7270a4 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sat, 10 Oct 2020 23:11:36 +0100
Subject: [PATCH] ipu3-cio2: Add T: entry to MAINTAINERS
Development for the ipu3-cio2 driver is taking place in media_tree, but
there's no T: entry in MAINTAINERS to denote that - rectify that oversight
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
MAINTAINERS | 1 +
1 file changed, 1 insertion(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 4fef10dd2975..7ac7d1ae8764 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8938,6 +8938,7 @@ M: Bingbu Cao <bingbu.cao@intel.com>
R: Tianshu Qiu <tian.shu.qiu@intel.com>
L: linux-media@vger.kernel.org
S: Maintained
+T: git git://linuxtv.org/media_tree.git
F: Documentation/userspace-api/media/v4l/pixfmt-srggb10-ipu3.rst
F: drivers/media/pci/intel/ipu3/
--
2.32.0
From 2c2d51e7c1971288e9e03a857483da9382c97c84 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sat, 10 Oct 2020 22:47:21 +0100
Subject: [PATCH] ipu3-cio2: Rename ipu3-cio2.c
ipu3-cio2 driver needs extending with multiple files; rename the main
source file and specify the renamed file in Makefile to accommodate that.
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/pci/intel/ipu3/Makefile | 2 ++
drivers/media/pci/intel/ipu3/{ipu3-cio2.c => ipu3-cio2-main.c} | 0
2 files changed, 2 insertions(+)
rename drivers/media/pci/intel/ipu3/{ipu3-cio2.c => ipu3-cio2-main.c} (100%)
diff --git a/drivers/media/pci/intel/ipu3/Makefile b/drivers/media/pci/intel/ipu3/Makefile
index 98ddd5beafe0..429d516452e4 100644
--- a/drivers/media/pci/intel/ipu3/Makefile
+++ b/drivers/media/pci/intel/ipu3/Makefile
@@ -1,2 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_VIDEO_IPU3_CIO2) += ipu3-cio2.o
+
+ipu3-cio2-y += ipu3-cio2-main.o
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
similarity index 100%
rename from drivers/media/pci/intel/ipu3/ipu3-cio2.c
rename to drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
--
2.32.0
From 1eb630ff976e433b62621515a9c4eda94a6b4b3c Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Wed, 21 Oct 2020 21:53:05 +0100
Subject: [PATCH] media: v4l2-core: v4l2-async: Check sd->fwnode->secondary in
match_fwnode()
Where the fwnode graph is comprised of software_nodes, these will be
assigned as the secondary to dev->fwnode. Check the v4l2_subdev's fwnode
for a secondary and attempt to match against it during match_fwnode() to
accommodate that possibility.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/v4l2-core/v4l2-async.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 33babe6e8b3a..d23dff76da3d 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -87,6 +87,14 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
if (sd->fwnode == asd->match.fwnode)
return true;
+ /*
+ * Check the same situation for any possible secondary assigned to the
+ * subdev's fwnode
+ */
+ if (!IS_ERR_OR_NULL(sd->fwnode->secondary) &&
+ sd->fwnode->secondary == asd->match.fwnode)
+ return true;
+
/*
* Otherwise, check if the sd fwnode and the asd fwnode refer to an
* endpoint or a device. If they're of the same type, there's no match.
--
2.32.0
From ee272d460a5f5cbe5c0d512334dc15ee5afda431 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sun, 15 Nov 2020 08:15:34 +0000
Subject: [PATCH] ACPI / bus: Add acpi_dev_get_next_match_dev() and helper
macro
To ensure we handle situations in which multiple sensors of the same
model (and therefore _HID) are present in a system, we need to be able
to iterate over devices matching a known _HID but unknown _UID and _HRV
- add acpi_dev_get_next_match_dev() to accommodate that possibility and
change acpi_dev_get_first_match_dev() to simply call the new function
with a NULL starting point. Add an iterator macro for convenience.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/acpi/utils.c | 30 ++++++++++++++++++++++++++----
include/acpi/acpi_bus.h | 7 +++++++
2 files changed, 33 insertions(+), 4 deletions(-)
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index d5411a166685..ddca1550cce6 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -843,12 +843,13 @@ bool acpi_dev_present(const char *hid, const char *uid, s64 hrv)
EXPORT_SYMBOL(acpi_dev_present);
/**
- * acpi_dev_get_first_match_dev - Return the first match of ACPI device
+ * acpi_dev_get_next_match_dev - Return the next match of ACPI device
+ * @adev: Pointer to the previous acpi_device matching this @hid, @uid and @hrv
* @hid: Hardware ID of the device.
* @uid: Unique ID of the device, pass NULL to not check _UID
* @hrv: Hardware Revision of the device, pass -1 to not check _HRV
*
- * Return the first match of ACPI device if a matching device was present
+ * Return the next match of ACPI device if another matching device was present
* at the moment of invocation, or NULL otherwise.
*
* The caller is responsible to call put_device() on the returned device.
@@ -856,8 +857,9 @@ EXPORT_SYMBOL(acpi_dev_present);
* See additional information in acpi_dev_present() as well.
*/
struct acpi_device *
-acpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv)
+acpi_dev_get_next_match_dev(struct acpi_device *adev, const char *hid, const char *uid, s64 hrv)
{
+ struct device *start = adev ? &adev->dev : NULL;
struct acpi_dev_match_info match = {};
struct device *dev;
@@ -865,9 +867,29 @@ acpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv)
match.uid = uid;
match.hrv = hrv;
- dev = bus_find_device(&acpi_bus_type, NULL, &match, acpi_dev_match_cb);
+ dev = bus_find_device(&acpi_bus_type, start, &match, acpi_dev_match_cb);
return dev ? to_acpi_device(dev) : NULL;
}
+EXPORT_SYMBOL(acpi_dev_get_next_match_dev);
+
+/**
+ * acpi_dev_get_first_match_dev - Return the first match of ACPI device
+ * @hid: Hardware ID of the device.
+ * @uid: Unique ID of the device, pass NULL to not check _UID
+ * @hrv: Hardware Revision of the device, pass -1 to not check _HRV
+ *
+ * Return the first match of ACPI device if a matching device was present
+ * at the moment of invocation, or NULL otherwise.
+ *
+ * The caller is responsible to call put_device() on the returned device.
+ *
+ * See additional information in acpi_dev_present() as well.
+ */
+struct acpi_device *
+acpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv)
+{
+ return acpi_dev_get_next_match_dev(NULL, hid, uid, hrv);
+}
EXPORT_SYMBOL(acpi_dev_get_first_match_dev);
/*
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 6ad3b89a8a2e..7295aa50120a 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -684,9 +684,16 @@ static inline bool acpi_device_can_poweroff(struct acpi_device *adev)
bool acpi_dev_hid_uid_match(struct acpi_device *adev, const char *hid2, const char *uid2);
+struct acpi_device *
+acpi_dev_get_next_match_dev(struct acpi_device *adev, const char *hid, const char *uid, s64 hrv);
struct acpi_device *
acpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv);
+#define for_each_acpi_dev_match(adev, hid, uid, hrv) \
+ for (adev = acpi_dev_get_first_match_dev(hid, uid, hrv); \
+ adev; \
+ adev = acpi_dev_get_next_match_dev(adev, hid, uid, hrv))
+
static inline void acpi_dev_put(struct acpi_device *adev)
{
if (adev)
--
2.32.0
From b150f1a0bd590417f29f8e3084d9f6f083a4ae6c Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sat, 19 Dec 2020 23:55:04 +0000
Subject: [PATCH] media: v4l2-fwnode: Include v4l2_fwnode_bus_type
V4L2 fwnode bus types are enumerated in v4l2-fwnode.c, meaning they aren't
available to the rest of the kernel. Move the enum to the corresponding
header so that I can use the label to refer to those values.
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/v4l2-core/v4l2-fwnode.c | 11 -----------
include/media/v4l2-fwnode.h | 22 ++++++++++++++++++++++
2 files changed, 22 insertions(+), 11 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index dfc53d11053f..fe01aeb59fd4 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -28,17 +28,6 @@
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
-enum v4l2_fwnode_bus_type {
- V4L2_FWNODE_BUS_TYPE_GUESS = 0,
- V4L2_FWNODE_BUS_TYPE_CSI2_CPHY,
- V4L2_FWNODE_BUS_TYPE_CSI1,
- V4L2_FWNODE_BUS_TYPE_CCP2,
- V4L2_FWNODE_BUS_TYPE_CSI2_DPHY,
- V4L2_FWNODE_BUS_TYPE_PARALLEL,
- V4L2_FWNODE_BUS_TYPE_BT656,
- NR_OF_V4L2_FWNODE_BUS_TYPE,
-};
-
static const struct v4l2_fwnode_bus_conv {
enum v4l2_fwnode_bus_type fwnode_bus_type;
enum v4l2_mbus_type mbus_type;
diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
index ed0840f3d5df..6ca337c28b3c 100644
--- a/include/media/v4l2-fwnode.h
+++ b/include/media/v4l2-fwnode.h
@@ -213,6 +213,28 @@ struct v4l2_fwnode_connector {
} connector;
};
+/**
+ * enum v4l2_fwnode_bus_type - Video bus types defined by firmware properties
+ * @V4L2_FWNODE_BUS_TYPE_GUESS: Default value if no bus-type fwnode property
+ * @V4L2_FWNODE_BUS_TYPE_CSI2_CPHY: MIPI CSI-2 bus, C-PHY physical layer
+ * @V4L2_FWNODE_BUS_TYPE_CSI1: MIPI CSI-1 bus
+ * @V4L2_FWNODE_BUS_TYPE_CCP2: SMIA Compact Camera Port 2 bus
+ * @V4L2_FWNODE_BUS_TYPE_CSI2_DPHY: MIPI CSI-2 bus, D-PHY physical layer
+ * @V4L2_FWNODE_BUS_TYPE_PARALLEL: Camera Parallel Interface bus
+ * @V4L2_FWNODE_BUS_TYPE_BT656: BT.656 video format bus-type
+ * @NR_OF_V4L2_FWNODE_BUS_TYPE: Number of bus-types
+ */
+enum v4l2_fwnode_bus_type {
+ V4L2_FWNODE_BUS_TYPE_GUESS = 0,
+ V4L2_FWNODE_BUS_TYPE_CSI2_CPHY,
+ V4L2_FWNODE_BUS_TYPE_CSI1,
+ V4L2_FWNODE_BUS_TYPE_CCP2,
+ V4L2_FWNODE_BUS_TYPE_CSI2_DPHY,
+ V4L2_FWNODE_BUS_TYPE_PARALLEL,
+ V4L2_FWNODE_BUS_TYPE_BT656,
+ NR_OF_V4L2_FWNODE_BUS_TYPE
+};
+
/**
* v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
* @fwnode: pointer to the endpoint's fwnode handle
--
2.32.0
From 778a6a05b1c5b51fa8f973317b91692d3a33aa70 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Wed, 21 Oct 2020 21:53:44 +0100
Subject: [PATCH] ipu3-cio2: Add cio2-bridge to ipu3-cio2 driver
Currently on platforms designed for Windows, connections between CIO2 and
sensors are not properly defined in DSDT. This patch extends the ipu3-cio2
driver to compensate by building software_node connections, parsing the
connection properties from the sensor's SSDB buffer.
Suggested-by: Jordan Hand <jorhand@linux.microsoft.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
MAINTAINERS | 1 +
drivers/media/pci/intel/ipu3/Kconfig | 18 +
drivers/media/pci/intel/ipu3/Makefile | 1 +
drivers/media/pci/intel/ipu3/cio2-bridge.c | 311 ++++++++++++++++++
drivers/media/pci/intel/ipu3/cio2-bridge.h | 125 +++++++
drivers/media/pci/intel/ipu3/ipu3-cio2-main.c | 34 ++
drivers/media/pci/intel/ipu3/ipu3-cio2.h | 6 +
7 files changed, 496 insertions(+)
create mode 100644 drivers/media/pci/intel/ipu3/cio2-bridge.c
create mode 100644 drivers/media/pci/intel/ipu3/cio2-bridge.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 7ac7d1ae8764..f313ba49c2b8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8935,6 +8935,7 @@ INTEL IPU3 CSI-2 CIO2 DRIVER
M: Yong Zhi <yong.zhi@intel.com>
M: Sakari Ailus <sakari.ailus@linux.intel.com>
M: Bingbu Cao <bingbu.cao@intel.com>
+M: Dan Scally <djrscally@gmail.com>
R: Tianshu Qiu <tian.shu.qiu@intel.com>
L: linux-media@vger.kernel.org
S: Maintained
diff --git a/drivers/media/pci/intel/ipu3/Kconfig b/drivers/media/pci/intel/ipu3/Kconfig
index 7a805201034b..24f4e79fe0cb 100644
--- a/drivers/media/pci/intel/ipu3/Kconfig
+++ b/drivers/media/pci/intel/ipu3/Kconfig
@@ -17,3 +17,21 @@ config VIDEO_IPU3_CIO2
Say Y or M here if you have a Skylake/Kaby Lake SoC with MIPI CSI-2
connected camera.
The module will be called ipu3-cio2.
+
+config CIO2_BRIDGE
+ bool "IPU3 CIO2 Sensors Bridge"
+ depends on VIDEO_IPU3_CIO2
+ help
+ This extension provides an API for the ipu3-cio2 driver to create
+ connections to cameras that are hidden in the SSDB buffer in ACPI.
+ It can be used to enable support for cameras in detachable / hybrid
+ devices that ship with Windows.
+
+ Say Y here if your device is a detachable / hybrid laptop that comes
+ with Windows installed by the OEM, for example:
+
+ - Microsoft Surface models (except Surface Pro 3)
+ - The Lenovo Miix line (for example the 510, 520, 710 and 720)
+ - Dell 7285
+
+ If in doubt, say N here.
diff --git a/drivers/media/pci/intel/ipu3/Makefile b/drivers/media/pci/intel/ipu3/Makefile
index 429d516452e4..933777e6ea8a 100644
--- a/drivers/media/pci/intel/ipu3/Makefile
+++ b/drivers/media/pci/intel/ipu3/Makefile
@@ -2,3 +2,4 @@
obj-$(CONFIG_VIDEO_IPU3_CIO2) += ipu3-cio2.o
ipu3-cio2-y += ipu3-cio2-main.o
+ipu3-cio2-$(CONFIG_CIO2_BRIDGE) += cio2-bridge.o
diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.c b/drivers/media/pci/intel/ipu3/cio2-bridge.c
new file mode 100644
index 000000000000..143f3c0f445e
--- /dev/null
+++ b/drivers/media/pci/intel/ipu3/cio2-bridge.c
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dan Scally <djrscally@gmail.com> */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/property.h>
+#include <media/v4l2-fwnode.h>
+
+#include "cio2-bridge.h"
+
+/*
+ * Extend this array with ACPI Hardware IDs of devices known to be working
+ * plus the number of link-frequencies expected by their drivers, along with
+ * the frequency values in hertz. This is somewhat opportunistic way of adding
+ * support for this for now in the hopes of a better source for the information
+ * (possibly some encoded value in the SSDB buffer that we're unaware of)
+ * becoming apparent in the future.
+ *
+ * Do not add an entry for a sensor that is not actually supported.
+ */
+static const struct cio2_sensor_config cio2_supported_sensors[] = {
+ /* Omnivision OV5693 */
+ CIO2_SENSOR_CONFIG("INT33BE", 0),
+ /* Omnivision OV2680 */
+ CIO2_SENSOR_CONFIG("OVTI2680", 0),
+};
+
+static const struct cio2_property_names prop_names = {
+ .clock_frequency = "clock-frequency",
+ .rotation = "rotation",
+ .bus_type = "bus-type",
+ .data_lanes = "data-lanes",
+ .remote_endpoint = "remote-endpoint",
+ .link_frequencies = "link-frequencies",
+};
+
+static int cio2_bridge_read_acpi_buffer(struct acpi_device *adev, char *id,
+ void *data, u32 size)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ acpi_status status;
+ int ret = 0;
+
+ status = acpi_evaluate_object(adev->handle, id, NULL, &buffer);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ obj = buffer.pointer;
+ if (!obj) {
+ dev_err(&adev->dev, "Couldn't locate ACPI buffer\n");
+ return -ENODEV;
+ }
+
+ if (obj->type != ACPI_TYPE_BUFFER) {
+ dev_err(&adev->dev, "Not an ACPI buffer\n");
+ ret = -ENODEV;
+ goto out_free_buff;
+ }
+
+ if (obj->buffer.length > size) {
+ dev_err(&adev->dev, "Given buffer is too small\n");
+ ret = -EINVAL;
+ goto out_free_buff;
+ }
+
+ memcpy(data, obj->buffer.pointer, obj->buffer.length);
+
+out_free_buff:
+ kfree(buffer.pointer);
+ return ret;
+}
+
+static void cio2_bridge_create_fwnode_properties(
+ struct cio2_sensor *sensor,
+ struct cio2_bridge *bridge,
+ const struct cio2_sensor_config *cfg)
+{
+ sensor->prop_names = prop_names;
+
+ sensor->local_ref[0].node = &sensor->swnodes[SWNODE_CIO2_ENDPOINT];
+ sensor->remote_ref[0].node = &sensor->swnodes[SWNODE_SENSOR_ENDPOINT];
+
+ sensor->dev_properties[0] = PROPERTY_ENTRY_U32(
+ sensor->prop_names.clock_frequency,
+ sensor->ssdb.mclkspeed);
+ sensor->dev_properties[1] = PROPERTY_ENTRY_U8(
+ sensor->prop_names.rotation,
+ sensor->ssdb.degree);
+
+ sensor->ep_properties[0] = PROPERTY_ENTRY_U32(
+ sensor->prop_names.bus_type,
+ V4L2_FWNODE_BUS_TYPE_CSI2_DPHY);
+ sensor->ep_properties[1] = PROPERTY_ENTRY_U32_ARRAY_LEN(
+ sensor->prop_names.data_lanes,
+ bridge->data_lanes,
+ sensor->ssdb.lanes);
+ sensor->ep_properties[2] = PROPERTY_ENTRY_REF_ARRAY(
+ sensor->prop_names.remote_endpoint,
+ sensor->local_ref);
+
+ if (cfg->nr_link_freqs > 0)
+ sensor->ep_properties[3] = PROPERTY_ENTRY_U64_ARRAY_LEN(
+ sensor->prop_names.link_frequencies,
+ cfg->link_freqs,
+ cfg->nr_link_freqs);
+
+ sensor->cio2_properties[0] = PROPERTY_ENTRY_U32_ARRAY_LEN(
+ sensor->prop_names.data_lanes,
+ bridge->data_lanes,
+ sensor->ssdb.lanes);
+ sensor->cio2_properties[1] = PROPERTY_ENTRY_REF_ARRAY(
+ sensor->prop_names.remote_endpoint,
+ sensor->remote_ref);
+}
+
+static void cio2_bridge_init_swnode_names(struct cio2_sensor *sensor)
+{
+ snprintf(sensor->node_names.remote_port,
+ sizeof(sensor->node_names.remote_port),
+ SWNODE_GRAPH_PORT_NAME_FMT, sensor->ssdb.link);
+ snprintf(sensor->node_names.port,
+ sizeof(sensor->node_names.port),
+ SWNODE_GRAPH_PORT_NAME_FMT, 0); /* Always port 0 */
+ snprintf(sensor->node_names.endpoint,
+ sizeof(sensor->node_names.endpoint),
+ SWNODE_GRAPH_ENDPOINT_NAME_FMT, 0); /* And endpoint 0 */
+}
+
+static void cio2_bridge_create_connection_swnodes(struct cio2_bridge *bridge,
+ struct cio2_sensor *sensor)
+{
+ struct software_node *nodes = sensor->swnodes;
+
+ cio2_bridge_init_swnode_names(sensor);
+
+ nodes[SWNODE_SENSOR_HID] = NODE_SENSOR(sensor->name,
+ sensor->dev_properties);
+ nodes[SWNODE_SENSOR_PORT] = NODE_PORT(sensor->node_names.port,
+ &nodes[SWNODE_SENSOR_HID]);
+ nodes[SWNODE_SENSOR_ENDPOINT] = NODE_ENDPOINT(
+ sensor->node_names.endpoint,
+ &nodes[SWNODE_SENSOR_PORT],
+ sensor->ep_properties);
+ nodes[SWNODE_CIO2_PORT] = NODE_PORT(sensor->node_names.remote_port,
+ &bridge->cio2_hid_node);
+ nodes[SWNODE_CIO2_ENDPOINT] = NODE_ENDPOINT(
+ sensor->node_names.endpoint,
+ &nodes[SWNODE_CIO2_PORT],
+ sensor->cio2_properties);
+}
+
+static void cio2_bridge_unregister_sensors(struct cio2_bridge *bridge)
+{
+ struct cio2_sensor *sensor;
+ unsigned int i;
+
+ for (i = 0; i < bridge->n_sensors; i++) {
+ sensor = &bridge->sensors[i];
+ software_node_unregister_nodes(sensor->swnodes);
+ acpi_dev_put(sensor->adev);
+ }
+}
+
+static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
+ struct cio2_bridge *bridge,
+ struct pci_dev *cio2)
+{
+ struct fwnode_handle *fwnode;
+ struct cio2_sensor *sensor;
+ struct acpi_device *adev;
+ int ret;
+
+ for_each_acpi_dev_match(adev, cfg->hid, NULL, -1) {
+ if (!adev->status.enabled)
+ continue;
+
+ if (bridge->n_sensors >= CIO2_NUM_PORTS) {
+ dev_err(&cio2->dev, "Exceeded available CIO2 ports\n");
+ cio2_bridge_unregister_sensors(bridge);
+ ret = -EINVAL;
+ goto err_out;
+ }
+
+ sensor = &bridge->sensors[bridge->n_sensors];
+ sensor->adev = adev;
+ strscpy(sensor->name, cfg->hid, sizeof(sensor->name));
+
+ ret = cio2_bridge_read_acpi_buffer(adev, "SSDB",
+ &sensor->ssdb,
+ sizeof(sensor->ssdb));
+ if (ret)
+ goto err_put_adev;
+
+ if (sensor->ssdb.lanes > CIO2_MAX_LANES) {
+ dev_err(&adev->dev,
+ "Number of lanes in SSDB is invalid\n");
+ ret = -EINVAL;
+ goto err_put_adev;
+ }
+
+ cio2_bridge_create_fwnode_properties(sensor, bridge, cfg);
+ cio2_bridge_create_connection_swnodes(bridge, sensor);
+
+ ret = software_node_register_nodes(sensor->swnodes);
+ if (ret)
+ goto err_put_adev;
+
+ fwnode = software_node_fwnode(&sensor->swnodes[SWNODE_SENSOR_HID]);
+ if (!fwnode) {
+ ret = -ENODEV;
+ goto err_free_swnodes;
+ }
+
+ adev->fwnode.secondary = fwnode;
+
+ dev_info(&cio2->dev, "Found supported sensor %s\n",
+ acpi_dev_name(adev));
+
+ bridge->n_sensors++;
+ }
+
+ return 0;
+
+err_free_swnodes:
+ software_node_unregister_nodes(sensor->swnodes);
+err_put_adev:
+ acpi_dev_put(sensor->adev);
+err_out:
+ return ret;
+}
+
+static int cio2_bridge_connect_sensors(struct cio2_bridge *bridge,
+ struct pci_dev *cio2)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(cio2_supported_sensors); i++) {
+ const struct cio2_sensor_config *cfg = &cio2_supported_sensors[i];
+
+ ret = cio2_bridge_connect_sensor(cfg, bridge, cio2);
+ if (ret)
+ goto err_unregister_sensors;
+ }
+
+ return 0;
+
+err_unregister_sensors:
+ cio2_bridge_unregister_sensors(bridge);
+ return ret;
+}
+
+int cio2_bridge_init(struct pci_dev *cio2)
+{
+ struct device *dev = &cio2->dev;
+ struct fwnode_handle *fwnode;
+ struct cio2_bridge *bridge;
+ unsigned int i;
+ int ret;
+
+ bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
+ if (!bridge)
+ return -ENOMEM;
+
+ strscpy(bridge->cio2_node_name, CIO2_HID, sizeof(bridge->cio2_node_name));
+ bridge->cio2_hid_node.name = bridge->cio2_node_name;
+
+ ret = software_node_register(&bridge->cio2_hid_node);
+ if (ret < 0) {
+ dev_err(dev, "Failed to register the CIO2 HID node\n");
+ goto err_free_bridge;
+ }
+
+ /*
+ * Map the lane arrangement, which is fixed for the IPU3 (meaning we
+ * only need one, rather than one per sensor). We include it as a
+ * member of the struct cio2_bridge rather than a global variable so
+ * that it survives if the module is unloaded along with the rest of
+ * the struct.
+ */
+ for (i = 0; i < CIO2_MAX_LANES; i++)
+ bridge->data_lanes[i] = i + 1;
+
+ ret = cio2_bridge_connect_sensors(bridge, cio2);
+ if (ret || bridge->n_sensors == 0)
+ goto err_unregister_cio2;
+
+ dev_info(dev, "Connected %d cameras\n", bridge->n_sensors);
+
+ fwnode = software_node_fwnode(&bridge->cio2_hid_node);
+ if (!fwnode) {
+ dev_err(dev, "Error getting fwnode from cio2 software_node\n");
+ ret = -ENODEV;
+ goto err_unregister_sensors;
+ }
+
+ set_secondary_fwnode(dev, fwnode);
+
+ return 0;
+
+err_unregister_sensors:
+ cio2_bridge_unregister_sensors(bridge);
+err_unregister_cio2:
+ software_node_unregister(&bridge->cio2_hid_node);
+err_free_bridge:
+ kfree(bridge);
+
+ return ret;
+}
diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.h b/drivers/media/pci/intel/ipu3/cio2-bridge.h
new file mode 100644
index 000000000000..dd0ffcafa489
--- /dev/null
+++ b/drivers/media/pci/intel/ipu3/cio2-bridge.h
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Author: Dan Scally <djrscally@gmail.com> */
+#ifndef __CIO2_BRIDGE_H
+#define __CIO2_BRIDGE_H
+
+#include <linux/property.h>
+#include <linux/types.h>
+
+#include "ipu3-cio2.h"
+
+#define CIO2_HID "INT343E"
+#define CIO2_MAX_LANES 4
+#define MAX_NUM_LINK_FREQS 3
+
+#define CIO2_SENSOR_CONFIG(_HID, _NR, ...) \
+ (const struct cio2_sensor_config) { \
+ .hid = _HID, \
+ .nr_link_freqs = _NR, \
+ .link_freqs = { __VA_ARGS__ } \
+ }
+
+#define NODE_SENSOR(_HID, _PROPS) \
+ (const struct software_node) { \
+ .name = _HID, \
+ .properties = _PROPS, \
+ }
+
+#define NODE_PORT(_PORT, _SENSOR_NODE) \
+ (const struct software_node) { \
+ .name = _PORT, \
+ .parent = _SENSOR_NODE, \
+ }
+
+#define NODE_ENDPOINT(_EP, _PORT, _PROPS) \
+ (const struct software_node) { \
+ .name = _EP, \
+ .parent = _PORT, \
+ .properties = _PROPS, \
+ }
+
+enum cio2_sensor_swnodes {
+ SWNODE_SENSOR_HID,
+ SWNODE_SENSOR_PORT,
+ SWNODE_SENSOR_ENDPOINT,
+ SWNODE_CIO2_PORT,
+ SWNODE_CIO2_ENDPOINT,
+ SWNODE_COUNT
+};
+
+/* Data representation as it is in ACPI SSDB buffer */
+struct cio2_sensor_ssdb {
+ u8 version;
+ u8 sku;
+ u8 guid_csi2[16];
+ u8 devfunction;
+ u8 bus;
+ u32 dphylinkenfuses;
+ u32 clockdiv;
+ u8 link;
+ u8 lanes;
+ u32 csiparams[10];
+ u32 maxlanespeed;
+ u8 sensorcalibfileidx;
+ u8 sensorcalibfileidxInMBZ[3];
+ u8 romtype;
+ u8 vcmtype;
+ u8 platforminfo;
+ u8 platformsubinfo;
+ u8 flash;
+ u8 privacyled;
+ u8 degree;
+ u8 mipilinkdefined;
+ u32 mclkspeed;
+ u8 controllogicid;
+ u8 reserved1[3];
+ u8 mclkport;
+ u8 reserved2[13];
+} __packed;
+
+struct cio2_property_names {
+ char clock_frequency[16];
+ char rotation[9];
+ char bus_type[9];
+ char data_lanes[11];
+ char remote_endpoint[16];
+ char link_frequencies[17];
+};
+
+struct cio2_node_names {
+ char port[7];
+ char endpoint[11];
+ char remote_port[7];
+};
+
+struct cio2_sensor_config {
+ const char *hid;
+ const u8 nr_link_freqs;
+ const u64 link_freqs[MAX_NUM_LINK_FREQS];
+};
+
+struct cio2_sensor {
+ char name[ACPI_ID_LEN];
+ struct acpi_device *adev;
+
+ struct software_node swnodes[6];
+ struct cio2_node_names node_names;
+
+ struct cio2_sensor_ssdb ssdb;
+ struct cio2_property_names prop_names;
+ struct property_entry ep_properties[5];
+ struct property_entry dev_properties[3];
+ struct property_entry cio2_properties[3];
+ struct software_node_ref_args local_ref[1];
+ struct software_node_ref_args remote_ref[1];
+};
+
+struct cio2_bridge {
+ char cio2_node_name[ACPI_ID_LEN];
+ struct software_node cio2_hid_node;
+ u32 data_lanes[4];
+ unsigned int n_sensors;
+ struct cio2_sensor sensors[CIO2_NUM_PORTS];
+};
+
+#endif
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
index c0cd4606810c..77cea941fd8d 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
@@ -1709,11 +1709,28 @@ static void cio2_queues_exit(struct cio2_device *cio2)
cio2_queue_exit(cio2, &cio2->queue[i]);
}
+static int cio2_check_fwnode_graph(struct fwnode_handle *fwnode)
+{
+ struct fwnode_handle *endpoint;
+
+ if (IS_ERR_OR_NULL(fwnode))
+ return -EINVAL;
+
+ endpoint = fwnode_graph_get_next_endpoint(fwnode, NULL);
+ if (endpoint) {
+ fwnode_handle_put(endpoint);
+ return 0;
+ }
+
+ return cio2_check_fwnode_graph(fwnode->secondary);
+}
+
/**************** PCI interface ****************/
static int cio2_pci_probe(struct pci_dev *pci_dev,
const struct pci_device_id *id)
{
+ struct fwnode_handle *fwnode = dev_fwnode(&pci_dev->dev);
struct cio2_device *cio2;
int r;
@@ -1722,6 +1739,23 @@ static int cio2_pci_probe(struct pci_dev *pci_dev,
return -ENOMEM;
cio2->pci_dev = pci_dev;
+ /*
+ * On some platforms no connections to sensors are defined in firmware,
+ * if the device has no endpoints then we can try to build those as
+ * software_nodes parsed from SSDB.
+ */
+ r = cio2_check_fwnode_graph(fwnode);
+ if (r) {
+ if (fwnode && !IS_ERR_OR_NULL(fwnode->secondary)) {
+ dev_err(&pci_dev->dev, "fwnode graph has no endpoints connected\n");
+ return -EINVAL;
+ }
+
+ r = cio2_bridge_init(pci_dev);
+ if (r)
+ return r;
+ }
+
r = pcim_enable_device(pci_dev);
if (r) {
dev_err(&pci_dev->dev, "failed to enable device (%d)\n", r);
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.h b/drivers/media/pci/intel/ipu3/ipu3-cio2.h
index 62187ab5ae43..dc3e343a37fb 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.h
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.h
@@ -455,4 +455,10 @@ static inline struct cio2_queue *vb2q_to_cio2_queue(struct vb2_queue *vq)
return container_of(vq, struct cio2_queue, vbq);
}
+#if IS_ENABLED(CONFIG_CIO2_BRIDGE)
+int cio2_bridge_init(struct pci_dev *cio2);
+#else
+int cio2_bridge_init(struct pci_dev *cio2) { return 0; }
+#endif
+
#endif
--
2.32.0
From f46cf5b91ced1e8c476afc861fa0bba744362a06 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Wed, 2 Dec 2020 12:38:10 +0000
Subject: [PATCH] acpi: utils: move acpi_lpss_dep() to utils
I need to be able to identify devices which declare themselves to be
dependent on other devices through _DEP; add this function to utils.c
and export it to the rest of the ACPI layer.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/acpi/acpi_lpss.c | 24 ------------------------
drivers/acpi/internal.h | 1 +
drivers/acpi/utils.c | 24 ++++++++++++++++++++++++
3 files changed, 25 insertions(+), 24 deletions(-)
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index be73974ce449..70c7d9a3f715 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -543,30 +543,6 @@ static struct device *acpi_lpss_find_device(const char *hid, const char *uid)
return bus_find_device(&pci_bus_type, NULL, &data, match_hid_uid);
}
-static bool acpi_lpss_dep(struct acpi_device *adev, acpi_handle handle)
-{
- struct acpi_handle_list dep_devices;
- acpi_status status;
- int i;
-
- if (!acpi_has_method(adev->handle, "_DEP"))
- return false;
-
- status = acpi_evaluate_reference(adev->handle, "_DEP", NULL,
- &dep_devices);
- if (ACPI_FAILURE(status)) {
- dev_dbg(&adev->dev, "Failed to evaluate _DEP.\n");
- return false;
- }
-
- for (i = 0; i < dep_devices.count; i++) {
- if (dep_devices.handles[i] == handle)
- return true;
- }
-
- return false;
-}
-
static void acpi_lpss_link_consumer(struct device *dev1,
const struct lpss_device_links *link)
{
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index a958ad60a339..3901a251c998 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -81,6 +81,7 @@ static inline void acpi_lpss_init(void) {}
#endif
void acpi_apd_init(void);
+bool acpi_lpss_dep(struct acpi_device *adev, acpi_handle handle);
acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src);
bool acpi_queue_hotplug_work(struct work_struct *work);
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index ddca1550cce6..78b38775f18b 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -807,6 +807,30 @@ static int acpi_dev_match_cb(struct device *dev, const void *data)
return hrv == match->hrv;
}
+bool acpi_lpss_dep(struct acpi_device *adev, acpi_handle handle)
+{
+ struct acpi_handle_list dep_devices;
+ acpi_status status;
+ int i;
+
+ if (!acpi_has_method(adev->handle, "_DEP"))
+ return false;
+
+ status = acpi_evaluate_reference(adev->handle, "_DEP", NULL,
+ &dep_devices);
+ if (ACPI_FAILURE(status)) {
+ dev_dbg(&adev->dev, "Failed to evaluate _DEP.\n");
+ return false;
+ }
+
+ for (i = 0; i < dep_devices.count; i++) {
+ if (dep_devices.handles[i] == handle)
+ return true;
+ }
+
+ return false;
+}
+
/**
* acpi_dev_present - Detect that a given ACPI device is present
* @hid: Hardware ID of the device.
--
2.32.0
From 3b0f082b6a6ae798f7eca080251ad53cff5579aa Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Thu, 26 Nov 2020 21:12:41 +0000
Subject: [PATCH] acpi: utils: Add function to fetch dependent acpi_devices
In some ACPI tables we encounter, devices use the _DEP method to assert
a dependence on other ACPI devices as opposed to the OpRegions that the
specification intends. We need to be able to find those devices "from"
the dependee, so add a function to parse all ACPI Devices and check if
the include the handle of the dependee device in their _DEP buffer.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/acpi/utils.c | 34 ++++++++++++++++++++++++++++++++++
include/acpi/acpi_bus.h | 2 ++
2 files changed, 36 insertions(+)
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 78b38775f18b..ec6a2406a886 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -831,6 +831,18 @@ bool acpi_lpss_dep(struct acpi_device *adev, acpi_handle handle)
return false;
}
+static int acpi_dev_match_by_dep(struct device *dev, const void *data)
+{
+ struct acpi_device *adev = to_acpi_device(dev);
+ const struct acpi_device *dependee = data;
+ acpi_handle handle = dependee->handle;
+
+ if (acpi_lpss_dep(adev, handle))
+ return 1;
+
+ return 0;
+}
+
/**
* acpi_dev_present - Detect that a given ACPI device is present
* @hid: Hardware ID of the device.
@@ -866,6 +878,28 @@ bool acpi_dev_present(const char *hid, const char *uid, s64 hrv)
}
EXPORT_SYMBOL(acpi_dev_present);
+/**
+ * acpi_dev_get_next_dep_dev - Return next ACPI device dependent on input dev
+ * @adev: Pointer to the dependee device
+ * @prev: Pointer to the previous dependent device (or NULL for first match)
+ *
+ * Return the next ACPI device which declares itself dependent on @adev in
+ * the _DEP buffer.
+ *
+ * The caller is responsible to call put_device() on the returned device.
+ */
+struct acpi_device *acpi_dev_get_next_dep_dev(struct acpi_device *adev,
+ struct acpi_device *prev)
+{
+ struct device *start = prev ? &prev->dev : NULL;
+ struct device *dev;
+
+ dev = bus_find_device(&acpi_bus_type, start, adev, acpi_dev_match_by_dep);
+
+ return dev ? to_acpi_device(dev) : NULL;
+}
+EXPORT_SYMBOL(acpi_dev_get_next_dep_dev);
+
/**
* acpi_dev_get_next_match_dev - Return the next match of ACPI device
* @adev: Pointer to the previous acpi_device matching this @hid, @uid and @hrv
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 7295aa50120a..58f964471da5 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -684,6 +684,8 @@ static inline bool acpi_device_can_poweroff(struct acpi_device *adev)
bool acpi_dev_hid_uid_match(struct acpi_device *adev, const char *hid2, const char *uid2);
+struct acpi_device *
+acpi_dev_get_next_dep_dev(struct acpi_device *adev, struct acpi_device *prev);
struct acpi_device *
acpi_dev_get_next_match_dev(struct acpi_device *adev, const char *hid, const char *uid, s64 hrv);
struct acpi_device *
--
2.32.0
From 427dcd2629b69fbbe78c88b5e7b51c36d2a55577 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Mon, 16 Nov 2020 21:38:49 +0000
Subject: [PATCH] i2c: i2c-core-base: Use format macro in i2c_dev_set_name()
Some places in the kernel allow users to map resources to a device
using device name (for example, gpiod_lookup_table). Currently
this involves waiting for the i2c_client to have been registered so we
can use dev_name(&client->dev). We want to add a function to allow users
to refer to an i2c device by name before it has been instantiated, so
create a macro for the format that's accessible outside the i2c layer
and use it in i2c_dev_set_name()
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/i2c/i2c-core-base.c | 4 ++--
include/linux/i2c.h | 7 +++++++
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index bdce6d3e5327..f3ecc78dca4e 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -813,12 +813,12 @@ static void i2c_dev_set_name(struct i2c_adapter *adap,
struct acpi_device *adev = ACPI_COMPANION(&client->dev);
if (info && info->dev_name) {
- dev_set_name(&client->dev, "i2c-%s", info->dev_name);
+ dev_set_name(&client->dev, I2C_DEV_NAME_FORMAT, info->dev_name);
return;
}
if (adev) {
- dev_set_name(&client->dev, "i2c-%s", acpi_dev_name(adev));
+ dev_set_name(&client->dev, I2C_DEV_NAME_FORMAT, acpi_dev_name(adev));
return;
}
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index a670ae129f4b..b18172f240af 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -39,6 +39,9 @@ enum i2c_slave_event;
typedef int (*i2c_slave_cb_t)(struct i2c_client *client,
enum i2c_slave_event event, u8 *val);
+/* I2C Device Name Format - to maintain consistency outside the i2c layer */
+#define I2C_DEV_NAME_FORMAT "i2c-%s"
+
/* I2C Frequency Modes */
#define I2C_MAX_STANDARD_MODE_FREQ 100000
#define I2C_MAX_FAST_MODE_FREQ 400000
@@ -1013,6 +1016,10 @@ static inline struct i2c_client *i2c_acpi_new_device(struct device *dev,
{
return ERR_PTR(-ENODEV);
}
+static inline char *i2c_acpi_dev_name(struct acpi_device *adev)
+{
+ return NULL;
+}
static inline struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle)
{
return NULL;
--
2.32.0
From 81f1849d80465d03b85618606d65784ff8c1a5b7 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Wed, 2 Dec 2020 16:41:42 +0000
Subject: [PATCH] i2c: i2c-core-acpi: Add i2c_acpi_dev_name()
We want to refer to an i2c device by name before it has been
created by the kernel; add a function that constructs the name
from the acpi device instead.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/i2c/i2c-core-acpi.c | 16 ++++++++++++++++
include/linux/i2c.h | 1 +
2 files changed, 17 insertions(+)
diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c
index aed579942436..89751415b69b 100644
--- a/drivers/i2c/i2c-core-acpi.c
+++ b/drivers/i2c/i2c-core-acpi.c
@@ -497,6 +497,22 @@ struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
}
EXPORT_SYMBOL_GPL(i2c_acpi_new_device);
+/**
+ * i2c_acpi_dev_name - Construct i2c device name for devs sourced from ACPI
+ * @adev: ACPI device to construct the name for
+ *
+ * Constructs the name of an i2c device matching the format used by
+ * i2c_dev_set_name() to allow users to refer to an i2c device by name even
+ * before they have been instantiated.
+ *
+ * The caller is responsible for freeing the returned pointer.
+ */
+char *i2c_acpi_dev_name(struct acpi_device *adev)
+{
+ return kasprintf(GFP_KERNEL, I2C_DEV_NAME_FORMAT, acpi_dev_name(adev));
+}
+EXPORT_SYMBOL_GPL(i2c_acpi_dev_name);
+
#ifdef CONFIG_ACPI_I2C_OPREGION
static int acpi_gsb_i2c_read_bytes(struct i2c_client *client,
u8 cmd, u8 *data, u8 data_len)
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index b18172f240af..269a2009080c 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -1000,6 +1000,7 @@ bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares,
u32 i2c_acpi_find_bus_speed(struct device *dev);
struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
struct i2c_board_info *info);
+char *i2c_acpi_dev_name(struct acpi_device *adev);
struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle);
#else
static inline bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares,
--
2.32.0
From 80f4c19363358c51fdee447bb60a6d7ab265faf3 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Mon, 16 Nov 2020 00:16:56 +0000
Subject: [PATCH] gpio: gpiolib-acpi: Export acpi_get_gpiod()
I need to be able to translate GPIO resources in an acpi_device's _CRS
into gpio_descs. Those are represented in _CRS as a pathname to a GPIO
device plus the pin's index number: this function is perfect for that
purpose.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/gpio/gpiolib-acpi.c | 3 ++-
include/linux/acpi.h | 5 +++++
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 6f11714ce023..4ae6fd33b783 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -111,7 +111,7 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
* controller does not have GPIO chip registered at the moment. This is to
* support probe deferral.
*/
-static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
+struct gpio_desc *acpi_get_gpiod(char *path, int pin)
{
struct gpio_chip *chip;
acpi_handle handle;
@@ -127,6 +127,7 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
return gpiochip_get_desc(chip, pin);
}
+EXPORT_SYMBOL_GPL(acpi_get_gpiod);
static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
{
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index fdb1d5262ce8..817f53506cfe 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -1080,6 +1080,7 @@ void __acpi_handle_debug(struct _ddebug *descriptor, acpi_handle handle, const c
bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
struct acpi_resource_gpio **agpio);
int acpi_dev_gpio_irq_get_by(struct acpi_device *adev, const char *name, int index);
+struct gpio_desc *acpi_get_gpiod(char *path, int pin);
#else
static inline bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
struct acpi_resource_gpio **agpio)
@@ -1091,6 +1092,10 @@ static inline int acpi_dev_gpio_irq_get_by(struct acpi_device *adev,
{
return -ENXIO;
}
+struct gpio_desc *acpi_get_gpiod(char *path, int pin)
+{
+ return NULL;
+}
#endif
static inline int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
--
2.32.0
From 7613e1bf2dc2f17f0e2c89a0aba74f7d446887c9 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sat, 12 Dec 2020 23:56:59 +0000
Subject: [PATCH] mfd: Remove tps68470 MFD driver
This driver only covered one scenario in which ACPI devices with _HID
INT3472 are found, and its functionality has been taken over by the
intel-skl-int3472 module, so remove it.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/acpi/pmic/Kconfig | 1 -
drivers/gpio/Kconfig | 1 -
drivers/mfd/Kconfig | 18 --------
drivers/mfd/Makefile | 1 -
drivers/mfd/tps68470.c | 97 ---------------------------------------
5 files changed, 118 deletions(-)
delete mode 100644 drivers/mfd/tps68470.c
diff --git a/drivers/acpi/pmic/Kconfig b/drivers/acpi/pmic/Kconfig
index 56bbcb2ce61b..e27d8ef3a32c 100644
--- a/drivers/acpi/pmic/Kconfig
+++ b/drivers/acpi/pmic/Kconfig
@@ -52,7 +52,6 @@ endif # PMIC_OPREGION
config TPS68470_PMIC_OPREGION
bool "ACPI operation region support for TPS68470 PMIC"
- depends on MFD_TPS68470
help
This config adds ACPI operation region support for TI TPS68470 PMIC.
TPS68470 device is an advanced power management unit that powers
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index d1300fc003ed..923768bf2719 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1321,7 +1321,6 @@ config GPIO_TPS65912
config GPIO_TPS68470
bool "TPS68470 GPIO"
- depends on MFD_TPS68470
help
Select this option to enable GPIO driver for the TPS68470
chip family.
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index b8847ae04d93..bd655a383cee 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1534,24 +1534,6 @@ config MFD_TPS65217
This driver can also be built as a module. If so, the module
will be called tps65217.
-config MFD_TPS68470
- bool "TI TPS68470 Power Management / LED chips"
- depends on ACPI && PCI && I2C=y
- depends on I2C_DESIGNWARE_PLATFORM=y
- select MFD_CORE
- select REGMAP_I2C
- help
- If you say yes here you get support for the TPS68470 series of
- Power Management / LED chips.
-
- These include voltage regulators, LEDs and other features
- that are often used in portable devices.
-
- This option is a bool as it provides an ACPI operation
- region, which must be available before any of the devices
- using this are probed. This option also configures the
- designware-i2c driver to be built-in, for the same reason.
-
config MFD_TI_LP873X
tristate "TI LP873X Power Management IC"
depends on I2C
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 1780019d2474..a23f38c4c38a 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -105,7 +105,6 @@ obj-$(CONFIG_MFD_TPS65910) += tps65910.o
obj-$(CONFIG_MFD_TPS65912) += tps65912-core.o
obj-$(CONFIG_MFD_TPS65912_I2C) += tps65912-i2c.o
obj-$(CONFIG_MFD_TPS65912_SPI) += tps65912-spi.o
-obj-$(CONFIG_MFD_TPS68470) += tps68470.o
obj-$(CONFIG_MFD_TPS80031) += tps80031.o
obj-$(CONFIG_MENELAUS) += menelaus.o
diff --git a/drivers/mfd/tps68470.c b/drivers/mfd/tps68470.c
deleted file mode 100644
index 4a4df4ffd18c..000000000000
--- a/drivers/mfd/tps68470.c
+++ /dev/null
@@ -1,97 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * TPS68470 chip Parent driver
- *
- * Copyright (C) 2017 Intel Corporation
- *
- * Authors:
- * Rajmohan Mani <rajmohan.mani@intel.com>
- * Tianshu Qiu <tian.shu.qiu@intel.com>
- * Jian Xu Zheng <jian.xu.zheng@intel.com>
- * Yuning Pu <yuning.pu@intel.com>
- */
-
-#include <linux/acpi.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/tps68470.h>
-#include <linux/regmap.h>
-
-static const struct mfd_cell tps68470s[] = {
- { .name = "tps68470-gpio" },
- { .name = "tps68470_pmic_opregion" },
-};
-
-static const struct regmap_config tps68470_regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
- .max_register = TPS68470_REG_MAX,
-};
-
-static int tps68470_chip_init(struct device *dev, struct regmap *regmap)
-{
- unsigned int version;
- int ret;
-
- /* Force software reset */
- ret = regmap_write(regmap, TPS68470_REG_RESET, TPS68470_REG_RESET_MASK);
- if (ret)
- return ret;
-
- ret = regmap_read(regmap, TPS68470_REG_REVID, &version);
- if (ret) {
- dev_err(dev, "Failed to read revision register: %d\n", ret);
- return ret;
- }
-
- dev_info(dev, "TPS68470 REVID: 0x%x\n", version);
-
- return 0;
-}
-
-static int tps68470_probe(struct i2c_client *client)
-{
- struct device *dev = &client->dev;
- struct regmap *regmap;
- int ret;
-
- regmap = devm_regmap_init_i2c(client, &tps68470_regmap_config);
- if (IS_ERR(regmap)) {
- dev_err(dev, "devm_regmap_init_i2c Error %ld\n",
- PTR_ERR(regmap));
- return PTR_ERR(regmap);
- }
-
- i2c_set_clientdata(client, regmap);
-
- ret = tps68470_chip_init(dev, regmap);
- if (ret < 0) {
- dev_err(dev, "TPS68470 Init Error %d\n", ret);
- return ret;
- }
-
- ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, tps68470s,
- ARRAY_SIZE(tps68470s), NULL, 0, NULL);
- if (ret < 0) {
- dev_err(dev, "devm_mfd_add_devices failed: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-static const struct acpi_device_id tps68470_acpi_ids[] = {
- {"INT3472"},
- {},
-};
-
-static struct i2c_driver tps68470_driver = {
- .driver = {
- .name = "tps68470",
- .acpi_match_table = tps68470_acpi_ids,
- },
- .probe_new = tps68470_probe,
-};
-builtin_i2c_driver(tps68470_driver);
--
2.32.0
From bc210192599430528bdd6536c37a8aecd9c23606 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Fri, 15 Jan 2021 12:37:31 +0000
Subject: [PATCH] platform: x86: Add intel_skl_int3472 driver
ACPI devices with _HID INT3472 are currently matched to the tps68470
driver, however this does not cover all situations in which that _HID
occurs. We've encountered three possibilities:
1. On Chrome OS devices, an ACPI device with _HID INT3472 (representing
a physical tps68470 device) that requires a GPIO and OpRegion driver
2. On devices designed for Windows, an ACPI device with _HID INT3472
(again representing a physical tps68470 device) which requires GPIO,
Clock and Regulator drivers.
3. On other devices designed for Windows, an ACPI device with _HID
INT3472 which does NOT represent a physical tps68470, and is instead
used as a dummy device to group some system GPIO lines which are meant
to be consumed by the sensor that is dependent on this entry.
This commit adds a new module, registering a platform driver to deal
with the 3rd scenario plus an i2c-driver to deal with #1 and #2, by
querying the CLDB buffer found against INT3472 entries to determine
which is most appropriate.
Suggested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
MAINTAINERS | 5 +
drivers/platform/x86/Kconfig | 25 +
drivers/platform/x86/Makefile | 5 +
.../platform/x86/intel_skl_int3472_common.c | 100 ++++
.../platform/x86/intel_skl_int3472_common.h | 99 ++++
.../platform/x86/intel_skl_int3472_discrete.c | 489 ++++++++++++++++++
.../platform/x86/intel_skl_int3472_tps68470.c | 145 ++++++
7 files changed, 868 insertions(+)
create mode 100644 drivers/platform/x86/intel_skl_int3472_common.c
create mode 100644 drivers/platform/x86/intel_skl_int3472_common.h
create mode 100644 drivers/platform/x86/intel_skl_int3472_discrete.c
create mode 100644 drivers/platform/x86/intel_skl_int3472_tps68470.c
diff --git a/MAINTAINERS b/MAINTAINERS
index f313ba49c2b8..7bec93adaae5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9045,6 +9045,11 @@ S: Maintained
F: arch/x86/include/asm/intel_scu_ipc.h
F: drivers/platform/x86/intel_scu_*
+INTEL SKL INT3472 ACPI DEVICE DRIVER
+M: Daniel Scally <djrscally@gmail.com>
+S: Maintained
+F: drivers/platform/x86/intel_skl_int3472_*
+
INTEL SPEED SELECT TECHNOLOGY
M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
L: platform-driver-x86@vger.kernel.org
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 533998040530..ab8324034c76 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -807,6 +807,31 @@ config INTEL_CHT_INT33FE
device and CONFIG_TYPEC_FUSB302=m and CONFIG_BATTERY_MAX17042=m
for Type-C device.
+config INTEL_SKL_INT3472
+ tristate "Intel SkyLake ACPI INT3472 Driver"
+ depends on X86 && ACPI
+ select REGMAP_I2C
+ help
+ This driver adds support for the INT3472 ACPI devices found on some
+ Intel SkyLake devices.
+
+ There are 3 kinds of INT3472 ACPI device possible; two for devices
+ designed for Windows (either with or without a physical tps68470
+ PMIC) and one designed for Chrome OS. This driver handles all three
+ situations by discovering information it needs to discern them at
+ runtime.
+
+ If your device was designed for Chrome OS, this driver will provide
+ an ACPI operation region, which must be available before any of the
+ devices using this are probed. For this reason, you should select Y
+ if your device was designed for ChromeOS. This option also configures
+ the designware-i2c driver to be built-in, for the same reason.
+
+ Say Y or M here if you have a SkyLake device designed for use
+ with Windows or ChromeOS. Say N here if you are not sure.
+
+ The module will be named "intel-skl-int3472"
+
config INTEL_HID_EVENT
tristate "INTEL HID Event"
depends on ACPI
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index f552cbfb7914..dd8fc06b224c 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -79,6 +79,11 @@ obj-$(CONFIG_INTEL_HID_EVENT) += intel-hid.o
obj-$(CONFIG_INTEL_INT0002_VGPIO) += intel_int0002_vgpio.o
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o
+obj-$(CONFIG_INTEL_SKL_INT3472) += intel_skl_int3472.o
+intel_skl_int3472-objs := intel_skl_int3472_common.o \
+ intel_skl_int3472_discrete.o \
+ intel_skl_int3472_tps68470.o
+
obj-$(CONFIG_INTEL_VBTN) += intel-vbtn.o
# Microsoft
diff --git a/drivers/platform/x86/intel_skl_int3472_common.c b/drivers/platform/x86/intel_skl_int3472_common.c
new file mode 100644
index 000000000000..08cb9d3c06aa
--- /dev/null
+++ b/drivers/platform/x86/intel_skl_int3472_common.c
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dan Scally <djrscally@gmail.com> */
+
+#include <linux/acpi.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+
+#include "intel_skl_int3472_common.h"
+
+int skl_int3472_get_cldb_buffer(struct acpi_device *adev,
+ struct int3472_cldb *cldb)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ acpi_handle handle = adev->handle;
+ union acpi_object *obj;
+ acpi_status status;
+ int ret = 0;
+
+ status = acpi_evaluate_object(handle, "CLDB", NULL, &buffer);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ obj = buffer.pointer;
+ if (!obj) {
+ dev_err(&adev->dev, "ACPI device has no CLDB object\n");
+ return -ENODEV;
+ }
+
+ if (obj->type != ACPI_TYPE_BUFFER) {
+ dev_err(&adev->dev, "CLDB object is not an ACPI buffer\n");
+ ret = -EINVAL;
+ goto out_free_buff;
+ }
+
+ if (obj->buffer.length > sizeof(*cldb)) {
+ dev_err(&adev->dev, "The CLDB buffer is too large\n");
+ ret = -EINVAL;
+ goto out_free_buff;
+ }
+
+ memcpy(cldb, obj->buffer.pointer, obj->buffer.length);
+
+out_free_buff:
+ kfree(buffer.pointer);
+ return ret;
+}
+
+static const struct acpi_device_id int3472_device_id[] = {
+ { "INT3472", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, int3472_device_id);
+
+static struct platform_driver int3472_discrete = {
+ .driver = {
+ .name = "int3472-discrete",
+ .acpi_match_table = int3472_device_id,
+ },
+ .probe = skl_int3472_discrete_probe,
+ .remove = skl_int3472_discrete_remove,
+};
+
+static struct i2c_driver int3472_tps68470 = {
+ .driver = {
+ .name = "int3472-tps68470",
+ .acpi_match_table = int3472_device_id,
+ },
+ .probe_new = skl_int3472_tps68470_probe,
+};
+
+static int skl_int3472_init(void)
+{
+ int ret = 0;
+
+ ret = platform_driver_register(&int3472_discrete);
+ if (ret)
+ return ret;
+
+ ret = i2c_register_driver(THIS_MODULE, &int3472_tps68470);
+ if (ret)
+ goto err_unregister_plat_drv;
+
+ return 0;
+
+err_unregister_plat_drv:
+ platform_driver_unregister(&int3472_discrete);
+ return ret;
+}
+module_init(skl_int3472_init);
+
+static void skl_int3472_exit(void)
+{
+ platform_driver_unregister(&int3472_discrete);
+ i2c_del_driver(&int3472_tps68470);
+}
+module_exit(skl_int3472_exit);
+
+MODULE_DESCRIPTION("Intel SkyLake INT3472 ACPI Device Driver");
+MODULE_AUTHOR("Daniel Scally <djrscally@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/intel_skl_int3472_common.h b/drivers/platform/x86/intel_skl_int3472_common.h
new file mode 100644
index 000000000000..4ac6bb2b223f
--- /dev/null
+++ b/drivers/platform/x86/intel_skl_int3472_common.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Author: Dan Scally <djrscally@gmail.com> */
+#include <linux/regulator/machine.h>
+#include <linux/clk-provider.h>
+#include <linux/gpio/machine.h>
+#include <linux/regulator/driver.h>
+#include <linux/types.h>
+
+/* PMIC GPIO Types */
+#define INT3472_GPIO_TYPE_RESET 0x00
+#define INT3472_GPIO_TYPE_POWERDOWN 0x01
+#define INT3472_GPIO_TYPE_CLK_ENABLE 0x0c
+#define INT3472_GPIO_TYPE_POWER_ENABLE 0x0b
+#define INT3472_GPIO_TYPE_PRIVACY_LED 0x0d
+#define INT3472_PDEV_MAX_NAME_LEN 23
+#define INT3472_MAX_SENSOR_GPIOS 3
+#define GPIO_REGULATOR_NAME_LENGTH 27
+#define GPIO_REGULATOR_SUPPLY_NAME_LENGTH 9
+
+#define INT3472_REGULATOR(_NAME, _SUPPLY, _OPS) \
+ (const struct regulator_desc) { \
+ .name = _NAME, \
+ .supply_name = _SUPPLY, \
+ .id = 0, \
+ .type = REGULATOR_VOLTAGE, \
+ .ops = _OPS, \
+ .owner = THIS_MODULE, \
+ }
+
+#define INT3472_GPIO_FUNCTION_REMAP(_PIN, _FUNCTION) \
+ (const struct int3472_gpio_function_remap) { \
+ .documented = _PIN, \
+ .actual = _FUNCTION \
+ }
+
+#define to_int3472_clk(hw) \
+ container_of(hw, struct int3472_gpio_clock, clk_hw)
+
+struct int3472_cldb {
+ u8 version;
+ /*
+ * control logic type
+ * 0: UNKNOWN
+ * 1: DISCRETE(CRD-D)
+ * 2: PMIC TPS68470
+ * 3: PMIC uP6641
+ */
+ u8 control_logic_type;
+ u8 control_logic_id;
+ u8 sensor_card_sku;
+ u8 reserved[28];
+};
+
+struct int3472_gpio_regulator {
+ char regulator_name[GPIO_REGULATOR_NAME_LENGTH];
+ char supply_name[GPIO_REGULATOR_SUPPLY_NAME_LENGTH];
+ struct gpio_desc *gpio;
+ struct regulator_dev *rdev;
+ struct regulator_desc rdesc;
+};
+
+struct int3472_gpio_clock {
+ struct clk *clk;
+ struct clk_hw clk_hw;
+ struct gpio_desc *gpio;
+};
+
+struct int3472_device {
+ struct acpi_device *adev;
+ struct platform_device *pdev;
+ struct acpi_device *sensor;
+ char *sensor_name;
+
+ unsigned int n_gpios; /* how many GPIOs have we seen */
+
+ struct int3472_gpio_regulator regulator;
+ struct int3472_gpio_clock clock;
+
+ unsigned int n_sensor_gpios; /* how many have we mapped to sensor */
+ bool gpios_mapped;
+ struct gpiod_lookup_table gpios;
+};
+
+struct int3472_gpio_function_remap {
+ char *documented;
+ char *actual;
+};
+
+struct int3472_sensor_config {
+ char *sensor_module_name;
+ struct regulator_consumer_supply supply_map;
+ const struct int3472_gpio_function_remap *function_maps;
+};
+
+int skl_int3472_discrete_probe(struct platform_device *pdev);
+int skl_int3472_discrete_remove(struct platform_device *pdev);
+int skl_int3472_tps68470_probe(struct i2c_client *client);
+int skl_int3472_get_cldb_buffer(struct acpi_device *adev,
+ struct int3472_cldb *cldb);
diff --git a/drivers/platform/x86/intel_skl_int3472_discrete.c b/drivers/platform/x86/intel_skl_int3472_discrete.c
new file mode 100644
index 000000000000..ea7e57f3e3f0
--- /dev/null
+++ b/drivers/platform/x86/intel_skl_int3472_discrete.c
@@ -0,0 +1,489 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dan Scally <djrscally@gmail.com> */
+
+#include <linux/acpi.h>
+#include <linux/clkdev.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+
+#include "intel_skl_int3472_common.h"
+
+/* 79234640-9e10-4fea-a5c1b5aa8b19756f */
+static const guid_t int3472_gpio_guid =
+ GUID_INIT(0x79234640, 0x9e10, 0x4fea,
+ 0xa5, 0xc1, 0xb5, 0xaa, 0x8b, 0x19, 0x75, 0x6f);
+
+/* 822ace8f-2814-4174-a56b5f029fe079ee */
+static const guid_t cio2_sensor_module_guid =
+ GUID_INIT(0x822ace8f, 0x2814, 0x4174,
+ 0xa5, 0x6b, 0x5f, 0x02, 0x9f, 0xe0, 0x79, 0xee);
+
+/*
+ * Here follows platform specific mapping information that we can pass to
+ * the functions mapping resources to the sensors. Where the sensors have
+ * a power enable pin defined in DSDT we need to provide a supply name so
+ * the sensor drivers can find the regulator. Optionally, we can provide a
+ * NULL terminated array of function name mappings to deal with any platform
+ * specific deviations from the documented behaviour of GPIOs.
+ *
+ * Map a GPIO function name to NULL to prevent the driver from mapping that
+ * GPIO at all.
+ */
+
+static const struct int3472_gpio_function_remap ov2680_gpio_function_remaps[] = {
+ INT3472_GPIO_FUNCTION_REMAP("reset", NULL),
+ INT3472_GPIO_FUNCTION_REMAP("powerdown", "reset"),
+ { }
+};
+
+static struct int3472_sensor_config int3472_sensor_configs[] = {
+ /* Lenovo Miix 510-12ISK - OV2680, Front */
+ { "GNDF140809R", { 0 }, ov2680_gpio_function_remaps},
+ /* Lenovo Miix 510-12ISK - OV5648, Rear */
+ { "GEFF150023R", REGULATOR_SUPPLY("avdd", "i2c-OVTI5648:00"), NULL},
+ /* Surface Go 1&2 - OV5693, Front */
+ { "YHCU", REGULATOR_SUPPLY("avdd", "i2c-INT33BE:00"), NULL},
+};
+
+/*
+ * The regulators have to have .ops to be valid, but the only ops we actually
+ * support are .enable and .disable which are handled via .ena_gpiod. Pass an
+ * empty struct to clear the check without lying about capabilities.
+ */
+static const struct regulator_ops int3472_gpio_regulator_ops = { 0 };
+
+static int skl_int3472_clk_enable(struct clk_hw *hw)
+{
+ struct int3472_gpio_clock *clk = to_int3472_clk(hw);
+
+ gpiod_set_value(clk->gpio, 1);
+
+ return 0;
+}
+
+static void skl_int3472_clk_disable(struct clk_hw *hw)
+{
+ struct int3472_gpio_clock *clk = to_int3472_clk(hw);
+
+ gpiod_set_value(clk->gpio, 0);
+}
+
+static int skl_int3472_clk_prepare(struct clk_hw *hw)
+{
+ /*
+ * We're just turning a GPIO on to enable, so nothing to do here, but
+ * we want to provide the op so prepare_enable() works.
+ */
+ return 0;
+}
+
+static void skl_int3472_clk_unprepare(struct clk_hw *hw)
+{
+ /* Likewise, nothing to do here... */
+}
+
+static const struct clk_ops skl_int3472_clock_ops = {
+ .prepare = skl_int3472_clk_prepare,
+ .unprepare = skl_int3472_clk_unprepare,
+ .enable = skl_int3472_clk_enable,
+ .disable = skl_int3472_clk_disable,
+};
+
+static struct int3472_sensor_config *
+int3472_get_sensor_module_config(struct int3472_device *int3472)
+{
+ unsigned int i = ARRAY_SIZE(int3472_sensor_configs);
+ struct int3472_sensor_config *ret;
+ union acpi_object *obj;
+
+ obj = acpi_evaluate_dsm_typed(int3472->sensor->handle,
+ &cio2_sensor_module_guid, 0x00,
+ 0x01, NULL, ACPI_TYPE_STRING);
+
+ if (!obj) {
+ dev_err(&int3472->pdev->dev,
+ "Failed to get sensor module string from _DSM\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ if (obj->string.type != ACPI_TYPE_STRING) {
+ dev_err(&int3472->pdev->dev,
+ "Sensor _DSM returned a non-string value\n");
+ ret = ERR_PTR(-EINVAL);
+ goto out_free_obj;
+ }
+
+ ret = ERR_PTR(-ENODEV);
+ while (i--) {
+ if (!strcmp(int3472_sensor_configs[i].sensor_module_name,
+ obj->string.pointer)) {
+ ret = &int3472_sensor_configs[i];
+ goto out_free_obj;
+ }
+ }
+
+out_free_obj:
+ ACPI_FREE(obj);
+ return ret;
+}
+
+static int int3472_map_gpio_to_sensor(struct int3472_device *int3472,
+ struct acpi_resource *ares,
+ char *func, u32 polarity)
+{
+ char *path = ares->data.gpio.resource_source.string_ptr;
+ struct int3472_sensor_config *sensor_config;
+ struct gpiod_lookup table_entry;
+ struct acpi_device *adev;
+ acpi_handle handle;
+ acpi_status status;
+ int ret;
+
+ sensor_config = int3472_get_sensor_module_config(int3472);
+ if (!IS_ERR(sensor_config) && sensor_config->function_maps) {
+ unsigned int i = 0;
+
+ while (sensor_config->function_maps[i].documented) {
+ if (!strcmp(func, sensor_config->function_maps[i].documented)) {
+ func = sensor_config->function_maps[i].actual;
+
+ break;
+ }
+
+ i++;
+ }
+ }
+
+ if (!func)
+ return 0;
+
+ if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) {
+ dev_warn(&int3472->pdev->dev, "Too many GPIOs mapped\n");
+ return -EINVAL;
+ }
+
+ status = acpi_get_handle(NULL, path, &handle);
+ if (ACPI_FAILURE(status))
+ return -EINVAL;
+
+ ret = acpi_bus_get_device(handle, &adev);
+ if (ret)
+ return -ENODEV;
+
+ table_entry = (struct gpiod_lookup)GPIO_LOOKUP_IDX(acpi_dev_name(adev),
+ ares->data.gpio.pin_table[0],
+ func, 0, polarity);
+
+ memcpy(&int3472->gpios.table[int3472->n_sensor_gpios], &table_entry,
+ sizeof(table_entry));
+
+ int3472->n_sensor_gpios++;
+
+ return 0;
+}
+
+static int int3472_register_clock(struct int3472_device *int3472,
+ struct acpi_resource *ares)
+{
+ char *path = ares->data.gpio.resource_source.string_ptr;
+ struct clk_init_data init = { };
+ int ret = 0;
+
+ init.name = kasprintf(GFP_KERNEL, "%s-clk", acpi_dev_name(int3472->adev));
+ init.ops = &skl_int3472_clock_ops;
+
+ int3472->clock.gpio = acpi_get_gpiod(path, ares->data.gpio.pin_table[0]);
+ if (IS_ERR(int3472->clock.gpio)) {
+ ret = PTR_ERR(int3472->clock.gpio);
+ goto out_free_init_name;
+ }
+
+ int3472->clock.clk_hw.init = &init;
+ int3472->clock.clk = clk_register(&int3472->adev->dev,
+ &int3472->clock.clk_hw);
+ if (IS_ERR(int3472->clock.clk)) {
+ ret = PTR_ERR(int3472->clock.clk);
+ goto err_put_gpio;
+ }
+
+ ret = clk_register_clkdev(int3472->clock.clk, "xvclk", int3472->sensor_name);
+ if (ret)
+ goto err_unregister_clk;
+
+ goto out_free_init_name;
+
+err_unregister_clk:
+ clk_unregister(int3472->clock.clk);
+err_put_gpio:
+ gpiod_put(int3472->clock.gpio);
+out_free_init_name:
+ kfree(init.name);
+
+ return ret;
+}
+
+static int int3472_register_regulator(struct int3472_device *int3472,
+ struct acpi_resource *ares)
+{
+ char *path = ares->data.gpio.resource_source.string_ptr;
+ struct int3472_sensor_config *sensor_config;
+ struct regulator_init_data init_data = { };
+ struct int3472_gpio_regulator *regulator;
+ struct regulator_config cfg = { };
+ int ret;
+
+ sensor_config = int3472_get_sensor_module_config(int3472);
+ if (IS_ERR_OR_NULL(sensor_config)) {
+ dev_err(&int3472->pdev->dev, "No sensor module config\n");
+ return PTR_ERR(sensor_config);
+ }
+
+ if (!sensor_config->supply_map.supply) {
+ dev_err(&int3472->pdev->dev, "No supply name defined\n");
+ return -ENODEV;
+ }
+
+ init_data.supply_regulator = NULL;
+ init_data.constraints.valid_ops_mask = REGULATOR_CHANGE_STATUS;
+ init_data.num_consumer_supplies = 1;
+ init_data.consumer_supplies = &sensor_config->supply_map;
+
+ snprintf(int3472->regulator.regulator_name, GPIO_REGULATOR_NAME_LENGTH,
+ "int3472-discrete-regulator");
+ snprintf(int3472->regulator.supply_name, GPIO_REGULATOR_SUPPLY_NAME_LENGTH,
+ "supply-0");
+
+ int3472->regulator.rdesc = INT3472_REGULATOR(int3472->regulator.regulator_name,
+ int3472->regulator.supply_name,
+ &int3472_gpio_regulator_ops);
+
+ int3472->regulator.gpio = acpi_get_gpiod(path, ares->data.gpio.pin_table[0]);
+ if (IS_ERR(int3472->regulator.gpio)) {
+ ret = PTR_ERR(int3472->regulator.gpio);
+ goto err_free_regulator;
+ }
+
+ cfg.dev = &int3472->adev->dev;
+ cfg.init_data = &init_data;
+ cfg.ena_gpiod = int3472->regulator.gpio;
+
+ int3472->regulator.rdev = regulator_register(&int3472->regulator.rdesc, &cfg);
+ if (IS_ERR(int3472->regulator.rdev)) {
+ ret = PTR_ERR(int3472->regulator.rdev);
+ goto err_free_gpio;
+ }
+
+ return 0;
+
+err_free_gpio:
+ gpiod_put(regulator->gpio);
+err_free_regulator:
+ kfree(regulator);
+
+ return ret;
+}
+
+/**
+ * int3472_handle_gpio_resources: maps PMIC resources to consuming sensor
+ * @ares: A pointer to a &struct acpi_resource
+ * @data: A pointer to a &struct int3472_device
+ *
+ * This function handles GPIO resources that are against an INT3472
+ * ACPI device, by checking the value of the corresponding _DSM entry.
+ * This will return a 32bit int, where the lowest byte represents the
+ * function of the GPIO pin:
+ *
+ * 0x00 Reset
+ * 0x01 Power down
+ * 0x0b Power enable
+ * 0x0c Clock enable
+ * 0x0d Privacy LED
+ *
+ * There are some known platform specific quirks where that does not quite
+ * hold up; for example where a pin with type 0x01 (Power down) is mapped to
+ * a sensor pin that performs a reset function. These will be handled by the
+ * mapping sub-functions.
+ *
+ * GPIOs will either be mapped directly to the sensor device or else used
+ * to create clocks and regulators via the usual frameworks.
+ *
+ * Return:
+ * * 0 - When all resources found are handled properly.
+ * * -EINVAL - If the resource is not a GPIO IO resource
+ * * -ENODEV - If the resource has no corresponding _DSM entry
+ * * -Other - Errors propagated from one of the sub-functions.
+ */
+static int int3472_handle_gpio_resources(struct acpi_resource *ares,
+ void *data)
+{
+ struct int3472_device *int3472 = data;
+ union acpi_object *obj;
+ int ret = 0;
+
+ if (ares->type != ACPI_RESOURCE_TYPE_GPIO ||
+ ares->data.gpio.connection_type != ACPI_RESOURCE_GPIO_TYPE_IO)
+ return EINVAL; /* Deliberately positive so parsing continues */
+
+ /*
+ * n_gpios + 2 because the index of this _DSM function is 1-based and
+ * the first function is just a count.
+ */
+ obj = acpi_evaluate_dsm_typed(int3472->adev->handle,
+ &int3472_gpio_guid, 0x00,
+ int3472->n_gpios + 2,
+ NULL, ACPI_TYPE_INTEGER);
+
+ if (!obj) {
+ dev_warn(&int3472->pdev->dev,
+ "No _DSM entry for this GPIO pin\n");
+ return ENODEV;
+ }
+
+ switch (obj->integer.value & 0xff) {
+ case INT3472_GPIO_TYPE_RESET:
+ ret = int3472_map_gpio_to_sensor(int3472, ares, "reset",
+ GPIO_ACTIVE_LOW);
+ if (ret)
+ dev_err(&int3472->pdev->dev,
+ "Failed to map reset pin to sensor\n");
+
+ break;
+ case INT3472_GPIO_TYPE_POWERDOWN:
+ ret = int3472_map_gpio_to_sensor(int3472, ares, "powerdown",
+ GPIO_ACTIVE_LOW);
+ if (ret)
+ dev_err(&int3472->pdev->dev,
+ "Failed to map powerdown pin to sensor\n");
+
+ break;
+ case INT3472_GPIO_TYPE_CLK_ENABLE:
+ ret = int3472_register_clock(int3472, ares);
+ if (ret)
+ dev_err(&int3472->pdev->dev,
+ "Failed to map clock to sensor\n");
+
+ break;
+ case INT3472_GPIO_TYPE_POWER_ENABLE:
+ ret = int3472_register_regulator(int3472, ares);
+ if (ret) {
+ dev_err(&int3472->pdev->dev,
+ "Failed to map regulator to sensor\n");
+ }
+
+ break;
+ case INT3472_GPIO_TYPE_PRIVACY_LED:
+ ret = int3472_map_gpio_to_sensor(int3472, ares, "indicator-led",
+ GPIO_ACTIVE_HIGH);
+ if (ret)
+ dev_err(&int3472->pdev->dev,
+ "Failed to map indicator led to sensor\n");
+
+ break;
+ default:
+ dev_warn(&int3472->pdev->dev,
+ "GPIO type 0x%llx unknown; the sensor may not work\n",
+ (obj->integer.value & 0xff));
+ ret = EINVAL;
+ }
+
+ int3472->n_gpios++;
+ ACPI_FREE(obj);
+
+ return ret;
+}
+
+static int int3472_parse_crs(struct int3472_device *int3472)
+{
+ struct list_head resource_list;
+ int ret = 0;
+
+ INIT_LIST_HEAD(&resource_list);
+
+ ret = acpi_dev_get_resources(int3472->adev, &resource_list,
+ int3472_handle_gpio_resources, int3472);
+
+ if (!ret) {
+ gpiod_add_lookup_table(&int3472->gpios);
+ int3472->gpios_mapped = true;
+ }
+
+ acpi_dev_free_resource_list(&resource_list);
+
+ return ret;
+}
+
+int skl_int3472_discrete_probe(struct platform_device *pdev)
+{
+ struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
+ struct int3472_device *int3472;
+ struct int3472_cldb cldb;
+ int ret = 0;
+
+ ret = skl_int3472_get_cldb_buffer(adev, &cldb);
+ if (ret || cldb.control_logic_type != 1)
+ return -EINVAL;
+
+ int3472 = kzalloc(sizeof(*int3472) +
+ ((INT3472_MAX_SENSOR_GPIOS + 1) * sizeof(struct gpiod_lookup)),
+ GFP_KERNEL);
+ if (!int3472)
+ return -ENOMEM;
+
+ int3472->adev = adev;
+ int3472->pdev = pdev;
+ platform_set_drvdata(pdev, int3472);
+
+ int3472->sensor = acpi_dev_get_next_dep_dev(adev, NULL);
+ if (!int3472->sensor) {
+ dev_err(&pdev->dev,
+ "This INT3472 entry seems to have no dependents.\n");
+ ret = -ENODEV;
+ goto err_free_int3472;
+ }
+ int3472->sensor_name = i2c_acpi_dev_name(int3472->sensor);
+ int3472->gpios.dev_id = int3472->sensor_name;
+
+ ret = int3472_parse_crs(int3472);
+ if (ret) {
+ skl_int3472_discrete_remove(pdev);
+ goto err_return_ret;
+ }
+
+ return 0;
+
+err_free_int3472:
+ kfree(int3472);
+err_return_ret:
+ return ret;
+}
+
+int skl_int3472_discrete_remove(struct platform_device *pdev)
+{
+ struct int3472_device *int3472;
+
+ int3472 = platform_get_drvdata(pdev);
+
+ if (int3472->gpios_mapped)
+ gpiod_remove_lookup_table(&int3472->gpios);
+
+ if (!IS_ERR_OR_NULL(int3472->regulator.rdev)) {
+ gpiod_put(int3472->regulator.gpio);
+ regulator_unregister(int3472->regulator.rdev);
+ }
+
+ if (!IS_ERR_OR_NULL(int3472->clock.clk)) {
+ gpiod_put(int3472->clock.gpio);
+ clk_unregister(int3472->clock.clk);
+ }
+
+ acpi_dev_put(int3472->sensor);
+
+ kfree(int3472->sensor_name);
+ kfree(int3472);
+
+ return 0;
+}
diff --git a/drivers/platform/x86/intel_skl_int3472_tps68470.c b/drivers/platform/x86/intel_skl_int3472_tps68470.c
new file mode 100644
index 000000000000..3fe27ec0caff
--- /dev/null
+++ b/drivers/platform/x86/intel_skl_int3472_tps68470.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dan Scally <djrscally@gmail.com> */
+
+#include <linux/i2c.h>
+#include <linux/mfd/tps68470.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "intel_skl_int3472_common.h"
+
+static const struct regmap_config tps68470_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = TPS68470_REG_MAX,
+};
+
+static int tps68470_chip_init(struct device *dev, struct regmap *regmap)
+{
+ unsigned int version;
+ int ret;
+
+ /* Force software reset */
+ ret = regmap_write(regmap, TPS68470_REG_RESET, TPS68470_REG_RESET_MASK);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(regmap, TPS68470_REG_REVID, &version);
+ if (ret) {
+ dev_err(dev, "Failed to read revision register: %d\n", ret);
+ return ret;
+ }
+
+ dev_info(dev, "TPS68470 REVID: 0x%x\n", version);
+
+ return 0;
+}
+
+static struct platform_device *
+skl_int3472_register_pdev(const char *name, struct device *parent)
+{
+ struct platform_device *pdev;
+ int ret;
+
+ pdev = platform_device_alloc(name, PLATFORM_DEVID_NONE);
+ if (IS_ERR_OR_NULL(pdev))
+ return ERR_PTR(-ENOMEM);
+
+ pdev->dev.parent = parent;
+ pdev->driver_override = kstrndup(pdev->name, INT3472_PDEV_MAX_NAME_LEN,
+ GFP_KERNEL);
+
+ ret = platform_device_add(pdev);
+ if (ret) {
+ platform_device_put(pdev);
+ return ERR_PTR(ret);
+ }
+
+ return pdev;
+}
+
+int skl_int3472_tps68470_probe(struct i2c_client *client)
+{
+ struct acpi_device *adev = ACPI_COMPANION(&client->dev);
+ struct platform_device *regulator_dev;
+ struct platform_device *opregion_dev;
+ struct platform_device *gpio_dev;
+ struct int3472_cldb cldb = { 0 };
+ struct platform_device *clk_dev;
+ bool cldb_present = true;
+ struct regmap *regmap;
+ int ret = 0;
+
+ regmap = devm_regmap_init_i2c(client, &tps68470_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&client->dev, "devm_regmap_init_i2c Error %ld\n",
+ PTR_ERR(regmap));
+ return PTR_ERR(regmap);
+ }
+
+ i2c_set_clientdata(client, regmap);
+
+ ret = tps68470_chip_init(&client->dev, regmap);
+ if (ret < 0) {
+ dev_err(&client->dev, "TPS68470 Init Error %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * Check CLDB buffer against the PMIC's adev. If present, then we check
+ * the value of control_logic_type field and follow one of the following
+ * scenarios:
+ *
+ * 1. No CLDB - likely ACPI tables designed for ChromeOS. We create
+ * platform devices for the GPIOs and OpRegion drivers.
+ *
+ * 2. CLDB, with control_logic_type = 2 - probably ACPI tables made
+ * for Windows 2-in-1 platforms. Register pdevs for GPIO, Clock and
+ * Regulator drivers to bind to.
+ *
+ * 3. Any other value in control_logic_type, we should never have
+ * gotten to this point; crash and burn.
+ */
+ ret = skl_int3472_get_cldb_buffer(adev, &cldb);
+ if (!ret && cldb.control_logic_type != 2)
+ return -EINVAL;
+
+ if (ret)
+ cldb_present = false;
+
+ gpio_dev = skl_int3472_register_pdev("tps68470-gpio", &client->dev);
+ if (IS_ERR(gpio_dev))
+ return PTR_ERR(gpio_dev);
+
+ if (cldb_present) {
+ clk_dev = skl_int3472_register_pdev("tps68470-clk",
+ &client->dev);
+ if (IS_ERR(clk_dev)) {
+ ret = PTR_ERR(clk_dev);
+ goto err_free_gpio;
+ }
+
+ regulator_dev = skl_int3472_register_pdev("tps68470-regulator",
+ &client->dev);
+ if (IS_ERR(regulator_dev)) {
+ ret = PTR_ERR(regulator_dev);
+ goto err_free_clk;
+ }
+ } else {
+ opregion_dev = skl_int3472_register_pdev("tps68470_pmic_opregion",
+ &client->dev);
+ if (IS_ERR(opregion_dev)) {
+ ret = PTR_ERR(opregion_dev);
+ goto err_free_gpio;
+ }
+ }
+
+ return 0;
+
+err_free_clk:
+ platform_device_put(clk_dev);
+err_free_gpio:
+ platform_device_put(gpio_dev);
+
+ return ret;
+}
--
2.32.0
From 9d6eb2f23ba20945bc6ecc571704c08ed3405d8e Mon Sep 17 00:00:00 2001
From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
Date: Fri, 11 Dec 2020 21:17:35 +0100
Subject: [PATCH] PCI: ACPI: Fix up ACPI companion lookup for device 0 on the
root bus
In some cases acpi_pci_find_companion() returns an incorrect device
object as the ACPI companion for device 0 on the root bus (bus 0).
On the affected systems that device is the PCI interface to the
host bridge and the "ACPI companion" returned for it corresponds
to a non-PCI device located in the SoC (e.g. a sensor on an I2C
bus). As a result of this, the ACPI device object "attached"
to PCI device 00:00.0 cannot be used for enumerating the device
that is really represented by it which (of course) is problematic.
Address that issue by preventing acpi_pci_find_companion() from
returning a device object with a valid _HID (which by the spec
should not be present uder ACPI device objects corresponding to
PCI devices) for PCI device 00:00.0.
Link: https://lore.kernel.org/linux-acpi/1409ba0c-1580-dc09-e6fe-a0c9bcda6462@gmail.com/
Reported-by: Daniel Scally <djrscally@gmail.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Patchset: cameras
---
drivers/pci/pci-acpi.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 745a4e0c4994..87e45a800919 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -1162,14 +1162,32 @@ void acpi_pci_remove_bus(struct pci_bus *bus)
static struct acpi_device *acpi_pci_find_companion(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
+ struct acpi_device *adev;
bool check_children;
u64 addr;
check_children = pci_is_bridge(pci_dev);
/* Please ref to ACPI spec for the syntax of _ADR */
addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn);
- return acpi_find_child_device(ACPI_COMPANION(dev->parent), addr,
+ adev = acpi_find_child_device(ACPI_COMPANION(dev->parent), addr,
check_children);
+ /*
+ * There may be ACPI device objects in the ACPI namespace that are
+ * children of the device object representing the host bridge, but don't
+ * represent PCI devices. Both _HID and _ADR may be present for them,
+ * even though that is against the specification (for example, see
+ * Section 6.1 of ACPI 6.3), but in many cases the _ADR returns 0 which
+ * appears to indicate that they should not be taken into consideration
+ * as potential companions of PCI devices on the root bus.
+ *
+ * To catch this special case, disregard the returned device object if
+ * it has a valid _HID, addr is 0 and the PCI device at hand is on the
+ * root bus.
+ */
+ if (adev && adev->pnp.type.platform_id && !addr && !pci_dev->bus->parent)
+ return NULL;
+
+ return adev;
}
/**
--
2.32.0
From 83da61098870cb0b7c69c12081e33a33c8db9d09 Mon Sep 17 00:00:00 2001
From: Jake Day <jake@ninebysix.com>
Date: Fri, 25 Sep 2020 10:24:53 -0400
Subject: [PATCH] media: i2c: Add support for the OV5693 image sensor
The OV5693 is a 5 Mpx CMOS image sensor, connected via MIPI CSI-2
in a one or two lane configuration.
Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@gmail.com>
Patchset: cameras
---
drivers/media/i2c/Kconfig | 11 +
drivers/media/i2c/Makefile | 1 +
drivers/media/i2c/ad5823.h | 63 ++
drivers/media/i2c/ov5693.c | 1788 ++++++++++++++++++++++++++++++++++++
drivers/media/i2c/ov5693.h | 1430 ++++++++++++++++++++++++++++
5 files changed, 3293 insertions(+)
create mode 100644 drivers/media/i2c/ad5823.h
create mode 100644 drivers/media/i2c/ov5693.c
create mode 100644 drivers/media/i2c/ov5693.h
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 878f66ef2719..10bbc85d0aba 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -958,6 +958,17 @@ config VIDEO_OV5675
To compile this driver as a module, choose M here: the
module will be called ov5675.
+config VIDEO_OV5693
+ tristate "OmniVision OV5693 sensor support"
+ depends on I2C && VIDEO_V4L2
+ select V4L2_FWNODE
+ help
+ This is a Video4Linux2 sensor driver for the OmniVision
+ OV5693 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ov5693.
+
config VIDEO_OV5695
tristate "OmniVision OV5695 sensor support"
depends on I2C && VIDEO_V4L2
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index f0a77473979d..2bc1dd3e791b 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -73,6 +73,7 @@ obj-$(CONFIG_VIDEO_OV5645) += ov5645.o
obj-$(CONFIG_VIDEO_OV5647) += ov5647.o
obj-$(CONFIG_VIDEO_OV5670) += ov5670.o
obj-$(CONFIG_VIDEO_OV5675) += ov5675.o
+obj-$(CONFIG_VIDEO_OV5693) += ov5693.o
obj-$(CONFIG_VIDEO_OV5695) += ov5695.o
obj-$(CONFIG_VIDEO_OV6650) += ov6650.o
obj-$(CONFIG_VIDEO_OV7251) += ov7251.o
diff --git a/drivers/media/i2c/ad5823.h b/drivers/media/i2c/ad5823.h
new file mode 100644
index 000000000000..f1362cd69f6e
--- /dev/null
+++ b/drivers/media/i2c/ad5823.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Support for AD5823 VCM.
+ *
+ * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ */
+
+#ifndef __AD5823_H__
+#define __AD5823_H__
+
+#include <linux/types.h>
+
+#define AD5823_VCM_ADDR 0x0c
+
+#define AD5823_REG_RESET 0x01
+#define AD5823_REG_MODE 0x02
+#define AD5823_REG_VCM_MOVE_TIME 0x03
+#define AD5823_REG_VCM_CODE_MSB 0x04
+#define AD5823_REG_VCM_CODE_LSB 0x05
+#define AD5823_REG_VCM_THRESHOLD_MSB 0x06
+#define AD5823_REG_VCM_THRESHOLD_LSB 0x07
+
+#define AD5823_REG_LENGTH 0x1
+
+#define AD5823_RING_CTRL_ENABLE 0x04
+#define AD5823_RING_CTRL_DISABLE 0x00
+
+#define AD5823_RESONANCE_PERIOD 100000
+#define AD5823_RESONANCE_COEF 512
+#define AD5823_HIGH_FREQ_RANGE 0x80
+
+#define VCM_CODE_MSB_MASK 0xfc
+#define AD5823_INIT_FOCUS_POS 350
+
+enum ad5823_tok_type {
+ AD5823_8BIT = 0x1,
+ AD5823_16BIT = 0x2,
+};
+
+enum ad5823_vcm_mode {
+ AD5823_ARC_RES0 = 0x0, /* Actuator response control RES1 */
+ AD5823_ARC_RES1 = 0x1, /* Actuator response control RES0.5 */
+ AD5823_ARC_RES2 = 0x2, /* Actuator response control RES2 */
+ AD5823_ESRC = 0x3, /* Enhanced slew rate control */
+ AD5823_DIRECT = 0x4, /* Direct control */
+};
+
+#define AD5823_INVALID_CONFIG 0xffffffff
+#define AD5823_MAX_FOCUS_POS 1023
+#define DELAY_PER_STEP_NS 1000000
+#define DELAY_MAX_PER_STEP_NS (1000000 * 1023)
+#endif
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
new file mode 100644
index 000000000000..32485e4ed42b
--- /dev/null
+++ b/drivers/media/i2c/ov5693.c
@@ -0,0 +1,1788 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Support for OmniVision OV5693 1080p HD camera sensor.
+ *
+ * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/moduleparam.h>
+#include <media/v4l2-device.h>
+#include <linux/io.h>
+#include <linux/acpi.h>
+#include <linux/regulator/consumer.h>
+
+#include "ov5693.h"
+#include "ad5823.h"
+
+#define __cci_delay(t) \
+ do { \
+ if ((t) < 10) { \
+ usleep_range((t) * 1000, ((t) + 1) * 1000); \
+ } else { \
+ msleep((t)); \
+ } \
+ } while (0)
+
+/* Value 30ms reached through experimentation on byt ecs.
+ * The DS specifies a much lower value but when using a smaller value
+ * the I2C bus sometimes locks up permanently when starting the camera.
+ * This issue could not be reproduced on cht, so we can reduce the
+ * delay value to a lower value when insmod.
+ */
+static uint up_delay = 30;
+module_param(up_delay, uint, 0644);
+MODULE_PARM_DESC(up_delay,
+ "Delay prior to the first CCI transaction for ov5693");
+
+
+/* Exposure/gain */
+
+#define OV5693_EXPOSURE_CTRL_HH_REG 0x3500
+#define OV5693_EXPOSURE_CTRL_HH(v) (((v) & GENMASK(18, 16)) >> 16)
+#define OV5693_EXPOSURE_CTRL_H_REG 0x3501
+#define OV5693_EXPOSURE_CTRL_H(v) (((v) & GENMASK(15, 8)) >> 8)
+#define OV5693_EXPOSURE_CTRL_L_REG 0x3502
+#define OV5693_EXPOSURE_CTRL_L(v) ((v) & GENMASK(7, 0))
+#define OV5693_EXPOSURE_GAIN_MANUAL_REG 0x3509
+
+#define OV5693_GAIN_CTRL_H_REG 0x3504
+#define OV5693_GAIN_CTRL_H(v) (((v) & GENMASK(9, 8)) >> 8)
+#define OV5693_GAIN_CTRL_L_REG 0x3505
+#define OV5693_GAIN_CTRL_L(v) ((v) & GENMASK(7, 0))
+
+#define OV5693_FORMAT1_REG 0x3820
+#define OV5693_FORMAT1_FLIP_VERT_ISP_EN BIT(2)
+#define OV5693_FORMAT1_FLIP_VERT_SENSOR_EN BIT(1)
+#define OV5693_FORMAT2_REG 0x3821
+#define OV5693_FORMAT2_HSYNC_EN BIT(6)
+#define OV5693_FORMAT2_FST_VBIN_EN BIT(5)
+#define OV5693_FORMAT2_FST_HBIN_EN BIT(4)
+#define OV5693_FORMAT2_ISP_HORZ_VAR2_EN BIT(3)
+#define OV5693_FORMAT2_FLIP_HORZ_ISP_EN BIT(2)
+#define OV5693_FORMAT2_FLIP_HORZ_SENSOR_EN BIT(1)
+#define OV5693_FORMAT2_SYNC_HBIN_EN BIT(0)
+
+/* ISP */
+
+#define OV5693_ISP_CTRL0_REG 0x5000
+#define OV5693_ISP_CTRL0_LENC_EN BIT(7)
+#define OV5693_ISP_CTRL0_WHITE_BALANCE_EN BIT(4)
+#define OV5693_ISP_CTRL0_DPC_BLACK_EN BIT(2)
+#define OV5693_ISP_CTRL0_DPC_WHITE_EN BIT(1)
+#define OV5693_ISP_CTRL1_REG 0x5001
+#define OV5693_ISP_CTRL1_BLC_EN BIT(0)
+
+/* native and active pixel array size. */
+#define OV5693_NATIVE_WIDTH 2688U
+#define OV5693_NATIVE_HEIGHT 1984U
+#define OV5693_PIXEL_ARRAY_LEFT 48U
+#define OV5693_PIXEL_ARRAY_TOP 20U
+#define OV5693_PIXEL_ARRAY_WIDTH 2592U
+#define OV5693_PIXEL_ARRAY_HEIGHT 1944U
+
+#define OV5693_PPL_DEFAULT 2800
+
+static int vcm_ad_i2c_wr8(struct i2c_client *client, u8 reg, u8 val)
+{
+ int err;
+ struct i2c_msg msg;
+ u8 buf[2];
+
+ buf[0] = reg;
+ buf[1] = val;
+
+ msg.addr = VCM_ADDR;
+ msg.flags = 0;
+ msg.len = 2;
+ msg.buf = &buf[0];
+
+ err = i2c_transfer(client->adapter, &msg, 1);
+ if (err != 1) {
+ dev_err(&client->dev, "%s: vcm i2c fail, err code = %d\n",
+ __func__, err);
+ return -EIO;
+ }
+ return 0;
+}
+
+static int ad5823_i2c_write(struct i2c_client *client, u8 reg, u8 val)
+{
+ struct i2c_msg msg;
+ u8 buf[2];
+
+ buf[0] = reg;
+ buf[1] = val;
+ msg.addr = AD5823_VCM_ADDR;
+ msg.flags = 0;
+ msg.len = 0x02;
+ msg.buf = &buf[0];
+
+ if (i2c_transfer(client->adapter, &msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+static int ad5823_i2c_read(struct i2c_client *client, u8 reg, u8 *val)
+{
+ struct i2c_msg msg[2];
+ u8 buf[2];
+
+ buf[0] = reg;
+ buf[1] = 0;
+
+ msg[0].addr = AD5823_VCM_ADDR;
+ msg[0].flags = 0;
+ msg[0].len = 0x01;
+ msg[0].buf = &buf[0];
+
+ msg[1].addr = 0x0c;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 0x01;
+ msg[1].buf = &buf[1];
+ *val = 0;
+ if (i2c_transfer(client->adapter, msg, 2) != 2)
+ return -EIO;
+ *val = buf[1];
+ return 0;
+}
+
+static const u32 ov5693_embedded_effective_size = 28;
+
+/* i2c read/write stuff */
+static int ov5693_read_reg(struct i2c_client *client,
+ u16 data_length, u16 reg, u16 *val)
+{
+ int err;
+ struct i2c_msg msg[2];
+ unsigned char data[6];
+
+ if (!client->adapter) {
+ dev_err(&client->dev, "%s error, no client->adapter\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ if (data_length != OV5693_8BIT && data_length != OV5693_16BIT
+ && data_length != OV5693_32BIT) {
+ dev_err(&client->dev, "%s error, invalid data length\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ memset(msg, 0, sizeof(msg));
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = I2C_MSG_LENGTH;
+ msg[0].buf = data;
+
+ /* high byte goes out first */
+ data[0] = (u8)(reg >> 8);
+ data[1] = (u8)(reg & 0xff);
+
+ msg[1].addr = client->addr;
+ msg[1].len = data_length;
+ msg[1].flags = I2C_M_RD;
+ msg[1].buf = data;
+
+ err = i2c_transfer(client->adapter, msg, 2);
+ if (err != 2) {
+ if (err >= 0)
+ err = -EIO;
+ dev_err(&client->dev,
+ "read from offset 0x%x error %d", reg, err);
+ return err;
+ }
+
+ *val = 0;
+ /* high byte comes first */
+ if (data_length == OV5693_8BIT)
+ *val = (u8)data[0];
+ else if (data_length == OV5693_16BIT)
+ *val = be16_to_cpu(*(__be16 *)&data[0]);
+ else
+ *val = be32_to_cpu(*(__be32 *)&data[0]);
+
+ return 0;
+}
+
+static int ov5693_i2c_write(struct i2c_client *client, u16 len, u8 *data)
+{
+ struct i2c_msg msg;
+ const int num_msg = 1;
+ int ret;
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = len;
+ msg.buf = data;
+ ret = i2c_transfer(client->adapter, &msg, 1);
+
+ return ret == num_msg ? 0 : -EIO;
+}
+
+static int vcm_dw_i2c_write(struct i2c_client *client, u16 data)
+{
+ struct i2c_msg msg;
+ const int num_msg = 1;
+ int ret;
+ __be16 val;
+
+ val = cpu_to_be16(data);
+ msg.addr = VCM_ADDR;
+ msg.flags = 0;
+ msg.len = OV5693_16BIT;
+ msg.buf = (void *)&val;
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+
+ return ret == num_msg ? 0 : -EIO;
+}
+
+/*
+ * Theory: per datasheet, the two VCMs both allow for a 2-byte read.
+ * The DW9714 doesn't actually specify what this does (it has a
+ * two-byte write-only protocol, but specifies the read sequence as
+ * legal), but it returns the same data (zeroes) always, after an
+ * undocumented initial NAK. The AD5823 has a one-byte address
+ * register to which all writes go, and subsequent reads will cycle
+ * through the 8 bytes of registers. Notably, the default values (the
+ * device is always power-cycled affirmatively, so we can rely on
+ * these) in AD5823 are not pairwise repetitions of the same 16 bit
+ * word. So all we have to do is sequentially read two bytes at a
+ * time and see if we detect a difference in any of the first four
+ * pairs.
+ */
+static int vcm_detect(struct i2c_client *client)
+{
+ int i, ret;
+ struct i2c_msg msg;
+ u16 data0 = 0, data;
+
+ for (i = 0; i < 4; i++) {
+ msg.addr = VCM_ADDR;
+ msg.flags = I2C_M_RD;
+ msg.len = sizeof(data);
+ msg.buf = (u8 *)&data;
+ ret = i2c_transfer(client->adapter, &msg, 1);
+
+ /*
+ * DW9714 always fails the first read and returns
+ * zeroes for subsequent ones
+ */
+ if (i == 0 && ret == -EREMOTEIO) {
+ data0 = 0;
+ continue;
+ }
+
+ if (i == 0)
+ data0 = data;
+
+ if (data != data0)
+ return VCM_AD5823;
+ }
+ return ret == 1 ? VCM_DW9714 : ret;
+}
+
+static int ov5693_write_reg(struct i2c_client *client, u16 data_length,
+ u16 reg, u16 val)
+{
+ int ret;
+ unsigned char data[4] = {0};
+ __be16 *wreg = (void *)data;
+ const u16 len = data_length + sizeof(u16); /* 16-bit address + data */
+
+ if (data_length != OV5693_8BIT && data_length != OV5693_16BIT) {
+ dev_err(&client->dev,
+ "%s error, invalid data_length\n", __func__);
+ return -EINVAL;
+ }
+
+ /* high byte goes out first */
+ *wreg = cpu_to_be16(reg);
+
+ if (data_length == OV5693_8BIT) {
+ data[2] = (u8)(val);
+ } else {
+ /* OV5693_16BIT */
+ __be16 *wdata = (void *)&data[2];
+
+ *wdata = cpu_to_be16(val);
+ }
+
+ ret = ov5693_i2c_write(client, len, data);
+ if (ret)
+ dev_err(&client->dev,
+ "write error: wrote 0x%x to offset 0x%x error %d",
+ val, reg, ret);
+
+ return ret;
+}
+
+/*
+ * ov5693_write_reg_array - Initializes a list of OV5693 registers
+ * @client: i2c driver client structure
+ * @reglist: list of registers to be written
+ *
+ * This function initializes a list of registers. When consecutive addresses
+ * are found in a row on the list, this function creates a buffer and sends
+ * consecutive data in a single i2c_transfer().
+ *
+ * __ov5693_flush_reg_array, __ov5693_buf_reg_array() and
+ * __ov5693_write_reg_is_consecutive() are internal functions to
+ * ov5693_write_reg_array_fast() and should be not used anywhere else.
+ *
+ */
+
+static int __ov5693_flush_reg_array(struct i2c_client *client,
+ struct ov5693_write_ctrl *ctrl)
+{
+ u16 size;
+ __be16 *reg = (void *)&ctrl->buffer.addr;
+
+ if (ctrl->index == 0)
+ return 0;
+
+ size = sizeof(u16) + ctrl->index; /* 16-bit address + data */
+
+ *reg = cpu_to_be16(ctrl->buffer.addr);
+ ctrl->index = 0;
+
+ return ov5693_i2c_write(client, size, (u8 *)reg);
+}
+
+static int __ov5693_buf_reg_array(struct i2c_client *client,
+ struct ov5693_write_ctrl *ctrl,
+ const struct ov5693_reg *next)
+{
+ int size;
+ __be16 *data16;
+
+ switch (next->type) {
+ case OV5693_8BIT:
+ size = 1;
+ ctrl->buffer.data[ctrl->index] = (u8)next->val;
+ break;
+ case OV5693_16BIT:
+ size = 2;
+
+ data16 = (void *)&ctrl->buffer.data[ctrl->index];
+ *data16 = cpu_to_be16((u16)next->val);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* When first item is added, we need to store its starting address */
+ if (ctrl->index == 0)
+ ctrl->buffer.addr = next->reg;
+
+ ctrl->index += size;
+
+ /*
+ * Buffer cannot guarantee free space for u32? Better flush it to avoid
+ * possible lack of memory for next item.
+ */
+ if (ctrl->index + sizeof(u16) >= OV5693_MAX_WRITE_BUF_SIZE)
+ return __ov5693_flush_reg_array(client, ctrl);
+
+ return 0;
+}
+
+static int __ov5693_write_reg_is_consecutive(struct i2c_client *client,
+ struct ov5693_write_ctrl *ctrl,
+ const struct ov5693_reg *next)
+{
+ if (ctrl->index == 0)
+ return 1;
+
+ return ctrl->buffer.addr + ctrl->index == next->reg;
+}
+
+static int ov5693_write_reg_array(struct i2c_client *client,
+ const struct ov5693_reg *reglist)
+{
+ const struct ov5693_reg *next = reglist;
+ struct ov5693_write_ctrl ctrl;
+ int err;
+
+ ctrl.index = 0;
+ for (; next->type != OV5693_TOK_TERM; next++) {
+ switch (next->type & OV5693_TOK_MASK) {
+ case OV5693_TOK_DELAY:
+ err = __ov5693_flush_reg_array(client, &ctrl);
+ if (err)
+ return err;
+ msleep(next->val);
+ break;
+ default:
+ /*
+ * If next address is not consecutive, data needs to be
+ * flushed before proceed.
+ */
+ if (!__ov5693_write_reg_is_consecutive(client, &ctrl,
+ next)) {
+ err = __ov5693_flush_reg_array(client, &ctrl);
+ if (err)
+ return err;
+ }
+ err = __ov5693_buf_reg_array(client, &ctrl, next);
+ if (err) {
+ dev_err(&client->dev,
+ "%s: write error, aborted\n",
+ __func__);
+ return err;
+ }
+ break;
+ }
+ }
+
+ return __ov5693_flush_reg_array(client, &ctrl);
+}
+
+static int ov5693_read_otp_reg_array(struct i2c_client *client, u16 size,
+ u16 addr, u8 *buf)
+{
+ u16 index;
+ int ret;
+ u16 *pVal = NULL;
+
+ for (index = 0; index <= size; index++) {
+ pVal = (u16 *)(buf + index);
+ ret =
+ ov5693_read_reg(client, OV5693_8BIT, addr + index,
+ pVal);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __ov5693_otp_read(struct v4l2_subdev *sd, u8 *buf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ int ret;
+ int i;
+ u8 *b = buf;
+
+ dev->otp_size = 0;
+ for (i = 1; i < OV5693_OTP_BANK_MAX; i++) {
+ /*set bank NO and OTP read mode. */
+ ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_OTP_BANK_REG,
+ (i | 0xc0)); //[7:6] 2'b11 [5:0] bank no
+ if (ret) {
+ dev_err(&client->dev, "failed to prepare OTP page\n");
+ return ret;
+ }
+ //dev_dbg(&client->dev, "write 0x%x->0x%x\n",OV5693_OTP_BANK_REG,(i|0xc0));
+
+ /*enable read */
+ ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_OTP_READ_REG,
+ OV5693_OTP_MODE_READ); // enable :1
+ if (ret) {
+ dev_err(&client->dev,
+ "failed to set OTP reading mode page");
+ return ret;
+ }
+ //dev_dbg(&client->dev, "write 0x%x->0x%x\n",
+ // OV5693_OTP_READ_REG,OV5693_OTP_MODE_READ);
+
+ /* Reading the OTP data array */
+ ret = ov5693_read_otp_reg_array(client, OV5693_OTP_BANK_SIZE,
+ OV5693_OTP_START_ADDR,
+ b);
+ if (ret) {
+ dev_err(&client->dev, "failed to read OTP data\n");
+ return ret;
+ }
+
+ //dev_dbg(&client->dev,
+ // "BANK[%2d] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ // i, *b, *(b+1), *(b+2), *(b+3), *(b+4), *(b+5), *(b+6), *(b+7),
+ // *(b+8), *(b+9), *(b+10), *(b+11), *(b+12), *(b+13), *(b+14), *(b+15));
+
+ //Intel OTP map, try to read 320byts first.
+ if (i == 21) {
+ if ((*b) == 0) {
+ dev->otp_size = 320;
+ break;
+ }
+ /* (*b) != 0 */
+ b = buf;
+ continue;
+ } else if (i ==
+ 24) { //if the first 320bytes data doesn't not exist, try to read the next 32bytes data.
+ if ((*b) == 0) {
+ dev->otp_size = 32;
+ break;
+ }
+ /* (*b) != 0 */
+ b = buf;
+ continue;
+ } else if (i ==
+ 27) { //if the prvious 32bytes data doesn't exist, try to read the next 32bytes data again.
+ if ((*b) == 0) {
+ dev->otp_size = 32;
+ break;
+ }
+ /* (*b) != 0 */
+ dev->otp_size = 0; // no OTP data.
+ break;
+ }
+
+ b = b + OV5693_OTP_BANK_SIZE;
+ }
+ return 0;
+}
+
+/*
+ * Read otp data and store it into a kmalloced buffer.
+ * The caller must kfree the buffer when no more needed.
+ * @size: set to the size of the returned otp data.
+ */
+static void *ov5693_otp_read(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 *buf;
+ int ret;
+
+ buf = devm_kzalloc(&client->dev, (OV5693_OTP_DATA_SIZE + 16), GFP_KERNEL);
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+
+ //otp valid after mipi on and sw stream on
+ ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_FRAME_OFF_NUM, 0x00);
+
+ ret = ov5693_write_reg(client, OV5693_8BIT,
+ OV5693_SW_STREAM, OV5693_START_STREAMING);
+
+ ret = __ov5693_otp_read(sd, buf);
+
+ //mipi off and sw stream off after otp read
+ ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_FRAME_OFF_NUM, 0x0f);
+
+ ret = ov5693_write_reg(client, OV5693_8BIT,
+ OV5693_SW_STREAM, OV5693_STOP_STREAMING);
+
+ /* Driver has failed to find valid data */
+ if (ret) {
+ dev_err(&client->dev, "sensor found no valid OTP data\n");
+ return ERR_PTR(ret);
+ }
+
+ return buf;
+}
+
+static int ov5693_update_bits(struct ov5693_device *sensor, u16 address,
+ u16 mask, u16 bits)
+{
+ u16 value = 0;
+ int ret;
+
+ ret = ov5693_read_reg(sensor->i2c_client, OV5693_8BIT, address, &value);
+ if (ret)
+ return ret;
+
+ value &= ~mask;
+ value |= bits;
+
+ ret = ov5693_write_reg(sensor->i2c_client, OV5693_8BIT, address, value);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+/* Flip */
+
+static int ov5693_flip_vert_configure(struct ov5693_device *sensor, bool enable)
+{
+ u8 bits = OV5693_FORMAT1_FLIP_VERT_ISP_EN |
+ OV5693_FORMAT1_FLIP_VERT_SENSOR_EN;
+ int ret;
+
+ ret = ov5693_update_bits(sensor, OV5693_FORMAT1_REG, bits,
+ enable ? bits : 0);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int ov5693_flip_horz_configure(struct ov5693_device *sensor, bool enable)
+{
+ u8 bits = OV5693_FORMAT2_FLIP_HORZ_ISP_EN |
+ OV5693_FORMAT2_FLIP_HORZ_SENSOR_EN;
+ int ret;
+
+ ret = ov5693_update_bits(sensor, OV5693_FORMAT2_REG, bits,
+ enable ? bits : 0);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+/*
+ * This returns the exposure time being used. This should only be used
+ * for filling in EXIF data, not for actual image processing.
+ */
+static int ov5693_q_exposure(struct v4l2_subdev *sd, s32 *value)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u16 reg_v, reg_v2;
+ int ret;
+
+ /* get exposure */
+ ret = ov5693_read_reg(client, OV5693_8BIT,
+ OV5693_EXPOSURE_L,
+ &reg_v);
+ if (ret)
+ goto err;
+
+ ret = ov5693_read_reg(client, OV5693_8BIT,
+ OV5693_EXPOSURE_M,
+ &reg_v2);
+ if (ret)
+ goto err;
+
+ reg_v += reg_v2 << 8;
+ ret = ov5693_read_reg(client, OV5693_8BIT,
+ OV5693_EXPOSURE_H,
+ &reg_v2);
+ if (ret)
+ goto err;
+
+ *value = reg_v + (((u32)reg_v2 << 16));
+err:
+ return ret;
+}
+
+static int ad5823_t_focus_vcm(struct v4l2_subdev *sd, u16 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = -EINVAL;
+ u8 vcm_code;
+
+ ret = ad5823_i2c_read(client, AD5823_REG_VCM_CODE_MSB, &vcm_code);
+ if (ret)
+ return ret;
+
+ /* set reg VCM_CODE_MSB Bit[1:0] */
+ vcm_code = (vcm_code & VCM_CODE_MSB_MASK) |
+ ((val >> 8) & ~VCM_CODE_MSB_MASK);
+ ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB, vcm_code);
+ if (ret)
+ return ret;
+
+ /* set reg VCM_CODE_LSB Bit[7:0] */
+ ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_LSB, (val & 0xff));
+ if (ret)
+ return ret;
+
+ /* set required vcm move time */
+ vcm_code = AD5823_RESONANCE_PERIOD / AD5823_RESONANCE_COEF
+ - AD5823_HIGH_FREQ_RANGE;
+ ret = ad5823_i2c_write(client, AD5823_REG_VCM_MOVE_TIME, vcm_code);
+
+ return ret;
+}
+
+static int ad5823_t_focus_abs(struct v4l2_subdev *sd, s32 value)
+{
+ value = min(value, AD5823_MAX_FOCUS_POS);
+ return ad5823_t_focus_vcm(sd, value);
+}
+
+static int ov5693_t_focus_abs(struct v4l2_subdev *sd, s32 value)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+
+ dev_dbg(&client->dev, "%s: FOCUS_POS: 0x%x\n", __func__, value);
+ value = clamp(value, 0, OV5693_VCM_MAX_FOCUS_POS);
+ if (dev->vcm == VCM_DW9714) {
+ if (dev->vcm_update) {
+ ret = vcm_dw_i2c_write(client, VCM_PROTECTION_OFF);
+ if (ret)
+ return ret;
+ ret = vcm_dw_i2c_write(client, DIRECT_VCM);
+ if (ret)
+ return ret;
+ ret = vcm_dw_i2c_write(client, VCM_PROTECTION_ON);
+ if (ret)
+ return ret;
+ dev->vcm_update = false;
+ }
+ ret = vcm_dw_i2c_write(client,
+ vcm_val(value, VCM_DEFAULT_S));
+ } else if (dev->vcm == VCM_AD5823) {
+ ad5823_t_focus_abs(sd, value);
+ }
+ if (ret == 0) {
+ dev->number_of_steps = value - dev->focus;
+ dev->focus = value;
+ dev->timestamp_t_focus_abs = ktime_get();
+ } else
+ dev_err(&client->dev,
+ "%s: i2c failed. ret %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int ov5693_t_focus_rel(struct v4l2_subdev *sd, s32 value)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+
+ return ov5693_t_focus_abs(sd, dev->focus + value);
+}
+
+#define DELAY_PER_STEP_NS 1000000
+#define DELAY_MAX_PER_STEP_NS (1000000 * 1023)
+
+/* Exposure */
+
+static int ov5693_get_exposure(struct ov5693_device *sensor)
+{
+ u16 reg_v, reg_v2;
+ int ret = 0;
+
+ /* get exposure */
+ ret = ov5693_read_reg(sensor->i2c_client, OV5693_8BIT,
+ OV5693_EXPOSURE_L,
+ &reg_v);
+ if (ret)
+ return ret;
+
+ ret = ov5693_read_reg(sensor->i2c_client, OV5693_8BIT,
+ OV5693_EXPOSURE_M,
+ &reg_v2);
+ if (ret)
+ return ret;
+
+ reg_v += reg_v2 << 8;
+ ret = ov5693_read_reg(sensor->i2c_client, OV5693_8BIT,
+ OV5693_EXPOSURE_H,
+ &reg_v2);
+ if (ret)
+ return ret;
+
+ printk("exposure set to: %u\n", reg_v + (((u32)reg_v2 << 16)));
+ return ret;
+}
+
+static int ov5693_exposure_configure(struct ov5693_device *sensor, u32 exposure)
+{
+ int ret;
+
+ ov5693_get_exposure(sensor);
+ ret = ov5693_write_reg(sensor->i2c_client, OV5693_8BIT,
+ OV5693_EXPOSURE_CTRL_HH_REG, OV5693_EXPOSURE_CTRL_HH(exposure));
+ if (ret)
+ return ret;
+
+ ret = ov5693_write_reg(sensor->i2c_client, OV5693_8BIT,
+ OV5693_EXPOSURE_CTRL_H_REG, OV5693_EXPOSURE_CTRL_H(exposure));
+ if (ret)
+ return ret;
+
+ ret = ov5693_write_reg(sensor->i2c_client, OV5693_8BIT,
+ OV5693_EXPOSURE_CTRL_L_REG, OV5693_EXPOSURE_CTRL_L(exposure));
+ if (ret)
+ return ret;
+ ov5693_get_exposure(sensor);
+
+ return 0;
+}
+
+/* Gain */
+
+static int ov5693_get_gain(struct ov5693_device *sensor, u32 *gain)
+{
+ u16 gain_l, gain_h;
+ int ret = 0;
+
+ ret = ov5693_read_reg(sensor->i2c_client, OV5693_8BIT,
+ OV5693_GAIN_CTRL_L_REG,
+ &gain_l);
+ if (ret)
+ return ret;
+
+ ret = ov5693_read_reg(sensor->i2c_client, OV5693_8BIT,
+ OV5693_GAIN_CTRL_H_REG,
+ &gain_h);
+ if (ret)
+ return ret;
+
+ *gain = (u32)(((gain_h >> 8) & 0x03) |
+ (gain_l & 0xff));
+
+ return ret;
+}
+static int ov5693_gain_configure(struct ov5693_device *sensor, u32 gain)
+{
+ int ret;
+
+ /* A 1.0 gain is 0x400 */
+ gain = (gain * 1024)/1000;
+
+ ret = ov5693_write_reg(sensor->i2c_client, OV5693_16BIT,
+ OV5693_MWB_RED_GAIN_H, gain);
+ if (ret) {
+ dev_err(&sensor->i2c_client->dev, "%s: write %x error, aborted\n",
+ __func__, OV5693_MWB_RED_GAIN_H);
+ return ret;
+ }
+
+ ret = ov5693_write_reg(sensor->i2c_client, OV5693_16BIT,
+ OV5693_MWB_GREEN_GAIN_H, gain);
+ if (ret) {
+ dev_err(&sensor->i2c_client->dev, "%s: write %x error, aborted\n",
+ __func__, OV5693_MWB_RED_GAIN_H);
+ return ret;
+ }
+
+ ret = ov5693_write_reg(sensor->i2c_client, OV5693_16BIT,
+ OV5693_MWB_BLUE_GAIN_H, gain);
+ if (ret) {
+ dev_err(&sensor->i2c_client->dev, "%s: write %x error, aborted\n",
+ __func__, OV5693_MWB_RED_GAIN_H);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ov5693_analog_gain_configure(struct ov5693_device *sensor, u32 gain)
+{
+ int ret;
+
+ /* Analog gain */
+ ret = ov5693_write_reg(sensor->i2c_client, OV5693_8BIT,
+ OV5693_AGC_L, gain & 0xff);
+ if (ret) {
+ dev_err(&sensor->i2c_client->dev, "%s: write %x error, aborted\n",
+ __func__, OV5693_AGC_L);
+ return ret;
+ }
+
+ ret = ov5693_write_reg(sensor->i2c_client, OV5693_8BIT,
+ OV5693_AGC_H, (gain >> 8) & 0xff);
+ if (ret) {
+ dev_err(&sensor->i2c_client->dev, "%s: write %x error, aborted\n",
+ __func__, OV5693_AGC_H);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ov5693_device *dev =
+ container_of(ctrl->handler, struct ov5693_device, ctrl_handler);
+ struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
+ int ret = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_FOCUS_ABSOLUTE:
+ dev_dbg(&client->dev, "%s: CID_FOCUS_ABSOLUTE:%d.\n",
+ __func__, ctrl->val);
+ ret = ov5693_t_focus_abs(&dev->sd, ctrl->val);
+ break;
+ case V4L2_CID_FOCUS_RELATIVE:
+ dev_dbg(&client->dev, "%s: CID_FOCUS_RELATIVE:%d.\n",
+ __func__, ctrl->val);
+ ret = ov5693_t_focus_rel(&dev->sd, ctrl->val);
+ break;
+ case V4L2_CID_EXPOSURE:
+ dev_dbg(&client->dev, "%s: CID_EXPOSURE:%d.\n",
+ __func__, ctrl->val);
+ ret = ov5693_exposure_configure(dev, ctrl->val);
+ if (ret)
+ return ret;
+ break;
+ case V4L2_CID_ANALOGUE_GAIN:
+ dev_dbg(&client->dev, "%s: CID_ANALOGUE_GAIN:%d.\n",
+ __func__, ctrl->val);
+ ret = ov5693_analog_gain_configure(dev, ctrl->val);
+ if (ret)
+ return ret;
+ break;
+ case V4L2_CID_DIGITAL_GAIN:
+ dev_dbg(&client->dev, "%s: CID_DIGITAL_GAIN:%d.\n",
+ __func__, ctrl->val);
+ ret = ov5693_gain_configure(dev, ctrl->val);
+ if (ret)
+ return ret;
+ break;
+ case V4L2_CID_HFLIP:
+ return ov5693_flip_horz_configure(dev, !!ctrl->val);
+ case V4L2_CID_VFLIP:
+ return ov5693_flip_vert_configure(dev, !!ctrl->val);
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int ov5693_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ov5693_device *dev =
+ container_of(ctrl->handler, struct ov5693_device, ctrl_handler);
+ int ret = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE_ABSOLUTE:
+ ret = ov5693_q_exposure(&dev->sd, &ctrl->val);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ ret = ov5693_get_gain(dev, &ctrl->val);
+ break;
+ case V4L2_CID_FOCUS_ABSOLUTE:
+ /* NOTE: there was atomisp-specific function ov5693_q_focus_abs() */
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops ov5693_ctrl_ops = {
+ .s_ctrl = ov5693_s_ctrl,
+ .g_volatile_ctrl = ov5693_g_volatile_ctrl
+};
+
+static const struct v4l2_ctrl_config ov5693_controls[] = {
+ {
+ .ops = &ov5693_ctrl_ops,
+ .id = V4L2_CID_FOCUS_ABSOLUTE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "focus move absolute",
+ .min = 0,
+ .max = OV5693_VCM_MAX_FOCUS_POS,
+ .step = 1,
+ .def = 0,
+ .flags = 0,
+ },
+ {
+ .ops = &ov5693_ctrl_ops,
+ .id = V4L2_CID_FOCUS_RELATIVE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "focus move relative",
+ .min = OV5693_VCM_MAX_FOCUS_NEG,
+ .max = OV5693_VCM_MAX_FOCUS_POS,
+ .step = 1,
+ .def = 0,
+ .flags = 0,
+ },
+};
+
+static int ov5693_isp_configure(struct ov5693_device *sensor)
+{
+ int ret;
+
+ /* Enable lens correction. */
+ ret = ov5693_write_reg(sensor->i2c_client, OV5693_8BIT,
+ OV5693_ISP_CTRL0_REG, 0x86);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int ov5693_init(struct v4l2_subdev *sd)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ if (!dev->has_vcm)
+ return 0;
+
+ dev_info(&client->dev, "%s\n", __func__);
+ mutex_lock(&dev->input_lock);
+ dev->vcm_update = false;
+
+ if (dev->vcm == VCM_AD5823) {
+ ret = vcm_ad_i2c_wr8(client, 0x01, 0x01); /* vcm init test */
+ if (ret)
+ dev_err(&client->dev,
+ "vcm reset failed\n");
+ /*change the mode*/
+ ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB,
+ AD5823_RING_CTRL_ENABLE);
+ if (ret)
+ dev_err(&client->dev,
+ "vcm enable ringing failed\n");
+ ret = ad5823_i2c_write(client, AD5823_REG_MODE,
+ AD5823_ARC_RES1);
+ if (ret)
+ dev_err(&client->dev,
+ "vcm change mode failed\n");
+ }
+
+ /*change initial focus value for ad5823*/
+ if (dev->vcm == VCM_AD5823) {
+ dev->focus = AD5823_INIT_FOCUS_POS;
+ ov5693_t_focus_abs(sd, AD5823_INIT_FOCUS_POS);
+ } else {
+ dev->focus = 0;
+ ov5693_t_focus_abs(sd, 0);
+ }
+
+ ov5693_isp_configure(dev);
+ mutex_unlock(&dev->input_lock);
+
+ return 0;
+}
+
+static int __power_up(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5693_device *sensor = to_ov5693_sensor(sd);
+ int ret;
+
+ ret = clk_prepare_enable(sensor->clk);
+ if (ret) {
+ dev_err(&client->dev, "Error enabling clock\n");
+ return -EINVAL;
+ }
+
+ if (sensor->indicator_led)
+ gpiod_set_value_cansleep(sensor->indicator_led, 1);
+
+ ret = regulator_bulk_enable(OV5693_NUM_SUPPLIES,
+ sensor->supplies);
+ if (ret)
+ goto fail_power;
+
+ __cci_delay(up_delay);
+
+ return 0;
+
+fail_power:
+ if (sensor->indicator_led)
+ gpiod_set_value_cansleep(sensor->indicator_led, 0);
+ dev_err(&client->dev, "sensor power-up failed\n");
+
+ return ret;
+}
+
+static int power_down(struct v4l2_subdev *sd)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+
+ dev->focus = OV5693_INVALID_CONFIG;
+
+ clk_disable_unprepare(dev->clk);
+
+ if (dev->indicator_led)
+ gpiod_set_value_cansleep(dev->indicator_led, 0);
+ return regulator_bulk_disable(OV5693_NUM_SUPPLIES, dev->supplies);
+}
+
+static int power_up(struct v4l2_subdev *sd)
+{
+ static const int retry_count = 4;
+ int i, ret;
+
+ for (i = 0; i < retry_count; i++) {
+ ret = __power_up(sd);
+ if (!ret)
+ return 0;
+
+ power_down(sd);
+ }
+ return ret;
+}
+
+static int ov5693_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ dev_info(&client->dev, "%s: on %d\n", __func__, on);
+
+ if (on == 0)
+ return power_down(sd);
+
+ /* on == 1 */
+ ret = power_up(sd);
+ if (!ret) {
+ ret = ov5693_init(sd);
+ /* restore settings */
+ ov5693_res = ov5693_res_video;
+ N_RES = N_RES_VIDEO;
+ }
+
+ return ret;
+}
+
+/*
+ * distance - calculate the distance
+ * @res: resolution
+ * @w: width
+ * @h: height
+ *
+ * Get the gap between res_w/res_h and w/h.
+ * distance = (res_w/res_h - w/h) / (w/h) * 8192
+ * res->width/height smaller than w/h wouldn't be considered.
+ * The gap of ratio larger than 1/8 wouldn't be considered.
+ * Returns the value of gap or -1 if fail.
+ */
+#define LARGEST_ALLOWED_RATIO_MISMATCH 1024
+static int distance(struct ov5693_resolution *res, u32 w, u32 h)
+{
+ int ratio;
+ int distance;
+
+ if (w == 0 || h == 0 ||
+ res->width < w || res->height < h)
+ return -1;
+
+ ratio = res->width << 13;
+ ratio /= w;
+ ratio *= h;
+ ratio /= res->height;
+
+ distance = abs(ratio - 8192);
+
+ if (distance > LARGEST_ALLOWED_RATIO_MISMATCH)
+ return -1;
+
+ return distance;
+}
+
+/* Return the nearest higher resolution index
+ * Firstly try to find the approximate aspect ratio resolution
+ * If we find multiple same AR resolutions, choose the
+ * minimal size.
+ */
+static int nearest_resolution_index(int w, int h)
+{
+ int i;
+ int idx = -1;
+ int dist;
+ int min_dist = INT_MAX;
+ int min_res_w = INT_MAX;
+ struct ov5693_resolution *tmp_res = NULL;
+
+ for (i = 0; i < N_RES; i++) {
+ tmp_res = &ov5693_res[i];
+ dist = distance(tmp_res, w, h);
+ if (dist == -1)
+ continue;
+ if (dist < min_dist) {
+ min_dist = dist;
+ idx = i;
+ min_res_w = ov5693_res[i].width;
+ continue;
+ }
+ if (dist == min_dist && ov5693_res[i].width < min_res_w)
+ idx = i;
+ }
+
+ return idx;
+}
+
+static int get_resolution_index(int w, int h)
+{
+ int i;
+
+ for (i = 0; i < N_RES; i++) {
+ if (w != ov5693_res[i].width)
+ continue;
+ if (h != ov5693_res[i].height)
+ continue;
+
+ return i;
+ }
+
+ return -1;
+}
+
+/* TODO: remove it. */
+static int startup(struct v4l2_subdev *sd)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+
+ ret = ov5693_write_reg(client, OV5693_8BIT,
+ OV5693_SW_RESET, 0x01);
+ if (ret) {
+ dev_err(&client->dev, "ov5693 reset err.\n");
+ return ret;
+ }
+
+ ret = ov5693_write_reg_array(client, ov5693_global_setting);
+ if (ret) {
+ dev_err(&client->dev, "ov5693 write register err.\n");
+ return ret;
+ }
+
+ ret = ov5693_write_reg_array(client, ov5693_res[dev->fmt_idx].regs);
+ if (ret) {
+ dev_err(&client->dev, "ov5693 write register err.\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int ov5693_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct v4l2_mbus_framefmt *fmt = &format->format;
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+ int idx;
+ int cnt;
+
+ if (format->pad)
+ return -EINVAL;
+ if (!fmt)
+ return -EINVAL;
+
+ mutex_lock(&dev->input_lock);
+ idx = nearest_resolution_index(fmt->width, fmt->height);
+ if (idx == -1) {
+ /* return the largest resolution */
+ fmt->width = ov5693_res[N_RES - 1].width;
+ fmt->height = ov5693_res[N_RES - 1].height;
+ } else {
+ fmt->width = ov5693_res[idx].width;
+ fmt->height = ov5693_res[idx].height;
+ }
+
+ fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+ cfg->try_fmt = *fmt;
+ ret = 0;
+ goto mutex_unlock;
+ }
+
+ dev->fmt_idx = get_resolution_index(fmt->width, fmt->height);
+ if (dev->fmt_idx == -1) {
+ dev_err(&client->dev, "get resolution fail\n");
+ ret = -EINVAL;
+ goto mutex_unlock;
+ }
+
+ for (cnt = 0; cnt < OV5693_POWER_UP_RETRY_NUM; cnt++) {
+ ret = power_up(sd);
+ if (ret) {
+ dev_err(&client->dev, "power up failed\n");
+ continue;
+ }
+
+ mutex_unlock(&dev->input_lock);
+ ov5693_init(sd);
+ mutex_lock(&dev->input_lock);
+ ret = startup(sd);
+ if (ret)
+ dev_err(&client->dev, " startup() FAILED!\n");
+ else
+ break;
+ }
+ if (cnt == OV5693_POWER_UP_RETRY_NUM) {
+ dev_err(&client->dev, "power up failed, gave up\n");
+ goto mutex_unlock;
+ }
+
+
+
+ /*
+ * After sensor settings are set to HW, sometimes stream is started.
+ * This would cause ISP timeout because ISP is not ready to receive
+ * data yet. So add stop streaming here.
+ */
+ ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM,
+ OV5693_STOP_STREAMING);
+ if (ret)
+ dev_warn(&client->dev, "ov5693 stream off err\n");
+
+mutex_unlock:
+ mutex_unlock(&dev->input_lock);
+ return ret;
+}
+
+static const struct v4l2_rect *
+__ov5693_get_pad_crop(struct ov5693_device *dev, struct v4l2_subdev_pad_config *cfg,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_crop(&dev->sd, cfg, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &dev->mode->crop;
+ }
+
+ return NULL;
+}
+static int ov5693_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
+{
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP: {
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+
+ mutex_lock(&dev->input_lock);
+ sel->r = *__ov5693_get_pad_crop(dev, cfg, sel->pad,
+ sel->which);
+ mutex_unlock(&dev->input_lock);
+
+ return 0;
+ }
+
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = OV5693_NATIVE_WIDTH;
+ sel->r.height = OV5693_NATIVE_HEIGHT;
+
+ return 0;
+
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ sel->r.top = OV5693_PIXEL_ARRAY_TOP;
+ sel->r.left = OV5693_PIXEL_ARRAY_LEFT;
+ sel->r.width = OV5693_PIXEL_ARRAY_WIDTH;
+ sel->r.height = OV5693_PIXEL_ARRAY_HEIGHT;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int ov5693_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct v4l2_mbus_framefmt *fmt = &format->format;
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+
+ if (format->pad)
+ return -EINVAL;
+
+ if (!fmt)
+ return -EINVAL;
+
+ fmt->width = ov5693_res[dev->fmt_idx].width;
+ fmt->height = ov5693_res[dev->fmt_idx].height;
+ fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+
+ return 0;
+}
+
+static int ov5693_detect(struct i2c_client *client)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ u16 high, low;
+ int ret;
+ u16 id;
+ u8 revision;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+ return -ENODEV;
+
+ ret = ov5693_read_reg(client, OV5693_8BIT,
+ OV5693_SC_CMMN_CHIP_ID_H, &high);
+ if (ret) {
+ dev_err(&client->dev, "sensor_id_high = 0x%x\n", high);
+ return -ENODEV;
+ }
+ ret = ov5693_read_reg(client, OV5693_8BIT,
+ OV5693_SC_CMMN_CHIP_ID_L, &low);
+ id = ((((u16)high) << 8) | (u16)low);
+
+ if (id != OV5693_ID) {
+ dev_err(&client->dev, "sensor ID error 0x%x\n", id);
+ return -ENODEV;
+ }
+
+ ret = ov5693_read_reg(client, OV5693_8BIT,
+ OV5693_SC_CMMN_SUB_ID, &high);
+ revision = (u8)high & 0x0f;
+
+ dev_info(&client->dev, "sensor_revision = 0x%x\n", revision);
+ dev_info(&client->dev, "sensor_address = 0x%02x\n", client->addr);
+ dev_info(&client->dev, "detect ov5693 success\n");
+ return 0;
+}
+
+static int ov5693_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ mutex_lock(&dev->input_lock);
+
+ /* power_on() here before streaming for regular PCs. */
+ if (enable) {
+ ret = power_up(sd);
+ if (ret) {
+ dev_err(&client->dev, "sensor power-up error\n");
+ goto out;
+ }
+ }
+
+ ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM,
+ enable ? OV5693_START_STREAMING :
+ OV5693_STOP_STREAMING);
+
+ /* power_off() here after streaming for regular PCs. */
+ if (!enable)
+ power_down(sd);
+
+out:
+ mutex_unlock(&dev->input_lock);
+
+ return ret;
+}
+
+static int ov5693_s_config(struct v4l2_subdev *sd, int irq)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+
+ mutex_lock(&dev->input_lock);
+ ret = power_up(sd);
+ if (ret) {
+ dev_err(&client->dev, "ov5693 power-up err.\n");
+ goto fail_power_on;
+ }
+
+ if (!dev->vcm)
+ dev->vcm = vcm_detect(client);
+
+ /* config & detect sensor */
+ ret = ov5693_detect(client);
+ if (ret) {
+ dev_err(&client->dev, "ov5693_detect err s_config.\n");
+ goto fail_power_on;
+ }
+
+ dev->otp_data = ov5693_otp_read(sd);
+
+ /* turn off sensor, after probed */
+ ret = power_down(sd);
+ if (ret) {
+ dev_err(&client->dev, "ov5693 power-off err.\n");
+ goto fail_power_on;
+ }
+ mutex_unlock(&dev->input_lock);
+
+ return ret;
+
+fail_power_on:
+ power_down(sd);
+ dev_err(&client->dev, "sensor power-gating failed\n");
+ mutex_unlock(&dev->input_lock);
+ return ret;
+}
+
+static int ov5693_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *interval)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+
+ interval->interval.numerator = 1;
+ interval->interval.denominator = ov5693_res[dev->fmt_idx].fps;
+
+ return 0;
+}
+
+static int ov5693_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index >= MAX_FMTS)
+ return -EINVAL;
+
+ code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+ return 0;
+}
+
+static int ov5693_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ int index = fse->index;
+
+ if (index >= N_RES)
+ return -EINVAL;
+
+ fse->min_width = ov5693_res[index].width;
+ fse->min_height = ov5693_res[index].height;
+ fse->max_width = ov5693_res[index].width;
+ fse->max_height = ov5693_res[index].height;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops ov5693_video_ops = {
+ .s_stream = ov5693_s_stream,
+ .g_frame_interval = ov5693_g_frame_interval,
+};
+
+static const struct v4l2_subdev_core_ops ov5693_core_ops = {
+ .s_power = ov5693_s_power,
+};
+
+static const struct v4l2_subdev_pad_ops ov5693_pad_ops = {
+ .enum_mbus_code = ov5693_enum_mbus_code,
+ .enum_frame_size = ov5693_enum_frame_size,
+ .get_fmt = ov5693_get_fmt,
+ .set_fmt = ov5693_set_fmt,
+ .get_selection = ov5693_get_selection,
+};
+
+static const struct v4l2_subdev_ops ov5693_ops = {
+ .core = &ov5693_core_ops,
+ .video = &ov5693_video_ops,
+ .pad = &ov5693_pad_ops,
+};
+
+static int ov5693_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
+ unsigned int i = OV5693_NUM_SUPPLIES;
+
+ dev_info(&client->dev, "%s...\n", __func__);
+
+ gpiod_put(ov5693->reset);
+ gpiod_put(ov5693->indicator_led);
+ while (i--)
+ regulator_put(ov5693->supplies[i].consumer);
+
+ v4l2_async_unregister_subdev(sd);
+
+ media_entity_cleanup(&ov5693->sd.entity);
+ v4l2_ctrl_handler_free(&ov5693->ctrl_handler);
+ kfree(ov5693);
+
+ return 0;
+}
+
+static int ov5693_init_controls(struct ov5693_device *ov5693)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov5693->sd);
+ const struct v4l2_ctrl_ops *ops = &ov5693_ctrl_ops;
+ struct v4l2_ctrl *ctrl;
+ unsigned int i;
+ int ret;
+ int hblank;
+
+ ret = v4l2_ctrl_handler_init(&ov5693->ctrl_handler,
+ ARRAY_SIZE(ov5693_controls));
+ if (ret) {
+ ov5693_remove(client);
+ return ret;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ov5693_controls); i++)
+ v4l2_ctrl_new_custom(&ov5693->ctrl_handler,
+ &ov5693_controls[i],
+ NULL);
+
+ /* link freq */
+ ctrl = v4l2_ctrl_new_int_menu(&ov5693->ctrl_handler, NULL,
+ V4L2_CID_LINK_FREQ,
+ 0, 0, link_freq_menu_items);
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ /* pixel rate */
+ v4l2_ctrl_new_std(&ov5693->ctrl_handler, NULL, V4L2_CID_PIXEL_RATE,
+ 0, OV5693_PIXEL_RATE, 1, OV5693_PIXEL_RATE);
+
+ if (ov5693->ctrl_handler.error) {
+ ov5693_remove(client);
+ return ov5693->ctrl_handler.error;
+ }
+
+ /* Exposure */
+
+ v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops, V4L2_CID_EXPOSURE, 16, 1048575, 16,
+ 512);
+
+ /* Gain */
+
+ v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops, V4L2_CID_ANALOGUE_GAIN, 1, 1023, 1, 128);
+ v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops, V4L2_CID_DIGITAL_GAIN, 1, 3999, 1, 1000);
+
+ /* Flip */
+
+ v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ hblank = OV5693_PPL_DEFAULT - ov5693->mode->width;
+ ov5693->hblank = v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops,
+ V4L2_CID_HBLANK, hblank, hblank,
+ 1, hblank);
+ if (ov5693->hblank)
+ ov5693->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ /* Use same lock for controls as for everything else. */
+ ov5693->ctrl_handler.lock = &ov5693->input_lock;
+ ov5693->sd.ctrl_handler = &ov5693->ctrl_handler;
+
+ return 0;
+}
+
+static int ov5693_configure_gpios(struct ov5693_device *ov5693)
+{
+ ov5693->reset = gpiod_get_index(&ov5693->i2c_client->dev, "reset", 0,
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(ov5693->reset)) {
+ dev_err(&ov5693->i2c_client->dev, "Couldn't find reset GPIO\n");
+ return -EINVAL;
+ }
+
+ ov5693->indicator_led = gpiod_get_index_optional(&ov5693->i2c_client->dev, "indicator-led", 0,
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(ov5693->indicator_led)) {
+ dev_err(&ov5693->i2c_client->dev, "Couldn't find indicator-led GPIO\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ov5693_get_regulators(struct ov5693_device *ov5693)
+{
+ unsigned int i;
+
+ for (i = 0; i < OV5693_NUM_SUPPLIES; i++)
+ ov5693->supplies[i].supply = ov5693_supply_names[i];
+
+ return regulator_bulk_get(&ov5693->i2c_client->dev,
+ OV5693_NUM_SUPPLIES,
+ ov5693->supplies);
+}
+
+static int ov5693_probe(struct i2c_client *client)
+{
+ struct ov5693_device *ov5693;
+ int ret = 0;
+
+ dev_info(&client->dev, "%s() called", __func__);
+
+ ov5693 = kzalloc(sizeof(*ov5693), GFP_KERNEL);
+ if (!ov5693)
+ return -ENOMEM;
+
+ ov5693->i2c_client = client;
+
+ /* check if VCM device exists */
+ /* TODO: read from SSDB */
+ ov5693->has_vcm = false;
+
+ mutex_init(&ov5693->input_lock);
+
+ v4l2_i2c_subdev_init(&ov5693->sd, client, &ov5693_ops);
+
+ ov5693->clk = devm_clk_get(&client->dev, "xvclk");
+ if (IS_ERR(ov5693->clk)) {
+ dev_err(&client->dev, "Error getting clock\n");
+ return -EINVAL;
+ }
+
+ ret = ov5693_configure_gpios(ov5693);
+ if (ret)
+ goto out_free;
+
+ ret = ov5693_get_regulators(ov5693);
+ if (ret)
+ goto out_put_reset;
+
+ ret = ov5693_s_config(&ov5693->sd, client->irq);
+ if (ret)
+ goto out_put_reset;
+
+ ov5693->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ ov5693->pad.flags = MEDIA_PAD_FL_SOURCE;
+ ov5693->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
+ ov5693->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ov5693->mode = &ov5693_res_video[N_RES_VIDEO-1];
+
+ ret = ov5693_init_controls(ov5693);
+ if (ret)
+ ov5693_remove(client);
+
+ ret = media_entity_pads_init(&ov5693->sd.entity, 1, &ov5693->pad);
+ if (ret)
+ ov5693_remove(client);
+
+ ret = v4l2_async_register_subdev_sensor_common(&ov5693->sd);
+ if (ret) {
+ dev_err(&client->dev, "failed to register V4L2 subdev: %d", ret);
+ goto media_entity_cleanup;
+ }
+
+ return ret;
+
+media_entity_cleanup:
+ media_entity_cleanup(&ov5693->sd.entity);
+out_put_reset:
+ gpiod_put(ov5693->reset);
+out_free:
+ v4l2_device_unregister_subdev(&ov5693->sd);
+ kfree(ov5693);
+ return ret;
+}
+
+static const struct acpi_device_id ov5693_acpi_match[] = {
+ {"INT33BE"},
+ {},
+};
+MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match);
+
+static struct i2c_driver ov5693_driver = {
+ .driver = {
+ .name = "ov5693",
+ .acpi_match_table = ov5693_acpi_match,
+ },
+ .probe_new = ov5693_probe,
+ .remove = ov5693_remove,
+};
+module_i2c_driver(ov5693_driver);
+
+MODULE_DESCRIPTION("A low-level driver for OmniVision 5693 sensors");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/ov5693.h b/drivers/media/i2c/ov5693.h
new file mode 100644
index 000000000000..9a508e1f3624
--- /dev/null
+++ b/drivers/media/i2c/ov5693.h
@@ -0,0 +1,1430 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Support for OmniVision OV5693 5M camera sensor.
+ *
+ * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ */
+
+#ifndef __OV5693_H__
+#define __OV5693_H__
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <linux/spinlock.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <linux/v4l2-mediabus.h>
+#include <media/media-entity.h>
+
+#define OV5693_HID "INT33BE"
+
+/*
+ * FIXME: non-preview resolutions are currently broken
+ */
+#define ENABLE_NON_PREVIEW 1
+
+#define OV5693_POWER_UP_RETRY_NUM 5
+
+/* Defines for register writes and register array processing */
+#define I2C_MSG_LENGTH 0x2
+#define I2C_RETRY_COUNT 5
+
+#define OV5693_FOCAL_LENGTH_NUM 334 /*3.34mm*/
+#define OV5693_FOCAL_LENGTH_DEM 100
+#define OV5693_F_NUMBER_DEFAULT_NUM 24
+#define OV5693_F_NUMBER_DEM 10
+
+#define MAX_FMTS 1
+
+/* sensor_mode_data read_mode adaptation */
+#define OV5693_READ_MODE_BINNING_ON 0x0400
+#define OV5693_READ_MODE_BINNING_OFF 0x00
+#define OV5693_INTEGRATION_TIME_MARGIN 8
+
+#define OV5693_MAX_EXPOSURE_VALUE 0xFFF1
+#define OV5693_MAX_GAIN_VALUE 0xFF
+
+/*
+ * focal length bits definition:
+ * bits 31-16: numerator, bits 15-0: denominator
+ */
+#define OV5693_FOCAL_LENGTH_DEFAULT 0x1B70064
+
+/*
+ * current f-number bits definition:
+ * bits 31-16: numerator, bits 15-0: denominator
+ */
+#define OV5693_F_NUMBER_DEFAULT 0x18000a
+
+/*
+ * f-number range bits definition:
+ * bits 31-24: max f-number numerator
+ * bits 23-16: max f-number denominator
+ * bits 15-8: min f-number numerator
+ * bits 7-0: min f-number denominator
+ */
+#define OV5693_F_NUMBER_RANGE 0x180a180a
+#define OV5693_ID 0x5690
+
+#define OV5693_FINE_INTG_TIME_MIN 0
+#define OV5693_FINE_INTG_TIME_MAX_MARGIN 0
+#define OV5693_COARSE_INTG_TIME_MIN 1
+#define OV5693_COARSE_INTG_TIME_MAX_MARGIN 6
+
+#define OV5693_BIN_FACTOR_MAX 4
+/*
+ * OV5693 System control registers
+ */
+#define OV5693_SW_SLEEP 0x0100
+#define OV5693_SW_RESET 0x0103
+#define OV5693_SW_STREAM 0x0100
+
+#define OV5693_SC_CMMN_CHIP_ID_H 0x300A
+#define OV5693_SC_CMMN_CHIP_ID_L 0x300B
+#define OV5693_SC_CMMN_SCCB_ID 0x300C
+#define OV5693_SC_CMMN_SUB_ID 0x302A /* process, version*/
+/*Bit[7:4] Group control, Bit[3:0] Group ID*/
+#define OV5693_GROUP_ACCESS 0x3208
+/*
+*Bit[3:0] Bit[19:16] of exposure,
+*remaining 16 bits lies in Reg0x3501&Reg0x3502
+*/
+#define OV5693_EXPOSURE_H 0x3500
+#define OV5693_EXPOSURE_M 0x3501
+#define OV5693_EXPOSURE_L 0x3502
+/*Bit[1:0] means Bit[9:8] of gain*/
+#define OV5693_AGC_H 0x350A
+#define OV5693_AGC_L 0x350B /*Bit[7:0] of gain*/
+
+#define OV5693_HORIZONTAL_START_H 0x3800 /*Bit[11:8]*/
+#define OV5693_HORIZONTAL_START_L 0x3801 /*Bit[7:0]*/
+#define OV5693_VERTICAL_START_H 0x3802 /*Bit[11:8]*/
+#define OV5693_VERTICAL_START_L 0x3803 /*Bit[7:0]*/
+#define OV5693_HORIZONTAL_END_H 0x3804 /*Bit[11:8]*/
+#define OV5693_HORIZONTAL_END_L 0x3805 /*Bit[7:0]*/
+#define OV5693_VERTICAL_END_H 0x3806 /*Bit[11:8]*/
+#define OV5693_VERTICAL_END_L 0x3807 /*Bit[7:0]*/
+#define OV5693_HORIZONTAL_OUTPUT_SIZE_H 0x3808 /*Bit[3:0]*/
+#define OV5693_HORIZONTAL_OUTPUT_SIZE_L 0x3809 /*Bit[7:0]*/
+#define OV5693_VERTICAL_OUTPUT_SIZE_H 0x380a /*Bit[3:0]*/
+#define OV5693_VERTICAL_OUTPUT_SIZE_L 0x380b /*Bit[7:0]*/
+/*High 8-bit, and low 8-bit HTS address is 0x380d*/
+#define OV5693_TIMING_HTS_H 0x380C
+/*High 8-bit, and low 8-bit HTS address is 0x380d*/
+#define OV5693_TIMING_HTS_L 0x380D
+/*High 8-bit, and low 8-bit HTS address is 0x380f*/
+#define OV5693_TIMING_VTS_H 0x380e
+/*High 8-bit, and low 8-bit HTS address is 0x380f*/
+#define OV5693_TIMING_VTS_L 0x380f
+
+#define OV5693_MWB_RED_GAIN_H 0x3400
+#define OV5693_MWB_GREEN_GAIN_H 0x3402
+#define OV5693_MWB_BLUE_GAIN_H 0x3404
+#define OV5693_MWB_GAIN_MAX 0x0fff
+
+#define OV5693_START_STREAMING 0x01
+#define OV5693_STOP_STREAMING 0x00
+
+#define VCM_ADDR 0x0c
+#define VCM_CODE_MSB 0x04
+
+#define OV5693_INVALID_CONFIG 0xffffffff
+
+#define OV5693_VCM_SLEW_STEP 0x30F0
+#define OV5693_VCM_SLEW_STEP_MAX 0x7
+#define OV5693_VCM_SLEW_STEP_MASK 0x7
+#define OV5693_VCM_CODE 0x30F2
+#define OV5693_VCM_SLEW_TIME 0x30F4
+#define OV5693_VCM_SLEW_TIME_MAX 0xffff
+#define OV5693_VCM_ENABLE 0x8000
+
+#define OV5693_VCM_MAX_FOCUS_NEG -1023
+#define OV5693_VCM_MAX_FOCUS_POS 1023
+
+#define DLC_ENABLE 1
+#define DLC_DISABLE 0
+#define VCM_PROTECTION_OFF 0xeca3
+#define VCM_PROTECTION_ON 0xdc51
+#define VCM_DEFAULT_S 0x0
+#define vcm_step_s(a) (u8)(a & 0xf)
+#define vcm_step_mclk(a) (u8)((a >> 4) & 0x3)
+#define vcm_dlc_mclk(dlc, mclk) (u16)((dlc << 3) | mclk | 0xa104)
+#define vcm_tsrc(tsrc) (u16)(tsrc << 3 | 0xf200)
+#define vcm_val(data, s) (u16)(data << 4 | s)
+#define DIRECT_VCM vcm_dlc_mclk(0, 0)
+
+/* Defines for OTP Data Registers */
+#define OV5693_FRAME_OFF_NUM 0x4202
+#define OV5693_OTP_BYTE_MAX 32 //change to 32 as needed by otpdata
+#define OV5693_OTP_SHORT_MAX 16
+#define OV5693_OTP_START_ADDR 0x3D00
+#define OV5693_OTP_END_ADDR 0x3D0F
+#define OV5693_OTP_DATA_SIZE 320
+#define OV5693_OTP_PROGRAM_REG 0x3D80
+#define OV5693_OTP_READ_REG 0x3D81 // 1:Enable 0:disable
+#define OV5693_OTP_BANK_REG 0x3D84 //otp bank and mode
+#define OV5693_OTP_READY_REG_DONE 1
+#define OV5693_OTP_BANK_MAX 28
+#define OV5693_OTP_BANK_SIZE 16 //16 bytes per bank
+#define OV5693_OTP_READ_ONETIME 16
+#define OV5693_OTP_MODE_READ 1
+
+/* link freq and pixel rate required for IPU3 */
+#define OV5693_LINK_FREQ_640MHZ 640000000
+/* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample
+ * To avoid integer overflow, dividing by bits_per_sample first.
+ */
+#define OV5693_PIXEL_RATE (OV5693_LINK_FREQ_640MHZ / 10) * 2 * 2
+static const s64 link_freq_menu_items[] = {
+ OV5693_LINK_FREQ_640MHZ
+};
+
+#define OV5693_NUM_SUPPLIES 2
+static const char * const ov5693_supply_names[] = {
+ "avdd",
+ "dovdd",
+};
+
+struct regval_list {
+ u16 reg_num;
+ u8 value;
+};
+
+struct ov5693_resolution {
+ u8 *desc;
+ const struct ov5693_reg *regs;
+ int res;
+ int width;
+ int height;
+ int fps;
+ int pix_clk_freq;
+ u16 pixels_per_line;
+ u16 lines_per_frame;
+ u8 bin_factor_x;
+ u8 bin_factor_y;
+ u8 bin_mode;
+ bool used;
+
+ /* Analog crop rectangle. */
+ struct v4l2_rect crop;
+};
+
+struct ov5693_format {
+ u8 *desc;
+ u32 pixelformat;
+ struct ov5693_reg *regs;
+};
+
+enum vcm_type {
+ VCM_UNKNOWN,
+ VCM_AD5823,
+ VCM_DW9714,
+};
+
+/*
+ * ov5693 device structure.
+ */
+struct ov5693_device {
+ struct i2c_client *i2c_client;
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+ struct v4l2_mbus_framefmt format;
+ struct mutex input_lock;
+ struct v4l2_ctrl_handler ctrl_handler;
+
+ struct gpio_desc *reset;
+ struct gpio_desc *indicator_led;
+ struct regulator_bulk_data supplies[OV5693_NUM_SUPPLIES];
+ struct clk *clk;
+
+ /* Current mode */
+ const struct ov5693_resolution *mode;
+
+ struct camera_sensor_platform_data *platform_data;
+ ktime_t timestamp_t_focus_abs;
+ int vt_pix_clk_freq_mhz;
+ int fmt_idx;
+ int run_mode;
+ int otp_size;
+ u8 *otp_data;
+ u32 focus;
+ s16 number_of_steps;
+ u8 res;
+ u8 type;
+ bool vcm_update;
+ enum vcm_type vcm;
+
+ bool has_vcm;
+
+ struct v4l2_ctrl *hblank;
+};
+
+enum ov5693_tok_type {
+ OV5693_8BIT = 0x0001,
+ OV5693_16BIT = 0x0002,
+ OV5693_32BIT = 0x0004,
+ OV5693_TOK_TERM = 0xf000, /* terminating token for reg list */
+ OV5693_TOK_DELAY = 0xfe00, /* delay token for reg list */
+ OV5693_TOK_MASK = 0xfff0
+};
+
+/**
+ * struct ov5693_reg - MI sensor register format
+ * @type: type of the register
+ * @reg: 16-bit offset to register
+ * @val: 8/16/32-bit register value
+ *
+ * Define a structure for sensor register initialization values
+ */
+struct ov5693_reg {
+ enum ov5693_tok_type type;
+ u16 reg;
+ u32 val; /* @set value for read/mod/write, @mask */
+};
+
+#define to_ov5693_sensor(x) container_of(x, struct ov5693_device, sd)
+
+#define OV5693_MAX_WRITE_BUF_SIZE 30
+
+struct ov5693_write_buffer {
+ u16 addr;
+ u8 data[OV5693_MAX_WRITE_BUF_SIZE];
+};
+
+struct ov5693_write_ctrl {
+ int index;
+ struct ov5693_write_buffer buffer;
+};
+
+static struct ov5693_reg const ov5693_global_setting[] = {
+ {OV5693_8BIT, 0x0103, 0x01},
+ {OV5693_8BIT, 0x3001, 0x0a},
+ {OV5693_8BIT, 0x3002, 0x80},
+ {OV5693_8BIT, 0x3006, 0x00},
+ {OV5693_8BIT, 0x3011, 0x21},
+ {OV5693_8BIT, 0x3012, 0x09},
+ {OV5693_8BIT, 0x3013, 0x10},
+ {OV5693_8BIT, 0x3014, 0x00},
+ {OV5693_8BIT, 0x3015, 0x08},
+ {OV5693_8BIT, 0x3016, 0xf0},
+ {OV5693_8BIT, 0x3017, 0xf0},
+ {OV5693_8BIT, 0x3018, 0xf0},
+ {OV5693_8BIT, 0x301b, 0xb4},
+ {OV5693_8BIT, 0x301d, 0x02},
+ {OV5693_8BIT, 0x3021, 0x00},
+ {OV5693_8BIT, 0x3022, 0x01},
+ {OV5693_8BIT, 0x3028, 0x44},
+ {OV5693_8BIT, 0x3098, 0x02},
+ {OV5693_8BIT, 0x3099, 0x19},
+ {OV5693_8BIT, 0x309a, 0x02},
+ {OV5693_8BIT, 0x309b, 0x01},
+ {OV5693_8BIT, 0x309c, 0x00},
+ {OV5693_8BIT, 0x30a0, 0xd2},
+ {OV5693_8BIT, 0x30a2, 0x01},
+ {OV5693_8BIT, 0x30b2, 0x00},
+ {OV5693_8BIT, 0x30b3, 0x7d},
+ {OV5693_8BIT, 0x30b4, 0x03},
+ {OV5693_8BIT, 0x30b5, 0x04},
+ {OV5693_8BIT, 0x30b6, 0x01},
+ {OV5693_8BIT, 0x3104, 0x21},
+ {OV5693_8BIT, 0x3106, 0x00},
+ {OV5693_8BIT, 0x3400, 0x04},
+ {OV5693_8BIT, 0x3401, 0x00},
+ {OV5693_8BIT, 0x3402, 0x04},
+ {OV5693_8BIT, 0x3403, 0x00},
+ {OV5693_8BIT, 0x3404, 0x04},
+ {OV5693_8BIT, 0x3405, 0x00},
+ {OV5693_8BIT, 0x3406, 0x01},
+ {OV5693_8BIT, 0x3500, 0x00},
+ {OV5693_8BIT, 0x3503, 0x07},
+ {OV5693_8BIT, 0x3504, 0x00},
+ {OV5693_8BIT, 0x3505, 0x00},
+ {OV5693_8BIT, 0x3506, 0x00},
+ {OV5693_8BIT, 0x3507, 0x02},
+ {OV5693_8BIT, 0x3508, 0x00},
+ {OV5693_8BIT, 0x3509, 0x10},
+ {OV5693_8BIT, 0x350a, 0x00},
+ {OV5693_8BIT, 0x350b, 0x40},
+ {OV5693_8BIT, 0x3601, 0x0a},
+ {OV5693_8BIT, 0x3602, 0x38},
+ {OV5693_8BIT, 0x3612, 0x80},
+ {OV5693_8BIT, 0x3620, 0x54},
+ {OV5693_8BIT, 0x3621, 0xc7},
+ {OV5693_8BIT, 0x3622, 0x0f},
+ {OV5693_8BIT, 0x3625, 0x10},
+ {OV5693_8BIT, 0x3630, 0x55},
+ {OV5693_8BIT, 0x3631, 0xf4},
+ {OV5693_8BIT, 0x3632, 0x00},
+ {OV5693_8BIT, 0x3633, 0x34},
+ {OV5693_8BIT, 0x3634, 0x02},
+ {OV5693_8BIT, 0x364d, 0x0d},
+ {OV5693_8BIT, 0x364f, 0xdd},
+ {OV5693_8BIT, 0x3660, 0x04},
+ {OV5693_8BIT, 0x3662, 0x10},
+ {OV5693_8BIT, 0x3663, 0xf1},
+ {OV5693_8BIT, 0x3665, 0x00},
+ {OV5693_8BIT, 0x3666, 0x20},
+ {OV5693_8BIT, 0x3667, 0x00},
+ {OV5693_8BIT, 0x366a, 0x80},
+ {OV5693_8BIT, 0x3680, 0xe0},
+ {OV5693_8BIT, 0x3681, 0x00},
+ {OV5693_8BIT, 0x3700, 0x42},
+ {OV5693_8BIT, 0x3701, 0x14},
+ {OV5693_8BIT, 0x3702, 0xa0},
+ {OV5693_8BIT, 0x3703, 0xd8},
+ {OV5693_8BIT, 0x3704, 0x78},
+ {OV5693_8BIT, 0x3705, 0x02},
+ {OV5693_8BIT, 0x370a, 0x00},
+ {OV5693_8BIT, 0x370b, 0x20},
+ {OV5693_8BIT, 0x370c, 0x0c},
+ {OV5693_8BIT, 0x370d, 0x11},
+ {OV5693_8BIT, 0x370e, 0x00},
+ {OV5693_8BIT, 0x370f, 0x40},
+ {OV5693_8BIT, 0x3710, 0x00},
+ {OV5693_8BIT, 0x371a, 0x1c},
+ {OV5693_8BIT, 0x371b, 0x05},
+ {OV5693_8BIT, 0x371c, 0x01},
+ {OV5693_8BIT, 0x371e, 0xa1},
+ {OV5693_8BIT, 0x371f, 0x0c},
+ {OV5693_8BIT, 0x3721, 0x00},
+ {OV5693_8BIT, 0x3724, 0x10},
+ {OV5693_8BIT, 0x3726, 0x00},
+ {OV5693_8BIT, 0x372a, 0x01},
+ {OV5693_8BIT, 0x3730, 0x10},
+ {OV5693_8BIT, 0x3738, 0x22},
+ {OV5693_8BIT, 0x3739, 0xe5},
+ {OV5693_8BIT, 0x373a, 0x50},
+ {OV5693_8BIT, 0x373b, 0x02},
+ {OV5693_8BIT, 0x373c, 0x41},
+ {OV5693_8BIT, 0x373f, 0x02},
+ {OV5693_8BIT, 0x3740, 0x42},
+ {OV5693_8BIT, 0x3741, 0x02},
+ {OV5693_8BIT, 0x3742, 0x18},
+ {OV5693_8BIT, 0x3743, 0x01},
+ {OV5693_8BIT, 0x3744, 0x02},
+ {OV5693_8BIT, 0x3747, 0x10},
+ {OV5693_8BIT, 0x374c, 0x04},
+ {OV5693_8BIT, 0x3751, 0xf0},
+ {OV5693_8BIT, 0x3752, 0x00},
+ {OV5693_8BIT, 0x3753, 0x00},
+ {OV5693_8BIT, 0x3754, 0xc0},
+ {OV5693_8BIT, 0x3755, 0x00},
+ {OV5693_8BIT, 0x3756, 0x1a},
+ {OV5693_8BIT, 0x3758, 0x00},
+ {OV5693_8BIT, 0x3759, 0x0f},
+ {OV5693_8BIT, 0x376b, 0x44},
+ {OV5693_8BIT, 0x375c, 0x04},
+ {OV5693_8BIT, 0x3774, 0x10},
+ {OV5693_8BIT, 0x3776, 0x00},
+ {OV5693_8BIT, 0x377f, 0x08},
+ {OV5693_8BIT, 0x3780, 0x22},
+ {OV5693_8BIT, 0x3781, 0x0c},
+ {OV5693_8BIT, 0x3784, 0x2c},
+ {OV5693_8BIT, 0x3785, 0x1e},
+ {OV5693_8BIT, 0x378f, 0xf5},
+ {OV5693_8BIT, 0x3791, 0xb0},
+ {OV5693_8BIT, 0x3795, 0x00},
+ {OV5693_8BIT, 0x3796, 0x64},
+ {OV5693_8BIT, 0x3797, 0x11},
+ {OV5693_8BIT, 0x3798, 0x30},
+ {OV5693_8BIT, 0x3799, 0x41},
+ {OV5693_8BIT, 0x379a, 0x07},
+ {OV5693_8BIT, 0x379b, 0xb0},
+ {OV5693_8BIT, 0x379c, 0x0c},
+ {OV5693_8BIT, 0x37c5, 0x00},
+ {OV5693_8BIT, 0x37c6, 0x00},
+ {OV5693_8BIT, 0x37c7, 0x00},
+ {OV5693_8BIT, 0x37c9, 0x00},
+ {OV5693_8BIT, 0x37ca, 0x00},
+ {OV5693_8BIT, 0x37cb, 0x00},
+ {OV5693_8BIT, 0x37de, 0x00},
+ {OV5693_8BIT, 0x37df, 0x00},
+ {OV5693_8BIT, 0x3800, 0x00},
+ {OV5693_8BIT, 0x3801, 0x00},
+ {OV5693_8BIT, 0x3802, 0x00},
+ {OV5693_8BIT, 0x3804, 0x0a},
+ {OV5693_8BIT, 0x3805, 0x3f},
+ {OV5693_8BIT, 0x3810, 0x00},
+ {OV5693_8BIT, 0x3812, 0x00},
+ {OV5693_8BIT, 0x3823, 0x00},
+ {OV5693_8BIT, 0x3824, 0x00},
+ {OV5693_8BIT, 0x3825, 0x00},
+ {OV5693_8BIT, 0x3826, 0x00},
+ {OV5693_8BIT, 0x3827, 0x00},
+ {OV5693_8BIT, 0x382a, 0x04},
+ {OV5693_8BIT, 0x3a04, 0x06},
+ {OV5693_8BIT, 0x3a05, 0x14},
+ {OV5693_8BIT, 0x3a06, 0x00},
+ {OV5693_8BIT, 0x3a07, 0xfe},
+ {OV5693_8BIT, 0x3b00, 0x00},
+ {OV5693_8BIT, 0x3b02, 0x00},
+ {OV5693_8BIT, 0x3b03, 0x00},
+ {OV5693_8BIT, 0x3b04, 0x00},
+ {OV5693_8BIT, 0x3b05, 0x00},
+ {OV5693_8BIT, 0x3e07, 0x20},
+ {OV5693_8BIT, 0x4000, 0x08},
+ {OV5693_8BIT, 0x4001, 0x04},
+ {OV5693_8BIT, 0x4002, 0x45},
+ {OV5693_8BIT, 0x4004, 0x08},
+ {OV5693_8BIT, 0x4005, 0x18},
+ {OV5693_8BIT, 0x4006, 0x20},
+ {OV5693_8BIT, 0x4008, 0x24},
+ {OV5693_8BIT, 0x4009, 0x10},
+ {OV5693_8BIT, 0x400c, 0x00},
+ {OV5693_8BIT, 0x400d, 0x00},
+ {OV5693_8BIT, 0x4058, 0x00},
+ {OV5693_8BIT, 0x404e, 0x37},
+ {OV5693_8BIT, 0x404f, 0x8f},
+ {OV5693_8BIT, 0x4058, 0x00},
+ {OV5693_8BIT, 0x4101, 0xb2},
+ {OV5693_8BIT, 0x4303, 0x00},
+ {OV5693_8BIT, 0x4304, 0x08},
+ {OV5693_8BIT, 0x4307, 0x31},
+ {OV5693_8BIT, 0x4311, 0x04},
+ {OV5693_8BIT, 0x4315, 0x01},
+ {OV5693_8BIT, 0x4511, 0x05},
+ {OV5693_8BIT, 0x4512, 0x01},
+ {OV5693_8BIT, 0x4806, 0x00},
+ {OV5693_8BIT, 0x4816, 0x52},
+ {OV5693_8BIT, 0x481f, 0x30},
+ {OV5693_8BIT, 0x4826, 0x2c},
+ {OV5693_8BIT, 0x4831, 0x64},
+ {OV5693_8BIT, 0x4d00, 0x04},
+ {OV5693_8BIT, 0x4d01, 0x71},
+ {OV5693_8BIT, 0x4d02, 0xfd},
+ {OV5693_8BIT, 0x4d03, 0xf5},
+ {OV5693_8BIT, 0x4d04, 0x0c},
+ {OV5693_8BIT, 0x4d05, 0xcc},
+ {OV5693_8BIT, 0x4837, 0x0a},
+ {OV5693_8BIT, 0x5000, 0x06},
+ {OV5693_8BIT, 0x5001, 0x01},
+ {OV5693_8BIT, 0x5003, 0x20},
+ {OV5693_8BIT, 0x5046, 0x0a},
+ {OV5693_8BIT, 0x5013, 0x00},
+ {OV5693_8BIT, 0x5046, 0x0a},
+ {OV5693_8BIT, 0x5780, 0x1c},
+ {OV5693_8BIT, 0x5786, 0x20},
+ {OV5693_8BIT, 0x5787, 0x10},
+ {OV5693_8BIT, 0x5788, 0x18},
+ {OV5693_8BIT, 0x578a, 0x04},
+ {OV5693_8BIT, 0x578b, 0x02},
+ {OV5693_8BIT, 0x578c, 0x02},
+ {OV5693_8BIT, 0x578e, 0x06},
+ {OV5693_8BIT, 0x578f, 0x02},
+ {OV5693_8BIT, 0x5790, 0x02},
+ {OV5693_8BIT, 0x5791, 0xff},
+ {OV5693_8BIT, 0x5842, 0x01},
+ {OV5693_8BIT, 0x5843, 0x2b},
+ {OV5693_8BIT, 0x5844, 0x01},
+ {OV5693_8BIT, 0x5845, 0x92},
+ {OV5693_8BIT, 0x5846, 0x01},
+ {OV5693_8BIT, 0x5847, 0x8f},
+ {OV5693_8BIT, 0x5848, 0x01},
+ {OV5693_8BIT, 0x5849, 0x0c},
+ {OV5693_8BIT, 0x5e00, 0x00},
+ {OV5693_8BIT, 0x5e10, 0x0c},
+ {OV5693_8BIT, 0x0100, 0x00},
+ {OV5693_TOK_TERM, 0, 0}
+};
+
+#if ENABLE_NON_PREVIEW
+/*
+ * 654x496 30fps 17ms VBlanking 2lane 10Bit (Scaling)
+ */
+static struct ov5693_reg const ov5693_654x496[] = {
+ {OV5693_8BIT, 0x3501, 0x3d},
+ {OV5693_8BIT, 0x3502, 0x00},
+ {OV5693_8BIT, 0x3708, 0xe6},
+ {OV5693_8BIT, 0x3709, 0xc7},
+ {OV5693_8BIT, 0x3803, 0x00},
+ {OV5693_8BIT, 0x3806, 0x07},
+ {OV5693_8BIT, 0x3807, 0xa3},
+ {OV5693_8BIT, 0x3808, 0x02},
+ {OV5693_8BIT, 0x3809, 0x90},
+ {OV5693_8BIT, 0x380a, 0x01},
+ {OV5693_8BIT, 0x380b, 0xf0},
+ {OV5693_8BIT, 0x380c, 0x0a},
+ {OV5693_8BIT, 0x380d, 0x80},
+ {OV5693_8BIT, 0x380e, 0x07},
+ {OV5693_8BIT, 0x380f, 0xc0},
+ {OV5693_8BIT, 0x3811, 0x08},
+ {OV5693_8BIT, 0x3813, 0x02},
+ {OV5693_8BIT, 0x3814, 0x31},
+ {OV5693_8BIT, 0x3815, 0x31},
+ {OV5693_8BIT, 0x3820, 0x04},
+ {OV5693_8BIT, 0x3821, 0x1f},
+ {OV5693_8BIT, 0x5002, 0x80},
+ {OV5693_8BIT, 0x0100, 0x01},
+ {OV5693_TOK_TERM, 0, 0}
+};
+
+/*
+ * 1296x976 30fps 17ms VBlanking 2lane 10Bit (Scaling)
+*DS from 2592x1952
+*/
+static struct ov5693_reg const ov5693_1296x976[] = {
+ {OV5693_8BIT, 0x3501, 0x7b},
+ {OV5693_8BIT, 0x3502, 0x00},
+ {OV5693_8BIT, 0x3708, 0xe2},
+ {OV5693_8BIT, 0x3709, 0xc3},
+
+ {OV5693_8BIT, 0x3800, 0x00},
+ {OV5693_8BIT, 0x3801, 0x00},
+ {OV5693_8BIT, 0x3802, 0x00},
+ {OV5693_8BIT, 0x3803, 0x00},
+
+ {OV5693_8BIT, 0x3804, 0x0a},
+ {OV5693_8BIT, 0x3805, 0x3f},
+ {OV5693_8BIT, 0x3806, 0x07},
+ {OV5693_8BIT, 0x3807, 0xA3},
+
+ {OV5693_8BIT, 0x3808, 0x05},
+ {OV5693_8BIT, 0x3809, 0x10},
+ {OV5693_8BIT, 0x380a, 0x03},
+ {OV5693_8BIT, 0x380b, 0xD0},
+
+ {OV5693_8BIT, 0x380c, 0x0a},
+ {OV5693_8BIT, 0x380d, 0x80},
+ {OV5693_8BIT, 0x380e, 0x07},
+ {OV5693_8BIT, 0x380f, 0xc0},
+
+ {OV5693_8BIT, 0x3810, 0x00},
+ {OV5693_8BIT, 0x3811, 0x10},
+ {OV5693_8BIT, 0x3812, 0x00},
+ {OV5693_8BIT, 0x3813, 0x02},
+
+ {OV5693_8BIT, 0x3814, 0x11}, /*X subsample control*/
+ {OV5693_8BIT, 0x3815, 0x11}, /*Y subsample control*/
+ {OV5693_8BIT, 0x3820, 0x00},
+ {OV5693_8BIT, 0x3821, 0x1e},
+ {OV5693_8BIT, 0x5002, 0x00},
+ {OV5693_8BIT, 0x5041, 0x84}, /* scale is auto enabled */
+ {OV5693_8BIT, 0x0100, 0x01},
+ {OV5693_TOK_TERM, 0, 0}
+
+};
+
+/*
+ * 336x256 30fps 17ms VBlanking 2lane 10Bit (Scaling)
+ DS from 2564x1956
+ */
+static struct ov5693_reg const ov5693_336x256[] = {
+ {OV5693_8BIT, 0x3501, 0x3d},
+ {OV5693_8BIT, 0x3502, 0x00},
+ {OV5693_8BIT, 0x3708, 0xe6},
+ {OV5693_8BIT, 0x3709, 0xc7},
+ {OV5693_8BIT, 0x3806, 0x07},
+ {OV5693_8BIT, 0x3807, 0xa3},
+ {OV5693_8BIT, 0x3808, 0x01},
+ {OV5693_8BIT, 0x3809, 0x50},
+ {OV5693_8BIT, 0x380a, 0x01},
+ {OV5693_8BIT, 0x380b, 0x00},
+ {OV5693_8BIT, 0x380c, 0x0a},
+ {OV5693_8BIT, 0x380d, 0x80},
+ {OV5693_8BIT, 0x380e, 0x07},
+ {OV5693_8BIT, 0x380f, 0xc0},
+ {OV5693_8BIT, 0x3811, 0x1E},
+ {OV5693_8BIT, 0x3814, 0x31},
+ {OV5693_8BIT, 0x3815, 0x31},
+ {OV5693_8BIT, 0x3820, 0x04},
+ {OV5693_8BIT, 0x3821, 0x1f},
+ {OV5693_8BIT, 0x5002, 0x80},
+ {OV5693_8BIT, 0x0100, 0x01},
+ {OV5693_TOK_TERM, 0, 0}
+};
+
+/*
+ * 336x256 30fps 17ms VBlanking 2lane 10Bit (Scaling)
+ DS from 2368x1956
+ */
+static struct ov5693_reg const ov5693_368x304[] = {
+ {OV5693_8BIT, 0x3501, 0x3d},
+ {OV5693_8BIT, 0x3502, 0x00},
+ {OV5693_8BIT, 0x3708, 0xe6},
+ {OV5693_8BIT, 0x3709, 0xc7},
+ {OV5693_8BIT, 0x3808, 0x01},
+ {OV5693_8BIT, 0x3809, 0x70},
+ {OV5693_8BIT, 0x380a, 0x01},
+ {OV5693_8BIT, 0x380b, 0x30},
+ {OV5693_8BIT, 0x380c, 0x0a},
+ {OV5693_8BIT, 0x380d, 0x80},
+ {OV5693_8BIT, 0x380e, 0x07},
+ {OV5693_8BIT, 0x380f, 0xc0},
+ {OV5693_8BIT, 0x3811, 0x80},
+ {OV5693_8BIT, 0x3814, 0x31},
+ {OV5693_8BIT, 0x3815, 0x31},
+ {OV5693_8BIT, 0x3820, 0x04},
+ {OV5693_8BIT, 0x3821, 0x1f},
+ {OV5693_8BIT, 0x5002, 0x80},
+ {OV5693_8BIT, 0x0100, 0x01},
+ {OV5693_TOK_TERM, 0, 0}
+};
+
+/*
+ * ov5693_192x160 30fps 17ms VBlanking 2lane 10Bit (Scaling)
+ DS from 2460x1956
+ */
+static struct ov5693_reg const ov5693_192x160[] = {
+ {OV5693_8BIT, 0x3501, 0x7b},
+ {OV5693_8BIT, 0x3502, 0x80},
+ {OV5693_8BIT, 0x3708, 0xe2},
+ {OV5693_8BIT, 0x3709, 0xc3},
+ {OV5693_8BIT, 0x3804, 0x0a},
+ {OV5693_8BIT, 0x3805, 0x3f},
+ {OV5693_8BIT, 0x3806, 0x07},
+ {OV5693_8BIT, 0x3807, 0xA3},
+ {OV5693_8BIT, 0x3808, 0x00},
+ {OV5693_8BIT, 0x3809, 0xC0},
+ {OV5693_8BIT, 0x380a, 0x00},
+ {OV5693_8BIT, 0x380b, 0xA0},
+ {OV5693_8BIT, 0x380c, 0x0a},
+ {OV5693_8BIT, 0x380d, 0x80},
+ {OV5693_8BIT, 0x380e, 0x07},
+ {OV5693_8BIT, 0x380f, 0xc0},
+ {OV5693_8BIT, 0x3811, 0x40},
+ {OV5693_8BIT, 0x3813, 0x00},
+ {OV5693_8BIT, 0x3814, 0x31},
+ {OV5693_8BIT, 0x3815, 0x31},
+ {OV5693_8BIT, 0x3820, 0x04},
+ {OV5693_8BIT, 0x3821, 0x1f},
+ {OV5693_8BIT, 0x5002, 0x80},
+ {OV5693_8BIT, 0x0100, 0x01},
+ {OV5693_TOK_TERM, 0, 0}
+};
+
+static struct ov5693_reg const ov5693_736x496[] = {
+ {OV5693_8BIT, 0x3501, 0x3d},
+ {OV5693_8BIT, 0x3502, 0x00},
+ {OV5693_8BIT, 0x3708, 0xe6},
+ {OV5693_8BIT, 0x3709, 0xc7},
+ {OV5693_8BIT, 0x3803, 0x68},
+ {OV5693_8BIT, 0x3806, 0x07},
+ {OV5693_8BIT, 0x3807, 0x3b},
+ {OV5693_8BIT, 0x3808, 0x02},
+ {OV5693_8BIT, 0x3809, 0xe0},
+ {OV5693_8BIT, 0x380a, 0x01},
+ {OV5693_8BIT, 0x380b, 0xf0},
+ {OV5693_8BIT, 0x380c, 0x0a}, /*hts*/
+ {OV5693_8BIT, 0x380d, 0x80},
+ {OV5693_8BIT, 0x380e, 0x07}, /*vts*/
+ {OV5693_8BIT, 0x380f, 0xc0},
+ {OV5693_8BIT, 0x3811, 0x08},
+ {OV5693_8BIT, 0x3813, 0x02},
+ {OV5693_8BIT, 0x3814, 0x31},
+ {OV5693_8BIT, 0x3815, 0x31},
+ {OV5693_8BIT, 0x3820, 0x04},
+ {OV5693_8BIT, 0x3821, 0x1f},
+ {OV5693_8BIT, 0x5002, 0x80},
+ {OV5693_8BIT, 0x0100, 0x01},
+ {OV5693_TOK_TERM, 0, 0}
+};
+#endif
+
+/*
+static struct ov5693_reg const ov5693_736x496[] = {
+ {OV5693_8BIT, 0x3501, 0x7b},
+ {OV5693_8BIT, 0x3502, 0x00},
+ {OV5693_8BIT, 0x3708, 0xe6},
+ {OV5693_8BIT, 0x3709, 0xc3},
+ {OV5693_8BIT, 0x3803, 0x00},
+ {OV5693_8BIT, 0x3806, 0x07},
+ {OV5693_8BIT, 0x3807, 0xa3},
+ {OV5693_8BIT, 0x3808, 0x02},
+ {OV5693_8BIT, 0x3809, 0xe0},
+ {OV5693_8BIT, 0x380a, 0x01},
+ {OV5693_8BIT, 0x380b, 0xf0},
+ {OV5693_8BIT, 0x380c, 0x0d},
+ {OV5693_8BIT, 0x380d, 0xb0},
+ {OV5693_8BIT, 0x380e, 0x05},
+ {OV5693_8BIT, 0x380f, 0xf2},
+ {OV5693_8BIT, 0x3811, 0x08},
+ {OV5693_8BIT, 0x3813, 0x02},
+ {OV5693_8BIT, 0x3814, 0x31},
+ {OV5693_8BIT, 0x3815, 0x31},
+ {OV5693_8BIT, 0x3820, 0x01},
+ {OV5693_8BIT, 0x3821, 0x1f},
+ {OV5693_8BIT, 0x5002, 0x00},
+ {OV5693_8BIT, 0x0100, 0x01},
+ {OV5693_TOK_TERM, 0, 0}
+};
+*/
+/*
+ * 976x556 30fps 8.8ms VBlanking 2lane 10Bit (Scaling)
+ */
+#if ENABLE_NON_PREVIEW
+static struct ov5693_reg const ov5693_976x556[] = {
+ {OV5693_8BIT, 0x3501, 0x7b},
+ {OV5693_8BIT, 0x3502, 0x00},
+ {OV5693_8BIT, 0x3708, 0xe2},
+ {OV5693_8BIT, 0x3709, 0xc3},
+ {OV5693_8BIT, 0x3803, 0xf0},
+ {OV5693_8BIT, 0x3806, 0x06},
+ {OV5693_8BIT, 0x3807, 0xa7},
+ {OV5693_8BIT, 0x3808, 0x03},
+ {OV5693_8BIT, 0x3809, 0xd0},
+ {OV5693_8BIT, 0x380a, 0x02},
+ {OV5693_8BIT, 0x380b, 0x2C},
+ {OV5693_8BIT, 0x380c, 0x0a},
+ {OV5693_8BIT, 0x380d, 0x80},
+ {OV5693_8BIT, 0x380e, 0x07},
+ {OV5693_8BIT, 0x380f, 0xc0},
+ {OV5693_8BIT, 0x3811, 0x10},
+ {OV5693_8BIT, 0x3813, 0x02},
+ {OV5693_8BIT, 0x3814, 0x11},
+ {OV5693_8BIT, 0x3815, 0x11},
+ {OV5693_8BIT, 0x3820, 0x00},
+ {OV5693_8BIT, 0x3821, 0x1e},
+ {OV5693_8BIT, 0x5002, 0x80},
+ {OV5693_8BIT, 0x0100, 0x01},
+ {OV5693_TOK_TERM, 0, 0}
+};
+
+/*DS from 2624x1492*/
+static struct ov5693_reg const ov5693_1296x736[] = {
+ {OV5693_8BIT, 0x3501, 0x7b},
+ {OV5693_8BIT, 0x3502, 0x00},
+ {OV5693_8BIT, 0x3708, 0xe2},
+ {OV5693_8BIT, 0x3709, 0xc3},
+
+ {OV5693_8BIT, 0x3800, 0x00},
+ {OV5693_8BIT, 0x3801, 0x00},
+ {OV5693_8BIT, 0x3802, 0x00},
+ {OV5693_8BIT, 0x3803, 0x00},
+
+ {OV5693_8BIT, 0x3804, 0x0a},
+ {OV5693_8BIT, 0x3805, 0x3f},
+ {OV5693_8BIT, 0x3806, 0x07},
+ {OV5693_8BIT, 0x3807, 0xA3},
+
+ {OV5693_8BIT, 0x3808, 0x05},
+ {OV5693_8BIT, 0x3809, 0x10},
+ {OV5693_8BIT, 0x380a, 0x02},
+ {OV5693_8BIT, 0x380b, 0xe0},
+
+ {OV5693_8BIT, 0x380c, 0x0a},
+ {OV5693_8BIT, 0x380d, 0x80},
+ {OV5693_8BIT, 0x380e, 0x07},
+ {OV5693_8BIT, 0x380f, 0xc0},
+
+ {OV5693_8BIT, 0x3813, 0xE8},
+
+ {OV5693_8BIT, 0x3814, 0x11}, /*X subsample control*/
+ {OV5693_8BIT, 0x3815, 0x11}, /*Y subsample control*/
+ {OV5693_8BIT, 0x3820, 0x00},
+ {OV5693_8BIT, 0x3821, 0x1e},
+ {OV5693_8BIT, 0x5002, 0x00},
+ {OV5693_8BIT, 0x5041, 0x84}, /* scale is auto enabled */
+ {OV5693_8BIT, 0x0100, 0x01},
+ {OV5693_TOK_TERM, 0, 0}
+};
+
+static struct ov5693_reg const ov5693_1636p_30fps[] = {
+ {OV5693_8BIT, 0x3501, 0x7b},
+ {OV5693_8BIT, 0x3502, 0x00},
+ {OV5693_8BIT, 0x3708, 0xe2},
+ {OV5693_8BIT, 0x3709, 0xc3},
+ {OV5693_8BIT, 0x3803, 0xf0},
+ {OV5693_8BIT, 0x3806, 0x06},
+ {OV5693_8BIT, 0x3807, 0xa7},
+ {OV5693_8BIT, 0x3808, 0x06},
+ {OV5693_8BIT, 0x3809, 0x64},
+ {OV5693_8BIT, 0x380a, 0x04},
+ {OV5693_8BIT, 0x380b, 0x48},
+ {OV5693_8BIT, 0x380c, 0x0a}, /*hts*/
+ {OV5693_8BIT, 0x380d, 0x80},
+ {OV5693_8BIT, 0x380e, 0x07}, /*vts*/
+ {OV5693_8BIT, 0x380f, 0xc0},
+ {OV5693_8BIT, 0x3811, 0x02},
+ {OV5693_8BIT, 0x3813, 0x02},
+ {OV5693_8BIT, 0x3814, 0x11},
+ {OV5693_8BIT, 0x3815, 0x11},
+ {OV5693_8BIT, 0x3820, 0x00},
+ {OV5693_8BIT, 0x3821, 0x1e},
+ {OV5693_8BIT, 0x5002, 0x80},
+ {OV5693_8BIT, 0x0100, 0x01},
+ {OV5693_TOK_TERM, 0, 0}
+};
+#endif
+
+static struct ov5693_reg const ov5693_1616x1216_30fps[] = {
+ {OV5693_8BIT, 0x3501, 0x7b},
+ {OV5693_8BIT, 0x3502, 0x80},
+ {OV5693_8BIT, 0x3708, 0xe2},
+ {OV5693_8BIT, 0x3709, 0xc3},
+ {OV5693_8BIT, 0x3800, 0x00}, /*{3800,3801} Array X start*/
+ {OV5693_8BIT, 0x3801, 0x08}, /* 04 //{3800,3801} Array X start*/
+ {OV5693_8BIT, 0x3802, 0x00}, /*{3802,3803} Array Y start*/
+ {OV5693_8BIT, 0x3803, 0x04}, /* 00 //{3802,3803} Array Y start*/
+ {OV5693_8BIT, 0x3804, 0x0a}, /*{3804,3805} Array X end*/
+ {OV5693_8BIT, 0x3805, 0x37}, /* 3b //{3804,3805} Array X end*/
+ {OV5693_8BIT, 0x3806, 0x07}, /*{3806,3807} Array Y end*/
+ {OV5693_8BIT, 0x3807, 0x9f}, /* a3 //{3806,3807} Array Y end*/
+ {OV5693_8BIT, 0x3808, 0x06}, /*{3808,3809} Final output H size*/
+ {OV5693_8BIT, 0x3809, 0x50}, /*{3808,3809} Final output H size*/
+ {OV5693_8BIT, 0x380a, 0x04}, /*{380a,380b} Final output V size*/
+ {OV5693_8BIT, 0x380b, 0xc0}, /*{380a,380b} Final output V size*/
+ {OV5693_8BIT, 0x380c, 0x0a}, /*{380c,380d} HTS*/
+ {OV5693_8BIT, 0x380d, 0x80}, /*{380c,380d} HTS*/
+ {OV5693_8BIT, 0x380e, 0x07}, /*{380e,380f} VTS*/
+ {OV5693_8BIT, 0x380f, 0xc0}, /* bc //{380e,380f} VTS*/
+ {OV5693_8BIT, 0x3810, 0x00}, /*{3810,3811} windowing X offset*/
+ {OV5693_8BIT, 0x3811, 0x10}, /*{3810,3811} windowing X offset*/
+ {OV5693_8BIT, 0x3812, 0x00}, /*{3812,3813} windowing Y offset*/
+ {OV5693_8BIT, 0x3813, 0x06}, /*{3812,3813} windowing Y offset*/
+ {OV5693_8BIT, 0x3814, 0x11}, /*X subsample control*/
+ {OV5693_8BIT, 0x3815, 0x11}, /*Y subsample control*/
+ {OV5693_8BIT, 0x3820, 0x00}, /*FLIP/Binnning control*/
+ {OV5693_8BIT, 0x3821, 0x1e}, /*MIRROR control*/
+ {OV5693_8BIT, 0x5002, 0x00},
+ {OV5693_8BIT, 0x5041, 0x84},
+ {OV5693_8BIT, 0x0100, 0x01},
+ {OV5693_TOK_TERM, 0, 0}
+};
+
+/*
+ * 1940x1096 30fps 8.8ms VBlanking 2lane 10bit (Scaling)
+ */
+#if ENABLE_NON_PREVIEW
+static struct ov5693_reg const ov5693_1940x1096[] = {
+ {OV5693_8BIT, 0x3501, 0x7b},
+ {OV5693_8BIT, 0x3502, 0x00},
+ {OV5693_8BIT, 0x3708, 0xe2},
+ {OV5693_8BIT, 0x3709, 0xc3},
+ {OV5693_8BIT, 0x3803, 0xf0},
+ {OV5693_8BIT, 0x3806, 0x06},
+ {OV5693_8BIT, 0x3807, 0xa7},
+ {OV5693_8BIT, 0x3808, 0x07},
+ {OV5693_8BIT, 0x3809, 0x94},
+ {OV5693_8BIT, 0x380a, 0x04},
+ {OV5693_8BIT, 0x380b, 0x48},
+ {OV5693_8BIT, 0x380c, 0x0a},
+ {OV5693_8BIT, 0x380d, 0x80},
+ {OV5693_8BIT, 0x380e, 0x07},
+ {OV5693_8BIT, 0x380f, 0xc0},
+ {OV5693_8BIT, 0x3811, 0x02},
+ {OV5693_8BIT, 0x3813, 0x02},
+ {OV5693_8BIT, 0x3814, 0x11},
+ {OV5693_8BIT, 0x3815, 0x11},
+ {OV5693_8BIT, 0x3820, 0x00},
+ {OV5693_8BIT, 0x3821, 0x1e},
+ {OV5693_8BIT, 0x5002, 0x80},
+ {OV5693_8BIT, 0x0100, 0x01},
+ {OV5693_TOK_TERM, 0, 0}
+};
+
+static struct ov5693_reg const ov5693_2592x1456_30fps[] = {
+ {OV5693_8BIT, 0x3501, 0x7b},
+ {OV5693_8BIT, 0x3502, 0x00},
+ {OV5693_8BIT, 0x3708, 0xe2},
+ {OV5693_8BIT, 0x3709, 0xc3},
+ {OV5693_8BIT, 0x3800, 0x00},
+ {OV5693_8BIT, 0x3801, 0x00},
+ {OV5693_8BIT, 0x3802, 0x00},
+ {OV5693_8BIT, 0x3803, 0xf0},
+ {OV5693_8BIT, 0x3804, 0x0a},
+ {OV5693_8BIT, 0x3805, 0x3f},
+ {OV5693_8BIT, 0x3806, 0x06},
+ {OV5693_8BIT, 0x3807, 0xa4},
+ {OV5693_8BIT, 0x3808, 0x0a},
+ {OV5693_8BIT, 0x3809, 0x20},
+ {OV5693_8BIT, 0x380a, 0x05},
+ {OV5693_8BIT, 0x380b, 0xb0},
+ {OV5693_8BIT, 0x380c, 0x0a},
+ {OV5693_8BIT, 0x380d, 0x80},
+ {OV5693_8BIT, 0x380e, 0x07},
+ {OV5693_8BIT, 0x380f, 0xc0},
+ {OV5693_8BIT, 0x3811, 0x10},
+ {OV5693_8BIT, 0x3813, 0x00},
+ {OV5693_8BIT, 0x3814, 0x11},
+ {OV5693_8BIT, 0x3815, 0x11},
+ {OV5693_8BIT, 0x3820, 0x00},
+ {OV5693_8BIT, 0x3821, 0x1e},
+ {OV5693_8BIT, 0x5002, 0x00},
+ {OV5693_TOK_TERM, 0, 0}
+};
+#endif
+
+static struct ov5693_reg const ov5693_2576x1456_30fps[] = {
+ {OV5693_8BIT, 0x3501, 0x7b},
+ {OV5693_8BIT, 0x3502, 0x00},
+ {OV5693_8BIT, 0x3708, 0xe2},
+ {OV5693_8BIT, 0x3709, 0xc3},
+ {OV5693_8BIT, 0x3800, 0x00},
+ {OV5693_8BIT, 0x3801, 0x00},
+ {OV5693_8BIT, 0x3802, 0x00},
+ {OV5693_8BIT, 0x3803, 0xf0},
+ {OV5693_8BIT, 0x3804, 0x0a},
+ {OV5693_8BIT, 0x3805, 0x3f},
+ {OV5693_8BIT, 0x3806, 0x06},
+ {OV5693_8BIT, 0x3807, 0xa4},
+ {OV5693_8BIT, 0x3808, 0x0a},
+ {OV5693_8BIT, 0x3809, 0x10},
+ {OV5693_8BIT, 0x380a, 0x05},
+ {OV5693_8BIT, 0x380b, 0xb0},
+ {OV5693_8BIT, 0x380c, 0x0a},
+ {OV5693_8BIT, 0x380d, 0x80},
+ {OV5693_8BIT, 0x380e, 0x07},
+ {OV5693_8BIT, 0x380f, 0xc0},
+ {OV5693_8BIT, 0x3811, 0x18},
+ {OV5693_8BIT, 0x3813, 0x00},
+ {OV5693_8BIT, 0x3814, 0x11},
+ {OV5693_8BIT, 0x3815, 0x11},
+ {OV5693_8BIT, 0x3820, 0x00},
+ {OV5693_8BIT, 0x3821, 0x1e},
+ {OV5693_8BIT, 0x5002, 0x00},
+ {OV5693_TOK_TERM, 0, 0}
+};
+
+/*
+ * 2592x1944 30fps 0.6ms VBlanking 2lane 10Bit
+ */
+#if ENABLE_NON_PREVIEW
+static struct ov5693_reg const ov5693_2592x1944_30fps[] = {
+ {OV5693_8BIT, 0x3501, 0x7b},
+ {OV5693_8BIT, 0x3502, 0x00},
+ {OV5693_8BIT, 0x3708, 0xe2},
+ {OV5693_8BIT, 0x3709, 0xc3},
+ {OV5693_8BIT, 0x3803, 0x00},
+ {OV5693_8BIT, 0x3806, 0x07},
+ {OV5693_8BIT, 0x3807, 0xa3},
+ {OV5693_8BIT, 0x3808, 0x0a},
+ {OV5693_8BIT, 0x3809, 0x20},
+ {OV5693_8BIT, 0x380a, 0x07},
+ {OV5693_8BIT, 0x380b, 0x98},
+ {OV5693_8BIT, 0x380c, 0x0a},
+ {OV5693_8BIT, 0x380d, 0x80},
+ {OV5693_8BIT, 0x380e, 0x07},
+ {OV5693_8BIT, 0x380f, 0xc0},
+ {OV5693_8BIT, 0x3811, 0x10},
+ {OV5693_8BIT, 0x3813, 0x00},
+ {OV5693_8BIT, 0x3814, 0x11},
+ {OV5693_8BIT, 0x3815, 0x11},
+ {OV5693_8BIT, 0x3820, 0x00},
+ {OV5693_8BIT, 0x3821, 0x1e},
+ {OV5693_8BIT, 0x5002, 0x00},
+ {OV5693_8BIT, 0x0100, 0x01},
+ {OV5693_TOK_TERM, 0, 0}
+};
+#endif
+
+/*
+ * 11:9 Full FOV Output, expected FOV Res: 2346x1920
+ * ISP Effect Res: 1408x1152
+ * Sensor out: 1424x1168, DS From: 2380x1952
+ *
+ * WA: Left Offset: 8, Hor scal: 64
+ */
+#if ENABLE_NON_PREVIEW
+static struct ov5693_reg const ov5693_1424x1168_30fps[] = {
+ {OV5693_8BIT, 0x3501, 0x3b}, /* long exposure[15:8] */
+ {OV5693_8BIT, 0x3502, 0x80}, /* long exposure[7:0] */
+ {OV5693_8BIT, 0x3708, 0xe2},
+ {OV5693_8BIT, 0x3709, 0xc3},
+ {OV5693_8BIT, 0x3800, 0x00}, /* TIMING_X_ADDR_START */
+ {OV5693_8BIT, 0x3801, 0x50}, /* 80 */
+ {OV5693_8BIT, 0x3802, 0x00}, /* TIMING_Y_ADDR_START */
+ {OV5693_8BIT, 0x3803, 0x02}, /* 2 */
+ {OV5693_8BIT, 0x3804, 0x09}, /* TIMING_X_ADDR_END */
+ {OV5693_8BIT, 0x3805, 0xdd}, /* 2525 */
+ {OV5693_8BIT, 0x3806, 0x07}, /* TIMING_Y_ADDR_END */
+ {OV5693_8BIT, 0x3807, 0xa1}, /* 1953 */
+ {OV5693_8BIT, 0x3808, 0x05}, /* TIMING_X_OUTPUT_SIZE */
+ {OV5693_8BIT, 0x3809, 0x90}, /* 1424 */
+ {OV5693_8BIT, 0x380a, 0x04}, /* TIMING_Y_OUTPUT_SIZE */
+ {OV5693_8BIT, 0x380b, 0x90}, /* 1168 */
+ {OV5693_8BIT, 0x380c, 0x0a}, /* TIMING_HTS */
+ {OV5693_8BIT, 0x380d, 0x80},
+ {OV5693_8BIT, 0x380e, 0x07}, /* TIMING_VTS */
+ {OV5693_8BIT, 0x380f, 0xc0},
+ {OV5693_8BIT, 0x3810, 0x00}, /* TIMING_ISP_X_WIN */
+ {OV5693_8BIT, 0x3811, 0x02}, /* 2 */
+ {OV5693_8BIT, 0x3812, 0x00}, /* TIMING_ISP_Y_WIN */
+ {OV5693_8BIT, 0x3813, 0x00}, /* 0 */
+ {OV5693_8BIT, 0x3814, 0x11}, /* TIME_X_INC */
+ {OV5693_8BIT, 0x3815, 0x11}, /* TIME_Y_INC */
+ {OV5693_8BIT, 0x3820, 0x00},
+ {OV5693_8BIT, 0x3821, 0x1e},
+ {OV5693_8BIT, 0x5002, 0x00},
+ {OV5693_8BIT, 0x5041, 0x84}, /* scale is auto enabled */
+ {OV5693_8BIT, 0x0100, 0x01},
+ {OV5693_TOK_TERM, 0, 0}
+};
+#endif
+
+/*
+ * 3:2 Full FOV Output, expected FOV Res: 2560x1706
+ * ISP Effect Res: 720x480
+ * Sensor out: 736x496, DS From 2616x1764
+ */
+static struct ov5693_reg const ov5693_736x496_30fps[] = {
+ {OV5693_8BIT, 0x3501, 0x3b}, /* long exposure[15:8] */
+ {OV5693_8BIT, 0x3502, 0x80}, /* long exposure[7:0] */
+ {OV5693_8BIT, 0x3708, 0xe2},
+ {OV5693_8BIT, 0x3709, 0xc3},
+ {OV5693_8BIT, 0x3800, 0x00}, /* TIMING_X_ADDR_START */
+ {OV5693_8BIT, 0x3801, 0x02}, /* 2 */
+ {OV5693_8BIT, 0x3802, 0x00}, /* TIMING_Y_ADDR_START */
+ {OV5693_8BIT, 0x3803, 0x62}, /* 98 */
+ {OV5693_8BIT, 0x3804, 0x0a}, /* TIMING_X_ADDR_END */
+ {OV5693_8BIT, 0x3805, 0x3b}, /* 2619 */
+ {OV5693_8BIT, 0x3806, 0x07}, /* TIMING_Y_ADDR_END */
+ {OV5693_8BIT, 0x3807, 0x43}, /* 1859 */
+ {OV5693_8BIT, 0x3808, 0x02}, /* TIMING_X_OUTPUT_SIZE */
+ {OV5693_8BIT, 0x3809, 0xe0}, /* 736 */
+ {OV5693_8BIT, 0x380a, 0x01}, /* TIMING_Y_OUTPUT_SIZE */
+ {OV5693_8BIT, 0x380b, 0xf0}, /* 496 */
+ {OV5693_8BIT, 0x380c, 0x0a}, /* TIMING_HTS */
+ {OV5693_8BIT, 0x380d, 0x80},
+ {OV5693_8BIT, 0x380e, 0x07}, /* TIMING_VTS */
+ {OV5693_8BIT, 0x380f, 0xc0},
+ {OV5693_8BIT, 0x3810, 0x00}, /* TIMING_ISP_X_WIN */
+ {OV5693_8BIT, 0x3811, 0x02}, /* 2 */
+ {OV5693_8BIT, 0x3812, 0x00}, /* TIMING_ISP_Y_WIN */
+ {OV5693_8BIT, 0x3813, 0x00}, /* 0 */
+ {OV5693_8BIT, 0x3814, 0x11}, /* TIME_X_INC */
+ {OV5693_8BIT, 0x3815, 0x11}, /* TIME_Y_INC */
+ {OV5693_8BIT, 0x3820, 0x00},
+ {OV5693_8BIT, 0x3821, 0x1e},
+ {OV5693_8BIT, 0x5002, 0x00},
+ {OV5693_8BIT, 0x5041, 0x84}, /* scale is auto enabled */
+ {OV5693_8BIT, 0x0100, 0x01},
+ {OV5693_TOK_TERM, 0, 0}
+};
+
+static struct ov5693_reg const ov5693_2576x1936_30fps[] = {
+ {OV5693_8BIT, 0x3501, 0x7b},
+ {OV5693_8BIT, 0x3502, 0x00},
+ {OV5693_8BIT, 0x3708, 0xe2},
+ {OV5693_8BIT, 0x3709, 0xc3},
+ {OV5693_8BIT, 0x3803, 0x00},
+ {OV5693_8BIT, 0x3806, 0x07},
+ {OV5693_8BIT, 0x3807, 0xa3},
+ {OV5693_8BIT, 0x3808, 0x0a},
+ {OV5693_8BIT, 0x3809, 0x10},
+ {OV5693_8BIT, 0x380a, 0x07},
+ {OV5693_8BIT, 0x380b, 0x90},
+ {OV5693_8BIT, 0x380c, 0x0a},
+ {OV5693_8BIT, 0x380d, 0x80},
+ {OV5693_8BIT, 0x380e, 0x07},
+ {OV5693_8BIT, 0x380f, 0xc0},
+ {OV5693_8BIT, 0x3811, 0x18},
+ {OV5693_8BIT, 0x3813, 0x00},
+ {OV5693_8BIT, 0x3814, 0x11},
+ {OV5693_8BIT, 0x3815, 0x11},
+ {OV5693_8BIT, 0x3820, 0x00},
+ {OV5693_8BIT, 0x3821, 0x1e},
+ {OV5693_8BIT, 0x5002, 0x00},
+ {OV5693_8BIT, 0x0100, 0x01},
+ {OV5693_TOK_TERM, 0, 0}
+};
+
+static struct ov5693_resolution ov5693_res_preview[] = {
+ {
+ .desc = "ov5693_736x496_30fps",
+ .width = 736,
+ .height = 496,
+ .pix_clk_freq = 160,
+ .fps = 30,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 1,
+ .bin_factor_y = 1,
+ .bin_mode = 0,
+ .regs = ov5693_736x496_30fps,
+ },
+ {
+ .desc = "ov5693_1616x1216_30fps",
+ .width = 1616,
+ .height = 1216,
+ .pix_clk_freq = 160,
+ .fps = 30,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 1,
+ .bin_factor_y = 1,
+ .bin_mode = 0,
+ .regs = ov5693_1616x1216_30fps,
+ },
+ {
+ .desc = "ov5693_5M_30fps",
+ .width = 2576,
+ .height = 1456,
+ .pix_clk_freq = 160,
+ .fps = 30,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 1,
+ .bin_factor_y = 1,
+ .bin_mode = 0,
+ .regs = ov5693_2576x1456_30fps,
+ },
+ {
+ .desc = "ov5693_5M_30fps",
+ .width = 2576,
+ .height = 1936,
+ .pix_clk_freq = 160,
+ .fps = 30,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 1,
+ .bin_factor_y = 1,
+ .bin_mode = 0,
+ .regs = ov5693_2576x1936_30fps,
+ },
+};
+
+#define N_RES_PREVIEW (ARRAY_SIZE(ov5693_res_preview))
+
+/*
+ * Disable non-preview configurations until the configuration selection is
+ * improved.
+ */
+#if ENABLE_NON_PREVIEW
+struct ov5693_resolution ov5693_res_still[] = {
+ {
+ .desc = "ov5693_736x496_30fps",
+ .width = 736,
+ .height = 496,
+ .pix_clk_freq = 160,
+ .fps = 30,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 1,
+ .bin_factor_y = 1,
+ .bin_mode = 0,
+ .regs = ov5693_736x496_30fps,
+ },
+ {
+ .desc = "ov5693_1424x1168_30fps",
+ .width = 1424,
+ .height = 1168,
+ .pix_clk_freq = 160,
+ .fps = 30,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 1,
+ .bin_factor_y = 1,
+ .bin_mode = 0,
+ .regs = ov5693_1424x1168_30fps,
+ },
+ {
+ .desc = "ov5693_1616x1216_30fps",
+ .width = 1616,
+ .height = 1216,
+ .pix_clk_freq = 160,
+ .fps = 30,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 1,
+ .bin_factor_y = 1,
+ .bin_mode = 0,
+ .regs = ov5693_1616x1216_30fps,
+ },
+ {
+ .desc = "ov5693_5M_30fps",
+ .width = 2592,
+ .height = 1456,
+ .pix_clk_freq = 160,
+ .fps = 30,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 1,
+ .bin_factor_y = 1,
+ .bin_mode = 0,
+ .regs = ov5693_2592x1456_30fps,
+ },
+ {
+ .desc = "ov5693_5M_30fps",
+ .width = 2592,
+ .height = 1944,
+ .pix_clk_freq = 160,
+ .fps = 30,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 1,
+ .bin_factor_y = 1,
+ .bin_mode = 0,
+ .regs = ov5693_2592x1944_30fps,
+ },
+};
+
+#define N_RES_STILL (ARRAY_SIZE(ov5693_res_still))
+
+struct ov5693_resolution ov5693_res_video[] = {
+ {
+ .desc = "ov5693_736x496_30fps",
+ .width = 736,
+ .height = 496,
+ .fps = 30,
+ .pix_clk_freq = 160,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 2,
+ .bin_factor_y = 2,
+ .bin_mode = 1,
+ .regs = ov5693_736x496,
+ },
+ {
+ .desc = "ov5693_336x256_30fps",
+ .width = 336,
+ .height = 256,
+ .fps = 30,
+ .pix_clk_freq = 160,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 2,
+ .bin_factor_y = 2,
+ .bin_mode = 1,
+ .regs = ov5693_336x256,
+ },
+ {
+ .desc = "ov5693_368x304_30fps",
+ .width = 368,
+ .height = 304,
+ .fps = 30,
+ .pix_clk_freq = 160,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 2,
+ .bin_factor_y = 2,
+ .bin_mode = 1,
+ .regs = ov5693_368x304,
+ },
+ {
+ .desc = "ov5693_192x160_30fps",
+ .width = 192,
+ .height = 160,
+ .fps = 30,
+ .pix_clk_freq = 160,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 2,
+ .bin_factor_y = 2,
+ .bin_mode = 1,
+ .regs = ov5693_192x160,
+ },
+ {
+ .desc = "ov5693_1296x736_30fps",
+ .width = 1296,
+ .height = 736,
+ .fps = 30,
+ .pix_clk_freq = 160,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 2,
+ .bin_factor_y = 2,
+ .bin_mode = 0,
+ .regs = ov5693_1296x736,
+ },
+ {
+ .desc = "ov5693_1296x976_30fps",
+ .width = 1296,
+ .height = 976,
+ .fps = 30,
+ .pix_clk_freq = 160,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 2,
+ .bin_factor_y = 2,
+ .bin_mode = 0,
+ .regs = ov5693_1296x976,
+ },
+ {
+ .desc = "ov5693_1636P_30fps",
+ .width = 1636,
+ .height = 1096,
+ .fps = 30,
+ .pix_clk_freq = 160,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 1,
+ .bin_factor_y = 1,
+ .bin_mode = 0,
+ .regs = ov5693_1636p_30fps,
+ },
+ {
+ .desc = "ov5693_1080P_30fps",
+ .width = 1940,
+ .height = 1096,
+ .fps = 30,
+ .pix_clk_freq = 160,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 1,
+ .bin_factor_y = 1,
+ .bin_mode = 0,
+ .regs = ov5693_1940x1096,
+ },
+ {
+ .desc = "ov5693_5M_30fps",
+ .width = 2592,
+ .height = 1456,
+ .pix_clk_freq = 160,
+ .fps = 30,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 1,
+ .bin_factor_y = 1,
+ .bin_mode = 0,
+ .regs = ov5693_2592x1456_30fps,
+ },
+ {
+ .desc = "ov5693_5M_30fps",
+ .width = 2592,
+ .height = 1944,
+ .pix_clk_freq = 160,
+ .fps = 30,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 1,
+ .bin_factor_y = 1,
+ .bin_mode = 0,
+ .regs = ov5693_2592x1944_30fps,
+ .crop = {
+ .left = 0,
+ .top = 0,
+ .width = 2592,
+ .height = 1944
+ },
+ },
+};
+
+#define N_RES_VIDEO (ARRAY_SIZE(ov5693_res_video))
+#endif
+
+static struct ov5693_resolution *ov5693_res = ov5693_res_video;
+static unsigned long N_RES = N_RES_VIDEO;
+#endif
--
2.32.0
From f615ea80c2456314f874eea6b48512e14c3058d7 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sun, 17 Jan 2021 19:08:18 +0000
Subject: [PATCH] media: i2c: Add reset pin toggling to ov5693
The ov5693 has an xshutdown pin which can be present and, if so, needs
toggling as part of power on sequence.
Add calls to handle the reset GPIO
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index 32485e4ed42b..f9ced52ad37a 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -1085,6 +1085,8 @@ static int __power_up(struct v4l2_subdev *sd)
if (ret)
goto fail_power;
+ gpiod_set_value_cansleep(sensor->reset, 0);
+
__cci_delay(up_delay);
return 0;
@@ -1103,6 +1105,8 @@ static int power_down(struct v4l2_subdev *sd)
dev->focus = OV5693_INVALID_CONFIG;
+ gpiod_set_value_cansleep(sensor->reset, 1);
+
clk_disable_unprepare(dev->clk);
if (dev->indicator_led)
--
2.32.0
From 1b3b4d04e4ae339d1e57cc01272109c1a2468ff9 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sun, 17 Jan 2021 21:39:15 +0000
Subject: [PATCH] media: i2c: Fix misnamed variable in power_down() for ov5693
Fix the misnamed variable in gpiod_set_value_cansleep().
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index f9ced52ad37a..9fd44a3d1d85 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -1105,7 +1105,7 @@ static int power_down(struct v4l2_subdev *sd)
dev->focus = OV5693_INVALID_CONFIG;
- gpiod_set_value_cansleep(sensor->reset, 1);
+ gpiod_set_value_cansleep(dev->reset, 1);
clk_disable_unprepare(dev->clk);
--
2.32.0
From efbaab144c4c329017759731a2e13dee0db58025 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fabian=20W=C3=BCthrich?= <me@fabwu.ch>
Date: Fri, 22 Jan 2021 20:58:13 +0100
Subject: [PATCH] cio2-bridge: Parse sensor orientation and rotation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The sensor orientation is read from the _PLC ACPI buffer and converted
to a v4l2 format.
See https://uefi.org/sites/default/files/resources/ACPI_6_3_final_Jan30.pdf
page 351 for a definition of the Panel property.
The sensor rotation is read from the SSDB ACPI buffer and converted into
degrees.
Signed-off-by: Fabian Wüthrich <me@fabwu.ch>
Patchset: cameras
---
drivers/media/pci/intel/ipu3/cio2-bridge.c | 45 ++++++++++++++++++++--
drivers/media/pci/intel/ipu3/cio2-bridge.h | 3 ++
2 files changed, 44 insertions(+), 4 deletions(-)
diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.c b/drivers/media/pci/intel/ipu3/cio2-bridge.c
index 143f3c0f445e..806d4e5fc177 100644
--- a/drivers/media/pci/intel/ipu3/cio2-bridge.c
+++ b/drivers/media/pci/intel/ipu3/cio2-bridge.c
@@ -29,6 +29,7 @@ static const struct cio2_sensor_config cio2_supported_sensors[] = {
static const struct cio2_property_names prop_names = {
.clock_frequency = "clock-frequency",
.rotation = "rotation",
+ .orientation = "orientation",
.bus_type = "bus-type",
.data_lanes = "data-lanes",
.remote_endpoint = "remote-endpoint",
@@ -72,11 +73,36 @@ static int cio2_bridge_read_acpi_buffer(struct acpi_device *adev, char *id,
return ret;
}
+static u32 cio2_bridge_parse_rotation(u8 rotation)
+{
+ if (rotation == 1)
+ return 180;
+ return 0;
+}
+
+static enum v4l2_fwnode_orientation cio2_bridge_parse_orientation(u8 panel)
+{
+ switch (panel) {
+ case 4:
+ return V4L2_FWNODE_ORIENTATION_FRONT;
+ case 5:
+ return V4L2_FWNODE_ORIENTATION_BACK;
+ default:
+ return V4L2_FWNODE_ORIENTATION_EXTERNAL;
+ }
+}
+
static void cio2_bridge_create_fwnode_properties(
struct cio2_sensor *sensor,
struct cio2_bridge *bridge,
const struct cio2_sensor_config *cfg)
{
+ u32 rotation;
+ enum v4l2_fwnode_orientation orientation;
+
+ rotation = cio2_bridge_parse_rotation(sensor->ssdb.degree);
+ orientation = cio2_bridge_parse_orientation(sensor->pld->panel);
+
sensor->prop_names = prop_names;
sensor->local_ref[0].node = &sensor->swnodes[SWNODE_CIO2_ENDPOINT];
@@ -85,9 +111,12 @@ static void cio2_bridge_create_fwnode_properties(
sensor->dev_properties[0] = PROPERTY_ENTRY_U32(
sensor->prop_names.clock_frequency,
sensor->ssdb.mclkspeed);
- sensor->dev_properties[1] = PROPERTY_ENTRY_U8(
+ sensor->dev_properties[1] = PROPERTY_ENTRY_U32(
sensor->prop_names.rotation,
- sensor->ssdb.degree);
+ rotation);
+ sensor->dev_properties[2] = PROPERTY_ENTRY_U32(
+ sensor->prop_names.orientation,
+ orientation);
sensor->ep_properties[0] = PROPERTY_ENTRY_U32(
sensor->prop_names.bus_type,
@@ -159,6 +188,7 @@ static void cio2_bridge_unregister_sensors(struct cio2_bridge *bridge)
for (i = 0; i < bridge->n_sensors; i++) {
sensor = &bridge->sensors[i];
software_node_unregister_nodes(sensor->swnodes);
+ ACPI_FREE(sensor->pld);
acpi_dev_put(sensor->adev);
}
}
@@ -170,6 +200,7 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
struct fwnode_handle *fwnode;
struct cio2_sensor *sensor;
struct acpi_device *adev;
+ acpi_status status;
int ret;
for_each_acpi_dev_match(adev, cfg->hid, NULL, -1) {
@@ -193,11 +224,15 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
if (ret)
goto err_put_adev;
+ status = acpi_get_physical_device_location(adev->handle, &sensor->pld);
+ if (ACPI_FAILURE(status))
+ goto err_put_adev;
+
if (sensor->ssdb.lanes > CIO2_MAX_LANES) {
dev_err(&adev->dev,
"Number of lanes in SSDB is invalid\n");
ret = -EINVAL;
- goto err_put_adev;
+ goto err_free_pld;
}
cio2_bridge_create_fwnode_properties(sensor, bridge, cfg);
@@ -205,7 +240,7 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
ret = software_node_register_nodes(sensor->swnodes);
if (ret)
- goto err_put_adev;
+ goto err_free_pld;
fwnode = software_node_fwnode(&sensor->swnodes[SWNODE_SENSOR_HID]);
if (!fwnode) {
@@ -225,6 +260,8 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg,
err_free_swnodes:
software_node_unregister_nodes(sensor->swnodes);
+err_free_pld:
+ ACPI_FREE(sensor->pld);
err_put_adev:
acpi_dev_put(sensor->adev);
err_out:
diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.h b/drivers/media/pci/intel/ipu3/cio2-bridge.h
index dd0ffcafa489..924d99d20328 100644
--- a/drivers/media/pci/intel/ipu3/cio2-bridge.h
+++ b/drivers/media/pci/intel/ipu3/cio2-bridge.h
@@ -80,6 +80,7 @@ struct cio2_sensor_ssdb {
struct cio2_property_names {
char clock_frequency[16];
char rotation[9];
+ char orientation[12];
char bus_type[9];
char data_lanes[11];
char remote_endpoint[16];
@@ -106,6 +107,8 @@ struct cio2_sensor {
struct cio2_node_names node_names;
struct cio2_sensor_ssdb ssdb;
+ struct acpi_pld_info *pld;
+
struct cio2_property_names prop_names;
struct property_entry ep_properties[5];
struct property_entry dev_properties[3];
--
2.32.0
From 1f1657a10fd29b520c2d80d946a2c9271d16c81b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fabian=20W=C3=BCthrich?= <me@fabwu.ch>
Date: Fri, 22 Jan 2021 21:23:47 +0100
Subject: [PATCH] ov5693: Add orientation and rotation controls
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Parse orientation and rotation from fwnodes and initialize the
respective controls.
Signed-off-by: Fabian Wüthrich <me@fabwu.ch>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index 9fd44a3d1d85..1a85800df7ed 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -31,6 +31,7 @@
#include <linux/i2c.h>
#include <linux/moduleparam.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
#include <linux/io.h>
#include <linux/acpi.h>
#include <linux/regulator/consumer.h>
@@ -1608,6 +1609,7 @@ static int ov5693_init_controls(struct ov5693_device *ov5693)
{
struct i2c_client *client = v4l2_get_subdevdata(&ov5693->sd);
const struct v4l2_ctrl_ops *ops = &ov5693_ctrl_ops;
+ struct v4l2_fwnode_device_properties props;
struct v4l2_ctrl *ctrl;
unsigned int i;
int ret;
@@ -1663,6 +1665,15 @@ static int ov5693_init_controls(struct ov5693_device *ov5693)
if (ov5693->hblank)
ov5693->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ /* set properties from fwnode (e.g. rotation, orientation) */
+ ret = v4l2_fwnode_device_parse(&client->dev, &props);
+ if (ret)
+ return ret;
+
+ ret = v4l2_ctrl_new_fwnode_properties(&ov5693->ctrl_handler, ops, &props);
+ if (ret)
+ return ret;
+
/* Use same lock for controls as for everything else. */
ov5693->ctrl_handler.lock = &ov5693->input_lock;
ov5693->sd.ctrl_handler = &ov5693->ctrl_handler;
--
2.32.0
From 2a609a8dd131f7bc04a36487476dabfefa3d955d Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sat, 23 Jan 2021 00:28:32 +0000
Subject: [PATCH] platform: x86: Stylistic updates for intel-skl-int3472
This commit makes a bunch of stylistic updates, minor changes and other
stuff that's part of the improvements pass I'm doing to the code after
taking into account feedback from the list.
It also alters the ACPI buffer fetching code to be more generalisable so
I can re-use it to fetch the clock frequency.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
.../platform/x86/intel_skl_int3472_common.c | 37 ++++---
.../platform/x86/intel_skl_int3472_common.h | 7 +-
.../platform/x86/intel_skl_int3472_discrete.c | 101 +++++++++---------
.../platform/x86/intel_skl_int3472_tps68470.c | 16 +--
4 files changed, 89 insertions(+), 72 deletions(-)
diff --git a/drivers/platform/x86/intel_skl_int3472_common.c b/drivers/platform/x86/intel_skl_int3472_common.c
index 08cb9d3c06aa..549d211979e1 100644
--- a/drivers/platform/x86/intel_skl_int3472_common.c
+++ b/drivers/platform/x86/intel_skl_int3472_common.c
@@ -7,41 +7,52 @@
#include "intel_skl_int3472_common.h"
-int skl_int3472_get_cldb_buffer(struct acpi_device *adev,
- struct int3472_cldb *cldb)
+union acpi_object *skl_int3472_get_acpi_buffer(struct acpi_device *adev,
+ char *id)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
acpi_handle handle = adev->handle;
union acpi_object *obj;
acpi_status status;
- int ret = 0;
- status = acpi_evaluate_object(handle, "CLDB", NULL, &buffer);
+ status = acpi_evaluate_object(handle, id, NULL, &buffer);
if (ACPI_FAILURE(status))
- return -ENODEV;
+ return ERR_PTR(-ENODEV);
obj = buffer.pointer;
if (!obj) {
- dev_err(&adev->dev, "ACPI device has no CLDB object\n");
- return -ENODEV;
+ dev_err(&adev->dev, "ACPI device has no %s object\n", id);
+ return ERR_PTR(-ENODEV);
}
if (obj->type != ACPI_TYPE_BUFFER) {
- dev_err(&adev->dev, "CLDB object is not an ACPI buffer\n");
- ret = -EINVAL;
- goto out_free_buff;
+ dev_err(&adev->dev, "%s object is not an ACPI buffer\n", id);
+ kfree(obj);
+ return ERR_PTR(-EINVAL);
}
+ return obj;
+}
+
+int skl_int3472_fill_cldb(struct acpi_device *adev, struct int3472_cldb *cldb)
+{
+ union acpi_object *obj;
+ int ret = 0;
+
+ obj = skl_int3472_get_acpi_buffer(adev, "CLDB");
+ if (IS_ERR(obj))
+ return PTR_ERR(obj);
+
if (obj->buffer.length > sizeof(*cldb)) {
dev_err(&adev->dev, "The CLDB buffer is too large\n");
ret = -EINVAL;
- goto out_free_buff;
+ goto out_free_obj;
}
memcpy(cldb, obj->buffer.pointer, obj->buffer.length);
-out_free_buff:
- kfree(buffer.pointer);
+out_free_obj:
+ kfree(obj);
return ret;
}
diff --git a/drivers/platform/x86/intel_skl_int3472_common.h b/drivers/platform/x86/intel_skl_int3472_common.h
index 4ac6bb2b223f..e1083bb67dc6 100644
--- a/drivers/platform/x86/intel_skl_int3472_common.h
+++ b/drivers/platform/x86/intel_skl_int3472_common.h
@@ -29,7 +29,7 @@
#define INT3472_GPIO_FUNCTION_REMAP(_PIN, _FUNCTION) \
(const struct int3472_gpio_function_remap) { \
- .documented = _PIN, \
+ .documented = _PIN, \
.actual = _FUNCTION \
}
@@ -95,5 +95,6 @@ struct int3472_sensor_config {
int skl_int3472_discrete_probe(struct platform_device *pdev);
int skl_int3472_discrete_remove(struct platform_device *pdev);
int skl_int3472_tps68470_probe(struct i2c_client *client);
-int skl_int3472_get_cldb_buffer(struct acpi_device *adev,
- struct int3472_cldb *cldb);
+union acpi_object *skl_int3472_get_acpi_buffer(struct acpi_device *adev,
+ char *id);
+int skl_int3472_fill_cldb(struct acpi_device *adev, struct int3472_cldb *cldb);
diff --git a/drivers/platform/x86/intel_skl_int3472_discrete.c b/drivers/platform/x86/intel_skl_int3472_discrete.c
index ea7e57f3e3f0..42ae8396eb64 100644
--- a/drivers/platform/x86/intel_skl_int3472_discrete.c
+++ b/drivers/platform/x86/intel_skl_int3472_discrete.c
@@ -12,12 +12,12 @@
#include "intel_skl_int3472_common.h"
-/* 79234640-9e10-4fea-a5c1b5aa8b19756f */
+/* 79234640-9e10-4fea-a5c1-b5aa8b19756f */
static const guid_t int3472_gpio_guid =
GUID_INIT(0x79234640, 0x9e10, 0x4fea,
0xa5, 0xc1, 0xb5, 0xaa, 0x8b, 0x19, 0x75, 0x6f);
-/* 822ace8f-2814-4174-a56b5f029fe079ee */
+/* 822ace8f-2814-4174-a56b-5f029fe079ee */
static const guid_t cio2_sensor_module_guid =
GUID_INIT(0x822ace8f, 0x2814, 0x4174,
0xa5, 0x6b, 0x5f, 0x02, 0x9f, 0xe0, 0x79, 0xee);
@@ -94,7 +94,7 @@ static const struct clk_ops skl_int3472_clock_ops = {
};
static struct int3472_sensor_config *
-int3472_get_sensor_module_config(struct int3472_device *int3472)
+skl_int3472_get_sensor_module_config(struct int3472_device *int3472)
{
unsigned int i = ARRAY_SIZE(int3472_sensor_configs);
struct int3472_sensor_config *ret;
@@ -131,9 +131,9 @@ int3472_get_sensor_module_config(struct int3472_device *int3472)
return ret;
}
-static int int3472_map_gpio_to_sensor(struct int3472_device *int3472,
- struct acpi_resource *ares,
- char *func, u32 polarity)
+static int skl_int3472_map_gpio_to_sensor(struct int3472_device *int3472,
+ struct acpi_resource *ares,
+ char *func, u32 polarity)
{
char *path = ares->data.gpio.resource_source.string_ptr;
struct int3472_sensor_config *sensor_config;
@@ -143,7 +143,7 @@ static int int3472_map_gpio_to_sensor(struct int3472_device *int3472,
acpi_status status;
int ret;
- sensor_config = int3472_get_sensor_module_config(int3472);
+ sensor_config = skl_int3472_get_sensor_module_config(int3472);
if (!IS_ERR(sensor_config) && sensor_config->function_maps) {
unsigned int i = 0;
@@ -186,17 +186,19 @@ static int int3472_map_gpio_to_sensor(struct int3472_device *int3472,
return 0;
}
-static int int3472_register_clock(struct int3472_device *int3472,
- struct acpi_resource *ares)
+static int skl_int3472_register_clock(struct int3472_device *int3472,
+ struct acpi_resource *ares)
{
char *path = ares->data.gpio.resource_source.string_ptr;
- struct clk_init_data init = { };
+ struct clk_init_data init = { 0 };
int ret = 0;
- init.name = kasprintf(GFP_KERNEL, "%s-clk", acpi_dev_name(int3472->adev));
+ init.name = kasprintf(GFP_KERNEL, "%s-clk",
+ acpi_dev_name(int3472->adev));
init.ops = &skl_int3472_clock_ops;
- int3472->clock.gpio = acpi_get_gpiod(path, ares->data.gpio.pin_table[0]);
+ int3472->clock.gpio = acpi_get_gpiod(path,
+ ares->data.gpio.pin_table[0]);
if (IS_ERR(int3472->clock.gpio)) {
ret = PTR_ERR(int3472->clock.gpio);
goto out_free_init_name;
@@ -226,17 +228,16 @@ static int int3472_register_clock(struct int3472_device *int3472,
return ret;
}
-static int int3472_register_regulator(struct int3472_device *int3472,
- struct acpi_resource *ares)
+static int skl_int3472_register_regulator(struct int3472_device *int3472,
+ struct acpi_resource *ares)
{
char *path = ares->data.gpio.resource_source.string_ptr;
struct int3472_sensor_config *sensor_config;
struct regulator_init_data init_data = { };
- struct int3472_gpio_regulator *regulator;
struct regulator_config cfg = { };
int ret;
- sensor_config = int3472_get_sensor_module_config(int3472);
+ sensor_config = skl_int3472_get_sensor_module_config(int3472);
if (IS_ERR_OR_NULL(sensor_config)) {
dev_err(&int3472->pdev->dev, "No sensor module config\n");
return PTR_ERR(sensor_config);
@@ -252,26 +253,29 @@ static int int3472_register_regulator(struct int3472_device *int3472,
init_data.num_consumer_supplies = 1;
init_data.consumer_supplies = &sensor_config->supply_map;
- snprintf(int3472->regulator.regulator_name, GPIO_REGULATOR_NAME_LENGTH,
- "int3472-discrete-regulator");
- snprintf(int3472->regulator.supply_name, GPIO_REGULATOR_SUPPLY_NAME_LENGTH,
- "supply-0");
+ snprintf(int3472->regulator.regulator_name,
+ GPIO_REGULATOR_NAME_LENGTH, "int3472-discrete-regulator");
+ snprintf(int3472->regulator.supply_name,
+ GPIO_REGULATOR_SUPPLY_NAME_LENGTH, "supply-0");
- int3472->regulator.rdesc = INT3472_REGULATOR(int3472->regulator.regulator_name,
- int3472->regulator.supply_name,
- &int3472_gpio_regulator_ops);
+ int3472->regulator.rdesc = INT3472_REGULATOR(
+ int3472->regulator.regulator_name,
+ int3472->regulator.supply_name,
+ &int3472_gpio_regulator_ops);
- int3472->regulator.gpio = acpi_get_gpiod(path, ares->data.gpio.pin_table[0]);
+ int3472->regulator.gpio = acpi_get_gpiod(path,
+ ares->data.gpio.pin_table[0]);
if (IS_ERR(int3472->regulator.gpio)) {
- ret = PTR_ERR(int3472->regulator.gpio);
- goto err_free_regulator;
+ dev_err(&int3472->pdev->dev, "Failed to get GPIO line\n");
+ return PTR_ERR(int3472->regulator.gpio);
}
cfg.dev = &int3472->adev->dev;
cfg.init_data = &init_data;
cfg.ena_gpiod = int3472->regulator.gpio;
- int3472->regulator.rdev = regulator_register(&int3472->regulator.rdesc, &cfg);
+ int3472->regulator.rdev = regulator_register(&int3472->regulator.rdesc,
+ &cfg);
if (IS_ERR(int3472->regulator.rdev)) {
ret = PTR_ERR(int3472->regulator.rdev);
goto err_free_gpio;
@@ -280,15 +284,13 @@ static int int3472_register_regulator(struct int3472_device *int3472,
return 0;
err_free_gpio:
- gpiod_put(regulator->gpio);
-err_free_regulator:
- kfree(regulator);
+ gpiod_put(int3472->regulator.gpio);
return ret;
}
/**
- * int3472_handle_gpio_resources: maps PMIC resources to consuming sensor
+ * skl_int3472_handle_gpio_resources: maps PMIC resources to consuming sensor
* @ares: A pointer to a &struct acpi_resource
* @data: A pointer to a &struct int3472_device
*
@@ -305,8 +307,9 @@ static int int3472_register_regulator(struct int3472_device *int3472,
*
* There are some known platform specific quirks where that does not quite
* hold up; for example where a pin with type 0x01 (Power down) is mapped to
- * a sensor pin that performs a reset function. These will be handled by the
- * mapping sub-functions.
+ * a sensor pin that performs a reset function or entries in _CRS and _DSM that
+ * do not actually correspond to a physical connection. These will be handled by
+ * the mapping sub-functions.
*
* GPIOs will either be mapped directly to the sensor device or else used
* to create clocks and regulators via the usual frameworks.
@@ -317,8 +320,8 @@ static int int3472_register_regulator(struct int3472_device *int3472,
* * -ENODEV - If the resource has no corresponding _DSM entry
* * -Other - Errors propagated from one of the sub-functions.
*/
-static int int3472_handle_gpio_resources(struct acpi_resource *ares,
- void *data)
+static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
+ void *data)
{
struct int3472_device *int3472 = data;
union acpi_object *obj;
@@ -345,30 +348,30 @@ static int int3472_handle_gpio_resources(struct acpi_resource *ares,
switch (obj->integer.value & 0xff) {
case INT3472_GPIO_TYPE_RESET:
- ret = int3472_map_gpio_to_sensor(int3472, ares, "reset",
- GPIO_ACTIVE_LOW);
+ ret = skl_int3472_map_gpio_to_sensor(int3472, ares, "reset",
+ GPIO_ACTIVE_LOW);
if (ret)
dev_err(&int3472->pdev->dev,
"Failed to map reset pin to sensor\n");
break;
case INT3472_GPIO_TYPE_POWERDOWN:
- ret = int3472_map_gpio_to_sensor(int3472, ares, "powerdown",
- GPIO_ACTIVE_LOW);
+ ret = skl_int3472_map_gpio_to_sensor(int3472, ares, "powerdown",
+ GPIO_ACTIVE_LOW);
if (ret)
dev_err(&int3472->pdev->dev,
"Failed to map powerdown pin to sensor\n");
break;
case INT3472_GPIO_TYPE_CLK_ENABLE:
- ret = int3472_register_clock(int3472, ares);
+ ret = skl_int3472_register_clock(int3472, ares);
if (ret)
dev_err(&int3472->pdev->dev,
"Failed to map clock to sensor\n");
break;
case INT3472_GPIO_TYPE_POWER_ENABLE:
- ret = int3472_register_regulator(int3472, ares);
+ ret = skl_int3472_register_regulator(int3472, ares);
if (ret) {
dev_err(&int3472->pdev->dev,
"Failed to map regulator to sensor\n");
@@ -376,8 +379,9 @@ static int int3472_handle_gpio_resources(struct acpi_resource *ares,
break;
case INT3472_GPIO_TYPE_PRIVACY_LED:
- ret = int3472_map_gpio_to_sensor(int3472, ares, "indicator-led",
- GPIO_ACTIVE_HIGH);
+ ret = skl_int3472_map_gpio_to_sensor(int3472, ares,
+ "indicator-led",
+ GPIO_ACTIVE_HIGH);
if (ret)
dev_err(&int3472->pdev->dev,
"Failed to map indicator led to sensor\n");
@@ -396,7 +400,7 @@ static int int3472_handle_gpio_resources(struct acpi_resource *ares,
return ret;
}
-static int int3472_parse_crs(struct int3472_device *int3472)
+static int skl_int3472_parse_crs(struct int3472_device *int3472)
{
struct list_head resource_list;
int ret = 0;
@@ -404,7 +408,8 @@ static int int3472_parse_crs(struct int3472_device *int3472)
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(int3472->adev, &resource_list,
- int3472_handle_gpio_resources, int3472);
+ skl_int3472_handle_gpio_resources,
+ int3472);
if (!ret) {
gpiod_add_lookup_table(&int3472->gpios);
@@ -423,7 +428,7 @@ int skl_int3472_discrete_probe(struct platform_device *pdev)
struct int3472_cldb cldb;
int ret = 0;
- ret = skl_int3472_get_cldb_buffer(adev, &cldb);
+ ret = skl_int3472_fill_cldb(adev, &cldb);
if (ret || cldb.control_logic_type != 1)
return -EINVAL;
@@ -444,10 +449,10 @@ int skl_int3472_discrete_probe(struct platform_device *pdev)
ret = -ENODEV;
goto err_free_int3472;
}
- int3472->sensor_name = i2c_acpi_dev_name(int3472->sensor);
+ int3472->sensor_name = kasprintf(GFP_KERNEL, I2C_DEV_NAME_FORMAT, acpi_dev_name(int3472->sensor));
int3472->gpios.dev_id = int3472->sensor_name;
- ret = int3472_parse_crs(int3472);
+ ret = skl_int3472_parse_crs(int3472);
if (ret) {
skl_int3472_discrete_remove(pdev);
goto err_return_ret;
diff --git a/drivers/platform/x86/intel_skl_int3472_tps68470.c b/drivers/platform/x86/intel_skl_int3472_tps68470.c
index 3fe27ec0caff..40629291b339 100644
--- a/drivers/platform/x86/intel_skl_int3472_tps68470.c
+++ b/drivers/platform/x86/intel_skl_int3472_tps68470.c
@@ -87,20 +87,20 @@ int skl_int3472_tps68470_probe(struct i2c_client *client)
/*
* Check CLDB buffer against the PMIC's adev. If present, then we check
- * the value of control_logic_type field and follow one of the following
- * scenarios:
+ * the value of control_logic_type field and follow one of the
+ * following scenarios:
*
- * 1. No CLDB - likely ACPI tables designed for ChromeOS. We create
- * platform devices for the GPIOs and OpRegion drivers.
+ * 1. No CLDB - likely ACPI tables designed for ChromeOS. We
+ * create platform devices for the GPIOs and OpRegion drivers.
*
- * 2. CLDB, with control_logic_type = 2 - probably ACPI tables made
- * for Windows 2-in-1 platforms. Register pdevs for GPIO, Clock and
- * Regulator drivers to bind to.
+ * 2. CLDB, with control_logic_type = 2 - probably ACPI tables
+ * made for Windows 2-in-1 platforms. Register pdevs for GPIO,
+ * Clock and Regulator drivers to bind to.
*
* 3. Any other value in control_logic_type, we should never have
* gotten to this point; crash and burn.
*/
- ret = skl_int3472_get_cldb_buffer(adev, &cldb);
+ ret = skl_int3472_fill_cldb(adev, &cldb);
if (!ret && cldb.control_logic_type != 2)
return -EINVAL;
--
2.32.0
From 165969e59a17b4d7fcb2cd3ba758cf914b3ea092 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sat, 23 Jan 2021 00:30:15 +0000
Subject: [PATCH] platform: x86: Add recalc_rate opp to int3472-discrete clock
This commit adds the recalc_rate opp to the clock registered by
int3472-discrete so that sensor drivers calling clk_get_rate() will get a
valid value returned.
The value is simply read from the sensor's SSDB buffer, and so we pass
CLK_GET_RATE_NOCACHE
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
.../platform/x86/intel_skl_int3472_common.h | 6 +++
.../platform/x86/intel_skl_int3472_discrete.c | 37 ++++++++++++++++++-
2 files changed, 41 insertions(+), 2 deletions(-)
diff --git a/drivers/platform/x86/intel_skl_int3472_common.h b/drivers/platform/x86/intel_skl_int3472_common.h
index e1083bb67dc6..860c849b7769 100644
--- a/drivers/platform/x86/intel_skl_int3472_common.h
+++ b/drivers/platform/x86/intel_skl_int3472_common.h
@@ -17,6 +17,8 @@
#define GPIO_REGULATOR_NAME_LENGTH 27
#define GPIO_REGULATOR_SUPPLY_NAME_LENGTH 9
+#define CIO2_SENSOR_SSDB_MCLKSPEED_OFFSET 86
+
#define INT3472_REGULATOR(_NAME, _SUPPLY, _OPS) \
(const struct regulator_desc) { \
.name = _NAME, \
@@ -36,6 +38,9 @@
#define to_int3472_clk(hw) \
container_of(hw, struct int3472_gpio_clock, clk_hw)
+#define to_int3472_device(clk) \
+ container_of(clk, struct int3472_device, clock)
+
struct int3472_cldb {
u8 version;
/*
@@ -62,6 +67,7 @@ struct int3472_gpio_regulator {
struct int3472_gpio_clock {
struct clk *clk;
struct clk_hw clk_hw;
+ struct clk_lookup *cl;
struct gpio_desc *gpio;
};
diff --git a/drivers/platform/x86/intel_skl_int3472_discrete.c b/drivers/platform/x86/intel_skl_int3472_discrete.c
index 42ae8396eb64..98eb1ec3399e 100644
--- a/drivers/platform/x86/intel_skl_int3472_discrete.c
+++ b/drivers/platform/x86/intel_skl_int3472_discrete.c
@@ -86,11 +86,41 @@ static void skl_int3472_clk_unprepare(struct clk_hw *hw)
/* Likewise, nothing to do here... */
}
+static unsigned int skl_int3472_get_clk_frequency(struct int3472_device *int3472)
+{
+ union acpi_object *obj;
+ unsigned int ret = 0;
+
+ obj = skl_int3472_get_acpi_buffer(int3472->sensor, "SSDB");
+ if (IS_ERR(obj))
+ goto out_free_buff; /* report rate as 0 on error */
+
+ if (obj->buffer.length < CIO2_SENSOR_SSDB_MCLKSPEED_OFFSET + sizeof(u32)) {
+ dev_err(&int3472->pdev->dev, "The buffer is too small\n");
+ goto out_free_buff;
+ }
+
+ ret = *(u32*)(obj->buffer.pointer + CIO2_SENSOR_SSDB_MCLKSPEED_OFFSET);
+
+out_free_buff:
+ kfree(obj);
+ return ret;
+}
+
+static unsigned long skl_int3472_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct int3472_gpio_clock *clk = to_int3472_clk(hw);
+ struct int3472_device *int3472 = to_int3472_device(clk);
+
+ return skl_int3472_get_clk_frequency(int3472);
+}
+
static const struct clk_ops skl_int3472_clock_ops = {
.prepare = skl_int3472_clk_prepare,
.unprepare = skl_int3472_clk_unprepare,
.enable = skl_int3472_clk_enable,
.disable = skl_int3472_clk_disable,
+ .recalc_rate = skl_int3472_clk_recalc_rate,
};
static struct int3472_sensor_config *
@@ -196,6 +226,7 @@ static int skl_int3472_register_clock(struct int3472_device *int3472,
init.name = kasprintf(GFP_KERNEL, "%s-clk",
acpi_dev_name(int3472->adev));
init.ops = &skl_int3472_clock_ops;
+ init.flags |= CLK_GET_RATE_NOCACHE;
int3472->clock.gpio = acpi_get_gpiod(path,
ares->data.gpio.pin_table[0]);
@@ -212,8 +243,9 @@ static int skl_int3472_register_clock(struct int3472_device *int3472,
goto err_put_gpio;
}
- ret = clk_register_clkdev(int3472->clock.clk, "xvclk", int3472->sensor_name);
- if (ret)
+ int3472->clock.cl = clkdev_create(int3472->clock.clk, "xvclk",
+ int3472->sensor_name);
+ if (IS_ERR_OR_NULL(int3472->clock.cl))
goto err_unregister_clk;
goto out_free_init_name;
@@ -483,6 +515,7 @@ int skl_int3472_discrete_remove(struct platform_device *pdev)
if (!IS_ERR_OR_NULL(int3472->clock.clk)) {
gpiod_put(int3472->clock.gpio);
clk_unregister(int3472->clock.clk);
+ clkdev_drop(int3472->clock.cl);
}
acpi_dev_put(int3472->sensor);
--
2.32.0
From 1d8dab673003189189bd7e9afc1ee83c011ed628 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fabian=20W=C3=BCthrich?= <me@fabwu.ch>
Date: Sun, 24 Jan 2021 11:07:42 +0100
Subject: [PATCH] cio2-bridge: Use macros and add warnings
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Use macros for the _PLD panel as defined in the ACPI spec 6.3 and emit
a warning if we see an unknown value.
Signed-off-by: Fabian Wüthrich <me@fabwu.ch>
Patchset: cameras
---
drivers/media/pci/intel/ipu3/cio2-bridge.c | 33 ++++++++++++++++------
drivers/media/pci/intel/ipu3/cio2-bridge.h | 13 +++++++++
2 files changed, 37 insertions(+), 9 deletions(-)
diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.c b/drivers/media/pci/intel/ipu3/cio2-bridge.c
index 806d4e5fc177..3c373ad1c0b0 100644
--- a/drivers/media/pci/intel/ipu3/cio2-bridge.c
+++ b/drivers/media/pci/intel/ipu3/cio2-bridge.c
@@ -73,21 +73,36 @@ static int cio2_bridge_read_acpi_buffer(struct acpi_device *adev, char *id,
return ret;
}
-static u32 cio2_bridge_parse_rotation(u8 rotation)
+static u32 cio2_bridge_parse_rotation(struct cio2_sensor *sensor)
{
- if (rotation == 1)
+ switch (sensor->ssdb.degree) {
+ case CIO2_SENSOR_ROTATION_NORMAL:
+ return 0;
+ case CIO2_SENSOR_ROTATION_INVERTED:
return 180;
- return 0;
+ default:
+ dev_warn(&sensor->adev->dev,
+ "Unknown rotation %d. Assume 0 degree rotation\n",
+ sensor->ssdb.degree);
+ return 0;
+ }
}
-static enum v4l2_fwnode_orientation cio2_bridge_parse_orientation(u8 panel)
+static enum v4l2_fwnode_orientation cio2_bridge_parse_orientation(struct cio2_sensor *sensor)
{
- switch (panel) {
- case 4:
+ switch (sensor->pld->panel) {
+ case CIO2_PLD_PANEL_FRONT:
return V4L2_FWNODE_ORIENTATION_FRONT;
- case 5:
+ case CIO2_PLD_PANEL_BACK:
return V4L2_FWNODE_ORIENTATION_BACK;
+ case CIO2_PLD_PANEL_TOP:
+ case CIO2_PLD_PANEL_LEFT:
+ case CIO2_PLD_PANEL_RIGHT:
+ case CIO2_PLD_PANEL_UNKNOWN:
+ return V4L2_FWNODE_ORIENTATION_EXTERNAL;
default:
+ dev_warn(&sensor->adev->dev, "Unknown _PLD panel value %d\n",
+ sensor->pld->panel);
return V4L2_FWNODE_ORIENTATION_EXTERNAL;
}
}
@@ -100,8 +115,8 @@ static void cio2_bridge_create_fwnode_properties(
u32 rotation;
enum v4l2_fwnode_orientation orientation;
- rotation = cio2_bridge_parse_rotation(sensor->ssdb.degree);
- orientation = cio2_bridge_parse_orientation(sensor->pld->panel);
+ rotation = cio2_bridge_parse_rotation(sensor);
+ orientation = cio2_bridge_parse_orientation(sensor);
sensor->prop_names = prop_names;
diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.h b/drivers/media/pci/intel/ipu3/cio2-bridge.h
index 924d99d20328..e1e388cc9f45 100644
--- a/drivers/media/pci/intel/ipu3/cio2-bridge.h
+++ b/drivers/media/pci/intel/ipu3/cio2-bridge.h
@@ -12,6 +12,19 @@
#define CIO2_MAX_LANES 4
#define MAX_NUM_LINK_FREQS 3
+/* Values are estimated guesses as we don't have a spec */
+#define CIO2_SENSOR_ROTATION_NORMAL 0
+#define CIO2_SENSOR_ROTATION_INVERTED 1
+
+/* Panel position defined in _PLD section of ACPI Specification 6.3 */
+#define CIO2_PLD_PANEL_TOP 0
+#define CIO2_PLD_PANEL_BOTTOM 1
+#define CIO2_PLD_PANEL_LEFT 2
+#define CIO2_PLD_PANEL_RIGHT 3
+#define CIO2_PLD_PANEL_FRONT 4
+#define CIO2_PLD_PANEL_BACK 5
+#define CIO2_PLD_PANEL_UNKNOWN 6
+
#define CIO2_SENSOR_CONFIG(_HID, _NR, ...) \
(const struct cio2_sensor_config) { \
.hid = _HID, \
--
2.32.0
From 10214fa721d6fccc3cbc3c961e7451e058e131c2 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Mon, 8 Feb 2021 21:44:38 +0000
Subject: [PATCH] media: i2c: Tidy up ov5693_init_controls()
The ov5693 driver initialises a bunch of v4l2 controls and throws away
the pointers. This seems weird, let's not do that.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 46 ++++++++++++++++++++++----------------
drivers/media/i2c/ov5693.h | 12 +++++++++-
2 files changed, 38 insertions(+), 20 deletions(-)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index 1a85800df7ed..a9747ab783d7 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -1610,7 +1610,6 @@ static int ov5693_init_controls(struct ov5693_device *ov5693)
struct i2c_client *client = v4l2_get_subdevdata(&ov5693->sd);
const struct v4l2_ctrl_ops *ops = &ov5693_ctrl_ops;
struct v4l2_fwnode_device_properties props;
- struct v4l2_ctrl *ctrl;
unsigned int i;
int ret;
int hblank;
@@ -1628,15 +1627,17 @@ static int ov5693_init_controls(struct ov5693_device *ov5693)
NULL);
/* link freq */
- ctrl = v4l2_ctrl_new_int_menu(&ov5693->ctrl_handler, NULL,
- V4L2_CID_LINK_FREQ,
- 0, 0, link_freq_menu_items);
- if (ctrl)
- ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ ov5693->ctrls.link_freq = v4l2_ctrl_new_int_menu(&ov5693->ctrl_handler,
+ NULL, V4L2_CID_LINK_FREQ,
+ 0, 0, link_freq_menu_items);
+ if (ov5693->ctrls.link_freq)
+ ov5693->ctrls.link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
/* pixel rate */
- v4l2_ctrl_new_std(&ov5693->ctrl_handler, NULL, V4L2_CID_PIXEL_RATE,
- 0, OV5693_PIXEL_RATE, 1, OV5693_PIXEL_RATE);
+ ov5693->ctrls.pixel_rate = v4l2_ctrl_new_std(&ov5693->ctrl_handler, NULL,
+ V4L2_CID_PIXEL_RATE, 0,
+ OV5693_PIXEL_RATE, 1,
+ OV5693_PIXEL_RATE);
if (ov5693->ctrl_handler.error) {
ov5693_remove(client);
@@ -1645,25 +1646,32 @@ static int ov5693_init_controls(struct ov5693_device *ov5693)
/* Exposure */
- v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops, V4L2_CID_EXPOSURE, 16, 1048575, 16,
- 512);
+ ov5693->ctrls.exposure = v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops,
+ V4L2_CID_EXPOSURE, 16,
+ 1048575, 16, 512);
/* Gain */
- v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops, V4L2_CID_ANALOGUE_GAIN, 1, 1023, 1, 128);
- v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops, V4L2_CID_DIGITAL_GAIN, 1, 3999, 1, 1000);
+ ov5693->ctrls.analogue_gain = v4l2_ctrl_new_std(&ov5693->ctrl_handler,
+ ops, V4L2_CID_ANALOGUE_GAIN,
+ 1, 1023, 1, 128);
+ ov5693->ctrls.digital_gain = v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops,
+ V4L2_CID_DIGITAL_GAIN, 1,
+ 3999, 1, 1000);
/* Flip */
- v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
+ ov5693->ctrls.hflip = v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ ov5693->ctrls.vflip = v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
hblank = OV5693_PPL_DEFAULT - ov5693->mode->width;
- ov5693->hblank = v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops,
- V4L2_CID_HBLANK, hblank, hblank,
- 1, hblank);
- if (ov5693->hblank)
- ov5693->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ ov5693->ctrls.hblank = v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops,
+ V4L2_CID_HBLANK, hblank, hblank,
+ 1, hblank);
+ if (ov5693->ctrls.hblank)
+ ov5693->ctrls.hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
/* set properties from fwnode (e.g. rotation, orientation) */
ret = v4l2_fwnode_device_parse(&client->dev, &props);
diff --git a/drivers/media/i2c/ov5693.h b/drivers/media/i2c/ov5693.h
index 9a508e1f3624..26819cf3f4d2 100644
--- a/drivers/media/i2c/ov5693.h
+++ b/drivers/media/i2c/ov5693.h
@@ -270,7 +270,17 @@ struct ov5693_device {
bool has_vcm;
- struct v4l2_ctrl *hblank;
+ struct ov5693_v4l2_ctrls {
+ struct v4l2_ctrl *link_freq;
+ struct v4l2_ctrl *pixel_rate;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *analogue_gain;
+ struct v4l2_ctrl *digital_gain;
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+ struct v4l2_ctrl *hblank;
+ } ctrls;
+
};
enum ov5693_tok_type {
--
2.32.0
From 67ad0308a145ba0d1c3a5d2cbb7ed61f8f1381ab Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Mon, 8 Feb 2021 21:46:49 +0000
Subject: [PATCH] media: i2c: Remove OV5693_PPL_DEFAULT
No need for this macro, the PPL setting is against the mode structs.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index a9747ab783d7..7fb368eec327 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -105,8 +105,6 @@ MODULE_PARM_DESC(up_delay,
#define OV5693_PIXEL_ARRAY_WIDTH 2592U
#define OV5693_PIXEL_ARRAY_HEIGHT 1944U
-#define OV5693_PPL_DEFAULT 2800
-
static int vcm_ad_i2c_wr8(struct i2c_client *client, u8 reg, u8 val)
{
int err;
@@ -1666,7 +1664,7 @@ static int ov5693_init_controls(struct ov5693_device *ov5693)
ov5693->ctrls.vflip = v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
- hblank = OV5693_PPL_DEFAULT - ov5693->mode->width;
+ hblank = ov5693->mode->pixels_per_line - ov5693->mode->width;
ov5693->ctrls.hblank = v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops,
V4L2_CID_HBLANK, hblank, hblank,
1, hblank);
--
2.32.0
From dd5bf9fb107acc628dff64bc4295e90acfffa777 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Mon, 8 Feb 2021 22:53:02 +0000
Subject: [PATCH] media: i2c: Add vblank control to ov5693 driver
The latest libcamera requires a V4L2_CID_VBLANK control in each sensor
driver; add a skeleton one to the ov5693 to fulfill the requirement.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 12 ++++++++++++
drivers/media/i2c/ov5693.h | 3 +++
2 files changed, 15 insertions(+)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index 7fb368eec327..1950d7ac2d54 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -946,6 +946,10 @@ static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl)
return ov5693_flip_horz_configure(dev, !!ctrl->val);
case V4L2_CID_VFLIP:
return ov5693_flip_vert_configure(dev, !!ctrl->val);
+ case V4L2_CID_VBLANK:
+ ret = ov5693_write_reg(client, OV5693_16BIT, OV5693_TIMING_VTS_H,
+ dev->mode->height + ctrl->val);
+ break;
default:
ret = -EINVAL;
}
@@ -1611,6 +1615,7 @@ static int ov5693_init_controls(struct ov5693_device *ov5693)
unsigned int i;
int ret;
int hblank;
+ int vblank_max, vblank_min, vblank_def;
ret = v4l2_ctrl_handler_init(&ov5693->ctrl_handler,
ARRAY_SIZE(ov5693_controls));
@@ -1671,6 +1676,13 @@ static int ov5693_init_controls(struct ov5693_device *ov5693)
if (ov5693->ctrls.hblank)
ov5693->ctrls.hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ vblank_max = OV5693_TIMING_MAX_VTS - ov5693->mode->height;
+ vblank_def = ov5693->mode->lines_per_frame - ov5693->mode->height;
+ vblank_min = ov5693->mode->lines_per_frame - ov5693->mode->height;
+ ov5693->ctrls.vblank = v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops,
+ V4L2_CID_VBLANK, vblank_min,
+ vblank_max, 1, vblank_def);
+
/* set properties from fwnode (e.g. rotation, orientation) */
ret = v4l2_fwnode_device_parse(&client->dev, &props);
if (ret)
diff --git a/drivers/media/i2c/ov5693.h b/drivers/media/i2c/ov5693.h
index 26819cf3f4d2..9d7eed97963b 100644
--- a/drivers/media/i2c/ov5693.h
+++ b/drivers/media/i2c/ov5693.h
@@ -131,6 +131,8 @@
/*High 8-bit, and low 8-bit HTS address is 0x380f*/
#define OV5693_TIMING_VTS_L 0x380f
+#define OV5693_TIMING_MAX_VTS 0xffff
+
#define OV5693_MWB_RED_GAIN_H 0x3400
#define OV5693_MWB_GREEN_GAIN_H 0x3402
#define OV5693_MWB_BLUE_GAIN_H 0x3404
@@ -279,6 +281,7 @@ struct ov5693_device {
struct v4l2_ctrl *hflip;
struct v4l2_ctrl *vflip;
struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *vblank;
} ctrls;
};
--
2.32.0
From 0eea3733faca1eef0929d4191d18b4343203b838 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Wed, 10 Feb 2021 00:36:32 +0000
Subject: [PATCH] media: i2c: update exposure control for ov5693
The exposure control for ov5693 currently is in units of 1/16th of a line,
but I think the framework expects it in units of lines. Set the control to
work in lines and simply apply the multiplication when configuring the chip
registers instead.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index 1950d7ac2d54..cea767230aa9 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -801,6 +801,12 @@ static int ov5693_exposure_configure(struct ov5693_device *sensor, u32 exposure)
{
int ret;
+ /*
+ * The control for exposure seems to be in units of lines, but the chip
+ * datasheet specifies exposure is in units of 1/16th of a line.
+ */
+ exposure = exposure * 16;
+
ov5693_get_exposure(sensor);
ret = ov5693_write_reg(sensor->i2c_client, OV5693_8BIT,
OV5693_EXPOSURE_CTRL_HH_REG, OV5693_EXPOSURE_CTRL_HH(exposure));
@@ -910,6 +916,16 @@ static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl)
struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
int ret = 0;
+ /* If VBLANK is altered we need to update exposure to compensate */
+ if (ctrl->id == V4L2_CID_VBLANK) {
+ int exposure_max;
+ exposure_max = dev->mode->lines_per_frame - 8;
+ __v4l2_ctrl_modify_range(dev->ctrls.exposure, dev->ctrls.exposure->minimum,
+ exposure_max, dev->ctrls.exposure->step,
+ dev->ctrls.exposure->val < exposure_max ?
+ dev->ctrls.exposure->val : exposure_max);
+ }
+
switch (ctrl->id) {
case V4L2_CID_FOCUS_ABSOLUTE:
dev_dbg(&client->dev, "%s: CID_FOCUS_ABSOLUTE:%d.\n",
@@ -1616,6 +1632,7 @@ static int ov5693_init_controls(struct ov5693_device *ov5693)
int ret;
int hblank;
int vblank_max, vblank_min, vblank_def;
+ int exposure_max;
ret = v4l2_ctrl_handler_init(&ov5693->ctrl_handler,
ARRAY_SIZE(ov5693_controls));
@@ -1648,10 +1665,10 @@ static int ov5693_init_controls(struct ov5693_device *ov5693)
}
/* Exposure */
-
+ exposure_max = ov5693->mode->lines_per_frame - 8;
ov5693->ctrls.exposure = v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops,
- V4L2_CID_EXPOSURE, 16,
- 1048575, 16, 512);
+ V4L2_CID_EXPOSURE, 1,
+ exposure_max, 1, 123);
/* Gain */
--
2.32.0
From c3f40e8470a640b01fcc3537f17eee270ae45a71 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Wed, 10 Feb 2021 00:39:42 +0000
Subject: [PATCH] media: i2c: Fix incorrect bit-setting
The bitmask macros to set the exposure for the ov5693 are not quite right.
Update them so that they're setting the correct bits in the registers.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index cea767230aa9..f681dbfcec56 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -63,11 +63,11 @@ MODULE_PARM_DESC(up_delay,
/* Exposure/gain */
#define OV5693_EXPOSURE_CTRL_HH_REG 0x3500
-#define OV5693_EXPOSURE_CTRL_HH(v) (((v) & GENMASK(18, 16)) >> 16)
+#define OV5693_EXPOSURE_CTRL_HH(v) (((v) & GENMASK(14, 12)) >> 12)
#define OV5693_EXPOSURE_CTRL_H_REG 0x3501
-#define OV5693_EXPOSURE_CTRL_H(v) (((v) & GENMASK(15, 8)) >> 8)
+#define OV5693_EXPOSURE_CTRL_H(v) (((v) & GENMASK(11, 4)) >> 4)
#define OV5693_EXPOSURE_CTRL_L_REG 0x3502
-#define OV5693_EXPOSURE_CTRL_L(v) ((v) & GENMASK(7, 0))
+#define OV5693_EXPOSURE_CTRL_L(v) (((v) & GENMASK(3, 0)) << 4)
#define OV5693_EXPOSURE_GAIN_MANUAL_REG 0x3509
#define OV5693_GAIN_CTRL_H_REG 0x3504
--
2.32.0
From 0678d6dc801d6da526a476085dd3d74f285fa275 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Wed, 10 Feb 2021 16:25:48 +0000
Subject: [PATCH] media: i2c: Don't set stream on during mode config
Currently the register lists for the ov5693 include setting stream on.
That register shouldn't be set until the control is called, so remove
this setting from all of the modes.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.h | 16 ----------------
1 file changed, 16 deletions(-)
diff --git a/drivers/media/i2c/ov5693.h b/drivers/media/i2c/ov5693.h
index 9d7eed97963b..965208078c2b 100644
--- a/drivers/media/i2c/ov5693.h
+++ b/drivers/media/i2c/ov5693.h
@@ -581,7 +581,6 @@ static struct ov5693_reg const ov5693_654x496[] = {
{OV5693_8BIT, 0x3820, 0x04},
{OV5693_8BIT, 0x3821, 0x1f},
{OV5693_8BIT, 0x5002, 0x80},
- {OV5693_8BIT, 0x0100, 0x01},
{OV5693_TOK_TERM, 0, 0}
};
@@ -626,7 +625,6 @@ static struct ov5693_reg const ov5693_1296x976[] = {
{OV5693_8BIT, 0x3821, 0x1e},
{OV5693_8BIT, 0x5002, 0x00},
{OV5693_8BIT, 0x5041, 0x84}, /* scale is auto enabled */
- {OV5693_8BIT, 0x0100, 0x01},
{OV5693_TOK_TERM, 0, 0}
};
@@ -656,7 +654,6 @@ static struct ov5693_reg const ov5693_336x256[] = {
{OV5693_8BIT, 0x3820, 0x04},
{OV5693_8BIT, 0x3821, 0x1f},
{OV5693_8BIT, 0x5002, 0x80},
- {OV5693_8BIT, 0x0100, 0x01},
{OV5693_TOK_TERM, 0, 0}
};
@@ -683,7 +680,6 @@ static struct ov5693_reg const ov5693_368x304[] = {
{OV5693_8BIT, 0x3820, 0x04},
{OV5693_8BIT, 0x3821, 0x1f},
{OV5693_8BIT, 0x5002, 0x80},
- {OV5693_8BIT, 0x0100, 0x01},
{OV5693_TOK_TERM, 0, 0}
};
@@ -715,7 +711,6 @@ static struct ov5693_reg const ov5693_192x160[] = {
{OV5693_8BIT, 0x3820, 0x04},
{OV5693_8BIT, 0x3821, 0x1f},
{OV5693_8BIT, 0x5002, 0x80},
- {OV5693_8BIT, 0x0100, 0x01},
{OV5693_TOK_TERM, 0, 0}
};
@@ -742,7 +737,6 @@ static struct ov5693_reg const ov5693_736x496[] = {
{OV5693_8BIT, 0x3820, 0x04},
{OV5693_8BIT, 0x3821, 0x1f},
{OV5693_8BIT, 0x5002, 0x80},
- {OV5693_8BIT, 0x0100, 0x01},
{OV5693_TOK_TERM, 0, 0}
};
#endif
@@ -771,7 +765,6 @@ static struct ov5693_reg const ov5693_736x496[] = {
{OV5693_8BIT, 0x3820, 0x01},
{OV5693_8BIT, 0x3821, 0x1f},
{OV5693_8BIT, 0x5002, 0x00},
- {OV5693_8BIT, 0x0100, 0x01},
{OV5693_TOK_TERM, 0, 0}
};
*/
@@ -802,7 +795,6 @@ static struct ov5693_reg const ov5693_976x556[] = {
{OV5693_8BIT, 0x3820, 0x00},
{OV5693_8BIT, 0x3821, 0x1e},
{OV5693_8BIT, 0x5002, 0x80},
- {OV5693_8BIT, 0x0100, 0x01},
{OV5693_TOK_TERM, 0, 0}
};
@@ -841,7 +833,6 @@ static struct ov5693_reg const ov5693_1296x736[] = {
{OV5693_8BIT, 0x3821, 0x1e},
{OV5693_8BIT, 0x5002, 0x00},
{OV5693_8BIT, 0x5041, 0x84}, /* scale is auto enabled */
- {OV5693_8BIT, 0x0100, 0x01},
{OV5693_TOK_TERM, 0, 0}
};
@@ -868,7 +859,6 @@ static struct ov5693_reg const ov5693_1636p_30fps[] = {
{OV5693_8BIT, 0x3820, 0x00},
{OV5693_8BIT, 0x3821, 0x1e},
{OV5693_8BIT, 0x5002, 0x80},
- {OV5693_8BIT, 0x0100, 0x01},
{OV5693_TOK_TERM, 0, 0}
};
#endif
@@ -904,7 +894,6 @@ static struct ov5693_reg const ov5693_1616x1216_30fps[] = {
{OV5693_8BIT, 0x3821, 0x1e}, /*MIRROR control*/
{OV5693_8BIT, 0x5002, 0x00},
{OV5693_8BIT, 0x5041, 0x84},
- {OV5693_8BIT, 0x0100, 0x01},
{OV5693_TOK_TERM, 0, 0}
};
@@ -935,7 +924,6 @@ static struct ov5693_reg const ov5693_1940x1096[] = {
{OV5693_8BIT, 0x3820, 0x00},
{OV5693_8BIT, 0x3821, 0x1e},
{OV5693_8BIT, 0x5002, 0x80},
- {OV5693_8BIT, 0x0100, 0x01},
{OV5693_TOK_TERM, 0, 0}
};
@@ -1029,7 +1017,6 @@ static struct ov5693_reg const ov5693_2592x1944_30fps[] = {
{OV5693_8BIT, 0x3820, 0x00},
{OV5693_8BIT, 0x3821, 0x1e},
{OV5693_8BIT, 0x5002, 0x00},
- {OV5693_8BIT, 0x0100, 0x01},
{OV5693_TOK_TERM, 0, 0}
};
#endif
@@ -1073,7 +1060,6 @@ static struct ov5693_reg const ov5693_1424x1168_30fps[] = {
{OV5693_8BIT, 0x3821, 0x1e},
{OV5693_8BIT, 0x5002, 0x00},
{OV5693_8BIT, 0x5041, 0x84}, /* scale is auto enabled */
- {OV5693_8BIT, 0x0100, 0x01},
{OV5693_TOK_TERM, 0, 0}
};
#endif
@@ -1114,7 +1100,6 @@ static struct ov5693_reg const ov5693_736x496_30fps[] = {
{OV5693_8BIT, 0x3821, 0x1e},
{OV5693_8BIT, 0x5002, 0x00},
{OV5693_8BIT, 0x5041, 0x84}, /* scale is auto enabled */
- {OV5693_8BIT, 0x0100, 0x01},
{OV5693_TOK_TERM, 0, 0}
};
@@ -1141,7 +1126,6 @@ static struct ov5693_reg const ov5693_2576x1936_30fps[] = {
{OV5693_8BIT, 0x3820, 0x00},
{OV5693_8BIT, 0x3821, 0x1e},
{OV5693_8BIT, 0x5002, 0x00},
- {OV5693_8BIT, 0x0100, 0x01},
{OV5693_TOK_TERM, 0, 0}
};
--
2.32.0
From 85cd5c85e7874f26a8867b3ca2be8b3fdb580379 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Wed, 10 Feb 2021 16:35:24 +0000
Subject: [PATCH] media: i2c: Update gain control for ov5693
The gain control of the ov5693 driver is setting the wrong bits and
defining an invalid maximum value; change (and use) the bitshifting
macros and update the control's ranges.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index f681dbfcec56..51eb3b05d121 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -71,9 +71,9 @@ MODULE_PARM_DESC(up_delay,
#define OV5693_EXPOSURE_GAIN_MANUAL_REG 0x3509
#define OV5693_GAIN_CTRL_H_REG 0x3504
-#define OV5693_GAIN_CTRL_H(v) (((v) & GENMASK(9, 8)) >> 8)
+#define OV5693_GAIN_CTRL_H(v) ((v >> 4) & GENMASK(2, 0))
#define OV5693_GAIN_CTRL_L_REG 0x3505
-#define OV5693_GAIN_CTRL_L(v) ((v) & GENMASK(7, 0))
+#define OV5693_GAIN_CTRL_L(v) ((v << 4) & GENMASK(7, 4))
#define OV5693_FORMAT1_REG 0x3820
#define OV5693_FORMAT1_FLIP_VERT_ISP_EN BIT(2)
@@ -889,9 +889,13 @@ static int ov5693_analog_gain_configure(struct ov5693_device *sensor, u32 gain)
{
int ret;
- /* Analog gain */
+ /*
+ * As with exposure, the lowest 4 bits are fractional bits. Setting
+ * those is not supported, so we have a tiny bit of bit shifting to
+ * do.
+ */
ret = ov5693_write_reg(sensor->i2c_client, OV5693_8BIT,
- OV5693_AGC_L, gain & 0xff);
+ OV5693_AGC_L, OV5693_GAIN_CTRL_L(gain));
if (ret) {
dev_err(&sensor->i2c_client->dev, "%s: write %x error, aborted\n",
__func__, OV5693_AGC_L);
@@ -899,7 +903,7 @@ static int ov5693_analog_gain_configure(struct ov5693_device *sensor, u32 gain)
}
ret = ov5693_write_reg(sensor->i2c_client, OV5693_8BIT,
- OV5693_AGC_H, (gain >> 8) & 0xff);
+ OV5693_AGC_H, OV5693_GAIN_CTRL_H(gain));
if (ret) {
dev_err(&sensor->i2c_client->dev, "%s: write %x error, aborted\n",
__func__, OV5693_AGC_H);
@@ -1674,10 +1678,10 @@ static int ov5693_init_controls(struct ov5693_device *ov5693)
ov5693->ctrls.analogue_gain = v4l2_ctrl_new_std(&ov5693->ctrl_handler,
ops, V4L2_CID_ANALOGUE_GAIN,
- 1, 1023, 1, 128);
+ 1, 127, 1, 8);
ov5693->ctrls.digital_gain = v4l2_ctrl_new_std(&ov5693->ctrl_handler, ops,
V4L2_CID_DIGITAL_GAIN, 1,
- 3999, 1, 1000);
+ 4095, 1, 1024);
/* Flip */
--
2.32.0
From 87536da9f003c95a26a2f22ad701c7224c660053 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Wed, 10 Feb 2021 23:44:39 +0000
Subject: [PATCH] media: i2c: Fixup gain read
This function reads the bits from the gain registers poorly. Update
it to do that properly (although, it probably just needs to be deleted)
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index 51eb3b05d121..952558c4f33b 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -770,30 +770,35 @@ static int ov5693_t_focus_rel(struct v4l2_subdev *sd, s32 value)
static int ov5693_get_exposure(struct ov5693_device *sensor)
{
- u16 reg_v, reg_v2;
+ u32 exposure = 0;
+ u16 tmp;
int ret = 0;
/* get exposure */
ret = ov5693_read_reg(sensor->i2c_client, OV5693_8BIT,
OV5693_EXPOSURE_L,
- &reg_v);
+ &tmp);
if (ret)
return ret;
+ exposure |= ((tmp >> 4) & 0b1111);
+
ret = ov5693_read_reg(sensor->i2c_client, OV5693_8BIT,
OV5693_EXPOSURE_M,
- &reg_v2);
+ &tmp);
if (ret)
return ret;
- reg_v += reg_v2 << 8;
+ exposure |= (tmp << 4);
ret = ov5693_read_reg(sensor->i2c_client, OV5693_8BIT,
OV5693_EXPOSURE_H,
- &reg_v2);
+ &tmp);
if (ret)
return ret;
- printk("exposure set to: %u\n", reg_v + (((u32)reg_v2 << 16)));
+ exposure |= (tmp << 12);
+
+ printk("exposure set to: %u\n", exposure);
return ret;
}
--
2.32.0
From 168060f6df58790bb05041d80b25ad6ada6adc1d Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Thu, 11 Feb 2021 00:40:10 +0000
Subject: [PATCH] media: i2c: Update controls on stream
Currently the ov5693 driver throws away control setting by simply loading
each mode's default registers. Instead, re-set the user defined controls
during stream with __v4l2_ctrl_handler_setup()
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index 952558c4f33b..dd31083eeb7b 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -1492,6 +1492,12 @@ static int ov5693_s_stream(struct v4l2_subdev *sd, int enable)
}
}
+ ret = __v4l2_ctrl_handler_setup(&dev->ctrl_handler);
+ if (ret) {
+ power_down(sd);
+ return ret;
+ }
+
ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM,
enable ? OV5693_START_STREAMING :
OV5693_STOP_STREAMING);
--
2.32.0
From b534102819248eac835506c5d29b82e50430f6b8 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Thu, 11 Feb 2021 23:29:15 +0000
Subject: [PATCH] media: i2c: Correct link frequency value
The link frequency is given by vts * hts * fps * bits / lanes / 2. In the
case of the ov5693 driver that works out to 400MHz, not 640Mhz. Correct
the macro.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/media/i2c/ov5693.h b/drivers/media/i2c/ov5693.h
index 965208078c2b..7f1d31a82d3d 100644
--- a/drivers/media/i2c/ov5693.h
+++ b/drivers/media/i2c/ov5693.h
@@ -186,13 +186,13 @@
#define OV5693_OTP_MODE_READ 1
/* link freq and pixel rate required for IPU3 */
-#define OV5693_LINK_FREQ_640MHZ 640000000
+#define OV5693_LINK_FREQ_400MHZ 400000000
/* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample
* To avoid integer overflow, dividing by bits_per_sample first.
*/
-#define OV5693_PIXEL_RATE (OV5693_LINK_FREQ_640MHZ / 10) * 2 * 2
+#define OV5693_PIXEL_RATE (OV5693_LINK_FREQ_400MHZ / 10) * 2 * 2
static const s64 link_freq_menu_items[] = {
- OV5693_LINK_FREQ_640MHZ
+ OV5693_LINK_FREQ_400MHZ
};
#define OV5693_NUM_SUPPLIES 2
--
2.32.0
From 73b7467e64dcfa601bd81362b1ad11683ef2ed96 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Mon, 25 Jan 2021 23:12:09 +0000
Subject: [PATCH] media: i2c: Cleanup ov5693 driver
This commit performs some cleanup to the ov5693 driver:
1. Superfluous words in variable names dropped; "i2c_client" becomes
"client", "input_lock" becomes "lock"
2. ov5693_configure_gpios() is does error handling properly, and uses
gpiod_get_optional()
3. The name of the struct ov5693_device variable in each functions, which
previously was a mix of dev, sensor or ov5693, is standardised to the
latter.
4. The list of headers is alphabetised (and probably also needs trimming)
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 309 +++++++++++++++++++------------------
drivers/media/i2c/ov5693.h | 5 +-
2 files changed, 165 insertions(+), 149 deletions(-)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index dd31083eeb7b..0643390c872a 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -16,25 +16,25 @@
*
*/
+#include <linux/acpi.h>
#include <linux/clk.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/errno.h>
+#include <linux/i2c.h>
#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
#include <linux/kmod.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
+#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/mm.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
-#include <linux/io.h>
-#include <linux/acpi.h>
-#include <linux/regulator/consumer.h>
#include "ov5693.h"
#include "ad5823.h"
@@ -485,12 +485,12 @@ static int ov5693_read_otp_reg_array(struct i2c_client *client, u16 size,
static int __ov5693_otp_read(struct v4l2_subdev *sd, u8 *buf)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
int ret;
int i;
u8 *b = buf;
- dev->otp_size = 0;
+ ov5693->otp_size = 0;
for (i = 1; i < OV5693_OTP_BANK_MAX; i++) {
/*set bank NO and OTP read mode. */
ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_OTP_BANK_REG,
@@ -529,7 +529,7 @@ static int __ov5693_otp_read(struct v4l2_subdev *sd, u8 *buf)
//Intel OTP map, try to read 320byts first.
if (i == 21) {
if ((*b) == 0) {
- dev->otp_size = 320;
+ ov5693->otp_size = 320;
break;
}
/* (*b) != 0 */
@@ -538,7 +538,7 @@ static int __ov5693_otp_read(struct v4l2_subdev *sd, u8 *buf)
} else if (i ==
24) { //if the first 320bytes data doesn't not exist, try to read the next 32bytes data.
if ((*b) == 0) {
- dev->otp_size = 32;
+ ov5693->otp_size = 32;
break;
}
/* (*b) != 0 */
@@ -547,11 +547,11 @@ static int __ov5693_otp_read(struct v4l2_subdev *sd, u8 *buf)
} else if (i ==
27) { //if the prvious 32bytes data doesn't exist, try to read the next 32bytes data again.
if ((*b) == 0) {
- dev->otp_size = 32;
+ ov5693->otp_size = 32;
break;
}
/* (*b) != 0 */
- dev->otp_size = 0; // no OTP data.
+ ov5693->otp_size = 0; // no OTP data.
break;
}
@@ -598,20 +598,20 @@ static void *ov5693_otp_read(struct v4l2_subdev *sd)
return buf;
}
-static int ov5693_update_bits(struct ov5693_device *sensor, u16 address,
+static int ov5693_update_bits(struct ov5693_device *ov5693, u16 address,
u16 mask, u16 bits)
{
u16 value = 0;
int ret;
- ret = ov5693_read_reg(sensor->i2c_client, OV5693_8BIT, address, &value);
+ ret = ov5693_read_reg(ov5693->client, OV5693_8BIT, address, &value);
if (ret)
return ret;
value &= ~mask;
value |= bits;
- ret = ov5693_write_reg(sensor->i2c_client, OV5693_8BIT, address, value);
+ ret = ov5693_write_reg(ov5693->client, OV5693_8BIT, address, value);
if (ret)
return ret;
@@ -620,13 +620,13 @@ static int ov5693_update_bits(struct ov5693_device *sensor, u16 address,
/* Flip */
-static int ov5693_flip_vert_configure(struct ov5693_device *sensor, bool enable)
+static int ov5693_flip_vert_configure(struct ov5693_device *ov5693, bool enable)
{
u8 bits = OV5693_FORMAT1_FLIP_VERT_ISP_EN |
OV5693_FORMAT1_FLIP_VERT_SENSOR_EN;
int ret;
- ret = ov5693_update_bits(sensor, OV5693_FORMAT1_REG, bits,
+ ret = ov5693_update_bits(ov5693, OV5693_FORMAT1_REG, bits,
enable ? bits : 0);
if (ret)
return ret;
@@ -634,13 +634,13 @@ static int ov5693_flip_vert_configure(struct ov5693_device *sensor, bool enable)
return 0;
}
-static int ov5693_flip_horz_configure(struct ov5693_device *sensor, bool enable)
+static int ov5693_flip_horz_configure(struct ov5693_device *ov5693, bool enable)
{
u8 bits = OV5693_FORMAT2_FLIP_HORZ_ISP_EN |
OV5693_FORMAT2_FLIP_HORZ_SENSOR_EN;
int ret;
- ret = ov5693_update_bits(sensor, OV5693_FORMAT2_REG, bits,
+ ret = ov5693_update_bits(ov5693, OV5693_FORMAT2_REG, bits,
enable ? bits : 0);
if (ret)
return ret;
@@ -721,14 +721,14 @@ static int ad5823_t_focus_abs(struct v4l2_subdev *sd, s32 value)
static int ov5693_t_focus_abs(struct v4l2_subdev *sd, s32 value)
{
- struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret = 0;
dev_dbg(&client->dev, "%s: FOCUS_POS: 0x%x\n", __func__, value);
value = clamp(value, 0, OV5693_VCM_MAX_FOCUS_POS);
- if (dev->vcm == VCM_DW9714) {
- if (dev->vcm_update) {
+ if (ov5693->vcm == VCM_DW9714) {
+ if (ov5693->vcm_update) {
ret = vcm_dw_i2c_write(client, VCM_PROTECTION_OFF);
if (ret)
return ret;
@@ -738,17 +738,17 @@ static int ov5693_t_focus_abs(struct v4l2_subdev *sd, s32 value)
ret = vcm_dw_i2c_write(client, VCM_PROTECTION_ON);
if (ret)
return ret;
- dev->vcm_update = false;
+ ov5693->vcm_update = false;
}
ret = vcm_dw_i2c_write(client,
vcm_val(value, VCM_DEFAULT_S));
- } else if (dev->vcm == VCM_AD5823) {
+ } else if (ov5693->vcm == VCM_AD5823) {
ad5823_t_focus_abs(sd, value);
}
if (ret == 0) {
- dev->number_of_steps = value - dev->focus;
- dev->focus = value;
- dev->timestamp_t_focus_abs = ktime_get();
+ ov5693->number_of_steps = value - ov5693->focus;
+ ov5693->focus = value;
+ ov5693->timestamp_t_focus_abs = ktime_get();
} else
dev_err(&client->dev,
"%s: i2c failed. ret %d\n", __func__, ret);
@@ -758,9 +758,9 @@ static int ov5693_t_focus_abs(struct v4l2_subdev *sd, s32 value)
static int ov5693_t_focus_rel(struct v4l2_subdev *sd, s32 value)
{
- struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
- return ov5693_t_focus_abs(sd, dev->focus + value);
+ return ov5693_t_focus_abs(sd, ov5693->focus + value);
}
#define DELAY_PER_STEP_NS 1000000
@@ -768,14 +768,14 @@ static int ov5693_t_focus_rel(struct v4l2_subdev *sd, s32 value)
/* Exposure */
-static int ov5693_get_exposure(struct ov5693_device *sensor)
+static int ov5693_get_exposure(struct ov5693_device *ov5693)
{
u32 exposure = 0;
u16 tmp;
int ret = 0;
/* get exposure */
- ret = ov5693_read_reg(sensor->i2c_client, OV5693_8BIT,
+ ret = ov5693_read_reg(ov5693->client, OV5693_8BIT,
OV5693_EXPOSURE_L,
&tmp);
if (ret)
@@ -783,14 +783,14 @@ static int ov5693_get_exposure(struct ov5693_device *sensor)
exposure |= ((tmp >> 4) & 0b1111);
- ret = ov5693_read_reg(sensor->i2c_client, OV5693_8BIT,
+ ret = ov5693_read_reg(ov5693->client, OV5693_8BIT,
OV5693_EXPOSURE_M,
&tmp);
if (ret)
return ret;
exposure |= (tmp << 4);
- ret = ov5693_read_reg(sensor->i2c_client, OV5693_8BIT,
+ ret = ov5693_read_reg(ov5693->client, OV5693_8BIT,
OV5693_EXPOSURE_H,
&tmp);
if (ret)
@@ -802,7 +802,7 @@ static int ov5693_get_exposure(struct ov5693_device *sensor)
return ret;
}
-static int ov5693_exposure_configure(struct ov5693_device *sensor, u32 exposure)
+static int ov5693_exposure_configure(struct ov5693_device *ov5693, u32 exposure)
{
int ret;
@@ -812,40 +812,40 @@ static int ov5693_exposure_configure(struct ov5693_device *sensor, u32 exposure)
*/
exposure = exposure * 16;
- ov5693_get_exposure(sensor);
- ret = ov5693_write_reg(sensor->i2c_client, OV5693_8BIT,
+ ov5693_get_exposure(ov5693);
+ ret = ov5693_write_reg(ov5693->client, OV5693_8BIT,
OV5693_EXPOSURE_CTRL_HH_REG, OV5693_EXPOSURE_CTRL_HH(exposure));
if (ret)
return ret;
- ret = ov5693_write_reg(sensor->i2c_client, OV5693_8BIT,
+ ret = ov5693_write_reg(ov5693->client, OV5693_8BIT,
OV5693_EXPOSURE_CTRL_H_REG, OV5693_EXPOSURE_CTRL_H(exposure));
if (ret)
return ret;
- ret = ov5693_write_reg(sensor->i2c_client, OV5693_8BIT,
+ ret = ov5693_write_reg(ov5693->client, OV5693_8BIT,
OV5693_EXPOSURE_CTRL_L_REG, OV5693_EXPOSURE_CTRL_L(exposure));
if (ret)
return ret;
- ov5693_get_exposure(sensor);
+ ov5693_get_exposure(ov5693);
return 0;
}
/* Gain */
-static int ov5693_get_gain(struct ov5693_device *sensor, u32 *gain)
+static int ov5693_get_gain(struct ov5693_device *ov5693, u32 *gain)
{
u16 gain_l, gain_h;
int ret = 0;
- ret = ov5693_read_reg(sensor->i2c_client, OV5693_8BIT,
+ ret = ov5693_read_reg(ov5693->client, OV5693_8BIT,
OV5693_GAIN_CTRL_L_REG,
&gain_l);
if (ret)
return ret;
- ret = ov5693_read_reg(sensor->i2c_client, OV5693_8BIT,
+ ret = ov5693_read_reg(ov5693->client, OV5693_8BIT,
OV5693_GAIN_CTRL_H_REG,
&gain_h);
if (ret)
@@ -856,33 +856,33 @@ static int ov5693_get_gain(struct ov5693_device *sensor, u32 *gain)
return ret;
}
-static int ov5693_gain_configure(struct ov5693_device *sensor, u32 gain)
+static int ov5693_gain_configure(struct ov5693_device *ov5693, u32 gain)
{
int ret;
/* A 1.0 gain is 0x400 */
gain = (gain * 1024)/1000;
- ret = ov5693_write_reg(sensor->i2c_client, OV5693_16BIT,
+ ret = ov5693_write_reg(ov5693->client, OV5693_16BIT,
OV5693_MWB_RED_GAIN_H, gain);
if (ret) {
- dev_err(&sensor->i2c_client->dev, "%s: write %x error, aborted\n",
+ dev_err(&ov5693->client->dev, "%s: write %x error, aborted\n",
__func__, OV5693_MWB_RED_GAIN_H);
return ret;
}
- ret = ov5693_write_reg(sensor->i2c_client, OV5693_16BIT,
+ ret = ov5693_write_reg(ov5693->client, OV5693_16BIT,
OV5693_MWB_GREEN_GAIN_H, gain);
if (ret) {
- dev_err(&sensor->i2c_client->dev, "%s: write %x error, aborted\n",
+ dev_err(&ov5693->client->dev, "%s: write %x error, aborted\n",
__func__, OV5693_MWB_RED_GAIN_H);
return ret;
}
- ret = ov5693_write_reg(sensor->i2c_client, OV5693_16BIT,
+ ret = ov5693_write_reg(ov5693->client, OV5693_16BIT,
OV5693_MWB_BLUE_GAIN_H, gain);
if (ret) {
- dev_err(&sensor->i2c_client->dev, "%s: write %x error, aborted\n",
+ dev_err(&ov5693->client->dev, "%s: write %x error, aborted\n",
__func__, OV5693_MWB_RED_GAIN_H);
return ret;
}
@@ -890,7 +890,7 @@ static int ov5693_gain_configure(struct ov5693_device *sensor, u32 gain)
return 0;
}
-static int ov5693_analog_gain_configure(struct ov5693_device *sensor, u32 gain)
+static int ov5693_analog_gain_configure(struct ov5693_device *ov5693, u32 gain)
{
int ret;
@@ -899,18 +899,18 @@ static int ov5693_analog_gain_configure(struct ov5693_device *sensor, u32 gain)
* those is not supported, so we have a tiny bit of bit shifting to
* do.
*/
- ret = ov5693_write_reg(sensor->i2c_client, OV5693_8BIT,
+ ret = ov5693_write_reg(ov5693->client, OV5693_8BIT,
OV5693_AGC_L, OV5693_GAIN_CTRL_L(gain));
if (ret) {
- dev_err(&sensor->i2c_client->dev, "%s: write %x error, aborted\n",
+ dev_err(&ov5693->client->dev, "%s: write %x error, aborted\n",
__func__, OV5693_AGC_L);
return ret;
}
- ret = ov5693_write_reg(sensor->i2c_client, OV5693_8BIT,
+ ret = ov5693_write_reg(ov5693->client, OV5693_8BIT,
OV5693_AGC_H, OV5693_GAIN_CTRL_H(gain));
if (ret) {
- dev_err(&sensor->i2c_client->dev, "%s: write %x error, aborted\n",
+ dev_err(&ov5693->client->dev, "%s: write %x error, aborted\n",
__func__, OV5693_AGC_H);
return ret;
}
@@ -920,60 +920,60 @@ static int ov5693_analog_gain_configure(struct ov5693_device *sensor, u32 gain)
static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct ov5693_device *dev =
+ struct ov5693_device *ov5693 =
container_of(ctrl->handler, struct ov5693_device, ctrl_handler);
- struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
+ struct i2c_client *client = v4l2_get_subdevdata(&ov5693->sd);
int ret = 0;
/* If VBLANK is altered we need to update exposure to compensate */
if (ctrl->id == V4L2_CID_VBLANK) {
int exposure_max;
- exposure_max = dev->mode->lines_per_frame - 8;
- __v4l2_ctrl_modify_range(dev->ctrls.exposure, dev->ctrls.exposure->minimum,
- exposure_max, dev->ctrls.exposure->step,
- dev->ctrls.exposure->val < exposure_max ?
- dev->ctrls.exposure->val : exposure_max);
+ exposure_max = ov5693->mode->lines_per_frame - 8;
+ __v4l2_ctrl_modify_range(ov5693->ctrls.exposure, ov5693->ctrls.exposure->minimum,
+ exposure_max, ov5693->ctrls.exposure->step,
+ ov5693->ctrls.exposure->val < exposure_max ?
+ ov5693->ctrls.exposure->val : exposure_max);
}
switch (ctrl->id) {
case V4L2_CID_FOCUS_ABSOLUTE:
dev_dbg(&client->dev, "%s: CID_FOCUS_ABSOLUTE:%d.\n",
__func__, ctrl->val);
- ret = ov5693_t_focus_abs(&dev->sd, ctrl->val);
+ ret = ov5693_t_focus_abs(&ov5693->sd, ctrl->val);
break;
case V4L2_CID_FOCUS_RELATIVE:
dev_dbg(&client->dev, "%s: CID_FOCUS_RELATIVE:%d.\n",
__func__, ctrl->val);
- ret = ov5693_t_focus_rel(&dev->sd, ctrl->val);
+ ret = ov5693_t_focus_rel(&ov5693->sd, ctrl->val);
break;
case V4L2_CID_EXPOSURE:
dev_dbg(&client->dev, "%s: CID_EXPOSURE:%d.\n",
__func__, ctrl->val);
- ret = ov5693_exposure_configure(dev, ctrl->val);
+ ret = ov5693_exposure_configure(ov5693, ctrl->val);
if (ret)
return ret;
break;
case V4L2_CID_ANALOGUE_GAIN:
dev_dbg(&client->dev, "%s: CID_ANALOGUE_GAIN:%d.\n",
__func__, ctrl->val);
- ret = ov5693_analog_gain_configure(dev, ctrl->val);
+ ret = ov5693_analog_gain_configure(ov5693, ctrl->val);
if (ret)
return ret;
break;
case V4L2_CID_DIGITAL_GAIN:
dev_dbg(&client->dev, "%s: CID_DIGITAL_GAIN:%d.\n",
__func__, ctrl->val);
- ret = ov5693_gain_configure(dev, ctrl->val);
+ ret = ov5693_gain_configure(ov5693, ctrl->val);
if (ret)
return ret;
break;
case V4L2_CID_HFLIP:
- return ov5693_flip_horz_configure(dev, !!ctrl->val);
+ return ov5693_flip_horz_configure(ov5693, !!ctrl->val);
case V4L2_CID_VFLIP:
- return ov5693_flip_vert_configure(dev, !!ctrl->val);
+ return ov5693_flip_vert_configure(ov5693, !!ctrl->val);
case V4L2_CID_VBLANK:
ret = ov5693_write_reg(client, OV5693_16BIT, OV5693_TIMING_VTS_H,
- dev->mode->height + ctrl->val);
+ ov5693->mode->height + ctrl->val);
break;
default:
ret = -EINVAL;
@@ -983,16 +983,16 @@ static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl)
static int ov5693_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
- struct ov5693_device *dev =
+ struct ov5693_device *ov5693 =
container_of(ctrl->handler, struct ov5693_device, ctrl_handler);
int ret = 0;
switch (ctrl->id) {
case V4L2_CID_EXPOSURE_ABSOLUTE:
- ret = ov5693_q_exposure(&dev->sd, &ctrl->val);
+ ret = ov5693_q_exposure(&ov5693->sd, &ctrl->val);
break;
case V4L2_CID_AUTOGAIN:
- ret = ov5693_get_gain(dev, &ctrl->val);
+ ret = ov5693_get_gain(ov5693, &ctrl->val);
break;
case V4L2_CID_FOCUS_ABSOLUTE:
/* NOTE: there was atomisp-specific function ov5693_q_focus_abs() */
@@ -1034,12 +1034,12 @@ static const struct v4l2_ctrl_config ov5693_controls[] = {
},
};
-static int ov5693_isp_configure(struct ov5693_device *sensor)
+static int ov5693_isp_configure(struct ov5693_device *ov5693)
{
int ret;
/* Enable lens correction. */
- ret = ov5693_write_reg(sensor->i2c_client, OV5693_8BIT,
+ ret = ov5693_write_reg(ov5693->client, OV5693_8BIT,
OV5693_ISP_CTRL0_REG, 0x86);
if (ret)
return ret;
@@ -1049,18 +1049,18 @@ static int ov5693_isp_configure(struct ov5693_device *sensor)
static int ov5693_init(struct v4l2_subdev *sd)
{
- struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
- if (!dev->has_vcm)
+ if (!ov5693->has_vcm)
return 0;
dev_info(&client->dev, "%s\n", __func__);
- mutex_lock(&dev->input_lock);
- dev->vcm_update = false;
+ mutex_lock(&ov5693->lock);
+ ov5693->vcm_update = false;
- if (dev->vcm == VCM_AD5823) {
+ if (ov5693->vcm == VCM_AD5823) {
ret = vcm_ad_i2c_wr8(client, 0x01, 0x01); /* vcm init test */
if (ret)
dev_err(&client->dev,
@@ -1079,16 +1079,16 @@ static int ov5693_init(struct v4l2_subdev *sd)
}
/*change initial focus value for ad5823*/
- if (dev->vcm == VCM_AD5823) {
- dev->focus = AD5823_INIT_FOCUS_POS;
+ if (ov5693->vcm == VCM_AD5823) {
+ ov5693->focus = AD5823_INIT_FOCUS_POS;
ov5693_t_focus_abs(sd, AD5823_INIT_FOCUS_POS);
} else {
- dev->focus = 0;
+ ov5693->focus = 0;
ov5693_t_focus_abs(sd, 0);
}
- ov5693_isp_configure(dev);
- mutex_unlock(&dev->input_lock);
+ ov5693_isp_configure(ov5693);
+ mutex_unlock(&ov5693->lock);
return 0;
}
@@ -1096,32 +1096,32 @@ static int ov5693_init(struct v4l2_subdev *sd)
static int __power_up(struct v4l2_subdev *sd)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov5693_device *sensor = to_ov5693_sensor(sd);
+ struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
int ret;
- ret = clk_prepare_enable(sensor->clk);
+ ret = clk_prepare_enable(ov5693->clk);
if (ret) {
dev_err(&client->dev, "Error enabling clock\n");
return -EINVAL;
}
- if (sensor->indicator_led)
- gpiod_set_value_cansleep(sensor->indicator_led, 1);
+ if (ov5693->indicator_led)
+ gpiod_set_value_cansleep(ov5693->indicator_led, 1);
ret = regulator_bulk_enable(OV5693_NUM_SUPPLIES,
- sensor->supplies);
+ ov5693->supplies);
if (ret)
goto fail_power;
- gpiod_set_value_cansleep(sensor->reset, 0);
+ gpiod_set_value_cansleep(ov5693->reset, 0);
__cci_delay(up_delay);
return 0;
fail_power:
- if (sensor->indicator_led)
- gpiod_set_value_cansleep(sensor->indicator_led, 0);
+ if (ov5693->indicator_led)
+ gpiod_set_value_cansleep(ov5693->indicator_led, 0);
dev_err(&client->dev, "sensor power-up failed\n");
return ret;
@@ -1129,17 +1129,17 @@ static int __power_up(struct v4l2_subdev *sd)
static int power_down(struct v4l2_subdev *sd)
{
- struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
- dev->focus = OV5693_INVALID_CONFIG;
+ ov5693->focus = OV5693_INVALID_CONFIG;
- gpiod_set_value_cansleep(dev->reset, 1);
+ gpiod_set_value_cansleep(ov5693->reset, 1);
- clk_disable_unprepare(dev->clk);
+ clk_disable_unprepare(ov5693->clk);
- if (dev->indicator_led)
- gpiod_set_value_cansleep(dev->indicator_led, 0);
- return regulator_bulk_disable(OV5693_NUM_SUPPLIES, dev->supplies);
+ if (ov5693->indicator_led)
+ gpiod_set_value_cansleep(ov5693->indicator_led, 0);
+ return regulator_bulk_disable(OV5693_NUM_SUPPLIES, ov5693->supplies);
}
static int power_up(struct v4l2_subdev *sd)
@@ -1265,7 +1265,7 @@ static int get_resolution_index(int w, int h)
/* TODO: remove it. */
static int startup(struct v4l2_subdev *sd)
{
- struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret = 0;
@@ -1282,7 +1282,7 @@ static int startup(struct v4l2_subdev *sd)
return ret;
}
- ret = ov5693_write_reg_array(client, ov5693_res[dev->fmt_idx].regs);
+ ret = ov5693_write_reg_array(client, ov5693_res[ov5693->fmt_idx].regs);
if (ret) {
dev_err(&client->dev, "ov5693 write register err.\n");
return ret;
@@ -1296,7 +1296,7 @@ static int ov5693_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
- struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret = 0;
int idx;
@@ -1307,7 +1307,7 @@ static int ov5693_set_fmt(struct v4l2_subdev *sd,
if (!fmt)
return -EINVAL;
- mutex_lock(&dev->input_lock);
+ mutex_lock(&ov5693->lock);
idx = nearest_resolution_index(fmt->width, fmt->height);
if (idx == -1) {
/* return the largest resolution */
@@ -1325,8 +1325,8 @@ static int ov5693_set_fmt(struct v4l2_subdev *sd,
goto mutex_unlock;
}
- dev->fmt_idx = get_resolution_index(fmt->width, fmt->height);
- if (dev->fmt_idx == -1) {
+ ov5693->fmt_idx = get_resolution_index(fmt->width, fmt->height);
+ if (ov5693->fmt_idx == -1) {
dev_err(&client->dev, "get resolution fail\n");
ret = -EINVAL;
goto mutex_unlock;
@@ -1339,9 +1339,9 @@ static int ov5693_set_fmt(struct v4l2_subdev *sd,
continue;
}
- mutex_unlock(&dev->input_lock);
+ mutex_unlock(&ov5693->lock);
ov5693_init(sd);
- mutex_lock(&dev->input_lock);
+ mutex_lock(&ov5693->lock);
ret = startup(sd);
if (ret)
dev_err(&client->dev, " startup() FAILED!\n");
@@ -1353,8 +1353,6 @@ static int ov5693_set_fmt(struct v4l2_subdev *sd,
goto mutex_unlock;
}
-
-
/*
* After sensor settings are set to HW, sometimes stream is started.
* This would cause ISP timeout because ISP is not ready to receive
@@ -1366,19 +1364,19 @@ static int ov5693_set_fmt(struct v4l2_subdev *sd,
dev_warn(&client->dev, "ov5693 stream off err\n");
mutex_unlock:
- mutex_unlock(&dev->input_lock);
+ mutex_unlock(&ov5693->lock);
return ret;
}
static const struct v4l2_rect *
-__ov5693_get_pad_crop(struct ov5693_device *dev, struct v4l2_subdev_pad_config *cfg,
+__ov5693_get_pad_crop(struct ov5693_device *ov5693, struct v4l2_subdev_pad_config *cfg,
unsigned int pad, enum v4l2_subdev_format_whence which)
{
switch (which) {
case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_get_try_crop(&dev->sd, cfg, pad);
+ return v4l2_subdev_get_try_crop(&ov5693->sd, cfg, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
- return &dev->mode->crop;
+ return &ov5693->mode->crop;
}
return NULL;
@@ -1389,12 +1387,12 @@ static int ov5693_get_selection(struct v4l2_subdev *sd,
{
switch (sel->target) {
case V4L2_SEL_TGT_CROP: {
- struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
- mutex_lock(&dev->input_lock);
- sel->r = *__ov5693_get_pad_crop(dev, cfg, sel->pad,
+ mutex_lock(&ov5693->lock);
+ sel->r = *__ov5693_get_pad_crop(ov5693, cfg, sel->pad,
sel->which);
- mutex_unlock(&dev->input_lock);
+ mutex_unlock(&ov5693->lock);
return 0;
}
@@ -1424,7 +1422,7 @@ static int ov5693_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_format *format)
{
struct v4l2_mbus_framefmt *fmt = &format->format;
- struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
if (format->pad)
return -EINVAL;
@@ -1432,8 +1430,8 @@ static int ov5693_get_fmt(struct v4l2_subdev *sd,
if (!fmt)
return -EINVAL;
- fmt->width = ov5693_res[dev->fmt_idx].width;
- fmt->height = ov5693_res[dev->fmt_idx].height;
+ fmt->width = ov5693_res[ov5693->fmt_idx].width;
+ fmt->height = ov5693_res[ov5693->fmt_idx].height;
fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
return 0;
@@ -1481,7 +1479,7 @@ static int ov5693_s_stream(struct v4l2_subdev *sd, int enable)
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
- mutex_lock(&dev->input_lock);
+ mutex_lock(&dev->lock);
/* power_on() here before streaming for regular PCs. */
if (enable) {
@@ -1507,26 +1505,26 @@ static int ov5693_s_stream(struct v4l2_subdev *sd, int enable)
power_down(sd);
out:
- mutex_unlock(&dev->input_lock);
+ mutex_unlock(&dev->lock);
return ret;
}
static int ov5693_s_config(struct v4l2_subdev *sd, int irq)
{
- struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret = 0;
- mutex_lock(&dev->input_lock);
+ mutex_lock(&ov5693->lock);
ret = power_up(sd);
if (ret) {
dev_err(&client->dev, "ov5693 power-up err.\n");
goto fail_power_on;
}
- if (!dev->vcm)
- dev->vcm = vcm_detect(client);
+ if (!ov5693->vcm)
+ ov5693->vcm = vcm_detect(client);
/* config & detect sensor */
ret = ov5693_detect(client);
@@ -1535,7 +1533,7 @@ static int ov5693_s_config(struct v4l2_subdev *sd, int irq)
goto fail_power_on;
}
- dev->otp_data = ov5693_otp_read(sd);
+ ov5693->otp_data = ov5693_otp_read(sd);
/* turn off sensor, after probed */
ret = power_down(sd);
@@ -1543,24 +1541,24 @@ static int ov5693_s_config(struct v4l2_subdev *sd, int irq)
dev_err(&client->dev, "ov5693 power-off err.\n");
goto fail_power_on;
}
- mutex_unlock(&dev->input_lock);
+ mutex_unlock(&ov5693->lock);
return ret;
fail_power_on:
power_down(sd);
dev_err(&client->dev, "sensor power-gating failed\n");
- mutex_unlock(&dev->input_lock);
+ mutex_unlock(&ov5693->lock);
return ret;
}
static int ov5693_g_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_frame_interval *interval)
{
- struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
interval->interval.numerator = 1;
- interval->interval.denominator = ov5693_res[dev->fmt_idx].fps;
+ interval->interval.denominator = ov5693_res[ov5693->fmt_idx].fps;
return 0;
}
@@ -1725,7 +1723,7 @@ static int ov5693_init_controls(struct ov5693_device *ov5693)
return ret;
/* Use same lock for controls as for everything else. */
- ov5693->ctrl_handler.lock = &ov5693->input_lock;
+ ov5693->ctrl_handler.lock = &ov5693->lock;
ov5693->sd.ctrl_handler = &ov5693->ctrl_handler;
return 0;
@@ -1733,21 +1731,38 @@ static int ov5693_init_controls(struct ov5693_device *ov5693)
static int ov5693_configure_gpios(struct ov5693_device *ov5693)
{
- ov5693->reset = gpiod_get_index(&ov5693->i2c_client->dev, "reset", 0,
+ int ret;
+
+ ov5693->reset = gpiod_get_optional(&ov5693->client->dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(ov5693->reset)) {
- dev_err(&ov5693->i2c_client->dev, "Couldn't find reset GPIO\n");
- return -EINVAL;
+ dev_err(&ov5693->client->dev, "Couldn't find reset GPIO\n");
+ return PTR_ERR(ov5693->reset);
+ }
+
+ ov5693->powerdown = gpiod_get_optional(&ov5693->client->dev, "powerdown",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(ov5693->powerdown)) {
+ dev_err(&ov5693->client->dev, "Couldn't find powerdown GPIO\n");
+ ret = PTR_ERR(ov5693->powerdown);
+ goto err_put_reset;
}
- ov5693->indicator_led = gpiod_get_index_optional(&ov5693->i2c_client->dev, "indicator-led", 0,
+ ov5693->indicator_led = gpiod_get_optional(&ov5693->client->dev, "indicator-led",
GPIOD_OUT_HIGH);
if (IS_ERR(ov5693->indicator_led)) {
- dev_err(&ov5693->i2c_client->dev, "Couldn't find indicator-led GPIO\n");
- return -EINVAL;
+ dev_err(&ov5693->client->dev, "Couldn't find indicator-led GPIO\n");
+ ret = PTR_ERR(ov5693->indicator_led);
+ goto err_put_powerdown;
}
return 0;
+err_put_reset:
+ gpiod_put(ov5693->reset);
+err_put_powerdown:
+ gpiod_put(ov5693->powerdown);
+
+ return ret;
}
static int ov5693_get_regulators(struct ov5693_device *ov5693)
@@ -1757,7 +1772,7 @@ static int ov5693_get_regulators(struct ov5693_device *ov5693)
for (i = 0; i < OV5693_NUM_SUPPLIES; i++)
ov5693->supplies[i].supply = ov5693_supply_names[i];
- return regulator_bulk_get(&ov5693->i2c_client->dev,
+ return regulator_bulk_get(&ov5693->client->dev,
OV5693_NUM_SUPPLIES,
ov5693->supplies);
}
@@ -1773,13 +1788,13 @@ static int ov5693_probe(struct i2c_client *client)
if (!ov5693)
return -ENOMEM;
- ov5693->i2c_client = client;
+ ov5693->client = client;
/* check if VCM device exists */
/* TODO: read from SSDB */
ov5693->has_vcm = false;
- mutex_init(&ov5693->input_lock);
+ mutex_init(&ov5693->lock);
v4l2_i2c_subdev_init(&ov5693->sd, client, &ov5693_ops);
diff --git a/drivers/media/i2c/ov5693.h b/drivers/media/i2c/ov5693.h
index 7f1d31a82d3d..70ccb3aae4c7 100644
--- a/drivers/media/i2c/ov5693.h
+++ b/drivers/media/i2c/ov5693.h
@@ -241,14 +241,15 @@ enum vcm_type {
* ov5693 device structure.
*/
struct ov5693_device {
- struct i2c_client *i2c_client;
+ struct i2c_client *client;
struct v4l2_subdev sd;
struct media_pad pad;
struct v4l2_mbus_framefmt format;
- struct mutex input_lock;
+ struct mutex lock;
struct v4l2_ctrl_handler ctrl_handler;
struct gpio_desc *reset;
+ struct gpio_desc *powerdown;
struct gpio_desc *indicator_led;
struct regulator_bulk_data supplies[OV5693_NUM_SUPPLIES];
struct clk *clk;
--
2.32.0
From 5ff97b493a91d818f1252ba1dfad49784739afea Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Thu, 28 Jan 2021 12:04:38 +0000
Subject: [PATCH] media: i2c: Add pm_runtime support to ov5693 driver
The ov5693 driver currently uses hacky and horrible power up/down methods
called directly in s_stream. Add pm_runtime support and use that in
s_stream instead. Replace all other uses of the power+up/down() calls with
the single ov5693_sensor_stream() for now.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 183 +++++++++++++++++++++++++++++--------
drivers/media/i2c/ov5693.h | 1 +
2 files changed, 146 insertions(+), 38 deletions(-)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index 0643390c872a..f2eaa5f71a31 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -29,6 +29,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/mm.h>
+#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/string.h>
@@ -935,6 +936,10 @@ static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl)
ov5693->ctrls.exposure->val : exposure_max);
}
+ /* Only apply changes to the controls if the device is powered up */
+ if (!pm_runtime_get_if_in_use(&ov5693->client->dev))
+ return 0;
+
switch (ctrl->id) {
case V4L2_CID_FOCUS_ABSOLUTE:
dev_dbg(&client->dev, "%s: CID_FOCUS_ABSOLUTE:%d.\n",
@@ -950,27 +955,23 @@ static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl)
dev_dbg(&client->dev, "%s: CID_EXPOSURE:%d.\n",
__func__, ctrl->val);
ret = ov5693_exposure_configure(ov5693, ctrl->val);
- if (ret)
- return ret;
break;
case V4L2_CID_ANALOGUE_GAIN:
dev_dbg(&client->dev, "%s: CID_ANALOGUE_GAIN:%d.\n",
__func__, ctrl->val);
ret = ov5693_analog_gain_configure(ov5693, ctrl->val);
- if (ret)
- return ret;
break;
case V4L2_CID_DIGITAL_GAIN:
dev_dbg(&client->dev, "%s: CID_DIGITAL_GAIN:%d.\n",
__func__, ctrl->val);
ret = ov5693_gain_configure(ov5693, ctrl->val);
- if (ret)
- return ret;
break;
case V4L2_CID_HFLIP:
- return ov5693_flip_horz_configure(ov5693, !!ctrl->val);
+ ret = ov5693_flip_horz_configure(ov5693, !!ctrl->val);
+ break;
case V4L2_CID_VFLIP:
- return ov5693_flip_vert_configure(ov5693, !!ctrl->val);
+ ret = ov5693_flip_vert_configure(ov5693, !!ctrl->val);
+ break;
case V4L2_CID_VBLANK:
ret = ov5693_write_reg(client, OV5693_16BIT, OV5693_TIMING_VTS_H,
ov5693->mode->height + ctrl->val);
@@ -978,6 +979,9 @@ static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl)
default:
ret = -EINVAL;
}
+
+ pm_runtime_put(&ov5693->client->dev);
+
return ret;
}
@@ -1093,6 +1097,106 @@ static int ov5693_init(struct v4l2_subdev *sd)
return 0;
}
+static int ov5693_sw_standby(struct ov5693_device *ov5693, bool standby)
+{
+ return ov5693_write_reg(ov5693->client, OV5693_8BIT, OV5693_SW_STREAM,
+ standby ? OV5693_STOP_STREAMING : OV5693_START_STREAMING);
+}
+
+static void ov5693_sensor_powerdown(struct ov5693_device *ov5693)
+{
+ gpiod_set_value_cansleep(ov5693->reset, 1);
+ gpiod_set_value_cansleep(ov5693->powerdown, 1);
+
+ regulator_bulk_disable(OV5693_NUM_SUPPLIES, ov5693->supplies);
+
+ clk_disable_unprepare(ov5693->clk);
+ gpiod_set_value_cansleep(ov5693->indicator_led, 0);
+}
+
+
+static int ov5693_sensor_powerup(struct ov5693_device *ov5693)
+{
+ int ret = 0;
+
+ gpiod_set_value_cansleep(ov5693->reset, 1);
+ gpiod_set_value_cansleep(ov5693->powerdown, 1);
+
+ ret = clk_prepare_enable(ov5693->clk);
+ if (ret) {
+ dev_err(&ov5693->client->dev, "Failed to enable clk\n");
+ goto fail_power;
+ }
+
+ ret = regulator_bulk_enable(OV5693_NUM_SUPPLIES, ov5693->supplies);
+ if (ret) {
+ dev_err(&ov5693->client->dev, "Failed to enable regulators\n");
+ goto fail_power;
+ }
+
+ gpiod_set_value_cansleep(ov5693->reset, 0);
+ gpiod_set_value_cansleep(ov5693->powerdown, 0);
+ gpiod_set_value_cansleep(ov5693->indicator_led, 1);
+
+ usleep_range(20000, 25000);
+
+ return 0;
+
+fail_power:
+ ov5693_sensor_powerdown(ov5693);
+ return ret;
+}
+
+static int __maybe_unused ov5693_sensor_suspend(struct device *dev)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
+ int ret;
+
+ mutex_lock(&ov5693->lock);
+
+ if (ov5693->streaming) {
+ ret = ov5693_sw_standby(ov5693, true);
+ if (ret)
+ goto out_unlock;
+ }
+
+ ov5693_sensor_powerdown(ov5693);
+
+out_unlock:
+ mutex_unlock(&ov5693->lock);
+ return ret;
+}
+
+static int __maybe_unused ov5693_sensor_resume(struct device *dev)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
+ int ret;
+
+ mutex_lock(&ov5693->lock);
+
+ ret = ov5693_sensor_powerup(ov5693);
+ if (ret)
+ goto out_unlock;
+
+ if (ov5693->streaming) {
+ ret = ov5693_sw_standby(ov5693, false);
+ if (ret)
+ goto err_power;
+ }
+
+ goto out_unlock;
+
+err_power:
+ ov5693_sensor_powerdown(ov5693);
+out_unlock:
+ mutex_unlock(&ov5693->lock);
+ return ret;
+}
+
static int __power_up(struct v4l2_subdev *sd)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -1134,6 +1238,7 @@ static int power_down(struct v4l2_subdev *sd)
ov5693->focus = OV5693_INVALID_CONFIG;
gpiod_set_value_cansleep(ov5693->reset, 1);
+ gpiod_set_value_cansleep(ov5693->powerdown, 1);
clk_disable_unprepare(ov5693->clk);
@@ -1333,7 +1438,7 @@ static int ov5693_set_fmt(struct v4l2_subdev *sd,
}
for (cnt = 0; cnt < OV5693_POWER_UP_RETRY_NUM; cnt++) {
- ret = power_up(sd);
+ ret = ov5693_sensor_powerup(ov5693);
if (ret) {
dev_err(&client->dev, "power up failed\n");
continue;
@@ -1475,38 +1580,34 @@ static int ov5693_detect(struct i2c_client *client)
static int ov5693_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct ov5693_device *dev = to_ov5693_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
int ret;
- mutex_lock(&dev->lock);
-
- /* power_on() here before streaming for regular PCs. */
if (enable) {
- ret = power_up(sd);
- if (ret) {
- dev_err(&client->dev, "sensor power-up error\n");
- goto out;
- }
+ ret = pm_runtime_get_sync(&ov5693->client->dev);
+ if (ret < 0)
+ goto err_power_down;
}
- ret = __v4l2_ctrl_handler_setup(&dev->ctrl_handler);
- if (ret) {
- power_down(sd);
- return ret;
- }
+ ret = __v4l2_ctrl_handler_setup(&ov5693->ctrl_handler);
+ if (ret)
+ goto err_power_down;
- ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM,
- enable ? OV5693_START_STREAMING :
- OV5693_STOP_STREAMING);
+ mutex_lock(&ov5693->lock);
+ ret = ov5693_sw_standby(ov5693, !enable);
+ mutex_unlock(&ov5693->lock);
+
+ if (ret)
+ goto err_power_down;
+ ov5693->streaming = !!enable;
/* power_off() here after streaming for regular PCs. */
if (!enable)
- power_down(sd);
-
-out:
- mutex_unlock(&dev->lock);
+ pm_runtime_put(&ov5693->client->dev);
+ return 0;
+err_power_down:
+ pm_runtime_put_noidle(&ov5693->client->dev);
return ret;
}
@@ -1517,7 +1618,7 @@ static int ov5693_s_config(struct v4l2_subdev *sd, int irq)
int ret = 0;
mutex_lock(&ov5693->lock);
- ret = power_up(sd);
+ ret = ov5693_sensor_powerup(ov5693);
if (ret) {
dev_err(&client->dev, "ov5693 power-up err.\n");
goto fail_power_on;
@@ -1536,17 +1637,14 @@ static int ov5693_s_config(struct v4l2_subdev *sd, int irq)
ov5693->otp_data = ov5693_otp_read(sd);
/* turn off sensor, after probed */
- ret = power_down(sd);
- if (ret) {
- dev_err(&client->dev, "ov5693 power-off err.\n");
- goto fail_power_on;
- }
+ ov5693_sensor_powerdown(ov5693);
+
mutex_unlock(&ov5693->lock);
return ret;
fail_power_on:
- power_down(sd);
+ ov5693_sensor_powerdown(ov5693);
dev_err(&client->dev, "sensor power-gating failed\n");
mutex_unlock(&ov5693->lock);
return ret;
@@ -1830,6 +1928,9 @@ static int ov5693_probe(struct i2c_client *client)
if (ret)
ov5693_remove(client);
+ pm_runtime_enable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+
ret = v4l2_async_register_subdev_sensor_common(&ov5693->sd);
if (ret) {
dev_err(&client->dev, "failed to register V4L2 subdev: %d", ret);
@@ -1839,6 +1940,7 @@ static int ov5693_probe(struct i2c_client *client)
return ret;
media_entity_cleanup:
+ pm_runtime_disable(&client->dev);
media_entity_cleanup(&ov5693->sd.entity);
out_put_reset:
gpiod_put(ov5693->reset);
@@ -1848,6 +1950,10 @@ static int ov5693_probe(struct i2c_client *client)
return ret;
}
+static const struct dev_pm_ops ov5693_pm_ops = {
+ SET_RUNTIME_PM_OPS(ov5693_sensor_suspend, ov5693_sensor_resume, NULL)
+};
+
static const struct acpi_device_id ov5693_acpi_match[] = {
{"INT33BE"},
{},
@@ -1858,6 +1964,7 @@ static struct i2c_driver ov5693_driver = {
.driver = {
.name = "ov5693",
.acpi_match_table = ov5693_acpi_match,
+ .pm = &ov5693_pm_ops,
},
.probe_new = ov5693_probe,
.remove = ov5693_remove,
diff --git a/drivers/media/i2c/ov5693.h b/drivers/media/i2c/ov5693.h
index 70ccb3aae4c7..b78d3b474a43 100644
--- a/drivers/media/i2c/ov5693.h
+++ b/drivers/media/i2c/ov5693.h
@@ -256,6 +256,7 @@ struct ov5693_device {
/* Current mode */
const struct ov5693_resolution *mode;
+ bool streaming;
struct camera_sensor_platform_data *platform_data;
ktime_t timestamp_t_focus_abs;
--
2.32.0
From 92ac42ec1daad352f944236be262878c21ddda70 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Thu, 28 Jan 2021 12:07:36 +0000
Subject: [PATCH] media: i2c: Remove old power methods from ov5693
Now that we have replaced the power_up/down() methods with a unified
function and pm_runtime support, we can remove these old methods from the
driver entirely along with some macros and a header.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 114 -------------------------------------
1 file changed, 114 deletions(-)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index f2eaa5f71a31..ce26ce86fbd5 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -27,7 +27,6 @@
#include <linux/kernel.h>
#include <linux/kmod.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/mm.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
@@ -40,27 +39,6 @@
#include "ov5693.h"
#include "ad5823.h"
-#define __cci_delay(t) \
- do { \
- if ((t) < 10) { \
- usleep_range((t) * 1000, ((t) + 1) * 1000); \
- } else { \
- msleep((t)); \
- } \
- } while (0)
-
-/* Value 30ms reached through experimentation on byt ecs.
- * The DS specifies a much lower value but when using a smaller value
- * the I2C bus sometimes locks up permanently when starting the camera.
- * This issue could not be reproduced on cht, so we can reduce the
- * delay value to a lower value when insmod.
- */
-static uint up_delay = 30;
-module_param(up_delay, uint, 0644);
-MODULE_PARM_DESC(up_delay,
- "Delay prior to the first CCI transaction for ov5693");
-
-
/* Exposure/gain */
#define OV5693_EXPOSURE_CTRL_HH_REG 0x3500
@@ -1197,93 +1175,6 @@ static int __maybe_unused ov5693_sensor_resume(struct device *dev)
return ret;
}
-static int __power_up(struct v4l2_subdev *sd)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
- int ret;
-
- ret = clk_prepare_enable(ov5693->clk);
- if (ret) {
- dev_err(&client->dev, "Error enabling clock\n");
- return -EINVAL;
- }
-
- if (ov5693->indicator_led)
- gpiod_set_value_cansleep(ov5693->indicator_led, 1);
-
- ret = regulator_bulk_enable(OV5693_NUM_SUPPLIES,
- ov5693->supplies);
- if (ret)
- goto fail_power;
-
- gpiod_set_value_cansleep(ov5693->reset, 0);
-
- __cci_delay(up_delay);
-
- return 0;
-
-fail_power:
- if (ov5693->indicator_led)
- gpiod_set_value_cansleep(ov5693->indicator_led, 0);
- dev_err(&client->dev, "sensor power-up failed\n");
-
- return ret;
-}
-
-static int power_down(struct v4l2_subdev *sd)
-{
- struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
-
- ov5693->focus = OV5693_INVALID_CONFIG;
-
- gpiod_set_value_cansleep(ov5693->reset, 1);
- gpiod_set_value_cansleep(ov5693->powerdown, 1);
-
- clk_disable_unprepare(ov5693->clk);
-
- if (ov5693->indicator_led)
- gpiod_set_value_cansleep(ov5693->indicator_led, 0);
- return regulator_bulk_disable(OV5693_NUM_SUPPLIES, ov5693->supplies);
-}
-
-static int power_up(struct v4l2_subdev *sd)
-{
- static const int retry_count = 4;
- int i, ret;
-
- for (i = 0; i < retry_count; i++) {
- ret = __power_up(sd);
- if (!ret)
- return 0;
-
- power_down(sd);
- }
- return ret;
-}
-
-static int ov5693_s_power(struct v4l2_subdev *sd, int on)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
-
- dev_info(&client->dev, "%s: on %d\n", __func__, on);
-
- if (on == 0)
- return power_down(sd);
-
- /* on == 1 */
- ret = power_up(sd);
- if (!ret) {
- ret = ov5693_init(sd);
- /* restore settings */
- ov5693_res = ov5693_res_video;
- N_RES = N_RES_VIDEO;
- }
-
- return ret;
-}
-
/*
* distance - calculate the distance
* @res: resolution
@@ -1694,10 +1585,6 @@ static const struct v4l2_subdev_video_ops ov5693_video_ops = {
.g_frame_interval = ov5693_g_frame_interval,
};
-static const struct v4l2_subdev_core_ops ov5693_core_ops = {
- .s_power = ov5693_s_power,
-};
-
static const struct v4l2_subdev_pad_ops ov5693_pad_ops = {
.enum_mbus_code = ov5693_enum_mbus_code,
.enum_frame_size = ov5693_enum_frame_size,
@@ -1707,7 +1594,6 @@ static const struct v4l2_subdev_pad_ops ov5693_pad_ops = {
};
static const struct v4l2_subdev_ops ov5693_ops = {
- .core = &ov5693_core_ops,
.video = &ov5693_video_ops,
.pad = &ov5693_pad_ops,
};
--
2.32.0
From be96a73783a26e423ba5bd8659e4277ad4851a72 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Thu, 28 Jan 2021 12:14:00 +0000
Subject: [PATCH] media: i2c: Trim unused headers from ov5693
The ov5693 driver includes a ton of unecessary headers,
trim the list down.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 8 --------
1 file changed, 8 deletions(-)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index ce26ce86fbd5..b3b391a49fdb 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -20,19 +20,11 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/errno.h>
#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/kmod.h>
#include <linux/module.h>
-#include <linux/mm.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/types.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
--
2.32.0
From e3e20fdc74abc4866ad9e4e4fd97729d56d838c0 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sat, 13 Feb 2021 21:39:35 +0000
Subject: [PATCH] media: i2c: Remove VCM stuff
This all needs binning, since we have no idea if it's right. It needs to
be moved to a driver for the VCM device I guess.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 325 +------------------------------------
1 file changed, 1 insertion(+), 324 deletions(-)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index b3b391a49fdb..2c82b6578de9 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -76,72 +76,6 @@
#define OV5693_PIXEL_ARRAY_WIDTH 2592U
#define OV5693_PIXEL_ARRAY_HEIGHT 1944U
-static int vcm_ad_i2c_wr8(struct i2c_client *client, u8 reg, u8 val)
-{
- int err;
- struct i2c_msg msg;
- u8 buf[2];
-
- buf[0] = reg;
- buf[1] = val;
-
- msg.addr = VCM_ADDR;
- msg.flags = 0;
- msg.len = 2;
- msg.buf = &buf[0];
-
- err = i2c_transfer(client->adapter, &msg, 1);
- if (err != 1) {
- dev_err(&client->dev, "%s: vcm i2c fail, err code = %d\n",
- __func__, err);
- return -EIO;
- }
- return 0;
-}
-
-static int ad5823_i2c_write(struct i2c_client *client, u8 reg, u8 val)
-{
- struct i2c_msg msg;
- u8 buf[2];
-
- buf[0] = reg;
- buf[1] = val;
- msg.addr = AD5823_VCM_ADDR;
- msg.flags = 0;
- msg.len = 0x02;
- msg.buf = &buf[0];
-
- if (i2c_transfer(client->adapter, &msg, 1) != 1)
- return -EIO;
- return 0;
-}
-
-static int ad5823_i2c_read(struct i2c_client *client, u8 reg, u8 *val)
-{
- struct i2c_msg msg[2];
- u8 buf[2];
-
- buf[0] = reg;
- buf[1] = 0;
-
- msg[0].addr = AD5823_VCM_ADDR;
- msg[0].flags = 0;
- msg[0].len = 0x01;
- msg[0].buf = &buf[0];
-
- msg[1].addr = 0x0c;
- msg[1].flags = I2C_M_RD;
- msg[1].len = 0x01;
- msg[1].buf = &buf[1];
- *val = 0;
- if (i2c_transfer(client->adapter, msg, 2) != 2)
- return -EIO;
- *val = buf[1];
- return 0;
-}
-
-static const u32 ov5693_embedded_effective_size = 28;
-
/* i2c read/write stuff */
static int ov5693_read_reg(struct i2c_client *client,
u16 data_length, u16 reg, u16 *val)
@@ -215,69 +149,6 @@ static int ov5693_i2c_write(struct i2c_client *client, u16 len, u8 *data)
return ret == num_msg ? 0 : -EIO;
}
-static int vcm_dw_i2c_write(struct i2c_client *client, u16 data)
-{
- struct i2c_msg msg;
- const int num_msg = 1;
- int ret;
- __be16 val;
-
- val = cpu_to_be16(data);
- msg.addr = VCM_ADDR;
- msg.flags = 0;
- msg.len = OV5693_16BIT;
- msg.buf = (void *)&val;
-
- ret = i2c_transfer(client->adapter, &msg, 1);
-
- return ret == num_msg ? 0 : -EIO;
-}
-
-/*
- * Theory: per datasheet, the two VCMs both allow for a 2-byte read.
- * The DW9714 doesn't actually specify what this does (it has a
- * two-byte write-only protocol, but specifies the read sequence as
- * legal), but it returns the same data (zeroes) always, after an
- * undocumented initial NAK. The AD5823 has a one-byte address
- * register to which all writes go, and subsequent reads will cycle
- * through the 8 bytes of registers. Notably, the default values (the
- * device is always power-cycled affirmatively, so we can rely on
- * these) in AD5823 are not pairwise repetitions of the same 16 bit
- * word. So all we have to do is sequentially read two bytes at a
- * time and see if we detect a difference in any of the first four
- * pairs.
- */
-static int vcm_detect(struct i2c_client *client)
-{
- int i, ret;
- struct i2c_msg msg;
- u16 data0 = 0, data;
-
- for (i = 0; i < 4; i++) {
- msg.addr = VCM_ADDR;
- msg.flags = I2C_M_RD;
- msg.len = sizeof(data);
- msg.buf = (u8 *)&data;
- ret = i2c_transfer(client->adapter, &msg, 1);
-
- /*
- * DW9714 always fails the first read and returns
- * zeroes for subsequent ones
- */
- if (i == 0 && ret == -EREMOTEIO) {
- data0 = 0;
- continue;
- }
-
- if (i == 0)
- data0 = data;
-
- if (data != data0)
- return VCM_AD5823;
- }
- return ret == 1 ? VCM_DW9714 : ret;
-}
-
static int ov5693_write_reg(struct i2c_client *client, u16 data_length,
u16 reg, u16 val)
{
@@ -654,89 +525,6 @@ static int ov5693_q_exposure(struct v4l2_subdev *sd, s32 *value)
return ret;
}
-static int ad5823_t_focus_vcm(struct v4l2_subdev *sd, u16 val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret = -EINVAL;
- u8 vcm_code;
-
- ret = ad5823_i2c_read(client, AD5823_REG_VCM_CODE_MSB, &vcm_code);
- if (ret)
- return ret;
-
- /* set reg VCM_CODE_MSB Bit[1:0] */
- vcm_code = (vcm_code & VCM_CODE_MSB_MASK) |
- ((val >> 8) & ~VCM_CODE_MSB_MASK);
- ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB, vcm_code);
- if (ret)
- return ret;
-
- /* set reg VCM_CODE_LSB Bit[7:0] */
- ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_LSB, (val & 0xff));
- if (ret)
- return ret;
-
- /* set required vcm move time */
- vcm_code = AD5823_RESONANCE_PERIOD / AD5823_RESONANCE_COEF
- - AD5823_HIGH_FREQ_RANGE;
- ret = ad5823_i2c_write(client, AD5823_REG_VCM_MOVE_TIME, vcm_code);
-
- return ret;
-}
-
-static int ad5823_t_focus_abs(struct v4l2_subdev *sd, s32 value)
-{
- value = min(value, AD5823_MAX_FOCUS_POS);
- return ad5823_t_focus_vcm(sd, value);
-}
-
-static int ov5693_t_focus_abs(struct v4l2_subdev *sd, s32 value)
-{
- struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret = 0;
-
- dev_dbg(&client->dev, "%s: FOCUS_POS: 0x%x\n", __func__, value);
- value = clamp(value, 0, OV5693_VCM_MAX_FOCUS_POS);
- if (ov5693->vcm == VCM_DW9714) {
- if (ov5693->vcm_update) {
- ret = vcm_dw_i2c_write(client, VCM_PROTECTION_OFF);
- if (ret)
- return ret;
- ret = vcm_dw_i2c_write(client, DIRECT_VCM);
- if (ret)
- return ret;
- ret = vcm_dw_i2c_write(client, VCM_PROTECTION_ON);
- if (ret)
- return ret;
- ov5693->vcm_update = false;
- }
- ret = vcm_dw_i2c_write(client,
- vcm_val(value, VCM_DEFAULT_S));
- } else if (ov5693->vcm == VCM_AD5823) {
- ad5823_t_focus_abs(sd, value);
- }
- if (ret == 0) {
- ov5693->number_of_steps = value - ov5693->focus;
- ov5693->focus = value;
- ov5693->timestamp_t_focus_abs = ktime_get();
- } else
- dev_err(&client->dev,
- "%s: i2c failed. ret %d\n", __func__, ret);
-
- return ret;
-}
-
-static int ov5693_t_focus_rel(struct v4l2_subdev *sd, s32 value)
-{
- struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
-
- return ov5693_t_focus_abs(sd, ov5693->focus + value);
-}
-
-#define DELAY_PER_STEP_NS 1000000
-#define DELAY_MAX_PER_STEP_NS (1000000 * 1023)
-
/* Exposure */
static int ov5693_get_exposure(struct ov5693_device *ov5693)
@@ -911,16 +699,6 @@ static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl)
return 0;
switch (ctrl->id) {
- case V4L2_CID_FOCUS_ABSOLUTE:
- dev_dbg(&client->dev, "%s: CID_FOCUS_ABSOLUTE:%d.\n",
- __func__, ctrl->val);
- ret = ov5693_t_focus_abs(&ov5693->sd, ctrl->val);
- break;
- case V4L2_CID_FOCUS_RELATIVE:
- dev_dbg(&client->dev, "%s: CID_FOCUS_RELATIVE:%d.\n",
- __func__, ctrl->val);
- ret = ov5693_t_focus_rel(&ov5693->sd, ctrl->val);
- break;
case V4L2_CID_EXPOSURE:
dev_dbg(&client->dev, "%s: CID_EXPOSURE:%d.\n",
__func__, ctrl->val);
@@ -983,90 +761,6 @@ static const struct v4l2_ctrl_ops ov5693_ctrl_ops = {
.g_volatile_ctrl = ov5693_g_volatile_ctrl
};
-static const struct v4l2_ctrl_config ov5693_controls[] = {
- {
- .ops = &ov5693_ctrl_ops,
- .id = V4L2_CID_FOCUS_ABSOLUTE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "focus move absolute",
- .min = 0,
- .max = OV5693_VCM_MAX_FOCUS_POS,
- .step = 1,
- .def = 0,
- .flags = 0,
- },
- {
- .ops = &ov5693_ctrl_ops,
- .id = V4L2_CID_FOCUS_RELATIVE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "focus move relative",
- .min = OV5693_VCM_MAX_FOCUS_NEG,
- .max = OV5693_VCM_MAX_FOCUS_POS,
- .step = 1,
- .def = 0,
- .flags = 0,
- },
-};
-
-static int ov5693_isp_configure(struct ov5693_device *ov5693)
-{
- int ret;
-
- /* Enable lens correction. */
- ret = ov5693_write_reg(ov5693->client, OV5693_8BIT,
- OV5693_ISP_CTRL0_REG, 0x86);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int ov5693_init(struct v4l2_subdev *sd)
-{
- struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
-
- if (!ov5693->has_vcm)
- return 0;
-
- dev_info(&client->dev, "%s\n", __func__);
- mutex_lock(&ov5693->lock);
- ov5693->vcm_update = false;
-
- if (ov5693->vcm == VCM_AD5823) {
- ret = vcm_ad_i2c_wr8(client, 0x01, 0x01); /* vcm init test */
- if (ret)
- dev_err(&client->dev,
- "vcm reset failed\n");
- /*change the mode*/
- ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB,
- AD5823_RING_CTRL_ENABLE);
- if (ret)
- dev_err(&client->dev,
- "vcm enable ringing failed\n");
- ret = ad5823_i2c_write(client, AD5823_REG_MODE,
- AD5823_ARC_RES1);
- if (ret)
- dev_err(&client->dev,
- "vcm change mode failed\n");
- }
-
- /*change initial focus value for ad5823*/
- if (ov5693->vcm == VCM_AD5823) {
- ov5693->focus = AD5823_INIT_FOCUS_POS;
- ov5693_t_focus_abs(sd, AD5823_INIT_FOCUS_POS);
- } else {
- ov5693->focus = 0;
- ov5693_t_focus_abs(sd, 0);
- }
-
- ov5693_isp_configure(ov5693);
- mutex_unlock(&ov5693->lock);
-
- return 0;
-}
-
static int ov5693_sw_standby(struct ov5693_device *ov5693, bool standby)
{
return ov5693_write_reg(ov5693->client, OV5693_8BIT, OV5693_SW_STREAM,
@@ -1327,9 +1021,6 @@ static int ov5693_set_fmt(struct v4l2_subdev *sd,
continue;
}
- mutex_unlock(&ov5693->lock);
- ov5693_init(sd);
- mutex_lock(&ov5693->lock);
ret = startup(sd);
if (ret)
dev_err(&client->dev, " startup() FAILED!\n");
@@ -1507,9 +1198,6 @@ static int ov5693_s_config(struct v4l2_subdev *sd, int irq)
goto fail_power_on;
}
- if (!ov5693->vcm)
- ov5693->vcm = vcm_detect(client);
-
/* config & detect sensor */
ret = ov5693_detect(client);
if (ret) {
@@ -1617,24 +1305,17 @@ static int ov5693_init_controls(struct ov5693_device *ov5693)
struct i2c_client *client = v4l2_get_subdevdata(&ov5693->sd);
const struct v4l2_ctrl_ops *ops = &ov5693_ctrl_ops;
struct v4l2_fwnode_device_properties props;
- unsigned int i;
int ret;
int hblank;
int vblank_max, vblank_min, vblank_def;
int exposure_max;
- ret = v4l2_ctrl_handler_init(&ov5693->ctrl_handler,
- ARRAY_SIZE(ov5693_controls));
+ ret = v4l2_ctrl_handler_init(&ov5693->ctrl_handler, 8);
if (ret) {
ov5693_remove(client);
return ret;
}
- for (i = 0; i < ARRAY_SIZE(ov5693_controls); i++)
- v4l2_ctrl_new_custom(&ov5693->ctrl_handler,
- &ov5693_controls[i],
- NULL);
-
/* link freq */
ov5693->ctrls.link_freq = v4l2_ctrl_new_int_menu(&ov5693->ctrl_handler,
NULL, V4L2_CID_LINK_FREQ,
@@ -1766,10 +1447,6 @@ static int ov5693_probe(struct i2c_client *client)
ov5693->client = client;
- /* check if VCM device exists */
- /* TODO: read from SSDB */
- ov5693->has_vcm = false;
-
mutex_init(&ov5693->lock);
v4l2_i2c_subdev_init(&ov5693->sd, client, &ov5693_ops);
--
2.32.0
From 89b871c65429c97af8e02c467ed335904b1c1119 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sat, 13 Feb 2021 22:16:08 +0000
Subject: [PATCH] media: i2c: Tidy up ov5693 sensor init
The initialisation of a mode when the sensor is activated is a bit messy,
so lets tidy that up a bit to bring it in line with other drivers.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 100 ++++++++++++++++---------------------
1 file changed, 42 insertions(+), 58 deletions(-)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index 2c82b6578de9..313bc9177328 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -767,6 +767,42 @@ static int ov5693_sw_standby(struct ov5693_device *ov5693, bool standby)
standby ? OV5693_STOP_STREAMING : OV5693_START_STREAMING);
}
+static int ov5693_sw_reset(struct ov5693_device *ov5693)
+{
+ return ov5693_write_reg(ov5693->client, OV5693_8BIT, OV5693_SW_RESET,
+ 0x01);
+}
+
+static int ov5693_sensor_init(struct ov5693_device *ov5693)
+{
+ struct i2c_client *client = ov5693->client;
+ int ret = 0;
+
+ ret = ov5693_sw_reset(ov5693);
+ if (ret) {
+ dev_err(&client->dev, "ov5693 reset err.\n");
+ return ret;
+ }
+
+ ret = ov5693_write_reg_array(client, ov5693_global_setting);
+ if (ret) {
+ dev_err(&client->dev, "ov5693 write register err.\n");
+ return ret;
+ }
+
+ ret = ov5693_write_reg_array(client, ov5693_res[ov5693->fmt_idx].regs);
+ if (ret) {
+ dev_err(&client->dev, "ov5693 write register err.\n");
+ return ret;
+ }
+
+ ret = ov5693_sw_standby(ov5693, true);
+ if (ret)
+ dev_err(&client->dev, "ov5693 stream off error\n");
+
+ return ret;
+}
+
static void ov5693_sensor_powerdown(struct ov5693_device *ov5693)
{
gpiod_set_value_cansleep(ov5693->reset, 1);
@@ -846,6 +882,12 @@ static int __maybe_unused ov5693_sensor_resume(struct device *dev)
if (ret)
goto out_unlock;
+ ret = ov5693_sensor_init(ov5693);
+ if (ret) {
+ dev_err(&client->dev, "ov5693 sensor init failure\n");
+ goto err_power;
+ }
+
if (ov5693->streaming) {
ret = ov5693_sw_standby(ov5693, false);
if (ret)
@@ -944,35 +986,6 @@ static int get_resolution_index(int w, int h)
return -1;
}
-/* TODO: remove it. */
-static int startup(struct v4l2_subdev *sd)
-{
- struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret = 0;
-
- ret = ov5693_write_reg(client, OV5693_8BIT,
- OV5693_SW_RESET, 0x01);
- if (ret) {
- dev_err(&client->dev, "ov5693 reset err.\n");
- return ret;
- }
-
- ret = ov5693_write_reg_array(client, ov5693_global_setting);
- if (ret) {
- dev_err(&client->dev, "ov5693 write register err.\n");
- return ret;
- }
-
- ret = ov5693_write_reg_array(client, ov5693_res[ov5693->fmt_idx].regs);
- if (ret) {
- dev_err(&client->dev, "ov5693 write register err.\n");
- return ret;
- }
-
- return ret;
-}
-
static int ov5693_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
@@ -982,7 +995,6 @@ static int ov5693_set_fmt(struct v4l2_subdev *sd,
struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret = 0;
int idx;
- int cnt;
if (format->pad)
return -EINVAL;
@@ -1014,34 +1026,6 @@ static int ov5693_set_fmt(struct v4l2_subdev *sd,
goto mutex_unlock;
}
- for (cnt = 0; cnt < OV5693_POWER_UP_RETRY_NUM; cnt++) {
- ret = ov5693_sensor_powerup(ov5693);
- if (ret) {
- dev_err(&client->dev, "power up failed\n");
- continue;
- }
-
- ret = startup(sd);
- if (ret)
- dev_err(&client->dev, " startup() FAILED!\n");
- else
- break;
- }
- if (cnt == OV5693_POWER_UP_RETRY_NUM) {
- dev_err(&client->dev, "power up failed, gave up\n");
- goto mutex_unlock;
- }
-
- /*
- * After sensor settings are set to HW, sometimes stream is started.
- * This would cause ISP timeout because ISP is not ready to receive
- * data yet. So add stop streaming here.
- */
- ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM,
- OV5693_STOP_STREAMING);
- if (ret)
- dev_warn(&client->dev, "ov5693 stream off err\n");
-
mutex_unlock:
mutex_unlock(&ov5693->lock);
return ret;
--
2.32.0
From af1a0a7bda0dfee190b72e48ae0bc1a7a32127d3 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Fri, 12 Feb 2021 16:14:04 +0000
Subject: [PATCH] media: i2c: cleanup macros in ov5693.h
Lots of orphaned or duplicated macros in this header file. Clean
those up a bit so it's less ugly.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.h | 89 +-------------------------------------
1 file changed, 2 insertions(+), 87 deletions(-)
diff --git a/drivers/media/i2c/ov5693.h b/drivers/media/i2c/ov5693.h
index b78d3b474a43..6502777eb5f3 100644
--- a/drivers/media/i2c/ov5693.h
+++ b/drivers/media/i2c/ov5693.h
@@ -37,68 +37,23 @@
*/
#define ENABLE_NON_PREVIEW 1
-#define OV5693_POWER_UP_RETRY_NUM 5
-
/* Defines for register writes and register array processing */
-#define I2C_MSG_LENGTH 0x2
-#define I2C_RETRY_COUNT 5
-
-#define OV5693_FOCAL_LENGTH_NUM 334 /*3.34mm*/
-#define OV5693_FOCAL_LENGTH_DEM 100
-#define OV5693_F_NUMBER_DEFAULT_NUM 24
-#define OV5693_F_NUMBER_DEM 10
+#define I2C_MSG_LENGTH 0x2
#define MAX_FMTS 1
-/* sensor_mode_data read_mode adaptation */
-#define OV5693_READ_MODE_BINNING_ON 0x0400
-#define OV5693_READ_MODE_BINNING_OFF 0x00
-#define OV5693_INTEGRATION_TIME_MARGIN 8
-
-#define OV5693_MAX_EXPOSURE_VALUE 0xFFF1
-#define OV5693_MAX_GAIN_VALUE 0xFF
-
-/*
- * focal length bits definition:
- * bits 31-16: numerator, bits 15-0: denominator
- */
-#define OV5693_FOCAL_LENGTH_DEFAULT 0x1B70064
-
-/*
- * current f-number bits definition:
- * bits 31-16: numerator, bits 15-0: denominator
- */
-#define OV5693_F_NUMBER_DEFAULT 0x18000a
-
-/*
- * f-number range bits definition:
- * bits 31-24: max f-number numerator
- * bits 23-16: max f-number denominator
- * bits 15-8: min f-number numerator
- * bits 7-0: min f-number denominator
- */
-#define OV5693_F_NUMBER_RANGE 0x180a180a
#define OV5693_ID 0x5690
-#define OV5693_FINE_INTG_TIME_MIN 0
-#define OV5693_FINE_INTG_TIME_MAX_MARGIN 0
-#define OV5693_COARSE_INTG_TIME_MIN 1
-#define OV5693_COARSE_INTG_TIME_MAX_MARGIN 6
-
-#define OV5693_BIN_FACTOR_MAX 4
/*
* OV5693 System control registers
*/
-#define OV5693_SW_SLEEP 0x0100
#define OV5693_SW_RESET 0x0103
#define OV5693_SW_STREAM 0x0100
#define OV5693_SC_CMMN_CHIP_ID_H 0x300A
#define OV5693_SC_CMMN_CHIP_ID_L 0x300B
-#define OV5693_SC_CMMN_SCCB_ID 0x300C
#define OV5693_SC_CMMN_SUB_ID 0x302A /* process, version*/
-/*Bit[7:4] Group control, Bit[3:0] Group ID*/
-#define OV5693_GROUP_ACCESS 0x3208
+
/*
*Bit[3:0] Bit[19:16] of exposure,
*remaining 16 bits lies in Reg0x3501&Reg0x3502
@@ -110,18 +65,6 @@
#define OV5693_AGC_H 0x350A
#define OV5693_AGC_L 0x350B /*Bit[7:0] of gain*/
-#define OV5693_HORIZONTAL_START_H 0x3800 /*Bit[11:8]*/
-#define OV5693_HORIZONTAL_START_L 0x3801 /*Bit[7:0]*/
-#define OV5693_VERTICAL_START_H 0x3802 /*Bit[11:8]*/
-#define OV5693_VERTICAL_START_L 0x3803 /*Bit[7:0]*/
-#define OV5693_HORIZONTAL_END_H 0x3804 /*Bit[11:8]*/
-#define OV5693_HORIZONTAL_END_L 0x3805 /*Bit[7:0]*/
-#define OV5693_VERTICAL_END_H 0x3806 /*Bit[11:8]*/
-#define OV5693_VERTICAL_END_L 0x3807 /*Bit[7:0]*/
-#define OV5693_HORIZONTAL_OUTPUT_SIZE_H 0x3808 /*Bit[3:0]*/
-#define OV5693_HORIZONTAL_OUTPUT_SIZE_L 0x3809 /*Bit[7:0]*/
-#define OV5693_VERTICAL_OUTPUT_SIZE_H 0x380a /*Bit[3:0]*/
-#define OV5693_VERTICAL_OUTPUT_SIZE_L 0x380b /*Bit[7:0]*/
/*High 8-bit, and low 8-bit HTS address is 0x380d*/
#define OV5693_TIMING_HTS_H 0x380C
/*High 8-bit, and low 8-bit HTS address is 0x380d*/
@@ -141,34 +84,6 @@
#define OV5693_START_STREAMING 0x01
#define OV5693_STOP_STREAMING 0x00
-#define VCM_ADDR 0x0c
-#define VCM_CODE_MSB 0x04
-
-#define OV5693_INVALID_CONFIG 0xffffffff
-
-#define OV5693_VCM_SLEW_STEP 0x30F0
-#define OV5693_VCM_SLEW_STEP_MAX 0x7
-#define OV5693_VCM_SLEW_STEP_MASK 0x7
-#define OV5693_VCM_CODE 0x30F2
-#define OV5693_VCM_SLEW_TIME 0x30F4
-#define OV5693_VCM_SLEW_TIME_MAX 0xffff
-#define OV5693_VCM_ENABLE 0x8000
-
-#define OV5693_VCM_MAX_FOCUS_NEG -1023
-#define OV5693_VCM_MAX_FOCUS_POS 1023
-
-#define DLC_ENABLE 1
-#define DLC_DISABLE 0
-#define VCM_PROTECTION_OFF 0xeca3
-#define VCM_PROTECTION_ON 0xdc51
-#define VCM_DEFAULT_S 0x0
-#define vcm_step_s(a) (u8)(a & 0xf)
-#define vcm_step_mclk(a) (u8)((a >> 4) & 0x3)
-#define vcm_dlc_mclk(dlc, mclk) (u16)((dlc << 3) | mclk | 0xa104)
-#define vcm_tsrc(tsrc) (u16)(tsrc << 3 | 0xf200)
-#define vcm_val(data, s) (u16)(data << 4 | s)
-#define DIRECT_VCM vcm_dlc_mclk(0, 0)
-
/* Defines for OTP Data Registers */
#define OV5693_FRAME_OFF_NUM 0x4202
#define OV5693_OTP_BYTE_MAX 32 //change to 32 as needed by otpdata
--
2.32.0
From bb355f481db0edacb0c5e19342c326f986374fd4 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Fri, 12 Feb 2021 16:19:09 +0000
Subject: [PATCH] media: i2c: use devm_kzalloc() to initialise ov5693
There's a memory leak in probe because we're not using devres; swtich
so that we are.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index 313bc9177328..d092ed698eb3 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -1425,7 +1425,7 @@ static int ov5693_probe(struct i2c_client *client)
dev_info(&client->dev, "%s() called", __func__);
- ov5693 = kzalloc(sizeof(*ov5693), GFP_KERNEL);
+ ov5693 = devm_kzalloc(&client->dev, sizeof(*ov5693), GFP_KERNEL);
if (!ov5693)
return -ENOMEM;
--
2.32.0
From ad003583211bd012de9e728bbbfb194c6f20bb40 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Fri, 12 Feb 2021 16:26:21 +0000
Subject: [PATCH] media: i2c: Check for supported clk rate in probe
The ov5693 driver is configured to support a 19.2MHz external clock only.
Check that we do indeed have that value and if not, exit with -EINVAL.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 8 ++++++++
drivers/media/i2c/ov5693.h | 2 ++
2 files changed, 10 insertions(+)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index d092ed698eb3..8082d37841da 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -1421,6 +1421,7 @@ static int ov5693_get_regulators(struct ov5693_device *ov5693)
static int ov5693_probe(struct i2c_client *client)
{
struct ov5693_device *ov5693;
+ u32 clk_rate;
int ret = 0;
dev_info(&client->dev, "%s() called", __func__);
@@ -1441,6 +1442,13 @@ static int ov5693_probe(struct i2c_client *client)
return -EINVAL;
}
+ clk_rate = clk_get_rate(ov5693->clk);
+ if (clk_rate != OV5693_XVCLK_FREQ) {
+ dev_err(&client->dev, "Unsupported clk freq %u, expected %u\n",
+ clk_rate, OV5693_XVCLK_FREQ);
+ return -EINVAL;
+ }
+
ret = ov5693_configure_gpios(ov5693);
if (ret)
goto out_free;
diff --git a/drivers/media/i2c/ov5693.h b/drivers/media/i2c/ov5693.h
index 6502777eb5f3..0dfbbe9a0ff2 100644
--- a/drivers/media/i2c/ov5693.h
+++ b/drivers/media/i2c/ov5693.h
@@ -100,6 +100,8 @@
#define OV5693_OTP_READ_ONETIME 16
#define OV5693_OTP_MODE_READ 1
+#define OV5693_XVCLK_FREQ 19200000
+
/* link freq and pixel rate required for IPU3 */
#define OV5693_LINK_FREQ_400MHZ 400000000
/* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample
--
2.32.0
From de36f872ad563328530b088a5710451cafc26fa9 Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sat, 13 Feb 2021 23:17:50 +0000
Subject: [PATCH] media: i2c: Use devres to fetch gpios
Use devres; it'll simplify error handling through this function
and probe.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 22 +++++-----------------
1 file changed, 5 insertions(+), 17 deletions(-)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index 8082d37841da..c580159079d2 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -1270,8 +1270,6 @@ static int ov5693_remove(struct i2c_client *client)
dev_info(&client->dev, "%s...\n", __func__);
- gpiod_put(ov5693->reset);
- gpiod_put(ov5693->indicator_led);
while (i--)
regulator_put(ov5693->supplies[i].consumer);
@@ -1372,38 +1370,28 @@ static int ov5693_init_controls(struct ov5693_device *ov5693)
static int ov5693_configure_gpios(struct ov5693_device *ov5693)
{
- int ret;
-
- ov5693->reset = gpiod_get_optional(&ov5693->client->dev, "reset",
+ ov5693->reset = devm_gpiod_get_optional(&ov5693->client->dev, "reset",
GPIOD_OUT_HIGH);
if (IS_ERR(ov5693->reset)) {
dev_err(&ov5693->client->dev, "Couldn't find reset GPIO\n");
return PTR_ERR(ov5693->reset);
}
- ov5693->powerdown = gpiod_get_optional(&ov5693->client->dev, "powerdown",
+ ov5693->powerdown = devm_gpiod_get_optional(&ov5693->client->dev, "powerdown",
GPIOD_OUT_HIGH);
if (IS_ERR(ov5693->powerdown)) {
dev_err(&ov5693->client->dev, "Couldn't find powerdown GPIO\n");
- ret = PTR_ERR(ov5693->powerdown);
- goto err_put_reset;
+ return PTR_ERR(ov5693->powerdown);
}
- ov5693->indicator_led = gpiod_get_optional(&ov5693->client->dev, "indicator-led",
+ ov5693->indicator_led = devm_gpiod_get_optional(&ov5693->client->dev, "indicator-led",
GPIOD_OUT_HIGH);
if (IS_ERR(ov5693->indicator_led)) {
dev_err(&ov5693->client->dev, "Couldn't find indicator-led GPIO\n");
- ret = PTR_ERR(ov5693->indicator_led);
- goto err_put_powerdown;
+ return PTR_ERR(ov5693->indicator_led);
}
return 0;
-err_put_reset:
- gpiod_put(ov5693->reset);
-err_put_powerdown:
- gpiod_put(ov5693->powerdown);
-
- return ret;
}
static int ov5693_get_regulators(struct ov5693_device *ov5693)
--
2.32.0
From 1ad63640be30fcd140be14538d103a4c2923420e Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sat, 13 Feb 2021 23:20:47 +0000
Subject: [PATCH] media: i2c: Use devres to fetch regulators
As before, use devres to simplify error handling and driver removal
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index c580159079d2..9f61b470f8ba 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -1266,13 +1266,9 @@ static int ov5693_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
- unsigned int i = OV5693_NUM_SUPPLIES;
dev_info(&client->dev, "%s...\n", __func__);
- while (i--)
- regulator_put(ov5693->supplies[i].consumer);
-
v4l2_async_unregister_subdev(sd);
media_entity_cleanup(&ov5693->sd.entity);
@@ -1401,7 +1397,7 @@ static int ov5693_get_regulators(struct ov5693_device *ov5693)
for (i = 0; i < OV5693_NUM_SUPPLIES; i++)
ov5693->supplies[i].supply = ov5693_supply_names[i];
- return regulator_bulk_get(&ov5693->client->dev,
+ return devm_regulator_bulk_get(&ov5693->client->dev,
OV5693_NUM_SUPPLIES,
ov5693->supplies);
}
--
2.32.0
From 4f05d8705fb88e3c7854ac12a54e7a11b9c37cfd Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sun, 14 Feb 2021 12:39:14 +0000
Subject: [PATCH] media: i2c: remove debug print
The exposure configure function has a debug print. It's working fine,
so bin it.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 37 -------------------------------------
1 file changed, 37 deletions(-)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index 9f61b470f8ba..622a7ddf4063 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -526,41 +526,6 @@ static int ov5693_q_exposure(struct v4l2_subdev *sd, s32 *value)
}
/* Exposure */
-
-static int ov5693_get_exposure(struct ov5693_device *ov5693)
-{
- u32 exposure = 0;
- u16 tmp;
- int ret = 0;
-
- /* get exposure */
- ret = ov5693_read_reg(ov5693->client, OV5693_8BIT,
- OV5693_EXPOSURE_L,
- &tmp);
- if (ret)
- return ret;
-
- exposure |= ((tmp >> 4) & 0b1111);
-
- ret = ov5693_read_reg(ov5693->client, OV5693_8BIT,
- OV5693_EXPOSURE_M,
- &tmp);
- if (ret)
- return ret;
-
- exposure |= (tmp << 4);
- ret = ov5693_read_reg(ov5693->client, OV5693_8BIT,
- OV5693_EXPOSURE_H,
- &tmp);
- if (ret)
- return ret;
-
- exposure |= (tmp << 12);
-
- printk("exposure set to: %u\n", exposure);
- return ret;
-}
-
static int ov5693_exposure_configure(struct ov5693_device *ov5693, u32 exposure)
{
int ret;
@@ -571,7 +536,6 @@ static int ov5693_exposure_configure(struct ov5693_device *ov5693, u32 exposure)
*/
exposure = exposure * 16;
- ov5693_get_exposure(ov5693);
ret = ov5693_write_reg(ov5693->client, OV5693_8BIT,
OV5693_EXPOSURE_CTRL_HH_REG, OV5693_EXPOSURE_CTRL_HH(exposure));
if (ret)
@@ -586,7 +550,6 @@ static int ov5693_exposure_configure(struct ov5693_device *ov5693, u32 exposure)
OV5693_EXPOSURE_CTRL_L_REG, OV5693_EXPOSURE_CTRL_L(exposure));
if (ret)
return ret;
- ov5693_get_exposure(ov5693);
return 0;
}
--
2.32.0
From 298bcba816e737d2ae899fd60509688c318837fa Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sun, 14 Feb 2021 14:32:50 +0000
Subject: [PATCH] media: i2c: Remove unused resolutions from ov5693
The list of resolutions in here is really unmaintanably long. For now just
bin all of the ones that are not part of ov5693_res_video, which is the
only array of resolutions in use anyway.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.h | 357 +------------------------------------
1 file changed, 1 insertion(+), 356 deletions(-)
diff --git a/drivers/media/i2c/ov5693.h b/drivers/media/i2c/ov5693.h
index 0dfbbe9a0ff2..29e6735112da 100644
--- a/drivers/media/i2c/ov5693.h
+++ b/drivers/media/i2c/ov5693.h
@@ -474,34 +474,7 @@ static struct ov5693_reg const ov5693_global_setting[] = {
};
#if ENABLE_NON_PREVIEW
-/*
- * 654x496 30fps 17ms VBlanking 2lane 10Bit (Scaling)
- */
-static struct ov5693_reg const ov5693_654x496[] = {
- {OV5693_8BIT, 0x3501, 0x3d},
- {OV5693_8BIT, 0x3502, 0x00},
- {OV5693_8BIT, 0x3708, 0xe6},
- {OV5693_8BIT, 0x3709, 0xc7},
- {OV5693_8BIT, 0x3803, 0x00},
- {OV5693_8BIT, 0x3806, 0x07},
- {OV5693_8BIT, 0x3807, 0xa3},
- {OV5693_8BIT, 0x3808, 0x02},
- {OV5693_8BIT, 0x3809, 0x90},
- {OV5693_8BIT, 0x380a, 0x01},
- {OV5693_8BIT, 0x380b, 0xf0},
- {OV5693_8BIT, 0x380c, 0x0a},
- {OV5693_8BIT, 0x380d, 0x80},
- {OV5693_8BIT, 0x380e, 0x07},
- {OV5693_8BIT, 0x380f, 0xc0},
- {OV5693_8BIT, 0x3811, 0x08},
- {OV5693_8BIT, 0x3813, 0x02},
- {OV5693_8BIT, 0x3814, 0x31},
- {OV5693_8BIT, 0x3815, 0x31},
- {OV5693_8BIT, 0x3820, 0x04},
- {OV5693_8BIT, 0x3821, 0x1f},
- {OV5693_8BIT, 0x5002, 0x80},
- {OV5693_TOK_TERM, 0, 0}
-};
+
/*
* 1296x976 30fps 17ms VBlanking 2lane 10Bit (Scaling)
@@ -660,62 +633,10 @@ static struct ov5693_reg const ov5693_736x496[] = {
};
#endif
-/*
-static struct ov5693_reg const ov5693_736x496[] = {
- {OV5693_8BIT, 0x3501, 0x7b},
- {OV5693_8BIT, 0x3502, 0x00},
- {OV5693_8BIT, 0x3708, 0xe6},
- {OV5693_8BIT, 0x3709, 0xc3},
- {OV5693_8BIT, 0x3803, 0x00},
- {OV5693_8BIT, 0x3806, 0x07},
- {OV5693_8BIT, 0x3807, 0xa3},
- {OV5693_8BIT, 0x3808, 0x02},
- {OV5693_8BIT, 0x3809, 0xe0},
- {OV5693_8BIT, 0x380a, 0x01},
- {OV5693_8BIT, 0x380b, 0xf0},
- {OV5693_8BIT, 0x380c, 0x0d},
- {OV5693_8BIT, 0x380d, 0xb0},
- {OV5693_8BIT, 0x380e, 0x05},
- {OV5693_8BIT, 0x380f, 0xf2},
- {OV5693_8BIT, 0x3811, 0x08},
- {OV5693_8BIT, 0x3813, 0x02},
- {OV5693_8BIT, 0x3814, 0x31},
- {OV5693_8BIT, 0x3815, 0x31},
- {OV5693_8BIT, 0x3820, 0x01},
- {OV5693_8BIT, 0x3821, 0x1f},
- {OV5693_8BIT, 0x5002, 0x00},
- {OV5693_TOK_TERM, 0, 0}
-};
-*/
/*
* 976x556 30fps 8.8ms VBlanking 2lane 10Bit (Scaling)
*/
#if ENABLE_NON_PREVIEW
-static struct ov5693_reg const ov5693_976x556[] = {
- {OV5693_8BIT, 0x3501, 0x7b},
- {OV5693_8BIT, 0x3502, 0x00},
- {OV5693_8BIT, 0x3708, 0xe2},
- {OV5693_8BIT, 0x3709, 0xc3},
- {OV5693_8BIT, 0x3803, 0xf0},
- {OV5693_8BIT, 0x3806, 0x06},
- {OV5693_8BIT, 0x3807, 0xa7},
- {OV5693_8BIT, 0x3808, 0x03},
- {OV5693_8BIT, 0x3809, 0xd0},
- {OV5693_8BIT, 0x380a, 0x02},
- {OV5693_8BIT, 0x380b, 0x2C},
- {OV5693_8BIT, 0x380c, 0x0a},
- {OV5693_8BIT, 0x380d, 0x80},
- {OV5693_8BIT, 0x380e, 0x07},
- {OV5693_8BIT, 0x380f, 0xc0},
- {OV5693_8BIT, 0x3811, 0x10},
- {OV5693_8BIT, 0x3813, 0x02},
- {OV5693_8BIT, 0x3814, 0x11},
- {OV5693_8BIT, 0x3815, 0x11},
- {OV5693_8BIT, 0x3820, 0x00},
- {OV5693_8BIT, 0x3821, 0x1e},
- {OV5693_8BIT, 0x5002, 0x80},
- {OV5693_TOK_TERM, 0, 0}
-};
/*DS from 2624x1492*/
static struct ov5693_reg const ov5693_1296x736[] = {
@@ -782,40 +703,6 @@ static struct ov5693_reg const ov5693_1636p_30fps[] = {
};
#endif
-static struct ov5693_reg const ov5693_1616x1216_30fps[] = {
- {OV5693_8BIT, 0x3501, 0x7b},
- {OV5693_8BIT, 0x3502, 0x80},
- {OV5693_8BIT, 0x3708, 0xe2},
- {OV5693_8BIT, 0x3709, 0xc3},
- {OV5693_8BIT, 0x3800, 0x00}, /*{3800,3801} Array X start*/
- {OV5693_8BIT, 0x3801, 0x08}, /* 04 //{3800,3801} Array X start*/
- {OV5693_8BIT, 0x3802, 0x00}, /*{3802,3803} Array Y start*/
- {OV5693_8BIT, 0x3803, 0x04}, /* 00 //{3802,3803} Array Y start*/
- {OV5693_8BIT, 0x3804, 0x0a}, /*{3804,3805} Array X end*/
- {OV5693_8BIT, 0x3805, 0x37}, /* 3b //{3804,3805} Array X end*/
- {OV5693_8BIT, 0x3806, 0x07}, /*{3806,3807} Array Y end*/
- {OV5693_8BIT, 0x3807, 0x9f}, /* a3 //{3806,3807} Array Y end*/
- {OV5693_8BIT, 0x3808, 0x06}, /*{3808,3809} Final output H size*/
- {OV5693_8BIT, 0x3809, 0x50}, /*{3808,3809} Final output H size*/
- {OV5693_8BIT, 0x380a, 0x04}, /*{380a,380b} Final output V size*/
- {OV5693_8BIT, 0x380b, 0xc0}, /*{380a,380b} Final output V size*/
- {OV5693_8BIT, 0x380c, 0x0a}, /*{380c,380d} HTS*/
- {OV5693_8BIT, 0x380d, 0x80}, /*{380c,380d} HTS*/
- {OV5693_8BIT, 0x380e, 0x07}, /*{380e,380f} VTS*/
- {OV5693_8BIT, 0x380f, 0xc0}, /* bc //{380e,380f} VTS*/
- {OV5693_8BIT, 0x3810, 0x00}, /*{3810,3811} windowing X offset*/
- {OV5693_8BIT, 0x3811, 0x10}, /*{3810,3811} windowing X offset*/
- {OV5693_8BIT, 0x3812, 0x00}, /*{3812,3813} windowing Y offset*/
- {OV5693_8BIT, 0x3813, 0x06}, /*{3812,3813} windowing Y offset*/
- {OV5693_8BIT, 0x3814, 0x11}, /*X subsample control*/
- {OV5693_8BIT, 0x3815, 0x11}, /*Y subsample control*/
- {OV5693_8BIT, 0x3820, 0x00}, /*FLIP/Binnning control*/
- {OV5693_8BIT, 0x3821, 0x1e}, /*MIRROR control*/
- {OV5693_8BIT, 0x5002, 0x00},
- {OV5693_8BIT, 0x5041, 0x84},
- {OV5693_TOK_TERM, 0, 0}
-};
-
/*
* 1940x1096 30fps 8.8ms VBlanking 2lane 10bit (Scaling)
*/
@@ -878,37 +765,6 @@ static struct ov5693_reg const ov5693_2592x1456_30fps[] = {
};
#endif
-static struct ov5693_reg const ov5693_2576x1456_30fps[] = {
- {OV5693_8BIT, 0x3501, 0x7b},
- {OV5693_8BIT, 0x3502, 0x00},
- {OV5693_8BIT, 0x3708, 0xe2},
- {OV5693_8BIT, 0x3709, 0xc3},
- {OV5693_8BIT, 0x3800, 0x00},
- {OV5693_8BIT, 0x3801, 0x00},
- {OV5693_8BIT, 0x3802, 0x00},
- {OV5693_8BIT, 0x3803, 0xf0},
- {OV5693_8BIT, 0x3804, 0x0a},
- {OV5693_8BIT, 0x3805, 0x3f},
- {OV5693_8BIT, 0x3806, 0x06},
- {OV5693_8BIT, 0x3807, 0xa4},
- {OV5693_8BIT, 0x3808, 0x0a},
- {OV5693_8BIT, 0x3809, 0x10},
- {OV5693_8BIT, 0x380a, 0x05},
- {OV5693_8BIT, 0x380b, 0xb0},
- {OV5693_8BIT, 0x380c, 0x0a},
- {OV5693_8BIT, 0x380d, 0x80},
- {OV5693_8BIT, 0x380e, 0x07},
- {OV5693_8BIT, 0x380f, 0xc0},
- {OV5693_8BIT, 0x3811, 0x18},
- {OV5693_8BIT, 0x3813, 0x00},
- {OV5693_8BIT, 0x3814, 0x11},
- {OV5693_8BIT, 0x3815, 0x11},
- {OV5693_8BIT, 0x3820, 0x00},
- {OV5693_8BIT, 0x3821, 0x1e},
- {OV5693_8BIT, 0x5002, 0x00},
- {OV5693_TOK_TERM, 0, 0}
-};
-
/*
* 2592x1944 30fps 0.6ms VBlanking 2lane 10Bit
*/
@@ -940,49 +796,6 @@ static struct ov5693_reg const ov5693_2592x1944_30fps[] = {
};
#endif
-/*
- * 11:9 Full FOV Output, expected FOV Res: 2346x1920
- * ISP Effect Res: 1408x1152
- * Sensor out: 1424x1168, DS From: 2380x1952
- *
- * WA: Left Offset: 8, Hor scal: 64
- */
-#if ENABLE_NON_PREVIEW
-static struct ov5693_reg const ov5693_1424x1168_30fps[] = {
- {OV5693_8BIT, 0x3501, 0x3b}, /* long exposure[15:8] */
- {OV5693_8BIT, 0x3502, 0x80}, /* long exposure[7:0] */
- {OV5693_8BIT, 0x3708, 0xe2},
- {OV5693_8BIT, 0x3709, 0xc3},
- {OV5693_8BIT, 0x3800, 0x00}, /* TIMING_X_ADDR_START */
- {OV5693_8BIT, 0x3801, 0x50}, /* 80 */
- {OV5693_8BIT, 0x3802, 0x00}, /* TIMING_Y_ADDR_START */
- {OV5693_8BIT, 0x3803, 0x02}, /* 2 */
- {OV5693_8BIT, 0x3804, 0x09}, /* TIMING_X_ADDR_END */
- {OV5693_8BIT, 0x3805, 0xdd}, /* 2525 */
- {OV5693_8BIT, 0x3806, 0x07}, /* TIMING_Y_ADDR_END */
- {OV5693_8BIT, 0x3807, 0xa1}, /* 1953 */
- {OV5693_8BIT, 0x3808, 0x05}, /* TIMING_X_OUTPUT_SIZE */
- {OV5693_8BIT, 0x3809, 0x90}, /* 1424 */
- {OV5693_8BIT, 0x380a, 0x04}, /* TIMING_Y_OUTPUT_SIZE */
- {OV5693_8BIT, 0x380b, 0x90}, /* 1168 */
- {OV5693_8BIT, 0x380c, 0x0a}, /* TIMING_HTS */
- {OV5693_8BIT, 0x380d, 0x80},
- {OV5693_8BIT, 0x380e, 0x07}, /* TIMING_VTS */
- {OV5693_8BIT, 0x380f, 0xc0},
- {OV5693_8BIT, 0x3810, 0x00}, /* TIMING_ISP_X_WIN */
- {OV5693_8BIT, 0x3811, 0x02}, /* 2 */
- {OV5693_8BIT, 0x3812, 0x00}, /* TIMING_ISP_Y_WIN */
- {OV5693_8BIT, 0x3813, 0x00}, /* 0 */
- {OV5693_8BIT, 0x3814, 0x11}, /* TIME_X_INC */
- {OV5693_8BIT, 0x3815, 0x11}, /* TIME_Y_INC */
- {OV5693_8BIT, 0x3820, 0x00},
- {OV5693_8BIT, 0x3821, 0x1e},
- {OV5693_8BIT, 0x5002, 0x00},
- {OV5693_8BIT, 0x5041, 0x84}, /* scale is auto enabled */
- {OV5693_TOK_TERM, 0, 0}
-};
-#endif
-
/*
* 3:2 Full FOV Output, expected FOV Res: 2560x1706
* ISP Effect Res: 720x480
@@ -1022,173 +835,6 @@ static struct ov5693_reg const ov5693_736x496_30fps[] = {
{OV5693_TOK_TERM, 0, 0}
};
-static struct ov5693_reg const ov5693_2576x1936_30fps[] = {
- {OV5693_8BIT, 0x3501, 0x7b},
- {OV5693_8BIT, 0x3502, 0x00},
- {OV5693_8BIT, 0x3708, 0xe2},
- {OV5693_8BIT, 0x3709, 0xc3},
- {OV5693_8BIT, 0x3803, 0x00},
- {OV5693_8BIT, 0x3806, 0x07},
- {OV5693_8BIT, 0x3807, 0xa3},
- {OV5693_8BIT, 0x3808, 0x0a},
- {OV5693_8BIT, 0x3809, 0x10},
- {OV5693_8BIT, 0x380a, 0x07},
- {OV5693_8BIT, 0x380b, 0x90},
- {OV5693_8BIT, 0x380c, 0x0a},
- {OV5693_8BIT, 0x380d, 0x80},
- {OV5693_8BIT, 0x380e, 0x07},
- {OV5693_8BIT, 0x380f, 0xc0},
- {OV5693_8BIT, 0x3811, 0x18},
- {OV5693_8BIT, 0x3813, 0x00},
- {OV5693_8BIT, 0x3814, 0x11},
- {OV5693_8BIT, 0x3815, 0x11},
- {OV5693_8BIT, 0x3820, 0x00},
- {OV5693_8BIT, 0x3821, 0x1e},
- {OV5693_8BIT, 0x5002, 0x00},
- {OV5693_TOK_TERM, 0, 0}
-};
-
-static struct ov5693_resolution ov5693_res_preview[] = {
- {
- .desc = "ov5693_736x496_30fps",
- .width = 736,
- .height = 496,
- .pix_clk_freq = 160,
- .fps = 30,
- .used = 0,
- .pixels_per_line = 2688,
- .lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
- .regs = ov5693_736x496_30fps,
- },
- {
- .desc = "ov5693_1616x1216_30fps",
- .width = 1616,
- .height = 1216,
- .pix_clk_freq = 160,
- .fps = 30,
- .used = 0,
- .pixels_per_line = 2688,
- .lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
- .regs = ov5693_1616x1216_30fps,
- },
- {
- .desc = "ov5693_5M_30fps",
- .width = 2576,
- .height = 1456,
- .pix_clk_freq = 160,
- .fps = 30,
- .used = 0,
- .pixels_per_line = 2688,
- .lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
- .regs = ov5693_2576x1456_30fps,
- },
- {
- .desc = "ov5693_5M_30fps",
- .width = 2576,
- .height = 1936,
- .pix_clk_freq = 160,
- .fps = 30,
- .used = 0,
- .pixels_per_line = 2688,
- .lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
- .regs = ov5693_2576x1936_30fps,
- },
-};
-
-#define N_RES_PREVIEW (ARRAY_SIZE(ov5693_res_preview))
-
-/*
- * Disable non-preview configurations until the configuration selection is
- * improved.
- */
-#if ENABLE_NON_PREVIEW
-struct ov5693_resolution ov5693_res_still[] = {
- {
- .desc = "ov5693_736x496_30fps",
- .width = 736,
- .height = 496,
- .pix_clk_freq = 160,
- .fps = 30,
- .used = 0,
- .pixels_per_line = 2688,
- .lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
- .regs = ov5693_736x496_30fps,
- },
- {
- .desc = "ov5693_1424x1168_30fps",
- .width = 1424,
- .height = 1168,
- .pix_clk_freq = 160,
- .fps = 30,
- .used = 0,
- .pixels_per_line = 2688,
- .lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
- .regs = ov5693_1424x1168_30fps,
- },
- {
- .desc = "ov5693_1616x1216_30fps",
- .width = 1616,
- .height = 1216,
- .pix_clk_freq = 160,
- .fps = 30,
- .used = 0,
- .pixels_per_line = 2688,
- .lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
- .regs = ov5693_1616x1216_30fps,
- },
- {
- .desc = "ov5693_5M_30fps",
- .width = 2592,
- .height = 1456,
- .pix_clk_freq = 160,
- .fps = 30,
- .used = 0,
- .pixels_per_line = 2688,
- .lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
- .regs = ov5693_2592x1456_30fps,
- },
- {
- .desc = "ov5693_5M_30fps",
- .width = 2592,
- .height = 1944,
- .pix_clk_freq = 160,
- .fps = 30,
- .used = 0,
- .pixels_per_line = 2688,
- .lines_per_frame = 1984,
- .bin_factor_x = 1,
- .bin_factor_y = 1,
- .bin_mode = 0,
- .regs = ov5693_2592x1944_30fps,
- },
-};
-
-#define N_RES_STILL (ARRAY_SIZE(ov5693_res_still))
-
struct ov5693_resolution ov5693_res_video[] = {
{
.desc = "ov5693_736x496_30fps",
@@ -1343,4 +989,3 @@ struct ov5693_resolution ov5693_res_video[] = {
static struct ov5693_resolution *ov5693_res = ov5693_res_video;
static unsigned long N_RES = N_RES_VIDEO;
-#endif
--
2.32.0
From cb4677a0ba7c6d511bb20aee9831a9eaecb5f33b Mon Sep 17 00:00:00 2001
From: Daniel Scally <djrscally@gmail.com>
Date: Sun, 14 Feb 2021 14:45:58 +0000
Subject: [PATCH] media: i2c: update set_fmt() for ov5693
The set_fmt() function is a bit messy still, using home grown solutions to
find the closest supported resolution instead of the v4l2 helpers. It also
fails to update control ranges to account for the new mode (though this is
moot currently as they're all the same, but the probably shouldn't be).
Fix it up a little.
Signed-off-by: Daniel Scally <djrscally@gmail.com>
Patchset: cameras
---
drivers/media/i2c/ov5693.c | 148 ++++++++++---------------------------
drivers/media/i2c/ov5693.h | 5 +-
2 files changed, 40 insertions(+), 113 deletions(-)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index 622a7ddf4063..09c84006d5c9 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -753,7 +753,7 @@ static int ov5693_sensor_init(struct ov5693_device *ov5693)
return ret;
}
- ret = ov5693_write_reg_array(client, ov5693_res[ov5693->fmt_idx].regs);
+ ret = ov5693_write_reg_array(client, ov5693->mode->regs);
if (ret) {
dev_err(&client->dev, "ov5693 write register err.\n");
return ret;
@@ -866,128 +866,56 @@ static int __maybe_unused ov5693_sensor_resume(struct device *dev)
return ret;
}
-/*
- * distance - calculate the distance
- * @res: resolution
- * @w: width
- * @h: height
- *
- * Get the gap between res_w/res_h and w/h.
- * distance = (res_w/res_h - w/h) / (w/h) * 8192
- * res->width/height smaller than w/h wouldn't be considered.
- * The gap of ratio larger than 1/8 wouldn't be considered.
- * Returns the value of gap or -1 if fail.
- */
-#define LARGEST_ALLOWED_RATIO_MISMATCH 1024
-static int distance(struct ov5693_resolution *res, u32 w, u32 h)
-{
- int ratio;
- int distance;
-
- if (w == 0 || h == 0 ||
- res->width < w || res->height < h)
- return -1;
-
- ratio = res->width << 13;
- ratio /= w;
- ratio *= h;
- ratio /= res->height;
-
- distance = abs(ratio - 8192);
-
- if (distance > LARGEST_ALLOWED_RATIO_MISMATCH)
- return -1;
-
- return distance;
-}
-
-/* Return the nearest higher resolution index
- * Firstly try to find the approximate aspect ratio resolution
- * If we find multiple same AR resolutions, choose the
- * minimal size.
- */
-static int nearest_resolution_index(int w, int h)
-{
- int i;
- int idx = -1;
- int dist;
- int min_dist = INT_MAX;
- int min_res_w = INT_MAX;
- struct ov5693_resolution *tmp_res = NULL;
-
- for (i = 0; i < N_RES; i++) {
- tmp_res = &ov5693_res[i];
- dist = distance(tmp_res, w, h);
- if (dist == -1)
- continue;
- if (dist < min_dist) {
- min_dist = dist;
- idx = i;
- min_res_w = ov5693_res[i].width;
- continue;
- }
- if (dist == min_dist && ov5693_res[i].width < min_res_w)
- idx = i;
- }
-
- return idx;
-}
-
-static int get_resolution_index(int w, int h)
-{
- int i;
-
- for (i = 0; i < N_RES; i++) {
- if (w != ov5693_res[i].width)
- continue;
- if (h != ov5693_res[i].height)
- continue;
-
- return i;
- }
-
- return -1;
-}
-
static int ov5693_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_format *format)
{
- struct v4l2_mbus_framefmt *fmt = &format->format;
struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
+ const struct ov5693_resolution *mode;
+ int exposure_max;
int ret = 0;
- int idx;
+ int hblank;
if (format->pad)
return -EINVAL;
- if (!fmt)
- return -EINVAL;
mutex_lock(&ov5693->lock);
- idx = nearest_resolution_index(fmt->width, fmt->height);
- if (idx == -1) {
- /* return the largest resolution */
- fmt->width = ov5693_res[N_RES - 1].width;
- fmt->height = ov5693_res[N_RES - 1].height;
- } else {
- fmt->width = ov5693_res[idx].width;
- fmt->height = ov5693_res[idx].height;
- }
- fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+ mode = v4l2_find_nearest_size(ov5693_res_video, ARRAY_SIZE(ov5693_res_video),
+ width, height, format->format.width,
+ format->format.height);
+
+ if (!mode)
+ return -EINVAL;
+
+ format->format.width = mode->width;
+ format->format.height = mode->height;
+ format->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
+
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- cfg->try_fmt = *fmt;
- ret = 0;
+ *v4l2_subdev_get_try_format(sd, cfg, format->pad) = format->format;
goto mutex_unlock;
}
- ov5693->fmt_idx = get_resolution_index(fmt->width, fmt->height);
- if (ov5693->fmt_idx == -1) {
- dev_err(&client->dev, "get resolution fail\n");
- ret = -EINVAL;
- goto mutex_unlock;
- }
+ ov5693->mode = mode;
+
+ /* Update limits and set FPS to default */
+ __v4l2_ctrl_modify_range(ov5693->ctrls.vblank,
+ mode->lines_per_frame - mode->height,
+ OV5693_TIMING_MAX_VTS - mode->height,
+ 1, mode->lines_per_frame - mode->height);
+ __v4l2_ctrl_s_ctrl(ov5693->ctrls.vblank,
+ mode->lines_per_frame - mode->height);
+
+ hblank = mode->pixels_per_line - mode->width;
+ __v4l2_ctrl_modify_range(ov5693->ctrls.hblank, hblank, hblank, 1, hblank);
+
+ exposure_max = mode->lines_per_frame - 8;
+ __v4l2_ctrl_modify_range(ov5693->ctrls.exposure,
+ ov5693->ctrls.exposure->minimum, exposure_max,
+ ov5693->ctrls.exposure->step,
+ ov5693->ctrls.exposure->val < exposure_max ?
+ ov5693->ctrls.exposure->val : exposure_max);
mutex_unlock:
mutex_unlock(&ov5693->lock);
@@ -1056,8 +984,8 @@ static int ov5693_get_fmt(struct v4l2_subdev *sd,
if (!fmt)
return -EINVAL;
- fmt->width = ov5693_res[ov5693->fmt_idx].width;
- fmt->height = ov5693_res[ov5693->fmt_idx].height;
+ fmt->width = ov5693->mode->width;
+ fmt->height = ov5693->mode->height;
fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
return 0;
@@ -1174,7 +1102,7 @@ static int ov5693_g_frame_interval(struct v4l2_subdev *sd,
struct ov5693_device *ov5693 = to_ov5693_sensor(sd);
interval->interval.numerator = 1;
- interval->interval.denominator = ov5693_res[ov5693->fmt_idx].fps;
+ interval->interval.denominator = ov5693->mode->fps;
return 0;
}
diff --git a/drivers/media/i2c/ov5693.h b/drivers/media/i2c/ov5693.h
index 29e6735112da..0377853f8b2b 100644
--- a/drivers/media/i2c/ov5693.h
+++ b/drivers/media/i2c/ov5693.h
@@ -127,8 +127,8 @@ struct ov5693_resolution {
u8 *desc;
const struct ov5693_reg *regs;
int res;
- int width;
- int height;
+ u32 width;
+ u32 height;
int fps;
int pix_clk_freq;
u16 pixels_per_line;
@@ -178,7 +178,6 @@ struct ov5693_device {
struct camera_sensor_platform_data *platform_data;
ktime_t timestamp_t_focus_abs;
int vt_pix_clk_freq_mhz;
- int fmt_idx;
int run_mode;
int otp_size;
u8 *otp_data;
--
2.32.0