clear-pkgs-linux-iot-lts2018/0062-media-i2c-crlmodule-li...

7928 lines
238 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Yew, Chang Ching" <chang.ching.yew@intel.com>
Date: Tue, 23 Oct 2018 13:23:51 +0800
Subject: [PATCH] media: i2c: crlmodule-lite: base code (configurable register
list)
Base code for common sensor driver, crlmodule-lite to work with ICI driver
Squash of below patches from
https://github.com/intel/linux-intel-lts/tree/4.14/base/drivers/media/i2c/crlmodule-lite/
43b66e media: i2c: crlmodule-lite: Add register settings to support multiple modes
b99df4 media: i2c: crlmodule-lite: Add mask field
f20974 media: i2c: crlmodule-lite: Remove op_sys_clock
33d606 media: intel-ipu4: [ICI] ACPI functionality for crlmodule-lite sensors
e90ece crlmodule-lite: Fixing un-used variable warning issue
87737a media:platform/crlmodule-lite:to overcome ACRN UOS limitation of GPIOs.
3f72fb crlmodule-lite: Adding config dependencies between crlmodule & crlmodule-lite
045726 media: i2c: common camera sensor driver crlmodule-lite for ICI
Change-Id: I12c120dedbfaf6c868e5b52b69d798bf1d4774f9
Signed-off-by: Yew, Chang Ching <chang.ching.yew@intel.com>
---
drivers/media/i2c/Kconfig | 1 +
drivers/media/i2c/Makefile | 1 +
drivers/media/i2c/crlmodule-lite/Kconfig | 7 +
drivers/media/i2c/crlmodule-lite/Makefile | 9 +
.../crl_adv7481_configuration.h | 703 +++++
.../crl_adv7481_cvbs_configuration.h | 264 ++
.../crl_adv7481_eval_configuration.h | 531 ++++
.../crl_adv7481_hdmi_configuration.c | 624 ++++
.../crl_adv7481_hdmi_configuration.h | 942 ++++++
.../crl_magna_configuration_ti964.h | 297 ++
.../media/i2c/crlmodule-lite/crlmodule-core.c | 2696 +++++++++++++++++
.../media/i2c/crlmodule-lite/crlmodule-data.c | 73 +
.../i2c/crlmodule-lite/crlmodule-msrlist.c | 160 +
.../i2c/crlmodule-lite/crlmodule-msrlist.h | 53 +
.../media/i2c/crlmodule-lite/crlmodule-nvm.c | 139 +
.../media/i2c/crlmodule-lite/crlmodule-nvm.h | 21 +
.../media/i2c/crlmodule-lite/crlmodule-regs.c | 330 ++
.../media/i2c/crlmodule-lite/crlmodule-regs.h | 24 +
.../i2c/crlmodule-lite/crlmodule-sensor-ds.h | 552 ++++
drivers/media/i2c/crlmodule-lite/crlmodule.h | 114 +
include/media/as3638.h | 33 +
include/media/crlmodule-lite.h | 25 +
include/media/dw9714.h | 32 +
include/media/lc898122.h | 14 +
include/media/lm3643.h | 50 +
25 files changed, 7695 insertions(+)
create mode 100644 drivers/media/i2c/crlmodule-lite/Kconfig
create mode 100644 drivers/media/i2c/crlmodule-lite/Makefile
create mode 100644 drivers/media/i2c/crlmodule-lite/crl_adv7481_configuration.h
create mode 100644 drivers/media/i2c/crlmodule-lite/crl_adv7481_cvbs_configuration.h
create mode 100644 drivers/media/i2c/crlmodule-lite/crl_adv7481_eval_configuration.h
create mode 100644 drivers/media/i2c/crlmodule-lite/crl_adv7481_hdmi_configuration.c
create mode 100644 drivers/media/i2c/crlmodule-lite/crl_adv7481_hdmi_configuration.h
create mode 100644 drivers/media/i2c/crlmodule-lite/crl_magna_configuration_ti964.h
create mode 100644 drivers/media/i2c/crlmodule-lite/crlmodule-core.c
create mode 100644 drivers/media/i2c/crlmodule-lite/crlmodule-data.c
create mode 100644 drivers/media/i2c/crlmodule-lite/crlmodule-msrlist.c
create mode 100644 drivers/media/i2c/crlmodule-lite/crlmodule-msrlist.h
create mode 100644 drivers/media/i2c/crlmodule-lite/crlmodule-nvm.c
create mode 100644 drivers/media/i2c/crlmodule-lite/crlmodule-nvm.h
create mode 100644 drivers/media/i2c/crlmodule-lite/crlmodule-regs.c
create mode 100644 drivers/media/i2c/crlmodule-lite/crlmodule-regs.h
create mode 100644 drivers/media/i2c/crlmodule-lite/crlmodule-sensor-ds.h
create mode 100644 drivers/media/i2c/crlmodule-lite/crlmodule.h
create mode 100644 include/media/as3638.h
create mode 100644 include/media/crlmodule-lite.h
create mode 100755 include/media/dw9714.h
create mode 100644 include/media/lc898122.h
create mode 100644 include/media/lm3643.h
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 5dda368ad88c..4d3ee27b80ba 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -949,6 +949,7 @@ config VIDEO_S5K5BAF
source "drivers/media/i2c/smiapp/Kconfig"
source "drivers/media/i2c/et8ek8/Kconfig"
source "drivers/media/i2c/crlmodule/Kconfig"
+source "drivers/media/i2c/crlmodule-lite/Kconfig"
config VIDEO_S5C73M3
tristate "Samsung S5C73M3 sensor support"
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index b23bd05aab9c..f1e412a8ca89 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -115,3 +115,4 @@ obj-$(CONFIG_VIDEO_CRLMODULE) += crlmodule/
obj-$(CONFIG_VIDEO_TI964) += ti964.o
obj-$(CONFIG_VIDEO_MAX9286) += max9286.o
obj-$(CONFIG_VIDEO_TI960) += ti960.o
+obj-$(CONFIG_VIDEO_CRLMODULE_LITE) += crlmodule-lite/
diff --git a/drivers/media/i2c/crlmodule-lite/Kconfig b/drivers/media/i2c/crlmodule-lite/Kconfig
new file mode 100644
index 000000000000..5f6b506ae749
--- /dev/null
+++ b/drivers/media/i2c/crlmodule-lite/Kconfig
@@ -0,0 +1,7 @@
+config VIDEO_CRLMODULE_LITE
+ tristate "CRL Module sensor support for ICI driver"
+ depends on I2C
+ depends on VIDEO_INTEL_ICI
+ depends on !VIDEO_CRLMODULE
+ ---help---
+ This is a generic driver for CRL based camera modules.
diff --git a/drivers/media/i2c/crlmodule-lite/Makefile b/drivers/media/i2c/crlmodule-lite/Makefile
new file mode 100644
index 000000000000..de5f5e4d3ccb
--- /dev/null
+++ b/drivers/media/i2c/crlmodule-lite/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
+
+crlmodule-lite-objs += crlmodule-core.o crlmodule-data.o \
+ crlmodule-regs.o crlmodule-nvm.o \
+ crl_adv7481_hdmi_configuration.o \
+ crlmodule-msrlist.o
+obj-$(CONFIG_VIDEO_CRLMODULE_LITE) += crlmodule-lite.o
+
+ccflags-y += -Idrivers/media/i2c
diff --git a/drivers/media/i2c/crlmodule-lite/crl_adv7481_configuration.h b/drivers/media/i2c/crlmodule-lite/crl_adv7481_configuration.h
new file mode 100644
index 000000000000..4ebe85478a24
--- /dev/null
+++ b/drivers/media/i2c/crlmodule-lite/crl_adv7481_configuration.h
@@ -0,0 +1,703 @@
+/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) */
+/*
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#ifndef __CRLMODULE_ADV7481_CONFIGURATION_H_
+#define __CRLMODULE_ADV7481_CONFIGURATION_H_
+
+#include "crlmodule-sensor-ds.h"
+
+static struct crl_register_write_rep adv7481_powerup_regset[] = {
+ {0xFF, CRL_REG_LEN_08BIT, 0xFF, 0xE0}, /* SW reset */
+ {0x00, CRL_REG_LEN_DELAY, 0x05, 0x00}, /* Delay 5ms */
+ {0x01, CRL_REG_LEN_08BIT, 0x76, 0xE0}, /* ADI recommended setting */
+ {0xF2, CRL_REG_LEN_08BIT, 0x01, 0xE0}, /* I2C Rd Auto-Increment=1 */
+ {0xF3, CRL_REG_LEN_08BIT, 0x4C, 0xE0}, /* DPLL Map Address */
+ {0xF4, CRL_REG_LEN_08BIT, 0x44, 0xE0}, /* CP Map Address */
+ {0xF5, CRL_REG_LEN_08BIT, 0x68, 0xE0}, /* HDMI RX Map Address */
+ {0xF6, CRL_REG_LEN_08BIT, 0x6C, 0xE0}, /* EDID Map Address */
+ {0xF7, CRL_REG_LEN_08BIT, 0x64, 0xE0}, /* HDMI RX Repeater Map Addr */
+ {0xF8, CRL_REG_LEN_08BIT, 0x62, 0xE0}, /* HDMI RX Infoframe Map Addr */
+ {0xF9, CRL_REG_LEN_08BIT, 0xF0, 0xE0}, /* CBUS Map Address Set */
+ {0xFA, CRL_REG_LEN_08BIT, 0x82, 0xE0}, /* CEC Map Address Set */
+ {0xFB, CRL_REG_LEN_08BIT, 0xF2, 0xE0}, /* SDP Main Map Address */
+ {0xFC, CRL_REG_LEN_08BIT, 0x90, 0xE0}, /* CSI-TXB Map Address */
+ {0xFD, CRL_REG_LEN_08BIT, 0x94, 0xE0}, /* CSI-TXA Map Address */
+ {0x00, CRL_REG_LEN_08BIT, 0x50, 0xE0}, /* Disable Chip Powerdown &
+ HDMI Rx Block */
+ {0x40, CRL_REG_LEN_08BIT, 0x83, 0x64}, /* Enable HDCP 1.1 */
+ {0x00, CRL_REG_LEN_08BIT, 0x08, 0x68}, /* ADI recommended setting */
+ {0x3D, CRL_REG_LEN_08BIT, 0x10, 0x68}, /* ADI recommended setting */
+ {0x3E, CRL_REG_LEN_08BIT, 0x69, 0x68}, /* ADI recommended setting */
+ {0x3F, CRL_REG_LEN_08BIT, 0x46, 0x68}, /* ADI recommended setting */
+ {0x4E, CRL_REG_LEN_08BIT, 0xFE, 0x68}, /* ADI recommended setting */
+ {0x4F, CRL_REG_LEN_08BIT, 0x08, 0x68}, /* ADI recommended setting */
+ {0x57, CRL_REG_LEN_08BIT, 0xA3, 0x68}, /* ADI recommended setting */
+ {0x58, CRL_REG_LEN_08BIT, 0x04, 0x68}, /* ADI recommended setting */
+ {0x85, CRL_REG_LEN_08BIT, 0x10, 0x68}, /* ADI recommended setting */
+ {0x83, CRL_REG_LEN_08BIT, 0x00, 0x68}, /* Enable All Terminations */
+ {0xBE, CRL_REG_LEN_08BIT, 0x00, 0x68}, /* ADI recommended setting */
+ {0x6C, CRL_REG_LEN_08BIT, 0x01, 0x68}, /* HPA Manual Enable */
+ {0xF8, CRL_REG_LEN_08BIT, 0x01, 0x68}, /* HPA Asserted */
+ {0x0F, CRL_REG_LEN_08BIT, 0x00, 0x68}, /* Audio Mute Speed =
+ Fastest Smallest Step Size */
+ {0x70, CRL_REG_LEN_08BIT, 0xA0, 0x64}, /* Write primary edid size */
+ {0x74, CRL_REG_LEN_08BIT, 0x01, 0x64}, /* Enable manual edid */
+ {0x7A, CRL_REG_LEN_08BIT, 0x00, 0x64}, /* Write edid sram select */
+ {0xF6, CRL_REG_LEN_08BIT, 0x6C, 0xE0}, /* Write edid map bus address */
+
+ {0x00*4, CRL_REG_LEN_32BIT, 0x00FFFFFF, 0x6C}, /* EDID programming */
+ {0x01*4, CRL_REG_LEN_32BIT, 0xFFFFFF00, 0x6C}, /* EDID programming */
+ {0x02*4, CRL_REG_LEN_32BIT, 0x4DD90100, 0x6C}, /* EDID programming */
+ {0x03*4, CRL_REG_LEN_32BIT, 0x00000000, 0x6C}, /* EDID programming */
+ {0x04*4, CRL_REG_LEN_32BIT, 0x00110103, 0x6C}, /* EDID programming */
+ {0x05*4, CRL_REG_LEN_32BIT, 0x80000078, 0x6C}, /* EDID programming */
+ {0x06*4, CRL_REG_LEN_32BIT, 0x0A0DC9A0, 0x6C}, /* EDID programming */
+ {0x07*4, CRL_REG_LEN_32BIT, 0x57479827, 0x6C}, /* EDID programming */
+ {0x08*4, CRL_REG_LEN_32BIT, 0x12484C00, 0x6C}, /* EDID programming */
+ {0x09*4, CRL_REG_LEN_32BIT, 0x00000101, 0x6C}, /* EDID programming */
+ {0x0A*4, CRL_REG_LEN_32BIT, 0x01010101, 0x6C}, /* EDID programming */
+ {0x0B*4, CRL_REG_LEN_32BIT, 0x01010101, 0x6C}, /* EDID programming */
+ {0x0C*4, CRL_REG_LEN_32BIT, 0x01010101, 0x6C}, /* EDID programming */
+ {0x0D*4, CRL_REG_LEN_32BIT, 0x0101011D, 0x6C}, /* EDID programming */
+ {0x0E*4, CRL_REG_LEN_32BIT, 0x80D0721C, 0x6C}, /* EDID programming */
+ {0x0F*4, CRL_REG_LEN_32BIT, 0x1620102C, 0x6C}, /* EDID programming */
+ {0x10*4, CRL_REG_LEN_32BIT, 0x2580C48E, 0x6C}, /* EDID programming */
+ {0x11*4, CRL_REG_LEN_32BIT, 0x2100009E, 0x6C}, /* EDID programming */
+ {0x12*4, CRL_REG_LEN_32BIT, 0x011D8018, 0x6C}, /* EDID programming */
+ {0x13*4, CRL_REG_LEN_32BIT, 0x711C1620, 0x6C}, /* EDID programming */
+ {0x14*4, CRL_REG_LEN_32BIT, 0x582C2500, 0x6C}, /* EDID programming */
+ {0x15*4, CRL_REG_LEN_32BIT, 0xC48E2100, 0x6C}, /* EDID programming */
+ {0x16*4, CRL_REG_LEN_32BIT, 0x009E0000, 0x6C}, /* EDID programming */
+ {0x17*4, CRL_REG_LEN_32BIT, 0x00FC0048, 0x6C}, /* EDID programming */
+ {0x18*4, CRL_REG_LEN_32BIT, 0x444D4920, 0x6C}, /* EDID programming */
+ {0x19*4, CRL_REG_LEN_32BIT, 0x4C4C430A, 0x6C}, /* EDID programming */
+ {0x1A*4, CRL_REG_LEN_32BIT, 0x20202020, 0x6C}, /* EDID programming */
+ {0x1B*4, CRL_REG_LEN_32BIT, 0x000000FD, 0x6C}, /* EDID programming */
+ {0x1C*4, CRL_REG_LEN_32BIT, 0x003B3D0F, 0x6C}, /* EDID programming */
+ {0x1D*4, CRL_REG_LEN_32BIT, 0x2D08000A, 0x6C}, /* EDID programming */
+ {0x1E*4, CRL_REG_LEN_32BIT, 0x20202020, 0x6C}, /* EDID programming */
+ {0x1F*4, CRL_REG_LEN_32BIT, 0x202001C1, 0x6C}, /* EDID programming */
+ {0x20*4, CRL_REG_LEN_32BIT, 0x02031E77, 0x6C}, /* EDID programming */
+ {0x21*4, CRL_REG_LEN_32BIT, 0x4F941305, 0x6C}, /* EDID programming */
+ {0x22*4, CRL_REG_LEN_32BIT, 0x03040201, 0x6C}, /* EDID programming */
+ {0x23*4, CRL_REG_LEN_32BIT, 0x16150706, 0x6C}, /* EDID programming */
+ {0x24*4, CRL_REG_LEN_32BIT, 0x1110121F, 0x6C}, /* EDID programming */
+ {0x25*4, CRL_REG_LEN_32BIT, 0x23090701, 0x6C}, /* EDID programming */
+ {0x26*4, CRL_REG_LEN_32BIT, 0x65030C00, 0x6C}, /* EDID programming */
+ {0x27*4, CRL_REG_LEN_32BIT, 0x10008C0A, 0x6C}, /* EDID programming */
+ {0x28*4, CRL_REG_LEN_32BIT, 0xD0902040, 0x6C}, /* EDID programming */
+ {0x29*4, CRL_REG_LEN_32BIT, 0x31200C40, 0x6C}, /* EDID programming */
+ {0x2A*4, CRL_REG_LEN_32BIT, 0x5500138E, 0x6C}, /* EDID programming */
+ {0x2B*4, CRL_REG_LEN_32BIT, 0x21000018, 0x6C}, /* EDID programming */
+ {0x2C*4, CRL_REG_LEN_32BIT, 0x011D00BC, 0x6C}, /* EDID programming */
+ {0x2D*4, CRL_REG_LEN_32BIT, 0x52D01E20, 0x6C}, /* EDID programming */
+ {0x2E*4, CRL_REG_LEN_32BIT, 0xB8285540, 0x6C}, /* EDID programming */
+ {0x2F*4, CRL_REG_LEN_32BIT, 0xC48E2100, 0x6C}, /* EDID programming */
+ {0x30*4, CRL_REG_LEN_32BIT, 0x001E8C0A, 0x6C}, /* EDID programming */
+ {0x31*4, CRL_REG_LEN_32BIT, 0xD08A20E0, 0x6C}, /* EDID programming */
+ {0x32*4, CRL_REG_LEN_32BIT, 0x2D10103E, 0x6C}, /* EDID programming */
+ {0x33*4, CRL_REG_LEN_32BIT, 0x9600C48E, 0x6C}, /* EDID programming */
+ {0x34*4, CRL_REG_LEN_32BIT, 0x21000018, 0x6C}, /* EDID programming */
+ {0x35*4, CRL_REG_LEN_32BIT, 0x011D0072, 0x6C}, /* EDID programming */
+ {0x36*4, CRL_REG_LEN_32BIT, 0x51D01E20, 0x6C}, /* EDID programming */
+ {0x37*4, CRL_REG_LEN_32BIT, 0x6E285500, 0x6C}, /* EDID programming */
+ {0x38*4, CRL_REG_LEN_32BIT, 0xC48E2100, 0x6C}, /* EDID programming */
+ {0x39*4, CRL_REG_LEN_32BIT, 0x001E8C0A, 0x6C}, /* EDID programming */
+ {0x3A*4, CRL_REG_LEN_32BIT, 0xD08A20E0, 0x6C}, /* EDID programming */
+ {0x3B*4, CRL_REG_LEN_32BIT, 0x2D10103E, 0x6C}, /* EDID programming */
+ {0x3C*4, CRL_REG_LEN_32BIT, 0x9600138E, 0x6C}, /* EDID programming */
+ {0x3D*4, CRL_REG_LEN_32BIT, 0x21000018, 0x6C}, /* EDID programming */
+ {0x3E*4, CRL_REG_LEN_32BIT, 0x00000000, 0x6C}, /* EDID programming */
+ {0x3F*4, CRL_REG_LEN_32BIT, 0x000000CB, 0x6C}, /* EDID programming */
+
+ {0x00, CRL_REG_LEN_08BIT, 0x84, 0x94}, /* Enable 4-lane MIPI */
+ {0x1E, CRL_REG_LEN_08BIT, 0x80, 0x94}, /* No MIPI frame start */
+ {0x26, CRL_REG_LEN_08BIT, 0x55, 0x94}, /* Disable sleep mode */
+ {0x27, CRL_REG_LEN_08BIT, 0x55, 0x94}, /* Disable escape mode */
+ {0x7E, CRL_REG_LEN_08BIT, 0xA0, 0x94}, /* ADI recommended setting */
+ {0xF0, CRL_REG_LEN_08BIT, 0x00, 0x90}, /* ADI recommended setting */
+ {0xDA, CRL_REG_LEN_08BIT, 0x01, 0x90}, /* ADI recommended setting */
+ {0xD6, CRL_REG_LEN_08BIT, 0x07, 0x94}, /* ADI recommended setting */
+ {0x34, CRL_REG_LEN_08BIT, 0x55, 0x94}, /* ADI recommended setting */
+ {0xC4, CRL_REG_LEN_08BIT, 0x0A, 0x94}, /* ADI recommended setting */
+ {0xCA, CRL_REG_LEN_08BIT, 0x02, 0x94}, /* ADI recommended setting */
+ {0x71, CRL_REG_LEN_08BIT, 0x33, 0x94}, /* ADI recommended setting */
+ {0x72, CRL_REG_LEN_08BIT, 0x11, 0x94}, /* ADI recommended setting */
+ {0xF0, CRL_REG_LEN_08BIT, 0x00, 0x94}, /* Power up DPHY */
+ {0x31, CRL_REG_LEN_08BIT, 0x82, 0x94}, /* ADI recommended setting */
+ {0xDA, CRL_REG_LEN_08BIT, 0x01, 0x94}, /* ADI recommended setting */
+ {0x00, CRL_REG_LEN_08BIT, 0xA4, 0x94}, /* ADI recommended setting */
+};
+
+static struct crl_register_write_rep adv7481_mode_1080p[] = {
+ {0x04, CRL_REG_LEN_08BIT, 0x00, 0xE0}, /* YCrCb output */
+ {0x05, CRL_REG_LEN_08BIT, 0x5E, 0xE0}, /* Select Resolution 1080P */
+ {0x12, CRL_REG_LEN_08BIT, 0xF2, 0xE0}, /* CSC Depends on ip Packets - SDR422 set */
+ {0x17, CRL_REG_LEN_08BIT, 0x80, 0xE0}, /* ADI recommended setting */
+ {0x03, CRL_REG_LEN_08BIT, 0x86, 0xE0}, /* CP-Insert_AV_Code */
+ {0x7C, CRL_REG_LEN_08BIT, 0x00, 0x44}, /* ADI recommended setting */
+
+ {0x8B, CRL_REG_LEN_08BIT, 0x43, 0x44}, /* 1080P shift left 44 pixel */
+ {0x8C, CRL_REG_LEN_08BIT, 0xD4, 0x44}, /* 1080P shift left 44 pixel */
+ {0x8B, CRL_REG_LEN_08BIT, 0x4F, 0x44}, /* 1080P shift left 44 pixel */
+ {0x8D, CRL_REG_LEN_08BIT, 0xD4, 0x44}, /* 1080P shift left 44 pixel */
+
+ {0x0C, CRL_REG_LEN_08BIT, 0xE0, 0xE0}, /* Enable LLC_DLL & Double LLC Timing */
+ {0x0E, CRL_REG_LEN_08BIT, 0xFF, 0xE0}, /* LLC/PIX/AUD/SPI PINS TRISTATED */
+ {0x10, CRL_REG_LEN_08BIT, 0xA0, 0xE0}, /* Enable 4-lane CSI Tx & Pixel Port */
+ {0x1C, CRL_REG_LEN_08BIT, 0x3A, 0xE0}, /* ADI recommended setting */
+};
+
+static struct crl_register_write_rep adv7481_mode_720p[] = {
+ {0x04, CRL_REG_LEN_08BIT, 0x00, 0xE0}, /* YCrCb output */
+ {0x05, CRL_REG_LEN_08BIT, 0x53, 0xE0}, /* Select Resolution 720P */
+ {0x12, CRL_REG_LEN_08BIT, 0xF2, 0xE0}, /* CSC Depends on ip Packets - SDR422 set */
+ {0x17, CRL_REG_LEN_08BIT, 0x80, 0xE0}, /* ADI recommended setting */
+ {0x03, CRL_REG_LEN_08BIT, 0x86, 0xE0}, /* CP-Insert_AV_Code */
+ {0x7C, CRL_REG_LEN_08BIT, 0x00, 0x44}, /* ADI recommended setting */
+
+ {0x8B, CRL_REG_LEN_08BIT, 0x43, 0x44}, /* 720P shift left 40 pixel */
+ {0x8C, CRL_REG_LEN_08BIT, 0xD8, 0x44}, /* 720P shift left 40 pixel */
+ {0x8B, CRL_REG_LEN_08BIT, 0x4F, 0x44}, /* 720P shift left 40 pixel */
+ {0x8D, CRL_REG_LEN_08BIT, 0xD8, 0x44}, /* 720P shift left 40 pixel */
+
+ {0x0C, CRL_REG_LEN_08BIT, 0xE0, 0xE0}, /* Enable LLC_DLL & Double LLC Timing */
+ {0x0E, CRL_REG_LEN_08BIT, 0xFF, 0xE0}, /* LLC/PIX/AUD/SPI PINS TRISTATED */
+ {0x10, CRL_REG_LEN_08BIT, 0xA0, 0xE0}, /* Enable 4-lane CSI Tx & Pixel Port */
+ {0x1C, CRL_REG_LEN_08BIT, 0x3A, 0xE0}, /* ADI recommended setting */
+};
+
+static struct crl_register_write_rep adv7481_mode_VGA[] = {
+ {0x04, CRL_REG_LEN_08BIT, 0x00, 0xE0}, /* YCrCb output */
+ {0x05, CRL_REG_LEN_08BIT, 0x88, 0xE0}, /* Select Resolution VGA */
+ {0x12, CRL_REG_LEN_08BIT, 0xF2, 0xE0}, /* CSC Depends on ip Packets - SDR422 set */
+ {0x17, CRL_REG_LEN_08BIT, 0x80, 0xE0}, /* ADI recommended setting */
+ {0x03, CRL_REG_LEN_08BIT, 0x86, 0xE0}, /* CP-Insert_AV_Code */
+ {0x7C, CRL_REG_LEN_08BIT, 0x00, 0x44}, /* ADI recommended setting */
+
+ {0x0C, CRL_REG_LEN_08BIT, 0xE0, 0xE0}, /* Enable LLC_DLL & Double LLC Timing */
+ {0x0E, CRL_REG_LEN_08BIT, 0xFF, 0xE0}, /* LLC/PIX/AUD/SPI PINS TRISTATED */
+ {0x10, CRL_REG_LEN_08BIT, 0xA0, 0xE0}, /* Enable 4-lane CSI Tx & Pixel Port */
+ {0x1C, CRL_REG_LEN_08BIT, 0x3A, 0xE0}, /* ADI recommended setting */
+};
+
+static struct crl_register_write_rep adv7481_mode_1080i[] = {
+ {0x04, CRL_REG_LEN_08BIT, 0x00, 0xE0}, /* YCrCb output */
+ {0x05, CRL_REG_LEN_08BIT, 0x54, 0xE0}, /* Select Resolution 1080i*/
+ {0x12, CRL_REG_LEN_08BIT, 0xF2, 0xE0}, /* CSC Depends on ip Packets - SDR422 set */
+ {0x17, CRL_REG_LEN_08BIT, 0x80, 0xE0}, /* ADI recommended setting */
+ {0x03, CRL_REG_LEN_08BIT, 0x86, 0xE0}, /* CP-Insert_AV_Code */
+ {0x7C, CRL_REG_LEN_08BIT, 0x00, 0x44}, /* ADI recommended setting */
+
+ {0x8B, CRL_REG_LEN_08BIT, 0x43, 0x44}, /* 1080i shift left 44 pixel */
+ {0x8C, CRL_REG_LEN_08BIT, 0xD4, 0x44}, /* 1080i shift left 44 pixel */
+ {0x8B, CRL_REG_LEN_08BIT, 0x4F, 0x44}, /* 1080i shift left 44 pixel */
+ {0x8D, CRL_REG_LEN_08BIT, 0xD4, 0x44}, /* 1080i shift left 44 pixel */
+
+ {0x0C, CRL_REG_LEN_08BIT, 0xE0, 0xE0}, /* Enable LLC_DLL & Double LLC Timing */
+ {0x0E, CRL_REG_LEN_08BIT, 0xFF, 0xE0}, /* LLC/PIX/AUD/SPI PINS TRISTATED */
+ {0x10, CRL_REG_LEN_08BIT, 0xA0, 0xE0}, /* Enable 4-lane CSI Tx & Pixel Port */
+ {0x1C, CRL_REG_LEN_08BIT, 0x3A, 0xE0}, /* ADI recommended setting */
+};
+
+static struct crl_register_write_rep adv7481_mode_480i[] = {
+ {0x04, CRL_REG_LEN_08BIT, 0x00, 0xE0}, /* YCrCb output */
+ {0x05, CRL_REG_LEN_08BIT, 0x40, 0xE0}, /* Select Resolution 480i */
+ {0x12, CRL_REG_LEN_08BIT, 0xF2, 0xE0}, /* CSC Depends on ip Packets - SDR422 set */
+ {0x17, CRL_REG_LEN_08BIT, 0x80, 0xE0}, /* ADI recommended setting */
+ {0x03, CRL_REG_LEN_08BIT, 0x86, 0xE0}, /* CP-Insert_AV_Code */
+ {0x7C, CRL_REG_LEN_08BIT, 0x00, 0x44}, /* ADI recommended setting */
+
+ {0x0C, CRL_REG_LEN_08BIT, 0xE0, 0xE0}, /* Enable LLC_DLL & Double LLC Timing */
+ {0x0E, CRL_REG_LEN_08BIT, 0xFF, 0xE0}, /* LLC/PIX/AUD/SPI PINS TRISTATED */
+ {0x10, CRL_REG_LEN_08BIT, 0xA0, 0xE0}, /* Enable 4-lane CSI Tx & Pixel Port */
+ {0x1C, CRL_REG_LEN_08BIT, 0x3A, 0xE0}, /* ADI recommended setting */
+};
+
+static struct crl_register_write_rep adv7481_mode_576p[] = {
+ {0x04, CRL_REG_LEN_08BIT, 0x00, 0xE0}, /* YCrCb output */
+ {0x05, CRL_REG_LEN_08BIT, 0x4B, 0xE0}, /* Select Resolution 576p*/
+ {0x12, CRL_REG_LEN_08BIT, 0xF2, 0xE0}, /* CSC Depends on ip Packets - SDR422 set */
+ {0x17, CRL_REG_LEN_08BIT, 0x80, 0xE0}, /* ADI recommended setting */
+ {0x03, CRL_REG_LEN_08BIT, 0x86, 0xE0}, /* CP-Insert_AV_Code */
+ {0x7C, CRL_REG_LEN_08BIT, 0x00, 0x44}, /* ADI recommended setting */
+
+ {0x0C, CRL_REG_LEN_08BIT, 0xE0, 0xE0}, /* Enable LLC_DLL & Double LLC Timing */
+ {0x0E, CRL_REG_LEN_08BIT, 0xFF, 0xE0}, /* LLC/PIX/AUD/SPI PINS TRISTATED */
+ {0x10, CRL_REG_LEN_08BIT, 0xA0, 0xE0}, /* Enable 4-lane CSI Tx & Pixel Port */
+ {0x1C, CRL_REG_LEN_08BIT, 0x3A, 0xE0}, /* ADI recommended setting */
+};
+
+static struct crl_register_write_rep adv7481_mode_576i[] = {
+ {0x04, CRL_REG_LEN_08BIT, 0x00, 0xE0}, /* YCrCb output */
+ {0x05, CRL_REG_LEN_08BIT, 0x41, 0xE0}, /* Select Resolution 576i*/
+ {0x12, CRL_REG_LEN_08BIT, 0xF2, 0xE0}, /* CSC Depends on ip Packets - SDR422 set */
+ {0x17, CRL_REG_LEN_08BIT, 0x80, 0xE0}, /* ADI recommended setting */
+ {0x03, CRL_REG_LEN_08BIT, 0x86, 0xE0}, /* CP-Insert_AV_Code */
+ {0x7C, CRL_REG_LEN_08BIT, 0x00, 0x44}, /* ADI recommended setting */
+
+ {0x0C, CRL_REG_LEN_08BIT, 0xE0, 0xE0}, /* Enable LLC_DLL & Double LLC Timing */
+ {0x0E, CRL_REG_LEN_08BIT, 0xFF, 0xE0}, /* LLC/PIX/AUD/SPI PINS TRISTATED */
+ {0x10, CRL_REG_LEN_08BIT, 0xA0, 0xE0}, /* Enable 4-lane CSI Tx & Pixel Port */
+ {0x1C, CRL_REG_LEN_08BIT, 0x3A, 0xE0}, /* ADI recommended setting */
+};
+
+static struct crl_register_write_rep adv7481_streamon_regs[] = {
+ {0x00, CRL_REG_LEN_DELAY, 0x02, 0x00},
+ {0x00, CRL_REG_LEN_08BIT, 0x24, 0x94}, /* Power-up CSI-TX */
+ {0x00, CRL_REG_LEN_DELAY, 0x01, 0x00},
+ {0xC1, CRL_REG_LEN_08BIT, 0x2B, 0x94}, /* ADI recommended setting */
+ {0x00, CRL_REG_LEN_DELAY, 0x01, 0x00},
+ {0x31, CRL_REG_LEN_08BIT, 0x80, 0x94}, /* ADI recommended setting */
+};
+
+static struct crl_register_write_rep adv7481_streamoff_regs[] = {
+ {0x31, CRL_REG_LEN_08BIT, 0x82, 0x94}, /* ADI Recommended Write */
+ {0x1E, CRL_REG_LEN_08BIT, 0x00, 0x94}, /* Reset the clock Lane */
+ {0x00, CRL_REG_LEN_08BIT, 0xA4, 0x94},
+ {0xDA, CRL_REG_LEN_08BIT, 0x00, 0x94}, /* i2c_mipi_pll_en - 1'b0 Disable MIPI PLL */
+ {0xC1, CRL_REG_LEN_08BIT, 0x3B, 0x94},
+};
+
+static struct crl_sensor_detect_config adv7481_sensor_detect_regset[] = {
+ {
+ .reg = { 0x0019, CRL_REG_LEN_08BIT, 0x000000ff },
+ .width = 5,
+ },
+ {
+ .reg = { 0x0016, CRL_REG_LEN_16BIT, 0x0000ffff },
+ .width = 7,
+ },
+};
+
+static struct crl_pll_configuration adv7481_pll_configurations[] = {
+ {
+ .input_clk = 24000000,
+ .op_sys_clk = 400000000,
+ .bitsperpixel = 16,
+ .pixel_rate_csi = 800000000,
+ .pixel_rate_pa = 800000000,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ .pll_regs_items = 0,
+ .pll_regs = NULL,
+ },
+
+};
+
+static struct crl_subdev_rect_rep adv7481_1080p_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_720p_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1280,
+ .out_rect.height = 720,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_VGA_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 640,
+ .out_rect.height = 480,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_1080i_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 540,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_480i_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 720,
+ .out_rect.height = 240,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_576p_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 720,
+ .out_rect.height = 576,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_576i_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 720,
+ .out_rect.height = 288,
+ },
+};
+static struct crl_mode_rep adv7481_modes[] = {
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_1080p_rects),
+ .sd_rects = adv7481_1080p_rects,
+ .binn_hor = 1,
+ .binn_vert = 1,
+ .scale_m = 1,
+ .width = 1920,
+ .height = 1080,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ .mode_regs_items = ARRAY_SIZE(adv7481_mode_1080p),
+ .mode_regs = adv7481_mode_1080p,
+ },
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_720p_rects),
+ .sd_rects = adv7481_720p_rects,
+ .binn_hor = 1,
+ .binn_vert = 1,
+ .scale_m = 1,
+ .width = 1280,
+ .height = 720,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ .mode_regs_items = ARRAY_SIZE(adv7481_mode_720p),
+ .mode_regs = adv7481_mode_720p,
+ },
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_VGA_rects),
+ .sd_rects = adv7481_VGA_rects,
+ .binn_hor = 3,
+ .binn_vert = 2,
+ .scale_m = 1,
+ .width = 640,
+ .height = 480,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ .mode_regs_items = ARRAY_SIZE(adv7481_mode_VGA),
+ .mode_regs = adv7481_mode_VGA,
+ },
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_1080i_rects),
+ .sd_rects = adv7481_1080i_rects,
+ .binn_hor = 1,
+ .binn_vert = 2,
+ .scale_m = 1,
+ .width = 1920,
+ .height = 540,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ .mode_regs_items = ARRAY_SIZE(adv7481_mode_1080i),
+ .mode_regs = adv7481_mode_1080i,
+ },
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_480i_rects),
+ .sd_rects = adv7481_480i_rects,
+ .binn_hor = 2,
+ .binn_vert = 4,
+ .scale_m = 1,
+ .width = 720,
+ .height = 240,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ .mode_regs_items = ARRAY_SIZE(adv7481_mode_480i),
+ .mode_regs = adv7481_mode_480i,
+ },
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_576p_rects),
+ .sd_rects = adv7481_576p_rects,
+ .binn_hor = 2,
+ .binn_vert = 1,
+ .scale_m = 1,
+ .width = 720,
+ .height = 576,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ .mode_regs_items = ARRAY_SIZE(adv7481_mode_576p),
+ .mode_regs = adv7481_mode_576p,
+ },
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_576i_rects),
+ .sd_rects = adv7481_576i_rects,
+ .binn_hor = 2,
+ .binn_vert = 3,
+ .scale_m = 1,
+ .width = 720,
+ .height = 288,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ .mode_regs_items = 0,
+ .mode_regs = adv7481_mode_576i,
+ },
+};
+
+static struct crl_sensor_subdev_config adv7481_sensor_subdevs[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .name = "adv7481 binner",
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .name = "adv7481 pixel array",
+ },
+};
+
+static struct crl_sensor_limits adv7481_sensor_limits = {
+ .x_addr_min = 0,
+ .y_addr_min = 0,
+ .x_addr_max = 1920,
+ .y_addr_max = 1080,
+ .min_frame_length_lines = 160,
+ .max_frame_length_lines = 65535,
+ .min_line_length_pixels = 6024,
+ .max_line_length_pixels = 32752,
+ .scaler_m_min = 1,
+ .scaler_m_max = 1,
+ .scaler_n_min = 1,
+ .scaler_n_max = 1,
+ .min_even_inc = 1,
+ .max_even_inc = 1,
+ .min_odd_inc = 1,
+ .max_odd_inc = 1,
+};
+
+static struct crl_csi_data_fmt adv7481_crl_csi_data_fmt[] = {
+ {
+ .code = ICI_FORMAT_UYVY,
+ .pixel_order = CRL_PIXEL_ORDER_GRBG,
+ .bits_per_pixel = 16,
+ .regs_items = ARRAY_SIZE(adv7481_mode_1080p),
+ .regs = adv7481_mode_1080p, /* default yuv422 format */
+ },
+};
+
+static struct crl_ctrl_data adv7481_ctrls[] = {
+ {
+ .sd_type = CRL_SUBDEV_TYPE_BINNER,
+ .op_type = CRL_CTRL_SET_OP,
+ .context = SENSOR_IDLE,
+ .ctrl_id = ICI_EXT_SD_PARAM_ID_LINK_FREQ,
+ .name = "CTRL_ID_LINK_FREQ",
+ .type = CRL_CTRL_TYPE_MENU_INT,
+ .data.int_menu.def = 0,
+ .data.int_menu.max = ARRAY_SIZE(adv7481_pll_configurations) - 1,
+ .flags = 0,
+ .impact = CRL_IMPACTS_NO_IMPACT,
+ .regs_items = 0,
+ .regs = 0,
+ .dep_items = 0,
+ .dep_ctrls = 0,
+ },
+ {
+ .sd_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .op_type = CRL_CTRL_GET_OP,
+ .context = SENSOR_POWERED_ON,
+ .ctrl_id = ICI_EXT_SD_PARAM_ID_PIXEL_RATE,
+ .name = "CTRL_ID_PIXEL_RATE_PA",
+ .type = CRL_CTRL_TYPE_INTEGER,
+ .data.std_data.min = 0,
+ .data.std_data.max = 0,
+ .data.std_data.step = 1,
+ .data.std_data.def = 0,
+ .flags = 0,
+ .impact = CRL_IMPACTS_NO_IMPACT,
+ .regs_items = 0,
+ .regs = 0,
+ .dep_items = 0,
+ .dep_ctrls = 0,
+ },
+ {
+ .sd_type = CRL_SUBDEV_TYPE_BINNER,
+ .op_type = CRL_CTRL_GET_OP,
+ .context = SENSOR_POWERED_ON,
+ .ctrl_id = ICI_EXT_SD_PARAM_ID_PIXEL_RATE,
+ .name = "CTRL_ID_PIXEL_RATE_CSI",
+ .type = CRL_CTRL_TYPE_INTEGER,
+ .data.std_data.min = 0,
+ .data.std_data.max = 0,
+ .data.std_data.step = 1,
+ .data.std_data.def = 0,
+ .flags = 0,
+ .impact = CRL_IMPACTS_NO_IMPACT,
+ .regs_items = 0,
+ .regs = 0,
+ .dep_items = 0,
+ .dep_ctrls = 0,
+ },
+};
+
+/* Power items, they are enabled in the order they are listed here */
+static struct crl_power_seq_entity adv7481_power_items[] = {
+ {
+ .type = CRL_POWER_ETY_CLK_FRAMEWORK,
+ .val = 24000000,
+ },
+ {
+ .type = CRL_POWER_ETY_GPIO_FROM_PDATA,
+ .val = 1,
+ },
+};
+
+static struct crl_sensor_configuration adv7481_crl_configuration = {
+
+ .power_items = ARRAY_SIZE(adv7481_power_items),
+ .power_entities = adv7481_power_items,
+
+ .powerup_regs_items = ARRAY_SIZE(adv7481_powerup_regset),
+ .powerup_regs = adv7481_powerup_regset,
+
+ .poweroff_regs_items = ARRAY_SIZE(adv7481_streamoff_regs),
+ .poweroff_regs = adv7481_streamoff_regs,
+
+ .id_reg_items = ARRAY_SIZE(adv7481_sensor_detect_regset),
+ .id_regs = adv7481_sensor_detect_regset,
+
+ .subdev_items = ARRAY_SIZE(adv7481_sensor_subdevs),
+ .subdevs = adv7481_sensor_subdevs,
+
+ .sensor_limits = &adv7481_sensor_limits,
+
+ .pll_config_items = ARRAY_SIZE(adv7481_pll_configurations),
+ .pll_configs = adv7481_pll_configurations,
+
+ .modes_items = ARRAY_SIZE(adv7481_modes),
+ .modes = adv7481_modes,
+
+ .streamon_regs_items = ARRAY_SIZE(adv7481_streamon_regs),
+ .streamon_regs = adv7481_streamon_regs,
+
+ .streamoff_regs_items = ARRAY_SIZE(adv7481_streamoff_regs),
+ .streamoff_regs = adv7481_streamoff_regs,
+
+ .ctrl_items = ARRAY_SIZE(adv7481_ctrls),
+ .ctrl_bank = adv7481_ctrls,
+
+ .csi_fmts_items = ARRAY_SIZE(adv7481_crl_csi_data_fmt),
+ .csi_fmts = adv7481_crl_csi_data_fmt,
+};
+
+#endif /* __CRLMODULE_ADV7481_CONFIGURATION_H_ */
diff --git a/drivers/media/i2c/crlmodule-lite/crl_adv7481_cvbs_configuration.h b/drivers/media/i2c/crlmodule-lite/crl_adv7481_cvbs_configuration.h
new file mode 100644
index 000000000000..5ea1f7c01f19
--- /dev/null
+++ b/drivers/media/i2c/crlmodule-lite/crl_adv7481_cvbs_configuration.h
@@ -0,0 +1,264 @@
+/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) */
+/*
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#ifndef __CRLMODULE_ADV7481_CVBS_CONFIGURATION_H_
+#define __CRLMODULE_ADV7481_CVBS_CONFIGURATION_H_
+
+#include "crlmodule-sensor-ds.h"
+
+static struct crl_register_write_rep adv7481_cvbs_powerup_regset[] = {
+ {0x0E, CRL_REG_LEN_08BIT, 0xFF, 0xE0}, //LLC/PIX/AUD/SPI PINS TRISTATED
+ {0x0F, CRL_REG_LEN_08BIT, 0x00, 0xF2}, //Exit Power Down Mode
+ {0x52, CRL_REG_LEN_08BIT, 0xCD, 0xF2}, //ADI Required Write
+ {0x00, CRL_REG_LEN_08BIT, 0x00, 0xF2}, //INSEL = CVBS in on Ain 1
+ {0x0E, CRL_REG_LEN_08BIT, 0x80, 0xF2}, //ADI Required Write
+ {0x9C, CRL_REG_LEN_08BIT, 0x00, 0xF2}, //ADI Required Write
+ {0x9C, CRL_REG_LEN_08BIT, 0xFF, 0xF2}, //ADI Required Write
+ {0x0E, CRL_REG_LEN_08BIT, 0x00, 0xF2}, //ADI Required Write
+ {0x80, CRL_REG_LEN_08BIT, 0x51, 0xF2}, //ADI Required Write
+ {0x81, CRL_REG_LEN_08BIT, 0x51, 0xF2}, //ADI Required Write
+ {0x82, CRL_REG_LEN_08BIT, 0x68, 0xF2}, //ADI Required Write
+ {0x03, CRL_REG_LEN_08BIT, 0x42, 0xF2}, //Tri-S Output Drivers, PwrDwn 656 pads
+ {0x04, CRL_REG_LEN_08BIT, 0x07, 0xF2}, //Power-up INTRQ pad, & Enable SFL
+ {0x13, CRL_REG_LEN_08BIT, 0x00, 0xF2}, //ADI Required Write
+ {0x17, CRL_REG_LEN_08BIT, 0x41, 0xF2}, //Select SH1
+ {0x31, CRL_REG_LEN_08BIT, 0x12, 0xF2}, //ADI Required Write
+ {0x10, CRL_REG_LEN_08BIT, 0xC0, 0xE0}, //Enable 1-Lane MIPI Tx, enable pixel output and route SD through Pixel port
+ {0x00, CRL_REG_LEN_08BIT, 0x81, 0x90}, //Enable 1-lane MIPI
+ {0x00, CRL_REG_LEN_08BIT, 0xA1, 0x90}, //Set Auto DPHY Timing
+ {0xF0, CRL_REG_LEN_08BIT, 0x00, 0x94}, //ADI Required Write
+ {0xD2, CRL_REG_LEN_08BIT, 0x40, 0x90}, //ADI Required Write
+ {0xC4, CRL_REG_LEN_08BIT, 0x0A, 0x90}, //ADI Required Write
+ {0x71, CRL_REG_LEN_08BIT, 0x33, 0x90}, //ADI Required Write
+ {0x72, CRL_REG_LEN_08BIT, 0x11, 0x90}, //ADI Required Write
+ {0xF0, CRL_REG_LEN_08BIT, 0x00, 0x90}, //i2c_dphy_pwdn - 1'b0
+ {0x31, CRL_REG_LEN_08BIT, 0x82, 0x90}, //ADI Required Write
+ {0x1E, CRL_REG_LEN_08BIT, 0xC0, 0x90}, //ADI Required Write
+};
+
+
+static struct crl_register_write_rep adv7481_cvbs_streamon_regs[] = {
+ {0xC1, CRL_REG_LEN_08BIT, 0x2B, 0x90}, //ADI Required Write
+ {0x00, CRL_REG_LEN_DELAY, 0x01, 0x00},
+ {0xDA, CRL_REG_LEN_08BIT, 0x01, 0x90}, //i2c_mipi_pll_en - 1'b1
+ {0x00, CRL_REG_LEN_DELAY, 0x02, 0x00},
+ {0x00, CRL_REG_LEN_08BIT, 0x21, 0x90}, //Power-up CSI-TX 21
+ {0x00, CRL_REG_LEN_DELAY, 0x01, 0x00},
+ {0x31, CRL_REG_LEN_08BIT, 0x80, 0x90}, //ADI Required Write
+};
+
+static struct crl_register_write_rep adv7481_cvbs_streamoff_regs[] = {
+ {0x31, CRL_REG_LEN_08BIT, 0x82, 0x90}, /* ADI Recommended Write */
+ {0x1E, CRL_REG_LEN_08BIT, 0x00, 0x90}, /* Reset the clock Lane */
+ {0x00, CRL_REG_LEN_08BIT, 0x81, 0x90},
+ {0xDA, CRL_REG_LEN_08BIT, 0x00, 0x90}, /* i2c_mipi_pll_en - 1'b0 Disable MIPI PLL */
+ {0xC1, CRL_REG_LEN_08BIT, 0x3B, 0x90},
+};
+
+
+static struct crl_pll_configuration adv7481_cvbs_pll_configurations[] = {
+ {
+ .input_clk = 286363636,
+ .op_sys_clk = 216000000,
+ .bitsperpixel = 16,
+ .pixel_rate_csi = 130000000,
+ .pixel_rate_pa = 130000000,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ .pll_regs_items = 0,
+ .pll_regs = NULL,
+ },
+ {
+ .input_clk = 24000000,
+ .op_sys_clk = 130000000,
+ .bitsperpixel = 16,
+ .pixel_rate_csi = 130000000,
+ .pixel_rate_pa = 130000000,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ .pll_regs_items = 0,
+ .pll_regs = NULL,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_cvbs_ntsc_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 720,
+ .in_rect.height = 240,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 720,
+ .out_rect.height = 240,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 720,
+ .in_rect.height = 240,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 720,
+ .out_rect.height = 240,
+ },
+};
+
+static struct crl_mode_rep adv7481_cvbs_modes[] = {
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_cvbs_ntsc_rects),
+ .sd_rects = adv7481_cvbs_ntsc_rects,
+ .binn_hor = 1,
+ .binn_vert = 1,
+ .scale_m = 1,
+ .width = 720,
+ .height = 240,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ .mode_regs_items = 0,
+ .mode_regs = 0,
+ },
+};
+
+static struct crl_sensor_subdev_config adv7481_cvbs_sensor_subdevs[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .name = "adv7481 cvbs binner",
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .name = "adv7481 cvbs pixel array",
+ },
+};
+
+static struct crl_sensor_limits adv7481_cvbs_sensor_limits = {
+ .x_addr_min = 0,
+ .y_addr_min = 0,
+ .x_addr_max = 720,
+ .y_addr_max = 240,
+ .min_frame_length_lines = 160,
+ .max_frame_length_lines = 65535,
+ .min_line_length_pixels = 6024,
+ .max_line_length_pixels = 32752,
+ .scaler_m_min = 1,
+ .scaler_m_max = 1,
+ .scaler_n_min = 1,
+ .scaler_n_max = 1,
+ .min_even_inc = 1,
+ .max_even_inc = 1,
+ .min_odd_inc = 1,
+ .max_odd_inc = 1,
+};
+
+static struct crl_csi_data_fmt adv7481_cvbs_crl_csi_data_fmt[] = {
+ {
+ .code = ICI_FORMAT_UYVY,
+ .pixel_order = CRL_PIXEL_ORDER_GRBG,
+ .bits_per_pixel = 16,
+ .regs_items = 0,
+ .regs = NULL,
+ },
+};
+
+static struct crl_ctrl_data adv7481_cvbs_ctrls[] = {
+ {
+ .sd_type = CRL_SUBDEV_TYPE_BINNER,
+ .op_type = CRL_CTRL_SET_OP,
+ .context = SENSOR_IDLE,
+ .ctrl_id = ICI_EXT_SD_PARAM_ID_LINK_FREQ,
+ .name = "CTRL_ID_LINK_FREQ",
+ .type = CRL_CTRL_TYPE_MENU_INT,
+ .data.int_menu.def = 0,
+ .data.int_menu.max = ARRAY_SIZE(adv7481_cvbs_pll_configurations) - 1,
+ .flags = 0,
+ .impact = CRL_IMPACTS_NO_IMPACT,
+ .regs_items = 0,
+ .regs = 0,
+ .dep_items = 0,
+ .dep_ctrls = 0,
+ },
+ {
+ .sd_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .op_type = CRL_CTRL_GET_OP,
+ .context = SENSOR_POWERED_ON,
+ .ctrl_id = ICI_EXT_SD_PARAM_ID_PIXEL_RATE,
+ .name = "CTRL_ID_PIXEL_RATE_PA",
+ .type = CRL_CTRL_TYPE_INTEGER,
+ .data.std_data.min = 0,
+ .data.std_data.max = 0,
+ .data.std_data.step = 1,
+ .data.std_data.def = 0,
+ .flags = 0,
+ .impact = CRL_IMPACTS_NO_IMPACT,
+ .regs_items = 0,
+ .regs = 0,
+ .dep_items = 0,
+ .dep_ctrls = 0,
+ },
+ {
+ .sd_type = CRL_SUBDEV_TYPE_BINNER,
+ .op_type = CRL_CTRL_GET_OP,
+ .context = SENSOR_POWERED_ON,
+ .ctrl_id = ICI_EXT_SD_PARAM_ID_PIXEL_RATE,
+ .name = "CTRL_ID_PIXEL_RATE_CSI",
+ .type = CRL_CTRL_TYPE_INTEGER,
+ .data.std_data.min = 0,
+ .data.std_data.max = 0,
+ .data.std_data.step = 1,
+ .data.std_data.def = 0,
+ .flags = 0,
+ .impact = CRL_IMPACTS_NO_IMPACT,
+ .regs_items = 0,
+ .regs = 0,
+ .dep_items = 0,
+ .dep_ctrls = 0,
+ },
+};
+
+static struct crl_sensor_configuration adv7481_cvbs_crl_configuration = {
+ .sensor_init = NULL,
+ .sensor_cleanup = NULL,
+
+ .onetime_init_regs_items = 0, //one time initialization is done by HDMI part
+ .onetime_init_regs = NULL,
+
+ .powerup_regs_items = ARRAY_SIZE(adv7481_cvbs_powerup_regset),
+ .powerup_regs = adv7481_cvbs_powerup_regset,
+
+ .poweroff_regs_items = ARRAY_SIZE(adv7481_cvbs_streamoff_regs),
+ .poweroff_regs = adv7481_cvbs_streamoff_regs,
+
+ .id_reg_items = 0,
+ .id_regs = NULL,
+
+ .subdev_items = ARRAY_SIZE(adv7481_cvbs_sensor_subdevs),
+ .subdevs = adv7481_cvbs_sensor_subdevs,
+
+ .sensor_limits = &adv7481_cvbs_sensor_limits,
+
+ .pll_config_items = ARRAY_SIZE(adv7481_cvbs_pll_configurations),
+ .pll_configs = adv7481_cvbs_pll_configurations,
+
+ .modes_items = ARRAY_SIZE(adv7481_cvbs_modes),
+ .modes = adv7481_cvbs_modes,
+
+ .streamon_regs_items = ARRAY_SIZE(adv7481_cvbs_streamon_regs),
+ .streamon_regs = adv7481_cvbs_streamon_regs,
+
+ .streamoff_regs_items = ARRAY_SIZE(adv7481_cvbs_streamoff_regs),
+ .streamoff_regs = adv7481_cvbs_streamoff_regs,
+
+ .ctrl_items = ARRAY_SIZE(adv7481_cvbs_ctrls),
+ .ctrl_bank = adv7481_cvbs_ctrls,
+
+ .csi_fmts_items = ARRAY_SIZE(adv7481_cvbs_crl_csi_data_fmt),
+ .csi_fmts = adv7481_cvbs_crl_csi_data_fmt,
+
+ .addr_len = CRL_ADDR_7BIT,
+};
+
+#endif /* __CRLMODULE_ADV7481_CVBS_CONFIGURATION_H_ */
diff --git a/drivers/media/i2c/crlmodule-lite/crl_adv7481_eval_configuration.h b/drivers/media/i2c/crlmodule-lite/crl_adv7481_eval_configuration.h
new file mode 100644
index 000000000000..575d2db42edc
--- /dev/null
+++ b/drivers/media/i2c/crlmodule-lite/crl_adv7481_eval_configuration.h
@@ -0,0 +1,531 @@
+/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) */
+/*
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#ifndef __CRLMODULE_ADV7481_EVAL_CONFIGURATION_H_
+#define __CRLMODULE_ADV7481_EVAL_CONFIGURATION_H_
+
+#include "crlmodule-sensor-ds.h"
+
+
+struct crl_ctrl_data_pair ctrl_data_lanes[] = {
+ {
+ .ctrl_id = ICI_EXT_SD_PARAM_ID_MIPI_LANES,
+ .data = 4,
+ },
+ {
+ .ctrl_id = ICI_EXT_SD_PARAM_ID_MIPI_LANES,
+ .data = 2,
+ },
+};
+static struct crl_pll_configuration adv7481_eval_pll_configurations[] = {
+ {
+ .input_clk = 24000000,
+ .op_sys_clk = 400000000,
+ .bitsperpixel = 16,
+ .pixel_rate_csi = 800000000,
+ .pixel_rate_pa = 800000000,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ .pll_regs_items = 0,
+ .pll_regs = NULL,
+ },
+ {
+ .input_clk = 24000000,
+ .op_sys_clk = 400000000,
+ .bitsperpixel = 24,
+ .pixel_rate_csi = 800000000,
+ .pixel_rate_pa = 800000000,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ .pll_regs_items = 0,
+ .pll_regs = NULL,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_eval_1080p_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_eval_720p_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1280,
+ .out_rect.height = 720,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_eval_VGA_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 640,
+ .out_rect.height = 480,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_eval_1080i_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 540,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_eval_480i_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 720,
+ .out_rect.height = 240,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_eval_576p_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 720,
+ .out_rect.height = 576,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_eval_576i_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 720,
+ .out_rect.height = 288,
+ },
+};
+static struct crl_mode_rep adv7481_eval_modes[] = {
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_eval_1080p_rects),
+ .sd_rects = adv7481_eval_1080p_rects,
+ .binn_hor = 1,
+ .binn_vert = 1,
+ .scale_m = 1,
+ .width = 1920,
+ .height = 1080,
+ .comp_items = 1,
+ .ctrl_data = &ctrl_data_lanes[0],
+ .mode_regs_items = 0,
+ .mode_regs = NULL,
+ },
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_eval_720p_rects),
+ .sd_rects = adv7481_eval_720p_rects,
+ .binn_hor = 1,
+ .binn_vert = 1,
+ .scale_m = 1,
+ .width = 1280,
+ .height = 720,
+ .comp_items = 1,
+ .ctrl_data = &ctrl_data_lanes[0],
+ .mode_regs_items = 0,
+ .mode_regs = NULL,
+ },
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_eval_VGA_rects),
+ .sd_rects = adv7481_eval_VGA_rects,
+ .binn_hor = 3,
+ .binn_vert = 2,
+ .scale_m = 1,
+ .width = 640,
+ .height = 480,
+ .comp_items = 1,
+ .ctrl_data = &ctrl_data_lanes[1],
+ .mode_regs_items = 0,
+ .mode_regs = NULL,
+ },
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_eval_1080i_rects),
+ .sd_rects = adv7481_eval_1080i_rects,
+ .binn_hor = 1,
+ .binn_vert = 2,
+ .scale_m = 1,
+ .width = 1920,
+ .height = 540,
+ .comp_items = 1,
+ .ctrl_data = &ctrl_data_lanes[1],
+ .mode_regs_items = 0,
+ .mode_regs = NULL,
+ },
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_eval_480i_rects),
+ .sd_rects = adv7481_eval_480i_rects,
+ .binn_hor = 2,
+ .binn_vert = 4,
+ .scale_m = 1,
+ .width = 720,
+ .height = 240,
+ .comp_items = 1,
+ .ctrl_data = &ctrl_data_lanes[1],
+ .mode_regs_items = 0,
+ .mode_regs = NULL,
+ },
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_eval_576p_rects),
+ .sd_rects = adv7481_eval_576p_rects,
+ .binn_hor = 2,
+ .binn_vert = 1,
+ .scale_m = 1,
+ .width = 720,
+ .height = 576,
+ .comp_items = 1,
+ .ctrl_data = &ctrl_data_lanes[1],
+ .mode_regs_items = 0,
+ .mode_regs = NULL,
+ },
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_eval_576i_rects),
+ .sd_rects = adv7481_eval_576i_rects,
+ .binn_hor = 2,
+ .binn_vert = 3,
+ .scale_m = 1,
+ .width = 720,
+ .height = 288,
+ .comp_items = 1,
+ .ctrl_data = &ctrl_data_lanes[1],
+ .mode_regs_items = 0,
+ .mode_regs = NULL,
+ },
+};
+
+static struct crl_sensor_subdev_config adv7481_eval_sensor_subdevs[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .name = "adv7481 binner",
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .name = "adv7481 pixel array",
+ },
+};
+
+static struct crl_sensor_subdev_config adv7481b_eval_sensor_subdevs[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .name = "adv7481b binner",
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .name = "adv7481b pixel array",
+ },
+};
+
+static struct crl_sensor_limits adv7481_eval_sensor_limits = {
+ .x_addr_min = 0,
+ .y_addr_min = 0,
+ .x_addr_max = 1920,
+ .y_addr_max = 1080,
+ .min_frame_length_lines = 160,
+ .max_frame_length_lines = 65535,
+ .min_line_length_pixels = 6024,
+ .max_line_length_pixels = 32752,
+ .scaler_m_min = 1,
+ .scaler_m_max = 1,
+ .scaler_n_min = 1,
+ .scaler_n_max = 1,
+ .min_even_inc = 1,
+ .max_even_inc = 1,
+ .min_odd_inc = 1,
+ .max_odd_inc = 1,
+};
+
+static struct crl_csi_data_fmt adv7481_eval_crl_csi_data_fmt[] = {
+ {
+ .code = ICI_FORMAT_YUYV,
+ .pixel_order = CRL_PIXEL_ORDER_GRBG,
+ .bits_per_pixel = 16,
+ .regs_items = 0,
+ .regs = NULL,
+ },
+ {
+ .code = ICI_FORMAT_UYVY,
+ .pixel_order = CRL_PIXEL_ORDER_GRBG,
+ .bits_per_pixel = 16,
+ .regs_items = 0,
+ .regs = NULL,
+ },
+ {
+ .code = ICI_FORMAT_RGB565,
+ .pixel_order = CRL_PIXEL_ORDER_GRBG,
+ .bits_per_pixel = 16,
+ .regs_items = 0,
+ .regs = NULL,
+ },
+ {
+ .code = ICI_FORMAT_RGB888,
+ .pixel_order = CRL_PIXEL_ORDER_GRBG,
+ .bits_per_pixel = 24,
+ .regs_items = 0,
+ .regs = NULL,
+ },
+};
+
+static struct crl_ctrl_data adv7481_eval_ctrls[] = {
+ {
+ .sd_type = CRL_SUBDEV_TYPE_BINNER,
+ .op_type = CRL_CTRL_SET_OP,
+ .context = SENSOR_IDLE,
+ .ctrl_id = ICI_EXT_SD_PARAM_ID_LINK_FREQ,
+ .name = "CTRL_ID_LINK_FREQ",
+ .type = CRL_CTRL_TYPE_MENU_INT,
+ .data.int_menu.def = 0,
+ .data.int_menu.max = ARRAY_SIZE(adv7481_eval_pll_configurations) - 1,
+ .flags = 0,
+ .impact = CRL_IMPACTS_NO_IMPACT,
+ .regs_items = 0,
+ .regs = 0,
+ .dep_items = 0,
+ .dep_ctrls = 0,
+ },
+ {
+ .sd_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .op_type = CRL_CTRL_GET_OP,
+ .context = SENSOR_POWERED_ON,
+ .ctrl_id = ICI_EXT_SD_PARAM_ID_PIXEL_RATE,
+ .name = "CTRL_ID_PIXEL_RATE_PA",
+ .type = CRL_CTRL_TYPE_INTEGER,
+ .data.std_data.min = 0,
+ .data.std_data.max = 0,
+ .data.std_data.step = 1,
+ .data.std_data.def = 0,
+ .flags = 0,
+ .impact = CRL_IMPACTS_NO_IMPACT,
+ .regs_items = 0,
+ .regs = 0,
+ .dep_items = 0,
+ .dep_ctrls = 0,
+ },
+ {
+ .sd_type = CRL_SUBDEV_TYPE_BINNER,
+ .op_type = CRL_CTRL_GET_OP,
+ .context = SENSOR_POWERED_ON,
+ .ctrl_id = ICI_EXT_SD_PARAM_ID_PIXEL_RATE,
+ .name = "CTRL_ID_PIXEL_RATE_CSI",
+ .type = CRL_CTRL_TYPE_INTEGER,
+ .data.std_data.min = 0,
+ .data.std_data.max = 0,
+ .data.std_data.step = 1,
+ .data.std_data.def = 0,
+ .flags = 0,
+ .impact = CRL_IMPACTS_NO_IMPACT,
+ .regs_items = 0,
+ .regs = 0,
+ .dep_items = 0,
+ .dep_ctrls = 0,
+ },
+ {
+ .sd_type = CRL_SUBDEV_TYPE_BINNER,
+ .op_type = CRL_CTRL_GET_OP,
+ .context = SENSOR_POWERED_ON,
+ .ctrl_id = ICI_EXT_SD_PARAM_ID_MIPI_LANES,
+ .name = "CTRL_ID_MIPI_LANES",
+ .type = CRL_CTRL_TYPE_CUSTOM,
+ .data.std_data.min = 2,
+ .data.std_data.max = 4,
+ .data.std_data.step = 2,
+ .data.std_data.def = 4,
+ .flags = 0,
+ .impact = CRL_IMPACTS_NO_IMPACT,
+ .regs_items = 0,
+ .regs = 0,
+ .dep_items = 0,
+ .dep_ctrls = 0,
+ .param.type = ICI_EXT_SD_PARAM_TYPE_INT32,
+ },
+};
+
+static struct crl_sensor_configuration adv7481_eval_crl_configuration = {
+
+ .powerup_regs_items = 0,
+ .powerup_regs = NULL,
+
+ .poweroff_regs_items = 0,
+ .poweroff_regs = NULL,
+
+ .id_reg_items = 0,
+ .id_regs = NULL,
+
+ .subdev_items = 0,
+ .subdevs = adv7481_eval_sensor_subdevs,
+
+ .sensor_limits = &adv7481_eval_sensor_limits,
+
+ .pll_config_items = ARRAY_SIZE(adv7481_eval_pll_configurations),
+ .pll_configs = adv7481_eval_pll_configurations,
+
+ .modes_items = ARRAY_SIZE(adv7481_eval_modes),
+ .modes = adv7481_eval_modes,
+
+ .streamon_regs_items = 0,
+ .streamon_regs = NULL,
+
+ .streamoff_regs_items = 0,
+ .streamoff_regs = NULL,
+
+ .ctrl_items = ARRAY_SIZE(adv7481_eval_ctrls),
+ .ctrl_bank = adv7481_eval_ctrls,
+
+ .csi_fmts_items = ARRAY_SIZE(adv7481_eval_crl_csi_data_fmt),
+ .csi_fmts = adv7481_eval_crl_csi_data_fmt,
+};
+
+static struct crl_sensor_configuration adv7481b_eval_crl_configuration = {
+
+ .powerup_regs_items = 0,
+ .powerup_regs = NULL,
+
+ .poweroff_regs_items = 0,
+ .poweroff_regs = NULL,
+
+ .id_reg_items = 0,
+ .id_regs = NULL,
+
+ .subdev_items = 0,
+ .subdevs = adv7481b_eval_sensor_subdevs,
+
+ .sensor_limits = &adv7481_eval_sensor_limits,
+
+ .pll_config_items = ARRAY_SIZE(adv7481_eval_pll_configurations),
+ .pll_configs = adv7481_eval_pll_configurations,
+
+ .modes_items = ARRAY_SIZE(adv7481_eval_modes),
+ .modes = adv7481_eval_modes,
+
+ .streamon_regs_items = 0,
+ .streamon_regs = NULL,
+
+ .streamoff_regs_items = 0,
+ .streamoff_regs = NULL,
+
+ .ctrl_items = ARRAY_SIZE(adv7481_eval_ctrls),
+ .ctrl_bank = adv7481_eval_ctrls,
+
+ .csi_fmts_items = ARRAY_SIZE(adv7481_eval_crl_csi_data_fmt),
+ .csi_fmts = adv7481_eval_crl_csi_data_fmt,
+};
+
+#endif /* __CRLMODULE_ADV7481_EVAL_CONFIGURATION_H_ */
diff --git a/drivers/media/i2c/crlmodule-lite/crl_adv7481_hdmi_configuration.c b/drivers/media/i2c/crlmodule-lite/crl_adv7481_hdmi_configuration.c
new file mode 100644
index 000000000000..80f668a462ea
--- /dev/null
+++ b/drivers/media/i2c/crlmodule-lite/crl_adv7481_hdmi_configuration.c
@@ -0,0 +1,624 @@
+// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
+/*
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#include <linux/version.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include "crlmodule.h"
+#include "crlmodule-regs.h"
+
+#define CREATE_ATTRIBUTE(attr) \
+ if (device_create_file(&client->dev, &attr) != 0) { \
+ dev_err(&client->dev, "ADV7481 couldn't register %s sysfs entry.\n", \
+ #attr); \
+ } \
+
+#define REMOVE_ATTRIBUTE(attr) \
+ device_remove_file(&client->dev, &attr);
+
+/* Size of the mondello KSV buffer in bytes */
+#define ADV7481_KSV_BUFFER_SIZE 0x80
+/* Size of a single KSV */
+#define ADV7481_KSV_SIZE 0x05
+/* Max number of devices (MAX_MONDELO_KSV_SIZE / HDCP_KSV_SIZE */
+#define ADV7481_MAX_DEVICES 0x19
+
+#define ADV7481_AKSV_UPDATE_A_ST 0x08
+#define ADV7481_CABLE_DET_A_ST 0x40
+#define ADV7481_V_LOCKED_A_ST 0x02
+#define ADV7481_DE_REGEN_A_ST 0x01
+
+#define ADV7481_GPIO 456
+
+/*
+ * Prevents executing another hot plug reset until current one will finish
+ */
+static unsigned int in_hot_plug_reset = 0;
+
+/*
+ * When hot plug reset is executed, HPA bit is deasserted for 2 seconds.
+ * This timer is used to assert HPA bit again after that time without blocking.
+ */
+static struct timer_list hot_plug_reset_timer;
+
+static struct workqueue_struct *irq_workqueue = NULL;
+static int hdmi_res_width;
+static int hdmi_res_height;
+static int hdmi_res_interlaced;
+
+static DEFINE_MUTEX(hot_plug_reset_lock);
+
+typedef struct {
+ struct work_struct work;
+ struct i2c_client *client;
+} irq_task_t;
+
+/* ADV7481 HDCP B-status register */
+struct adv7481_bstatus {
+ union {
+ __u8 bstatus[2];
+ struct {
+ __u8 device_count:7;
+ __u8 max_devs_exceeded:1;
+ __u8 depth:3;
+ __u8 max_cascade_exceeded:1;
+ __u8 hdmi_mode:1;
+ __u8 hdmi_reserved_2:1;
+ __u8 rsvd:2;
+ };
+ };
+};
+
+struct adv7481_dev_info {
+ struct adv7481_bstatus bstatus;
+ __u8 ksv[ADV7481_KSV_BUFFER_SIZE];
+};
+
+struct adv7481_bcaps {
+ union {
+ __u8 bcaps;
+ struct {
+ __u8 fast_reauth:1;
+ __u8 features:1;
+ __u8 reserved:2;
+ __u8 fast:1;
+ __u8 ksv_fifo_ready:1;
+ __u8 repeater:1;
+ __u8 hdmi_reserved:1;
+ };
+ };
+};
+
+static int adv_i2c_write(struct i2c_client *client, u16 i2c_addr, u16 reg, u8 val)
+{
+ struct ici_ext_subdev *subdev =
+ i2c_get_clientdata(client);
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+
+ return crlmodule_write_reg(sensor, i2c_addr, reg, 1, 0xFF, val);
+}
+
+static int adv_i2c_read(struct i2c_client *client, u16 i2c_addr, u16 reg, u32 *val)
+{
+ struct ici_ext_subdev *subdev =
+ i2c_get_clientdata(client);
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+ struct crl_register_read_rep read_reg;
+
+ read_reg.address = reg;
+ read_reg.len = CRL_REG_LEN_08BIT;
+ read_reg.dev_i2c_addr = i2c_addr;
+ return crlmodule_read_reg(sensor, read_reg, val);
+}
+
+/*
+ * Writes the HDCP BKSV list & status when the system acts
+ * as an HDCP 1.4 repeater
+ */
+static long adv_write_bksv(struct i2c_client *client,
+ struct adv7481_dev_info *dev_info)
+{
+ unsigned int k = 0;
+ int ret = 0;
+ u32 reg;
+ struct ici_ext_subdev *subdev =
+ i2c_get_clientdata(client);
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+
+ dev_dbg(&client->dev, "%s: Writing ADV7481 BKSV list.\n", __func__);
+
+ /* Clear BCAPS KSV list ready */
+ ret = adv_i2c_write(client, 0x64, 0x78, 0x01);
+ if (ret) {
+ dev_err(&client->dev, "%s: Error clearing BCAPS KSV list ready!\n", __func__);
+ return ret;
+ }
+
+ /* KSV_LIST_READY_PORT_A KSV list not ready */
+ ret = adv_i2c_write(client, 0x64, 0x69, 0x00);
+ if (ret) {
+ dev_err(&client->dev, "%s: Error clearing KSV_LIST_READY_PORT_A register!\n", __func__);
+ return ret;
+ }
+
+ /* Write the BSKV list, one device at a time */
+ /* Writing the entire list in one call exceeds frame size */
+ for (k = 0; k < ADV7481_MAX_DEVICES; ++k) {
+ unsigned int j = k * ADV7481_KSV_SIZE;
+ struct crl_register_write_rep adv_ksv_cmd[] = {
+ {0x80 + j, CRL_REG_LEN_08BIT, dev_info->ksv[j + 0], 0x64},
+ {0x81 + j, CRL_REG_LEN_08BIT, dev_info->ksv[j + 1], 0x64},
+ {0x82 + j, CRL_REG_LEN_08BIT, dev_info->ksv[j + 2], 0x64},
+ {0x83 + j, CRL_REG_LEN_08BIT, dev_info->ksv[j + 3], 0x64},
+ {0x84 + j, CRL_REG_LEN_08BIT, dev_info->ksv[j + 4], 0x64},
+ };
+ ret = crlmodule_write_regs(sensor, adv_ksv_cmd, ARRAY_SIZE(adv_ksv_cmd));
+
+ if (ret) {
+ dev_err(&client->dev, "%s: Error while writing BKSV list!\n", __func__);
+ return ret;
+ }
+ }
+
+ /* Finally update the bstatus registers */
+ ret = adv_i2c_read(client, 0x64, 0x42, &reg);
+
+ if (ret) {
+ dev_err(&client->dev, "%s: Error reading bstatus register!\n", __func__);
+ return ret;
+ }
+
+ /* ADV recommendation: only update bits [0:11] */
+ /* Take the lower nibble (bits [11:8]) of the input bstatus */
+ /* Take the upper nibble (bits [15:12]) of the current register */
+ dev_info->bstatus.bstatus[1] =
+ (dev_info->bstatus.bstatus[1] & 0x0F) | (reg & 0xF0);
+ {
+ struct crl_register_write_rep adv_cmd[] = {
+ {0x41, CRL_REG_LEN_08BIT, dev_info->bstatus.bstatus[0], 0x64},
+ {0x42, CRL_REG_LEN_08BIT, dev_info->bstatus.bstatus[1], 0x64},
+ {0x69, CRL_REG_LEN_08BIT, 0x01, 0x64}, /* KSV_LIST_READY_PORT_A */
+ };
+
+ ret = crlmodule_write_regs(sensor, adv_cmd, ARRAY_SIZE(adv_cmd));
+ }
+
+ return ret;
+}
+
+static ssize_t adv_bcaps_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ u32 val;
+ int ret;
+ struct i2c_client* client = container_of(dev, struct i2c_client, dev);
+
+ ret = adv_i2c_read(client, 0x64, 0x40, &val);
+
+ if (ret != 0) {
+ return -EIO;
+ }
+
+ val = val & 0xFF;
+ *buf = val;
+ return 1;
+}
+
+/* Declares bcaps attribute that will be exposed to user space via sysfs */
+static DEVICE_ATTR(bcaps, S_IRUGO, adv_bcaps_show, NULL);
+
+/*
+ * Writes provided BKSV value from user space to chip.
+ * BKSV should be formatted as adv7481_dev_info struct,
+ * it does basic validation and checks if provided buffer size matches size of adv7481_dev_info struct.
+ * In case of error return EIO.
+ */
+static ssize_t adv_bksv_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int ret;
+ struct adv7481_dev_info dev_info;
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+ if (count != sizeof (struct adv7481_dev_info)) {
+ return -EIO;
+ }
+
+ dev_info = *((struct adv7481_dev_info*) buf);
+
+ ret = adv_write_bksv(client, &dev_info);
+
+ if (ret != 0) {
+ return -EIO;
+ }
+
+ return count;
+}
+
+/* Declares bksv attribute that will be exposed to user space via sysfs */
+static DEVICE_ATTR(bksv, S_IWUSR | S_IWGRP, NULL, adv_bksv_store);
+
+/*
+ * Enables HPA_MAN_VALUE_PORT_A to enable hot plug detection.
+ */
+static void adv_hpa_assert(struct work_struct *work)
+{
+ irq_task_t *task = (irq_task_t*) work;
+ struct i2c_client *client = task->client;
+
+ adv_i2c_write(client, 0x68, 0xF8, 0x01);
+ in_hot_plug_reset = 0;
+ kfree(work);
+}
+
+/*
+ * Handles hpa timer interrupt, defers enalbing of HPA to adv_hpa_assert
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
+static void adv_hpa_reset_callback(unsigned long data)
+{
+ irq_task_t *task = NULL;
+
+ task = (irq_task_t*) kmalloc(sizeof(irq_task_t), GFP_ATOMIC);
+ if (task) {
+ INIT_WORK( (struct work_struct*) task, adv_hpa_assert);
+ task->client = (struct i2c_client*) data;
+ queue_work(irq_workqueue, (struct work_struct*)task);
+ }
+}
+#else
+static void adv_hpa_reset_callback(struct timer_list *t)
+{
+ irq_task_t *task = NULL;
+
+ task = (irq_task_t*) kmalloc(sizeof(irq_task_t), GFP_ATOMIC);
+ if (task) {
+ INIT_WORK( (struct work_struct*) task, adv_hpa_assert);
+ queue_work(irq_workqueue, (struct work_struct*)task);
+ }
+}
+#endif
+
+/*
+ * Reauthenticates HDCP by disabling hot plug detection for 2 seconds.
+ * It can be triggered by user space by writing any value to "reauthenticate" attribute.
+ * After that time connected source will automatically ask for HDCP authentication once again.
+ * To prevent sleep, timer is used to delay enabling of hot plug by 2 seconds.
+ * In case that previous reauthentication is not completed, returns EBUSY.
+ * In case of error returns EIO.
+ */
+static ssize_t adv_reauthenticate_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ int ret;
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+
+ mutex_lock(&hot_plug_reset_lock);
+
+ if (in_hot_plug_reset) {
+ mutex_unlock(&hot_plug_reset_lock);
+ return -EBUSY;
+ }
+
+ /* Clear BCAPS KSV list ready */
+ ret = adv_i2c_write(client, 0x64, 0x78, 0x01);
+ if (ret != 0) {
+ dev_err(&client->dev, "%s: Error clearing BCAPS KSV list ready!\n", __func__);
+ mutex_unlock(&hot_plug_reset_lock);
+ return -EIO;
+ }
+
+ /* KSV_LIST_READY_PORT_A KSV list not ready */
+ ret = adv_i2c_write(client, 0x64, 0x69, 0x00);
+ if (ret != 0) {
+ dev_err(&client->dev, "%s: Error clearing KSV_LIST_READY_PORT_A register!\n", __func__);
+ mutex_unlock(&hot_plug_reset_lock);
+ return -EIO;
+ }
+
+ ret = adv_i2c_write(client, 0x68, 0xF8, 0x00);
+
+ if (ret != 0) {
+ mutex_unlock(&hot_plug_reset_lock);
+ return -EIO;
+ }
+
+ in_hot_plug_reset = 1;
+ mod_timer(&hot_plug_reset_timer, jiffies + msecs_to_jiffies(2000));
+
+ mutex_unlock(&hot_plug_reset_lock);
+ return count;
+}
+
+/* Declares reauthenticate attribute that will be exposed to user space via sysfs */
+static DEVICE_ATTR(reauthenticate, S_IWUSR | S_IWGRP, NULL, adv_reauthenticate_store);
+
+/* Dummy show to prevent WARN when registering aksv attribute */
+static ssize_t adv_aksv_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ (void) dev;
+ (void) attr;
+ (void) buf;
+
+ return -EIO;
+}
+
+/* Declares aksv attribute that will be exposed to user space via sysfs, to notify about AKSV events */
+static DEVICE_ATTR(aksv, S_IRUGO, adv_aksv_show, NULL);
+
+
+static ssize_t adv_hdmi_cable_connected_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ char interlaced = 'p';
+ if (hdmi_res_interlaced) {
+ interlaced = 'i';
+ }
+
+ return snprintf(buf, 20, "%dx%d%c", hdmi_res_width, hdmi_res_height, interlaced);
+}
+static DEVICE_ATTR(hdmi_cable_connected, S_IRUGO, adv_hdmi_cable_connected_show, NULL);
+
+static ssize_t adv_bstatus_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ u32 b0, b1;
+ int ret;
+ struct i2c_client* client = container_of(dev, struct i2c_client, dev);
+ dev_dbg(&client->dev, "Getting bstatus\n");
+ ret = adv_i2c_read(client, 0x64, 0x41, &b0);
+ if (ret != 0) {
+ dev_err(&client->dev, "Error getting bstatus(0)\n");
+ return -EIO;
+ }
+ dev_dbg(&client->dev, "btatus(0): 0x%x\n", b0 & 0xff);
+ ret = adv_i2c_read(client, 0x64, 0x42, &b1);
+ if (ret != 0) {
+ dev_err(&client->dev, "Error getting bstatus(1)\n");
+ return -EIO;
+ }
+ dev_dbg(&client->dev, "bstatus(1): 0x%x\n", b1 & 0xff);
+ *buf = b0 & 0xff;
+ buf++;
+ *buf = b1 & 0xff;
+ return 2;
+}
+static DEVICE_ATTR(bstatus, S_IRUGO, adv_bstatus_show, NULL);
+
+// irq GPIO ping unavailable on ACRN UOS
+#if (!IS_ENABLED(CONFIG_VIDEO_INTEL_UOS))
+static void adv_isr_bh(struct work_struct *work)
+{
+ irq_task_t *task = (irq_task_t*) work;
+ struct i2c_client *client = task->client;
+
+ u32 interrupt_st;
+ u32 raw_value;
+ u32 temp[3];
+ int ret = 0;
+
+ struct crl_register_read_rep reg;
+ reg.address = 0x90;
+ reg.len = CRL_REG_LEN_08BIT;
+ reg.mask = 0xFF;
+ reg.dev_i2c_addr = 0xE0;
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+
+ /* AKSV_UPDATE_A_ST: check interrupt status */
+ ret = adv_i2c_read(client, 0xE0, 0x90, &interrupt_st);
+
+ if (interrupt_st & 0x08 /*ADV7481_AKSV_UPDATE_A_ST*/) {
+ dev_dbg(&client->dev, "%s: ADV7481 ISR: AKSV_UPDATE_A_ST: 0x%x\n",
+ __func__, interrupt_st);
+
+ /* Notify user space about AKSV event */
+ sysfs_notify(&client->dev.kobj, NULL, "aksv");
+
+ /* Clear interrupt bit */
+ ret = adv_i2c_write(client, 0xE0, 0x91, 0x08);
+ }
+
+ /* Check interrupt status for: CABLE_DET_A_ST, V_LOCKED_A_ST and DE_REGEN_LCK_A_ST */
+ ret = adv_i2c_read(client, 0xE0, 0x72, &interrupt_st);
+
+ /* If any of CABLE_DET_A_ST, V_LOCKED_A_ST and DE_REGEN_LCK_A_ST interrupts was set,
+ * get updated values of CABLE_DET_RAW, V_LOCKED_RAW and DE_REGEN_LCK_RAW
+ */
+ if (interrupt_st) {
+ ret = adv_i2c_read(client, 0xE0, 0x71, &raw_value);
+ }
+
+ /* Check CABLE_DET_A_ST interrupt */
+ if ((interrupt_st & ADV7481_CABLE_DET_A_ST)) {
+ /* Clear interrupt bit */
+ ret = adv_i2c_write(client, 0xE0, 0x73, 0x40);
+
+ /* HDMI cable is connected */
+ if (raw_value & ADV7481_CABLE_DET_A_ST) {
+ dev_dbg(&client->dev, "%s: ADV7481 ISR: HDMI cable connected\n", __func__);
+ ret = adv_i2c_write(client, 0xE0, 0x10, 0xA1);
+ }
+ else {
+ dev_dbg(&client->dev, "%s: ADV7481 ISR: HDMI cable disconnected\n", __func__);
+ }
+ }
+
+ /* Check V_LOCKED_A_ST interrupt */
+ if((interrupt_st & ADV7481_V_LOCKED_A_ST)) {
+ /* Clear interrupt bit */
+ ret = adv_i2c_write(client, 0xE0, 0x73, 0x02);
+ /* Vertical sync filter has been locked, resolution height can be read */
+ if (raw_value & ADV7481_V_LOCKED_A_ST) {
+ dev_dbg(&client->dev, "%s: ADV7481 ISR: Vertical Sync Filter Locked\n", __func__);
+ reg.dev_i2c_addr = 0x68; //HDMI_RX_MAP;
+ reg.address = 0x09;
+ adv_i2c_read(client, 0x68, 0x09, &temp[0]);
+ adv_i2c_read(client, 0x68, 0x0A, &temp[1]);
+ adv_i2c_read(client, 0x68, 0x0B, &temp[2]);
+
+ temp[0] = temp[0] & 0x1F;
+ hdmi_res_height = (temp[0]<<8) + temp[1];
+ if (temp[2] & 0x20) {
+ hdmi_res_height = hdmi_res_height << 1;
+ hdmi_res_interlaced = 1;
+ }
+ else {
+ hdmi_res_interlaced = 0;
+ }
+
+ /* If resolution width was already read, notify user space about new resolution */
+ if (hdmi_res_width) {
+ sysfs_notify(&client->dev.kobj, NULL, "hdmi_cable_connected");
+ }
+ }
+ else {
+ dev_dbg(&client->dev, "%s: ADV7481 ISR: Vertical Sync Filter Lost\n", __func__);
+ hdmi_res_height = 0;
+ /* Notify user space about losing resolution */
+ if (!hdmi_res_width) {
+ sysfs_notify(&client->dev.kobj, NULL, "hdmi_cable_connected");
+ }
+ }
+ }
+
+ /* Check DE_REGEN_A_ST interrupt */
+ if((interrupt_st & ADV7481_DE_REGEN_A_ST)) {
+ /* Clear interrupt bit */
+ ret = adv_i2c_write(client, 0xE0, 0x73, 0x01);
+
+ /* DE regeneration has been locked, resolution height can be read */
+ if (raw_value & ADV7481_DE_REGEN_A_ST) {
+ dev_dbg(&client->dev, "%s: ADV7481 ISR: DE Regeneration Locked\n", __func__);
+ reg.dev_i2c_addr = 0x68; //HDMI_RX_MAP;
+ reg.address = 0x07;
+ adv_i2c_read(client, 0x68, 0x07, &temp[0]);
+ adv_i2c_read(client, 0x68, 0x08, &temp[1]);
+
+ temp[0] = temp[0] & 0x1F;
+ hdmi_res_width = (temp[0]<<8) + temp[1];
+
+ /* If resolution height was already read back, notify user space about new resolution */
+ if (hdmi_res_height) {
+ sysfs_notify(&client->dev.kobj, NULL, "hdmi_cable_connected");
+ }
+ }
+ else {
+ dev_dbg(&client->dev, "%s: ADV7481 ISR: DE Regeneration Lost\n", __func__);
+ hdmi_res_width = 0;
+ /* Notfiy user space about losing resolution */
+ if (!hdmi_res_height) {
+ sysfs_notify(&client->dev.kobj, NULL, "hdmi_cable_connected");
+ }
+ }
+ }
+}
+
+static irq_handler_t adv7481_irq_handler(unsigned int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ irq_task_t *task = NULL;
+ struct i2c_client *client = (struct i2c_client*)dev_id;
+
+ dev_dbg(&client->dev, "%s: Interrupt in ADV7481\n", __func__);
+
+ task = (irq_task_t*) kmalloc(sizeof(irq_task_t), GFP_ATOMIC);
+ if (task) {
+ INIT_WORK( (struct work_struct*) task, adv_isr_bh);
+ task->client = client;
+ queue_work(irq_workqueue, (struct work_struct*)task);
+ }
+
+ return (irq_handler_t)IRQ_HANDLED;
+}
+
+static int unregister_gpio_irq(void)
+{
+ gpio_free(ADV7481_GPIO);
+ return 0;
+}
+
+static int register_gpio_irq(struct i2c_client *client)
+{
+ int res = 0;
+ unsigned int irq;
+
+
+ if (!gpio_is_valid(ADV7481_GPIO)) {
+ dev_err(&client->dev, "%s: ADV7481 GPIO pin %d is invalid!\n",
+ __func__, ADV7481_GPIO);
+ return -ENODEV;
+ } else {
+ dev_dbg(&client->dev, "%s: GPIO %d is valid.\n", __func__, ADV7481_GPIO);
+ }
+
+ res = gpio_request(ADV7481_GPIO, "ADV7481 Interrupt");
+ if (res) {
+ dev_err(&client->dev, "%s: ADV7481 GPIO pin request failed!\n", __func__);
+ return -ENODEV;
+ }
+
+ gpio_direction_input(ADV7481_GPIO);
+ irq = gpio_to_irq(ADV7481_GPIO);
+ res = request_irq(irq,
+ (irq_handler_t)adv7481_irq_handler,
+ IRQF_TRIGGER_RISING,
+ "adv7481_irq_handler",
+ client);
+
+ dev_dbg(&client->dev, "%s: GPIO register GPIO IRQ result: %d\n", __func__, res);
+
+ return res;
+}
+#endif
+
+int adv7481_sensor_init(struct i2c_client *client)
+{
+ dev_dbg(&client->dev, "%s ADV7481_sensor_init\n", __func__);
+ irq_workqueue = create_workqueue("adv7481_irq_workqueue");
+// irq GPIO ping unavailable on ACRN UOS
+#if (!IS_ENABLED(CONFIG_VIDEO_INTEL_UOS))
+ register_gpio_irq(client);
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
+ setup_timer(&hot_plug_reset_timer, adv_hpa_reset_callback, (unsigned long) client);
+#else
+ timer_setup(&hot_plug_reset_timer, adv_hpa_reset_callback, 0);
+#endif
+ CREATE_ATTRIBUTE(dev_attr_hdmi_cable_connected);
+ CREATE_ATTRIBUTE(dev_attr_bcaps);
+ CREATE_ATTRIBUTE(dev_attr_aksv);
+ CREATE_ATTRIBUTE(dev_attr_bksv);
+ CREATE_ATTRIBUTE(dev_attr_reauthenticate);
+ CREATE_ATTRIBUTE(dev_attr_bstatus);
+
+ return 0;
+}
+
+int adv7481_sensor_cleanup(struct i2c_client *client)
+{
+ dev_dbg(&client->dev, "%s: ADV7481_sensor_cleanup\n", __func__);
+ if (irq_workqueue != NULL) {
+ free_irq(gpio_to_irq(ADV7481_GPIO), client);
+// irq GPIO ping unavailable on ACRN UOS
+#if (!IS_ENABLED(CONFIG_VIDEO_INTEL_UOS))
+ unregister_gpio_irq();
+#endif
+ del_timer(&hot_plug_reset_timer);
+ flush_workqueue(irq_workqueue);
+ destroy_workqueue(irq_workqueue);
+ irq_workqueue = NULL;
+ }
+ REMOVE_ATTRIBUTE(dev_attr_bstatus);
+ REMOVE_ATTRIBUTE(dev_attr_reauthenticate);
+ REMOVE_ATTRIBUTE(dev_attr_bksv);
+ REMOVE_ATTRIBUTE(dev_attr_aksv);
+ REMOVE_ATTRIBUTE(dev_attr_bcaps);
+ REMOVE_ATTRIBUTE(dev_attr_hdmi_cable_connected);
+ return 0;
+}
diff --git a/drivers/media/i2c/crlmodule-lite/crl_adv7481_hdmi_configuration.h b/drivers/media/i2c/crlmodule-lite/crl_adv7481_hdmi_configuration.h
new file mode 100644
index 000000000000..489a3eb97878
--- /dev/null
+++ b/drivers/media/i2c/crlmodule-lite/crl_adv7481_hdmi_configuration.h
@@ -0,0 +1,942 @@
+/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) */
+/*
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#ifndef __CRLMODULE_ADV7481_HDMI_CONFIGURATION_H_
+#define __CRLMODULE_ADV7481_HDMI_CONFIGURATION_H_
+
+#include "crlmodule-sensor-ds.h"
+
+static struct crl_register_write_rep adv7481_hdmi_onetime_init_regset[] = {
+ {0xFF, CRL_REG_LEN_08BIT, 0xFF, 0xE0},
+ {0x00, CRL_REG_LEN_DELAY, 0x05, 0x00},
+ {0x01, CRL_REG_LEN_08BIT, 0x76, 0xE0}, /* ADI Required Write */
+ {0x05, CRL_REG_LEN_08BIT, 0x96, 0xE0}, /* Setting Vid_Std to
+ 1600x1200(UXGA)@60 */
+ {0xF2, CRL_REG_LEN_08BIT, 0x01, 0xE0}, /* Enable I2C Read
+ Auto-Increment */
+ {0xF3, CRL_REG_LEN_08BIT, 0x4C, 0xE0}, /* DPLL Map Address
+ Set to 0x4C */
+ {0xF4, CRL_REG_LEN_08BIT, 0x44, 0xE0}, /* CP Map Address
+ Set to 0x44 */
+ {0xF5, CRL_REG_LEN_08BIT, 0x68, 0xE0}, /* HDMI RX Map Address
+ Set to 0x68 */
+ {0xF6, CRL_REG_LEN_08BIT, 0x6C, 0xE0}, /* EDID Map Address
+ Set to 0x6C */
+ {0xF7, CRL_REG_LEN_08BIT, 0x64, 0xE0}, /* HDMI RX Repeater Map Address
+ Set to 0x64 */
+ {0xF8, CRL_REG_LEN_08BIT, 0x62, 0xE0}, /* HDMI RX Infoframe Map Address
+ Set to 0x62 */
+ {0xF9, CRL_REG_LEN_08BIT, 0xF0, 0xE0}, /* CBUS Map Address
+ Set to 0xF0 */
+ {0xFA, CRL_REG_LEN_08BIT, 0x82, 0xE0}, /* CEC Map Address
+ Set to 0x82 */
+ {0xFB, CRL_REG_LEN_08BIT, 0xF2, 0xE0}, /* SDP Main Map Address
+ Set to 0xF2 */
+ {0xFC, CRL_REG_LEN_08BIT, 0x90, 0xE0}, /* CSI-TXB Map Address
+ Set to 0x90 */
+ {0xFD, CRL_REG_LEN_08BIT, 0x94, 0xE0}, /* CSI-TXA Map Address
+ Set to 0x94 */
+ {0x00, CRL_REG_LEN_08BIT, 0x40, 0xE0}, /* Disable chip powerdown &
+ Enable HDMI Rx block */
+
+ {0x40, CRL_REG_LEN_08BIT, 0xC3, 0x64}, /* Enable HDCP 1.1 Repeater */
+ {0x69, CRL_REG_LEN_08BIT, 0x00, 0x64}, /* KSV List not ready port A */
+ {0x77, CRL_REG_LEN_08BIT, 0x08, 0x64}, /* Clear KSV List */
+ {0x78, CRL_REG_LEN_08BIT, 0x01, 0x64}, /* KSV_LIST_READY_CLR_A:
+ Clears the BCAPS ready bit */
+ {0x68, CRL_REG_LEN_08BIT, 0x00, 0x64}, /* Disable dual ksv list
+ for port A */
+ {0x41, CRL_REG_LEN_08BIT, 0x00, 0x64}, /* Reset b-status (1) */
+ {0x42, CRL_REG_LEN_08BIT, 0x00, 0x64}, /* Reset b-status (2) */
+ {0x91, CRL_REG_LEN_08BIT, 0x08, 0xE0}, /* AKSV Update Clear */
+
+ {0x00, CRL_REG_LEN_08BIT, 0x08, 0x68}, /* Foreground Channel = A */
+ {0x98, CRL_REG_LEN_08BIT, 0xFF, 0x68}, /* ADI Required Write */
+ {0x99, CRL_REG_LEN_08BIT, 0xA3, 0x68}, /* ADI Required Write */
+ {0x9A, CRL_REG_LEN_08BIT, 0x00, 0x68}, /* ADI Required Write */
+ {0x9B, CRL_REG_LEN_08BIT, 0x0A, 0x68}, /* ADI Required Write */
+ {0x9D, CRL_REG_LEN_08BIT, 0x40, 0x68}, /* ADI Required Write */
+ {0xCB, CRL_REG_LEN_08BIT, 0x09, 0x68}, /* ADI Required Write */
+ {0x3D, CRL_REG_LEN_08BIT, 0x10, 0x68}, /* ADI Required Write */
+ {0x3E, CRL_REG_LEN_08BIT, 0x7B, 0x68}, /* ADI Required Write */
+ {0x3F, CRL_REG_LEN_08BIT, 0x5E, 0x68}, /* ADI Required Write */
+ {0x4E, CRL_REG_LEN_08BIT, 0xFE, 0x68}, /* ADI Required Write */
+ {0x4F, CRL_REG_LEN_08BIT, 0x18, 0x68}, /* ADI Required Write */
+ {0x57, CRL_REG_LEN_08BIT, 0xA3, 0x68}, /* ADI Required Write */
+ {0x58, CRL_REG_LEN_08BIT, 0x04, 0x68}, /* ADI Required Write */
+ {0x85, CRL_REG_LEN_08BIT, 0x10, 0x68}, /* ADI Required Write */
+ {0x83, CRL_REG_LEN_08BIT, 0x00, 0x68}, /* Enable All Terminatio ns */
+ {0xA3, CRL_REG_LEN_08BIT, 0x01, 0x68}, /* ADI Required Write */
+ {0xBE, CRL_REG_LEN_08BIT, 0x00, 0x68}, /* ADI Required Write */
+ {0x6C, CRL_REG_LEN_08BIT, 0x01, 0x68}, /* HPA Manual Enable */
+ {0xF8, CRL_REG_LEN_08BIT, 0x01, 0x68}, /* HPA Asserted */
+ {0x0F, CRL_REG_LEN_08BIT, 0x00, 0x68}, /* Audio Mute Speed
+ Set to Fastest (Smallest Step Size) */
+ {0x0E, CRL_REG_LEN_08BIT, 0xFF, 0xE0}, /* LLC/PIX/AUD/SPI PINS
+ TRISTATED */
+
+ {0x74, CRL_REG_LEN_08BIT, 0x43, 0xE0}, /* Enable interrupts */
+ {0x75, CRL_REG_LEN_08BIT, 0x43, 0xE0},
+
+ {0x70, CRL_REG_LEN_08BIT, 0xA0, 0x64}, /* Write primary edid size */
+ {0x74, CRL_REG_LEN_08BIT, 0x01, 0x64}, /* Enable manual edid */
+ {0x7A, CRL_REG_LEN_08BIT, 0x00, 0x64}, /* Write edid sram select */
+ {0xF6, CRL_REG_LEN_08BIT, 0x6C, 0xE0}, /* Write edid map bus address */
+
+ {0x00*4, CRL_REG_LEN_32BIT, 0x00FFFFFF, 0x6C}, /* EDID programming */
+ {0x01*4, CRL_REG_LEN_32BIT, 0xFFFFFF00, 0x6C}, /* EDID programming */
+ {0x02*4, CRL_REG_LEN_32BIT, 0x4DD90100, 0x6C}, /* EDID programming */
+ {0x03*4, CRL_REG_LEN_32BIT, 0x00000000, 0x6C}, /* EDID programming */
+ {0x04*4, CRL_REG_LEN_32BIT, 0x00110103, 0x6C}, /* EDID programming */
+ {0x05*4, CRL_REG_LEN_32BIT, 0x80000078, 0x6C}, /* EDID programming */
+ {0x06*4, CRL_REG_LEN_32BIT, 0x0A0DC9A0, 0x6C}, /* EDID programming */
+ {0x07*4, CRL_REG_LEN_32BIT, 0x57479827, 0x6C}, /* EDID programming */
+ {0x08*4, CRL_REG_LEN_32BIT, 0x12484C00, 0x6C}, /* EDID programming */
+ {0x09*4, CRL_REG_LEN_32BIT, 0x00000101, 0x6C}, /* EDID programming */
+ {0x0A*4, CRL_REG_LEN_32BIT, 0x01010101, 0x6C}, /* EDID programming */
+ {0x0B*4, CRL_REG_LEN_32BIT, 0x01010101, 0x6C}, /* EDID programming */
+ {0x0C*4, CRL_REG_LEN_32BIT, 0x01010101, 0x6C}, /* EDID programming */
+ {0x0D*4, CRL_REG_LEN_32BIT, 0x0101011D, 0x6C}, /* EDID programming */
+ {0x0E*4, CRL_REG_LEN_32BIT, 0x80D0721C, 0x6C}, /* EDID programming */
+ {0x0F*4, CRL_REG_LEN_32BIT, 0x1620102C, 0x6C}, /* EDID programming */
+ {0x10*4, CRL_REG_LEN_32BIT, 0x2580C48E, 0x6C}, /* EDID programming */
+ {0x11*4, CRL_REG_LEN_32BIT, 0x2100009E, 0x6C}, /* EDID programming */
+ {0x12*4, CRL_REG_LEN_32BIT, 0x011D8018, 0x6C}, /* EDID programming */
+ {0x13*4, CRL_REG_LEN_32BIT, 0x711C1620, 0x6C}, /* EDID programming */
+ {0x14*4, CRL_REG_LEN_32BIT, 0x582C2500, 0x6C}, /* EDID programming */
+ {0x15*4, CRL_REG_LEN_32BIT, 0xC48E2100, 0x6C}, /* EDID programming */
+ {0x16*4, CRL_REG_LEN_32BIT, 0x009E0000, 0x6C}, /* EDID programming */
+ {0x17*4, CRL_REG_LEN_32BIT, 0x00FC0048, 0x6C}, /* EDID programming */
+ {0x18*4, CRL_REG_LEN_32BIT, 0x444D4920, 0x6C}, /* EDID programming */
+ {0x19*4, CRL_REG_LEN_32BIT, 0x4C4C430A, 0x6C}, /* EDID programming */
+ {0x1A*4, CRL_REG_LEN_32BIT, 0x20202020, 0x6C}, /* EDID programming */
+ {0x1B*4, CRL_REG_LEN_32BIT, 0x000000FD, 0x6C}, /* EDID programming */
+ {0x1C*4, CRL_REG_LEN_32BIT, 0x003B3D0F, 0x6C}, /* EDID programming */
+ {0x1D*4, CRL_REG_LEN_32BIT, 0x2D08000A, 0x6C}, /* EDID programming */
+ {0x1E*4, CRL_REG_LEN_32BIT, 0x20202020, 0x6C}, /* EDID programming */
+ {0x1F*4, CRL_REG_LEN_32BIT, 0x202001C1, 0x6C}, /* EDID programming */
+ {0x20*4, CRL_REG_LEN_32BIT, 0x02031E77, 0x6C}, /* EDID programming */
+ {0x21*4, CRL_REG_LEN_32BIT, 0x4F941305, 0x6C}, /* EDID programming */
+ {0x22*4, CRL_REG_LEN_32BIT, 0x03040201, 0x6C}, /* EDID programming */
+ {0x23*4, CRL_REG_LEN_32BIT, 0x16150706, 0x6C}, /* EDID programming */
+ {0x24*4, CRL_REG_LEN_32BIT, 0x1110121F, 0x6C}, /* EDID programming */
+ {0x25*4, CRL_REG_LEN_32BIT, 0x23090701, 0x6C}, /* EDID programming */
+ {0x26*4, CRL_REG_LEN_32BIT, 0x65030C00, 0x6C}, /* EDID programming */
+ {0x27*4, CRL_REG_LEN_32BIT, 0x10008C0A, 0x6C}, /* EDID programming */
+ {0x28*4, CRL_REG_LEN_32BIT, 0xD0902040, 0x6C}, /* EDID programming */
+ {0x29*4, CRL_REG_LEN_32BIT, 0x31200C40, 0x6C}, /* EDID programming */
+ {0x2A*4, CRL_REG_LEN_32BIT, 0x5500138E, 0x6C}, /* EDID programming */
+ {0x2B*4, CRL_REG_LEN_32BIT, 0x21000018, 0x6C}, /* EDID programming */
+ {0x2C*4, CRL_REG_LEN_32BIT, 0x011D00BC, 0x6C}, /* EDID programming */
+ {0x2D*4, CRL_REG_LEN_32BIT, 0x52D01E20, 0x6C}, /* EDID programming */
+ {0x2E*4, CRL_REG_LEN_32BIT, 0xB8285540, 0x6C}, /* EDID programming */
+ {0x2F*4, CRL_REG_LEN_32BIT, 0xC48E2100, 0x6C}, /* EDID programming */
+ {0x30*4, CRL_REG_LEN_32BIT, 0x001E8C0A, 0x6C}, /* EDID programming */
+ {0x31*4, CRL_REG_LEN_32BIT, 0xD08A20E0, 0x6C}, /* EDID programming */
+ {0x32*4, CRL_REG_LEN_32BIT, 0x2D10103E, 0x6C}, /* EDID programming */
+ {0x33*4, CRL_REG_LEN_32BIT, 0x9600C48E, 0x6C}, /* EDID programming */
+ {0x34*4, CRL_REG_LEN_32BIT, 0x21000018, 0x6C}, /* EDID programming */
+ {0x35*4, CRL_REG_LEN_32BIT, 0x011D0072, 0x6C}, /* EDID programming */
+ {0x36*4, CRL_REG_LEN_32BIT, 0x51D01E20, 0x6C}, /* EDID programming */
+ {0x37*4, CRL_REG_LEN_32BIT, 0x6E285500, 0x6C}, /* EDID programming */
+ {0x38*4, CRL_REG_LEN_32BIT, 0xC48E2100, 0x6C}, /* EDID programming */
+ {0x39*4, CRL_REG_LEN_32BIT, 0x001E8C0A, 0x6C}, /* EDID programming */
+ {0x3A*4, CRL_REG_LEN_32BIT, 0xD08A20E0, 0x6C}, /* EDID programming */
+ {0x3B*4, CRL_REG_LEN_32BIT, 0x2D10103E, 0x6C}, /* EDID programming */
+ {0x3C*4, CRL_REG_LEN_32BIT, 0x9600138E, 0x6C}, /* EDID programming */
+ {0x3D*4, CRL_REG_LEN_32BIT, 0x21000018, 0x6C}, /* EDID programming */
+ {0x3E*4, CRL_REG_LEN_32BIT, 0x00000000, 0x6C}, /* EDID programming */
+ {0x3F*4, CRL_REG_LEN_32BIT, 0x000000CB, 0x6C}, /* EDID programming */
+};
+
+static struct crl_register_write_rep adv7481_hdmi_mode_rgb565[] = {
+ {0x04, CRL_REG_LEN_08BIT, 0x02, 0xE0}, //RGB Out of CP
+ {0x12, CRL_REG_LEN_08BIT, 0xF0, 0xE0}, //CSC Depends on ip Packets - SDR 444
+ {0x17, CRL_REG_LEN_08BIT, 0xB8, 0xE0}, //Configure for RGB565 & Luma & Chroma Values Can Reach 254d
+ {0x03, CRL_REG_LEN_08BIT, 0x86, 0xE0}, //CP-Insert_AV_Code
+ {0x7C, CRL_REG_LEN_08BIT, 0x00, 0x44}, //ADI Required Write
+ {0x0C, CRL_REG_LEN_08BIT, 0xE0, 0xE0}, //Enable LLC_DLL & Double LLC Timing
+ {0x0E, CRL_REG_LEN_08BIT, 0xDD, 0xE0}, //LLC/PIX/SPI PINS TRISTATED AUD Outputs Enabled
+ {0x10, CRL_REG_LEN_08BIT, 0xC0, 0xE0}, //Enable 4-lane CSI Tx & Pixel Port
+ {0x7E, CRL_REG_LEN_08BIT, 0x98, 0x94}, //ADI Required Write
+};
+
+static struct crl_register_write_rep adv7481_hdmi_mode_rgb888[] = {
+ {0x04, CRL_REG_LEN_08BIT, 0x02, 0xE0}, /* RGB Out of CP */
+ {0x12, CRL_REG_LEN_08BIT, 0xF0, 0xE0}, /* CSC Depends on ip Packets -
+ SDR 444 */
+ {0x17, CRL_REG_LEN_08BIT, 0x80, 0xE0}, /* Luma & Chroma Values Can
+ Reach 254d */
+ {0x03, CRL_REG_LEN_08BIT, 0x86, 0xE0}, /* CP-Insert_AV_Code */
+ {0x7C, CRL_REG_LEN_08BIT, 0x00, 0x44}, /* ADI Required Write */
+ {0x0C, CRL_REG_LEN_08BIT, 0xE0, 0xE0}, /* Enable LLC_DLL &
+ Double LLC Timing */
+ {0x0E, CRL_REG_LEN_08BIT, 0xDD, 0xE0}, /* LLC/PIX/SPI PINS TRISTATED
+ AUD Outputs Enabled */
+ {0xDB, CRL_REG_LEN_08BIT, 0x10, 0x94}, /* ADI Required Write */
+ {0x7E, CRL_REG_LEN_08BIT, 0x1B, 0x94}, /* ADI Required Write */
+};
+
+static struct crl_register_write_rep adv7481_hdmi_mode_uyvy[] = {
+ {0x04, CRL_REG_LEN_08BIT, 0x00, 0xE0}, //YCrCb output
+ {0x12, CRL_REG_LEN_08BIT, 0xF2, 0xE0}, //CSC Depends on ip Packets - SDR422 set
+ {0x17, CRL_REG_LEN_08BIT, 0x80, 0xE0}, //Luma & Chroma Values Can Reach 254d
+ {0x03, CRL_REG_LEN_08BIT, 0x86, 0xE0}, //CP-Insert_AV_Code
+ {0x7C, CRL_REG_LEN_08BIT, 0x00, 0x44}, //ADI Required Write
+ {0x0C, CRL_REG_LEN_08BIT, 0xE0, 0xE0}, //Enable LLC_DLL & Double LLC Timing
+ {0x0E, CRL_REG_LEN_08BIT, 0xDD, 0xE0}, //LLC/PIX/SPI PINS TRISTATED AUD Outputs Enabled
+ {0x10, CRL_REG_LEN_08BIT, 0xC0, 0xE0}, //Enable 4-lane CSI Tx & Pixel Port
+ {0x00, CRL_REG_LEN_08BIT, 0x84, 0x94}, //Enable 4-lane MIPI
+ {0x00, CRL_REG_LEN_08BIT, 0xA4, 0x94}, //Set Auto DPHY Timing
+ {0xDB, CRL_REG_LEN_08BIT, 0x10, 0x94}, //ADI Required Write
+ {0x7E, CRL_REG_LEN_08BIT, 0x00, 0x94}, //ADI Required Write
+};
+
+static struct crl_register_write_rep adv7481_hdmi_mode_yuyv[] = {
+ {0x1C, CRL_REG_LEN_08BIT, 0x3A, 0xE0}, /* Enable Interrupt*/
+ {0x04, CRL_REG_LEN_08BIT, 0x40, 0xE0}, /* YCrCb output good=0xE0*/
+ /* CSC Depends on ip Packets - SDR422 set */
+ {0x12, CRL_REG_LEN_08BIT, 0xF2, 0xE0},
+ /* Luma & Chroma Values Can Reach 254d */
+ {0x17, CRL_REG_LEN_08BIT, 0x80, 0xE0},
+ {0x7C, CRL_REG_LEN_08BIT, 0x00, 0x44}, /* ADI Required Write */
+ {0x3E, CRL_REG_LEN_08BIT, 0x08, 0x44}, /* Invert order of Cb and Cr*/
+ /* Enable LLC_DLL & Double LLC Timing */
+ {0x0C, CRL_REG_LEN_08BIT, 0xE0, 0xE0},
+ /* LLC/PIX/SPI PINS TRISTATED AUD Outputs Enabled */
+ {0x0E, CRL_REG_LEN_08BIT, 0xDD, 0xE0},
+ {0x10, CRL_REG_LEN_08BIT | CRL_REG_READ_AND_UPDATE, 0xA0, 0xE0},
+ /* Enable 4-lane CSI TXB & Pixel Port */
+ {0x00, CRL_REG_LEN_08BIT, 0x84, 0x94}, /* Enable 4-lane MIPI */
+ {0x00, CRL_REG_LEN_08BIT, 0xA4, 0x94}, /* Set Auto DPHY Timing */
+ {0xDB, CRL_REG_LEN_08BIT, 0x10, 0x94}, /* ADI Required Write */
+ {0x7E, CRL_REG_LEN_08BIT, 0x00, 0x94}, /* ADI Required Write */
+};
+
+static struct crl_register_write_rep adv7481_hdmi_mode_1080p[] = {
+ {0x00, CRL_REG_LEN_08BIT, 0x84, 0x94}, /* Enable 4-lane MIPI */
+ {0x00, CRL_REG_LEN_08BIT, 0xA4, 0x94}, /* Set Auto DPHY Timing */
+ {0x10, CRL_REG_LEN_08BIT | CRL_REG_READ_AND_UPDATE, 0xA0, 0xE0, 0xA0},
+ {0xD6, CRL_REG_LEN_08BIT, 0x07, 0x94},
+ {0xC4, CRL_REG_LEN_08BIT, 0x0A, 0x94},
+ {0x71, CRL_REG_LEN_08BIT, 0x33, 0x94},
+ {0x72, CRL_REG_LEN_08BIT, 0x11, 0x94},
+ {0xF0, CRL_REG_LEN_08BIT, 0x00, 0x94},
+ {0x31, CRL_REG_LEN_08BIT, 0x82, 0x94},
+ {0x1E, CRL_REG_LEN_08BIT, 0x80, 0x94},
+ {0xDA, CRL_REG_LEN_08BIT, 0x01, 0x94},
+ {0x00, CRL_REG_LEN_08BIT, 0x24, 0x94},
+ {0xC1, CRL_REG_LEN_08BIT, 0x2B, 0x94},
+ {0x31, CRL_REG_LEN_08BIT, 0x80, 0x94},
+ {0xC9, CRL_REG_LEN_08BIT, 0x2D, 0x44},
+ {0x05, CRL_REG_LEN_08BIT, 0x5E, 0xE0},
+ {0x8B, CRL_REG_LEN_08BIT, 0x43, 0x44}, /* shift 44 pixel to right */
+ {0x8C, CRL_REG_LEN_08BIT, 0xD4, 0x44},
+ {0x8B, CRL_REG_LEN_08BIT, 0x4F, 0x44},
+ {0x8D, CRL_REG_LEN_08BIT, 0xD4, 0x44},
+ {0x00, CRL_REG_LEN_DELAY, 0x05, 0x00},
+ {0x03, CRL_REG_LEN_08BIT, 0x00, 0xE0},
+ {0x04, CRL_REG_LEN_08BIT | CRL_REG_READ_AND_UPDATE, 0x00, 0xE0, 0xFD},
+ {0x37, CRL_REG_LEN_08BIT, 0x00, 0x44},
+};
+
+static struct crl_register_write_rep adv7481_hdmi_mode_1080i[] = {
+ {0x00, CRL_REG_LEN_08BIT, 0x84, 0x94}, /* Enable 4-lane MIPI */
+ {0x00, CRL_REG_LEN_08BIT, 0xA4, 0x94}, /* Set Auto DPHY Timing */
+ {0x10, CRL_REG_LEN_08BIT | CRL_REG_READ_AND_UPDATE, 0xA0, 0xE0, 0xA0},
+ {0xD6, CRL_REG_LEN_08BIT, 0x07, 0x94},
+ {0xC4, CRL_REG_LEN_08BIT, 0x0A, 0x94},
+ {0x71, CRL_REG_LEN_08BIT, 0x33, 0x94},
+ {0x72, CRL_REG_LEN_08BIT, 0x11, 0x94},
+ {0xF0, CRL_REG_LEN_08BIT, 0x00, 0x94},
+ {0x31, CRL_REG_LEN_08BIT, 0x82, 0x94},
+ {0x1E, CRL_REG_LEN_08BIT, 0x80, 0x94},
+ {0xDA, CRL_REG_LEN_08BIT, 0x01, 0x94},
+ {0x00, CRL_REG_LEN_08BIT, 0x24, 0x94},
+ {0xC1, CRL_REG_LEN_08BIT, 0x2B, 0x94},
+ {0x31, CRL_REG_LEN_08BIT, 0x80, 0x94},
+ {0xC9, CRL_REG_LEN_08BIT, 0x2D, 0x44},
+ {0x05, CRL_REG_LEN_08BIT, 0x54, 0xE0},
+ {0x8B, CRL_REG_LEN_08BIT, 0x43, 0x44}, /* shift 44 pixel to right */
+ {0x8C, CRL_REG_LEN_08BIT, 0xD4, 0x44},
+ {0x8B, CRL_REG_LEN_08BIT, 0x4F, 0x44},
+ {0x8D, CRL_REG_LEN_08BIT, 0xD4, 0x44},
+ {0x00, CRL_REG_LEN_DELAY, 0x05, 0x00},
+ {0x03, CRL_REG_LEN_08BIT, 0x00, 0xE0},
+ {0x04, CRL_REG_LEN_08BIT | CRL_REG_READ_AND_UPDATE, 0x00, 0xE0, 0xFD},
+ {0x37, CRL_REG_LEN_08BIT, 0x00, 0x44},
+};
+
+static struct crl_register_write_rep adv7481_hdmi_mode_480p[] = {
+ {0x00, CRL_REG_LEN_08BIT, 0x84, 0x94}, /* Enable 4-lane MIPI */
+ {0x00, CRL_REG_LEN_08BIT, 0xA4, 0x94}, /* Set Auto DPHY Timing */
+ {0x10, CRL_REG_LEN_08BIT | CRL_REG_READ_AND_UPDATE, 0xA0, 0xE0, 0xA0},
+ {0xD6, CRL_REG_LEN_08BIT, 0x07, 0x94},
+ {0xC4, CRL_REG_LEN_08BIT, 0x0A, 0x94},
+ {0x71, CRL_REG_LEN_08BIT, 0x33, 0x94},
+ {0x72, CRL_REG_LEN_08BIT, 0x11, 0x94},
+ {0xF0, CRL_REG_LEN_08BIT, 0x00, 0x94},
+ {0x31, CRL_REG_LEN_08BIT, 0x82, 0x94},
+ {0x1E, CRL_REG_LEN_08BIT, 0x80, 0x94},
+ {0xDA, CRL_REG_LEN_08BIT, 0x01, 0x94},
+ {0x00, CRL_REG_LEN_08BIT, 0x24, 0x94},
+ {0xC1, CRL_REG_LEN_08BIT, 0x2B, 0x94},
+ {0x31, CRL_REG_LEN_08BIT, 0x80, 0x94},
+ {0xC9, CRL_REG_LEN_08BIT, 0x2D, 0x44},
+ {0x05, CRL_REG_LEN_08BIT, 0x4A, 0xE0},
+ {0x00, CRL_REG_LEN_DELAY, 0x05, 0x00},
+ {0x03, CRL_REG_LEN_08BIT, 0x00, 0xE0},
+ {0x04, CRL_REG_LEN_08BIT | CRL_REG_READ_AND_UPDATE, 0x00, 0xE0, 0xFD},
+ {0x37, CRL_REG_LEN_08BIT, 0x00, 0x44},
+};
+
+static struct crl_register_write_rep adv7481_hdmi_mode_720p[] = {
+ {0x00, CRL_REG_LEN_08BIT, 0x84, 0x94}, /* Enable 4-lane MIPI */
+ {0x00, CRL_REG_LEN_08BIT, 0xA4, 0x94}, /* Set Auto DPHY Timing */
+ {0x10, CRL_REG_LEN_08BIT | CRL_REG_READ_AND_UPDATE, 0xA0, 0xE0, 0xA0},
+ {0xD6, CRL_REG_LEN_08BIT, 0x07, 0x94},
+ {0xC4, CRL_REG_LEN_08BIT, 0x0A, 0x94},
+ {0x71, CRL_REG_LEN_08BIT, 0x33, 0x94},
+ {0x72, CRL_REG_LEN_08BIT, 0x11, 0x94},
+ {0xF0, CRL_REG_LEN_08BIT, 0x00, 0x94},
+ {0x31, CRL_REG_LEN_08BIT, 0x82, 0x94},
+ {0x1E, CRL_REG_LEN_08BIT, 0x80, 0x94},
+ {0xDA, CRL_REG_LEN_08BIT, 0x01, 0x94},
+ {0x00, CRL_REG_LEN_08BIT, 0x24, 0x94},
+ {0xC1, CRL_REG_LEN_08BIT, 0x2B, 0x94},
+ {0x31, CRL_REG_LEN_08BIT, 0x80, 0x94},
+ {0xC9, CRL_REG_LEN_08BIT, 0x2D, 0x44},
+ {0x05, CRL_REG_LEN_08BIT, 0x53, 0xE0},
+ {0x8B, CRL_REG_LEN_08BIT, 0x43, 0x44}, /* shift 40 pixel to right */
+ {0x8C, CRL_REG_LEN_08BIT, 0xD8, 0x44},
+ {0x8B, CRL_REG_LEN_08BIT, 0x4F, 0x44},
+ {0x8D, CRL_REG_LEN_08BIT, 0xD8, 0x44},
+ {0x00, CRL_REG_LEN_DELAY, 0x05, 0x00},
+ {0x03, CRL_REG_LEN_08BIT, 0x00, 0xE0},
+ {0x04, CRL_REG_LEN_08BIT | CRL_REG_READ_AND_UPDATE, 0x00, 0xE0, 0xFD},
+ {0x37, CRL_REG_LEN_08BIT, 0x00, 0x44},
+};
+
+static struct crl_register_write_rep adv7481_hdmi_mode_576p[] = {
+ {0x00, CRL_REG_LEN_08BIT, 0x84, 0x94}, /* Enable 4-lane MIPI */
+ {0x00, CRL_REG_LEN_08BIT, 0xA4, 0x94}, /* Set Auto DPHY Timing */
+ {0x10, CRL_REG_LEN_08BIT | CRL_REG_READ_AND_UPDATE, 0xA0, 0xE0, 0xA0},
+ {0xD6, CRL_REG_LEN_08BIT, 0x07, 0x94},
+ {0xC4, CRL_REG_LEN_08BIT, 0x0A, 0x94},
+ {0x71, CRL_REG_LEN_08BIT, 0x33, 0x94},
+ {0x72, CRL_REG_LEN_08BIT, 0x11, 0x94},
+ {0xF0, CRL_REG_LEN_08BIT, 0x00, 0x94},
+ {0x31, CRL_REG_LEN_08BIT, 0x82, 0x94},
+ {0x1E, CRL_REG_LEN_08BIT, 0x80, 0x94},
+ {0xDA, CRL_REG_LEN_08BIT, 0x01, 0x94},
+ {0x00, CRL_REG_LEN_08BIT, 0x24, 0x94},
+ {0xC1, CRL_REG_LEN_08BIT, 0x2B, 0x94},
+ {0x31, CRL_REG_LEN_08BIT, 0x80, 0x94},
+ {0xC9, CRL_REG_LEN_08BIT, 0x2D, 0x44},
+ {0x05, CRL_REG_LEN_08BIT, 0x4B, 0xE0},
+ {0x00, CRL_REG_LEN_DELAY, 0x05, 0x00},
+ {0x03, CRL_REG_LEN_08BIT, 0x00, 0xE0},
+ {0x04, CRL_REG_LEN_08BIT | CRL_REG_READ_AND_UPDATE, 0x00, 0xE0, 0xFD},
+ {0x37, CRL_REG_LEN_08BIT, 0x00, 0x44},
+};
+
+static struct crl_register_write_rep adv7481_hdmi_mode_576i[] = {
+ {0x00, CRL_REG_LEN_08BIT, 0x81, 0x94}, /* Enable 1-lane MIPI */
+ {0x00, CRL_REG_LEN_08BIT, 0xA1, 0x94}, /* Set Auto DPHY Timing */
+ {0x10, CRL_REG_LEN_08BIT | CRL_REG_READ_AND_UPDATE, 0xA0, 0xE0, 0xA0},
+ {0xD6, CRL_REG_LEN_08BIT, 0x07, 0x94},
+ {0xC4, CRL_REG_LEN_08BIT, 0x0A, 0x94},
+ {0x71, CRL_REG_LEN_08BIT, 0x33, 0x94},
+ {0x72, CRL_REG_LEN_08BIT, 0x11, 0x94},
+ {0xF0, CRL_REG_LEN_08BIT, 0x00, 0x94},
+ {0x31, CRL_REG_LEN_08BIT, 0x82, 0x94},
+ {0x1E, CRL_REG_LEN_08BIT, 0x80, 0x94},
+ {0xDA, CRL_REG_LEN_08BIT, 0x01, 0x94},
+ {0x00, CRL_REG_LEN_08BIT, 0x21, 0x94},
+ {0xC1, CRL_REG_LEN_08BIT, 0x2B, 0x94},
+ {0x31, CRL_REG_LEN_08BIT, 0x80, 0x94},
+ {0xC9, CRL_REG_LEN_08BIT, 0x2D, 0x44},
+ {0x05, CRL_REG_LEN_08BIT, 0x41, 0xE0},
+ {0x00, CRL_REG_LEN_DELAY, 0x05, 0x00},
+ {0x03, CRL_REG_LEN_08BIT, 0x00, 0xE0},
+ {0x04, CRL_REG_LEN_08BIT | CRL_REG_READ_AND_UPDATE, 0x00, 0xE0, 0xFD},
+ {0x37, CRL_REG_LEN_08BIT, 0x00, 0x44},
+};
+
+static struct crl_register_write_rep adv7481_hdmi_mode_480i[] = {
+ {0x00, CRL_REG_LEN_08BIT, 0x81, 0x94}, /* Enable 1-lane MIPI */
+ {0x00, CRL_REG_LEN_08BIT, 0xA1, 0x94}, /* Set Auto DPHY Timing */
+ {0x10, CRL_REG_LEN_08BIT | CRL_REG_READ_AND_UPDATE, 0xA0, 0xE0, 0xA0},
+ {0xD6, CRL_REG_LEN_08BIT, 0x07, 0x94},
+ {0xC4, CRL_REG_LEN_08BIT, 0x0A, 0x94},
+ {0x71, CRL_REG_LEN_08BIT, 0x33, 0x94},
+ {0x72, CRL_REG_LEN_08BIT, 0x11, 0x94},
+ {0xF0, CRL_REG_LEN_08BIT, 0x00, 0x94},
+ {0x31, CRL_REG_LEN_08BIT, 0x82, 0x94},
+ {0x1E, CRL_REG_LEN_08BIT, 0x80, 0x94},
+ {0xDA, CRL_REG_LEN_08BIT, 0x01, 0x94},
+ {0x00, CRL_REG_LEN_08BIT, 0x21, 0x94},
+ {0xC1, CRL_REG_LEN_08BIT, 0x2B, 0x94},
+ {0x31, CRL_REG_LEN_08BIT, 0x80, 0x94},
+ {0xC9, CRL_REG_LEN_08BIT, 0x2D, 0x44},
+ {0x05, CRL_REG_LEN_08BIT, 0x40, 0xE0},
+ {0x00, CRL_REG_LEN_DELAY, 0x05, 0x00},
+ {0x03, CRL_REG_LEN_08BIT, 0x00, 0xE0},
+ {0x04, CRL_REG_LEN_08BIT | CRL_REG_READ_AND_UPDATE, 0x00, 0xE0, 0xFD},
+ {0x37, CRL_REG_LEN_08BIT, 0x00, 0x44},
+};
+
+static struct crl_register_write_rep adv7481_hdmi_mode_vga[] = {
+ {0x00, CRL_REG_LEN_08BIT, 0x84, 0x94}, /* Enable 4-lane MIPI */
+ {0x00, CRL_REG_LEN_08BIT, 0xA4, 0x94}, /* Set Auto DPHY Timing */
+ {0x10, CRL_REG_LEN_08BIT | CRL_REG_READ_AND_UPDATE, 0xA0, 0xE0, 0xA0},
+ {0xD6, CRL_REG_LEN_08BIT, 0x07, 0x94},
+ {0xC4, CRL_REG_LEN_08BIT, 0x0A, 0x94},
+ {0x71, CRL_REG_LEN_08BIT, 0x33, 0x94},
+ {0x72, CRL_REG_LEN_08BIT, 0x11, 0x94},
+ {0xF0, CRL_REG_LEN_08BIT, 0x00, 0x94},
+ {0x31, CRL_REG_LEN_08BIT, 0x82, 0x94},
+ {0x1E, CRL_REG_LEN_08BIT, 0x80, 0x94},
+ {0xDA, CRL_REG_LEN_08BIT, 0x01, 0x94},
+ {0x00, CRL_REG_LEN_08BIT, 0x24, 0x94},
+ {0xC1, CRL_REG_LEN_08BIT, 0x2B, 0x94},
+ {0x31, CRL_REG_LEN_08BIT, 0x80, 0x94},
+ {0xC9, CRL_REG_LEN_08BIT, 0x2D, 0x44},
+ {0x05, CRL_REG_LEN_08BIT, 0x88, 0xE0},
+ {0x00, CRL_REG_LEN_DELAY, 0x05, 0x00},
+ {0x03, CRL_REG_LEN_08BIT, 0x00, 0xE0},
+ {0x04, CRL_REG_LEN_08BIT | CRL_REG_READ_AND_UPDATE, 0x00, 0xE0, 0xFD},
+ {0x37, CRL_REG_LEN_08BIT, 0x00, 0x44},
+};
+
+static struct crl_register_write_rep adv7481_hdmi_powerup_regset[] = {
+ {0x00, CRL_REG_LEN_08BIT, 0x84, 0x94}, /* Enable 4-lane MIPI */
+ {0x00, CRL_REG_LEN_08BIT, 0xA4, 0x94}, /* Set Auto DPHY Timing */
+ {0xDB, CRL_REG_LEN_08BIT, 0x10, 0x94}, /* ADI Required Write */
+ {0xD6, CRL_REG_LEN_08BIT, 0x07, 0x94}, /* ADI Required Write */
+ {0xC4, CRL_REG_LEN_08BIT, 0x0A, 0x94}, /* ADI Required Write */
+ {0x71, CRL_REG_LEN_08BIT, 0x33, 0x94}, /* ADI Required Write */
+ {0x72, CRL_REG_LEN_08BIT, 0x11, 0x94}, /* ADI Required Write */
+ {0xF0, CRL_REG_LEN_08BIT, 0x00, 0x94}, /* i2c_dphy_pwdn - 1'b0 */
+ {0x31, CRL_REG_LEN_08BIT, 0x82, 0x94}, /* ADI Required Write */
+ {0x1E, CRL_REG_LEN_08BIT, 0xC0, 0x94},
+ /* ADI Required Write, transmit only Frame Start/End packets */
+ {0xDA, CRL_REG_LEN_08BIT, 0x01, 0x94}, /* i2c_mipi_pll_en - 1'b1 */
+};
+
+static struct crl_register_write_rep adv7481_hdmi_streamon_regs[] = {
+ {0x00, CRL_REG_LEN_DELAY, 0x02, 0x00},
+ {0x00, CRL_REG_LEN_08BIT, 0x24, 0x94}, /* Power-up CSI-TX */
+ {0x00, CRL_REG_LEN_DELAY, 0x01, 0x00},
+ {0xC1, CRL_REG_LEN_08BIT, 0x2B, 0x94}, /* ADI recommended setting */
+ {0x00, CRL_REG_LEN_DELAY, 0x01, 0x00},
+ {0x31, CRL_REG_LEN_08BIT, 0x80, 0x94}, /* ADI recommended setting */
+};
+
+static struct crl_register_write_rep adv7481_hdmi_streamoff_regs[] = {
+ {0x31, CRL_REG_LEN_08BIT, 0x82, 0x94}, /* ADI Recommended Write */
+ {0x1E, CRL_REG_LEN_08BIT, 0x00, 0x94}, /* Reset the clock Lane */
+ {0x00, CRL_REG_LEN_08BIT, 0xA4, 0x94},
+ {0xDA, CRL_REG_LEN_08BIT, 0x00, 0x94},
+ /* i2c_mipi_pll_en -1'b0 Disable MIPI PLL */
+ {0xC1, CRL_REG_LEN_08BIT, 0x3B, 0x94},
+};
+
+static struct crl_pll_configuration adv7481_hdmi_pll_configurations[] = {
+ {
+ .input_clk = 24000000,
+ .op_sys_clk = 297000000,
+ .bitsperpixel = 16,
+ .pixel_rate_csi = 594000000,
+ .pixel_rate_pa = 594000000,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ .pll_regs_items = 0,
+ .pll_regs = NULL,
+ },
+ {
+ .input_clk = 24000000,
+ .op_sys_clk = 445500000,
+ .bitsperpixel = 24,
+ .pixel_rate_csi = 891000000,
+ .pixel_rate_pa = 891000000,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ .pll_regs_items = 0,
+ .pll_regs = NULL,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_hdmi_1080p_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_hdmi_720p_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1280,
+ .out_rect.height = 720,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_hdmi_VGA_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 640,
+ .out_rect.height = 480,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_hdmi_1080i_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 540,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_hdmi_480p_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 720,
+ .out_rect.height = 480,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_hdmi_480i_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 720,
+ .out_rect.height = 240,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_hdmi_576p_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 720,
+ .out_rect.height = 576,
+ },
+};
+
+static struct crl_subdev_rect_rep adv7481_hdmi_576i_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1920,
+ .out_rect.height = 1080,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1920,
+ .in_rect.height = 1080,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 720,
+ .out_rect.height = 288,
+ },
+};
+static struct crl_mode_rep adv7481_hdmi_modes[] = {
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_hdmi_1080p_rects),
+ .sd_rects = adv7481_hdmi_1080p_rects,
+ .binn_hor = 1,
+ .binn_vert = 1,
+ .scale_m = 1,
+ .width = 1920,
+ .height = 1080,
+ .mode_regs_items = ARRAY_SIZE(adv7481_hdmi_mode_1080p),
+ .mode_regs = adv7481_hdmi_mode_1080p,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ },
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_hdmi_720p_rects),
+ .sd_rects = adv7481_hdmi_720p_rects,
+ .binn_hor = 1,
+ .binn_vert = 1,
+ .scale_m = 1,
+ .width = 1280,
+ .height = 720,
+ .mode_regs_items = ARRAY_SIZE(adv7481_hdmi_mode_720p),
+ .mode_regs = adv7481_hdmi_mode_720p,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ },
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_hdmi_VGA_rects),
+ .sd_rects = adv7481_hdmi_VGA_rects,
+ .binn_hor = 3,
+ .binn_vert = 2,
+ .scale_m = 1,
+ .width = 640,
+ .height = 480,
+ .mode_regs_items = ARRAY_SIZE(adv7481_hdmi_mode_vga),
+ .mode_regs = adv7481_hdmi_mode_vga,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ },
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_hdmi_1080i_rects),
+ .sd_rects = adv7481_hdmi_1080i_rects,
+ .binn_hor = 1,
+ .binn_vert = 2,
+ .scale_m = 1,
+ .width = 1920,
+ .height = 540,
+ .mode_regs_items = ARRAY_SIZE(adv7481_hdmi_mode_1080i),
+ .mode_regs = adv7481_hdmi_mode_1080i,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ },
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_hdmi_480p_rects),
+ .sd_rects = adv7481_hdmi_480p_rects,
+ .binn_hor = 2,
+ .binn_vert = 2,
+ .scale_m = 1,
+ .width = 720,
+ .height = 480,
+ .mode_regs_items = ARRAY_SIZE(adv7481_hdmi_mode_480p),
+ .mode_regs = adv7481_hdmi_mode_480p,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ },
+
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_hdmi_480i_rects),
+ .sd_rects = adv7481_hdmi_480i_rects,
+ .binn_hor = 2,
+ .binn_vert = 4,
+ .scale_m = 1,
+ .width = 720,
+ .height = 240,
+ .mode_regs_items = ARRAY_SIZE(adv7481_hdmi_mode_480i),
+ .mode_regs = adv7481_hdmi_mode_480i,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ },
+
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_hdmi_576p_rects),
+ .sd_rects = adv7481_hdmi_576p_rects,
+ .binn_hor = 2,
+ .binn_vert = 1,
+ .scale_m = 1,
+ .width = 720,
+ .height = 576,
+ .mode_regs_items = ARRAY_SIZE(adv7481_hdmi_mode_576p),
+ .mode_regs = adv7481_hdmi_mode_576p,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ },
+ {
+ .sd_rects_items = ARRAY_SIZE(adv7481_hdmi_576i_rects),
+ .sd_rects = adv7481_hdmi_576i_rects,
+ .binn_hor = 2,
+ .binn_vert = 3,
+ .scale_m = 1,
+ .width = 720,
+ .height = 288,
+ .mode_regs_items = ARRAY_SIZE(adv7481_hdmi_mode_576i),
+ .mode_regs = adv7481_hdmi_mode_576i,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ },
+};
+
+static struct crl_sensor_subdev_config adv7481_hdmi_sensor_subdevs[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .name = "adv7481 hdmi binner",
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .name = "adv7481 hdmi pixel array",
+ },
+};
+
+static struct crl_sensor_limits adv7481_hdmi_sensor_limits = {
+ .x_addr_min = 0,
+ .y_addr_min = 0,
+ .x_addr_max = 1920,
+ .y_addr_max = 1080,
+ .min_frame_length_lines = 160,
+ .max_frame_length_lines = 65535,
+ .min_line_length_pixels = 6024,
+ .max_line_length_pixels = 32752,
+ .scaler_m_min = 1,
+ .scaler_m_max = 1,
+ .scaler_n_min = 1,
+ .scaler_n_max = 1,
+ .min_even_inc = 1,
+ .max_even_inc = 1,
+ .min_odd_inc = 1,
+ .max_odd_inc = 1,
+};
+
+static struct crl_csi_data_fmt adv7481_hdmi_crl_csi_data_fmt[] = {
+ {
+ .code = ICI_FORMAT_RGB565,
+ .pixel_order = CRL_PIXEL_ORDER_GRBG,
+ .bits_per_pixel = 16,
+ .regs_items = ARRAY_SIZE(adv7481_hdmi_mode_rgb565),
+ .regs = adv7481_hdmi_mode_rgb565,
+ },
+ {
+ .code = ICI_FORMAT_UYVY,
+ .pixel_order = CRL_PIXEL_ORDER_GRBG,
+ .bits_per_pixel = 16,
+ .regs_items = ARRAY_SIZE(adv7481_hdmi_mode_uyvy),
+ .regs = adv7481_hdmi_mode_uyvy,
+ },
+ {
+ .code = ICI_FORMAT_YUYV,
+ .pixel_order = CRL_PIXEL_ORDER_GRBG,
+ .bits_per_pixel = 16,
+ .regs_items = ARRAY_SIZE(adv7481_hdmi_mode_yuyv),
+ .regs = adv7481_hdmi_mode_yuyv,
+ },
+ {
+ .code = ICI_FORMAT_RGB888,
+ .pixel_order = CRL_PIXEL_ORDER_GRBG,
+ .bits_per_pixel = 24,
+ .regs_items = ARRAY_SIZE(adv7481_hdmi_mode_rgb888),
+ .regs = adv7481_hdmi_mode_rgb888,
+ },
+};
+
+static struct crl_ctrl_data adv7481_hdmi_ctrls[] = {
+ {
+ .sd_type = CRL_SUBDEV_TYPE_BINNER,
+ .op_type = CRL_CTRL_SET_OP,
+ .context = SENSOR_IDLE,
+ .ctrl_id = ICI_EXT_SD_PARAM_ID_LINK_FREQ,
+ .name = "CTRL_ID_LINK_FREQ",
+ .type = CRL_CTRL_TYPE_MENU_INT,
+ .data.int_menu.def = 0,
+ .data.int_menu.max = ARRAY_SIZE(adv7481_hdmi_pll_configurations) - 1,
+ .flags = 0,
+ .impact = CRL_IMPACTS_NO_IMPACT,
+ .regs_items = 0,
+ .regs = 0,
+ .dep_items = 0,
+ .dep_ctrls = 0,
+ },
+ {
+ .sd_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .op_type = CRL_CTRL_GET_OP,
+ .context = SENSOR_POWERED_ON,
+ .ctrl_id = ICI_EXT_SD_PARAM_ID_PIXEL_RATE,
+ .name = "CTRL_ID_PIXEL_RATE_PA",
+ .type = CRL_CTRL_TYPE_INTEGER,
+ .data.std_data.min = 0,
+ .data.std_data.max = 0,
+ .data.std_data.step = 1,
+ .data.std_data.def = 0,
+ .flags = 0,
+ .impact = CRL_IMPACTS_NO_IMPACT,
+ .regs_items = 0,
+ .regs = 0,
+ .dep_items = 0,
+ .dep_ctrls = 0,
+ },
+ {
+ .sd_type = CRL_SUBDEV_TYPE_BINNER,
+ .op_type = CRL_CTRL_GET_OP,
+ .context = SENSOR_POWERED_ON,
+ .ctrl_id = ICI_EXT_SD_PARAM_ID_PIXEL_RATE,
+ .name = "CTRL_ID_PIXEL_RATE_CSI",
+ .type = CRL_CTRL_TYPE_INTEGER,
+ .data.std_data.min = 0,
+ .data.std_data.max = 0,
+ .data.std_data.step = 1,
+ .data.std_data.def = 0,
+ .flags = 0,
+ .impact = CRL_IMPACTS_NO_IMPACT,
+ .regs_items = 0,
+ .regs = 0,
+ .dep_items = 0,
+ .dep_ctrls = 0,
+ },
+};
+
+int adv7481_sensor_init(struct i2c_client*);
+int adv7481_sensor_cleanup(struct i2c_client*);
+
+static struct crl_sensor_configuration adv7481_hdmi_crl_configuration = {
+
+ .sensor_init = adv7481_sensor_init,
+ .sensor_cleanup = adv7481_sensor_cleanup,
+
+ .onetime_init_regs_items = ARRAY_SIZE(adv7481_hdmi_onetime_init_regset),
+ .onetime_init_regs = adv7481_hdmi_onetime_init_regset,
+
+ .powerup_regs_items = ARRAY_SIZE(adv7481_hdmi_powerup_regset),
+ .powerup_regs = adv7481_hdmi_powerup_regset,
+
+ .poweroff_regs_items = ARRAY_SIZE(adv7481_hdmi_streamoff_regs),
+ .poweroff_regs = adv7481_hdmi_streamoff_regs,
+
+ .id_reg_items = 0,
+ .id_regs = NULL,
+
+ .subdev_items = ARRAY_SIZE(adv7481_hdmi_sensor_subdevs),
+ .subdevs = adv7481_hdmi_sensor_subdevs,
+
+ .sensor_limits = &adv7481_hdmi_sensor_limits,
+
+ .pll_config_items = ARRAY_SIZE(adv7481_hdmi_pll_configurations),
+ .pll_configs = adv7481_hdmi_pll_configurations,
+
+ .modes_items = ARRAY_SIZE(adv7481_hdmi_modes),
+ .modes = adv7481_hdmi_modes,
+
+ .streamon_regs_items = ARRAY_SIZE(adv7481_hdmi_streamon_regs),
+ .streamon_regs = adv7481_hdmi_streamon_regs,
+
+ .streamoff_regs_items = ARRAY_SIZE(adv7481_hdmi_streamoff_regs),
+ .streamoff_regs = adv7481_hdmi_streamoff_regs,
+
+ .ctrl_items = ARRAY_SIZE(adv7481_hdmi_ctrls),
+ .ctrl_bank = adv7481_hdmi_ctrls,
+
+ .csi_fmts_items = ARRAY_SIZE(adv7481_hdmi_crl_csi_data_fmt),
+ .csi_fmts = adv7481_hdmi_crl_csi_data_fmt,
+
+ .addr_len = CRL_ADDR_7BIT,
+};
+
+#endif /* __CRLMODULE_ADV7481_HDMI_CONFIGURATION_H_ */
diff --git a/drivers/media/i2c/crlmodule-lite/crl_magna_configuration_ti964.h b/drivers/media/i2c/crlmodule-lite/crl_magna_configuration_ti964.h
new file mode 100644
index 000000000000..c8d0d7b3550d
--- /dev/null
+++ b/drivers/media/i2c/crlmodule-lite/crl_magna_configuration_ti964.h
@@ -0,0 +1,297 @@
+/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) */
+/*
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#ifndef __CRLMODULE_MAGNA_TI964_CONFIGURATION_H_
+#define __CRLMODULE_MAGNA_TI964_CONFIGURATION_H_
+
+#include "crlmodule-sensor-ds.h"
+
+#define TI964_I2C_PHY_ADDR 0x3d
+
+static struct crl_pll_configuration magna_ti964_pll_configurations[] = {
+ {
+ .input_clk = 24000000,
+ .op_sys_clk = 400000000,
+ .bitsperpixel = 16,
+ .pixel_rate_csi = 529000000,
+ .pixel_rate_pa = 529000000, /* pixel_rate = MIPICLK*2 *4/12 */
+ .csi_lanes = 4,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ .pll_regs_items = 0,
+ .pll_regs = NULL,
+ },
+ {
+ .input_clk = 24000000,
+ .op_sys_clk = 400000000,
+ .bitsperpixel = 10,
+ .pixel_rate_csi = 529000000,
+ .pixel_rate_pa = 529000000, /* pixel_rate = MIPICLK*2 *4/12 */
+ .csi_lanes = 4,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ .pll_regs_items = 0,
+ .pll_regs = NULL,
+ },
+ {
+ .input_clk = 24000000,
+ .op_sys_clk = 400000000,
+ .bitsperpixel = 20,
+ .pixel_rate_csi = 529000000,
+ .pixel_rate_pa = 529000000, /* pixel_rate = MIPICLK*2 *4/12 */
+ .csi_lanes = 4,
+ .comp_items = 0,
+ .ctrl_data = 0,
+ .pll_regs_items = 0,
+ .pll_regs = NULL,
+ }
+};
+
+static struct crl_subdev_rect_rep magna_ti964_1280_720_rects[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1280,
+ .in_rect.height = 720,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1280,
+ .out_rect.height = 720,
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .in_rect.left = 0,
+ .in_rect.top = 0,
+ .in_rect.width = 1280,
+ .in_rect.height = 720,
+ .out_rect.left = 0,
+ .out_rect.top = 0,
+ .out_rect.width = 1280,
+ .out_rect.height = 720,
+ },
+};
+
+static struct crl_register_write_rep magna_ti964_powerup_regs[] = {
+ {0x4c, CRL_REG_LEN_08BIT, 0x1, TI964_I2C_PHY_ADDR}, /* Select RX port 0 */
+};
+
+static struct crl_register_write_rep magna_ti964_poweroff_regs[] = {
+ {0x1, CRL_REG_LEN_08BIT, 0x20, TI964_I2C_PHY_ADDR},
+};
+
+static struct crl_mode_rep magna_ti964_modes[] = {
+ {
+ .sd_rects_items = ARRAY_SIZE(magna_ti964_1280_720_rects),
+ .sd_rects = magna_ti964_1280_720_rects,
+ .binn_hor = 1,
+ .binn_vert = 1,
+ .scale_m = 1,
+ .width = 1280,
+ .height = 720,
+ .min_llp = 2250,
+ .min_fll = 1320,
+ },
+};
+
+static struct crl_sensor_subdev_config magna_ti964_subdevs[] = {
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .name = "ti964",
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_BINNER,
+ .name = "magna binner",
+ },
+ {
+ .subdev_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .name = "magna pixel array",
+ }
+};
+
+static struct crl_sensor_limits magna_ti964_limits = {
+ .x_addr_min = 0,
+ .y_addr_min = 0,
+ .x_addr_max = 1280,
+ .y_addr_max = 720,
+ .min_frame_length_lines = 240,
+ .max_frame_length_lines = 65535,
+ .min_line_length_pixels = 320,
+ .max_line_length_pixels = 32752,
+};
+
+static struct crl_csi_data_fmt magna_ti964_crl_csi_data_fmt[] = {
+ {
+ .code = ICI_FORMAT_YUYV,
+ .pixel_order = CRL_PIXEL_ORDER_IGNORE,
+ .bits_per_pixel = 16,
+ },
+ {
+ .code = ICI_FORMAT_UYVY,
+ .pixel_order = CRL_PIXEL_ORDER_IGNORE,
+ .bits_per_pixel = 16,
+ },
+};
+
+static struct crl_ctrl_data magna_ti964_ctrls[] = {
+ {
+ .sd_type = CRL_SUBDEV_TYPE_BINNER,
+ .op_type = CRL_CTRL_SET_OP,
+ .context = SENSOR_IDLE,
+ .ctrl_id = ICI_EXT_SD_PARAM_ID_LINK_FREQ,
+ .name = "CTRL_ID_LINK_FREQ",
+ .type = CRL_CTRL_TYPE_MENU_INT,
+ .data.int_menu.def = 0,
+ .data.int_menu.max = 0,
+ .data.int_menu.menu = 0,
+ .flags = 0,
+ .impact = CRL_IMPACTS_NO_IMPACT,
+ .regs_items = 0,
+ .regs = 0,
+ .dep_items = 0,
+ .dep_ctrls = 0,
+ },
+ {
+ .sd_type = CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+ .op_type = CRL_CTRL_GET_OP,
+ .context = SENSOR_POWERED_ON,
+ .ctrl_id = ICI_EXT_SD_PARAM_ID_PIXEL_RATE,
+ .name = "CTRL_ID_PIXEL_RATE_PA",
+ .type = CRL_CTRL_TYPE_INTEGER,
+ .data.std_data.min = 0,
+ .data.std_data.max = INT_MAX,
+ .data.std_data.step = 1,
+ .data.std_data.def = 0,
+ .flags = 0,
+ .impact = CRL_IMPACTS_NO_IMPACT,
+ .regs_items = 0,
+ .regs = 0,
+ .dep_items = 0,
+ .dep_ctrls = 0,
+ },
+ {
+ .sd_type = CRL_SUBDEV_TYPE_BINNER,
+ .op_type = CRL_CTRL_GET_OP,
+ .context = SENSOR_POWERED_ON,
+ .ctrl_id = ICI_EXT_SD_PARAM_ID_PIXEL_RATE,
+ .name = "CTRL_ID_PIXEL_RATE_CSI",
+ .type = CRL_CTRL_TYPE_INTEGER,
+ .data.std_data.min = 0,
+ .data.std_data.max = INT_MAX,
+ .data.std_data.step = 1,
+ .data.std_data.def = 0,
+ .flags = 0,
+ .impact = CRL_IMPACTS_NO_IMPACT,
+ .regs_items = 0,
+ .regs = 0,
+ .dep_items = 0,
+ .dep_ctrls = 0,
+ },
+};
+
+struct crl_register_write_rep magna_ti964_streamon_regs[] = {
+ {0x1f, CRL_REG_LEN_08BIT, 0x2, TI964_I2C_PHY_ADDR},
+ {0x33, CRL_REG_LEN_08BIT, 0x1, TI964_I2C_PHY_ADDR},
+ {0x6d, CRL_REG_LEN_08BIT, 0x7f, TI964_I2C_PHY_ADDR},
+ {0x7c, CRL_REG_LEN_08BIT, 0x80, TI964_I2C_PHY_ADDR},
+ {0x20, CRL_REG_LEN_08BIT, 0xe0, TI964_I2C_PHY_ADDR},
+};
+
+struct crl_register_write_rep magna_ti964_streamoff_regs[] = {
+ {0x6d, CRL_REG_LEN_08BIT, 0x7f, TI964_I2C_PHY_ADDR},
+ {0x7c, CRL_REG_LEN_08BIT, 0x81, TI964_I2C_PHY_ADDR},
+ {0x20, CRL_REG_LEN_08BIT, 0xf0, TI964_I2C_PHY_ADDR},
+};
+
+struct crl_register_write_rep magna_ti964_onetime_init_regs[] = {
+ {0x8, CRL_REG_LEN_08BIT, 0x1c, TI964_I2C_PHY_ADDR},
+ {0xa, CRL_REG_LEN_08BIT, 0x79, TI964_I2C_PHY_ADDR},
+ {0xb, CRL_REG_LEN_08BIT, 0x79, TI964_I2C_PHY_ADDR},
+ {0xd, CRL_REG_LEN_08BIT, 0xb9, TI964_I2C_PHY_ADDR},
+ {0x10, CRL_REG_LEN_08BIT, 0x91, TI964_I2C_PHY_ADDR},
+ {0x11, CRL_REG_LEN_08BIT, 0x85, TI964_I2C_PHY_ADDR},
+ {0x12, CRL_REG_LEN_08BIT, 0x89, TI964_I2C_PHY_ADDR},
+ {0x13, CRL_REG_LEN_08BIT, 0xc1, TI964_I2C_PHY_ADDR},
+ {0x17, CRL_REG_LEN_08BIT, 0xe1, TI964_I2C_PHY_ADDR},
+ {0x18, CRL_REG_LEN_08BIT, 0x0, TI964_I2C_PHY_ADDR}, /* Disable frame sync. */
+ {0x19, CRL_REG_LEN_08BIT, 0x0, TI964_I2C_PHY_ADDR}, /* Frame sync high time. */
+ {0x1a, CRL_REG_LEN_08BIT, 0x2, TI964_I2C_PHY_ADDR},
+ {0x1b, CRL_REG_LEN_08BIT, 0xa, TI964_I2C_PHY_ADDR}, /* Frame sync low time. */
+ {0x1c, CRL_REG_LEN_08BIT, 0xd3, TI964_I2C_PHY_ADDR},
+ {0x21, CRL_REG_LEN_08BIT, 0x43, TI964_I2C_PHY_ADDR}, /* Enable best effort mode. */
+ {0xb0, CRL_REG_LEN_08BIT, 0x10, TI964_I2C_PHY_ADDR},
+ {0xb1, CRL_REG_LEN_08BIT, 0x14, TI964_I2C_PHY_ADDR},
+ {0xb2, CRL_REG_LEN_08BIT, 0x1f, TI964_I2C_PHY_ADDR},
+ {0xb3, CRL_REG_LEN_08BIT, 0x8, TI964_I2C_PHY_ADDR},
+ {0x32, CRL_REG_LEN_08BIT, 0x1, TI964_I2C_PHY_ADDR}, /* Select CSI port 0 */
+ {0x4c, CRL_REG_LEN_08BIT, 0x1, TI964_I2C_PHY_ADDR}, /* Select RX port 0 */
+ {0x58, CRL_REG_LEN_08BIT, 0x58, TI964_I2C_PHY_ADDR},
+ {0x5c, CRL_REG_LEN_08BIT, 0x18, TI964_I2C_PHY_ADDR}, /* TI913 alias addr 0xc */
+ {0x6d, CRL_REG_LEN_08BIT, 0x7f, TI964_I2C_PHY_ADDR},
+ {0x70, CRL_REG_LEN_08BIT, 0x1e, TI964_I2C_PHY_ADDR}, /* YUV422_8 */
+ {0x7c, CRL_REG_LEN_08BIT, 0x81, TI964_I2C_PHY_ADDR}, /* Use RAW10 8bit mode */
+ {0xd2, CRL_REG_LEN_08BIT, 0x84, TI964_I2C_PHY_ADDR},
+ {0x4c, CRL_REG_LEN_08BIT, 0x12, TI964_I2C_PHY_ADDR}, /* Select RX port 1 */
+ {0x58, CRL_REG_LEN_08BIT, 0x58, TI964_I2C_PHY_ADDR},
+ {0x5c, CRL_REG_LEN_08BIT, 0x1a, TI964_I2C_PHY_ADDR}, /* TI913 alias addr 0xd */
+ {0x6d, CRL_REG_LEN_08BIT, 0x7f, TI964_I2C_PHY_ADDR},
+ {0x70, CRL_REG_LEN_08BIT, 0x5e, TI964_I2C_PHY_ADDR}, /* YUV422_8 */
+ {0x7c, CRL_REG_LEN_08BIT, 0x81, TI964_I2C_PHY_ADDR}, /* Use RAW10 8bit mode */
+ {0xd2, CRL_REG_LEN_08BIT, 0x84, TI964_I2C_PHY_ADDR},
+ {0x4c, CRL_REG_LEN_08BIT, 0x24, TI964_I2C_PHY_ADDR}, /* Select RX port 2*/
+ {0x58, CRL_REG_LEN_08BIT, 0x58, TI964_I2C_PHY_ADDR},
+ {0x5c, CRL_REG_LEN_08BIT, 0x1c, TI964_I2C_PHY_ADDR}, /* TI913 alias addr 0xe */
+ {0x6d, CRL_REG_LEN_08BIT, 0x7f, TI964_I2C_PHY_ADDR},
+ {0x70, CRL_REG_LEN_08BIT, 0x9e, TI964_I2C_PHY_ADDR}, /* YUV422_8 */
+ {0x7c, CRL_REG_LEN_08BIT, 0x81, TI964_I2C_PHY_ADDR}, /* Use RAW10 8bit mode */
+ {0xd2, CRL_REG_LEN_08BIT, 0x84, TI964_I2C_PHY_ADDR},
+ {0x4c, CRL_REG_LEN_08BIT, 0x38, TI964_I2C_PHY_ADDR}, /* Select RX port3 */
+ {0x58, CRL_REG_LEN_08BIT, 0x58, TI964_I2C_PHY_ADDR},
+ {0x5c, CRL_REG_LEN_08BIT, 0x1e, TI964_I2C_PHY_ADDR}, /* TI913 alias addr 0xf */
+ {0x6d, CRL_REG_LEN_08BIT, 0x7f, TI964_I2C_PHY_ADDR},
+ {0x70, CRL_REG_LEN_08BIT, 0xde, TI964_I2C_PHY_ADDR}, /* YUV422_8 */
+ {0x7c, CRL_REG_LEN_08BIT, 0x81, TI964_I2C_PHY_ADDR}, /* Use RAW10 8bit mode */
+ {0xd2, CRL_REG_LEN_08BIT, 0x84, TI964_I2C_PHY_ADDR},
+ {0x6e, CRL_REG_LEN_08BIT, 0x89, TI964_I2C_PHY_ADDR},
+};
+
+struct crl_sensor_configuration magna_ti964_crl_configuration = {
+
+ .powerup_regs_items = ARRAY_SIZE(magna_ti964_powerup_regs),
+ .powerup_regs = magna_ti964_powerup_regs,
+
+ .poweroff_regs_items = ARRAY_SIZE(magna_ti964_poweroff_regs),
+ .poweroff_regs = magna_ti964_poweroff_regs,
+
+ .onetime_init_regs_items = ARRAY_SIZE(magna_ti964_onetime_init_regs),
+ .onetime_init_regs = magna_ti964_onetime_init_regs,
+
+ .subdev_items = ARRAY_SIZE(magna_ti964_subdevs),
+ .subdevs = magna_ti964_subdevs,
+
+ .pll_config_items = ARRAY_SIZE(magna_ti964_pll_configurations),
+ .pll_configs = magna_ti964_pll_configurations,
+
+ .sensor_limits = &magna_ti964_limits,
+
+ .modes_items = ARRAY_SIZE(magna_ti964_modes),
+ .modes = magna_ti964_modes,
+
+ .streamon_regs_items = ARRAY_SIZE(magna_ti964_streamon_regs),
+ .streamon_regs = magna_ti964_streamon_regs,
+
+ .streamoff_regs_items = ARRAY_SIZE(magna_ti964_streamoff_regs),
+ .streamoff_regs = magna_ti964_streamoff_regs,
+
+ .ctrl_items = ARRAY_SIZE(magna_ti964_ctrls),
+ .ctrl_bank = magna_ti964_ctrls,
+
+ .csi_fmts_items = ARRAY_SIZE(magna_ti964_crl_csi_data_fmt),
+ .csi_fmts = magna_ti964_crl_csi_data_fmt,
+
+ .addr_len = CRL_ADDR_8BIT,
+};
+
+#endif /* __CRLMODULE_MAGNA_TI964_CONFIGURATION_H_ */
diff --git a/drivers/media/i2c/crlmodule-lite/crlmodule-core.c b/drivers/media/i2c/crlmodule-lite/crlmodule-core.c
new file mode 100644
index 000000000000..59896f45b0db
--- /dev/null
+++ b/drivers/media/i2c/crlmodule-lite/crlmodule-core.c
@@ -0,0 +1,2696 @@
+// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
+/*
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include <media/ici.h>
+
+#include "crlmodule.h"
+#include "crlmodule-nvm.h"
+#include "crlmodule-regs.h"
+#include "crlmodule-msrlist.h"
+
+static int init_ext_sd(struct i2c_client *client,
+ struct crl_subdev *ssd, int idx);
+static void crlmodule_update_current_mode(struct crl_sensor *sensor);
+
+static int __crlmodule_get_variable_ref(struct crl_sensor *sensor,
+ enum crl_member_data_reference_ids ref,
+ u32 *val)
+{
+ switch (ref) {
+ case CRL_VAR_REF_OUTPUT_WIDTH:
+ *val = sensor->src->crop[CRL_PAD_SRC].width;
+ break;
+ case CRL_VAR_REF_OUTPUT_HEIGHT:
+ *val = sensor->src->crop[CRL_PAD_SRC].height;
+ break;
+ case CRL_VAR_REF_BITSPERPIXEL:
+ *val = sensor->sensor_ds->csi_fmts[
+ sensor->fmt_index].bits_per_pixel;
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ return 0;
+}
+
+/*
+ * Get the data format index from the configuration definition data
+ */
+static int __crlmodule_get_data_fmt_index(struct crl_sensor *sensor,
+ u32 code)
+{
+ unsigned int i;
+
+ for (i = 0; i < sensor->sensor_ds->csi_fmts_items; i++) {
+ if (sensor->sensor_ds->csi_fmts[i].code == code)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * Find the index of the ctrl pointer from the array of ctrls
+ * maintained by the CRL module based on the ctrl id.
+ */
+static int __crlmodule_get_crl_ctrl_index(struct crl_sensor *sensor,
+ u32 id, unsigned int *index)
+{
+ unsigned int i;
+
+ for (i = 0; i < sensor->sensor_ds->ctrl_items; i++)
+ if (sensor->ctrl_bank[i].ctrl_id == id)
+ break;
+
+ if (i >= sensor->sensor_ds->ctrl_items)
+ return -EINVAL;
+
+ *index = i;
+ return 0;
+}
+
+/*
+ * Finds the value of a specific ctrl based on the ctrl-id
+ */
+static int __crlmodule_get_param_value(struct crl_sensor *sensor,
+ u32 id, u32 *val)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ unsigned int i;
+ int ret;
+ struct ici_ext_sd_param* param;
+
+ ret = __crlmodule_get_crl_ctrl_index(sensor, id, &i);
+ if (ret)
+ return ret;
+
+ /* If no corresponding ctrl created, return */
+ if (sensor->ctrl_bank[i].param.id != id) {
+ dev_dbg(&client->dev,
+ "%s ctrl_id: 0x%x desc: %s not ready\n", __func__, id,
+ sensor->ctrl_bank[i].name);
+ return -ENODATA;
+ }
+
+ param = &sensor->ctrl_bank[i].param;
+ switch (sensor->ctrl_bank[i].type) {
+ case CRL_CTRL_TYPE_MENU_INT:
+ if (param->val <= sensor->ctrl_bank[i].data.int_menu.max)
+ *val = sensor->ctrl_bank[i].data.int_menu.menu[param->val];
+ else
+ *val = 0;
+ break;
+ case CRL_CTRL_TYPE_INTEGER:
+ default:
+ *val = param->val;
+ break;
+ }
+
+
+ dev_dbg(&client->dev, "%s ctrl_id: 0x%x desc: %s val: %d\n",
+ __func__, id,
+ sensor->ctrl_bank[i].name, *val);
+ return 0;
+}
+
+/*
+ * Finds the v4l2 based on the control id
+ */
+static struct crl_ctrl_data *__crlmodule_get_ctrl(
+ struct crl_sensor *sensor,
+ u32 id)
+{
+ unsigned int i;
+
+ if (__crlmodule_get_crl_ctrl_index(sensor, id, &i))
+ return NULL;
+
+ return &sensor->ctrl_bank[i];
+}
+
+/*
+ * Grab / Release controls based on the ctrl update context
+ */
+static void __crlmodule_enable_param(struct crl_sensor *sensor,
+ enum crl_ctrl_update_context ctxt,
+ bool enable)
+{
+ struct crl_ctrl_data *crl_ctrl;
+ unsigned int i;
+
+ for (i = 0; i < sensor->sensor_ds->ctrl_items; i++) {
+ crl_ctrl = &sensor->ctrl_bank[i];
+
+ if (crl_ctrl->context == ctxt)
+ crl_ctrl->enabled = enable;
+ }
+}
+
+/*
+ * Checks if the ctrl sepecific data is satisfied in the mode and PLL
+ * selection logic.
+ */
+static bool __crlmodule_compare_ctrl_specific_data(
+ struct crl_sensor *sensor,
+ unsigned int items,
+ struct crl_ctrl_data_pair *ctrl_val)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ unsigned int i;
+ u32 val;
+ int ret;
+
+ /* Go through all the controls associated with this config */
+ for (i = 0; i < items; i++) {
+ /* Get the value set for the control */
+ ret = __crlmodule_get_param_value(sensor, ctrl_val[i].ctrl_id,
+ &val);
+ if (ret) {
+ dev_err(&client->dev, "%s ctrl_id: 0x%x not found\n",
+ __func__, ctrl_val[i].ctrl_id);
+ return false;
+ }
+
+ /* Compare the value from the sensor definition file config */
+ if (val != ctrl_val[i].data) {
+ dev_err(&client->dev,
+ "%s ctrl_id: 0x%x value not match %d != %d\n",
+ __func__, ctrl_val[i].ctrl_id, val,
+ ctrl_val[i].data);
+ return false;
+ }
+ }
+
+ dev_dbg(&client->dev, "%s success\n", __func__);
+ return true;
+}
+
+/*
+ * Finds the correct PLL settings index based on the parameters
+ */
+static int __crlmodule_update_pll_index(struct crl_sensor *sensor,
+ struct crl_ctrl_data *crl_ctrl)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ const struct crl_pll_configuration *pll_config;
+ const struct crl_csi_data_fmt *fmts =
+ &sensor->sensor_ds->csi_fmts[sensor->fmt_index];
+ unsigned int i;
+ u32 link_freq = 0;
+
+ if (!sensor->link_freq ||
+ sensor->link_freq->type != CRL_CTRL_TYPE_MENU_INT) {
+ dev_err(&client->dev, "%s Invalid link freq ctrl\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ sensor->link_freq->param.val = crl_ctrl->param.val;
+ if (crl_ctrl->param.val <=
+ sensor->link_freq->data.int_menu.max) {
+ link_freq =sensor->link_freq->data.int_menu.menu[
+ crl_ctrl->param.val];
+ }
+
+ dev_dbg(&client->dev, "%s PLL Items: %d link_freq: %d\n",
+ __func__, sensor->sensor_ds->pll_config_items,
+ link_freq);
+
+ for (i = 0; i < sensor->sensor_ds->pll_config_items; i++) {
+ pll_config = &sensor->sensor_ds->pll_configs[i];
+
+ if (pll_config->op_sys_clk != link_freq)
+ continue;
+
+ if (pll_config->input_clk != sensor->platform_data->ext_clk)
+ continue;
+
+ /* if pll_config->csi_lanes == 0, lanes do not matter */
+ if (pll_config->csi_lanes)
+ if (sensor->platform_data->lanes != pll_config->csi_lanes)
+ continue;
+
+ /* PLL config must match to bpps*/
+ if (fmts->bits_per_pixel != pll_config->bitsperpixel)
+ continue;
+
+ /* Check if there are any dynamic compare items */
+ if (sensor->ext_ctrl_impacts_pll_selection &&
+ !__crlmodule_compare_ctrl_specific_data(sensor,
+ pll_config->comp_items,
+ pll_config->ctrl_data))
+ continue;
+
+ /* Found PLL index */
+ dev_dbg(&client->dev, "%s Found PLL index: %d for freq: %d\n",
+ __func__, i, link_freq);
+
+ sensor->pll_index = i;
+
+ /* Update the control values for pixelrate_pa and csi */
+ sensor->pixel_rate_pa->param.s64val = pll_config->pixel_rate_pa;
+ sensor->pixel_rate_csi->param.s64val = pll_config->pixel_rate_csi;
+ return 0;
+ }
+
+ dev_err(&client->dev, "%s no configuration found for freq: %d\n",
+ __func__, link_freq);
+ return -EINVAL;
+}
+
+/*
+ * Perform the action for the dependency control
+ */
+static void __crlmodule_dep_ctrl_perform_action(
+ struct crl_sensor *sensor,
+ struct crl_dep_ctrl_provision *prov,
+ u32 *val, u32 *dep_val)
+{
+ enum crl_dep_ctrl_condition cond;
+ unsigned int i;
+ u32 temp;
+
+ if (*val > *dep_val)
+ cond = CRL_DEP_CTRL_CONDITION_GREATER;
+ else if (*val < *dep_val)
+ cond = CRL_DEP_CTRL_CONDITION_LESSER;
+ else
+ cond = CRL_DEP_CTRL_CONDITION_EQUAL;
+
+ for (i = 0; i < prov->action_items; i++) {
+ if (prov->action[i].cond == cond)
+ break;
+ }
+
+ /* No handler found-. Return completed */
+ if (i >= prov->action_items)
+ return;
+
+ /* if this is dependency control, switch val and dep val */
+ if (prov->action_type == CRL_DEP_CTRL_ACTION_TYPE_DEP_CTRL) {
+ temp = *val;
+ *val = *dep_val;
+ *dep_val = temp;
+ }
+
+ switch (prov->action[i].action) {
+ case CRL_DEP_CTRL_CONDITION_ADD:
+ *val = *dep_val + prov->action[i].action_value;
+ break;
+ case CRL_DEP_CTRL_CONDITION_SUBTRACT:
+ *val = *dep_val - prov->action[i].action_value;
+ break;
+ case CRL_DEP_CTRL_CONDITION_MULTIPLY:
+ *val = *dep_val * prov->action[i].action_value;
+ break;
+ case CRL_DEP_CTRL_CONDITION_DIVIDE:
+ *val = *dep_val / prov->action[i].action_value;
+ break;
+ }
+
+ /* if this is dependency control, switch val and dep val back*/
+ if (prov->action_type == CRL_DEP_CTRL_ACTION_TYPE_DEP_CTRL) {
+ temp = *val;
+ *val = *dep_val;
+ *dep_val = temp;
+ }
+
+ return;
+}
+
+/*
+ * Parse the dynamic entity based on the Operand type
+ */
+static int __crlmodule_parse_dynamic_entity(struct crl_sensor *sensor,
+ struct crl_dynamic_entity entity,
+ u32 *val)
+{
+ switch (entity.entity_type) {
+ case CRL_DYNAMIC_VAL_OPERAND_TYPE_CONST:
+ *val = entity.entity_val;
+ return 0;
+ case CRL_DYNAMIC_VAL_OPERAND_TYPE_VAR_REF:
+ return __crlmodule_get_variable_ref(sensor,
+ entity.entity_val, val);
+ case CRL_DYNAMIC_VAL_OPERAND_TYPE_CTRL_VAL:
+ return __crlmodule_get_param_value(sensor,
+ entity.entity_val, val);
+ case CRL_DYNAMIC_VAL_OPERAND_TYPE_REG_VAL: {
+ struct crl_register_read_rep reg;
+
+ /* Note: Only 8bit registers are supported. */
+ reg.address = entity.entity_val;
+ reg.len = CRL_REG_LEN_08BIT;
+ reg.mask = 0xff;
+ reg.dev_i2c_addr = CRL_I2C_ADDRESS_NO_OVERRIDE;
+ return crlmodule_read_reg(sensor, reg, val);
+ }
+ default:
+ break;
+ };
+
+ return -EINVAL;
+}
+
+static int __crlmodule_calc_dynamic_entity_values(
+ struct crl_sensor *sensor,
+ unsigned int ops_items,
+ struct crl_arithmetic_ops *ops_arr,
+ unsigned int *val)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ unsigned int i;
+
+ /* perform the bitwise operation on val one by one */
+ for (i = 0; i < ops_items; i++) {
+ struct crl_arithmetic_ops *ops = &ops_arr[i];
+ u32 operand;
+ int ret = __crlmodule_parse_dynamic_entity(sensor, ops->operand,
+ &operand);
+ if (ret) {
+ dev_dbg(&client->dev,
+ "%s failed to parse dynamic entity: %d %d\n",
+ __func__, ops->operand.entity_type,
+ ops->operand.entity_val);
+ return ret;
+ }
+
+ switch (ops->op) {
+ case CRL_BITWISE_AND:
+ *val &= operand;
+ break;
+ case CRL_BITWISE_OR:
+ *val |= operand;
+ break;
+ case CRL_BITWISE_LSHIFT:
+ *val <<= operand;
+ break;
+ case CRL_BITWISE_RSHIFT:
+ *val >>= operand;
+ break;
+ case CRL_BITWISE_XOR:
+ *val ^= operand;
+ break;
+ case CRL_BITWISE_COMPLEMENT:
+ *val = ~(*val);
+ break;
+ case CRL_ADD:
+ *val += operand;
+ break;
+ case CRL_SUBTRACT:
+ *val = *val > operand ? *val - operand : operand - *val;
+ break;
+ case CRL_MULTIPLY:
+ *val *= operand;
+ break;
+ case CRL_DIV:
+ if(operand==0) {
+ dev_err(&client->dev, "CRL_DIV error for operand returned is zero.");
+ return -EINVAL;
+ }
+ *val /= operand;
+ break;
+ case CRL_ASSIGNMENT:
+ *val = operand;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Dynamic registers' value is not direct but depends on a referrence value.
+ * This kind of registers are mainly used in crlmodule's ctrl logic.
+ *
+ * This is to handle cases like the below examples, where mutliple registers
+ * need to be modified based on the input value "val"
+ * R3000 = val & 0xff and R3001 = val >> 8 & 0xff and R3002 = val >> 16 & 0xff
+ * R4001 = val and R4002 = val or
+ * R2800 = FLL - val and R2802 = LLP - val
+ */
+static int __crlmodule_update_dynamic_regs(struct crl_sensor *sensor,
+ struct crl_ctrl_data *crl_ctrl,
+ unsigned int val)
+{
+ unsigned int i;
+
+ for (i = 0; i < crl_ctrl->regs_items; i++) {
+ struct crl_dynamic_register_access *reg = &crl_ctrl->regs[i];
+ /*
+ * Each register group must start from the initial value, not
+ * as a continuation of the previous calculations. The sensor
+ * configurations must take care of this restriction.
+ */
+ u32 val_t = val;
+ int ret;
+
+ /* Get the value associated with the dynamic entity */
+ ret = __crlmodule_calc_dynamic_entity_values(sensor,
+ reg->ops_items,
+ reg->ops, &val_t);
+ if (ret)
+ return ret;
+
+ /* Now ready to write the value */
+ ret = crlmodule_write_reg(sensor, reg->dev_i2c_addr,
+ reg->address, reg->len,
+ reg->mask, val_t);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * Handles the dependency control actions. Dependency control is a control
+ * which' value depends on the current control. This information is encoded in
+ * the sensor configuration file.
+ */
+static int __crlmodule_handle_dependency_ctrl(
+ struct crl_sensor *sensor,
+ struct crl_ctrl_data *crl_ctrl,
+ unsigned int *val,
+ enum crl_dep_ctrl_action_type type)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ struct crl_ctrl_data *dep_crl_ctrl;
+ struct crl_dep_ctrl_provision *dep_prov;
+ unsigned int i, idx;
+ u32 dep_val;
+ int ret;
+
+ dev_dbg(&client->dev, "%s ctrl_id: 0x%x dependency controls: %d\n",
+ __func__, crl_ctrl->ctrl_id,
+ crl_ctrl->dep_items);
+
+ for (i = 0; i < crl_ctrl->dep_items; i++) {
+ dep_prov = &crl_ctrl->dep_ctrls[i];
+
+ /* If not the type, continue */
+ if (dep_prov->action_type != type)
+ continue;
+
+ /* Get the value from the dependency ctrl */
+ ret = __crlmodule_get_param_value(sensor, dep_prov->ctrl_id,
+ &dep_val);
+ if (ret) {
+ dev_err(&client->dev, "%s ctrl_id: 0x%x not found\n",
+ __func__, dep_prov->ctrl_id);
+ /* TODO! Shoud continue? */
+ continue;
+ }
+
+ /* Perform the action */
+ __crlmodule_dep_ctrl_perform_action(sensor, dep_prov, val,
+ &dep_val);
+
+ /* if this is dependency control, update the register */
+ if (dep_prov->action_type ==
+ CRL_DEP_CTRL_ACTION_TYPE_DEP_CTRL) {
+ ret = __crlmodule_get_crl_ctrl_index(sensor,
+ dep_prov->ctrl_id, &idx);
+ if (ret)
+ continue;
+
+ dep_crl_ctrl = &sensor->ctrl_bank[idx];
+ dev_dbg(&client->dev,
+ "%s crl_ctrl: 0x%p 0x%p\n", __func__,
+ &sensor->ctrl_bank[idx],
+ dep_crl_ctrl);
+
+ ret = __crlmodule_update_dynamic_regs(sensor,
+ dep_crl_ctrl, dep_val);
+ if (ret)
+ continue;
+ }
+ }
+ return 0;
+}
+
+
+static int crlmodule_get_fmt_index(struct crl_sensor *sensor,
+ u8 pixel_order, u8 bpp)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ const struct crl_csi_data_fmt *f;
+ int i;
+
+ /*
+ * Go through the fmt list and check if this format with matching bpp
+ * is supported by this module definition file
+ */
+ for (i = 0; i < sensor->sensor_ds->csi_fmts_items; i++) {
+ f = &sensor->sensor_ds->csi_fmts[i];
+
+ if (f->pixel_order == pixel_order && f->bits_per_pixel == bpp)
+ return i;
+ }
+
+ dev_err(&client->dev, "%s no supported format for order: %d bpp: %d\n",
+ __func__, pixel_order, bpp);
+
+ return -EINVAL;
+}
+
+static int __crlmodule_update_flip_info(struct crl_sensor *sensor,
+ struct crl_ctrl_data *crl_ctrl,
+ struct ici_ext_sd_param *param)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ const struct crl_csi_data_fmt *fmt =
+ &sensor->sensor_ds->csi_fmts[sensor->fmt_index];
+ u8 bpp = fmt->bits_per_pixel;
+ u8 flip_info = sensor->flip_info;
+ u8 new_order = 0;
+ int i, ret;
+
+ dev_dbg(&client->dev, "%s current flip_info: %d curr index: %d\n",
+ __func__, flip_info, sensor->fmt_index);
+
+ switch (param->id) {
+ case ICI_EXT_SD_PARAM_ID_HFLIP:
+ flip_info &= CRL_FLIP_HFLIP_MASK;
+ flip_info |= param->val > 0 ? CRL_FLIP_HFLIP : 0;
+ break;
+ case ICI_EXT_SD_PARAM_ID_VFLIP:
+ flip_info &= CRL_FLIP_VFLIP_MASK;
+ flip_info |= param->val > 0 ? CRL_FLIP_VFLIP : 0;
+ break;
+ }
+
+ dev_dbg(&client->dev, "%s flip success new flip_info: %d\n",
+ __func__, flip_info);
+
+ /* First check if the module actually supports any pixelorder changes */
+ for (i = 0; i < sensor->sensor_ds->flip_items; i++) {
+ if (flip_info == sensor->sensor_ds->flip_data[i].flip) {
+ new_order = sensor->sensor_ds->flip_data[i].pixel_order;
+ break;
+ }
+ }
+
+ if (i >= sensor->sensor_ds->flip_items) {
+ dev_err(&client->dev, "%s flip not supported %d\n",
+ __func__, flip_info);
+ return -EINVAL;
+ }
+
+ /*
+ * Flip changes only pixel order. So check if the supported format list
+ * has any format with new pixel order and current bits per pixel
+ */
+ i = crlmodule_get_fmt_index(sensor, new_order, bpp);
+ if (i < 0) {
+ dev_err(&client->dev, "%s no format found order: %d bpp: %d\n",
+ __func__, new_order, bpp);
+ return -EINVAL;
+ }
+
+ ret = __crlmodule_update_dynamic_regs(sensor, crl_ctrl, param->val);
+ if (ret) {
+ dev_err(&client->dev, "%s register access failed\n", __func__);
+ return ret;
+ }
+
+ /* New format found. Update info */
+ sensor->fmt_index = i;
+ sensor->flip_info = flip_info;
+
+ dev_dbg(&client->dev, "%s flip success flip: %d new fmt index: %d\n",
+ __func__, flip_info, i);
+
+ return 0;
+}
+static int __crlmodule_update_framesize(struct crl_sensor *sensor,
+ struct crl_ctrl_data *crl_ctrl,
+ struct ici_ext_sd_param *param)
+{
+ const struct crl_mode_rep *mode = sensor->current_mode;
+ unsigned int val;
+
+ switch (param->id) {
+ case ICI_EXT_SD_PARAM_ID_FRAME_LENGTH_LINES:
+ val = max(param->val, mode->min_fll);
+ break;
+ case ICI_EXT_SD_PARAM_ID_LINE_LENGTH_PIXELS:
+ val = max(param->val, mode->min_llp);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return __crlmodule_update_dynamic_regs(sensor, crl_ctrl, val);
+}
+static int __crlmodule_update_blanking(struct crl_sensor *sensor,
+ struct crl_ctrl_data *crl_ctrl,
+ struct ici_ext_sd_param *param)
+{
+ unsigned int val;
+
+ switch (param->id) {
+ case ICI_EXT_SD_PARAM_ID_HBLANK:
+ val = sensor->pixel_array->crop[CRL_PA_PAD_SRC].width +
+ param->val;
+ break;
+ case ICI_EXT_SD_PARAM_ID_VBLANK:
+ val = sensor->pixel_array->crop[CRL_PA_PAD_SRC].height +
+ param->val;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return __crlmodule_update_dynamic_regs(sensor, crl_ctrl, val);
+}
+
+static void __crlmodule_update_selection_impact_flags(
+ struct crl_sensor *sensor,
+ struct crl_ctrl_data *crl_ctrl)
+{
+ if (crl_ctrl->impact & CRL_IMPACTS_PLL_SELECTION)
+ sensor->ext_ctrl_impacts_pll_selection = true;
+
+ if (crl_ctrl->impact & CRL_IMPACTS_MODE_SELECTION)
+ sensor->ext_ctrl_impacts_mode_selection = true;
+}
+
+static struct crl_ctrl_data *__crlmodule_find_crlctrl(
+ struct crl_sensor *sensor,
+ struct ici_ext_sd_param *param)
+{
+ struct crl_ctrl_data *crl_ctrl;
+ unsigned int i;
+
+ for (i = 0; i < sensor->sensor_ds->ctrl_items; i++) {
+ crl_ctrl = &sensor->ctrl_bank[i];
+ if (crl_ctrl->param.sd == param->sd &&
+ crl_ctrl->ctrl_id == param->id)
+ return crl_ctrl;
+ }
+
+ return NULL;
+}
+
+static int crlmodule_set_param(struct ici_ext_sd_param *param)
+{
+ struct crl_sensor *sensor = to_crlmodule_sensor(param->sd);
+ struct i2c_client *client = sensor->src->sd.client;
+ struct crl_ctrl_data *crl_ctrl = NULL;
+ int ret = 0;
+
+ dev_dbg(&client->dev, "%s id:%d val:%d\n", __func__, param->id,
+ param->val);
+
+ /*
+ * Need to find the corresponding crlmodule wrapper for this param.
+ */
+ crl_ctrl = __crlmodule_find_crlctrl(sensor, param);
+ if (!crl_ctrl) {
+ dev_err(&client->dev, "%s ctrl :0x%x not supported\n",
+ __func__, param->id);
+ return -EINVAL;
+ }
+
+ dev_dbg(&client->dev, "%s id:0x%x name:%s\n", __func__, param->id,
+ crl_ctrl->name);
+
+ if (!crl_ctrl->enabled ||
+ crl_ctrl->flags & CRL_CTRL_FLAG_READ_ONLY) {
+ dev_err(&client->dev, "%s Control id:0x%x is not writeable\n",
+ __func__, param->id);
+ return -EINVAL;
+ }
+
+ if (param->type != ICI_EXT_SD_PARAM_TYPE_INT32) {
+ dev_err(&client->dev, "%s Control id:0x%x only INT32 is supported\n",
+ __func__, param->id);
+ return -EINVAL;
+ }
+
+ crl_ctrl->param.val = param->val;
+
+ /* Then go through the mandatory controls */
+ switch (param->id) {
+ case ICI_EXT_SD_PARAM_ID_LINK_FREQ:
+ /* Go through the supported list and compare the values */
+ ret = __crlmodule_update_pll_index(sensor, crl_ctrl);
+ goto out;
+ };
+
+ /* update the selection impacts flags */
+ __crlmodule_update_selection_impact_flags(sensor, crl_ctrl);
+
+ /*
+ * Dependency control is a control whose value is affected by the value
+ * for the current control. For example, vblank can be a dependency
+ * control for exposure. Whenever exposure changes, the sensor can
+ * automatically adjust the vblank or rely on manual adjustment. In
+ * case of manual adjustment the sensor configuration file needs to
+ * specify the dependency control, the condition for an action and
+ * typs of action.
+ *
+ * Now check if there is any dependency controls for this. And if there
+ * are any we need to split the action to two. First if the current
+ * control needs to be changed, then do it before updating the register.
+ * If some other control is affected, then do it after wrriting the
+ * current values
+ *
+ * Now check in the dependency control list, if the action type is
+ * "self" and update the value accordingly now
+ */
+ __crlmodule_handle_dependency_ctrl(sensor, crl_ctrl, &param->val,
+ CRL_DEP_CTRL_ACTION_TYPE_SELF);
+
+ /* Handle specific controls */
+ switch (param->id) {
+ case ICI_EXT_SD_PARAM_ID_HFLIP:
+ case ICI_EXT_SD_PARAM_ID_VFLIP:
+ ret = __crlmodule_update_flip_info(sensor, crl_ctrl, param);
+ goto out;
+
+ case ICI_EXT_SD_PARAM_ID_VBLANK:
+ case ICI_EXT_SD_PARAM_ID_HBLANK:
+ if (sensor->blanking_ctrl_not_use) {
+ dev_info(&client->dev, "%s Blanking controls are not used \
+ in this configuration, setting them has no effect\n", __func__);
+ /* Disable control*/
+ crl_ctrl->enabled = false;
+
+ } else {
+ ret = __crlmodule_update_blanking(sensor, crl_ctrl, param);
+ }
+ goto out;
+
+ case ICI_EXT_SD_PARAM_ID_FRAME_LENGTH_LINES:
+ case ICI_EXT_SD_PARAM_ID_LINE_LENGTH_PIXELS:
+ ret = __crlmodule_update_framesize(sensor, crl_ctrl, param);
+ goto out;
+
+ case ICI_EXT_SD_PARAM_ID_SENSOR_MODE:
+ sensor->sensor_mode = param->val;
+ crlmodule_update_current_mode(sensor);
+ goto out;
+ }
+
+ ret = __crlmodule_update_dynamic_regs(sensor, crl_ctrl, param->val);
+
+out:
+ /*
+ * Now check in the dependency control list, if the action type is
+ * "dependency control" and update the value accordingly now
+ */
+ if (!ret && crl_ctrl)
+ __crlmodule_handle_dependency_ctrl(sensor, crl_ctrl, &param->val,
+ CRL_DEP_CTRL_ACTION_TYPE_DEP_CTRL);
+
+ return ret;
+}
+
+static int crlmodule_get_param(struct ici_ext_sd_param *param)
+{
+ struct crl_sensor *sensor = to_crlmodule_sensor(param->sd);
+ struct i2c_client *client = sensor->src->sd.client;
+ struct crl_ctrl_data *crl_ctrl;
+ struct crl_dynamic_register_access *reg;
+
+ /*
+ * Need to find the corresponding crlmodule wrapper for this param.
+ */
+ crl_ctrl = __crlmodule_find_crlctrl(sensor, param);
+ if (!crl_ctrl) {
+ dev_err(&client->dev, "%s ctrl :0x%x not supported\n",
+ __func__, param->id);
+ return -EINVAL;
+ }
+
+ dev_dbg(&client->dev, "%s id:0x%x name:%s\n", __func__, param->id,
+ crl_ctrl->name);
+
+ if (crl_ctrl->flags & CRL_CTRL_FLAG_WRITE_ONLY) {
+ dev_err(&client->dev, "%s Control id:0x%x is not readable\n",
+ __func__, param->id);
+ return -EINVAL;
+ }
+
+ param->type = ICI_EXT_SD_PARAM_TYPE_INT32;
+ if (!(crl_ctrl->flags & CRL_CTRL_FLAG_READ_ONLY)) {
+ param->val = crl_ctrl->param.val;
+ return 0;
+ }
+
+ /*
+ * Found the crl control wrapper. Use the dynamic entity information
+ * to calculate the value for this control. For get control, there
+ * could be only one item in the crl_dynamic_register_access. ctrl->
+ * regs_items must be 1. Also the crl_dynamic_register_access.address
+ * and crl_dynamic_register_access.len are not used.
+ * Instead the values to be found or calculated need to be encoded into
+ * crl_dynamic_register_access.crl_arithmetic_ops. It has possibility
+ * to read from registers, existing control values and simple arithmetic
+ * operations etc.
+ */
+ if (!crl_ctrl->regs || !crl_ctrl->regs_items) {
+ dev_err(&client->dev, "%s no dynamic entities found\n",
+ __func__);
+ return -EINVAL;
+ }
+ if (crl_ctrl->regs_items > 1)
+ dev_warn(&client->dev,
+ "%s multiple dynamic entities, will skip the rest\n",
+ __func__);
+ reg = &crl_ctrl->regs[0];
+
+ /* Get the value associated with the dynamic entity */
+ return __crlmodule_calc_dynamic_entity_values(sensor, reg->ops_items,
+ reg->ops, &param->val);
+}
+
+static int crlmodule_get_menu_item(
+ struct ici_ext_sd_param *param, u32 idx)
+{
+ struct crl_sensor *sensor = to_crlmodule_sensor(param->sd);
+ struct i2c_client *client = sensor->src->sd.client;
+ struct crl_ctrl_data *crl_ctrl;
+
+ crl_ctrl = __crlmodule_find_crlctrl(sensor, param);
+ if (!crl_ctrl) {
+ dev_err(&client->dev, "%s ctrl :0x%x not supported\n",
+ __func__, param->id);
+ return -EINVAL;
+ }
+
+ if (idx > crl_ctrl->max) {
+ dev_err(&client->dev, "%s Control id:0x%x has invalid index %u\n",
+ __func__, param->id, idx);
+ return -EINVAL;
+ }
+ switch (crl_ctrl->type)
+ {
+ case CRL_CTRL_TYPE_MENU_INT:
+ param->type = ICI_EXT_SD_PARAM_TYPE_INT64;
+ param->s64val = crl_ctrl->data.int_menu.menu[idx];
+ break;
+ case CRL_CTRL_TYPE_MENU_ITEMS:
+ if (!param->custom.size || !param->custom.data) {
+ dev_err(&client->dev, "%s Control id:0x%x param->custom.data must be preallocated by caller\n",
+ __func__, param->id);
+ return -EINVAL;
+ }
+ param->type = ICI_EXT_SD_PARAM_TYPE_STR;
+ strncpy(param->custom.data,
+ crl_ctrl->data.menu_items.menu[idx],
+ param->custom.size - 1);
+ param->custom.data[param->custom.size - 1] = '\0';
+ break;
+ default:
+ dev_err(&client->dev, "%s Control id:0x%x does not have a menu\n",
+ __func__, param->id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int __crlmodule_init_link_freq_ctrl_menu(
+ struct crl_sensor *sensor,
+ struct crl_ctrl_data *crl_ctrl)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ unsigned int items = 0;
+ unsigned int i;
+
+ /* Cannot handle if the control type is not integer menu */
+ if (crl_ctrl->type != CRL_CTRL_TYPE_MENU_INT)
+ return 0;
+
+ /* If the menu contents exist, skip filling it dynamically */
+ if (crl_ctrl->data.int_menu.menu)
+ return 0;
+
+ sensor->link_freq_menu = devm_kzalloc(&client->dev, sizeof(s64) *
+ sensor->sensor_ds->pll_config_items,
+ GFP_KERNEL);
+ if (!sensor->link_freq_menu)
+ return -ENOMEM;
+
+ for (i = 0; i < sensor->sensor_ds->pll_config_items; i++) {
+ bool dup = false;
+ unsigned int j;
+
+ /*
+ * Skip the duplicate entries. We are using the value to match
+ * not the index
+ */
+ for (j = 0; j < items && !dup; j++)
+ dup = (sensor->link_freq_menu[j] ==
+ sensor->sensor_ds->pll_configs[i].op_sys_clk);
+ if (dup)
+ continue;
+
+ sensor->link_freq_menu[items] =
+ sensor->sensor_ds->pll_configs[i].op_sys_clk;
+ items++;
+ }
+
+ crl_ctrl->data.int_menu.menu = sensor->link_freq_menu;
+
+ /* items will not be 0 as there will be atleast one pll_config_item */
+ crl_ctrl->data.int_menu.max = items - 1;
+
+ return 0;
+}
+
+static int crlmodule_init_controls(struct crl_sensor *sensor)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ unsigned int pa_ctrls = 0;
+ unsigned int src_ctrls = 0;
+ struct crl_ctrl_data *crl_ctrl;
+ unsigned int i;
+ int rval;
+
+ sensor->ctrl_bank = devm_kzalloc(&client->dev,
+ sizeof(struct crl_ctrl_data) *
+ sensor->sensor_ds->ctrl_items,
+ GFP_KERNEL);
+ if (!sensor->ctrl_bank)
+ return -ENOMEM;
+
+ /* Prepare to initialise the ctrls from the crl wrapper */
+ for (i = 0; i < sensor->sensor_ds->ctrl_items; i++) {
+ /*
+ * First copy the ctrls to the sensor as there could be
+ * more than one similar sensors in a product which could share
+ * the same configuration files
+ */
+ sensor->ctrl_bank[i] =
+ sensor->sensor_ds->ctrl_bank[i];
+
+ crl_ctrl = &sensor->ctrl_bank[i];
+ crl_ctrl->param.id = crl_ctrl->ctrl_id;
+ if (crl_ctrl->sd_type == CRL_SUBDEV_TYPE_PIXEL_ARRAY) {
+ if (sensor->pixel_array) {
+ crl_ctrl->param.sd =
+ &sensor->pixel_array->sd;
+ }
+ pa_ctrls++;
+ }
+
+ if (crl_ctrl->sd_type == CRL_SUBDEV_TYPE_SCALER) {
+ if (sensor->scaler) {
+ crl_ctrl->param.sd =
+ &sensor->scaler->sd;
+ }
+ src_ctrls++;
+ }
+ if (crl_ctrl->sd_type == CRL_SUBDEV_TYPE_BINNER) {
+ if (sensor->binner) {
+ crl_ctrl->param.sd =
+ &sensor->binner->sd;
+ }
+ src_ctrls++;
+ }
+
+ /* populate the ctrl for the Link_freq dynamically */
+ if (crl_ctrl->ctrl_id == ICI_EXT_SD_PARAM_ID_LINK_FREQ &&
+ (crl_ctrl->sd_type == CRL_SUBDEV_TYPE_SCALER ||
+ crl_ctrl->sd_type == CRL_SUBDEV_TYPE_BINNER)) {
+ rval = __crlmodule_init_link_freq_ctrl_menu(sensor,
+ crl_ctrl);
+ if (rval)
+ return rval;
+ }
+ }
+ dev_dbg(&client->dev, "%s pa_ctrls: %d src_ctrls: %d\n", __func__,
+ pa_ctrls, src_ctrls);
+ for (i = 0; i < sensor->sensor_ds->ctrl_items; i++) {
+ crl_ctrl = &sensor->ctrl_bank[i];
+ switch (crl_ctrl->type) {
+ case CRL_CTRL_TYPE_MENU_ITEMS:
+ crl_ctrl->max = crl_ctrl->data.menu_items.size - 1;
+ break;
+ case CRL_CTRL_TYPE_MENU_INT:
+ crl_ctrl->max = crl_ctrl->data.int_menu.max;
+ crl_ctrl->def = crl_ctrl->data.int_menu.def;
+ break;
+ case CRL_CTRL_TYPE_INTEGER64:
+ case CRL_CTRL_TYPE_INTEGER:
+ case CRL_CTRL_TYPE_CUSTOM:
+ crl_ctrl->min = crl_ctrl->data.std_data.min;
+ crl_ctrl->max = crl_ctrl->data.std_data.max;
+ crl_ctrl->step = crl_ctrl->data.std_data.step;
+ crl_ctrl->def = crl_ctrl->data.std_data.def;
+ break;
+ case CRL_CTRL_TYPE_BOOLEAN:
+ case CRL_CTRL_TYPE_BUTTON:
+ case CRL_CTRL_TYPE_CTRL_CLASS:
+ default:
+ dev_err(&client->dev,
+ "%s Invalid control type\n", __func__);
+ continue;
+ break;
+ }
+
+ /*
+ * Blanking and framesize controls access to same register,
+ * Blank controls are disabled if framesize controls exists.
+ */
+ if (crl_ctrl->ctrl_id == ICI_EXT_SD_PARAM_ID_FRAME_LENGTH_LINES ||
+ crl_ctrl->ctrl_id == ICI_EXT_SD_PARAM_ID_LINE_LENGTH_PIXELS)
+ sensor->blanking_ctrl_not_use = 1;
+
+ if (crl_ctrl->ctrl_id == ICI_EXT_SD_PARAM_ID_SENSOR_MODE)
+ sensor->direct_mode_in_use = 1;
+
+ /* Save mandatory control references - link_freq in src sd */
+ if (crl_ctrl->ctrl_id == ICI_EXT_SD_PARAM_ID_LINK_FREQ &&
+ (crl_ctrl->sd_type == CRL_SUBDEV_TYPE_SCALER ||
+ crl_ctrl->sd_type == CRL_SUBDEV_TYPE_BINNER))
+ sensor->link_freq = crl_ctrl;
+
+ /* Save mandatory control references - pixel_rate_pa PA sd */
+ if (crl_ctrl->ctrl_id == ICI_EXT_SD_PARAM_ID_PIXEL_RATE &&
+ crl_ctrl->sd_type == CRL_SUBDEV_TYPE_PIXEL_ARRAY)
+ sensor->pixel_rate_pa = crl_ctrl;
+
+ /* Save mandatory control references - pixel_rate_csi src sd */
+ if (crl_ctrl->ctrl_id == ICI_EXT_SD_PARAM_ID_PIXEL_RATE &&
+ (crl_ctrl->sd_type == CRL_SUBDEV_TYPE_SCALER ||
+ crl_ctrl->sd_type == CRL_SUBDEV_TYPE_BINNER))
+ sensor->pixel_rate_csi = crl_ctrl;
+
+ dev_dbg(&client->dev,
+ "%s idx: %d ctrl_id: 0x%x ctrl_name: %s\n",
+ __func__, i, crl_ctrl->ctrl_id, crl_ctrl->name);
+ }
+
+ return 0;
+}
+
+
+static bool __crlmodule_rect_matches(struct i2c_client *client,
+ const struct ici_rect *const rect1,
+ const struct ici_rect *const rect2)
+{
+ dev_dbg(&client->dev, "%s rect1 l:%d t:%d w:%d h:%d\n", __func__,
+ rect1->left, rect1->top, rect1->width, rect1->height);
+ dev_dbg(&client->dev, "%s rect2 l:%d t:%d w:%d h:%d\n", __func__,
+ rect2->left, rect2->top, rect2->width, rect2->height);
+
+ return (rect1->left == rect2->left &&
+ rect1->top == rect2->top &&
+ rect1->width == rect2->width &&
+ rect1->height == rect2->height);
+}
+
+static int __crlmodule_update_hblank(struct crl_sensor *sensor,
+ struct crl_ctrl_data *hblank)
+{
+ const struct crl_mode_rep *mode = sensor->current_mode;
+ const struct crl_sensor_limits *limits = sensor->sensor_ds->sensor_limits;
+ unsigned int width = sensor->pixel_array->crop[CRL_PA_PAD_SRC].width;
+ unsigned int min_llp, max_llp;
+
+ if (mode->min_llp)
+ min_llp = mode->min_llp; /* mode specific limit */
+ else if (limits->min_line_length_pixels)
+ min_llp = limits->min_line_length_pixels; /* sensor limit */
+ else /* No restrictions */
+ min_llp = width;
+
+ if (mode->max_llp)
+ max_llp = mode->max_llp; /* mode specific limit */
+ else if (limits->min_line_length_pixels)
+ max_llp = limits->max_line_length_pixels; /* sensor limit */
+ else /* No restrictions */
+ max_llp = USHRT_MAX;
+
+ hblank->min = min_llp - width;
+ hblank->max = max_llp - width;
+ hblank->def = hblank->min;
+ return 0;
+}
+
+static int __crlmodule_update_vblank(struct crl_sensor *sensor,
+ struct crl_ctrl_data *vblank)
+{
+ const struct crl_mode_rep *mode = sensor->current_mode;
+ const struct crl_sensor_limits *limits = sensor->sensor_ds->sensor_limits;
+ unsigned int height = sensor->pixel_array->crop[CRL_PA_PAD_SRC].height;
+ unsigned int min_fll, max_fll;
+
+ if (mode->min_fll)
+ min_fll = mode->min_fll; /* mode specific limit */
+ else if (limits->min_frame_length_lines)
+ min_fll = limits->min_frame_length_lines; /* sensor limit */
+ else /* No restrictions */
+ min_fll = height;
+
+ if (mode->max_fll)
+ max_fll = mode->max_fll; /* mode specific limit */
+ else if (limits->min_line_length_pixels)
+ max_fll = limits->max_line_length_pixels; /* sensor limit */
+ else /* No restrictions */
+ max_fll = USHRT_MAX;
+
+ vblank->min = min_fll - height;
+ vblank->max = max_fll - height;
+ vblank->def = vblank->min;
+ return 0;
+}
+
+static void crlmodule_update_framesize(struct crl_sensor *sensor)
+{
+ const struct crl_mode_rep *mode = sensor->current_mode;
+ struct crl_ctrl_data *llength;
+ struct crl_ctrl_data *flength;
+
+ llength = __crlmodule_get_ctrl(sensor, ICI_EXT_SD_PARAM_ID_LINE_LENGTH_PIXELS);
+ flength = __crlmodule_get_ctrl(sensor, ICI_EXT_SD_PARAM_ID_FRAME_LENGTH_LINES);
+
+ if (llength) {
+ llength->min = mode->min_llp;
+ llength->def = llength->min;
+ }
+
+ if (flength) {
+ flength->min = mode->min_fll;
+ flength->def = flength->min;
+ }
+}
+
+static int crlmodule_update_frame_blanking(struct crl_sensor *sensor)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ struct crl_ctrl_data *vblank;
+ struct crl_ctrl_data *hblank;
+ int ret;
+
+ vblank = __crlmodule_get_ctrl(sensor, ICI_EXT_SD_PARAM_ID_VBLANK);
+ hblank = __crlmodule_get_ctrl(sensor, ICI_EXT_SD_PARAM_ID_HBLANK);
+
+ if (hblank) {
+ ret = __crlmodule_update_hblank(sensor, hblank);
+ if (ret)
+ return ret;
+ dev_dbg(&client->dev, "%s hblank:%d\n", __func__, hblank->param.val);
+ }
+
+ if (vblank) {
+ ret = __crlmodule_update_vblank(sensor, vblank);
+ if (ret)
+ return ret;
+ dev_dbg(&client->dev, "%s vblank:%d\n", __func__, vblank->param.val);
+ }
+
+ return 0;
+}
+
+static void crlmodule_update_mode_bysel(struct crl_sensor *sensor)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ const struct crl_mode_rep *this;
+ unsigned int i;
+
+ dev_dbg(&client->dev, "%s look for w: %d, h: %d, in [%d] modes\n",
+ __func__, sensor->src->crop[CRL_PAD_SRC].width,
+ sensor->src->crop[CRL_PAD_SRC].height,
+ sensor->sensor_ds->modes_items);
+
+ for (i = 0; i < sensor->sensor_ds->modes_items; i++) {
+ this = &sensor->sensor_ds->modes[i];
+
+ dev_dbg(&client->dev, "%s check mode list[%d] w: %d, h: %d\n",
+ __func__, i, this->width, this->height);
+ if (this->width != sensor->src->crop[CRL_PAD_SRC].width ||
+ this->height != sensor->src->crop[CRL_PAD_SRC].height)
+ continue;
+
+ if (sensor->pixel_array) {
+ dev_dbg(&client->dev, "%s Compare PA out rect\n", __func__);
+ if (!__crlmodule_rect_matches(client,
+ &sensor->pixel_array->crop[CRL_PA_PAD_SRC],
+ &this->sd_rects[CRL_SD_PA_INDEX].out_rect))
+ continue;
+ }
+ if (sensor->binner) {
+ dev_dbg(&client->dev, "%s binning hor: %d vs. %d\n",
+ __func__,
+ sensor->binning_horizontal,
+ this->binn_hor);
+ if (sensor->binning_horizontal != this->binn_hor)
+ continue;
+
+ dev_dbg(&client->dev, "%s binning vert: %d vs. %d\n",
+ __func__,
+ sensor->binning_vertical,
+ this->binn_vert);
+ if (sensor->binning_vertical != this->binn_vert)
+ continue;
+
+ dev_dbg(&client->dev, "%s binner in rect\n", __func__);
+ if (!__crlmodule_rect_matches(client,
+ &sensor->binner->crop[CRL_PAD_SINK],
+ &this->sd_rects[CRL_SD_BINNER_INDEX].in_rect))
+ continue;
+
+ dev_dbg(&client->dev, "%s binner out rect\n", __func__);
+ if (!__crlmodule_rect_matches(client,
+ &sensor->binner->crop[CRL_PAD_SRC],
+ &this->sd_rects[CRL_SD_BINNER_INDEX].out_rect))
+ continue;
+ }
+
+ if (sensor->scaler) {
+ dev_dbg(&client->dev, "%s scaler scale_m %d vs. %d\n",
+ __func__, sensor->scale_m,
+ this->scale_m);
+ if (sensor->scale_m != this->scale_m)
+ continue;
+
+ dev_dbg(&client->dev, "%s scaler in rect\n", __func__);
+ if (!__crlmodule_rect_matches(client,
+ &sensor->scaler->crop[CRL_PAD_SINK],
+ &this->sd_rects[CRL_SD_SCALER_INDEX].in_rect))
+ continue;
+
+ dev_dbg(&client->dev, "%s scaler out rect\n", __func__);
+ if (!__crlmodule_rect_matches(client,
+ &sensor->scaler->crop[CRL_PAD_SRC],
+ &this->sd_rects[CRL_SD_SCALER_INDEX].out_rect))
+ continue;
+ }
+
+ /* Check if there are any dynamic compare items */
+ if (sensor->ext_ctrl_impacts_mode_selection &&
+ !__crlmodule_compare_ctrl_specific_data(sensor,
+ this->comp_items,
+ this->ctrl_data))
+ continue;
+
+ /* Found a perfect match! */
+ dev_dbg(&client->dev, "%s found mode. idx: %d\n", __func__, i);
+ break;
+ }
+
+ /* If no modes found, fall back to the fail safe mode index */
+ if (i >= sensor->sensor_ds->modes_items) {
+ i = sensor->sensor_ds->fail_safe_mode_index;
+ this = &sensor->sensor_ds->modes[i];
+ dev_info(&client->dev,
+ "%s no matching mode, set to default: %d\n",
+ __func__, i);
+ }
+
+ sensor->current_mode = this;
+}
+
+static void crlmodule_update_mode_ctrl(struct crl_sensor *sensor)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ const struct crl_mode_rep *this;
+ int i;
+
+ dev_dbg(&client->dev, "%s Sensor Mode :%d\n",
+ __func__, sensor->sensor_mode);
+ /* point to selected mode */
+ this = &sensor->sensor_ds->modes[sensor->sensor_mode];
+ sensor->current_mode = this;
+
+ for (i = 0; i < this->sd_rects_items; i++) {
+
+ if (CRL_SUBDEV_TYPE_PIXEL_ARRAY ==
+ this->sd_rects[i].subdev_type) {
+ sensor->pixel_array->crop[CRL_PA_PAD_SRC] =
+ this->sd_rects[CRL_SD_PA_INDEX].out_rect;
+ }
+
+ if (CRL_SUBDEV_TYPE_BINNER ==
+ this->sd_rects[i].subdev_type) {
+ sensor->binner->sink_fmt =
+ this->sd_rects[i].in_rect;
+ sensor->binner->crop[CRL_PAD_SINK] =
+ this->sd_rects[i].in_rect;
+ sensor->binner->crop[CRL_PAD_SRC] =
+ this->sd_rects[i].out_rect;
+ sensor->binning_vertical = this->binn_vert;
+ sensor->binning_horizontal = this->binn_hor;
+ if (this->binn_vert > 1)
+ sensor->binner->compose =
+ this->sd_rects[i].out_rect;
+ }
+
+ if (CRL_SUBDEV_TYPE_SCALER ==
+ this->sd_rects[i].subdev_type) {
+ sensor->scaler->crop[CRL_PAD_SINK] =
+ this->sd_rects[i].in_rect;
+ sensor->scaler->crop[CRL_PAD_SRC] =
+ this->sd_rects[i].out_rect;
+ sensor->scaler->sink_fmt =
+ this->sd_rects[i].in_rect;
+ sensor->scale_m = this->scale_m;
+ if (this->scale_m != 1)
+ sensor->scaler->compose =
+ this->sd_rects[i].out_rect;
+ }
+ }
+
+ /* Set source */
+ sensor->src->crop[CRL_PAD_SRC].width = this->width;
+ sensor->src->crop[CRL_PAD_SRC].height = this->height;
+}
+
+static void crlmodule_update_current_mode(struct crl_sensor *sensor)
+{
+ const struct crl_mode_rep *this;
+ int i;
+
+ if (sensor->direct_mode_in_use)
+ crlmodule_update_mode_ctrl(sensor);
+ else
+ crlmodule_update_mode_bysel(sensor);
+
+ /*
+ * We have a valid mode now. If there are any mode specific "get"
+ * controls defined in the configuration it could be queried by the
+ * user space for any mode specific information. So go through the
+ * mode specific ctrls and update its value from the selected mode.
+ */
+
+ this = sensor->current_mode;
+
+ for (i = 0; i < this->comp_items; i++) {
+ struct crl_ctrl_data_pair *ctrl_comp = &this->ctrl_data[i];
+ unsigned int idx;
+
+ /* Get the ctl_ctrl pointer corresponding ctrl id */
+ if (__crlmodule_get_crl_ctrl_index(sensor, ctrl_comp->ctrl_id,
+ &idx))
+ /* If not found, move to the next ctrl */
+ continue;
+
+ /* No need to update this control, if this is a set op ctrl */
+ if (sensor->ctrl_bank[idx].op_type == CRL_CTRL_SET_OP)
+ continue;
+
+ /* Update the control value */
+ sensor->ctrl_bank[idx].param.val = ctrl_comp->data;
+ }
+
+ if (sensor->blanking_ctrl_not_use)
+ crlmodule_update_framesize(sensor);
+ else
+ crlmodule_update_frame_blanking(sensor);
+}
+
+/*
+ * Function main code replicated from /drivers/media/i2c/smiapp/smiapp-core.c
+ * Slightly modified based on the CRL Module changes
+ */
+static int __crlmodule_get_format(
+ struct ici_ext_subdev* subdev,
+ struct ici_pad_framefmt* pff)
+{
+ struct crl_subdev *ssd = to_crlmodule_subdev(subdev);
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+ struct ici_rect *r;
+
+ if (pff->pad.pad_idx == ssd->source_pad)
+ r = &ssd->crop[ssd->source_pad];
+ else
+ r = &ssd->sink_fmt;
+
+ pff->ffmt.width = r->width;
+ pff->ffmt.height = r->height;
+ pff->ffmt.pixelformat =
+ sensor->sensor_ds->csi_fmts[sensor->fmt_index].code;
+ pff->ffmt.field =
+ ((ssd->field == ICI_FIELD_ANY) ?
+ ICI_FIELD_NONE : ssd->field);
+ return 0;
+}
+
+/*
+ * Function main code replicated from /drivers/media/i2c/smiapp/smiapp-core.c
+ * Slightly modified based on the CRL Module changes
+ */
+static int crlmodule_enum_pixelformat(
+ struct ici_isys_node* node,
+ struct ici_pad_supported_format_desc* psfd)
+{
+ struct ici_ext_subdev* subdev = node->sd;
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+
+ if (psfd->idx >= sensor->sensor_ds->csi_fmts_items)
+ return -EINVAL;
+
+ psfd->color_format =
+ sensor->sensor_ds->csi_fmts[psfd->idx].code;
+ psfd->min_width = sensor->sensor_ds->sensor_limits->x_addr_min;
+ psfd->max_width = sensor->sensor_ds->sensor_limits->x_addr_max;
+ psfd->min_height = sensor->sensor_ds->sensor_limits->y_addr_min;
+ psfd->max_height = sensor->sensor_ds->sensor_limits->y_addr_max;
+ return 0;
+}
+
+/*
+ * Function main code replicated from /drivers/media/i2c/smiapp/smiapp-core.c
+ * Slightly modified based on the CRL Module changes
+ */
+static int crlmodule_get_format(
+ struct ici_isys_node* node,
+ struct ici_pad_framefmt* pff)
+{
+ struct ici_ext_subdev* subdev = node->sd;
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+ int rval;
+
+ mutex_lock(&sensor->mutex);
+ rval = __crlmodule_get_format(subdev, pff);
+ mutex_unlock(&sensor->mutex);
+
+ return rval;
+}
+
+static int __crlmodule_sel_supported(
+ struct ici_ext_subdev *subdev,
+ u32 pad,
+ u32 type)
+{
+ struct crl_subdev *ssd = to_crlmodule_subdev(subdev);
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+
+ if (ssd == sensor->pixel_array && pad == CRL_PA_PAD_SRC) {
+ switch (type) {
+ case ICI_EXT_SEL_TYPE_NATIVE:
+ case ICI_EXT_SEL_TYPE_CROP:
+ case ICI_EXT_SEL_TYPE_CROP_BOUNDS:
+ return 0;
+ }
+ }
+ if (ssd == sensor->binner) {
+ switch (type) {
+ case ICI_EXT_SEL_TYPE_COMPOSE:
+ case ICI_EXT_SEL_TYPE_COMPOSE_BOUNDS:
+ if (pad == CRL_PAD_SINK)
+ return 0;
+ break;
+ }
+ }
+ if (ssd == sensor->scaler) {
+ switch (type) {
+ case ICI_EXT_SEL_TYPE_CROP:
+ case ICI_EXT_SEL_TYPE_CROP_BOUNDS:
+ if (pad == CRL_PAD_SRC)
+ return 0;
+ break;
+ case ICI_EXT_SEL_TYPE_COMPOSE:
+ case ICI_EXT_SEL_TYPE_COMPOSE_BOUNDS:
+ if (pad == CRL_PAD_SINK)
+ return 0;
+ break;
+ }
+ }
+ return -EINVAL;
+}
+
+/*
+ * Function main code replicated from /drivers/media/i2c/smiapp/smiapp-core.c
+ * Slightly modified based on the CRL Module changes
+ */
+static void crlmodule_get_crop_compose(
+ struct ici_ext_subdev *subdev,
+ struct ici_rect **crops,
+ struct ici_rect **comps)
+{
+ struct crl_subdev *ssd = to_crlmodule_subdev(subdev);
+ unsigned int i;
+
+ /* Currently we support only 2 pads */
+ BUG_ON(subdev->num_pads > CRL_PADS);
+
+ if (crops)
+ for (i = 0; i < subdev->num_pads; i++)
+ crops[i] = &ssd->crop[i];
+ if (comps)
+ *comps = &ssd->compose;
+}
+
+/*
+ * Function main code replicated from /drivers/media/i2c/smiapp/smiapp-core.c
+ * Slightly modified based on the CRL Module changes
+ */
+static int crlmodule_get_selection(
+ struct ici_isys_node *node,
+ struct ici_pad_selection* ps)
+{
+ struct ici_ext_subdev *subdev = node->sd;
+ struct crl_subdev *ssd = to_crlmodule_subdev(subdev);
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+ struct ici_rect *comp, *crops[CRL_PADS];
+ struct ici_rect sink_fmt;
+ int ret;
+
+ ret = __crlmodule_sel_supported(subdev, ps->pad.pad_idx,
+ ps->sel_type);
+ if (ret)
+ return ret;
+
+ crlmodule_get_crop_compose(subdev, crops, &comp);
+
+ sink_fmt = ssd->sink_fmt;
+
+ switch (ps->sel_type) {
+ case ICI_EXT_SEL_TYPE_CROP_BOUNDS:
+ case ICI_EXT_SEL_TYPE_NATIVE:
+ if (ssd == sensor->pixel_array) {
+ ps->rect.left = ps->rect.top = 0;
+ ps->rect.width =
+ sensor->sensor_ds->sensor_limits->x_addr_max;
+ ps->rect.height =
+ sensor->sensor_ds->sensor_limits->y_addr_max;
+ } else if (ps->pad.pad_idx == ssd->sink_pad) {
+ ps->rect = sink_fmt;
+ } else {
+ ps->rect = *comp;
+ }
+ break;
+ case ICI_EXT_SEL_TYPE_CROP:
+ case ICI_EXT_SEL_TYPE_COMPOSE_BOUNDS:
+ ps->rect = *crops[ps->pad.pad_idx];
+ break;
+ case ICI_EXT_SEL_TYPE_COMPOSE:
+ ps->rect = *comp;
+ break;
+ }
+ return 0;
+}
+
+/*
+ * Function main code replicated from /drivers/media/i2c/smiapp/smiapp-core.c
+ * Slightly modified based on the CRL Module changes
+ */
+static void crlmodule_propagate(
+ struct ici_ext_subdev *subdev,
+ u32 type)
+{
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+ struct crl_subdev *ssd = to_crlmodule_subdev(subdev);
+ struct ici_rect *comp, *crops[CRL_PADS];
+
+ crlmodule_get_crop_compose(subdev, crops, &comp);
+
+ switch (type) {
+ case ICI_EXT_SEL_TYPE_CROP:
+ comp->width = crops[CRL_PAD_SINK]->width;
+ comp->height = crops[CRL_PAD_SINK]->height;
+ if (ssd == sensor->scaler) {
+ sensor->scale_m = 1;
+ } else if (ssd == sensor->binner) {
+ sensor->binning_horizontal = 1;
+ sensor->binning_vertical = 1;
+ }
+ /* Fall through */
+ case ICI_EXT_SEL_TYPE_COMPOSE:
+ *crops[CRL_PAD_SRC] = *comp;
+ break;
+ default:
+ BUG();
+ }
+}
+
+/*
+ * Function main code replicated from /drivers/media/i2c/smiapp/smiapp-core.c
+ * Slightly modified based on the CRL Module changes
+ */
+static int crlmodule_set_compose(
+ struct ici_ext_subdev *subdev,
+ struct ici_rect *r)
+{
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+ struct crl_subdev *ssd = to_crlmodule_subdev(subdev);
+ struct ici_rect *comp, *crops[CRL_PADS];
+
+ crlmodule_get_crop_compose(subdev, crops, &comp);
+
+ r->top = 0;
+ r->left = 0;
+
+ if (ssd == sensor->binner) {
+ sensor->binning_horizontal = crops[CRL_PAD_SINK]->width /
+ r->width;
+ sensor->binning_vertical = crops[CRL_PAD_SINK]->height /
+ r->height;
+ } else {
+ sensor->scale_m = crops[CRL_PAD_SINK]->width *
+ sensor->sensor_ds->sensor_limits->scaler_m_min /
+ r->width;
+ }
+
+ *comp = *r;
+
+ crlmodule_propagate(subdev,
+ ICI_EXT_SEL_TYPE_COMPOSE);
+
+ crlmodule_update_current_mode(sensor);
+ return 0;
+}
+
+/*
+ * Function main code replicated from /drivers/media/i2c/smiapp/smiapp-core.c
+ * Slightly modified based on the CRL Module changes
+ */
+static int crlmodule_set_crop(
+ struct ici_ext_subdev *subdev,
+ u32 pad,
+ struct ici_rect *r)
+{
+ struct crl_subdev *ssd = to_crlmodule_subdev(subdev);
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+ struct ici_rect *src_size, *crops[CRL_PADS];
+
+ crlmodule_get_crop_compose(subdev, crops, NULL);
+
+ if (pad == ssd->sink_pad)
+ src_size = &ssd->sink_fmt;
+ else
+ src_size = &ssd->compose;
+
+ if (ssd == sensor->src && pad == CRL_PAD_SRC) {
+ r->left = 0;
+ r->top = 0;
+ }
+
+ r->width = min(r->width, src_size->width);
+ r->height = min(r->height, src_size->height);
+
+ r->left = min_t(s32, r->left, src_size->width - r->width);
+ r->top = min_t(s32, r->top, src_size->height - r->height);
+
+ *crops[pad] = *r;
+
+ if (ssd != sensor->pixel_array && pad == CRL_PAD_SINK)
+ crlmodule_propagate(subdev,
+ ICI_EXT_SEL_TYPE_CROP);
+
+ /* TODO! Should we short list supported mode? */
+
+ return 0;
+}
+
+/*
+ * Function main code replicated from /drivers/media/i2c/smiapp/smiapp-core.c
+ * Modified based on the CRL Module changes
+ */
+static int crlmodule_set_format(
+ struct ici_isys_node *node,
+ struct ici_pad_framefmt *pff)
+{
+ struct ici_ext_subdev *subdev = node->sd;
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+ struct crl_subdev *ssd = to_crlmodule_subdev(subdev);
+ struct i2c_client *client = sensor->src->sd.client;
+ struct ici_rect *crops[CRL_PADS];
+
+ dev_dbg(&client->dev, "%s sd_name: %s pad: %d w: %d, h: %d code: 0x%x",
+ __func__, node->name, pff->pad.pad_idx,
+ pff->ffmt.width,
+ pff->ffmt.height,
+ pff->ffmt.pixelformat);
+
+ mutex_lock(&sensor->mutex);
+
+ /* Currently we only support ALTERNATE interlaced mode. */
+ if (pff->ffmt.field != ICI_FIELD_ALTERNATE)
+ pff->ffmt.field = ICI_FIELD_NONE;
+ pff->ffmt.colorspace = 0;
+ memset(pff->ffmt.reserved, 0, sizeof(pff->ffmt.reserved));
+ ssd->field = pff->ffmt.field;
+
+ if (pff->pad.pad_idx == ssd->source_pad) {
+ u32 code = pff->ffmt.pixelformat;
+ int rval = __crlmodule_get_format(subdev, pff);
+
+ if (!rval && subdev == &sensor->src->sd) {
+ /* Check if this code is supported, if yes get index */
+ int idx = __crlmodule_get_data_fmt_index(sensor, code);
+
+ if (idx < 0) {
+ dev_err(&client->dev, "%s invalid format\n",
+ __func__);
+ mutex_unlock(&sensor->mutex);
+ return -EINVAL;
+ }
+
+ sensor->fmt_index = idx;
+ rval = __crlmodule_get_format(subdev, pff);
+ /* TODO! validate PLL? */
+ }
+ mutex_unlock(&sensor->mutex);
+ return rval;
+ }
+
+ pff->ffmt.width =
+ clamp_t(uint32_t, pff->ffmt.width,
+ sensor->sensor_ds->sensor_limits->x_addr_min,
+ sensor->sensor_ds->sensor_limits->x_addr_max);
+ pff->ffmt.height =
+ clamp_t(uint32_t, pff->ffmt.height,
+ sensor->sensor_ds->sensor_limits->y_addr_min,
+ sensor->sensor_ds->sensor_limits->y_addr_max);
+
+ crlmodule_get_crop_compose(subdev, crops, NULL);
+
+ crops[ssd->sink_pad]->left = 0;
+ crops[ssd->sink_pad]->top = 0;
+ crops[ssd->sink_pad]->width = pff->ffmt.width;
+ crops[ssd->sink_pad]->height = pff->ffmt.height;
+ ssd->sink_fmt = *crops[ssd->sink_pad];
+
+ crlmodule_propagate(subdev, ICI_EXT_SEL_TYPE_CROP);
+
+ crlmodule_update_current_mode(sensor);
+
+ mutex_unlock(&sensor->mutex);
+
+ return 0;
+}
+
+/*
+ * Function main code replicated from /drivers/media/i2c/smiapp/smiapp-core.c
+ * Slightly modified based on the CRL Module changes
+ */
+static int crlmodule_set_selection(
+ struct ici_isys_node *node,
+ struct ici_pad_selection* ps)
+{
+ struct ici_ext_subdev *subdev = node->sd;
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+ struct i2c_client *client = sensor->src->sd.client;
+ int ret;
+
+ dev_dbg(&client->dev, "%s sd_name: %s sel w: %d, h: %d",
+ __func__, node->name, ps->rect.width,
+ ps->rect.height);
+
+ ret = __crlmodule_sel_supported(subdev, ps->pad.pad_idx,
+ ps->sel_type);
+ if (ret) {
+ dev_dbg(&client->dev,
+ "%s sd_name: %s w: %d, h: %d not supported",
+ __func__, node->name, ps->rect.width,
+ ps->rect.height);
+ return ret;
+ }
+
+ mutex_lock(&sensor->mutex);
+
+ ps->rect.width = max_t(unsigned int,
+ sensor->sensor_ds->sensor_limits->x_addr_min,
+ ps->rect.width);
+ ps->rect.height = max_t(unsigned int,
+ sensor->sensor_ds->sensor_limits->y_addr_min,
+ ps->rect.height);
+ switch (ps->sel_type) {
+ case ICI_EXT_SEL_TYPE_CROP:
+ ret = crlmodule_set_crop(subdev, ps->pad.pad_idx,
+ &ps->rect);
+ break;
+ case ICI_EXT_SEL_TYPE_COMPOSE:
+ ret = crlmodule_set_compose(subdev, &ps->rect);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ crlmodule_update_current_mode(sensor);
+
+ mutex_unlock(&sensor->mutex);
+ return ret;
+}
+
+static int crlmodule_start_streaming(struct crl_sensor *sensor)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ const struct crl_pll_configuration *pll;
+ const struct crl_csi_data_fmt *fmt;
+ int rval;
+
+ dev_dbg(&client->dev, "%s start streaming pll_idx: %d fmt_idx: %d\n",
+ __func__, sensor->pll_index,
+ sensor->fmt_index);
+
+ pll = &sensor->sensor_ds->pll_configs[sensor->pll_index];
+ fmt = &sensor->sensor_ds->csi_fmts[sensor->fmt_index];
+
+ crlmodule_update_current_mode(sensor);
+
+ rval = crlmodule_write_regs(sensor, fmt->regs, fmt->regs_items);
+ if (rval) {
+ dev_err(&client->dev, "%s failed to set format\n", __func__);
+ return rval;
+ }
+
+ rval = crlmodule_write_regs(sensor, pll->pll_regs, pll->pll_regs_items);
+ if (rval) {
+ dev_err(&client->dev, "%s failed to set plls\n", __func__);
+ return rval;
+ }
+
+ /* Write mode list */
+ rval = crlmodule_write_regs(sensor,
+ sensor->current_mode->mode_regs,
+ sensor->current_mode->mode_regs_items);
+ if (rval) {
+ dev_err(&client->dev, "%s failed to set mode\n", __func__);
+ return rval;
+ }
+
+ /* Write stream on list */
+ rval = crlmodule_write_regs(sensor,
+ sensor->sensor_ds->streamon_regs,
+ sensor->sensor_ds->streamon_regs_items);
+ if (rval) {
+ dev_err(&client->dev, "%s failed to set stream\n", __func__);
+ return rval;
+ }
+
+ return 0;
+}
+
+static int crlmodule_stop_streaming(struct crl_sensor *sensor)
+{
+ return crlmodule_write_regs(sensor,
+ sensor->sensor_ds->streamoff_regs,
+ sensor->sensor_ds->streamoff_regs_items);
+}
+
+static int crlmodule_set_stream(
+ struct ici_isys_node* node,
+ void* ip,
+ int enable)
+{
+ struct ici_ext_subdev *subdev = node->sd;
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+ struct i2c_client *client = sensor->src->sd.client;
+ int rval = 0;
+
+ mutex_lock(&sensor->mutex);
+
+ if (sensor->streaming == enable)
+ goto out;
+
+ if (enable) {
+
+ if (sensor->msr_list) {
+ rval = crlmodule_apply_msrlist(client,
+ sensor->msr_list);
+ if (rval)
+ dev_warn(&client->dev, "msrlist write error %d\n",
+ rval);
+ }
+ rval = crlmodule_start_streaming(sensor);
+ if (!rval)
+ sensor->streaming = 1;
+ } else {
+ rval = crlmodule_stop_streaming(sensor);
+ sensor->streaming = 0;
+ }
+
+out:
+ mutex_unlock(&sensor->mutex);
+
+ /* SENSOR_IDLE control cannot be set when streaming*/
+ __crlmodule_enable_param(sensor, SENSOR_IDLE, enable);
+
+ /* SENSOR_STREAMING controls cannot be set when not streaming */
+ __crlmodule_enable_param(sensor, SENSOR_STREAMING, !enable);
+
+ /* SENSOR_POWERED_ON controls does not matter about streaming. */
+ __crlmodule_enable_param(sensor, SENSOR_POWERED_ON, false);
+
+ return rval;
+}
+
+static int crlmodule_identify_module(
+ struct ici_ext_subdev *subdev)
+{
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+ struct i2c_client *client = sensor->src->sd.client;
+ unsigned int size = 0;
+ char *id_string;
+ char *temp;
+ int i, ret;
+ u32 val;
+
+ for (i = 0; i < sensor->sensor_ds->id_reg_items; i++)
+ size += sensor->sensor_ds->id_regs[i].width + 1;
+
+ /* TODO! If no ID! return success? */
+ if (!size)
+ return 0;
+
+ /* Create string variabel to append module ID */
+ id_string = kzalloc(size, GFP_KERNEL);
+ if (!id_string)
+ return -ENOMEM;
+ *id_string = '\0';
+
+ /* Go through each regs in the list and append to id_string */
+ for (i = 0; i < sensor->sensor_ds->id_reg_items; i++) {
+ ret = crlmodule_read_reg(sensor,
+ sensor->sensor_ds->id_regs[i].reg,
+ &val);
+ if (ret)
+ goto out;
+
+ temp = kzalloc(sensor->sensor_ds->id_regs[i].width, GFP_KERNEL);
+ if (!temp) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ snprintf(temp, sensor->sensor_ds->id_regs[i].width, "0x%x ",
+ val);
+ strcat(id_string, temp);
+ snprintf(id_string, sensor->sensor_ds->id_regs[i].width,
+ "%s 0x%x ", temp, val);
+
+ kfree(temp);
+ }
+
+ /* TODO! Check here if this module in the supported list
+ * Ideally the module manufacturer and id should be in platform
+ * data or ACPI and here the driver should read the value from the
+ * register and check if this matches to any in the supported
+ * platform data */
+
+out:
+ dev_dbg(&client->dev, "%s module: %s", __func__, id_string);
+ kfree(id_string);
+ if (ret)
+ dev_err(&client->dev, "sensor detection failed\n");
+ return ret;
+}
+
+/*
+ * This function executes the initialisation routines after the power on
+ * is successfully completed. Following operations are done
+ *
+ * Initiases registers after sensor power up - if any such list is configured
+ * Ctrl handler framework intialisation
+ */
+static int crlmodule_run_poweron_init(struct crl_sensor *sensor)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ int rval;
+
+ dev_dbg(&client->dev, "%s set power up registers: %d\n",
+ __func__, sensor->sensor_ds->powerup_regs_items);
+
+ /* Write the power up registers */
+ rval = crlmodule_write_regs(sensor, sensor->sensor_ds->powerup_regs,
+ sensor->sensor_ds->powerup_regs_items);
+ if (rval) {
+ dev_err(&client->dev, "%s failed to set powerup registers\n",
+ __func__);
+ return rval;
+ }
+
+ /* Are we still initialising...? If yes, return here. */
+ if (!sensor->pixel_array)
+ return 0;
+
+ dev_dbg(&client->dev, "%s init controls", __func__);
+
+
+ /* SENSOR_IDLE control can be set only when not streaming*/
+ __crlmodule_enable_param(sensor, SENSOR_IDLE, false);
+
+ /* SENSOR_STREAMING controls can be set only when streaming */
+ __crlmodule_enable_param(sensor, SENSOR_STREAMING, true);
+
+ /* SENSOR_POWERED_ON controls can be set after power on */
+ __crlmodule_enable_param(sensor, SENSOR_POWERED_ON, false);
+
+ mutex_lock(&sensor->mutex);
+ crlmodule_update_current_mode(sensor);
+ mutex_unlock(&sensor->mutex);
+
+ return rval;
+}
+
+
+/*
+ * This function handles sensor power up routine failure because of any failed
+ * step in the routine. The index "i" is the index to last successfull power
+ * sequence entity successfull completed. This function executes the power
+ * senquence entities in the reverse or with undo value.
+ */
+static void crlmodule_undo_poweron_entities(
+ struct crl_sensor *sensor,
+ int rev_idx)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ struct crl_power_seq_entity *entity;
+ int idx;
+
+ for (idx = rev_idx; idx >= 0; idx--) {
+ entity = &sensor->pwr_entity[idx];
+ dev_dbg(&client->dev, "%s power type %d index %d\n",
+ __func__, entity->type, idx);
+
+ switch (entity->type) {
+ case CRL_POWER_ETY_GPIO_FROM_PDATA:
+ gpio_set_value(sensor->platform_data->xshutdown,
+ entity->undo_val);
+ break;
+ case CRL_POWER_ETY_GPIO_CUSTOM:
+ gpio_set_value(entity->ent_number, entity->undo_val);
+ break;
+ case CRL_POWER_ETY_REGULATOR_FRAMEWORK:
+ regulator_disable(entity->regulator_priv);
+ break;
+ case CRL_POWER_ETY_CLK_FRAMEWORK:
+ clk_disable_unprepare(sensor->xclk);
+ break;
+ default:
+ dev_err(&client->dev, "%s Invalid power type\n", __func__);
+ break;
+ }
+
+ if (entity->delay)
+ usleep_range(entity->delay, entity->delay + 10);
+ }
+}
+
+static int __crlmodule_powerup_sequence(struct crl_sensor *sensor)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ struct crl_power_seq_entity *entity;
+ unsigned idx;
+ int rval;
+
+ for (idx = 0; idx < sensor->sensor_ds->power_items; idx++) {
+ entity = &sensor->pwr_entity[idx];
+ dev_dbg(&client->dev, "%s power type %d index %d\n",
+ __func__, entity->type, idx);
+
+ switch (entity->type) {
+ case CRL_POWER_ETY_GPIO_FROM_PDATA:
+ gpio_set_value(sensor->platform_data->xshutdown, entity->val);
+ break;
+ case CRL_POWER_ETY_GPIO_CUSTOM:
+ gpio_set_value(entity->ent_number, entity->val);
+ break;
+ case CRL_POWER_ETY_REGULATOR_FRAMEWORK:
+ rval = regulator_enable(entity->regulator_priv);
+ if (rval) {
+ dev_err(&client->dev, "Failed to enable regulator: %d\n",
+ rval);
+ devm_regulator_put(entity->regulator_priv);
+ entity->regulator_priv = NULL;
+ goto error;
+ }
+ break;
+ case CRL_POWER_ETY_CLK_FRAMEWORK:
+ rval = clk_set_rate(sensor->xclk, sensor->platform_data->ext_clk);
+ if (rval < 0) {
+ dev_err(&client->dev,
+ "unable to set clock freq to %u\n",
+ sensor->platform_data->ext_clk);
+ goto error;
+ }
+ if (clk_get_rate(sensor->xclk) != sensor->platform_data->ext_clk)
+ dev_warn(&client->dev,
+ "warning: unable to set accurate clock freq %u\n",
+ sensor->platform_data->ext_clk);
+ rval = clk_prepare_enable(sensor->xclk);
+ if (rval) {
+ dev_err(&client->dev, "Failed to enable clock: %d\n", rval);
+ goto error;
+ }
+ break;
+ default:
+ dev_err(&client->dev, "Invalid power type\n");
+ rval = -ENODEV;
+ goto error;
+ break;
+ }
+
+ if (entity->delay)
+ usleep_range(entity->delay, entity->delay + 10);
+ }
+ return 0;
+error:
+ dev_err(&client->dev, "Error:Power sequece failed\n");
+ if (idx > 0)
+ crlmodule_undo_poweron_entities(sensor, idx-1);
+ return rval;
+}
+
+static int crlmodule_set_power(
+ struct ici_isys_node* node,
+ int on)
+{
+ struct ici_ext_subdev *subdev = node->sd;
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+ struct i2c_client *client = sensor->src->sd.client;
+ int ret = 0;
+
+ pr_err("crlmodule_set_power %d\n", on);
+ if (on) {
+ ret = pm_runtime_get_sync(&client->dev);
+ pr_err("crlmodule_set_power val %d\n", ret);
+ if (ret < 0) {
+ pm_runtime_put(&client->dev);
+ return ret;
+ }
+ }
+
+ mutex_lock(&sensor->power_mutex);
+ if (on && !sensor->power_count) {
+ usleep_range(2000, 3000);
+ ret = crlmodule_run_poweron_init(sensor);
+ if (ret < 0) {
+ pr_err("crlmodule_set_power err (2) %d\n", ret);
+ pm_runtime_put(&client->dev);
+ goto out;
+ }
+ }
+
+ /* Update the power count. */
+ sensor->power_count += on ? 1 : -1;
+ WARN_ON(sensor->power_count < 0);
+
+out:
+ mutex_unlock(&sensor->power_mutex);
+
+ if (!on)
+ pm_runtime_put(&client->dev);
+
+ pr_err("crlmodule_set_power ret %d\n", ret);
+ return ret;
+}
+
+/*
+ * Function main code replicated from /drivers/media/i2c/smiapp/smiapp-core.c
+ * Modified based on the CRL Module changes
+ */
+static int crlmodule_init_subdevs(
+ struct ici_ext_subdev *subdev)
+{
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+ struct i2c_client *client = sensor->src->sd.client;
+ struct crl_subdev *prev_sd = NULL;
+ int i = 0;
+ struct crl_subdev *sd;
+ int rval = 0;
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+
+ /*
+ * The scaler, binner and PA order matters. Sensor configuration file
+ * must maintain this order. PA sub dev is a must and binner and
+ * scaler can be omitted based on the sensor. But if scaler is present
+ * it must be the first sd.
+ */
+ if (sensor->sensor_ds->subdevs[i].subdev_type
+ == CRL_SUBDEV_TYPE_SCALER) {
+ sensor->scaler = &sensor->ssds[sensor->ssds_used];
+ sensor->ssds_used++;
+ i++;
+ }
+
+ if (sensor->sensor_ds->subdevs[i].subdev_type
+ == CRL_SUBDEV_TYPE_BINNER) {
+ sensor->binner = &sensor->ssds[sensor->ssds_used];
+ sensor->ssds_used++;
+ i++;
+ }
+
+ if (sensor->sensor_ds->subdevs[i].subdev_type
+ == CRL_SUBDEV_TYPE_PIXEL_ARRAY) {
+ sensor->pixel_array = &sensor->ssds[sensor->ssds_used];
+ sensor->ssds_used++;
+ i++;
+ }
+
+ /* CRL MediaCTL IF driver can't handle if none of these sd's present! */
+ if (!sensor->ssds_used) {
+ dev_err(&client->dev, "%s no subdevs present\n", __func__);
+ return -ENODEV;
+ }
+
+ if (!sensor->sensor_ds->pll_config_items) {
+ dev_err(&client->dev, "%s no pll configurations\n", __func__);
+ return -ENODEV;
+ }
+
+ /* TODO validate rest of the settings from the sensor definition file */
+
+ dev_dbg(&client->dev, "%s subdevs: %d\n", __func__, i);
+
+ for (i = 0; i < sensor->ssds_used; i++) {
+ sd = &sensor->ssds[i];
+
+ sd->sensor = sensor;
+ if (sd == sensor->pixel_array) {
+ sd->npads = 1;
+ } else {
+ sd->npads = 2;
+ sd->source_pad = 1;
+ }
+
+ sd->sink_fmt.width =
+ sensor->sensor_ds->sensor_limits->x_addr_max;
+ sd->sink_fmt.height =
+ sensor->sensor_ds->sensor_limits->y_addr_max;
+ sd->compose.width = sd->sink_fmt.width;
+ sd->compose.height = sd->sink_fmt.height;
+ sd->crop[sd->source_pad] = sd->compose;
+ //sd->pads[sd->source_pad].flags = ICI_PAD_FLAGS_SOURCE;
+ if (sd != sensor->pixel_array) {
+ sd->crop[sd->sink_pad] = sd->compose;
+ //sd->pads[sd->sink_pad].flags = ICI_PAD_FLAGS_SINK;
+ }
+
+ rval = init_ext_sd(client, sd, i);
+ if (rval)
+ return rval;
+
+ if (prev_sd == NULL) {
+ prev_sd = sd;
+ continue;
+ }
+
+ if (sensor->reg.create_link) {
+ rval = sensor->reg.create_link(&sd->sd.node,
+ sd->source_pad,
+ &prev_sd->sd.node,
+ prev_sd->sink_pad,
+ 0);
+ if (rval)
+ return rval;
+ }
+ prev_sd = sd;
+ }
+
+ return rval;
+}
+
+static int __init_power_resources(
+ struct ici_ext_subdev *subdev)
+{
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+ struct i2c_client *client = sensor->src->sd.client;
+ struct crl_power_seq_entity *entity;
+ unsigned idx;
+
+ sensor->pwr_entity = devm_kzalloc(&client->dev,
+ sizeof(struct crl_power_seq_entity) *
+ sensor->sensor_ds->power_items, GFP_KERNEL);
+
+ if (!sensor->pwr_entity)
+ return -ENOMEM;
+
+ for (idx = 0; idx < sensor->sensor_ds->power_items; idx++)
+ sensor->pwr_entity[idx] =
+ sensor->sensor_ds->power_entities[idx];
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+
+ for (idx = 0; idx < sensor->sensor_ds->power_items; idx++) {
+ int rval;
+ entity = &sensor->pwr_entity[idx];
+
+ switch (entity->type) {
+ case CRL_POWER_ETY_GPIO_FROM_PDATA:
+ if (devm_gpio_request_one(&client->dev,
+ sensor->platform_data->xshutdown, 0,
+ "CRL xshutdown") != 0) {
+ dev_err(&client->dev, "unable to acquire xshutdown %d\n",
+ sensor->platform_data->xshutdown);
+ return -ENODEV;
+ }
+ break;
+ case CRL_POWER_ETY_GPIO_CUSTOM:
+ if (devm_gpio_request_one(&client->dev,
+ entity->ent_number, 0,
+ "CRL Custom") != 0) {
+ dev_err(&client->dev, "unable to acquire custom gpio %d\n",
+ entity->ent_number);
+ return -ENODEV;
+ }
+ break;
+ case CRL_POWER_ETY_REGULATOR_FRAMEWORK:
+ entity->regulator_priv = devm_regulator_get(&client->dev,
+ entity->ent_name);
+ if (IS_ERR(entity->regulator_priv)) {
+ dev_err(&client->dev, "Failed to get regulator: %s\n",
+ entity->ent_name);
+ entity->regulator_priv = NULL;
+ return -ENODEV;
+ }
+ rval = regulator_set_voltage(entity->regulator_priv,
+ entity->val,
+ entity->val);
+ /* Not all regulator supports voltage change */
+ if (rval < 0)
+ dev_info(&client->dev,
+ "Failed to set voltage %s %d\n",
+ entity->ent_name, entity->val);
+ break;
+ case CRL_POWER_ETY_CLK_FRAMEWORK:
+ sensor->xclk = devm_clk_get(&client->dev, NULL);
+ if (IS_ERR(sensor->xclk)) {
+ dev_err(&client->dev, "Cannot get sensor clk\n");
+ return -ENODEV;
+ }
+ break;
+ default:
+ dev_err(&client->dev, "Invalid Power item\n");
+ return -ENODEV;
+ }
+ }
+ return 0;
+}
+
+static int crlmodule_registered(
+ struct ici_ext_subdev_register *reg)
+{
+ struct ici_ext_subdev* subdev = reg->sd;
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+ struct i2c_client *client = sensor->src->sd.client;
+
+ int rval;
+
+ if (!reg->sd || !reg->setup_node || !reg->create_link)
+ return -EINVAL;
+
+ rval = __init_power_resources(subdev);
+ if (rval)
+ return -ENODEV;
+
+
+ /* Power up the sensor */
+ if (pm_runtime_get_sync(&client->dev) < 0) {
+ pm_runtime_put(&client->dev);
+ return -ENODEV;
+ }
+
+ /* one time init */
+ rval = crlmodule_write_regs(sensor, sensor->sensor_ds->onetime_init_regs,
+ sensor->sensor_ds->onetime_init_regs_items);
+ if (rval) {
+ dev_err(&client->dev, "%s failed to set powerup registers\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ /* sensor specific init */
+ if (sensor->sensor_ds->sensor_init) {
+ rval = sensor->sensor_ds->sensor_init(client);
+
+ if (rval) {
+ dev_err(&client->dev, "%s failed to run sensor specific init\n",
+ __func__);
+ return -ENODEV;
+ }
+ }
+ /* Identify the module */
+ rval = crlmodule_identify_module(subdev);
+ if (rval) {
+ rval = -ENODEV;
+ goto out;
+ }
+
+ sensor->reg = *reg;
+
+ rval = crlmodule_init_subdevs(subdev);
+ if (rval)
+ goto out;
+
+ sensor->binning_horizontal = 1;
+ sensor->binning_vertical = 1;
+ sensor->scale_m = 1;
+ sensor->flip_info = CRL_FLIP_DEFAULT_NONE;
+ sensor->ext_ctrl_impacts_pll_selection = false;
+ sensor->ext_ctrl_impacts_mode_selection = false;
+
+ rval = crlmodule_init_controls(sensor);
+ if (rval)
+ goto out;
+
+ mutex_lock(&sensor->mutex);
+ crlmodule_update_current_mode(sensor);
+ mutex_unlock(&sensor->mutex);
+ rval = crlmodule_nvm_init(sensor);
+
+out:
+ dev_dbg(&client->dev, "%s rval: %d\n", __func__, rval);
+ /* crlmodule_power_off(sensor); */
+ pm_runtime_put(&client->dev);
+
+ return rval;
+}
+
+static void crlmodule_unregistered(
+ struct ici_ext_subdev *subdev)
+{
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+ struct i2c_client *client = sensor->src->sd.client;
+ dev_dbg(&client->dev, "%s\n", __func__);
+}
+
+static int init_ext_sd(struct i2c_client *client,
+ struct crl_subdev *ssd, int idx)
+{
+ int rval;
+ struct ici_ext_subdev* sd = &ssd->sd;
+ struct crl_sensor *sensor = ssd->sensor;
+ char name[ICI_MAX_NODE_NAME];
+ if (sensor->platform_data->suffix)
+ snprintf(name,
+ sizeof(name), "%s %c",
+ sensor->sensor_ds->subdevs[idx].name,
+ sensor->platform_data->suffix);
+ else
+ snprintf(name,
+ sizeof(name), "%s",
+ sensor->sensor_ds->subdevs[idx].name);
+
+ sd->client = client;
+ sd->num_pads = ssd->npads;
+ sd->src_pad = ssd->source_pad;
+ sd->set_param = crlmodule_set_param;
+ sd->get_param = crlmodule_get_param;
+ sd->get_menu_item = crlmodule_get_menu_item;
+ if (sensor->reg.setup_node) {
+ rval = sensor->reg.setup_node(sensor->reg.ipu_data,
+ sd, name);
+ if (rval)
+ return rval;
+ }
+ sd->node.node_set_power = crlmodule_set_power;
+ sd->node.node_set_streaming = crlmodule_set_stream;
+ sd->node.node_get_pad_supported_format =
+ crlmodule_enum_pixelformat;
+ sd->node.node_set_pad_ffmt = crlmodule_set_format;
+ sd->node.node_get_pad_ffmt = crlmodule_get_format;
+ sd->node.node_set_pad_sel = crlmodule_set_selection;
+ sd->node.node_get_pad_sel = crlmodule_get_selection;
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int crlmodule_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ici_ext_subdev *sd =
+ i2c_get_clientdata(client);
+ struct crl_sensor *sensor = to_crlmodule_sensor(sd);
+
+ crlmodule_undo_poweron_entities(sensor,
+ sensor->sensor_ds->power_items - 1);
+ return 0;
+}
+
+static int crlmodule_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ici_ext_subdev *sd =
+ i2c_get_clientdata(client);
+ struct crl_subdev *ssd = to_crlmodule_subdev(sd);
+ struct crl_sensor *sensor = ssd->sensor;
+
+ if (sensor->streaming)
+ crlmodule_stop_streaming(sensor);
+
+ crlmodule_undo_poweron_entities(sensor,
+ sensor->sensor_ds->power_items - 1);
+ return 0;
+}
+
+static int crlmodule_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ici_ext_subdev *sd =
+ i2c_get_clientdata(client);
+ struct crl_sensor *sensor = to_crlmodule_sensor(sd);
+
+ return __crlmodule_powerup_sequence(sensor);
+}
+
+static int crlmodule_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ici_ext_subdev *sd =
+ i2c_get_clientdata(client);
+ struct crl_subdev *ssd = to_crlmodule_subdev(sd);
+ struct crl_sensor *sensor = ssd->sensor;
+ int rval;
+
+ rval = __crlmodule_powerup_sequence(sensor);
+ if (!rval && sensor->power_count)
+ rval = crlmodule_run_poweron_init(sensor);
+ if (!rval && sensor->streaming)
+ rval = crlmodule_start_streaming(sensor);
+
+ return rval;
+}
+
+#else
+
+#define crlmodule_runtime_suspend NULL
+#define crlmodule_runtime_resume NULL
+#define crlmodule_suspend NULL
+#define crlmodule_resume NULL
+
+#endif /* CONFIG_PM */
+
+
+static int crlmodule_probe(struct i2c_client *client,
+ const struct i2c_device_id *devid)
+{
+ struct crl_sensor *sensor;
+ int ret;
+
+ if (client->dev.platform_data == NULL)
+ return -ENODEV;
+
+ /* TODO! Create the sensor based on the interface */
+ sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
+ if (sensor == NULL)
+ return -ENOMEM;
+
+ sensor->platform_data = client->dev.platform_data;
+ mutex_init(&sensor->mutex);
+ mutex_init(&sensor->power_mutex);
+
+ ret = crlmodule_populate_ds(sensor, &client->dev);
+ if (ret)
+ return -ENODEV;
+
+ sensor->src = &sensor->ssds[sensor->ssds_used];
+ sensor->src->sensor = sensor;
+
+ sensor->src->sd.client = client;
+ sensor->src->sd.do_register = crlmodule_registered;
+ sensor->src->sd.do_unregister = crlmodule_unregistered;
+ i2c_set_clientdata(client, &sensor->src->sd);
+
+ pm_runtime_enable(&client->dev);
+
+ /* Load IQ tuning registers from drvb file*/
+ if (sensor->sensor_ds->msr_file_name) {
+ ret = crlmodule_load_msrlist(client,
+ sensor->sensor_ds->msr_file_name,
+ &sensor->msr_list);
+ if (ret)
+ dev_warn(&client->dev,
+ "msrlist loading failed. Ignore, move on\n");
+ } else {
+ /* sensor will still continue streaming */
+ dev_warn(&client->dev, "No msrlists associated with sensor\n");
+ }
+
+ return 0;
+}
+
+static int crlmodule_remove(struct i2c_client *client)
+{
+ struct ici_ext_subdev *subdev =
+ i2c_get_clientdata(client);
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+ unsigned int i;
+
+ if (sensor->sensor_ds->sensor_cleanup)
+ sensor->sensor_ds->sensor_cleanup(client);
+
+ for (i = 0; i < sensor->ssds_used; i++) {
+ struct ici_ext_subdev *sd =
+ &sensor->ssds[i].sd;
+ if (sd->do_unregister)
+ sd->do_unregister(sd);
+ }
+
+ i2c_set_clientdata(client, NULL);
+
+ crlmodule_nvm_deinit(sensor);
+ crlmodule_release_ds(sensor);
+ crlmodule_release_msrlist(&sensor->msr_list);
+
+ pm_runtime_disable(&client->dev);
+
+ return 0;
+}
+
+
+static const struct i2c_device_id crlmodule_id_table[] = {
+ { CRLMODULE_LITE_NAME, 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, crlmodule_id_table);
+
+static const struct dev_pm_ops crlmodule_pm_ops = {
+ .runtime_suspend = crlmodule_runtime_suspend,
+ .runtime_resume = crlmodule_runtime_resume,
+ .suspend = crlmodule_suspend,
+ .resume = crlmodule_resume,
+};
+
+static struct i2c_driver crlmodule_i2c_driver = {
+ .driver = {
+ .name = CRLMODULE_LITE_NAME,
+ .pm = &crlmodule_pm_ops,
+ },
+ .probe = crlmodule_probe,
+ .remove = crlmodule_remove,
+ .id_table = crlmodule_id_table,
+};
+
+module_i2c_driver(crlmodule_i2c_driver);
+
+MODULE_AUTHOR("Vinod Govindapillai <vinod.govindapillai@intel.com>");
+MODULE_AUTHOR("Jouni Ukkonen <jouni.ukkonen@intel.com>");
+MODULE_AUTHOR("Tommi Franttila <tommi.franttila@intel.com>");
+MODULE_DESCRIPTION("Generic driver for common register list based camera sensor modules");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/crlmodule-lite/crlmodule-data.c b/drivers/media/i2c/crlmodule-lite/crlmodule-data.c
new file mode 100644
index 000000000000..c22dc1fbf87a
--- /dev/null
+++ b/drivers/media/i2c/crlmodule-lite/crlmodule-data.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
+/*
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#include "crlmodule.h"
+#include "crl_adv7481_cvbs_configuration.h"
+#include "crl_adv7481_hdmi_configuration.h"
+#include "crl_adv7481_eval_configuration.h"
+#include "crl_magna_configuration_ti964.h"
+
+static const struct crlmodule_sensors supported_sensors[] = {
+ { "ADV7481 CVBS", "adv7481_cvbs", &adv7481_cvbs_crl_configuration },
+ { "ADV7481 HDMI", "adv7481_hdmi", &adv7481_hdmi_crl_configuration },
+ { "ADV7481_EVAL", "adv7481_eval", &adv7481_eval_crl_configuration },
+ { "ADV7481B_EVAL", "adv7481b_eval", &adv7481b_eval_crl_configuration },
+ { "MAGNA_TI964", "magna_ti964", &magna_ti964_crl_configuration },
+ { "i2c-ADV7481A:00", "adv7481_hdmi", &adv7481_hdmi_crl_configuration },
+ { "i2c-ADV7481B:00", "adv7481_cvbs", &adv7481_cvbs_crl_configuration },
+};
+
+/*
+ * Function to populate the CRL data structure from the sensor configuration
+ * definition file
+ */
+int crlmodule_populate_ds(struct crl_sensor *sensor, struct device *dev)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(supported_sensors); i++) {
+ /* Check the ACPI supported modules */
+ if (!strcmp(dev_name(dev), supported_sensors[i].pname)) {
+ sensor->sensor_ds = supported_sensors[i].ds;
+ dev_info(dev, "%s %s selected\n",
+ __func__, supported_sensors[i].name);
+ return 0;
+ };
+
+ /* Check the non ACPI modules */
+ if (!strcmp(sensor->platform_data->module_name,
+ supported_sensors[i].pname)) {
+ sensor->sensor_ds = supported_sensors[i].ds;
+ dev_info(dev, "%s %s selected\n",
+ __func__, supported_sensors[i].name);
+ return 0;
+ };
+ }
+
+ dev_err(dev, "%s No suitable configuration found for %s\n",
+ __func__, dev_name(dev));
+ return -EINVAL;
+}
+
+/*
+ * Function validate the contents CRL data structure to check if all the
+ * required fields are filled and are according to the limits.
+ */
+int crlmodule_validate_ds(struct crl_sensor *sensor)
+{
+ /* TODO! Revisit this. */
+ return 0;
+}
+
+/* Function to free all resources allocated for the CRL data structure */
+void crlmodule_release_ds(struct crl_sensor *sensor)
+{
+ /*
+ * TODO! Revisit this.
+ * Place for cleaning all the resources used for the generation
+ * of CRL data structure.
+ */
+}
+
diff --git a/drivers/media/i2c/crlmodule-lite/crlmodule-msrlist.c b/drivers/media/i2c/crlmodule-lite/crlmodule-msrlist.c
new file mode 100644
index 000000000000..c2ad74e59be9
--- /dev/null
+++ b/drivers/media/i2c/crlmodule-lite/crlmodule-msrlist.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
+/*
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#include <linux/i2c.h>
+#include <linux/firmware.h>
+#include "crlmodule-msrlist.h"
+#include "crlmodule.h"
+
+/*
+ *
+ * DRVB file is part of the old structure of tagged
+ * binary container, which is used as such in crlmodule.
+ * Changes needs to be done in cameralibs to remove the
+ * tagged structure and convert to untagged drvb format.
+ * Below are the tagged binary data container structure
+ * definitions. Most of it is copied from libmsrlisthelper.c
+ * and some changes done for crlmodule.
+ *
+ */
+
+static int crlmodule_write_msrlist(struct i2c_client *client, u8 *bufptr,
+ unsigned int size)
+{
+ /*
+ *
+ * The configuration data contains any number of sequences where
+ * the first byte (that is, u8) that marks the number of bytes
+ * in the sequence to follow, is indeed followed by the indicated
+ * number of bytes of actual data to be written to sensor.
+ * By convention, the first two bytes of actual data should be
+ * understood as an address in the sensor address space (hibyte
+ * followed by lobyte) where the remaining data in the sequence
+ * will be written.
+ *
+ */
+
+ u8 *ptr = bufptr;
+ int ret;
+
+ while (ptr < bufptr + size) {
+ struct i2c_msg msg = {
+ .addr = client->addr,
+ .flags = 0,
+ };
+
+ msg.len = *ptr++;
+ msg.buf = ptr;
+ ptr += msg.len;
+
+ if (ptr > bufptr + size)
+ return -EINVAL;
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret < 0) {
+ dev_err(&client->dev, "i2c write error: %d", ret);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int crlmodule_parse_msrlist(struct i2c_client *client, u8 *buffer,
+ unsigned int size)
+{
+ u8 *endptr8 = buffer + size;
+ int ret;
+ unsigned int dataset = 0;
+ struct tbd_data_record_header *header =
+ (struct tbd_data_record_header *)buffer;
+
+ do {
+
+ if ((u8 *)header + sizeof(*header) > endptr8)
+ return -EINVAL;
+
+ if ((u8 *)header + header->data_offset +
+ header->data_size > endptr8)
+ return -EINVAL;
+
+ dataset++;
+
+ if (header->data_size && (header->flags & 1)) {
+
+ ret = crlmodule_write_msrlist(client,
+ buffer + header->data_offset,
+ header->data_size);
+ if (ret)
+ return ret;
+ }
+ header = (struct tbd_data_record_header *)(buffer +
+ header->next_offset);
+ } while (header->next_offset);
+
+ return 0;
+}
+
+
+int crlmodule_apply_msrlist(struct i2c_client *client,
+ const struct firmware *fw)
+{
+ struct tbd_header *header;
+ struct tbd_record_header *record;
+
+ header = (struct tbd_header *)fw->data;
+ record = (struct tbd_record_header *)(header + 1);
+
+ if (record->size && record->class_id != TBD_CLASS_DRV_ID)
+ return -EINVAL;
+
+ return crlmodule_parse_msrlist(client, (u8 *)(record + 1),
+ record->size);
+}
+
+
+int crlmodule_load_msrlist(struct i2c_client *client, char *name,
+ const struct firmware **fw)
+{
+
+ struct tbd_header *header;
+ struct tbd_record_header *record;
+ int ret = -ENOENT;
+
+ ret = request_firmware(fw, name, &client->dev);
+ if (ret) {
+ dev_err(&client->dev,
+ "Error %d while requesting firmware %s\n",
+ ret, name);
+ return ret;
+ }
+ header = (struct tbd_header *)(*fw)->data;
+
+ if (sizeof(*header) > (*fw)->size)
+ goto out;
+
+ /* Check that we have drvb block. */
+ if (memcmp(&header->tag, "DRVB", 4))
+ goto out;
+
+ if (header->size != (*fw)->size)
+ goto out;
+
+ if (sizeof(*header) + sizeof(*record) > (*fw)->size)
+ goto out;
+
+
+ return 0;
+
+out:
+ crlmodule_release_msrlist(fw);
+ return ret;
+}
+
+
+void crlmodule_release_msrlist(const struct firmware **fw)
+{
+ release_firmware(*fw);
+ *fw = NULL;
+}
diff --git a/drivers/media/i2c/crlmodule-lite/crlmodule-msrlist.h b/drivers/media/i2c/crlmodule-lite/crlmodule-msrlist.h
new file mode 100644
index 000000000000..2b296c9f9d74
--- /dev/null
+++ b/drivers/media/i2c/crlmodule-lite/crlmodule-msrlist.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) */
+/*
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#ifndef __CRLMODULE_MSRLIST_H__
+#define __CRLMODULE_MSRLIST_H__
+
+#define TBD_CLASS_DRV_ID 2
+
+struct i2c_client;
+struct firmware;
+
+struct tbd_header {
+ /* Tag identifier, also checks endianness */
+ u32 tag;
+ /* Container size including this header */
+ u32 size;
+ /* Version, format 0xYYMMDDVV */
+ u32 version;
+ /* Revision, format 0xYYMMDDVV */
+ u32 revision;
+ /* Configuration flag bits set */
+ u32 config_bits;
+ /* Global checksum, header included */
+ u32 checksum;
+} __packed;
+
+struct tbd_record_header {
+ /* Size of record including header */
+ u32 size;
+ /* tbd_format_t enumeration values used */
+ u8 format_id;
+ /* Packing method; 0 = no packing */
+ u8 packing_key;
+ /* tbd_class_t enumeration values used */
+ u16 class_id;
+} __packed;
+
+struct tbd_data_record_header {
+ u16 next_offset;
+ u16 flags;
+ u16 data_offset;
+ u16 data_size;
+} __packed;
+
+int crlmodule_load_msrlist(struct i2c_client *client, char *name,
+ const struct firmware **fw);
+int crlmodule_apply_msrlist(struct i2c_client *client,
+ const struct firmware *fw);
+void crlmodule_release_msrlist(const struct firmware **fw);
+
+#endif /* ifndef __CRLMODULE_MSRLIST_H__ */
diff --git a/drivers/media/i2c/crlmodule-lite/crlmodule-nvm.c b/drivers/media/i2c/crlmodule-lite/crlmodule-nvm.c
new file mode 100644
index 000000000000..935a967a525a
--- /dev/null
+++ b/drivers/media/i2c/crlmodule-lite/crlmodule-nvm.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
+/*
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#include <linux/device.h>
+#include "crlmodule.h"
+#include "crlmodule-nvm.h"
+#include "crlmodule-regs.h"
+
+static ssize_t crlmodule_sysfs_nvm_read(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ici_ext_subdev *subdev =
+ i2c_get_clientdata(to_i2c_client(dev));
+ struct crl_sensor *sensor = to_crlmodule_sensor(subdev);
+
+ memcpy(buf, sensor->nvm_data, sensor->nvm_size);
+ return sensor->nvm_size;
+}
+
+DEVICE_ATTR(nvm, S_IRUGO, crlmodule_sysfs_nvm_read, NULL);
+
+static unsigned int crlmodule_get_nvm_size(struct crl_sensor *sensor)
+{
+
+ struct i2c_client *client = sensor->src->sd.client;
+ unsigned int i, size = 0;
+
+ for (i = 0; i < sensor->sensor_ds->crl_nvm_info.nvm_blobs_items; i++)
+ size += sensor->sensor_ds->crl_nvm_info.nvm_config[i].size;
+
+ if (size > PAGE_SIZE) {
+ dev_err(&client->dev, "nvm size too big\n");
+ size = 0;
+ }
+ return size;
+}
+
+static int crlmodule_get_nvm_data(struct crl_sensor *sensor)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ int i;
+ int rval = 0;
+
+ u8 *nvm_data = sensor->nvm_data;
+
+ if (sensor->sensor_ds->crl_nvm_info.nvm_preop_regs_items) {
+ dev_dbg(&client->dev,
+ "%s perform pre-operations\n", __func__);
+
+ rval = crlmodule_write_regs(
+ sensor,
+ sensor->sensor_ds->crl_nvm_info.nvm_preop_regs,
+ sensor->sensor_ds->crl_nvm_info.nvm_preop_regs_items);
+ if (rval) {
+ dev_err(&client->dev,
+ "failed to perform nvm pre-operations\n");
+ return rval;
+ }
+ }
+
+ for (i = 0; i < sensor->sensor_ds->crl_nvm_info.nvm_blobs_items; i++) {
+
+ dev_dbg(&client->dev,
+ "%s read blob %d dev_addr: 0x%x start_addr: 0x%x size: %d",
+ __func__, i,
+ sensor->sensor_ds->crl_nvm_info.nvm_config->dev_addr,
+ sensor->sensor_ds->crl_nvm_info.nvm_config->start_addr,
+ sensor->sensor_ds->crl_nvm_info.nvm_config->size);
+
+ crlmodule_block_read(sensor,
+ sensor->sensor_ds->crl_nvm_info.nvm_config->dev_addr,
+ sensor->sensor_ds->crl_nvm_info.nvm_config->start_addr,
+ sensor->sensor_ds->crl_nvm_info.nvm_flags
+ & CRL_NVM_ADDR_MODE_MASK,
+ sensor->sensor_ds->crl_nvm_info.nvm_config->size,
+ nvm_data);
+
+ nvm_data += sensor->sensor_ds->crl_nvm_info.nvm_config->size;
+ sensor->sensor_ds->crl_nvm_info.nvm_config++;
+ }
+
+ if (sensor->sensor_ds->crl_nvm_info.nvm_postop_regs_items) {
+ dev_dbg(&client->dev, "%s perform post-operations\n",
+ __func__);
+ rval = crlmodule_write_regs(
+ sensor,
+ sensor->sensor_ds->crl_nvm_info.nvm_postop_regs,
+ sensor->sensor_ds->crl_nvm_info.nvm_postop_regs_items);
+ if (rval) {
+ dev_err(&client->dev,
+ "failed to perform nvm post-operations\n");
+ return rval;
+ }
+ }
+ return rval;
+}
+
+int crlmodule_nvm_init(struct crl_sensor *sensor)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ unsigned int size = crlmodule_get_nvm_size(sensor);
+ int rval;
+
+ if (size) {
+ sensor->nvm_data = devm_kzalloc(&client->dev, size, GFP_KERNEL);
+ if (sensor->nvm_data == NULL) {
+ dev_err(&client->dev, "nvm buf allocation failed\n");
+ return -ENOMEM;
+ }
+ sensor->nvm_size = size;
+
+ rval = crlmodule_get_nvm_data(sensor);
+ if (rval)
+ goto err;
+ if (device_create_file(&client->dev, &dev_attr_nvm) != 0) {
+ dev_err(&client->dev, "sysfs nvm entry failed\n");
+ rval = -EBUSY;
+ goto err;
+ }
+ }
+
+ return 0;
+err:
+ sensor->nvm_size = 0;
+ return rval;
+}
+
+void crlmodule_nvm_deinit(struct crl_sensor *sensor)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+
+ if (sensor->nvm_size) {
+ device_remove_file(&client->dev, &dev_attr_nvm);
+ sensor->nvm_size = 0;
+ }
+}
diff --git a/drivers/media/i2c/crlmodule-lite/crlmodule-nvm.h b/drivers/media/i2c/crlmodule-lite/crlmodule-nvm.h
new file mode 100644
index 000000000000..9cbabfa950bd
--- /dev/null
+++ b/drivers/media/i2c/crlmodule-lite/crlmodule-nvm.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) */
+/*
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#ifndef __CRLMODULE_NVM_H_
+#define __CRLMODULE_NVM_H_
+
+#include "crlmodule.h"
+
+#define CRL_NVM_ADDR_MODE_8BIT 0x00000001
+#define CRL_NVM_ADDR_MODE_16BIT 0x00000002
+
+#define CRL_NVM_ADDR_MODE_MASK (CRL_NVM_ADDR_MODE_8BIT | \
+ CRL_NVM_ADDR_MODE_16BIT)
+
+
+int crlmodule_nvm_init(struct crl_sensor *sensor);
+void crlmodule_nvm_deinit(struct crl_sensor *sensor);
+
+#endif /* __CRLMODULE_NVM_H_ */
diff --git a/drivers/media/i2c/crlmodule-lite/crlmodule-regs.c b/drivers/media/i2c/crlmodule-lite/crlmodule-regs.c
new file mode 100644
index 000000000000..d7b6d0181410
--- /dev/null
+++ b/drivers/media/i2c/crlmodule-lite/crlmodule-regs.c
@@ -0,0 +1,330 @@
+// SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
+/*
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#include <linux/delay.h>
+
+#include "crlmodule.h"
+#include "crlmodule-nvm.h"
+#include "crlmodule-regs.h"
+
+static int crlmodule_i2c_read(struct crl_sensor *sensor, u16 dev_i2c_addr, u16 reg,
+ u8 len, u32 *val)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ struct i2c_msg msg[2];
+ unsigned char data[4];
+ int r;
+
+ dev_dbg(&client->dev, "%s reg, len: [0x%04x, %d]", __func__, reg, len);
+
+ if (len != CRL_REG_LEN_08BIT && len != CRL_REG_LEN_16BIT &&
+ len != CRL_REG_LEN_24BIT && len != CRL_REG_LEN_32BIT)
+ return -EINVAL;
+
+ if (dev_i2c_addr == CRL_I2C_ADDRESS_NO_OVERRIDE)
+ msg[0].addr = client->addr;
+ else
+ msg[0].addr = dev_i2c_addr;
+
+ msg[1].addr = msg[0].addr;
+
+ msg[0].flags = 0;
+ msg[0].buf = data;
+
+ if (sensor->sensor_ds->addr_len == CRL_ADDR_7BIT) {
+ msg[0].addr = msg[0].addr>>1;
+ msg[1].addr = msg[1].addr>>1;
+ }
+
+ if ((sensor->sensor_ds->addr_len == CRL_ADDR_8BIT) ||
+ (sensor->sensor_ds->addr_len == CRL_ADDR_7BIT)) {
+ data[0] = (u8) (reg & 0xff);
+ msg[0].len = 1;
+ } else {
+ /* high byte goes out first */
+ data[0] = (u8) (reg >> 8);
+ data[1] = (u8) (reg & 0xff);
+ msg[0].len = 2;
+ }
+
+ msg[1].flags = I2C_M_RD;
+ msg[1].buf = data;
+ msg[1].len = len;
+
+ r = i2c_transfer(client->adapter, msg, 2);
+
+ if (r < 0) {
+ goto err;
+ }
+
+ *val = 0;
+ /* high byte comes first */
+ switch (len) {
+ case CRL_REG_LEN_32BIT:
+ *val = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) +
+ data[3];
+ break;
+ case CRL_REG_LEN_24BIT:
+ *val = (data[0] << 16) + (data[1] << 8) + data[2];
+ break;
+ case CRL_REG_LEN_16BIT:
+ *val = (data[0] << 8) + data[1];
+ break;
+ case CRL_REG_LEN_08BIT:
+ *val = data[0];
+ break;
+ }
+
+ return 0;
+
+err:
+ dev_err(&client->dev, "read from offset 0x%x error %d\n", reg, r);
+
+ return r;
+}
+
+static int crlmodule_i2c_write(struct crl_sensor *sensor, u16 dev_i2c_addr,
+ u16 reg, u8 len, u32 val)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ struct i2c_msg msg;
+ unsigned char data[6];
+ unsigned int retries;
+ int r;
+ unsigned char *data_offset;
+
+ if (len != CRL_REG_LEN_08BIT && len != CRL_REG_LEN_16BIT &&
+ len != CRL_REG_LEN_24BIT && len != CRL_REG_LEN_32BIT)
+ return -EINVAL;
+
+ if (dev_i2c_addr == CRL_I2C_ADDRESS_NO_OVERRIDE)
+ msg.addr = client->addr;
+ else
+ msg.addr = dev_i2c_addr;
+
+ msg.flags = 0; /* Write */
+ msg.buf = data;
+
+ if (sensor->sensor_ds->addr_len == CRL_ADDR_7BIT)
+ msg.addr = msg.addr>>1;
+ if ((sensor->sensor_ds->addr_len == CRL_ADDR_8BIT) ||
+ (sensor->sensor_ds->addr_len == CRL_ADDR_7BIT)) {
+ data[0] = (u8) (reg & 0xff);
+ msg.len = 1 + len;
+ data_offset = &data[1];
+ } else {
+ /* high byte goes out first */
+ data[0] = (u8) (reg >> 8);
+ data[1] = (u8) (reg & 0xff);
+ msg.len = 2 + len;
+ data_offset = &data[2];
+ }
+
+ dev_dbg(&client->dev, "%s len reg, val: [%d, 0x%04x, 0x%04x]",
+ __func__, len, reg, val);
+
+ switch (len) {
+ case CRL_REG_LEN_08BIT:
+ data_offset[0] = val;
+ break;
+ case CRL_REG_LEN_16BIT:
+ data_offset[0] = val >> 8;
+ data_offset[1] = val;
+ break;
+ case CRL_REG_LEN_24BIT:
+ data_offset[0] = val >> 16;
+ data_offset[1] = val >> 8;
+ data_offset[2] = val;
+ break;
+ case CRL_REG_LEN_32BIT:
+ data_offset[0] = val >> 24;
+ data_offset[1] = val >> 16;
+ data_offset[2] = val >> 8;
+ data_offset[3] = val;
+ break;
+ }
+
+ for (retries = 0; retries < 5; retries++) {
+ /*
+ * Due to unknown reason sensor stops responding. This
+ * loop is a temporaty solution until the root cause
+ * is found.
+ */
+ r = i2c_transfer(client->adapter, &msg, 1);
+ if (r == 1) {
+ if (retries)
+ dev_err(&client->dev,
+ "sensor i2c stall encountered. retries: %d\n",
+ retries);
+ return 0;
+ }
+
+ usleep_range(2000, 2000);
+ }
+
+ dev_err(&client->dev,
+ "wrote 0x%x to offset 0x%x error %d\n", val, reg, r);
+
+ return r;
+}
+
+int crlmodule_read_reg(struct crl_sensor *sensor,
+ const struct crl_register_read_rep reg, u32 *val)
+{
+ return crlmodule_i2c_read(sensor, reg.dev_i2c_addr, reg.address,
+ reg.len, val);
+}
+
+int crlmodule_write_regs(struct crl_sensor *sensor,
+ const struct crl_register_write_rep *regs, int len)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ unsigned int i;
+ int ret;
+ u32 val;
+
+ for (i = 0; i < len; i++) {
+ /*
+ * Sensor setting sequence may need some delay.
+ * delay value is specified by reg.val field
+ */
+ if (regs[i].len == CRL_REG_LEN_DELAY) {
+ msleep(regs[i].val);
+ continue;
+ }
+ /*
+ * If the same register is being used for two settings, updating
+ * one value should not overwrite the other one. Such registers
+ * must be marked as CRL_REG_READ_AND_UPDATE. For such registers
+ * first read the register and update it
+ */
+ val = regs[i].val;
+ if (regs[i].len & CRL_REG_READ_AND_UPDATE) {
+ ret = crlmodule_i2c_read(sensor, regs[i].dev_i2c_addr,
+ regs[i].address,
+ regs[i].len & CRL_REG_LEN_READ_MASK, &val);
+ if (ret)
+ return ret;
+ val |= regs[i].val;
+ }
+
+ ret = crlmodule_i2c_write(sensor, regs[i].dev_i2c_addr,
+ regs[i].address,
+ regs[i].len & CRL_REG_LEN_READ_MASK,
+ val);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "error %d writing reg 0x%4.4x, val 0x%2.2x",
+ ret, regs[i].address, regs[i].val);
+ return ret;
+ }
+ };
+
+ return 0;
+}
+
+int crlmodule_write_reg(struct crl_sensor *sensor, u16 dev_i2c_addr, u16 reg,
+ u8 len, u32 mask, u32 val)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ int ret;
+ u32 val2;
+
+ /*
+ * Sensor setting sequence may need some delay.
+ * delay value is specified by reg.val field
+ */
+ if (len == CRL_REG_LEN_DELAY) {
+ msleep(val);
+ return 0;
+ }
+
+ /*
+ * If the same register is being used for two settings, updating
+ * one value should not overwrite the other one. Such registers
+ * must be marked as CRL_REG_READ_AND_UPDATE. For such registers
+ * first read the register and update it
+ */
+ if (len & CRL_REG_READ_AND_UPDATE) {
+ u32 tmp;
+
+ ret = crlmodule_i2c_read(sensor, dev_i2c_addr, reg,
+ len & CRL_REG_LEN_READ_MASK, &val2);
+ if (ret)
+ return ret;
+
+ tmp = val2 & ~mask;
+ tmp |= val & mask;
+ val = tmp;
+ } else {
+ val &= mask;
+ }
+
+ ret = crlmodule_i2c_write(sensor, dev_i2c_addr, reg,
+ len & CRL_REG_LEN_READ_MASK, val);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "error %d writing reg 0x%4.4x, val 0x%2.2x",
+ ret, reg, val);
+ return ret;
+ }
+
+ return 0;
+}
+
+int crlmodule_block_read(struct crl_sensor *sensor, u16 dev_i2c_addr, u16 addr,
+ u8 addr_mode, u16 len, u8 *buf)
+{
+ struct i2c_client *client = sensor->src->sd.client;
+ struct i2c_msg msg[2];
+ u8 data[2];
+ u16 offset = 0;
+ int r;
+
+ memset(msg, 0, sizeof(msg));
+
+ if (dev_i2c_addr == CRL_I2C_ADDRESS_NO_OVERRIDE) {
+ msg[0].addr = client->addr;
+ msg[1].addr = client->addr;
+ } else {
+ msg[0].addr = dev_i2c_addr;
+ msg[1].addr = dev_i2c_addr;
+ }
+
+ if (addr_mode & CRL_NVM_ADDR_MODE_8BIT)
+ msg[0].len = 1;
+ else if (addr_mode & CRL_NVM_ADDR_MODE_16BIT)
+ msg[0].len = 2;
+ else
+ return -EINVAL;
+
+ msg[0].flags = 0;
+ msg[1].flags = I2C_M_RD;
+
+ while (offset < len) {
+ if (addr_mode & CRL_NVM_ADDR_MODE_8BIT) {
+ data[0] = addr & 0xff;
+ } else {
+ data[0] = (addr >> 8) & 0xff;
+ data[1] = addr & 0xff;
+ }
+
+ msg[0].buf = data;
+ msg[1].len = min(CRLMODULE_I2C_BLOCK_SIZE, len - offset);
+ msg[1].buf = &buf[offset];
+ r = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+ if (r != ARRAY_SIZE(msg)) {
+ if (r >= 0)
+ r = -EIO;
+ goto err;
+ }
+ addr += msg[1].len;
+ offset += msg[1].len;
+ }
+ return 0;
+err:
+ dev_err(&client->dev, "read from offset 0x%x error %d\n", offset, r);
+ return r;
+}
diff --git a/drivers/media/i2c/crlmodule-lite/crlmodule-regs.h b/drivers/media/i2c/crlmodule-lite/crlmodule-regs.h
new file mode 100644
index 000000000000..45341a16025d
--- /dev/null
+++ b/drivers/media/i2c/crlmodule-lite/crlmodule-regs.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) */
+/*
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#ifndef __CRLMODULE_REGS_H_
+#define __CRLMODULE_REGS_H_
+
+struct crl_sensor;
+struct crl_register_read_rep;
+struct crl_register_write_rep;
+
+#define CRLMODULE_I2C_BLOCK_SIZE 0x20
+
+int crlmodule_read_reg(struct crl_sensor *sensor,
+ const struct crl_register_read_rep reg, u32 *val);
+int crlmodule_write_regs(struct crl_sensor *sensor,
+ const struct crl_register_write_rep *regs, int len);
+int crlmodule_write_reg(struct crl_sensor *sensor, u16 dev_i2c_addr, u16 reg,
+ u8 len, u32 mask, u32 val);
+int crlmodule_block_read(struct crl_sensor *sensor, u16 dev_i2c_addr, u16 addr,
+ u8 addr_mode, u16 len, u8 *buf);
+
+#endif /* __CRLMODULE_REGS_H_ */
diff --git a/drivers/media/i2c/crlmodule-lite/crlmodule-sensor-ds.h b/drivers/media/i2c/crlmodule-lite/crlmodule-sensor-ds.h
new file mode 100644
index 000000000000..e8a6a6f85ae7
--- /dev/null
+++ b/drivers/media/i2c/crlmodule-lite/crlmodule-sensor-ds.h
@@ -0,0 +1,552 @@
+/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) */
+/*
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#ifndef __CRLMODULE_SENSOR_DS_H_
+#define __CRLMODULE_SENSOR_DS_H_
+
+#include "crlmodule.h"
+
+#define CRL_SUBDEVS 3
+
+/* Index for subdevs in any structure with multiple SDs */
+#define CRL_SD_PA_INDEX 0
+#define CRL_SD_BINNER_INDEX 1
+#define CRL_SD_SCALER_INDEX 2
+
+#define CRL_REG_LEN_08BIT 1
+#define CRL_REG_LEN_16BIT 2
+#define CRL_REG_LEN_24BIT 3
+#define CRL_REG_LEN_32BIT 4
+
+#define CRL_REG_READ_AND_UPDATE (1 << 3)
+#define CRL_REG_LEN_READ_MASK 0x07
+#define CRL_REG_LEN_DELAY 0x10
+
+#define CRL_FLIP_DEFAULT_NONE 0
+#define CRL_FLIP_HFLIP 1
+#define CRL_FLIP_VFLIP 2
+#define CRL_FLIP_HFLIP_VFLIP 3
+
+#define CRL_FLIP_HFLIP_MASK 0xfe
+#define CRL_FLIP_VFLIP_MASK 0xfd
+
+#define CRL_PIXEL_ORDER_GRBG 0
+#define CRL_PIXEL_ORDER_RGGB 1
+#define CRL_PIXEL_ORDER_BGGR 2
+#define CRL_PIXEL_ORDER_GBRG 3
+#define CRL_PIXEL_ORDER_IGNORE 255
+
+/* Flag to notify configuration selction imact from Ctrls */
+#define CRL_IMPACTS_NO_IMPACT 0
+#define CRL_IMPACTS_PLL_SELECTION (1 << 1)
+#define CRL_IMPACTS_MODE_SELECTION (1 << 2)
+
+/*
+ * In crl_dynamic_entity::entity_type is denoted by bits 6 and 7
+ * 0 -> crl_dynamic_entity:entity_value is a constant
+ * 1 -> crl_dynamic_entity:entity_value is a referene to variable
+ * 2 -> crl_dynamic_entity:entity_value is a ctrl value
+ * 3 -> crl_dynamic_entity:entity_value is a 8 bit register address
+ */
+enum crl_dynamic_entity_type {
+ CRL_DYNAMIC_VAL_OPERAND_TYPE_CONST = 0,
+ CRL_DYNAMIC_VAL_OPERAND_TYPE_VAR_REF,
+ CRL_DYNAMIC_VAL_OPERAND_TYPE_CTRL_VAL,
+ CRL_DYNAMIC_VAL_OPERAND_TYPE_REG_VAL, /* Only 8bit registers */
+};
+
+/*
+ * For some combo device which has some devices inside itself with different
+ * i2c address, adding flag to specify whether current device needs i2c
+ * address override.
+ * For back-compatibility, making flag equals 0. So existing sensor configure
+ * doesn't need to be modified.
+ */
+#define CRL_I2C_ADDRESS_NO_OVERRIDE 0
+
+struct crl_sensor;
+struct i2c_client;
+
+enum crl_subdev_type {
+ CRL_SUBDEV_TYPE_SCALER,
+ CRL_SUBDEV_TYPE_BINNER,
+ CRL_SUBDEV_TYPE_PIXEL_ARRAY,
+};
+
+enum crl_ctrl_op_type {
+ CRL_CTRL_SET_OP,
+ CRL_CTRL_GET_OP,
+};
+
+enum crl_ctrl_update_context {
+ SENSOR_IDLE, /* Powered on. But not streamind */
+ SENSOR_STREAMING, /* Sensor streaming */
+ SENSOR_POWERED_ON, /* streaming or idle */
+};
+
+enum crl_operators {
+ CRL_BITWISE_AND = 0,
+ CRL_BITWISE_OR,
+ CRL_BITWISE_LSHIFT,
+ CRL_BITWISE_RSHIFT,
+ CRL_BITWISE_XOR,
+ CRL_BITWISE_COMPLEMENT,
+ CRL_ADD,
+ CRL_SUBTRACT,
+ CRL_MULTIPLY,
+ CRL_DIV,
+ CRL_ASSIGNMENT,
+};
+
+/* Replicated from videodev2.h */
+enum crl_ctrl_type {
+ CRL_CTRL_TYPE_INTEGER = 1,
+ CRL_CTRL_TYPE_BOOLEAN,
+ CRL_CTRL_TYPE_MENU_INT,
+ CRL_CTRL_TYPE_MENU_ITEMS,
+ CRL_CTRL_TYPE_BUTTON,
+ CRL_CTRL_TYPE_INTEGER64,
+ CRL_CTRL_TYPE_CTRL_CLASS,
+ CRL_CTRL_TYPE_CUSTOM,
+};
+
+enum crl_addr_len {
+ CRL_ADDR_16BIT = 0,
+ CRL_ADDR_8BIT,
+ CRL_ADDR_7BIT,
+};
+
+enum crl_operands {
+ CRL_CONSTANT = 0,
+ CRL_VARIABLE,
+ CRL_CONTROL,
+};
+
+/* References to the CRL driver member variables */
+enum crl_member_data_reference_ids {
+ CRL_VAR_REF_OUTPUT_WIDTH = 1,
+ CRL_VAR_REF_OUTPUT_HEIGHT,
+ CRL_VAR_REF_PA_CROP_WIDTH,
+ CRL_VAR_REF_PA_CROP_HEIGHT,
+ CRL_VAR_REF_FRAME_TIMING_WIDTH,
+ CRL_VAR_REF_FRAME_TIMING_HEIGHT,
+ CRL_VAR_REF_BINNER_WIDTH,
+ CRL_VAR_REF_BINNER_HEIGHT,
+ CRL_VAR_REF_H_BINN_FACTOR,
+ CRL_VAR_REF_V_BINN_FACTOR,
+ CRL_VAR_REF_SCALE_FACTOR,
+ CRL_VAR_REF_BITSPERPIXEL,
+ CRL_VAR_REF_PIXELRATE_PA,
+ CRL_VAR_REF_PIXELRATE_CSI,
+ CRL_VAR_REF_PIXELRATE_LINK_FREQ,
+};
+
+enum crl_frame_desc_type {
+ CRL_MBUS_FRAME_DESC_TYPE_PLATFORM,
+ CRL_MBUS_FRAME_DESC_TYPE_PARALLEL,
+ CRL_MBUS_FRAME_DESC_TYPE_CCP2,
+ CRL_MBUS_FRAME_DESC_TYPE_CSI2,
+};
+
+enum crl_pwr_ent_type {
+ CRL_POWER_ETY_GPIO_FROM_PDATA = 1,
+ CRL_POWER_ETY_GPIO_CUSTOM,
+ CRL_POWER_ETY_REGULATOR_FRAMEWORK,
+ CRL_POWER_ETY_CLK_FRAMEWORK,
+};
+
+struct crl_dynamic_entity {
+ enum crl_dynamic_entity_type entity_type;
+ u32 entity_val;
+};
+
+struct crl_arithmetic_ops {
+ enum crl_operators op;
+ struct crl_dynamic_entity operand;
+};
+
+struct crl_dynamic_calculated_entity {
+ u8 ops_items;
+ struct crl_arithmetic_ops *ops;
+};
+
+struct crl_register_write_rep {
+ u16 address;
+ u8 len;
+ u32 val;
+ u16 dev_i2c_addr;
+ u32 mask;
+};
+
+struct crl_register_read_rep {
+ u16 address;
+ u8 len;
+ u32 mask;
+ u16 dev_i2c_addr;
+};
+
+/*
+ * crl_dynamic_register_access is used mainly in the ctrl context.
+ * This is intended to provide some generic arithmetic operations on the values
+ * to be written to a control's register or on the values read from a register.
+ * These arithmetic operations are controlled using struct crl_arithmetic_ops.
+ *
+ * One important information is that this structure behave differently for the
+ * set controls and volatile get controls.
+ *
+ * For the set control operation, the usage of the members are straight forward.
+ * The set control can result into multiple register write operations. Hence
+ * there can be more than one crl_dynamic_register_access entries associated
+ * with a control which results into separate register writes.
+ *
+ * But for the volatile get control operation, where a control is used
+ * to query read only information from the sensor, there could be only one
+ * crl_dynamic_register_access entry. Because the result of a get control is
+ * a single value. crl_dynamic_register_access.address, len and mask values are
+ * not used in volatile get control context. Instead all the needed information
+ * must be encoded into member -> ops (struct crl_arithmetic_ops)
+ */
+struct crl_dynamic_register_access {
+ u16 address;
+ u8 len;
+ u32 mask;
+ u8 ops_items;
+ struct crl_arithmetic_ops *ops;
+ u16 dev_i2c_addr;
+};
+
+struct crl_sensor_detect_config {
+ struct crl_register_read_rep reg; /* Register to read */
+ unsigned int width; /* width of the value in chars*/
+};
+
+struct crl_sensor_subdev_config {
+ enum crl_subdev_type subdev_type;
+ char name[32];
+};
+
+enum crl_ctrl_flag {
+ CRL_CTRL_FLAG_UPDATE = 1,
+ CRL_CTRL_FLAG_READ_ONLY = 2,
+ CRL_CTRL_FLAG_WRITE_ONLY = 4,
+};
+
+/*
+ * The ctrl id value pair which should be compared when selecting a
+ * configuration. This gives flexibility to provide any data through set ctrl
+ * and provide selection mechanism for a particular configuration
+ */
+struct crl_ctrl_data_pair {
+ u32 ctrl_id;
+ u32 data;
+};
+
+enum crl_dep_ctrl_action_type {
+ CRL_DEP_CTRL_ACTION_TYPE_SELF = 0,
+ CRL_DEP_CTRL_ACTION_TYPE_DEP_CTRL,
+};
+
+enum crl_dep_ctrl_condition {
+ CRL_DEP_CTRL_CONDITION_GREATER = 0,
+ CRL_DEP_CTRL_CONDITION_LESSER,
+ CRL_DEP_CTRL_CONDITION_EQUAL,
+};
+
+enum crl_dep_ctrl_action {
+ CRL_DEP_CTRL_CONDITION_ADD = 0,
+ CRL_DEP_CTRL_CONDITION_SUBTRACT,
+ CRL_DEP_CTRL_CONDITION_MULTIPLY,
+ CRL_DEP_CTRL_CONDITION_DIVIDE,
+};
+
+struct crl_dep_ctrl_cond_action {
+ enum crl_dep_ctrl_condition cond;
+ u32 cond_value;
+ enum crl_dep_ctrl_action action;
+ u32 action_value;
+};
+
+/* Dependency control provision */
+struct crl_dep_ctrl_provision {
+ u32 ctrl_id;
+ enum crl_dep_ctrl_action_type action_type;
+ unsigned int action_items;
+ struct crl_dep_ctrl_cond_action *action;
+};
+
+struct crl_sensor_limits {
+ unsigned int x_addr_max;
+ unsigned int y_addr_max;
+ unsigned int x_addr_min;
+ unsigned int y_addr_min;
+ unsigned int min_frame_length_lines;
+ unsigned int max_frame_length_lines;
+ unsigned int min_line_length_pixels;
+ unsigned int max_line_length_pixels;
+ u8 scaler_m_min;
+ u8 scaler_m_max;
+ u8 scaler_n_min;
+ u8 scaler_n_max;
+ u8 min_even_inc;
+ u8 max_even_inc;
+ u8 min_odd_inc;
+ u8 max_odd_inc;
+};
+
+struct crl_ctrl_data_std {
+ s64 min;
+ s64 max;
+ u64 step;
+ s64 def;
+};
+
+struct crl_ctrl_data_menu_items {
+ const char *const *menu;
+ unsigned int size;
+};
+
+struct crl_ctrl_data_int_menu {
+ const s64 *menu;
+ s64 max;
+ s64 def;
+};
+
+union crl_ctrl_data_types {
+ struct crl_ctrl_data_std std_data;
+ struct crl_ctrl_data_menu_items menu_items;
+ struct crl_ctrl_data_int_menu int_menu;
+};
+
+/*
+ * Please note a difference in the usage of "regs" member in case of a
+ * volatile get control for read only purpose. Please check the
+ * "struct crl_dynamic_register_access" declaration comments for more details.
+ *
+ * Read only controls must have "flags" CRL_CTRL_FLAG_READ_ONLY set.
+ */
+struct crl_ctrl_data {
+ enum crl_subdev_type sd_type;
+ enum crl_ctrl_op_type op_type;
+ enum crl_ctrl_update_context context;
+ char name[32];
+ u32 ctrl_id;
+ enum crl_ctrl_type type;
+ union crl_ctrl_data_types data;
+ unsigned long flags;
+ u32 impact; /* If this control impact any config selection */
+ struct ici_ext_sd_param param;
+ bool enabled;
+ unsigned int regs_items;
+ struct crl_dynamic_register_access *regs;
+ unsigned int dep_items;
+ struct crl_dep_ctrl_provision *dep_ctrls;
+ s64 min;
+ s64 max;
+ u64 step;
+ s64 def;
+};
+
+struct crl_pll_configuration {
+ s64 input_clk;
+ s64 op_sys_clk;
+ u8 bitsperpixel;
+ u32 pixel_rate_csi;
+ u32 pixel_rate_pa;
+ u8 csi_lanes;
+ unsigned int comp_items;
+ struct crl_ctrl_data_pair *ctrl_data;
+ unsigned int pll_regs_items;
+ const struct crl_register_write_rep *pll_regs;
+};
+
+struct crl_subdev_rect_rep {
+ enum crl_subdev_type subdev_type;
+ struct ici_rect in_rect;
+ struct ici_rect out_rect;
+};
+
+struct crl_mode_rep {
+ unsigned int sd_rects_items;
+ const struct crl_subdev_rect_rep *sd_rects;
+ u8 binn_hor;
+ u8 binn_vert;
+ u8 scale_m;
+ s32 width;
+ s32 height;
+ unsigned int comp_items;
+ struct crl_ctrl_data_pair *ctrl_data;
+ unsigned int mode_regs_items;
+ const struct crl_register_write_rep *mode_regs;
+
+ /*
+ * Minimum and maximum value for line length pixels and frame length
+ * lines are added for modes. This facilitates easy handling of
+ * modes which binning skipping and affects the calculation of vblank and
+ * hblank values.
+ *
+ * The blank values are limited based on the following logic
+ *
+ * If mode specific limits are available
+ * vblank = clamp(min_llp - PA_width, max_llp - PA_width)
+ * hblank = clamp(min_fll - PA_Height, max_fll - PA_Height
+ *
+ * If mode specific blanking limits are not available, then the sensor
+ * limits will be used in the same manner.
+ *
+ * If sensor mode limits are not available, then the values will be
+ * written directly to the associated control registers.
+ */
+ s32 min_llp; /* minimum/maximum value for line length pixels */
+ s32 max_llp;
+ s32 min_fll;
+ s32 max_fll; /* minimum/maximum value for frame length lines */
+};
+
+struct crl_csi_data_fmt {
+ u32 code;
+ u8 pixel_order;
+ u8 bits_per_pixel;
+ unsigned int regs_items;
+ const struct crl_register_write_rep *regs;
+};
+
+struct crl_flip_data {
+ u8 flip;
+ u8 pixel_order;
+};
+
+struct crl_power_seq_entity {
+ enum crl_pwr_ent_type type;
+ char ent_name[12];
+ int ent_number;
+ u16 address;
+ unsigned int val;
+ unsigned int undo_val; /* Undo value if any previous step failed */
+ unsigned int delay; /* delay in micro seconds */
+ struct regulator *regulator_priv; /* R/W */
+};
+
+struct crl_nvm_blob {
+ u8 dev_addr;
+ u16 start_addr;
+ u16 size;
+};
+
+struct crl_nvm {
+ unsigned int nvm_preop_regs_items;
+ const struct crl_register_write_rep *nvm_preop_regs;
+
+ unsigned int nvm_postop_regs_items;
+ const struct crl_register_write_rep *nvm_postop_regs;
+
+ unsigned int nvm_blobs_items;
+ struct crl_nvm_blob *nvm_config;
+ u32 nvm_flags;
+};
+
+/* Representation for v4l2_mbus_frame_desc_entry */
+struct crl_frame_desc {
+ struct crl_dynamic_entity flags;
+ struct crl_dynamic_entity bpp;
+ struct crl_dynamic_entity pixelcode;
+ struct crl_dynamic_entity start_line;
+ struct crl_dynamic_entity start_pixel;
+ struct crl_dynamic_calculated_entity width;
+ struct crl_dynamic_calculated_entity height;
+ struct crl_dynamic_entity length;
+ struct crl_dynamic_entity csi2_channel;
+ struct crl_dynamic_entity csi2_data_type;
+};
+
+typedef int (*sensor_specific_init)(struct i2c_client*);
+typedef int (*sensor_specific_cleanup)(struct i2c_client*);
+
+struct crl_sensor_configuration {
+
+ const struct crl_clock_entity *clock_entity;
+
+ const unsigned int power_items;
+ const struct crl_power_seq_entity *power_entities;
+ const unsigned int power_delay; /* in micro seconds */
+
+ const unsigned int onetime_init_regs_items;
+ const struct crl_register_write_rep *onetime_init_regs;
+
+ const unsigned int powerup_regs_items;
+ const struct crl_register_write_rep *powerup_regs;
+
+ const unsigned int poweroff_regs_items;
+ const struct crl_register_write_rep *poweroff_regs;
+
+ const unsigned int id_reg_items;
+ const struct crl_sensor_detect_config *id_regs;
+
+ const unsigned int subdev_items;
+ const struct crl_sensor_subdev_config *subdevs;
+
+ const struct crl_sensor_limits *sensor_limits;
+
+ const unsigned int pll_config_items;
+ const struct crl_pll_configuration *pll_configs;
+
+ const unsigned int modes_items;
+ const struct crl_mode_rep *modes;
+ /*
+ * Fail safe mode should be the largest resolution available in the
+ * mode list. If none of the mode parameters are matched, the driver
+ * will select this mode for streaming.
+ */
+ const unsigned int fail_safe_mode_index;
+
+ const unsigned int streamon_regs_items;
+ const struct crl_register_write_rep *streamon_regs;
+
+ const unsigned int streamoff_regs_items;
+ const struct crl_register_write_rep *streamoff_regs;
+
+ const unsigned int ctrl_items;
+ const struct crl_ctrl_data *ctrl_bank;
+
+ const unsigned int csi_fmts_items;
+ const struct crl_csi_data_fmt *csi_fmts;
+
+ const unsigned int flip_items;
+ const struct crl_flip_data *flip_data;
+
+ struct crl_nvm crl_nvm_info;
+
+ enum crl_addr_len addr_len;
+
+ unsigned int frame_desc_entries;
+ enum crl_frame_desc_type frame_desc_type;
+ struct crl_frame_desc *frame_desc;
+ char *msr_file_name;
+
+ sensor_specific_init sensor_init;
+ sensor_specific_cleanup sensor_cleanup;
+};
+
+struct crlmodule_sensors {
+ char *pname;
+ char *name;
+ struct crl_sensor_configuration *ds;
+};
+
+/*
+ * Function to populate the CRL data structure from the sensor configuration
+ * definition file
+ */
+int crlmodule_populate_ds(struct crl_sensor *sensor, struct device *dev);
+
+/*
+ * Function validate the contents CRL data structure to check if all the
+ * required fields are filled and are according to the limits.
+ */
+int crlmodule_validate_ds(struct crl_sensor *sensor);
+
+/* Function to free all resources allocated for the CRL data structure */
+void crlmodule_release_ds(struct crl_sensor *sensor);
+
+#endif /* __CRLMODULE_SENSOR_DS_H_ */
diff --git a/drivers/media/i2c/crlmodule-lite/crlmodule.h b/drivers/media/i2c/crlmodule-lite/crlmodule.h
new file mode 100644
index 000000000000..f522409cb22e
--- /dev/null
+++ b/drivers/media/i2c/crlmodule-lite/crlmodule.h
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) */
+/*
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#ifndef __CRLMODULE_PRIV_H_
+#define __CRLMODULE_PRIV_H_
+
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+#include <linux/firmware.h>
+#include "../../../../include/media/crlmodule-lite.h"
+#include <media/ici.h>
+#include "crlmodule-sensor-ds.h"
+
+#define CRL_SUBDEVS 3
+
+#define CRL_PA_PAD_SRC 0
+#define CRL_PAD_SINK 0
+#define CRL_PAD_SRC 1
+#define CRL_PADS 2
+
+struct crl_subdev {
+ struct ici_ext_subdev sd;
+ struct ici_rect sink_fmt;
+ struct ici_rect crop[2];
+ struct ici_rect compose; /* compose on sink */
+ unsigned short sink_pad;
+ unsigned short source_pad;
+ int npads;
+ struct crl_sensor *sensor;
+ unsigned int field;
+};
+
+struct crl_sensor {
+ /*
+ * "mutex" is used to serialise access to all fields here
+ * except ctrls at the end of the struct. "mutex" is also
+ * used to serialise access to file handle specific
+ * information. The exception to this rule is the power_mutex
+ * below.
+ */
+ struct mutex mutex;
+ /*
+ * power mutex became necessity because of the v4l2_ctrl_handler_setup
+ * is being called from power on function which needs to be serialised
+ * but v4l2_ctrl_handler setup uses "mutex" so it cannot be used.
+ */
+ struct mutex power_mutex;
+
+ struct crl_subdev ssds[CRL_SUBDEVS];
+ u32 ssds_used;
+ struct crl_subdev *src;
+ struct crl_subdev *binner;
+ struct crl_subdev *scaler;
+ struct crl_subdev *pixel_array;
+
+ struct crlmodule_lite_platform_data *platform_data;
+
+ u8 binning_horizontal;
+ u8 binning_vertical;
+
+ u8 sensor_mode;
+ u8 scale_m;
+ u8 fmt_index;
+ u8 flip_info;
+ u8 pll_index;
+
+
+ int power_count;
+
+ bool streaming;
+
+ struct crl_sensor_configuration *sensor_ds;
+ struct crl_ctrl_data *ctrl_bank;
+
+ /* These are mandatory controls. So good to have reference to these */
+ struct crl_ctrl_data *pixel_rate_pa;
+ struct crl_ctrl_data *link_freq;
+ struct crl_ctrl_data *pixel_rate_csi;
+
+ s64 *link_freq_menu;
+
+ /* If extra v4l2 contrl has an impact on PLL selection */
+ bool ext_ctrl_impacts_pll_selection;
+ bool ext_ctrl_impacts_mode_selection;
+ bool blanking_ctrl_not_use;
+ bool direct_mode_in_use;
+ const struct crl_mode_rep *current_mode;
+
+ struct clk *xclk;
+ struct crl_power_seq_entity *pwr_entity;
+
+ u8 *nvm_data;
+ u16 nvm_size;
+
+ /* Pointer to binary file which contains
+ * tunable IQ parameters like NR, DPC, BLC
+ * Not all MSR's are moved to the binary
+ * at the moment.
+ */
+ const struct firmware *msr_list;
+
+ struct ici_ext_subdev_register reg;
+};
+
+#define to_crlmodule_subdev(_sd) \
+ container_of(_sd, struct crl_subdev, sd)
+
+#define to_crlmodule_sensor(_sd) \
+ (to_crlmodule_subdev(_sd)->sensor)
+
+#endif /* __CRLMODULE_PRIV_H_ */
diff --git a/include/media/as3638.h b/include/media/as3638.h
new file mode 100644
index 000000000000..8e847efaac9f
--- /dev/null
+++ b/include/media/as3638.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2016 - 2018 Intel Corporation */
+
+#ifndef __AS3638_H__
+#define __AS3638_H__
+
+#define AS3638_NAME "as3638"
+#define AS3638_I2C_ADDR 0x30
+
+#define AS3638_FLASH_MAX_BRIGHTNESS_LED1 500 /* mA, IR LED */
+#define AS3638_TORCH_MAX_BRIGHTNESS_LED1 99 /* mA, IR LED */
+#define AS3638_FLASH_MAX_BRIGHTNESS_LED2 1200 /* mA, Ultra White LED */
+#define AS3638_TORCH_MAX_BRIGHTNESS_LED2 88 /* mA, Ultra White LED */
+#define AS3638_FLASH_MAX_BRIGHTNESS_LED3 1200 /* mA, Warm White LED */
+#define AS3638_TORCH_MAX_BRIGHTNESS_LED3 88 /* mA, Warm White LED */
+
+enum as3638_led_id {
+ AS3638_LED1 = 0,
+ AS3638_LED2,
+ AS3638_LED3,
+ AS3638_LED_MAX,
+};
+#define AS3638_NO_LED -1
+
+struct as3638_platform_data {
+ int gpio_torch;
+ int gpio_strobe;
+ int gpio_reset;
+ u32 flash_max_brightness[AS3638_LED_MAX];
+ u32 torch_max_brightness[AS3638_LED_MAX];
+};
+
+#endif /* __AS3638_H__ */
diff --git a/include/media/crlmodule-lite.h b/include/media/crlmodule-lite.h
new file mode 100644
index 000000000000..ce812e8d909d
--- /dev/null
+++ b/include/media/crlmodule-lite.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0) */
+/*
+ * Copyright (C) 2018 Intel Corporation
+ */
+
+#ifndef __CRLMODULE_LITE_H
+#define __CRLMODULE_LITE_H
+
+#define CRLMODULE_LITE_NAME "crlmodule-lite"
+
+struct crlmodule_lite_platform_data {
+ unsigned short i2c_addr;
+ unsigned short i2c_adapter;
+
+ unsigned int ext_clk; /* sensor external clk */
+
+ unsigned int lanes; /* Number of CSI-2 lanes */
+ const s64 *op_sys_clock;
+
+ int xshutdown; /* gpio */
+ char module_name[16]; /* module name from ACPI */
+ char suffix; /* suffix to identify multi sensors, abcd.. */
+};
+
+#endif /* __CRLMODULE_LITE_H */
diff --git a/include/media/dw9714.h b/include/media/dw9714.h
new file mode 100755
index 000000000000..11737c6ca824
--- /dev/null
+++ b/include/media/dw9714.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2015 - 2018 Intel Corporation
+ *
+ * Based on ATOMISP dw9714 implementation by
+ * Huang Shenbo <shenbo.huang@intel.com.
+ *
+ */
+
+#ifndef __DW9714_H__
+#define __DW9714_H__
+
+#include <linux/types.h>
+
+#define DW9714_NAME "dw9714"
+
+#define DW9714_MAX_FOCUS_POS 1023
+#define DW9714_CTRL_STEPS 16 /* Keep this value power of 2 */
+#define DW9714_CTRL_DELAY_US 1000
+
+#define VCM_DEFAULT_S 0x0
+#define VCM_VAL(data, s) (u16)((data) << 4 | (s))
+
+struct dw9714_platform_data {
+ struct device *sensor_dev;
+ int gpio_xsd; /* Should be < 0 if not used */
+};
+
+#ifdef CONFIG_INTEL_IPU4_OV13858
+extern bool vcm_in_use;
+extern void crlmodule_vcm_gpio_set_value(unsigned int gpio, int value);
+#endif
+#endif
diff --git a/include/media/lc898122.h b/include/media/lc898122.h
new file mode 100644
index 000000000000..5c426407b5ed
--- /dev/null
+++ b/include/media/lc898122.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2016 - 2018 Intel Corporation */
+
+#ifndef __LC898122_HEADER__
+#define __LC898122_HEADER__
+
+#define LC898122_VCM_ADDR 0x24
+#define LC898122_NAME "lc898122"
+
+struct lc898122_platform_data {
+ struct device *sensor_device;
+};
+
+#endif /* __LC898122_HEADER__ */
diff --git a/include/media/lm3643.h b/include/media/lm3643.h
new file mode 100644
index 000000000000..58acf6f9662a
--- /dev/null
+++ b/include/media/lm3643.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2013 - 2018 Intel Corporation */
+
+#ifndef __LM3643_H__
+#define __LM3643_H__
+
+
+#define LM3643_NAME "lm3643"
+#define LM3643_I2C_ADDR_REVA (0x67)
+#define LM3643_I2C_ADDR (0x63)
+
+#define LM3643_FLASH_TOUT_DEF 0xa /*150ms*/
+
+#define LM3643_FLASH_BRT_MIN 10900
+#define LM3643_FLASH_BRT_STEP 11725
+#define LM3643_FLASH_BRT_MAX 1500000
+#define LM3643_FLASH_BRT_mA_TO_REG(a) \
+ (((a) * 1000) < LM3643_FLASH_BRT_MIN ? LM3643_FLASH_BRT_MIN : \
+ ((((a) * 1000) - LM3643_FLASH_BRT_MIN) / LM3643_FLASH_BRT_STEP))
+
+#define LM3643_FLASH_BRT_REG_TO_mA(a) \
+ (((a) * LM3643_FLASH_BRT_STEP + LM3643_FLASH_BRT_MIN) / 1000)
+
+#define LM3643_FLASH_DEFAULT_BRIGHTNESS 729000
+
+#define LM3643_TORCH_BRT_MIN 977
+#define LM3643_TORCH_BRT_STEP 1400
+#define LM3643_TORCH_BRT_MAX 179000
+#define LM3643_TORCH_BRT_mA_TO_REG(a) \
+ (((a) * 1000) < LM3643_TORCH_BRT_MIN ? LM3643_TORCH_BRT_MIN : \
+ ((((a) * 1000) - LM3643_TORCH_BRT_MIN) / LM3643_TORCH_BRT_STEP))
+
+#define LM3643_TORCH_DEFAULT_BRIGHTNESS 89
+
+
+#define LM3643_FLASH_TOUT_MIN 0
+#define LM3643_FLASH_TOUT_STEP 1
+#define LM3643_FLASH_TOUT_MAX 15
+
+/* struct lm3643_platform_data
+ */
+struct lm3643_platform_data {
+ int gpio_torch;
+ int gpio_strobe;
+ int gpio_reset;
+ int flash_max_brightness; /*mA*/
+ int torch_max_brightness; /*mA*/
+};
+
+#endif /* __LM3643_H__ */
--
https://clearlinux.org