ab0e42fad6
Changes: - SAM: - Fix bug in battery event handling, causing events to be dropped and logged as unhandled. Links: - kernel:c4a64d988a
- SAM:77eadd698c
11663 lines
347 KiB
Diff
11663 lines
347 KiB
Diff
From 7c74c767a4b74f801bc2b283e84aef02f9aca9a6 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.31.1
|
|
|
|
From 929a2ffeafb59ded7e7a9211c5fbce78204a1609 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 dcbfe8c9abc7..a1f574095acc 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.31.1
|
|
|
|
From e3d768c25ce3020fac64692ef6f33a26e085cd51 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 a1f574095acc..93fd25a5a3e9 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.31.1
|
|
|
|
From 600e15b2927e7099ceeae93427bf8964bc0a7e3a 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 93fd25a5a3e9..b244b9de142a 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.31.1
|
|
|
|
From 644d554fab684284102140fdd98b639f55d1562e 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.31.1
|
|
|
|
From 275cc95c08ececab19ca8ed9ca221038ccd7d331 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.31.1
|
|
|
|
From 1f5487f982534a9a6a3ab0d2fb132b544dff4ff7 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.31.1
|
|
|
|
From 755a1392936f33ea6f062bedd5b287a17be87154 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.31.1
|
|
|
|
From 6365d85c962dc3a9185cecdb3a55cf3bea27de67 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.31.1
|
|
|
|
From 342be6e43cb8a981ef4e0d77fb36b7bfa86ca0df 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.31.1
|
|
|
|
From c78dc2864837a1cdb95467afda680c7c72915967 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.31.1
|
|
|
|
From aa916703bd6155574e11b94ae80c1ef2da797728 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.31.1
|
|
|
|
From a70d4aef14938791ecc817928a070c4b8f9bab1f 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 24cdfcf334ea..d15fa5b4558a 100644
|
|
--- a/MAINTAINERS
|
|
+++ b/MAINTAINERS
|
|
@@ -8937,6 +8937,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.31.1
|
|
|
|
From 90d80417aed43cace9b4397b2d9588dbea3182a9 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.31.1
|
|
|
|
From 73bbb53d1d3f451c5af6ca7c84e6c48cf222f919 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 e3ab003a6c85..9dd896d085ec 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.31.1
|
|
|
|
From 86f3eee6517363ea087020584bdf0c915281a54b 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 37dac195adbb..f28b097c658f 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)
|
|
{
|
|
put_device(&adev->dev);
|
|
--
|
|
2.31.1
|
|
|
|
From 3244bd5c49d370a188a39ffcf42d94711acb1483 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.31.1
|
|
|
|
From 87e12748d0887979241bd90aea53c8fc49588f1a 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 d15fa5b4558a..7ecd004b550f 100644
|
|
--- a/MAINTAINERS
|
|
+++ b/MAINTAINERS
|
|
@@ -8934,6 +8934,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 b244b9de142a..d820de44f341 100644
|
|
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
|
|
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
|
|
@@ -1712,11 +1712,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;
|
|
|
|
@@ -1725,6 +1742,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.31.1
|
|
|
|
From 0a62cf0628d0d993848903935d6a919712fd851f 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.31.1
|
|
|
|
From 6ca9d64a0bad3e88e17f53d48f2f555b9b10098a 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 f28b097c658f..9bec3373f850 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.31.1
|
|
|
|
From 80cce6c417d6ca8a0217383d36de4d77f7c154ce 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 c13e7f107dd3..2ca4697c2339 100644
|
|
--- a/drivers/i2c/i2c-core-base.c
|
|
+++ b/drivers/i2c/i2c-core-base.c
|
|
@@ -810,12 +810,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 56622658b215..65acae61dc5c 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
|
|
@@ -1011,6 +1014,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.31.1
|
|
|
|
From edd879804a6209f7d6e366fa26b32a716657d982 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 65acae61dc5c..b82aac05b17f 100644
|
|
--- a/include/linux/i2c.h
|
|
+++ b/include/linux/i2c.h
|
|
@@ -998,6 +998,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.31.1
|
|
|
|
From da79b55172275043be7589fc54b0233d37d10986 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 863f059bc498..91689457116b 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.31.1
|
|
|
|
From 067fba193bbd42635071b0e59f7412aefdbc91d3 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 14751c7ccd1f..442b2cc5e2f0 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 4789507f325b..3ebbb2ee173a 100644
|
|
--- a/drivers/mfd/Kconfig
|
|
+++ b/drivers/mfd/Kconfig
|
|
@@ -1533,24 +1533,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.31.1
|
|
|
|
From e359c36a6f7ff5df0f64c28aaf5c6c9aa5809a36 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 7ecd004b550f..07924325b238 100644
|
|
--- a/MAINTAINERS
|
|
+++ b/MAINTAINERS
|
|
@@ -9044,6 +9044,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 0c513c8bbd2b..c50e8596b440 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.31.1
|
|
|
|
From 53cbd912c6f1c34a4be214ec9d0da64ff2e1a488 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.31.1
|
|
|
|
From e540fb9bb9e04dfab1b37dad940ce65a58ae03b4 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,
|
|
+ ®_v);
|
|
+ if (ret)
|
|
+ goto err;
|
|
+
|
|
+ ret = ov5693_read_reg(client, OV5693_8BIT,
|
|
+ OV5693_EXPOSURE_M,
|
|
+ ®_v2);
|
|
+ if (ret)
|
|
+ goto err;
|
|
+
|
|
+ reg_v += reg_v2 << 8;
|
|
+ ret = ov5693_read_reg(client, OV5693_8BIT,
|
|
+ OV5693_EXPOSURE_H,
|
|
+ ®_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,
|
|
+ ®_v);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = ov5693_read_reg(sensor->i2c_client, OV5693_8BIT,
|
|
+ OV5693_EXPOSURE_M,
|
|
+ ®_v2);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ reg_v += reg_v2 << 8;
|
|
+ ret = ov5693_read_reg(sensor->i2c_client, OV5693_8BIT,
|
|
+ OV5693_EXPOSURE_H,
|
|
+ ®_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.31.1
|
|
|
|
From d6b23c2531f82d8113a2b181594437fcb476d34f 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.31.1
|
|
|
|
From 05ec620f745c01476678e3a254c65d9cf138a237 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.31.1
|
|
|
|
From 8f24b839c274128f6f31aba5729e475cb7d7925b 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.31.1
|
|
|
|
From c8b0263611dfe58bb0c5a25928c08256eb00b964 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.31.1
|
|
|
|
From 9c0388dfb499f10adfcd92fb4d70c7a64ca3e771 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.31.1
|
|
|
|
From f316f4e86d43762864937435de31a89ea2d6bbce 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.31.1
|
|
|
|
From 24e98d89000e1d12da1e0afd387976530ac61046 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.31.1
|
|
|
|
From 5e083e40013e31f42fcc32105af1258b96b6c773 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.31.1
|
|
|
|
From 04a1a7cebc88a0a0edc1f639977066166872ee7a 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.31.1
|
|
|
|
From ec4e9e4556086a5a9be966b520c8b067d55f595e 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.31.1
|
|
|
|
From 176d78d3b066dbac2eb2c4e7def6d25747bee6a5 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.31.1
|
|
|
|
From 0aa24398833fe7f9e0653c2d978886d56475df4a 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.31.1
|
|
|
|
From a818e60b4708c2f5ee7934ec3ef2d722d271e013 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.31.1
|
|
|
|
From 82a0c50b95789701519956368b1fb8f50d2057b4 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.31.1
|
|
|
|
From f0a8810d8b7927c8b9ad5b9a9625bc83e828edf8 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,
|
|
- ®_v);
|
|
+ &tmp);
|
|
if (ret)
|
|
return ret;
|
|
|
|
+ exposure |= ((tmp >> 4) & 0b1111);
|
|
+
|
|
ret = ov5693_read_reg(sensor->i2c_client, OV5693_8BIT,
|
|
OV5693_EXPOSURE_M,
|
|
- ®_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,
|
|
- ®_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.31.1
|
|
|
|
From a80b6dd55f8069ddf9cb3de4290ef13a3cee0c97 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.31.1
|
|
|
|
From 4e0394ddc7e69e6c9aacc8bf05f4848ac059d228 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.31.1
|
|
|
|
From 100a8cb15eeb0598da28f09d40103c054a826b20 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.31.1
|
|
|
|
From 81c1e332cbef88696b39fb860403aabf051aadc2 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.31.1
|
|
|
|
From ff6ecf5c42baa7f8e5bec61cecf998e8bf0a44eb 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.31.1
|
|
|
|
From 9d45ec1a52bc142a07b77bdd240b011b0ef285c5 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.31.1
|
|
|
|
From 5b8eec805d07c67938f0f660965c63d771b978d0 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.31.1
|
|
|
|
From 14513a30b56eef0b49f92b73547de78c65438ecb 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.31.1
|
|
|
|
From dc883689a71f6776f69ce308f28c9f90095eac19 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.31.1
|
|
|
|
From 7b385b6cc5fdfbc1a3bbe3c1cbb055d5ca371e93 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.31.1
|
|
|
|
From b58b8806a0d99d83d50a1f9e2ac4650b52b11af9 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.31.1
|
|
|
|
From 0c090bb22ebab445c5f6a0e26f8fbeac15966284 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.31.1
|
|
|
|
From 64d40bedc77d664e33e380342fc30f3ea0e26718 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.31.1
|
|
|
|
From 695c7c75156e65a1e68874da3018807c31d9b753 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.31.1
|
|
|
|
From 33b753411046d83b4a21a1640e897811750e020d 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.31.1
|
|
|
|
From 0a8c91405e88c3c6270319774c5a5fe81e7b487f 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.31.1
|
|
|