Add initial patches for v5.10 Links: - SAM:aaad476104
- hotplug:fcc8c8740b
- gpe:a4c2e07a4a
- ipts:0a4a44c2a9
- cameras:35305e7c5f
- kernel:489ca4dccb
6100 lines
181 KiB
Diff
6100 lines
181 KiB
Diff
From afa67133ede6f72963ad48ad97567e69402a47d6 Mon Sep 17 00:00:00 2001
|
|
From: Sakari Ailus <sakari.ailus@linux.intel.com>
|
|
Date: Mon, 12 Oct 2020 21:04:07 +0300
|
|
Subject: [PATCH] ipu3-cio2: Return actual subdev format
|
|
|
|
Return actual subdev format on ipu3-cio2 subdev pads. The earlier
|
|
implementation was based on an infinite recursion that exhausted the
|
|
stack.
|
|
|
|
Reported-by: Tsuchiya Yuto <kitakar@gmail.com>
|
|
Fixes: c2a6a07afe4a ("media: intel-ipu3: cio2: add new MIPI-CSI2 driver")
|
|
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
|
|
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
Reviewed-by: Bingbu Cao <bingbu.cao@intel.com>
|
|
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
|
|
Cc: stable@vger.kernel.org # v4.16 and up
|
|
Patchset: cameras
|
|
---
|
|
drivers/media/pci/intel/ipu3/ipu3-cio2.c | 24 +++---------------------
|
|
1 file changed, 3 insertions(+), 21 deletions(-)
|
|
|
|
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
|
|
index 4e598e937dfe..afa472026ba4 100644
|
|
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c
|
|
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
|
|
@@ -1232,29 +1232,11 @@ static int cio2_subdev_get_fmt(struct v4l2_subdev *sd,
|
|
struct v4l2_subdev_format *fmt)
|
|
{
|
|
struct cio2_queue *q = container_of(sd, struct cio2_queue, subdev);
|
|
- struct v4l2_subdev_format format;
|
|
- int ret;
|
|
|
|
- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
|
|
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
|
|
fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
|
|
- return 0;
|
|
- }
|
|
-
|
|
- if (fmt->pad == CIO2_PAD_SINK) {
|
|
- format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
|
|
- ret = v4l2_subdev_call(sd, pad, get_fmt, NULL,
|
|
- &format);
|
|
-
|
|
- if (ret)
|
|
- return ret;
|
|
- /* update colorspace etc */
|
|
- q->subdev_fmt.colorspace = format.format.colorspace;
|
|
- q->subdev_fmt.ycbcr_enc = format.format.ycbcr_enc;
|
|
- q->subdev_fmt.quantization = format.format.quantization;
|
|
- q->subdev_fmt.xfer_func = format.format.xfer_func;
|
|
- }
|
|
-
|
|
- fmt->format = q->subdev_fmt;
|
|
+ else
|
|
+ fmt->format = q->subdev_fmt;
|
|
|
|
return 0;
|
|
}
|
|
--
|
|
2.29.2
|
|
|
|
From 06bc173a5547f48dfbf1b890e946abf86b458301 Mon Sep 17 00:00:00 2001
|
|
From: Sakari Ailus <sakari.ailus@linux.intel.com>
|
|
Date: Mon, 12 Oct 2020 21:04:08 +0300
|
|
Subject: [PATCH] ipu3-cio2: Serialise access to pad format
|
|
|
|
Pad format can be accessed from user space. Serialise access to it.
|
|
|
|
Fixes: c2a6a07afe4a ("media: intel-ipu3: cio2: add new MIPI-CSI2 driver")
|
|
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
|
|
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
Reviewed-by: Bingbu Cao <bingbu.cao@intel.com>
|
|
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
|
|
Cc: stable@vger.kernel.org # v4.16 and up
|
|
Patchset: cameras
|
|
---
|
|
drivers/media/pci/intel/ipu3/ipu3-cio2.c | 11 +++++++++++
|
|
drivers/media/pci/intel/ipu3/ipu3-cio2.h | 1 +
|
|
2 files changed, 12 insertions(+)
|
|
|
|
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
|
|
index afa472026ba4..b3a08196e08c 100644
|
|
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c
|
|
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
|
|
@@ -1233,11 +1233,15 @@ static int cio2_subdev_get_fmt(struct v4l2_subdev *sd,
|
|
{
|
|
struct cio2_queue *q = container_of(sd, struct cio2_queue, subdev);
|
|
|
|
+ mutex_lock(&q->subdev_lock);
|
|
+
|
|
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
|
|
fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
|
|
else
|
|
fmt->format = q->subdev_fmt;
|
|
|
|
+ mutex_unlock(&q->subdev_lock);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -1261,6 +1265,8 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd,
|
|
if (fmt->pad == CIO2_PAD_SOURCE)
|
|
return cio2_subdev_get_fmt(sd, cfg, fmt);
|
|
|
|
+ mutex_lock(&q->subdev_lock);
|
|
+
|
|
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
|
|
*v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
|
|
} else {
|
|
@@ -1271,6 +1277,8 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd,
|
|
fmt->format = q->subdev_fmt;
|
|
}
|
|
|
|
+ mutex_unlock(&q->subdev_lock);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
@@ -1529,6 +1537,7 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q)
|
|
|
|
/* Initialize miscellaneous variables */
|
|
mutex_init(&q->lock);
|
|
+ mutex_init(&q->subdev_lock);
|
|
|
|
/* Initialize formats to default values */
|
|
fmt = &q->subdev_fmt;
|
|
@@ -1645,6 +1654,7 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q)
|
|
fail_subdev_media_entity:
|
|
cio2_fbpt_exit(q, &cio2->pci_dev->dev);
|
|
fail_fbpt:
|
|
+ mutex_destroy(&q->subdev_lock);
|
|
mutex_destroy(&q->lock);
|
|
|
|
return r;
|
|
@@ -1657,6 +1667,7 @@ static void cio2_queue_exit(struct cio2_device *cio2, struct cio2_queue *q)
|
|
v4l2_device_unregister_subdev(&q->subdev);
|
|
media_entity_cleanup(&q->subdev.entity);
|
|
cio2_fbpt_exit(q, &cio2->pci_dev->dev);
|
|
+ mutex_destroy(&q->subdev_lock);
|
|
mutex_destroy(&q->lock);
|
|
}
|
|
|
|
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.h b/drivers/media/pci/intel/ipu3/ipu3-cio2.h
|
|
index 549b08f88f0c..146492383aa5 100644
|
|
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.h
|
|
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.h
|
|
@@ -335,6 +335,7 @@ struct cio2_queue {
|
|
|
|
/* Subdev, /dev/v4l-subdevX */
|
|
struct v4l2_subdev subdev;
|
|
+ struct mutex subdev_lock; /* Serialise acces to subdev_fmt field */
|
|
struct media_pad subdev_pads[CIO2_PADS];
|
|
struct v4l2_mbus_framefmt subdev_fmt;
|
|
atomic_t frame_sequence;
|
|
--
|
|
2.29.2
|
|
|
|
From 4f63065a65d41cfc304cafad5b0bc36f4601a336 Mon Sep 17 00:00:00 2001
|
|
From: Sakari Ailus <sakari.ailus@linux.intel.com>
|
|
Date: Mon, 12 Oct 2020 21:04:09 +0300
|
|
Subject: [PATCH] ipu3-cio2: Validate mbus format in setting subdev format
|
|
|
|
Validate media bus code, width and height when setting the subdev format.
|
|
|
|
This effectively reworks how setting subdev format is implemented in the
|
|
driver.
|
|
|
|
Fixes: c2a6a07afe4a ("media: intel-ipu3: cio2: add new MIPI-CSI2 driver")
|
|
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>
|
|
Cc: stable@vger.kernel.org # v4.16 and up
|
|
Patchset: cameras
|
|
---
|
|
drivers/media/pci/intel/ipu3/ipu3-cio2.c | 29 ++++++++++++++++--------
|
|
1 file changed, 20 insertions(+), 9 deletions(-)
|
|
|
|
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
|
|
index b3a08196e08c..72095f8a4d46 100644
|
|
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c
|
|
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
|
|
@@ -1257,6 +1257,9 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd,
|
|
struct v4l2_subdev_format *fmt)
|
|
{
|
|
struct cio2_queue *q = container_of(sd, struct cio2_queue, subdev);
|
|
+ struct v4l2_mbus_framefmt *mbus;
|
|
+ u32 mbus_code = fmt->format.code;
|
|
+ unsigned int i;
|
|
|
|
/*
|
|
* Only allow setting sink pad format;
|
|
@@ -1265,18 +1268,26 @@ static int cio2_subdev_set_fmt(struct v4l2_subdev *sd,
|
|
if (fmt->pad == CIO2_PAD_SOURCE)
|
|
return cio2_subdev_get_fmt(sd, cfg, fmt);
|
|
|
|
- mutex_lock(&q->subdev_lock);
|
|
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
|
|
+ mbus = v4l2_subdev_get_try_format(sd, cfg, fmt->pad);
|
|
+ else
|
|
+ mbus = &q->subdev_fmt;
|
|
|
|
- if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
|
|
- *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) = fmt->format;
|
|
- } else {
|
|
- /* It's the sink, allow changing frame size */
|
|
- q->subdev_fmt.width = fmt->format.width;
|
|
- q->subdev_fmt.height = fmt->format.height;
|
|
- q->subdev_fmt.code = fmt->format.code;
|
|
- fmt->format = q->subdev_fmt;
|
|
+ fmt->format.code = formats[0].mbus_code;
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(formats); i++) {
|
|
+ if (formats[i].mbus_code == fmt->format.code) {
|
|
+ fmt->format.code = mbus_code;
|
|
+ break;
|
|
+ }
|
|
}
|
|
|
|
+ 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);
|
|
+
|
|
+ mutex_lock(&q->subdev_lock);
|
|
+ *mbus = fmt->format;
|
|
mutex_unlock(&q->subdev_lock);
|
|
|
|
return 0;
|
|
--
|
|
2.29.2
|
|
|
|
From ea89cce810cb71b6fa2e379e9cc3da589c0c6f21 Mon Sep 17 00:00:00 2001
|
|
From: Sakari Ailus <sakari.ailus@linux.intel.com>
|
|
Date: Mon, 12 Oct 2020 21:04:10 +0300
|
|
Subject: [PATCH] ipu3-cio2: Make the field on subdev format V4L2_FIELD_NONE
|
|
|
|
The ipu3-cio2 doesn't make use of the field and this is reflected in V4L2
|
|
buffers as well as the try format. Do this in active format, too.
|
|
|
|
Fixes: c2a6a07afe4a ("media: intel-ipu3: cio2: add new MIPI-CSI2 driver")
|
|
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
|
|
Reviewed-by: Bingbu Cao <bingbu.cao@intel.com>
|
|
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
|
|
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
|
|
Cc: stable@vger.kernel.org # v4.16 and up
|
|
Patchset: cameras
|
|
---
|
|
drivers/media/pci/intel/ipu3/ipu3-cio2.c | 1 +
|
|
1 file changed, 1 insertion(+)
|
|
|
|
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
|
|
index 72095f8a4d46..87d040e176f7 100644
|
|
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c
|
|
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
|
|
@@ -1285,6 +1285,7 @@ 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.field = V4L2_FIELD_NONE;
|
|
|
|
mutex_lock(&q->subdev_lock);
|
|
*mbus = fmt->format;
|
|
--
|
|
2.29.2
|
|
|
|
From d88c459341202091c3e42968b26ab89f064d7329 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.29.2
|
|
|
|
From f0c29960c5c83276be43f56c6cc3bf268955fecc 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 87d040e176f7..e42177f8c426 100644
|
|
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c
|
|
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
|
|
@@ -1282,9 +1282,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.29.2
|
|
|
|
From 050624316d233dea4feebf00e99fb21c9d350a24 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 e42177f8c426..d9baa8bfe54f 100644
|
|
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c
|
|
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
|
|
@@ -1094,8 +1094,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;
|
|
@@ -1283,7 +1283,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.29.2
|
|
|
|
From 6b3e853bff9ab00397f06a9c6a87c46785dd7eaf Mon Sep 17 00:00:00 2001
|
|
From: Sakari Ailus <sakari.ailus@linux.intel.com>
|
|
Date: Mon, 12 Oct 2020 21:04:14 +0300
|
|
Subject: [PATCH] ipu3-cio2: Remove traces of returned buffers
|
|
|
|
If starting a video buffer queue fails, the buffers are returned to
|
|
videobuf2. Remove the reference to the buffer from driver's queue as well.
|
|
|
|
Fixes: c2a6a07afe4a ("media: intel-ipu3: cio2: add new MIPI-CSI2 driver")
|
|
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
|
|
Cc: stable@vger.kernel.org # v4.16 and up
|
|
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 | 1 +
|
|
1 file changed, 1 insertion(+)
|
|
|
|
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
|
|
index d9baa8bfe54f..51c4dd6a8f9a 100644
|
|
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c
|
|
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
|
|
@@ -791,6 +791,7 @@ static void cio2_vb2_return_all_buffers(struct cio2_queue *q,
|
|
atomic_dec(&q->bufs_queued);
|
|
vb2_buffer_done(&q->bufs[i]->vbb.vb2_buf,
|
|
state);
|
|
+ q->bufs[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
--
|
|
2.29.2
|
|
|
|
From 1710b6b3fa4bc59ad4e1f4f3391b947dea87bd57 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 51c4dd6a8f9a..c557d189200b 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.29.2
|
|
|
|
From b7ce18c0c18c4368e9a317935ff5de10f0a97677 Mon Sep 17 00:00:00 2001
|
|
From: Daniel Scally <djrscally@gmail.com>
|
|
Date: Sat, 5 Dec 2020 17:04:03 +0000
|
|
Subject: [PATCH] Revert "ACPI / resources: Use AE_CTRL_TERMINATE to terminate
|
|
resources walks"
|
|
|
|
This reverts commit 8a66790b7850a6669129af078768a1d42076a0ef.
|
|
|
|
Switching this function to AE_CTRL_TERMINATE broke the documented
|
|
behaviour of acpi_dev_get_resources() - AE_CTRL_TERMINATE does not, in
|
|
fact, terminate the resource walk because acpi_walk_resource_buffer()
|
|
ignores it (specifically converting it to AE_OK), referring to that
|
|
value as "an OK termination by the user function". This means that
|
|
acpi_dev_get_resources() does not abort processing when the preproc
|
|
function returns a negative value.
|
|
|
|
Signed-off-by: Daniel Scally <djrscally@gmail.com>
|
|
Patchset: cameras
|
|
---
|
|
drivers/acpi/resource.c | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
|
|
index ad04824ca3ba..f2f5f1dc7c61 100644
|
|
--- a/drivers/acpi/resource.c
|
|
+++ b/drivers/acpi/resource.c
|
|
@@ -541,7 +541,7 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares,
|
|
ret = c->preproc(ares, c->preproc_data);
|
|
if (ret < 0) {
|
|
c->error = ret;
|
|
- return AE_CTRL_TERMINATE;
|
|
+ return AE_ABORT_METHOD;
|
|
} else if (ret > 0) {
|
|
return AE_OK;
|
|
}
|
|
--
|
|
2.29.2
|
|
|
|
From 2768db4310e1ae416a2968755ef8bfd37f53a089 Mon Sep 17 00:00:00 2001
|
|
From: Daniel Scally <djrscally@gmail.com>
|
|
Date: Sat, 24 Oct 2020 22:42:28 +0100
|
|
Subject: [PATCH] property: Return true in fwnode_device_is_available for node
|
|
types that do not implement this operation
|
|
|
|
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>
|
|
Signed-off-by: Daniel Scally <djrscally@gmail.com>
|
|
Patchset: cameras
|
|
---
|
|
drivers/base/property.c | 5 +++++
|
|
1 file changed, 5 insertions(+)
|
|
|
|
diff --git a/drivers/base/property.c b/drivers/base/property.c
|
|
index 4c43d30145c6..a5ca2306796f 100644
|
|
--- a/drivers/base/property.c
|
|
+++ b/drivers/base/property.c
|
|
@@ -785,9 +785,14 @@ 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.29.2
|
|
|
|
From 71e1ad0181866d9b9035a078351a15bb3e1207a9 Mon Sep 17 00:00:00 2001
|
|
From: Daniel Scally <djrscally@gmail.com>
|
|
Date: Sat, 21 Nov 2020 22:06:38 +0000
|
|
Subject: [PATCH] property: Add support for calling
|
|
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.
|
|
|
|
Signed-off-by: Daniel Scally <djrscally@gmail.com>
|
|
Patchset: cameras
|
|
---
|
|
drivers/base/property.c | 4 ++++
|
|
1 file changed, 4 insertions(+)
|
|
|
|
diff --git a/drivers/base/property.c b/drivers/base/property.c
|
|
index a5ca2306796f..4ece6b086e36 100644
|
|
--- a/drivers/base/property.c
|
|
+++ b/drivers/base/property.c
|
|
@@ -1162,6 +1162,10 @@ fwnode_graph_get_endpoint_by_id(const struct fwnode_handle *fwnode,
|
|
best_ep_id = fwnode_ep.id;
|
|
}
|
|
|
|
+ if (!best_ep && fwnode && !IS_ERR_OR_NULL(fwnode->secondary))
|
|
+ return fwnode_graph_get_endpoint_by_id(fwnode->secondary, port,
|
|
+ endpoint, flags);
|
|
+
|
|
return best_ep;
|
|
}
|
|
EXPORT_SYMBOL_GPL(fwnode_graph_get_endpoint_by_id);
|
|
--
|
|
2.29.2
|
|
|
|
From f45445df730f2e0c6b5291d422d92ec9eff0a9dd Mon Sep 17 00:00:00 2001
|
|
From: Daniel Scally <djrscally@gmail.com>
|
|
Date: Sat, 10 Oct 2020 23:42:09 +0100
|
|
Subject: [PATCH] software_node: Fix failure to put() and get() references to
|
|
children in software_node_get_next_child()
|
|
|
|
The software_node_get_next_child() function currently does not hold
|
|
references to the child software_node that it finds or put the ref that
|
|
is held against the old child - fix that.
|
|
|
|
Signed-off-by: Daniel Scally <djrscally@gmail.com>
|
|
Patchset: cameras
|
|
---
|
|
drivers/base/swnode.c | 8 ++++++--
|
|
1 file changed, 6 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
|
|
index 010828fc785b..615a0c93e116 100644
|
|
--- a/drivers/base/swnode.c
|
|
+++ b/drivers/base/swnode.c
|
|
@@ -443,14 +443,18 @@ software_node_get_next_child(const struct fwnode_handle *fwnode,
|
|
struct swnode *c = to_swnode(child);
|
|
|
|
if (!p || list_empty(&p->children) ||
|
|
- (c && list_is_last(&c->entry, &p->children)))
|
|
+ (c && list_is_last(&c->entry, &p->children))) {
|
|
+ fwnode_handle_put(child);
|
|
return NULL;
|
|
+ }
|
|
|
|
if (c)
|
|
c = list_next_entry(c, entry);
|
|
else
|
|
c = list_first_entry(&p->children, struct swnode, entry);
|
|
- return &c->fwnode;
|
|
+
|
|
+ fwnode_handle_put(child);
|
|
+ return fwnode_handle_get(&c->fwnode);
|
|
}
|
|
|
|
static struct fwnode_handle *
|
|
--
|
|
2.29.2
|
|
|
|
From 46b551f9a08d90c64f8151bfa2c0584b47b36552 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
|
|
array for software_node_register_nodes()
|
|
|
|
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 to this function.
|
|
|
|
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 615a0c93e116..af7930b3679e 100644
|
|
--- a/drivers/base/swnode.c
|
|
+++ b/drivers/base/swnode.c
|
|
@@ -700,14 +700,21 @@ int software_node_register_nodes(const struct software_node *nodes)
|
|
int i;
|
|
|
|
for (i = 0; nodes[i].name; i++) {
|
|
+ if (nodes[i].parent)
|
|
+ if (!software_node_to_swnode(nodes[i].parent)) {
|
|
+ ret = -EINVAL;
|
|
+ goto err_unregister_nodes;
|
|
+ }
|
|
+
|
|
ret = software_node_register(&nodes[i]);
|
|
- if (ret) {
|
|
- software_node_unregister_nodes(nodes);
|
|
- return ret;
|
|
- }
|
|
+ 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);
|
|
|
|
--
|
|
2.29.2
|
|
|
|
From 7216f1a437fc3e6c1f4c04540d25cea572e83be2 Mon Sep 17 00:00:00 2001
|
|
From: Daniel Scally <djrscally@gmail.com>
|
|
Date: Wed, 21 Oct 2020 22:16:38 +0100
|
|
Subject: [PATCH] software_node: Alter software_node_unregister_nodes() to
|
|
unregister the array in reverse order
|
|
|
|
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
|
|
this function unregisters software_nodes.
|
|
|
|
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
|
Signed-off-by: Daniel Scally <djrscally@gmail.com>
|
|
Patchset: cameras
|
|
---
|
|
drivers/base/swnode.c | 19 ++++++++++++-------
|
|
1 file changed, 12 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
|
|
index af7930b3679e..d39e1c76d98d 100644
|
|
--- a/drivers/base/swnode.c
|
|
+++ b/drivers/base/swnode.c
|
|
@@ -720,20 +720,25 @@ 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
|
|
+ * @nodes: Zero terminated array of software nodes to be unregistered. 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.
|
|
*
|
|
* Unregister multiple software nodes at once.
|
|
*
|
|
- * 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.29.2
|
|
|
|
From 7923fe9e96e74be55a090303c2bd40c870c1f6aa 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: amend software_node_unregister_node_group() to
|
|
perform unregistration of array in reverse order to be consistent with
|
|
software_node_unregister_nodes()
|
|
|
|
To maintain consistency with software_node_unregister_nodes(), reverse
|
|
the order in which the software_node_unregister_node_group() function
|
|
unregisters nodes.
|
|
|
|
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
|
Signed-off-by: Daniel Scally <djrscally@gmail.com>
|
|
Patchset: cameras
|
|
---
|
|
drivers/base/swnode.c | 5 ++++-
|
|
1 file changed, 4 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
|
|
index d39e1c76d98d..9bd0bb77ad5b 100644
|
|
--- a/drivers/base/swnode.c
|
|
+++ b/drivers/base/swnode.c
|
|
@@ -782,7 +782,10 @@ void software_node_unregister_node_group(const struct software_node **node_group
|
|
if (!node_group)
|
|
return;
|
|
|
|
- for (i = 0; node_group[i]; i++)
|
|
+ while (node_group[i]->name)
|
|
+ i++;
|
|
+
|
|
+ while (i--)
|
|
software_node_unregister(node_group[i]);
|
|
}
|
|
EXPORT_SYMBOL_GPL(software_node_unregister_node_group);
|
|
--
|
|
2.29.2
|
|
|
|
From fe2c734788b35fc29f7f13cd3b893c4c7c8ef6e7 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 vector 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 "port0", "port1",
|
|
...) 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".
|
|
|
|
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 | 110 +++++++++++++++++++++++++++++++++++++++++-
|
|
1 file changed, 109 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
|
|
index 9bd0bb77ad5b..0c7a8d6b9ea8 100644
|
|
--- a/drivers/base/swnode.c
|
|
+++ b/drivers/base/swnode.c
|
|
@@ -540,6 +540,110 @@ 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))) {
|
|
+ if (!strncmp(to_swnode(port)->node->name, "port", 4))
|
|
+ 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 *old = endpoint;
|
|
+ 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, old);
|
|
+ if (endpoint) {
|
|
+ fwnode_handle_put(port);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* No more endpoints for that port, so stop passing old */
|
|
+ old = NULL;
|
|
+ }
|
|
+
|
|
+ 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);
|
|
+ struct fwnode_handle *parent;
|
|
+
|
|
+ if (!strcmp(swnode->parent->node->name, "ports"))
|
|
+ parent = &swnode->parent->parent->fwnode;
|
|
+ else
|
|
+ parent = &swnode->parent->fwnode;
|
|
+
|
|
+ return software_node_get(parent);
|
|
+}
|
|
+
|
|
+static int
|
|
+software_node_graph_parse_endpoint(const struct fwnode_handle *fwnode,
|
|
+ struct fwnode_endpoint *endpoint)
|
|
+{
|
|
+ struct swnode *swnode = to_swnode(fwnode);
|
|
+ int ret;
|
|
+
|
|
+ ret = kstrtou32(swnode->parent->node->name + 4, 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 +655,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.29.2
|
|
|
|
From 967aa372bff3f4accbbe11baa99366f2b20f293c 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.
|
|
|
|
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.29.2
|
|
|
|
From 5084b1163737fe56f0be22559c4b46684ba3b160 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
|
|
|
|
Signed-off-by: Daniel Scally <djrscally@gmail.com>
|
|
Patchset: cameras
|
|
---
|
|
MAINTAINERS | 1 +
|
|
1 file changed, 1 insertion(+)
|
|
|
|
diff --git a/MAINTAINERS b/MAINTAINERS
|
|
index 281de213ef47..5a1c6e959aa8 100644
|
|
--- a/MAINTAINERS
|
|
+++ b/MAINTAINERS
|
|
@@ -8938,6 +8938,7 @@ M: Bingbu Cao <bingbu.cao@intel.com>
|
|
R: Tianshu Qiu <tian.shu.qiu@intel.com>
|
|
L: linux-media@vger.kernel.org
|
|
S: Maintained
|
|
+T: git git://linuxtv.org/media_tree.git
|
|
F: Documentation/userspace-api/media/v4l/pixfmt-srggb10-ipu3.rst
|
|
F: drivers/media/pci/intel/ipu3/
|
|
|
|
--
|
|
2.29.2
|
|
|
|
From 79c271179b1510b7647f24efdc74d4855c6b403e 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 to allow module to be built
|
|
from multiple source files retaining ipu3-cio2 name
|
|
|
|
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>
|
|
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.29.2
|
|
|
|
From 79df97e863c8c795e6ba52947527bf802e98ef38 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 possible match in
|
|
match_fwnode based on sd->fwnode->secondary
|
|
|
|
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.
|
|
|
|
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..6486dbde784f 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.29.2
|
|
|
|
From 7ab0a086dc85f8bf6cfc1b82a72dfb87ae8cdeae 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: Add acpi_dev_get_next_match_dev() and macro to iterate
|
|
through acpi_devices matching a given _HID
|
|
|
|
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.
|
|
|
|
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..c177165c8db2 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 a3abcc4b7d9f..0a028ba967d3 100644
|
|
--- a/include/acpi/acpi_bus.h
|
|
+++ b/include/acpi/acpi_bus.h
|
|
@@ -688,9 +688,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.29.2
|
|
|
|
From 157bc7db969c97313f8c8067b3eccc7fd0ee1d34 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 functionality allowing software_node
|
|
connections to sensors on platforms designed for Windows
|
|
|
|
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>
|
|
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 | 260 ++++++++++++++++++
|
|
drivers/media/pci/intel/ipu3/cio2-bridge.h | 108 ++++++++
|
|
drivers/media/pci/intel/ipu3/ipu3-cio2-main.c | 27 ++
|
|
drivers/media/pci/intel/ipu3/ipu3-cio2.h | 6 +
|
|
7 files changed, 421 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 5a1c6e959aa8..a6924e3401e8 100644
|
|
--- a/MAINTAINERS
|
|
+++ b/MAINTAINERS
|
|
@@ -8935,6 +8935,7 @@ INTEL IPU3 CSI-2 CIO2 DRIVER
|
|
M: Yong Zhi <yong.zhi@intel.com>
|
|
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
|
M: Bingbu Cao <bingbu.cao@intel.com>
|
|
+M: Dan Scally <djrscally@gmail.com>
|
|
R: Tianshu Qiu <tian.shu.qiu@intel.com>
|
|
L: linux-media@vger.kernel.org
|
|
S: Maintained
|
|
diff --git a/drivers/media/pci/intel/ipu3/Kconfig b/drivers/media/pci/intel/ipu3/Kconfig
|
|
index 82d7f17e6a02..2b3350d042be 100644
|
|
--- a/drivers/media/pci/intel/ipu3/Kconfig
|
|
+++ b/drivers/media/pci/intel/ipu3/Kconfig
|
|
@@ -16,3 +16,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 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..fd3f8ba07274
|
|
--- /dev/null
|
|
+++ b/drivers/media/pci/intel/ipu3/cio2-bridge.c
|
|
@@ -0,0 +1,260 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/* Author: Dan Scally <djrscally@gmail.com> */
|
|
+#include <linux/acpi.h>
|
|
+#include <linux/device.h>
|
|
+#include <linux/i2c.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/pci.h>
|
|
+#include <linux/property.h>
|
|
+#include <media/v4l2-subdev.h>
|
|
+
|
|
+#include "cio2-bridge.h"
|
|
+
|
|
+/*
|
|
+ * Extend this array with ACPI Hardware ID's of devices known to be working.
|
|
+ * Do not add a HID for a sensor that is not actually supported.
|
|
+ */
|
|
+static const char * const cio2_supported_devices[] = {
|
|
+ "INT33BE",
|
|
+ "OVTI2680",
|
|
+};
|
|
+
|
|
+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;
|
|
+
|
|
+ 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);
|
|
+ ret = obj->buffer.length;
|
|
+
|
|
+out_free_buff:
|
|
+ kfree(buffer.pointer);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void cio2_bridge_init_property_names(struct cio2_sensor *sensor)
|
|
+{
|
|
+ strcpy(sensor->prop_names.clock_frequency, "clock-frequency");
|
|
+ strcpy(sensor->prop_names.rotation, "rotation");
|
|
+ strcpy(sensor->prop_names.bus_type, "bus-type");
|
|
+ strcpy(sensor->prop_names.data_lanes, "data-lanes");
|
|
+ strcpy(sensor->prop_names.remote_endpoint, "remote-endpoint");
|
|
+}
|
|
+
|
|
+static void cio2_bridge_create_fwnode_properties(struct cio2_sensor *sensor)
|
|
+{
|
|
+ unsigned int i;
|
|
+
|
|
+ cio2_bridge_init_property_names(sensor);
|
|
+
|
|
+ for (i = 0; i < 4; i++)
|
|
+ sensor->data_lanes[i] = i + 1;
|
|
+
|
|
+ /*
|
|
+ * Can't use PROPERTY_ENTRY_REF because it creates a new variable to
|
|
+ * point to, which doesn't survive the function.
|
|
+ */
|
|
+ sensor->local_ref[0] = (struct software_node_ref_args){
|
|
+ .node = &sensor->swnodes[SWNODE_CIO2_ENDPOINT]
|
|
+ };
|
|
+ sensor->remote_ref[0] = (struct software_node_ref_args){
|
|
+ .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, 5);
|
|
+ sensor->ep_properties[1] = PROPERTY_ENTRY_U32_ARRAY_LEN(sensor->prop_names.data_lanes,
|
|
+ sensor->data_lanes,
|
|
+ sensor->ssdb.lanes);
|
|
+ sensor->ep_properties[2] = PROPERTY_ENTRY_REF_ARRAY(sensor->prop_names.remote_endpoint,
|
|
+ sensor->local_ref);
|
|
+
|
|
+ sensor->cio2_properties[0] = PROPERTY_ENTRY_U32_ARRAY_LEN(sensor->prop_names.data_lanes,
|
|
+ sensor->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, 6, "port%u", sensor->ssdb.link);
|
|
+ strcpy(sensor->node_names.port, "port0");
|
|
+ strcpy(sensor->node_names.endpoint, "endpoint0");
|
|
+}
|
|
+
|
|
+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_sensors(struct cio2_bridge *bridge)
|
|
+{
|
|
+ struct fwnode_handle *fwnode;
|
|
+ struct cio2_sensor *sensor;
|
|
+ struct acpi_device *adev;
|
|
+ unsigned int i;
|
|
+ int ret = 0;
|
|
+
|
|
+ for (i = 0; i < ARRAY_SIZE(cio2_supported_devices); i++) {
|
|
+ const char *this_device = cio2_supported_devices[i];
|
|
+
|
|
+ for_each_acpi_dev_match(adev, this_device, NULL, -1) {
|
|
+ if (!adev || !(adev->status.present && adev->status.enabled))
|
|
+ continue;
|
|
+
|
|
+ sensor = &bridge->sensors[bridge->n_sensors];
|
|
+ sensor->adev = adev;
|
|
+ strscpy(sensor->name, this_device, sizeof(sensor->name));
|
|
+
|
|
+ ret = cio2_bridge_read_acpi_buffer(adev, "SSDB",
|
|
+ &sensor->ssdb,
|
|
+ sizeof(sensor->ssdb));
|
|
+ if (ret < 0)
|
|
+ goto err_put_adev;
|
|
+
|
|
+ if (sensor->ssdb.lanes > 4) {
|
|
+ dev_err(&adev->dev,
|
|
+ "Number of lanes in SSDB is invalid\n");
|
|
+ goto err_put_adev;
|
|
+ }
|
|
+
|
|
+ cio2_bridge_create_fwnode_properties(sensor);
|
|
+ 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(&bridge->cio2->dev,
|
|
+ "Found supported sensor %s\n",
|
|
+ acpi_dev_name(adev));
|
|
+
|
|
+ bridge->n_sensors++;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+
|
|
+err_free_swnodes:
|
|
+ software_node_unregister_nodes(sensor->swnodes);
|
|
+err_put_adev:
|
|
+ acpi_dev_put(sensor->adev);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int cio2_bridge_init(struct pci_dev *cio2)
|
|
+{
|
|
+ struct device *dev = &cio2->dev;
|
|
+ struct fwnode_handle *fwnode;
|
|
+ struct cio2_bridge *bridge;
|
|
+ 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 = (const struct software_node){ bridge->cio2_node_name };
|
|
+ bridge->cio2 = pci_dev_get(cio2);
|
|
+
|
|
+ ret = software_node_register(&bridge->cio2_hid_node);
|
|
+ if (ret < 0) {
|
|
+ dev_err(dev, "Failed to register the CIO2 HID node\n");
|
|
+ goto err_put_cio2;
|
|
+ }
|
|
+
|
|
+ ret = cio2_bridge_connect_sensors(bridge);
|
|
+ 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_put_cio2:
|
|
+ pci_dev_put(bridge->cio2);
|
|
+
|
|
+ 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..96f5c8a12be0
|
|
--- /dev/null
|
|
+++ b/drivers/media/pci/intel/ipu3/cio2-bridge.h
|
|
@@ -0,0 +1,108 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/* Author: Dan Scally <djrscally@gmail.com> */
|
|
+#ifndef __CIO2_BRIDGE_H
|
|
+#define __CIO2_BRIDGE_H
|
|
+
|
|
+#include <linux/property.h>
|
|
+
|
|
+#define CIO2_HID "INT343E"
|
|
+#define CIO2_NUM_PORTS 4
|
|
+
|
|
+#define NODE_SENSOR(_HID, _PROPS) \
|
|
+ ((const struct software_node) { \
|
|
+ .name = _HID, \
|
|
+ .properties = _PROPS, \
|
|
+ })
|
|
+
|
|
+#define NODE_PORT(_PORT, _SENSOR_NODE) \
|
|
+ ((const struct software_node) { \
|
|
+ _PORT, \
|
|
+ _SENSOR_NODE, \
|
|
+ })
|
|
+
|
|
+#define NODE_ENDPOINT(_EP, _PORT, _PROPS) \
|
|
+ ((const struct software_node) { \
|
|
+ _EP, \
|
|
+ _PORT, \
|
|
+ _PROPS, \
|
|
+ })
|
|
+
|
|
+enum cio2_sensor_swnodes {
|
|
+ SWNODE_SENSOR_HID,
|
|
+ SWNODE_SENSOR_PORT,
|
|
+ SWNODE_SENSOR_ENDPOINT,
|
|
+ SWNODE_CIO2_PORT,
|
|
+ SWNODE_CIO2_ENDPOINT,
|
|
+ NR_OF_SENSOR_SWNODES
|
|
+};
|
|
+
|
|
+/* 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];
|
|
+};
|
|
+
|
|
+struct cio2_node_names {
|
|
+ char port[6];
|
|
+ char endpoint[10];
|
|
+ char remote_port[6];
|
|
+};
|
|
+
|
|
+struct cio2_sensor {
|
|
+ char name[ACPI_ID_LEN];
|
|
+ struct acpi_device *adev;
|
|
+
|
|
+ struct software_node swnodes[6];
|
|
+ struct cio2_node_names node_names;
|
|
+
|
|
+ u32 data_lanes[4];
|
|
+ struct cio2_sensor_ssdb ssdb;
|
|
+ struct cio2_property_names prop_names;
|
|
+ struct property_entry ep_properties[4];
|
|
+ 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 {
|
|
+ struct pci_dev *cio2;
|
|
+ char cio2_node_name[ACPI_ID_LEN];
|
|
+ struct software_node cio2_hid_node;
|
|
+ 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 c557d189200b..9f29af0c0941 100644
|
|
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
|
|
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
|
|
@@ -1712,6 +1712,22 @@ static void cio2_queues_exit(struct cio2_device *cio2)
|
|
cio2_queue_exit(cio2, &cio2->queue[i]);
|
|
}
|
|
|
|
+static bool cio2_check_fwnode_graph(struct fwnode_handle *fwnode)
|
|
+{
|
|
+ struct fwnode_handle *endpoint;
|
|
+
|
|
+ if (IS_ERR_OR_NULL(fwnode))
|
|
+ return false;
|
|
+
|
|
+ endpoint = fwnode_graph_get_next_endpoint(fwnode, NULL);
|
|
+ if (endpoint) {
|
|
+ fwnode_handle_put(endpoint);
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ return cio2_check_fwnode_graph(fwnode->secondary);
|
|
+}
|
|
+
|
|
/**************** PCI interface ****************/
|
|
|
|
static int cio2_pci_probe(struct pci_dev *pci_dev,
|
|
@@ -1725,6 +1741,17 @@ 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.
|
|
+ */
|
|
+ if (!cio2_check_fwnode_graph(dev_fwnode(&pci_dev->dev))) {
|
|
+ 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 ccf0b85ae36f..520a27c9cdad 100644
|
|
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.h
|
|
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.h
|
|
@@ -437,4 +437,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.29.2
|
|
|
|
From eeaefa51854c2ff5513171ffc5e0aff68173b41f 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
|
|
|
|
ACPI devices declare themselves dependent on other devices via the _DEP
|
|
buffer. Fetching the dependee from dependent is a matter of parsing
|
|
_DEP, but currently there's no method to fetch dependent from dependee.
|
|
Add one, so we can parse sensors dependent on a PMIC from the PMIC's
|
|
acpi_driver.
|
|
|
|
Signed-off-by: Daniel Scally <djrscally@gmail.com>
|
|
Patchset: cameras
|
|
---
|
|
drivers/acpi/utils.c | 68 +++++++++++++++++++++++++++++++++++++++++
|
|
include/acpi/acpi_bus.h | 2 ++
|
|
2 files changed, 70 insertions(+)
|
|
|
|
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
|
|
index c177165c8db2..7099529121db 100644
|
|
--- a/drivers/acpi/utils.c
|
|
+++ b/drivers/acpi/utils.c
|
|
@@ -807,6 +807,52 @@ static int acpi_dev_match_cb(struct device *dev, const void *data)
|
|
return hrv == match->hrv;
|
|
}
|
|
|
|
+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;
|
|
+ struct acpi_handle_list dep_handles;
|
|
+ struct acpi_device *candidate;
|
|
+ acpi_handle handle;
|
|
+ acpi_status status;
|
|
+ unsigned int i;
|
|
+ int ret;
|
|
+
|
|
+ handle = adev->handle;
|
|
+
|
|
+ if (!acpi_has_method(handle, "_DEP"))
|
|
+ return 0;
|
|
+
|
|
+ status = acpi_evaluate_reference(handle, "_DEP", NULL, &dep_handles);
|
|
+ if (ACPI_FAILURE(status))
|
|
+ return 0;
|
|
+
|
|
+ for (i = 0; i < dep_handles.count; i++) {
|
|
+ struct acpi_device_info *info;
|
|
+
|
|
+ status = acpi_get_object_info(dep_handles.handles[i], &info);
|
|
+ if (ACPI_FAILURE(status))
|
|
+ continue;
|
|
+
|
|
+ if (info->valid & ACPI_VALID_HID) {
|
|
+ ret = acpi_bus_get_device(dep_handles.handles[i], &candidate);
|
|
+ if (ret || !candidate) {
|
|
+ kfree(info);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (candidate == dependee) {
|
|
+ acpi_dev_put(candidate);
|
|
+ kfree(info);
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ kfree(info);
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/**
|
|
* acpi_dev_present - Detect that a given ACPI device is present
|
|
* @hid: Hardware ID of the device.
|
|
@@ -842,6 +888,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 0a028ba967d3..f5dfeb030b9c 100644
|
|
--- a/include/acpi/acpi_bus.h
|
|
+++ b/include/acpi/acpi_bus.h
|
|
@@ -688,6 +688,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.29.2
|
|
|
|
From ae7aff84078ff49fdaaf82f0afbc50282fe2bb60 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-acpi: Add i2c_acpi_dev_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). Adding this function means that we can
|
|
achieve the same thing without having to wait to the i2c device.
|
|
|
|
Signed-off-by: Daniel Scally <djrscally@gmail.com>
|
|
Patchset: cameras
|
|
---
|
|
drivers/i2c/i2c-core-acpi.c | 15 +++++++++++++++
|
|
include/linux/i2c.h | 5 +++++
|
|
2 files changed, 20 insertions(+)
|
|
|
|
diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c
|
|
index aed579942436..a48e20a806c5 100644
|
|
--- a/drivers/i2c/i2c-core-acpi.c
|
|
+++ b/drivers/i2c/i2c-core-acpi.c
|
|
@@ -497,6 +497,21 @@ 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
|
|
+ *
|
|
+ * Prefixes "i2c-" to the ACPI device name, for use in i2c_dev_set_name() and
|
|
+ * also anywhere else in the kernel that needs to refer to an i2c device by
|
|
+ * name but before they have been instantiated.
|
|
+ */
|
|
+char *i2c_acpi_dev_name(struct acpi_device *adev)
|
|
+{
|
|
+ return devm_kasprintf(&adev->dev, GFP_KERNEL, "i2c-%s",
|
|
+ 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 56622658b215..ab0e505b2ca6 100644
|
|
--- a/include/linux/i2c.h
|
|
+++ b/include/linux/i2c.h
|
|
@@ -995,6 +995,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,
|
|
@@ -1011,6 +1012,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.29.2
|
|
|
|
From 6217d5b9fbb78710e5d206e7a48febfa213f5d41 Mon Sep 17 00:00:00 2001
|
|
From: Dan Scally <djrscally@gmail.com>
|
|
Date: Mon, 16 Nov 2020 21:45:22 +0000
|
|
Subject: [PATCH] i2c: i2c-core-base: Use the new i2c_acpi_dev_name() in
|
|
i2c_set_dev_name()
|
|
|
|
To make sure the new i2c_acpi_dev_name() always reflects the name of i2c
|
|
devices sourced from ACPI, use it in i2c_set_dev_name().
|
|
|
|
Signed-off-by: Dan Scally <djrscally@gmail.com>
|
|
Patchset: cameras
|
|
---
|
|
drivers/i2c/i2c-core-base.c | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
|
|
index 573b5da145d1..a6d4ceb01077 100644
|
|
--- a/drivers/i2c/i2c-core-base.c
|
|
+++ b/drivers/i2c/i2c-core-base.c
|
|
@@ -814,7 +814,7 @@ static void i2c_dev_set_name(struct i2c_adapter *adap,
|
|
}
|
|
|
|
if (adev) {
|
|
- dev_set_name(&client->dev, "i2c-%s", acpi_dev_name(adev));
|
|
+ dev_set_name(&client->dev, i2c_acpi_dev_name(adev));
|
|
return;
|
|
}
|
|
|
|
--
|
|
2.29.2
|
|
|
|
From 201a549af887f4d676ddf9cb97c18241dd48a24c 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 834a12f3219e..cfadbc263475 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 39263c6b52e1..737115a93138 100644
|
|
--- a/include/linux/acpi.h
|
|
+++ b/include/linux/acpi.h
|
|
@@ -1066,6 +1066,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(struct acpi_device *adev, 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)
|
|
@@ -1076,6 +1077,10 @@ static inline int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index)
|
|
{
|
|
return -ENXIO;
|
|
}
|
|
+struct gpio_desc *acpi_get_gpiod(char *path, int pin)
|
|
+{
|
|
+ return NULL;
|
|
+}
|
|
#endif
|
|
|
|
/* Device properties */
|
|
--
|
|
2.29.2
|
|
|
|
From c47090d4b0a9724ecb14d76d832ffb704db0b535 Mon Sep 17 00:00:00 2001
|
|
From: Daniel Scally <djrscally@gmail.com>
|
|
Date: Fri, 27 Nov 2020 10:18:10 +0000
|
|
Subject: [PATCH] ipu3: Add driver for dummy INT3472 ACPI device
|
|
|
|
On platforms where ACPI is designed for use with Windows, resources
|
|
that are intended to be consumed by sensor devices are sometimes in
|
|
the _CRS of a dummy INT3472 device upon which the sensor depends. This
|
|
driver binds to the dummy acpi device (which does not represent a
|
|
physical PMIC) and maps them into GPIO lines and regulators for use by
|
|
the sensor device instead.
|
|
|
|
Signed-off-by: Daniel Scally <djrscally@gmail.com>
|
|
Patchset: cameras
|
|
---
|
|
MAINTAINERS | 7 +
|
|
drivers/media/pci/intel/ipu3/Kconfig | 14 +
|
|
drivers/media/pci/intel/ipu3/Makefile | 1 +
|
|
drivers/media/pci/intel/ipu3/int3472.c | 381 +++++++++++++++++++++++++
|
|
drivers/media/pci/intel/ipu3/int3472.h | 96 +++++++
|
|
5 files changed, 499 insertions(+)
|
|
create mode 100644 drivers/media/pci/intel/ipu3/int3472.c
|
|
create mode 100644 drivers/media/pci/intel/ipu3/int3472.h
|
|
|
|
diff --git a/MAINTAINERS b/MAINTAINERS
|
|
index a6924e3401e8..b5bd52b4dae3 100644
|
|
--- a/MAINTAINERS
|
|
+++ b/MAINTAINERS
|
|
@@ -8761,6 +8761,13 @@ L: linux-crypto@vger.kernel.org
|
|
S: Maintained
|
|
F: drivers/crypto/inside-secure/
|
|
|
|
+INT3472 ACPI DEVICE DRIVER
|
|
+M: Daniel Scally <djrscally@gmail.com>
|
|
+L: linux-media@vger.kernel.org
|
|
+S: Maintained
|
|
+F: drivers/media/pci/intel/ipu3/int3472.c
|
|
+F: drivers/media/pci/intel/ipu3/int3472.h
|
|
+
|
|
INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
|
|
M: Mimi Zohar <zohar@linux.ibm.com>
|
|
M: Dmitry Kasatkin <dmitry.kasatkin@gmail.com>
|
|
diff --git a/drivers/media/pci/intel/ipu3/Kconfig b/drivers/media/pci/intel/ipu3/Kconfig
|
|
index 2b3350d042be..9dd3b280f821 100644
|
|
--- a/drivers/media/pci/intel/ipu3/Kconfig
|
|
+++ b/drivers/media/pci/intel/ipu3/Kconfig
|
|
@@ -34,3 +34,17 @@ config CIO2_BRIDGE
|
|
- Dell 7285
|
|
|
|
If in doubt, say N here.
|
|
+
|
|
+config INT3472
|
|
+ tristate "INT3472 Dummy ACPI Device Driver"
|
|
+ depends on VIDEO_IPU3_CIO2
|
|
+ depends on ACPI && REGULATOR && GPIOLIB
|
|
+ help
|
|
+ This module provides an ACPI driver for INT3472 devices that do not
|
|
+ represent an actual physical tps68470 device.
|
|
+
|
|
+ Say Y here if your device is a detachable / hybrid laptop that comes
|
|
+ with Windows installed by the OEM.
|
|
+ The module will be called int3472.
|
|
+
|
|
+ If in doubt, say N here.
|
|
diff --git a/drivers/media/pci/intel/ipu3/Makefile b/drivers/media/pci/intel/ipu3/Makefile
|
|
index 933777e6ea8a..2285947b2bd2 100644
|
|
--- a/drivers/media/pci/intel/ipu3/Makefile
|
|
+++ b/drivers/media/pci/intel/ipu3/Makefile
|
|
@@ -1,5 +1,6 @@
|
|
# SPDX-License-Identifier: GPL-2.0-only
|
|
obj-$(CONFIG_VIDEO_IPU3_CIO2) += ipu3-cio2.o
|
|
+obj-$(CONFIG_INT3472) += int3472.o
|
|
|
|
ipu3-cio2-y += ipu3-cio2-main.o
|
|
ipu3-cio2-$(CONFIG_CIO2_BRIDGE) += cio2-bridge.o
|
|
diff --git a/drivers/media/pci/intel/ipu3/int3472.c b/drivers/media/pci/intel/ipu3/int3472.c
|
|
new file mode 100644
|
|
index 000000000000..9fab8dd2ac1b
|
|
--- /dev/null
|
|
+++ b/drivers/media/pci/intel/ipu3/int3472.c
|
|
@@ -0,0 +1,381 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/* Author: Dan Scally <djrscally@gmail.com> */
|
|
+#include <linux/acpi.h>
|
|
+#include <linux/gpio/consumer.h>
|
|
+#include <linux/gpio/machine.h>
|
|
+#include <linux/i2c.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/list.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/regulator/driver.h>
|
|
+
|
|
+#include "int3472.h"
|
|
+
|
|
+/*
|
|
+ * 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 int3472_map_gpio_to_sensor(struct int3472_device *int3472,
|
|
+ struct acpi_resource *ares, char *func)
|
|
+{
|
|
+ char *path = ares->data.gpio.resource_source.string_ptr;
|
|
+ struct gpiod_lookup table_entry;
|
|
+ struct acpi_device *adev;
|
|
+ acpi_handle handle;
|
|
+ acpi_status status;
|
|
+ int ret;
|
|
+
|
|
+ /* Make sure we don't overflow, and leave room for a terminator */
|
|
+ if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) {
|
|
+ dev_warn(&int3472->sensor->dev, "Too many GPIOs mapped\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ /* Fetch ACPI handle for the GPIO chip */
|
|
+ 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, GPIO_ACTIVE_HIGH);
|
|
+
|
|
+ memcpy(&int3472->gpios.table[int3472->n_sensor_gpios], &table_entry,
|
|
+ sizeof(table_entry));
|
|
+ int3472->n_sensor_gpios++;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct int3472_sensor_regulator_map *
|
|
+int3472_get_sensor_supply_map(struct int3472_device *int3472)
|
|
+{
|
|
+ struct int3472_sensor_regulator_map *ret;
|
|
+ union acpi_object *obj;
|
|
+ unsigned int i;
|
|
+
|
|
+ /*
|
|
+ * Sensor modules seem to be identified by a unique string. We use that
|
|
+ * to make sure we pass the right device and supply names to the new
|
|
+ * regulator's consumer_supplies
|
|
+ */
|
|
+ obj = acpi_evaluate_dsm_typed(int3472->sensor->handle,
|
|
+ &cio2_sensor_module_guid, 0x00,
|
|
+ 0x01, NULL, ACPI_TYPE_STRING);
|
|
+
|
|
+ if (!obj) {
|
|
+ dev_err(&int3472->sensor->dev,
|
|
+ "Failed to get sensor module string from _DSM\n");
|
|
+ return ERR_PTR(-ENODEV);
|
|
+ }
|
|
+
|
|
+ if (obj->string.type != ACPI_TYPE_STRING) {
|
|
+ dev_err(&int3472->sensor->dev,
|
|
+ "Sensor _DSM returned a non-string value\n");
|
|
+ ret = ERR_PTR(-EINVAL);
|
|
+ goto out_free_obj;
|
|
+ }
|
|
+
|
|
+ ret = ERR_PTR(-ENODEV);
|
|
+ for (i = 0; i < ARRAY_SIZE(int3472_sensor_regulator_maps); i++) {
|
|
+ if (!strcmp(int3472_sensor_regulator_maps[i].sensor_module_name,
|
|
+ obj->string.pointer)) {
|
|
+ ret = &int3472_sensor_regulator_maps[i];
|
|
+ goto out_free_obj;
|
|
+ }
|
|
+ }
|
|
+
|
|
+out_free_obj:
|
|
+ ACPI_FREE(obj);
|
|
+ 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_regulator_map *regulator_map;
|
|
+ struct regulator_init_data init_data = { };
|
|
+ struct int3472_gpio_regulator *regulator;
|
|
+ struct regulator_config cfg = { };
|
|
+ int ret;
|
|
+
|
|
+ /*
|
|
+ * We lookup supply names from machine specific tables, based on a
|
|
+ * unique identifier in the sensor's _DSM
|
|
+ */
|
|
+ regulator_map = int3472_get_sensor_supply_map(int3472);
|
|
+ if (IS_ERR_OR_NULL(regulator_map)) {
|
|
+ dev_err(&int3472->sensor->dev,
|
|
+ "Found no supplies defined for this sensor\n");
|
|
+ return PTR_ERR(regulator_map);
|
|
+ }
|
|
+
|
|
+ if (int3472->n_regulators >= regulator_map->n_supplies) {
|
|
+ dev_err(&int3472->sensor->dev,
|
|
+ "All known supplies are already mapped\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ init_data.supply_regulator = NULL;
|
|
+ init_data.constraints.valid_ops_mask = REGULATOR_CHANGE_STATUS;
|
|
+ init_data.num_consumer_supplies = 1;
|
|
+ init_data.consumer_supplies = ®ulator_map->supplies[int3472->n_regulators];
|
|
+
|
|
+ regulator = kmalloc(sizeof(*regulator), GFP_KERNEL);
|
|
+ if (!regulator)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ snprintf(regulator->regulator_name, GPIO_REGULATOR_NAME_LENGTH,
|
|
+ "gpio-regulator-%d", int3472->n_regulators);
|
|
+ snprintf(regulator->supply_name, GPIO_REGULATOR_SUPPLY_NAME_LENGTH,
|
|
+ "supply-%d", int3472->n_regulators);
|
|
+
|
|
+ regulator->rdesc = INT3472_REGULATOR(regulator->regulator_name,
|
|
+ regulator->supply_name,
|
|
+ int3472->n_regulators,
|
|
+ &int3472_gpio_regulator_ops);
|
|
+
|
|
+ regulator->gpio = acpi_get_gpiod(path, ares->data.gpio.pin_table[0]);
|
|
+ if (IS_ERR(regulator->gpio)) {
|
|
+ ret = PTR_ERR(regulator->gpio);
|
|
+ goto err_free_regulator;
|
|
+ }
|
|
+
|
|
+ cfg.dev = &int3472->adev->dev;
|
|
+ cfg.init_data = &init_data;
|
|
+ cfg.ena_gpiod = regulator->gpio;
|
|
+
|
|
+ regulator->rdev = regulator_register(®ulator->rdesc, &cfg);
|
|
+ if (IS_ERR(regulator->rdev)) {
|
|
+ ret = PTR_ERR(regulator->rdev);
|
|
+ goto err_free_gpio;
|
|
+ }
|
|
+
|
|
+ list_add(®ulator->list, &int3472->regulators);
|
|
+ int3472->n_regulators++;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+err_free_gpio:
|
|
+ gpiod_put(regulator->gpio);
|
|
+err_free_regulator:
|
|
+ kfree(regulator);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+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 */
|
|
+
|
|
+ /*
|
|
+ * 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->adev->dev,
|
|
+ "No _DSM entry for this GPIO pin\n");
|
|
+ return ENODEV;
|
|
+ }
|
|
+
|
|
+ switch (obj->integer.value & 0xff) { /* low byte holds type data */
|
|
+ case 0x00: /* Purpose unclear, possibly a reset GPIO pin */
|
|
+ ret = int3472_map_gpio_to_sensor(int3472, ares, "reset");
|
|
+ if (ret)
|
|
+ dev_warn(&int3472->adev->dev,
|
|
+ "Failed to map reset pin to sensor\n");
|
|
+
|
|
+ break;
|
|
+ case 0x01: /* Power regulators (we think) */
|
|
+ case 0x0c:
|
|
+ ret = int3472_register_regulator(int3472, ares);
|
|
+ if (ret)
|
|
+ dev_warn(&int3472->adev->dev,
|
|
+ "Failed to map regulator to sensor\n");
|
|
+
|
|
+ break;
|
|
+ case 0x0b: /* Power regulators, but to a device separate to sensor */
|
|
+ ret = int3472_register_regulator(int3472, ares);
|
|
+ if (ret)
|
|
+ dev_warn(&int3472->adev->dev,
|
|
+ "Failed to map regulator to sensor\n");
|
|
+
|
|
+ break;
|
|
+ case 0x0d: /* Indicator LEDs */
|
|
+ ret = int3472_map_gpio_to_sensor(int3472, ares, "indicator-led");
|
|
+ if (ret)
|
|
+ dev_warn(&int3472->adev->dev,
|
|
+ "Failed to map indicator led to sensor\n");
|
|
+
|
|
+ break;
|
|
+ default:
|
|
+ /* if we've gotten here, we're not sure what they are yet */
|
|
+ dev_warn(&int3472->adev->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 abs(ret);
|
|
+}
|
|
+
|
|
+static void int3472_parse_crs(struct int3472_device *int3472)
|
|
+{
|
|
+ struct list_head resource_list;
|
|
+
|
|
+ INIT_LIST_HEAD(&resource_list);
|
|
+
|
|
+ acpi_dev_get_resources(int3472->adev, &resource_list,
|
|
+ int3472_handle_gpio_resources, int3472);
|
|
+
|
|
+ acpi_dev_free_resource_list(&resource_list);
|
|
+ gpiod_add_lookup_table(&int3472->gpios);
|
|
+}
|
|
+
|
|
+static int int3472_add(struct acpi_device *adev)
|
|
+{
|
|
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
|
+ struct int3472_device *int3472;
|
|
+ struct int3472_cldb cldb;
|
|
+ union acpi_object *obj;
|
|
+ acpi_status status;
|
|
+ int ret = 0;
|
|
+
|
|
+ /*
|
|
+ * This driver is only intended to support "dummy" INT3472 devices
|
|
+ * which appear in ACPI designed for Windows. These are distinguishable
|
|
+ * from INT3472 entries representing an actual tps68470 PMIC through
|
|
+ * the presence of a CLDB buffer with a particular value set.
|
|
+ */
|
|
+ status = acpi_evaluate_object(adev->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);
|
|
+
|
|
+ /*
|
|
+ * control_logic_type = 1 indicates this is a dummy INT3472 device of
|
|
+ * the kind we're looking for. If any other value then we shouldn't try
|
|
+ * to handle it
|
|
+ */
|
|
+ if (cldb.control_logic_type != 1) {
|
|
+ ret = -EINVAL;
|
|
+ goto out_free_buff;
|
|
+ }
|
|
+
|
|
+ /* Space for 4 GPIOs - one more than we've seen so far plus a null */
|
|
+ int3472 = kzalloc(sizeof(*int3472) +
|
|
+ ((INT3472_MAX_SENSOR_GPIOS + 1) * sizeof(struct gpiod_lookup)),
|
|
+ GFP_KERNEL);
|
|
+ if (!int3472) {
|
|
+ ret = -ENOMEM;
|
|
+ goto out_free_buff;
|
|
+ }
|
|
+
|
|
+ int3472->adev = adev;
|
|
+ adev->driver_data = int3472;
|
|
+
|
|
+ int3472->sensor = acpi_dev_get_next_dep_dev(adev, NULL);
|
|
+ if (!int3472->sensor) {
|
|
+ dev_err(&adev->dev,
|
|
+ "This INT3472 entry seems to have no dependents.\n");
|
|
+ ret = -ENODEV;
|
|
+ goto out_free_int3472;
|
|
+ }
|
|
+
|
|
+ int3472->gpios.dev_id = i2c_acpi_dev_name(int3472->sensor);
|
|
+
|
|
+ INIT_LIST_HEAD(&int3472->regulators);
|
|
+
|
|
+ int3472_parse_crs(int3472);
|
|
+
|
|
+ goto out_free_buff;
|
|
+
|
|
+out_free_int3472:
|
|
+ kfree(int3472);
|
|
+out_free_buff:
|
|
+ kfree(buffer.pointer);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int int3472_remove(struct acpi_device *adev)
|
|
+{
|
|
+ struct int3472_gpio_regulator *reg;
|
|
+ struct int3472_device *int3472;
|
|
+
|
|
+ int3472 = acpi_driver_data(adev);
|
|
+
|
|
+ acpi_dev_put(int3472->sensor);
|
|
+ gpiod_remove_lookup_table(&int3472->gpios);
|
|
+
|
|
+ list_for_each_entry(reg, &int3472->regulators, list) {
|
|
+ gpiod_put(reg->gpio);
|
|
+ regulator_unregister(reg->rdev);
|
|
+ }
|
|
+
|
|
+ kfree(int3472);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct acpi_device_id int3472_device_id[] = {
|
|
+ { "INT3472", 0 },
|
|
+ { },
|
|
+};
|
|
+MODULE_DEVICE_TABLE(acpi, int3472_device_id);
|
|
+
|
|
+static struct acpi_driver int3472_driver = {
|
|
+ .name = "int3472",
|
|
+ .ids = int3472_device_id,
|
|
+ .ops = {
|
|
+ .add = int3472_add,
|
|
+ .remove = int3472_remove,
|
|
+ },
|
|
+ .owner = THIS_MODULE,
|
|
+};
|
|
+
|
|
+module_acpi_driver(int3472_driver);
|
|
+
|
|
+MODULE_LICENSE("GPL v2");
|
|
+MODULE_AUTHOR("Dan Scally <djrscally@gmail.com>");
|
|
+MODULE_DESCRIPTION("ACPI Driver for Discrete type INT3472 ACPI Devices");
|
|
diff --git a/drivers/media/pci/intel/ipu3/int3472.h b/drivers/media/pci/intel/ipu3/int3472.h
|
|
new file mode 100644
|
|
index 000000000000..6964726e8e1f
|
|
--- /dev/null
|
|
+++ b/drivers/media/pci/intel/ipu3/int3472.h
|
|
@@ -0,0 +1,96 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/* Author: Dan Scally <djrscally@gmail.com> */
|
|
+#include <linux/regulator/machine.h>
|
|
+
|
|
+#define INT3472_MAX_SENSOR_GPIOS 3
|
|
+#define GPIO_REGULATOR_NAME_LENGTH 17
|
|
+#define GPIO_REGULATOR_SUPPLY_NAME_LENGTH 9
|
|
+
|
|
+#define INT3472_REGULATOR(_NAME, _SUPPLY, _ID, _OPS) \
|
|
+ ((const struct regulator_desc) { \
|
|
+ .name = _NAME, \
|
|
+ .supply_name = _SUPPLY, \
|
|
+ .id = _ID, \
|
|
+ .type = REGULATOR_VOLTAGE, \
|
|
+ .ops = _OPS, \
|
|
+ .owner = THIS_MODULE, \
|
|
+ })
|
|
+
|
|
+const guid_t int3472_gpio_guid = GUID_INIT(0x79234640, 0x9e10, 0x4fea,
|
|
+ 0xa5, 0xc1, 0xb5, 0xaa, 0x8b,
|
|
+ 0x19, 0x75, 0x6f);
|
|
+
|
|
+const guid_t cio2_sensor_module_guid = GUID_INIT(0x822ace8f, 0x2814, 0x4174,
|
|
+ 0xa5, 0x6b, 0x5f, 0x02, 0x9f,
|
|
+ 0xe0, 0x79, 0xee);
|
|
+
|
|
+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_device {
|
|
+ struct acpi_device *adev;
|
|
+ struct acpi_device *sensor;
|
|
+
|
|
+ unsigned int n_gpios; /* how many GPIOs have we seen */
|
|
+
|
|
+ unsigned int n_regulators;
|
|
+ struct list_head regulators;
|
|
+
|
|
+ unsigned int n_sensor_gpios; /* how many have we mapped to sensor */
|
|
+ struct gpiod_lookup_table gpios;
|
|
+};
|
|
+
|
|
+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 list_head list;
|
|
+};
|
|
+
|
|
+struct int3472_sensor_regulator_map {
|
|
+ char *sensor_module_name;
|
|
+ unsigned int n_supplies;
|
|
+ struct regulator_consumer_supply *supplies;
|
|
+};
|
|
+
|
|
+/*
|
|
+ * Here follows platform specific mapping information that we can pass to
|
|
+ * regulator_init_data when we register our regulators. They're just mapped
|
|
+ * via index, I.E. the first regulator pin that the code finds for the
|
|
+ * i2c-OVTI2680:00 device is avdd, the second is dovdd and so on.
|
|
+ */
|
|
+
|
|
+static struct regulator_consumer_supply miix_510_ov2680[] = {
|
|
+ { "i2c-OVTI2680:00", "avdd" },
|
|
+ { "i2c-OVTI2680:00", "dovdd" },
|
|
+};
|
|
+
|
|
+static struct regulator_consumer_supply surface_go2_ov5693[] = {
|
|
+ { "i2c-INT33BE:00", "avdd" },
|
|
+ { "i2c-INT33BE:00", "dovdd" },
|
|
+};
|
|
+
|
|
+static struct regulator_consumer_supply surface_book_ov5693[] = {
|
|
+ { "i2c-INT33BE:00", "avdd" },
|
|
+ { "i2c-INT33BE:00", "dovdd" },
|
|
+};
|
|
+
|
|
+static struct int3472_sensor_regulator_map int3472_sensor_regulator_maps[] = {
|
|
+ { "GNDF140809R", 2, miix_510_ov2680 },
|
|
+ { "YHCU", 2, surface_go2_ov5693 },
|
|
+ { "MSHW0070", 2, surface_book_ov5693 },
|
|
+};
|
|
--
|
|
2.29.2
|
|
|
|
From 120cadac0508f256794984dfe742805d4522a056 Mon Sep 17 00:00:00 2001
|
|
From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
Date: Thu, 10 Dec 2020 17:45:49 +0100
|
|
Subject: [PATCH] ipu3: int3472: Add missing IDs for Surface Book 1
|
|
|
|
Patchset: cameras
|
|
---
|
|
drivers/media/pci/intel/ipu3/int3472.h | 16 ++++++++++++++--
|
|
1 file changed, 14 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/drivers/media/pci/intel/ipu3/int3472.h b/drivers/media/pci/intel/ipu3/int3472.h
|
|
index 6964726e8e1f..d9f74a0c94c9 100644
|
|
--- a/drivers/media/pci/intel/ipu3/int3472.h
|
|
+++ b/drivers/media/pci/intel/ipu3/int3472.h
|
|
@@ -84,13 +84,25 @@ static struct regulator_consumer_supply surface_go2_ov5693[] = {
|
|
{ "i2c-INT33BE:00", "dovdd" },
|
|
};
|
|
|
|
-static struct regulator_consumer_supply surface_book_ov5693[] = {
|
|
+static struct regulator_consumer_supply surface_ov5693[] = {
|
|
{ "i2c-INT33BE:00", "avdd" },
|
|
{ "i2c-INT33BE:00", "dovdd" },
|
|
};
|
|
|
|
+static struct regulator_consumer_supply surface_ov8865[] = {
|
|
+ { "i2c-INT347A:00", "avdd" },
|
|
+ { "i2c-INT347A:00", "dovdd" },
|
|
+};
|
|
+
|
|
+static struct regulator_consumer_supply surface_ov7251[] = {
|
|
+ { "i2c-INT347E:00", "avdd" },
|
|
+ { "i2c-INT347E:00", "dovdd" },
|
|
+};
|
|
+
|
|
static struct int3472_sensor_regulator_map int3472_sensor_regulator_maps[] = {
|
|
{ "GNDF140809R", 2, miix_510_ov2680 },
|
|
{ "YHCU", 2, surface_go2_ov5693 },
|
|
- { "MSHW0070", 2, surface_book_ov5693 },
|
|
+ { "MSHW0070", 2, surface_ov5693 }, /* Surface Book 1/Pro 4, front */
|
|
+ { "MSHW0071", 2, surface_ov8865 }, /* Surface Book 1/Pro 4, rear */
|
|
+ { "MSHW0072", 2, surface_ov7251 }, /* Surface Book 1/Pro 4, IR */
|
|
};
|
|
--
|
|
2.29.2
|
|
|
|
From 904f101714f0e47e20f56c9a077f7653260567a4 Mon Sep 17 00:00:00 2001
|
|
From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
Date: Thu, 10 Dec 2020 17:46:22 +0100
|
|
Subject: [PATCH] ipu3: int3472: Add IDs for Surface Book 2
|
|
|
|
Patchset: cameras
|
|
---
|
|
drivers/media/pci/intel/ipu3/int3472.h | 6 ++++++
|
|
1 file changed, 6 insertions(+)
|
|
|
|
diff --git a/drivers/media/pci/intel/ipu3/int3472.h b/drivers/media/pci/intel/ipu3/int3472.h
|
|
index d9f74a0c94c9..242cc82b9e95 100644
|
|
--- a/drivers/media/pci/intel/ipu3/int3472.h
|
|
+++ b/drivers/media/pci/intel/ipu3/int3472.h
|
|
@@ -105,4 +105,10 @@ static struct int3472_sensor_regulator_map int3472_sensor_regulator_maps[] = {
|
|
{ "MSHW0070", 2, surface_ov5693 }, /* Surface Book 1/Pro 4, front */
|
|
{ "MSHW0071", 2, surface_ov8865 }, /* Surface Book 1/Pro 4, rear */
|
|
{ "MSHW0072", 2, surface_ov7251 }, /* Surface Book 1/Pro 4, IR */
|
|
+ { "MSHW0140", 2, surface_ov5693 }, /* Surface Book 2 (13"), front */
|
|
+ { "MSHW0141", 2, surface_ov8865 }, /* Surface Book 2 (13"), rear */
|
|
+ { "MSHW0142", 2, surface_ov7251 }, /* Surface Book 2 (13"), IR */
|
|
+ { "MSHW0150", 2, surface_ov5693 }, /* Surface Book 2 (15"), front */
|
|
+ { "MSHW0151", 2, surface_ov8865 }, /* Surface Book 2 (15"), rear */
|
|
+ { "MSHW0152", 2, surface_ov7251 }, /* Surface Book 2 (15"), IR */
|
|
};
|
|
--
|
|
2.29.2
|
|
|
|
From 7f0e60d4628f5563ca0d75f8737cfd02d24eeb7a Mon Sep 17 00:00:00 2001
|
|
From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
Date: Tue, 15 Dec 2020 17:43:00 +0100
|
|
Subject: [PATCH] ipu3: int3472: Add IDs for Surface Pro 5 and Pro 6
|
|
|
|
Patchset: cameras
|
|
---
|
|
drivers/media/pci/intel/ipu3/int3472.h | 3 +++
|
|
1 file changed, 3 insertions(+)
|
|
|
|
diff --git a/drivers/media/pci/intel/ipu3/int3472.h b/drivers/media/pci/intel/ipu3/int3472.h
|
|
index 242cc82b9e95..1d2e9cea54f4 100644
|
|
--- a/drivers/media/pci/intel/ipu3/int3472.h
|
|
+++ b/drivers/media/pci/intel/ipu3/int3472.h
|
|
@@ -105,6 +105,9 @@ static struct int3472_sensor_regulator_map int3472_sensor_regulator_maps[] = {
|
|
{ "MSHW0070", 2, surface_ov5693 }, /* Surface Book 1/Pro 4, front */
|
|
{ "MSHW0071", 2, surface_ov8865 }, /* Surface Book 1/Pro 4, rear */
|
|
{ "MSHW0072", 2, surface_ov7251 }, /* Surface Book 1/Pro 4, IR */
|
|
+ { "MSHW0120", 2, surface_ov5693 }, /* Surface Pro 5/Pro 6, front */
|
|
+ { "MSHW0121", 2, surface_ov8865 }, /* Surface Pro 5/Pro 6, rear */
|
|
+ { "MSHW0122", 2, surface_ov7251 }, /* Surface Pro 5/Pro 6, IR */
|
|
{ "MSHW0140", 2, surface_ov5693 }, /* Surface Book 2 (13"), front */
|
|
{ "MSHW0141", 2, surface_ov8865 }, /* Surface Book 2 (13"), rear */
|
|
{ "MSHW0142", 2, surface_ov7251 }, /* Surface Book 2 (13"), IR */
|
|
--
|
|
2.29.2
|
|
|
|
From d0340fc1858765f795aab4190ca6e6a0ffeb6bb7 Mon Sep 17 00:00:00 2001
|
|
From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
Date: Thu, 10 Dec 2020 18:42:44 +0100
|
|
Subject: [PATCH] media: i2c: Add driver for OV5693 sensor
|
|
|
|
Copied from https://github.com/djrscally/surface-ipu3-cameras/tree/18cdb0c0238bc26258501d2bfe95ed7b971803fa
|
|
|
|
Patchset: cameras
|
|
---
|
|
drivers/media/i2c/Kconfig | 13 +
|
|
drivers/media/i2c/Makefile | 1 +
|
|
drivers/media/i2c/ad5823.h | 63 ++
|
|
drivers/media/i2c/ov5693.c | 1606 ++++++++++++++++++++++++++++++++++++
|
|
drivers/media/i2c/ov5693.h | 1415 +++++++++++++++++++++++++++++++
|
|
5 files changed, 3098 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..cc3263a91175 100644
|
|
--- a/drivers/media/i2c/Kconfig
|
|
+++ b/drivers/media/i2c/Kconfig
|
|
@@ -958,6 +958,19 @@ 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 MEDIA_CONTROLLER
|
|
+ select VIDEO_V4L2_SUBDEV_API
|
|
+ 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..0b2b76781b11
|
|
--- /dev/null
|
|
+++ b/drivers/media/i2c/ov5693.c
|
|
@@ -0,0 +1,1606 @@
|
|
+// 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/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");
|
|
+
|
|
+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 long __ov5693_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
|
|
+ int gain, int digitgain)
|
|
+
|
|
+{
|
|
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
|
|
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
|
|
+ u16 vts, hts;
|
|
+ int ret, exp_val;
|
|
+
|
|
+ hts = ov5693_res[dev->fmt_idx].pixels_per_line;
|
|
+ vts = ov5693_res[dev->fmt_idx].lines_per_frame;
|
|
+ /*
|
|
+ * If coarse_itg is larger than 1<<15, can not write to reg directly.
|
|
+ * The way is to write coarse_itg/2 to the reg, meanwhile write 2*hts
|
|
+ * to the reg.
|
|
+ */
|
|
+ if (coarse_itg > (1 << 15)) {
|
|
+ hts = hts * 2;
|
|
+ coarse_itg = (int)coarse_itg / 2;
|
|
+ }
|
|
+ /* group hold */
|
|
+ ret = ov5693_write_reg(client, OV5693_8BIT,
|
|
+ OV5693_GROUP_ACCESS, 0x00);
|
|
+ if (ret) {
|
|
+ dev_err(&client->dev, "%s: write %x error, aborted\n",
|
|
+ __func__, OV5693_GROUP_ACCESS);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = ov5693_write_reg(client, OV5693_8BIT,
|
|
+ OV5693_TIMING_HTS_H, (hts >> 8) & 0xFF);
|
|
+ if (ret) {
|
|
+ dev_err(&client->dev, "%s: write %x error, aborted\n",
|
|
+ __func__, OV5693_TIMING_HTS_H);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = ov5693_write_reg(client, OV5693_8BIT,
|
|
+ OV5693_TIMING_HTS_L, hts & 0xFF);
|
|
+ if (ret) {
|
|
+ dev_err(&client->dev, "%s: write %x error, aborted\n",
|
|
+ __func__, OV5693_TIMING_HTS_L);
|
|
+ return ret;
|
|
+ }
|
|
+ /* Increase the VTS to match exposure + MARGIN */
|
|
+ if (coarse_itg > vts - OV5693_INTEGRATION_TIME_MARGIN)
|
|
+ vts = (u16)coarse_itg + OV5693_INTEGRATION_TIME_MARGIN;
|
|
+
|
|
+ ret = ov5693_write_reg(client, OV5693_8BIT,
|
|
+ OV5693_TIMING_VTS_H, (vts >> 8) & 0xFF);
|
|
+ if (ret) {
|
|
+ dev_err(&client->dev, "%s: write %x error, aborted\n",
|
|
+ __func__, OV5693_TIMING_VTS_H);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = ov5693_write_reg(client, OV5693_8BIT,
|
|
+ OV5693_TIMING_VTS_L, vts & 0xFF);
|
|
+ if (ret) {
|
|
+ dev_err(&client->dev, "%s: write %x error, aborted\n",
|
|
+ __func__, OV5693_TIMING_VTS_L);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ /* set exposure */
|
|
+
|
|
+ /* Lower four bit should be 0*/
|
|
+ exp_val = coarse_itg << 4;
|
|
+ ret = ov5693_write_reg(client, OV5693_8BIT,
|
|
+ OV5693_EXPOSURE_L, exp_val & 0xFF);
|
|
+ if (ret) {
|
|
+ dev_err(&client->dev, "%s: write %x error, aborted\n",
|
|
+ __func__, OV5693_EXPOSURE_L);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = ov5693_write_reg(client, OV5693_8BIT,
|
|
+ OV5693_EXPOSURE_M, (exp_val >> 8) & 0xFF);
|
|
+ if (ret) {
|
|
+ dev_err(&client->dev, "%s: write %x error, aborted\n",
|
|
+ __func__, OV5693_EXPOSURE_M);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = ov5693_write_reg(client, OV5693_8BIT,
|
|
+ OV5693_EXPOSURE_H, (exp_val >> 16) & 0x0F);
|
|
+ if (ret) {
|
|
+ dev_err(&client->dev, "%s: write %x error, aborted\n",
|
|
+ __func__, OV5693_EXPOSURE_H);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ /* Analog gain */
|
|
+ ret = ov5693_write_reg(client, OV5693_8BIT,
|
|
+ OV5693_AGC_L, gain & 0xff);
|
|
+ if (ret) {
|
|
+ dev_err(&client->dev, "%s: write %x error, aborted\n",
|
|
+ __func__, OV5693_AGC_L);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = ov5693_write_reg(client, OV5693_8BIT,
|
|
+ OV5693_AGC_H, (gain >> 8) & 0xff);
|
|
+ if (ret) {
|
|
+ dev_err(&client->dev, "%s: write %x error, aborted\n",
|
|
+ __func__, OV5693_AGC_H);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ /* Digital gain */
|
|
+ if (digitgain) {
|
|
+ ret = ov5693_write_reg(client, OV5693_16BIT,
|
|
+ OV5693_MWB_RED_GAIN_H, digitgain);
|
|
+ if (ret) {
|
|
+ dev_err(&client->dev, "%s: write %x error, aborted\n",
|
|
+ __func__, OV5693_MWB_RED_GAIN_H);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = ov5693_write_reg(client, OV5693_16BIT,
|
|
+ OV5693_MWB_GREEN_GAIN_H, digitgain);
|
|
+ if (ret) {
|
|
+ dev_err(&client->dev, "%s: write %x error, aborted\n",
|
|
+ __func__, OV5693_MWB_RED_GAIN_H);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ ret = ov5693_write_reg(client, OV5693_16BIT,
|
|
+ OV5693_MWB_BLUE_GAIN_H, digitgain);
|
|
+ if (ret) {
|
|
+ dev_err(&client->dev, "%s: write %x error, aborted\n",
|
|
+ __func__, OV5693_MWB_RED_GAIN_H);
|
|
+ return ret;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* End group */
|
|
+ ret = ov5693_write_reg(client, OV5693_8BIT,
|
|
+ OV5693_GROUP_ACCESS, 0x10);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ /* Delay launch group */
|
|
+ ret = ov5693_write_reg(client, OV5693_8BIT,
|
|
+ OV5693_GROUP_ACCESS, 0xa0);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int ov5693_set_exposure(struct v4l2_subdev *sd, int exposure,
|
|
+ int gain, int digitgain)
|
|
+{
|
|
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
|
|
+ int ret;
|
|
+
|
|
+ mutex_lock(&dev->input_lock);
|
|
+ ret = __ov5693_set_exposure(sd, exposure, gain, digitgain);
|
|
+ mutex_unlock(&dev->input_lock);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+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;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * 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)
|
|
+
|
|
+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;
|
|
+ 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_FOCUS_ABSOLUTE:
|
|
+ /* NOTE: there was atomisp-specific function ov5693_q_focus_abs() */
|
|
+ break;
|
|
+ default:
|
|
+ ret = -EINVAL;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const struct v4l2_ctrl_ops ctrl_ops = {
|
|
+ .s_ctrl = ov5693_s_ctrl,
|
|
+ .g_volatile_ctrl = ov5693_g_volatile_ctrl
|
|
+};
|
|
+
|
|
+static const struct v4l2_ctrl_config ov5693_controls[] = {
|
|
+ {
|
|
+ .ops = &ctrl_ops,
|
|
+ .id = V4L2_CID_EXPOSURE_ABSOLUTE,
|
|
+ .type = V4L2_CTRL_TYPE_INTEGER,
|
|
+ .name = "exposure",
|
|
+ .min = 0x0,
|
|
+ .max = 0xffff,
|
|
+ .step = 0x01,
|
|
+ .def = 0x00,
|
|
+ .flags = 0,
|
|
+ },
|
|
+ {
|
|
+ .ops = &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 = &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_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);
|
|
+ }
|
|
+
|
|
+ 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;
|
|
+
|
|
+ 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;
|
|
+
|
|
+ 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_preview;
|
|
+ N_RES = N_RES_PREVIEW;
|
|
+ }
|
|
+
|
|
+ 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++) {
|
|
+// power_down(sd);
|
|
+ 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 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");
|
|
+// power_down(sd);
|
|
+ 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);
|
|
+ /* power off the module, then power on it in future
|
|
+ * as first power on by board may not fulfill the
|
|
+ * power on sequqence needed by the module
|
|
+ */
|
|
+// ret = power_down(sd);
|
|
+// if (ret) {
|
|
+// dev_err(&client->dev, "ov5693 power-off err.\n");
|
|
+// goto fail_power_off;
|
|
+// }
|
|
+
|
|
+ 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");
|
|
+fail_power_off:
|
|
+ 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,
|
|
+};
|
|
+
|
|
+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);
|
|
+ struct v4l2_ctrl *ctrl;
|
|
+ unsigned int i;
|
|
+ int ret;
|
|
+
|
|
+ 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;
|
|
+ }
|
|
+
|
|
+ /* 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->client->dev, "reset", 0,
|
|
+ GPIOD_OUT_HIGH);
|
|
+ if (IS_ERR(ov5693->reset)) {
|
|
+ dev_err(&ov5693->client->dev, "Couldn't find reset GPIO\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ ov5693->indicator_led = gpiod_get_index_optional(&ov5693->client->dev, "indicator-led", 0,
|
|
+ GPIOD_OUT_HIGH);
|
|
+ if (IS_ERR(ov5693->indicator_led)) {
|
|
+ dev_err(&ov5693->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->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->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);
|
|
+
|
|
+ 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;
|
|
+
|
|
+ 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..9ad9bbe67d0d
|
|
--- /dev/null
|
|
+++ b/drivers/media/i2c/ov5693.h
|
|
@@ -0,0 +1,1415 @@
|
|
+/* 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 0
|
|
+
|
|
+#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;
|
|
+};
|
|
+
|
|
+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 *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 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;
|
|
+};
|
|
+
|
|
+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,
|
|
+ },
|
|
+};
|
|
+
|
|
+#define N_RES_VIDEO (ARRAY_SIZE(ov5693_res_video))
|
|
+#endif
|
|
+
|
|
+static struct ov5693_resolution *ov5693_res = ov5693_res_preview;
|
|
+static unsigned long N_RES = N_RES_PREVIEW;
|
|
+#endif
|
|
--
|
|
2.29.2
|
|
|