Compare commits

..

No commits in common. "master" and "jetpack-4.2.2" have entirely different histories.

16 changed files with 2771 additions and 469 deletions

114
README.md
View File

@ -1,20 +1,34 @@
# Leopard Imaging LI-M021C-MIPI Stereo-Optic Cameras
## Cameras setup
The camera sensors should be conencted to a ConnectTech's Elroy board.
## Kernel Changes
The source code we have modified or added and is pertinent to these cameras is in the following files:
* controls-utility.sh
* hardware/nvidia/platform/t18x/common/kernel-dts/t18x-common-platforms/tegra186-tx2-spiri-camera-base.dtsi
* hardware/nvidia/platform/t18x/common/kernel-dts/t18x-common-platforms/tegra186-tx2-spiri-camera.dtsi
* hardware/nvidia/platform/t18x/quill/kernel-dts/Makefile
* hardware/nvidia/platform/t18x/quill/kernel-dts/tegra186-tx2-spiri-USB3.dts
* hardware/nvidia/platform/t18x/quill/kernel-dts/tegra186-tx2-spiri-base.dts
* hardware/nvidia/platform/t18x/quill/kernel-dts/tegra186-tx2-spiri-mPCIe.dts
* hardware/nvidia/platform/t18x/quill/kernel-dts/tegra186-tx2-spiri-revF+.dts
* nvidia/drivers/media/i2c/mt9m021.c
* nvidia/drivers/media/i2c/mt9m021_mode_tbls.h
* nvidia/drivers/media/platform/tegra/camera/camera_common.c
* nvidia/drivers/media/platform/tegra/camera/tegracam_ctrls.c
* nvidia/include/media/camera_common.h
* nvidia/include/media/tegra-v4l2-camera.h
All these modifications and additions are part of the Spiri Mu kernel, and are represented by symbolic links from this repository into https://git.spirirobotics.com/Spiri/mu_kernel_sources, with the exception of the controls-utility.sh script, which is transferred in the spiri_scripts folder of the rootfs.
## Features
* V4L2 Kernel Driver Version 2.0 supported on L4T32.4.4
* V4L2 Kernel Driver Version 2.0 supported on L4T32.2.1
* V4l2 controls
* test pattern
* individual gains
* vertical/horizontal flip
* flash control
* LibArgus and nvarguscamerasrc
* Resolutions supported:
* 1280x720 @ 60fps
* 1280x960 @ 45fps
* Resolution supported: 1280x720 @ 60fps
* Gain, exposure, and framerate controls
* Camera synchronization
@ -35,7 +49,7 @@ gst-launch-1.0 nvarguscamerasrc sensor-id=0 aelock=true awblock=true ! 'video/x-
### UDP Streaming Test
#### Sender Endpoint
```
gst-launch-1.0 nvarguscamerasrc ! 'video/x-raw(memory:NVMM), width=(int)1280, height=(int)720, format=(string)NV12,framerate=(fraction)60/1' ! omxh264enc control-rate=2 bitrate=8000000 ! 'video/x-h264, stream-format=(string)byte-stream' ! h264parse ! rtph264pay mtu=1400 ! udpsink host=$HOST_IP port=5000 sync=false async=false
gst-launch-1.0 nvarguscamerasrc ! 'video/x-raw(memory:NVMM), width=(int)1280, height=(int)720, format=(string)NV12,framerate=(fraction)30/1' ! omxh264enc control-rate=2 bitrate=8000000 ! 'video/x-h264, stream-format=(string)byte-stream' ! h264parse ! rtph264pay mtu=1400 ! udpsink host=$HOST_IP port=5000 sync=false async=false
```
#### Receiver Endpoint
@ -73,92 +87,10 @@ v4l2-ctl -d /dev/video0 --set-fmt-video=width=1280,height=720,pixelformat=RG12 -
#### Slave
```
v4l2-ctl -d /dev/video1 --set-fmt-video=width=1280,height=720,pixelformat=RG12 --set-ctrl bypass_mode=0 --stream-mmap
v4l2-ctl -d /dev/video01 --set-fmt-video=width=1280,height=720,pixelformat=RG12 --set-ctrl bypass_mode=0 --stream-mmap
```
### AE Synchronized
First run the master pipeline and then the slave pipeline:
#### Master Pipeline
```
gst-launch-1.0 nvarguscamerasrc sensor-id=1 ! 'video/x-raw(memory:NVMM), width=(int)1280, height=(int)720, format=(string)NV12,framerate=(fraction)60/1' ! fakesink
```
#### Slave Pipeline
```
gst-launch-1.0 nvarguscamerasrc sensor-id=0 aelock=true awblock=true ! 'video/x-raw(memory:NVMM), width=(int)1280, height=(int)720, format=(string)NV12,framerate=(fraction)60/1' ! fakesink
```
### Run script
```
./script_to_control_gain_exposure.sh &
```
## Appends
#### Auto Exposure
The AE controls realays in the feedback provided by the Driver's camera sensor to the nvarguscamerasrc libraries,
and the custom DTSIs with the sensor parameters definitions.
As the AE has interdependency with the digital gain. This gain it's and operation on the Driver, and follows this setup:
MT9M021 sensor datasheet:
* <a href="https://files.niemo.de/aptina_pdfs/MT9M021-M031_Developer_Guide.pdf">MT9M021 Developer Guide</a>
Where, the `min_gain_val, max_gain_val, step_gain_val` are part of the cameras' DTSI (tegra186-tx2-spiri-camera.dtsi) fixed parameters
as per the datasheet. The `gain` consists on the steps (1x + n * 1/32 for the register) scaled to a value that represents this fraction in an integer value for the gain register.
#### Kernel Changes
The Driver for the MT9M021 cameras consists on the following structure, that adds the DTB and Kernel sources, along with its Makefiles that lead its portability to a Kernel source.
```bash
.
├── hardware
│ └── nvidia-spiri
│ └── platform
│ └── t18x
│ ├── common
│ │ └── kernel-dts
│ │ └── t18x-common-platforms
│ │ ├── tegra186-tx2-spiri-camera-base.dtsi
│ │ └── tegra186-tx2-spiri-camera.dtsi
│ └── quill
│ └── kernel-dts
│ ├── Makefile
│ ├── tegra186-tx2-spiri-base.dts
│ ├── tegra186-tx2-spiri-mPCIe.dts
│ ├── tegra186-tx2-spiri-revF+.dts
│ └── tegra186-tx2-spiri-USB3.dts
├── kernel
│ ├── kernel-4.9
│ │ └── arch
│ │ └── arm64
│ │ └── configs
│ │ └── tegra_defconfig
│ └── nvidia-spiri
│ ├── drivers
│ │ └── media
│ │ ├── i2c
│ │ │ ├── Kconfig
│ │ │ ├── Makefile
│ │ │ ├── mt9m021.c
│ │ │ └── mt9m021_mode_tbls.h
│ └── include
│ └── media
│ └── mt9m021.h
└── README.md
```
In order to add the Driver to the Kernel, the following reference Kernel files are patched for adding custom controls that the camera implements.
* kernel/nvidia/drivers/media/platform/tegra/camera/camera_common.c
* kernel/nvidia/drivers/media/platform/tegra/camera/tegracam_ctrls.c
* kernel/nvidia/include/media/camera_common.h
* kernel/nvidia/include/media/tegra-v4l2-camera.h
#### Documentation
## Documentation
* <a href="https://nextcloud.spirirobotics.com/f/3369">CSI2 adapter board guide</a>
* <a href="https://nextcloud.spirirobotics.com/f/3382">Camera module data sheet</a>
* <a href="https://nextcloud.spirirobotics.com/f/3392">Camera sensor data sheet</a>

View File

@ -1,3 +1,4 @@
/*Base include for cameras, sets up all the CSI and VI lanes etc,
include this file in any baord specific camera files */
@ -19,26 +20,35 @@ include this file in any baord specific camera files */
tpg_max_iso = <3916800>;
};
// all cameras are disabled by default
/* set camera gpio direction to output */
/* gpio@2200000 {
camera-control-output-low {
gpio-hog;
output-low;
gpios = <CAM0_RST_L 0 CAM0_PWDN 0
CAM1_RST_L 0 CAM1_PWDN 0>;
label = "cam0-rst", "cam0-pwdn",
"cam1-rst", "cam1-pwdn";
};
};*/
/* all cameras are disabled by default */
host1x {
vi_base: vi@15700000 {
num-channels = <6>;
status = "okay";
num-channels = <6>;
ports {
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
vi_port0: port@0 {
status = "okay";
reg = <0>;
status = "disabled";
vi_in0: endpoint {
status = "okay";
status = "disabled";
};
};
};
vi_port1: port@1 {
reg = <1>;
status = "okay";
status = "disabled";
vi_in1: endpoint {
status = "disabled";
};
@ -71,10 +81,8 @@ include this file in any baord specific camera files */
status = "disabled";
};
};
};
};
};
csi_base: nvcsi@150c0000 {
#address-cells = <1>;
#size-cells = <0>;
@ -214,7 +222,98 @@ include this file in any baord specific camera files */
};
};
};
};
};
i2c@3180000 {
e3326_cam0: ov5693_c@36 {
status = "disabled";
};
e3323_cam0: ov23850_a@10 {
status = "disabled";
};
e3323_vcm0: lc898212@72 {
status = "disabled";
};
tca6408@21 {
status = "disabled";
};
tca9548@77 {
status = "disabled";
i2c@0 {
e3333_cam0: ov5693_a@36 {
status = "disabled";
};
e3322_cam0: imx219_a@10 {
status = "disabled";
};
};
i2c@1 {
e3333_cam1: ov5693_b@36 {
status = "disabled";
};
e3322_cam1: imx219_b@10 {
status = "disabled";
};
};
i2c@2 {
e3333_cam2: ov5693_c@36 {
status = "disabled";
};
e3322_cam2: imx219_c@10 {
status = "disabled";
};
};
i2c@3 {
e3333_cam3: ov5693_d@36 {
status = "disabled";
};
e3322_cam3: imx219_d@10 {
status = "disabled";
};
};
i2c@4 {
e3333_cam4: ov5693_e@36 {
status = "disabled";
};
e3322_cam4: imx219_e@10 {
status = "disabled";
};
};
i2c@5 {
e3333_cam5: ov5693_f@36 {
status = "disabled";
};
e3322_cam5: imx219_f@10 {
status = "disabled";
};
};
};
tca9546_70: tca9546@70 {
status = "disabled";
i2c@0 {
imx185_cam0: imx185_a@1a {
status = "disabled";
};
};
};
tca9546_70: tca9546@70 {
status = "disabled";
i2c@0 {
imx274_cam0: imx274_a@1a {
status = "disabled";
};
};
};
};
i2c@c240000 {
e3323_cam1: ov23850_c@36 {
status = "disabled";
};
e3323_vcm1: lc898212@72 {
status = "disabled";
};
};
tcp: tegra-camera-platform {
compatible = "nvidia, tegra-camera-platform";

View File

@ -18,7 +18,7 @@
#define CAM0_RST TEGRA_MAIN_GPIO(R, 5)
#define CAM1_RST TEGRA_MAIN_GPIO(R, 1)
#define CAM0_PWDN TEGRA_MAIN_GPIO(R, 0)
#define CAM1_PWDN TEGRA_MAIN_GPIO(N, 2)
#define CAM1_PWDN TEGRA_MAIN_GPIO(N, 2)
/*
@ -35,19 +35,16 @@ i2c7 = "/i2c@c250000";
i2c8 = "/i2c@31e0000";
*/
/ {
gpio@2200000 {
camera-control-output-low {
gpio-hog;
output-low;
gpios = <CAM0_RST 0 CAM0_PWDN 0 CAM1_RST 0 CAM1_PWDN 0>;
label = "cam0-rst", "cam0-pwdn, cam1-rst, cam1-pwdn";
status = "okay";
};
};
gpio@2200000 {
camera-control-output-low {
gpio-hog;
output-low;
gpios = <CAM0_RST 0 CAM0_PWDN 0 CAM1_RST 0 CAM1_PWDN 0>;
label = "cam0-rst", "cam0-pwdn, cam1-rst, cam1-pwdn";
status = "okay";
};
};
i2c@c240000 {
status = "okay";
#address-cells = <1>;
@ -56,28 +53,28 @@ i2c8 = "/i2c@31e0000";
mt9m021_b@10 {
compatible = "nvidia,mt9m021";
// I2C device address
/* I2C device address */
reg = <0x10>;
// Physical dimensions of sensor
/* Physical dimensions of sensor */
physical_w = "10";
physical_h = "10";
// Sensor Model
/* Sensor Model */
sensor_model ="mt9m021";
// slave or master mode
/* slave or master mode */
trigger_mode = "slave";
// input clock for the device in MHz
/* input clock for the device in MHz*/
clocks = <&tegra_car TEGRA186_CLK_EXTPERIPH2>,
<&tegra_car TEGRA186_CLK_PLLP_OUT0>;
clock-names = "extperiph2", "pllp_grtba";
clock-frequency = <24000000>;
mclk = "extperiph2";
// gpios
reset-gpios = <&tegra_main_gpio CAM1_RST GPIO_ACTIVE_HIGH>;
/* gpios */
reset-gpios = <&tegra_main_gpio CAM1_RST GPIO_ACTIVE_HIGH>;
mode0 {
mclk_khz = "24000";
@ -93,84 +90,43 @@ i2c8 = "/i2c@31e0000";
csi_pixel_bit_depth = "12";
mode_type = "bayer";
pixel_phase = "rggb";
readout_orientation = "0";
readout_orientation = "0";
line_length = "1650";
inherent_gain = "1";
pix_clk_hz = "74250000";
gain_factor = "3125";
gain_factor = "1";
framerate_factor = "1000000";
exposure_factor = "1000000";
min_gain_val = "100000"; /* 1x */
max_gain_val = "796875"; /* 7.97x */
min_gain_val = "4";
max_gain_val = "6476";
step_gain_val = "1";
default_gain = "100000"; /* 1x */
default_gain = "100";
min_hdr_ratio = "1";
max_hdr_ratio = "1";
min_framerate = "2000000";
max_framerate = "60000000";
max_framerate = "60000000";
step_framerate = "1";
default_framerate = "60000000"; // 60.0 fps
default_framerate = "6000000"; /* 60.0 fps */
min_exp_time = "100"; // us
max_exp_time = "16620"; // us
min_exp_time = "23"; /* us */
max_exp_time = "14933"; /* us */
step_exp_time = "1";
default_exp_time = "16620"; // us
default_exp_time = "10000"; /* us */
};
mode1 {
mclk_khz = "24000";
num_lanes = "1";
tegra_sinterface = "serial_b";
discontinuous_clk = "no";
dpcm_enable = "false";
cil_settletime = "26";
active_w = "1280";
active_h = "960";
dynamic_pixel_bit_depth = "12";
csi_pixel_bit_depth = "12";
mode_type = "bayer";
pixel_phase = "rggb";
readout_orientation = "0";
line_length = "1650";
inherent_gain = "1";
pix_clk_hz = "74250000";
gain_factor = "3125";
framerate_factor = "1000000";
exposure_factor = "1000000";
min_gain_val = "100000"; /* 1x */
max_gain_val = "796875"; /* 7.97x */
step_gain_val = "1";
default_gain = "100000"; /* 1x */
min_hdr_ratio = "1";
max_hdr_ratio = "1";
min_framerate = "2000000";
max_framerate = "45000000";
step_framerate = "1";
default_framerate = "45000000"; // 45.0 fps
min_exp_time = "100"; // us
max_exp_time = "22220"; // us
step_exp_time = "1";
default_exp_time = "22220"; // us
};
ports {
ports {
#address-cells = <0x1>;
#size-cells = <0x0>;
port@0 {
reg = <0x0>;
status = "okay";
mt9m021_slave: endpoint {
port-index = <0x1>;
bus-width = <0x1>;
remote-endpoint = <&mt9m021_slave_nvcsi_port0>;
};
};
};
};
};
};
@ -180,32 +136,32 @@ i2c8 = "/i2c@31e0000";
#address-cells = <1>;
#size-cells = <0>;
mt9m021_a@10 {
compatible = "nvidia,mt9m021";
// I2C device address
/* I2C device address */
reg = <0x10>;
// Physical dimensions of sensor
/* Physical dimensions of sensor */
physical_w = "10";
physical_h = "10";
// Sensor Model /
/* Sensor Model */
sensor_model ="mt9m021";
// slave or master mode //
/* slave or master mode */
trigger_mode = "master";
// input clock for the device in MHz
/* input clock for the device in MHz*/
clocks = <&tegra_car TEGRA186_CLK_EXTPERIPH1>,
<&tegra_car TEGRA186_CLK_PLLP_OUT0>;
clock-names = "extperiph1", "pllp_grtba";
clock-frequency = <24000000>;
mclk = "extperiph1";
// gpios
/* gpios */
reset-gpios = <&tegra_main_gpio CAM0_RST GPIO_ACTIVE_HIGH>;
mode0 {
mclk_khz = "24000";
num_lanes = "1";
@ -220,71 +176,32 @@ i2c8 = "/i2c@31e0000";
csi_pixel_bit_depth = "12";
mode_type = "bayer";
pixel_phase = "rggb";
readout_orientation = "0";
readout_orientation = "0";
line_length = "1650";
inherent_gain = "1";
pix_clk_hz = "74250000";
gain_factor = "3125";
gain_factor = "1";
framerate_factor = "1000000";
exposure_factor = "1000000";
min_gain_val = "100000"; /* 1x */
max_gain_val = "796875"; /* 7.97x */
min_gain_val = "4";
max_gain_val = "6476";
step_gain_val = "1";
default_gain = "100000"; /* 1x */
default_gain = "100";
min_hdr_ratio = "1";
max_hdr_ratio = "1";
min_framerate = "2000000";
max_framerate = "60000000";
step_framerate = "1";
default_framerate = "60000000"; // 60.0 fps
default_framerate = "6000000"; /* 60.0 fps */
min_exp_time = "100"; // us
max_exp_time = "16620"; // us
min_exp_time = "23"; /* us */
max_exp_time = "14933"; /* us */
step_exp_time = "1";
default_exp_time = "16620"; // us
default_exp_time = "10000"; /* us */
};
mode1 {
mclk_khz = "24000";
num_lanes = "1";
tegra_sinterface = "serial_a";
discontinuous_clk = "no";
dpcm_enable = "false";
cil_settletime = "26";
active_w = "1280";
active_h = "960";
dynamic_pixel_bit_depth = "12";
csi_pixel_bit_depth = "12";
mode_type = "bayer";
pixel_phase = "rggb";
readout_orientation = "0";
line_length = "1650";
inherent_gain = "1";
pix_clk_hz = "74250000";
gain_factor = "3125";
framerate_factor = "1000000";
exposure_factor = "1000000";
min_gain_val = "100000"; /* 1x */
max_gain_val = "796875"; /* 7.97x */
step_gain_val = "1";
default_gain = "100000"; /* 1x */
min_hdr_ratio = "1";
max_hdr_ratio = "1";
min_framerate = "2000000";
max_framerate = "45000000";
step_framerate = "1";
default_framerate = "45000000"; // 45.0 fps
min_exp_time = "100"; // us
max_exp_time = "22220"; // us
step_exp_time = "1";
default_exp_time = "22220"; // us
};
ports {
ports {
#address-cells = <0x1>;
#size-cells = <0x0>;
@ -296,10 +213,8 @@ i2c8 = "/i2c@31e0000";
remote-endpoint = <&mt9m021_master_nvcsi_port0>;
};
};
};
};
};
host1x {
@ -308,7 +223,6 @@ i2c8 = "/i2c@31e0000";
ports {
#address-cells = <0x1>;
#size-cells = <0x0>;
status = "okay";
port@0 {
reg = <0x0>;
status = "okay";
@ -332,8 +246,6 @@ i2c8 = "/i2c@31e0000";
};
};
nvcsi@150c0000 {
status = "okay";
num-channels = <0x2>;
@ -392,7 +304,7 @@ i2c8 = "/i2c@31e0000";
};
};
};
};
};
tegra-camera-platform {
compatible = "nvidia, tegra-camera-platform";
@ -432,5 +344,4 @@ i2c8 = "/i2c@31e0000";
};
};
};
};

View File

@ -17,7 +17,8 @@
/ {
model = "quill";
compatible = "nvidia,quill", "nvidia,p2597-0000+p3310-1000", "nvidia,tegra186";
compatible = "nvidia,quill", "nvidia,tegra186";
nvidia,boardids = "3310:0000:C03";
nvidia,proc-boardid = "3310:0000:C03";
@ -78,14 +79,11 @@
/*
gpio@74{
status = "disabled";
/delete-node/ touch-rails;
};
*/
/*
gpio@77{
status = "disabled";
/delete-node/ lcd-bias-rails;
};
*/
@ -98,10 +96,6 @@
i2c@c240000 {
clock-frequency = <400000>;
};
spi@3240000 {
status = "disabled";
};
cpus {
status = "disabled";
@ -222,60 +216,7 @@
fixed-regulators {
regulator@1 {
gpio = <&tegra_main_gpio TEGRA_MAIN_GPIO(P, 6) 0>;
};
regulator@2 {
regulator-always-on;
/delete-property/ gpio;
/delete-property/ enable-active-high;
};
regulator@3 {
regulator-always-on;
/delete-property/ gpio;
};
regulator@6 {
regulator-always-on;
/delete-property/ gpio;
};
regulator@7 {
regulator-always-on;
/delete-property/ gpio;
};
regulator@8 {
regulator-always-on;
/delete-property/ gpio;
};
regulator@9 {
regulator-always-on;
/delete-property/ gpio;
};
regulator@10 {
regulator-always-on;
/delete-property/ gpio;
};
regulator@11 {
regulator-always-on;
/delete-property/ gpio;
};
regulator@12 {
regulator-always-on;
/delete-property/ gpio;
};
regulator@13 { //fixes PWM fan
regulator-always-on;
/delete-property/ gpio;
};
regulator@15 {
regulator-always-on;
/delete-property/ gpio;
};
regulator@17 {
regulator-always-on;
/delete-property/ gpio;
};
regulator@118 {
regulator-always-on;
/delete-property/ gpio;
};
};
};
bpmp_i2c {

View File

@ -128,19 +128,6 @@
status = "okay";
};
};
spi@3210000 {
status = "okay";
spi@0 {
compatible = "spidev";
reg = <0x0>;
spi-max-frequency = <33000000>;
controller-data {
nvidia,enable-hw-based-cs;
nvidia,rx-clk-tap-delay = <0x8>;
nvidia,tx-clk-tap-delay = <0x16>;
};
};
};
};

View File

@ -1 +0,0 @@
CONFIG_VIDEO_I2C_SPIRI_CAM=y

View File

@ -1,13 +0,0 @@
if VIDEO_V4L2
menu "NVIDIA overlay Encoders, decoders, sensors and other helper chips"
visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST
config VIDEO_I2C_SPIRI_CAM
tristate "Spiri mt9m021 camera sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
---help---
This is a Video4Linux2 sensor-level driver for Spiri Cameras
endmenu
endif

View File

@ -1,10 +0,0 @@
subdir-ccflags-y += -Werror
obj-$(CONFIG_VIDEO_I2C_SPIRI_CAM) += mt9m021.o
ccflags-$(CONFIG_VIDEO_I2C_SPIRI_CAM) := -I$(srctree.nvidia-spiri)/include/
ccflags-$(CONFIG_VIDEO_I2C_SPIRI_CAM) += -I$(srctree.nvidia-spiri)/include/media/
ccflags-$(CONFIG_VIDEO_I2C_SPIRI_CAM) += -I$(srctree.nvidia-spiri)/drivers/media/i2c/
ccflags-$(CONFIG_VIDEO_I2C_SPIRI_CAM) += -I$(srctree.nvidia)/drivers/media/platform/tegra/camera

View File

@ -32,7 +32,7 @@
#include <media/tegra_v4l2_camera.h>
#include <media/tegracam_core.h>
#include "camera_gpio.h"
#include "../platform/tegra/camera/camera_gpio.h"
#include "mt9m021_mode_tbls.h"
/***************************************************
@ -135,8 +135,8 @@
#define MT9M021_ANALOG_GAIN_SHIFT 4
#define MT9M021_ANALOG_GAIN_MASK 0x0030
#define MT9M021_GLOBAL_GAIN_MIN 100
#define MT9M021_GLOBAL_GAIN_MAX 762
#define MT9M021_GLOBAL_GAIN_MIN 4
#define MT9M021_GLOBAL_GAIN_MAX 6476
#define MT9M021_GLOBAL_GAIN_DEF 100
#define MT9M021_COARSE_INT_TIME_MIN 0x0001
@ -397,38 +397,59 @@ static int mt9m021_set_gain(struct tegracam_device *tc_dev, s64 val)
struct camera_common_data *s_data = tc_dev->s_data;
struct device *dev = tc_dev->dev;
int err = 0;
u64 gain = 0;
u16 gain_mul;
u16 reg16 = 0;
u8 integer, fraction;
dev_dbg(dev, "Setting Gain to: %lld", val);
/*
* Digital gain equation:
*
* RANGE: 1x, 7.97x
* STEPS: 1/32
*
* gain accepts mapping from range 32 - 255
*
* SCALE FACTOR = 3125
*
* min_gain_val = 100000
* max_gain_val = 796875
* gain_factor = 3125
*
*/
gain = val / 3125;
if (val >= MT9M021_GAIN_8X_FIXED) {
integer = val / MT9M021_GAIN_8X_FIXED;
fraction = ((val / 8) % 100) * 32 / 100;
gain_mul = MT9M021_GAIN_8X;
} else if (val >= MT9M021_GAIN_4X_FIXED) {
integer = val / MT9M021_GAIN_4X_FIXED;
fraction = ((val / 4) % 100) * 32 / 100;
gain_mul = MT9M021_GAIN_4X;
} else if (val >= MT9M021_GAIN_2X_FIXED) {
integer = val / MT9M021_GAIN_2X_FIXED;
fraction = ((val / 2) % 100) * 32 / 100;
gain_mul = MT9M021_GAIN_2X;
} else {
integer = val / MT9M021_GAIN_1X_FIXED;
fraction = (val % 100) * 32 / 100;
gain_mul = MT9M021_GAIN_1X;
}
/* Update global gain */
err = mt9m021_write_reg16(s_data, MT9M021_GLOBAL_GAIN, gain);
/* Update analog gain multiplier */
err = mt9m021_read_reg16(s_data, MT9M021_DIGITAL_TEST, &reg16);
if (err)
goto exit;
err = mt9m021_write_reg16(s_data, MT9M021_GLOBAL_GAIN_CB, gain);
reg16 =
(reg16 & ~MT9M021_ANALOG_GAIN_MASK) |
((gain_mul << MT9M021_ANALOG_GAIN_SHIFT) &
MT9M021_ANALOG_GAIN_MASK);
err = mt9m021_write_reg16(s_data, MT9M021_DIGITAL_TEST, reg16);
msleep(10);
if (err)
goto exit;
/* Update global gain */
err =
mt9m021_write_reg16(s_data, MT9M021_GLOBAL_GAIN,
(integer << 5) | fraction);
msleep(10);
if (err)
goto exit;
err =
mt9m021_write_reg16(s_data, MT9M021_GLOBAL_GAIN_CB,
(integer << 5) | fraction);
if (err)
goto exit;
return 0;
exit:
exit:
dev_err(dev, "Gain control error: %d", err);
return err;
@ -473,7 +494,7 @@ static int mt9m021_set_frame_rate(struct tegracam_device *tc_dev, s64 val)
return 0;
exit:
exit:
dev_err(dev, "Frame rate control error: %d", err);
return err;
}
@ -492,6 +513,7 @@ static int mt9m021_set_coarse_time(struct mt9m021 *priv, s64 val)
err = mt9m021_write_reg16(s_data, MT9M021_COARSE_INT_TIME_CB, val);
if (err)
return err;
msleep(30);
return 0;
}
@ -506,11 +528,11 @@ static int mt9m021_set_exposure(struct tegracam_device *tc_dev, s64 val)
u64 coarse_time;
int err = 0;
dev_dbg(dev, "Setting Exposure Time to : %lld", val);
dev_dbg(dev, "Setting Exposure Time to: %lld", val);
coarse_time =
val * mode->signal_properties.pixel_clock.val /
mode->image_properties.line_length /
/* Calculate coarse-time */
coarse_time = mode->signal_properties.pixel_clock.val *
val / mode->image_properties.line_length /
mode->control_properties.exposure_factor;
err = mt9m021_set_coarse_time(priv, coarse_time);
@ -519,7 +541,7 @@ static int mt9m021_set_exposure(struct tegracam_device *tc_dev, s64 val)
return err;
exit:
exit:
dev_err(dev, "Exposure control error: %d", err);
return err;
}
@ -539,14 +561,16 @@ static int mt9m021_set_analog_gain(struct tegracam_device *tc_dev, s64 val)
goto exit;
reg16 =
(reg16 & ~MT9M021_ANALOG_GAIN_MASK) |
((val << MT9M021_ANALOG_GAIN_SHIFT) & MT9M021_ANALOG_GAIN_MASK);
((val << MT9M021_ANALOG_GAIN_SHIFT) &
MT9M021_ANALOG_GAIN_MASK);
err = mt9m021_write_reg16(s_data, MT9M021_DIGITAL_TEST, reg16);
msleep(30);
if (err)
goto exit;
return 0;
exit:
exit:
dev_err(dev, "Analog Gain control error: %d", err);
return err;
@ -596,10 +620,11 @@ static int mt9m021_set_digital_gain(struct tegracam_device *tc_dev, s64 val,
err = mt9m021_write_reg16(s_data, gain_cb_reg, val);
if (err)
goto exit;
msleep(30);
return 0;
exit:
exit:
dev_err(dev, "Digital Gain control error: %d", err);
return err;
}
@ -616,13 +641,15 @@ static int mt9m021_set_test_pattern(struct tegracam_device *tc_dev, s32 val)
err = mt9m021_write_reg16(s_data, MT9M021_TEST_PATTERN,
MT9M021_TEST_PATTERN_VAL);
else
err = mt9m021_write_reg16(s_data, MT9M021_TEST_PATTERN, val);
err = mt9m021_write_reg16(s_data, MT9M021_TEST_PATTERN,
val);
msleep(30);
if (err)
goto exit;
return 0;
exit:
exit:
dev_err(dev, "Test Pattern control error: %d", err);
return err;
@ -637,7 +664,7 @@ static int mt9m021_set_flash(struct tegracam_device *tc_dev, s32 val)
dev_dbg(dev, "Setting Flash to: %d", val);
switch (val) {
switch(val) {
case V4L2_FLASH_LED_MODE_NONE:
err = mt9m021_write_reg16(s_data, MT9M021_FLASH, 0x0000);
priv->flash_en = false;
@ -656,7 +683,7 @@ static int mt9m021_set_flash(struct tegracam_device *tc_dev, s32 val)
goto exit;
return 0;
exit:
exit:
dev_err(dev, "Flash control error: %d", err);
return err;
@ -670,7 +697,7 @@ static int mt9m021_set_flip(struct tegracam_device *tc_dev, s32 val, int id)
dev_dbg(dev, "Setting Flip to: %d", val);
switch (id) {
switch(id) {
case V4L2_CID_HFLIP:
err = mt9m021_update_bits(s_data, MT9M021_READ_MODE,
val << 14, MT9M021_HFLIP_MASK);
@ -689,7 +716,7 @@ static int mt9m021_set_flip(struct tegracam_device *tc_dev, s32 val, int id)
goto exit;
return 0;
exit:
exit:
dev_err(dev, "Flip control error: %d", err);
return err;
@ -760,7 +787,7 @@ static int mt9m021_power_off(struct camera_common_data *s_data)
usleep_range(2000, 2010);
}
power_off_done:
power_off_done:
pw->state = SWITCH_OFF;
return 0;
@ -882,7 +909,7 @@ static struct camera_common_pdata *mt9m021_parse_dt(struct tegracam_device
return board_priv_pdata;
error:
error:
devm_kfree(dev, board_priv_pdata);
return ret;
@ -929,10 +956,13 @@ static int mt9m021_col_correction(struct mt9m021 *priv)
if (ret < 0)
return ret;
msleep(200);
/* Enable Streaming */
ret = mt9m021_write_table(priv, mode_table[MT9M021_MODE_START_STREAM]);
if (ret < 0)
return ret;
msleep(200);
/* Disable Streaming */
ret = mt9m021_write_table(priv, mode_table[MT9M021_MODE_STOP_STREAM]);
@ -943,6 +973,7 @@ static int mt9m021_col_correction(struct mt9m021 *priv)
ret = mt9m021_write_reg16(s_data, MT9M021_COLUMN_CORRECTION, 0xE007);
if (ret < 0)
return ret;
msleep(200);
return ret;
}
@ -1089,8 +1120,7 @@ static int mt9m021_verify_chip_id(struct mt9m021 *priv)
err = mt9m021_read_reg16(s_data, MT9M021_CHIP_ID_REG, &chip_id);
if (!err)
break;
dev_info(&client->dev,
"Failed to read Chip ID, trying again\n");
dev_info(&client->dev, "Failed to read Chip ID, trying again\n");
max_retries--;
msleep(30);
}
@ -1106,7 +1136,7 @@ static int mt9m021_verify_chip_id(struct mt9m021 *priv)
goto exit;
}
exit:
exit:
ret = mt9m021_power_off(s_data);
if (ret)
return ret;

View File

@ -21,7 +21,7 @@
#ifndef __MT9M021_I2C_TABLES__
#define __MT9M021_I2C_TABLES__
#include "media/camera_common.h"
#include <media/camera_common.h>
#define MT9M021_TABLE_WAIT_MS 0
#define MT9M021_TABLE_END 1
@ -31,12 +31,12 @@
#define mt9m021_reg struct reg_16
static const mt9m021_reg mt9m021_start[] = {
{0x301A, 0x00DC}, /* Enable Streaming */
{0x301A, 0x00DC}, /* Enable Streaming */
{MT9M021_TABLE_END, 0x00}
};
static const mt9m021_reg mt9m021_stop[] = {
{0x301A, 0x00D8}, /* Disable Streaming */
{0x301A, 0x00D8}, /* Disable Streaming */
{MT9M021_TABLE_END, 0x00}
};
@ -102,42 +102,8 @@ static const mt9m021_reg mt9m021_mode_1280x720_60fps[] = {
{MT9M021_TABLE_END, 0x00}
};
static const mt9m021_reg mt9m021_mode_1280x960_45fps[] = {
/* Rev2 Settings */
{0x307A, 0x0000},
{0x30EA, 0x0C00},
{0x3044, 0x0404},
{0x301E, 0x012C},
{0x3180, 0x8000},
{0x3014, 0x0000},
/* Analog Settings */
{0x3ED6, 0x00FD},
{0x3ED8, 0x0FFF},
{0x3EDA, 0x0003},
{0x3EDC, 0xF87A},
{0x3EDE, 0xE075},
{0x3EE0, 0x077C},
{0x3EE2, 0xA4EB},
{0x3EE4, 0xD208},
/* Size Settings */
{0x3064, 0x1802}, /* EMBEDDED_DATA_CTRL */
{0x3032, 0x0020}, /* DIGITAL_BINNING */
{0x3002, 0x0004}, /* Y ADDR START */
{0x3004, 0x0001}, /* X ADDR START */
{0x3006, 0x03C3}, /* Y ADDR END */
{0x3008, 0x0500}, /* X ADDR END */
{0x300A, 0x03DE}, /* FRAME_LENGTH_LINES */
{0x300C, 0x0672}, /* LINE_LENGTH_PCK */
{0x30A2, 0x0001}, /* X_ODD_INC */
{0x30A6, 0x0001}, /* Y_ODD_INC */
{MT9M021_TABLE_END, 0x00}
};
enum {
MT9M021_MODE_1280x720_60FPS,
MT9M021_MODE_1280x960_45FPS,
MT9M021_MODE_PLL_SETUP,
@ -146,16 +112,15 @@ enum {
};
static const mt9m021_reg *mode_table[] = {
[MT9M021_MODE_1280x720_60FPS] = mt9m021_mode_1280x720_60fps,
[MT9M021_MODE_1280x960_45FPS] = mt9m021_mode_1280x960_45fps,
[MT9M021_MODE_1280x720_60FPS] = mt9m021_mode_1280x720_60fps,
[MT9M021_MODE_PLL_SETUP] = mt9m021_pll_setup,
[MT9M021_MODE_PLL_SETUP] = mt9m021_pll_setup,
[MT9M021_MODE_START_STREAM] = mt9m021_start,
[MT9M021_MODE_STOP_STREAM] = mt9m021_stop,
[MT9M021_MODE_START_STREAM] = mt9m021_start,
[MT9M021_MODE_STOP_STREAM] = mt9m021_stop,
};
static const int mt9m021_framerates_1280x720[] = {
static const int mt9m021_framerates[] = {
10,
20,
30,
@ -164,19 +129,8 @@ static const int mt9m021_framerates_1280x720[] = {
60,
};
static const int mt9m021_framerates_1280x960[] = {
10,
20,
30,
40,
45,
};
static const struct camera_common_frmfmt mt9m021_frmfmt[] = {
{{1280, 720}, mt9m021_framerates_1280x720, 1, 0,
MT9M021_MODE_1280x720_60FPS},
{{1280, 960}, mt9m021_framerates_1280x960, 1, 0,
MT9M021_MODE_1280x960_45FPS},
{{1280, 720}, mt9m021_framerates, 1, 0, MT9M021_MODE_1280x720_60FPS},
};
#endif /* __MT9M021_I2C_TABLES__ */
#endif /* __MT9M021_I2C_TABLES__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,786 @@
/*
* tegracam_ctrls - control framework for tegra camera drivers
*
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/types.h>
#include <media/tegra-v4l2-camera.h>
#include <media/camera_common.h>
#include <media/tegracam_utils.h>
#define CTRL_U32_MIN 0
#define CTRL_U32_MAX 0x7FFFFFFF
#define CTRL_U64_MIN 0
#define CTRL_U64_MAX 0x7FFFFFFFFFFFFFFFLL
#define CTRL_S32_MIN 0x80000000
#define CTRL_S32_MAX 0x7FFFFFFF
#define CTRL_S64_MIN 0x8000000000000000LL
#define CTRL_S64_MAX 0x7FFFFFFFFFFFFFFFLL
#define CTRL_MAX_STR_SIZE 4096
#define TEGRACAM_DEF_CTRLS 1
/* MT9M021 Controls Information */
#define MT9M021_DEFAULT_ANALOG_GAIN (0x0)
#define MT9M021_MAX_ANALOG_GAIN (0x3)
static const char * const mt9m021_test_pattern_menu[] = {
"0:Disabled",
"1:Solid color test pattern",
"2:color bar test pattern",
"3:Fade to gray color bar test pattern",
"256:Walking 1s test pattern (12 bit)"
};
static int tegracam_s_ctrl(struct v4l2_ctrl *ctrl);
static const struct v4l2_ctrl_ops tegracam_ctrl_ops = {
.s_ctrl = tegracam_s_ctrl,
};
static const u32 tegracam_def_cids[] = {
TEGRA_CAMERA_CID_GROUP_HOLD,
};
/*
* For auto control, the states of the previous controls must
* be applied to get optimal quality faster. List all the controls
* which must be overriden
*/
static const u32 tegracam_override_cids[] = {
TEGRA_CAMERA_CID_GAIN,
TEGRA_CAMERA_CID_EXPOSURE,
TEGRA_CAMERA_CID_FRAME_RATE,
};
#define NUM_OVERRIDE_CTRLS ARRAY_SIZE(tegracam_override_cids)
static struct v4l2_ctrl_config ctrl_cfg_list[] = {
/* Do not change the name field for the controls! */
{
.ops = &tegracam_ctrl_ops,
.id = TEGRA_CAMERA_CID_GAIN,
.name = "Gain",
.type = V4L2_CTRL_TYPE_INTEGER64,
.flags = V4L2_CTRL_FLAG_SLIDER,
.min = CTRL_U64_MIN,
.max = CTRL_U64_MAX,
.def = CTRL_U64_MIN,
.step = 1,
},
{
.ops = &tegracam_ctrl_ops,
.id = TEGRA_CAMERA_CID_EXPOSURE,
.name = "Exposure",
.type = V4L2_CTRL_TYPE_INTEGER64,
.flags = V4L2_CTRL_FLAG_SLIDER,
.min = CTRL_U64_MIN,
.max = CTRL_U64_MAX,
.def = CTRL_U64_MIN,
.step = 1,
},
{
.ops = &tegracam_ctrl_ops,
.id = TEGRA_CAMERA_CID_EXPOSURE_SHORT,
.name = "Exposure Short",
.type = V4L2_CTRL_TYPE_INTEGER64,
.flags = V4L2_CTRL_FLAG_SLIDER,
.min = CTRL_U64_MIN,
.max = CTRL_U64_MAX,
.def = CTRL_U64_MIN,
.step = 1,
},
{
.ops = &tegracam_ctrl_ops,
.id = TEGRA_CAMERA_CID_FRAME_RATE,
.name = "Frame Rate",
.type = V4L2_CTRL_TYPE_INTEGER64,
.flags = V4L2_CTRL_FLAG_SLIDER,
.min = CTRL_U64_MIN,
.max = CTRL_U64_MAX,
.def = CTRL_U64_MIN,
.step = 1,
},
{
.ops = &tegracam_ctrl_ops,
.id = TEGRA_CAMERA_CID_GROUP_HOLD,
.name = "Group Hold",
.type = V4L2_CTRL_TYPE_BOOLEAN,
.flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE,
.min = 0,
.max = 1,
.def = 0,
.step = 1,
},
{
.ops = &tegracam_ctrl_ops,
.id = TEGRA_CAMERA_CID_EEPROM_DATA,
.name = "EEPROM Data",
.type = V4L2_CTRL_TYPE_STRING,
.flags = V4L2_CTRL_FLAG_READ_ONLY,
.min = 0,
.max = CTRL_MAX_STR_SIZE,
.step = 2,
},
{
.ops = &tegracam_ctrl_ops,
.id = TEGRA_CAMERA_CID_FUSE_ID,
.name = "Fuse ID",
.type = V4L2_CTRL_TYPE_STRING,
.flags = V4L2_CTRL_FLAG_READ_ONLY,
.min = 0,
.max = CTRL_MAX_STR_SIZE,
.step = 2,
},
{
.ops = &tegracam_ctrl_ops,
.id = TEGRA_CAMERA_CID_SENSOR_MODE_ID,
.name = "Sensor Mode",
.type = V4L2_CTRL_TYPE_INTEGER64,
.flags = V4L2_CTRL_FLAG_SLIDER,
.min = CTRL_U32_MIN,
.max = CTRL_U32_MAX,
.def = CTRL_U32_MIN,
.step = 1,
},
{
.ops = &tegracam_ctrl_ops,
.id = TEGRA_CAMERA_CID_HDR_EN,
.name = "HDR enable",
.type = V4L2_CTRL_TYPE_INTEGER_MENU,
.min = 0,
.max = ARRAY_SIZE(switch_ctrl_qmenu) - 1,
.menu_skip_mask = 0,
.def = 0,
.qmenu_int = switch_ctrl_qmenu,
},
{
.ops = &tegracam_ctrl_ops,
.id = TEGRA_CAMERA_CID_OTP_DATA,
.name = "OTP Data",
.type = V4L2_CTRL_TYPE_STRING,
.flags = V4L2_CTRL_FLAG_READ_ONLY,
.min = 0,
.max = CTRL_MAX_STR_SIZE,
.step = 2,
},
/* Controls extension for MT9M021 */
{
.ops = &tegracam_ctrl_ops,
.id = V4L2_CID_ANALOGUE_GAIN,
.name = "Analog Gain",
.type = V4L2_CTRL_TYPE_INTEGER64,
.flags = V4L2_CTRL_FLAG_SLIDER,
.min = CTRL_U64_MIN,
.max = MT9M021_MAX_ANALOG_GAIN,
.def = MT9M021_DEFAULT_ANALOG_GAIN,
.step = 1,
},
{
.ops = &tegracam_ctrl_ops,
.id = V4L2_CID_GAIN_RED,
.name = "Red Gain",
.type = V4L2_CTRL_TYPE_INTEGER64,
.flags = V4L2_CTRL_FLAG_SLIDER,
.min = CTRL_U64_MIN,
.max = CTRL_U64_MAX,
.def = CTRL_U64_MIN,
.step = 1,
},
{
.ops = &tegracam_ctrl_ops,
.id = V4L2_CID_GAIN_GREENR,
.name = "GreenR Gain",
.type = V4L2_CTRL_TYPE_INTEGER64,
.flags = V4L2_CTRL_FLAG_SLIDER,
.min = CTRL_U64_MIN,
.max = CTRL_U64_MAX,
.def = CTRL_U64_MIN,
.step = 1,
},
{
.ops = &tegracam_ctrl_ops,
.id = V4L2_CID_GAIN_GREENB,
.name = "GreenB Gain",
.type = V4L2_CTRL_TYPE_INTEGER64,
.flags = V4L2_CTRL_FLAG_SLIDER,
.min = CTRL_U64_MIN,
.max = CTRL_U64_MAX,
.def = CTRL_U64_MIN,
.step = 1,
},
{
.ops = &tegracam_ctrl_ops,
.id = V4L2_CID_GAIN_BLUE,
.name = "Blue Gain",
.type = V4L2_CTRL_TYPE_INTEGER64,
.flags = V4L2_CTRL_FLAG_SLIDER,
.min = CTRL_U64_MIN,
.max = CTRL_U64_MAX,
.def = CTRL_U64_MIN,
.step = 1,
},
{
.ops = &tegracam_ctrl_ops,
.id = V4L2_CID_TEST_PATTERN,
.type = V4L2_CTRL_TYPE_MENU,
.name = "Test Pattern",
.min = 0,
.max = ARRAY_SIZE(mt9m021_test_pattern_menu) - 1,
.step = 0,
.def = 0,
.flags = 0,
.menu_skip_mask = 0,
.qmenu = mt9m021_test_pattern_menu,
},
{
.ops = &tegracam_ctrl_ops,
.id = V4L2_CID_FLASH_LED_MODE,
.name = "Flash",
.type = V4L2_CTRL_TYPE_INTEGER,
.flags = 0,
.min = V4L2_FLASH_LED_MODE_NONE,
.max = V4L2_FLASH_LED_MODE_FLASH,
.def = V4L2_FLASH_LED_MODE_FLASH,
.step = 1,
},
{
.ops = &tegracam_ctrl_ops,
.id = V4L2_CID_HFLIP,
.name = "Horizontal Flip",
.type = V4L2_CTRL_TYPE_INTEGER_MENU,
.min = 0,
.max = ARRAY_SIZE(switch_ctrl_qmenu) - 1,
.menu_skip_mask = 0,
.def = 0,
.qmenu_int = switch_ctrl_qmenu,
},
{
.ops = &tegracam_ctrl_ops,
.id = V4L2_CID_VFLIP,
.name = "Vertical Flip",
.type = V4L2_CTRL_TYPE_INTEGER_MENU,
.min = 0,
.max = ARRAY_SIZE(switch_ctrl_qmenu) - 1,
.menu_skip_mask = 0,
.def = 0,
.qmenu_int = switch_ctrl_qmenu,
},
};
static int tegracam_get_ctrl_index(u32 cid)
{
int i;
for (i = 0; i < ARRAY_SIZE(ctrl_cfg_list); i++) {
if (ctrl_cfg_list[i].id == cid)
return i;
}
return -EINVAL;
}
static int tegracam_get_string_ctrl_size(u32 cid,
const struct tegracam_ctrl_ops *ops)
{
u32 index = 0;
switch (cid) {
case TEGRA_CAMERA_CID_EEPROM_DATA:
index = TEGRA_CAM_STRING_CTRL_EEPROM_INDEX;
break;
case TEGRA_CAMERA_CID_FUSE_ID:
index = TEGRA_CAM_STRING_CTRL_FUSEID_INDEX;
break;
case TEGRA_CAMERA_CID_OTP_DATA:
index = TEGRA_CAM_STRING_CTRL_OTP_INDEX;
break;
default:
return -EINVAL;
}
return ops->string_ctrl_size[index];
}
static int tegracam_setup_string_ctrls(struct tegracam_device *tc_dev,
struct tegracam_ctrl_handler *handler)
{
const struct tegracam_ctrl_ops *ops = handler->ctrl_ops;
u32 numctrls = ops->numctrls;
int i;
int err = 0;
for (i = 0; i < numctrls; i++) {
struct v4l2_ctrl *ctrl = handler->ctrls[i];
if (ctrl->type == V4L2_CTRL_TYPE_STRING) {
err = ops->fill_string_ctrl(tc_dev, ctrl);
if (err)
return err;
}
}
return 0;
}
static int tegracam_set_ctrls(struct tegracam_ctrl_handler *handler,
struct v4l2_ctrl *ctrl)
{
const struct tegracam_ctrl_ops *ops = handler->ctrl_ops;
struct tegracam_device *tc_dev = handler->tc_dev;
struct camera_common_data *s_data = tc_dev->s_data;
int err = 0;
u32 status = 0;
/* For controls that are independent of power state */
switch (ctrl->id) {
case TEGRA_CAMERA_CID_SENSOR_MODE_ID:
s_data->sensor_mode_id = (int) (*ctrl->p_new.p_s64);
return 0;
case TEGRA_CAMERA_CID_HDR_EN:
return 0;
}
if (v4l2_subdev_call(&s_data->subdev, video,
g_input_status, &status)) {
dev_err(s_data->dev, "power status query unsupported\n");
return -ENOTTY;
}
/* power state is turned off, do not program sensor now */
if (!status)
return 0;
/* For controls that require sensor to be on */
switch (ctrl->id) {
case TEGRA_CAMERA_CID_GAIN:
err = ops->set_gain(tc_dev, *ctrl->p_new.p_s64);
break;
case TEGRA_CAMERA_CID_FRAME_RATE:
err = ops->set_frame_rate(tc_dev, *ctrl->p_new.p_s64);
break;
case TEGRA_CAMERA_CID_EXPOSURE:
err = ops->set_exposure(tc_dev, *ctrl->p_new.p_s64);
break;
case TEGRA_CAMERA_CID_EXPOSURE_SHORT:
err = ops->set_exposure_short(tc_dev, *ctrl->p_new.p_s64);
break;
case TEGRA_CAMERA_CID_GROUP_HOLD:
err = ops->set_group_hold(tc_dev, ctrl->val);
break;
case V4L2_CID_ANALOGUE_GAIN:
err = ops->set_analog_gain(tc_dev, *ctrl->p_new.p_s64);
break;
case V4L2_CID_GAIN_RED:
case V4L2_CID_GAIN_GREENR:
case V4L2_CID_GAIN_GREENB:
case V4L2_CID_GAIN_BLUE:
err = ops->set_digital_gain(tc_dev, *ctrl->p_new.p_s64,
ctrl->id);
break;
case V4L2_CID_TEST_PATTERN:
err = ops->set_test_pattern(tc_dev, ctrl->val);
break;
case V4L2_CID_FLASH_LED_MODE:
err = ops->set_flash(tc_dev, ctrl->val);
break;
case V4L2_CID_HFLIP:
case V4L2_CID_VFLIP:
err = ops->set_flip(tc_dev, ctrl->val, ctrl->id);
break;
default:
pr_err("%s: unknown ctrl id.\n", __func__);
return -EINVAL;
}
return err;
}
static int tegracam_set_grouphold_ex(struct tegracam_device *tc_dev,
struct sensor_blob *blob,
bool status)
{
const struct tegracam_ctrl_ops *ops = tc_dev->tcctrl_ops;
struct camera_common_data *s_data = tc_dev->s_data;
int err = 0;
/*
* when grouphold is set, reset control blob
* set grouphold register using set API
* start packetize commands for delivering the blob
* when grouphold is unset, unset grouphold register
* and write the blob only if sensor is streaming.
*/
if (status) {
memset(blob, 0, sizeof(struct sensor_blob));
err = ops->set_group_hold_ex(tc_dev, blob, status);
if (err)
return err;
} else {
err = ops->set_group_hold_ex(tc_dev, blob, status);
if (err)
return err;
/* TODO: block this write selectively from VI5 */
if (tc_dev->is_streaming) {
err = write_sensor_blob(s_data->regmap, blob);
if (err)
return err;
}
}
return 0;
}
static int tegracam_set_ctrls_ex(struct tegracam_ctrl_handler *handler,
struct v4l2_ctrl *ctrl)
{
const struct tegracam_ctrl_ops *ops = handler->ctrl_ops;
struct tegracam_device *tc_dev = handler->tc_dev;
struct camera_common_data *s_data = tc_dev->s_data;
struct tegracam_sensor_data *sensor_data = &handler->sensor_data;
struct sensor_blob *blob = &sensor_data->ctrls_blob;
int err = 0;
switch (ctrl->id) {
case TEGRA_CAMERA_CID_GAIN:
err = ops->set_gain_ex(tc_dev, blob, *ctrl->p_new.p_s64);
break;
case TEGRA_CAMERA_CID_FRAME_RATE:
err = ops->set_frame_rate_ex(tc_dev, blob, *ctrl->p_new.p_s64);
break;
case TEGRA_CAMERA_CID_EXPOSURE:
err = ops->set_exposure_ex(tc_dev, blob, *ctrl->p_new.p_s64);
break;
case TEGRA_CAMERA_CID_GROUP_HOLD:
err = tegracam_set_grouphold_ex(tc_dev, blob, ctrl->val);
break;
case TEGRA_CAMERA_CID_SENSOR_MODE_ID:
s_data->sensor_mode_id = (int) (*ctrl->p_new.p_s64);
break;
case TEGRA_CAMERA_CID_HDR_EN:
break;
default:
pr_err("%s: unknown ctrl id.\n", __func__);
return -EINVAL;
}
return err;
}
static int tegracam_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct tegracam_ctrl_handler *handler =
container_of(ctrl->handler,
struct tegracam_ctrl_handler, ctrl_handler);
const struct tegracam_ctrl_ops *ops = handler->ctrl_ops;
if (ops->is_blob_supported)
return tegracam_set_ctrls_ex(handler, ctrl);
else
return tegracam_set_ctrls(handler, ctrl);
return 0;
}
int tegracam_ctrl_set_overrides(struct tegracam_ctrl_handler *hdl)
{
struct v4l2_ext_controls ctrls;
struct v4l2_ext_control control;
struct tegracam_device *tc_dev = hdl->tc_dev;
struct device *dev = tc_dev->dev;
const struct tegracam_ctrl_ops *ops = hdl->ctrl_ops;
struct tegracam_sensor_data *sensor_data = &hdl->sensor_data;
struct sensor_blob *blob = &sensor_data->ctrls_blob;
bool is_blob_supported = ops->is_blob_supported;
int err, result = 0;
int i;
/*
* write list of override regs for the asking frame length,
* coarse integration time, and gain. Failures to write
* overrides are non-fatal
*/
memset(&ctrls, 0, sizeof(ctrls));
#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 9, 0)
ctrls.which = V4L2_CTRL_ID2WHICH(TEGRA_CAMERA_CID_BASE);
#else
ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(TEGRA_CAMERA_CID_BASE);
#endif
ctrls.count = 1;
ctrls.controls = &control;
for (i = 0; i < NUM_OVERRIDE_CTRLS; i++) {
s64 val = 0;
control.id = tegracam_override_cids[i];
result = v4l2_g_ext_ctrls(&hdl->ctrl_handler, &ctrls);
if (result == 0) {
val = control.value64;
switch (control.id) {
case TEGRA_CAMERA_CID_GAIN:
if (is_blob_supported)
err = ops->set_gain_ex(tc_dev,
blob, val);
else
err = ops->set_gain(tc_dev, val);
break;
case TEGRA_CAMERA_CID_EXPOSURE:
if (is_blob_supported)
err = ops->set_exposure_ex(tc_dev,
blob, val);
else
err = ops->set_exposure(tc_dev, val);
break;
case TEGRA_CAMERA_CID_FRAME_RATE:
if (is_blob_supported)
err = ops->set_frame_rate_ex(tc_dev,
blob, val);
else
err = ops->set_frame_rate(tc_dev, val);
break;
default:
dev_err(dev, "%s: unsupported override %x\n",
__func__, control.id);
return -EINVAL;
}
if (err) {
dev_err(dev, "%s: error to set %d override\n",
__func__, control.id);
return err;
}
}
}
return 0;
}
int tegracam_init_ctrl_ranges_by_mode(
struct tegracam_ctrl_handler *handler,
u32 modeidx)
{
struct tegracam_device *tc_dev = handler->tc_dev;
struct camera_common_data *s_data = tc_dev->s_data;
struct sensor_control_properties *ctrlprops = NULL;
s64 min_short_exp_time = 0;
s64 max_short_exp_time = 0;
s64 default_short_exp_time = 0;
int i;
if (modeidx >= s_data->sensor_props.num_modes)
return -EINVAL;
ctrlprops =
&s_data->sensor_props.sensor_modes[modeidx].control_properties;
for (i = 0; i < handler->numctrls; i++) {
struct v4l2_ctrl *ctrl = handler->ctrls[i];
int err = 0;
switch (ctrl->id) {
case TEGRA_CAMERA_CID_GAIN:
case V4L2_CID_GAIN_RED:
case V4L2_CID_GAIN_GREENR:
case V4L2_CID_GAIN_GREENB:
case V4L2_CID_GAIN_BLUE:
err = v4l2_ctrl_modify_range(ctrl,
ctrlprops->min_gain_val,
ctrlprops->max_gain_val,
ctrlprops->step_gain_val,
ctrlprops->default_gain);
break;
case TEGRA_CAMERA_CID_FRAME_RATE:
err = v4l2_ctrl_modify_range(ctrl,
ctrlprops->min_framerate,
ctrlprops->max_framerate,
ctrlprops->step_framerate,
ctrlprops->default_framerate);
break;
case TEGRA_CAMERA_CID_EXPOSURE:
err = v4l2_ctrl_modify_range(ctrl,
ctrlprops->min_exp_time.val,
ctrlprops->max_exp_time.val,
ctrlprops->step_exp_time.val,
ctrlprops->default_exp_time.val);
break;
case TEGRA_CAMERA_CID_EXPOSURE_SHORT:
/*
* min_hdr_ratio should be equal to max_hdr_ratio.
* This will ensure consistent short exposure
* limit calculations.
*/
min_short_exp_time =
ctrlprops->min_exp_time.val /
ctrlprops->min_hdr_ratio;
max_short_exp_time =
ctrlprops->max_exp_time.val /
ctrlprops->min_hdr_ratio;
default_short_exp_time =
ctrlprops->default_exp_time.val /
ctrlprops->min_hdr_ratio;
err = v4l2_ctrl_modify_range(ctrl,
min_short_exp_time,
max_short_exp_time,
ctrlprops->step_exp_time.val,
default_short_exp_time);
dev_dbg(s_data->dev,
"%s:short_exp_limits[%lld,%lld], default_short_exp_time=%lld\n",
__func__,
min_short_exp_time,
max_short_exp_time,
default_short_exp_time);
break;
default:
/* Not required to modify these control ranges */
break;
}
if (err) {
dev_err(s_data->dev,
"ctrl %s range update failed\n", ctrl->name);
return err;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(tegracam_init_ctrl_ranges_by_mode);
int tegracam_init_ctrl_ranges(struct tegracam_ctrl_handler *handler)
{
struct tegracam_device *tc_dev = handler->tc_dev;
struct camera_common_data *s_data = tc_dev->s_data;
struct device *dev = tc_dev->dev;
int i, err = 0;
/* Updating static control ranges */
for (i = 0; i < handler->numctrls; i++) {
struct v4l2_ctrl *ctrl = handler->ctrls[i];
switch (ctrl->id) {
case TEGRA_CAMERA_CID_SENSOR_MODE_ID:
err = v4l2_ctrl_modify_range(ctrl,
CTRL_U32_MIN,
(s64) s_data->sensor_props.num_modes,
1,
CTRL_U32_MIN);
break;
default:
/* Not required to modify these control ranges */
break;
}
if (err) {
dev_err(s_data->dev,
"ctrl %s range update failed\n", ctrl->name);
return err;
}
}
/* Use mode 0 control ranges as default */
if (s_data->sensor_props.num_modes > 0) {
err = tegracam_init_ctrl_ranges_by_mode(handler, 0);
if (err) {
dev_err(dev,
"Error %d updating mode specific control ranges\n",
err);
return err;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(tegracam_init_ctrl_ranges);
int tegracam_ctrl_handler_init(struct tegracam_ctrl_handler *handler)
{
struct tegracam_device *tc_dev = handler->tc_dev;
struct v4l2_ctrl *ctrl;
struct v4l2_ctrl_config *ctrl_cfg;
struct device *dev = tc_dev->dev;
const struct tegracam_ctrl_ops *ops = handler->ctrl_ops;
const u32 *cids = ops->ctrl_cid_list;
u32 numctrls = ops->numctrls + TEGRACAM_DEF_CTRLS;
int i, j;
int err = 0;
err = v4l2_ctrl_handler_init(&handler->ctrl_handler, numctrls);
for (i = 0, j = 0; i < numctrls; i++) {
u32 cid = i < ops->numctrls ? cids[i] : tegracam_def_cids[j++];
int index = tegracam_get_ctrl_index(cid);
int size = 0;
if (index >= ARRAY_SIZE(ctrl_cfg_list)) {
dev_err(dev, "unsupported control in the list\n");
return -ENOTTY;
}
ctrl_cfg = &ctrl_cfg_list[index];
if (ctrl_cfg->type == V4L2_CTRL_TYPE_STRING) {
size = tegracam_get_string_ctrl_size(ctrl_cfg->id, ops);
if (size < 0) {
dev_err(dev, "Invalid string ctrl size\n");
return -EINVAL;
}
ctrl_cfg->max = size;
}
ctrl = v4l2_ctrl_new_custom(&handler->ctrl_handler,
ctrl_cfg, NULL);
if (ctrl == NULL) {
dev_err(dev, "Failed to init %s ctrl\n",
ctrl_cfg->name);
return -EINVAL;
}
if (ctrl_cfg->type == V4L2_CTRL_TYPE_STRING &&
ctrl_cfg->flags & V4L2_CTRL_FLAG_READ_ONLY) {
ctrl->p_new.p_char = devm_kzalloc(tc_dev->dev,
size + 1, GFP_KERNEL);
}
handler->ctrls[i] = ctrl;
};
handler->numctrls = numctrls;
err = v4l2_ctrl_handler_setup(&handler->ctrl_handler);
if (err) {
dev_err(dev, "Error %d in control hdl setup\n", err);
goto error;
}
err = handler->ctrl_handler.error;
if (err) {
dev_err(dev, "Error %d adding controls\n", err);
goto error;
}
err = tegracam_setup_string_ctrls(tc_dev, handler);
if (err) {
dev_err(dev, "setup string controls failed\n");
goto error;
}
err = tegracam_init_ctrl_ranges(handler);
if (err) {
dev_err(dev, "Error %d updating control ranges\n", err);
goto error;
}
return 0;
error:
v4l2_ctrl_handler_free(&handler->ctrl_handler);
return err;
}
EXPORT_SYMBOL_GPL(tegracam_ctrl_handler_init);

View File

@ -0,0 +1,413 @@
/**
* camera_common.h - utilities for tegra camera driver
*
* Copyright (c) 2015-2019, NVIDIA Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __camera_common__
#define __camera_common__
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/platform_device.h>
#include <linux/v4l2-mediabus.h>
#include <linux/version.h>
#include <linux/videodev2.h>
#include <media/camera_version_utils.h>
#include <media/nvc_focus.h>
#include <media/sensor_common.h>
#include <media/soc_camera.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-ctrls.h>
#include <media/tegracam_core.h>
/*
* Scaling factor for converting a Q10.22 fixed point value
* back to its original floating point value
*/
#define FIXED_POINT_SCALING_FACTOR (1ULL << 22)
struct reg_8 {
u16 addr;
u8 val;
};
struct reg_16 {
u16 addr;
u16 val;
};
struct camera_common_power_rail {
struct regulator *dvdd;
struct regulator *avdd;
struct regulator *iovdd;
struct regulator *vcmvdd;
struct clk *mclk;
unsigned int pwdn_gpio;
unsigned int reset_gpio;
unsigned int af_gpio;
bool state;
};
struct camera_common_regulators {
const char *avdd;
const char *dvdd;
const char *iovdd;
const char *vcmvdd;
};
struct camera_common_pdata {
const char *mclk_name; /* NULL for default default_mclk */
const char *parentclk_name; /* NULL for no parent clock*/
unsigned int pwdn_gpio;
unsigned int reset_gpio;
unsigned int af_gpio;
bool ext_reg;
int (*power_on)(struct camera_common_power_rail *pw);
int (*power_off)(struct camera_common_power_rail *pw);
struct camera_common_regulators regulators;
bool use_cam_gpio;
bool has_eeprom;
bool v_flip;
bool h_mirror;
unsigned int fuse_id_addr;
};
struct camera_common_eeprom_data {
struct i2c_client *i2c_client;
struct i2c_adapter *adap;
struct i2c_board_info brd;
struct regmap *regmap;
};
int
regmap_util_write_table_8(struct regmap *regmap,
const struct reg_8 table[],
const struct reg_8 override_list[],
int num_override_regs,
u16 wait_ms_addr, u16 end_addr);
int
regmap_util_write_table_16_as_8(struct regmap *regmap,
const struct reg_16 table[],
const struct reg_16 override_list[],
int num_override_regs,
u16 wait_ms_addr, u16 end_addr);
enum switch_state {
SWITCH_OFF,
SWITCH_ON,
};
static const s64 switch_ctrl_qmenu[] = {
SWITCH_OFF, SWITCH_ON
};
/*
* The memory buffers allocated from nvrm are aligned to
* fullfill the hardware requirements:
* - size in alignment with a multiple of 128K/64K bytes,
* see CL http://git-master/r/256468 and bug 1321091.
*/
static const s64 size_align_ctrl_qmenu[] = {
1, (64 * 1024), (128 * 1024),
};
struct camera_common_frmfmt {
struct v4l2_frmsize_discrete size;
const int *framerates;
int num_framerates;
bool hdr_en;
int mode;
};
struct camera_common_colorfmt {
unsigned int code;
enum v4l2_colorspace colorspace;
int pix_fmt;
enum v4l2_xfer_func xfer_func;
enum v4l2_ycbcr_encoding ycbcr_enc;
enum v4l2_quantization quantization;
};
struct camera_common_framesync {
u32 inck; /* kHz */
u32 xhs; /* in inck */
u32 xvs; /* in xhs */
u32 fps; /* frames in 1000 second */
};
struct tegracam_device ;
struct camera_common_data;
struct camera_common_sensor_ops {
u32 numfrmfmts;
const struct camera_common_frmfmt *frmfmt_table;
int (*power_on)(struct camera_common_data *s_data);
int (*power_off)(struct camera_common_data *s_data);
int (*write_reg)(struct camera_common_data *s_data,
u16 addr, u8 val);
int (*read_reg)(struct camera_common_data *s_data,
u16 addr, u8 *val);
struct camera_common_pdata *(*parse_dt)(struct tegracam_device *tc_dev);
int (*power_get)(struct tegracam_device *tc_dev);
int (*power_put)(struct tegracam_device *tc_dev);
int (*get_framesync)(struct camera_common_data *s_data,
struct camera_common_framesync *vshs);
int (*set_mode)(struct tegracam_device *tc_dev);
int (*start_streaming)(struct tegracam_device *tc_dev);
int (*stop_streaming)(struct tegracam_device *tc_dev);
};
struct tegracam_sensor_data {
struct sensor_blob mode_blob;
struct sensor_blob ctrls_blob;
};
struct tegracam_ctrl_ops {
u32 numctrls;
u32 string_ctrl_size[TEGRA_CAM_MAX_STRING_CONTROLS];
const u32 *ctrl_cid_list;
bool is_blob_supported;
int (*set_gain)(struct tegracam_device *tc_dev, s64 val);
int (*set_exposure)(struct tegracam_device *tc_dev, s64 val);
int (*set_exposure_short)(struct tegracam_device *tc_dev, s64 val);
int (*set_frame_rate)(struct tegracam_device *tc_dev, s64 val);
int (*set_group_hold)(struct tegracam_device *tc_dev, bool val);
int (*fill_string_ctrl)(struct tegracam_device *tc_dev,
struct v4l2_ctrl *ctrl);
int (*set_gain_ex)(struct tegracam_device *tc_dev,
struct sensor_blob *blob, s64 val);
int (*set_exposure_ex)(struct tegracam_device *tc_dev,
struct sensor_blob *blob, s64 val);
int (*set_frame_rate_ex)(struct tegracam_device *tc_dev,
struct sensor_blob *blob, s64 val);
int (*set_group_hold_ex)(struct tegracam_device *tc_dev,
struct sensor_blob *blob, bool val);
int (*set_analog_gain)(struct tegracam_device *tc_dev, s64 val);
int (*set_digital_gain)(struct tegracam_device *tc_dev, s64 val,
int id);
int (*set_test_pattern)(struct tegracam_device *tc_dev, s32 val);
int (*set_flash)(struct tegracam_device *tc_dev, s32 val);
int (*set_flip)(struct tegracam_device *tc_dev, s32 val, int id);
};
struct tegracam_ctrl_handler {
struct v4l2_ctrl_handler ctrl_handler;
const struct tegracam_ctrl_ops *ctrl_ops;
struct tegracam_device *tc_dev;
struct tegracam_sensor_data sensor_data;
int numctrls;
struct v4l2_ctrl *ctrls[MAX_CID_CONTROLS];
};
struct camera_common_data {
struct camera_common_sensor_ops *ops;
struct v4l2_ctrl_handler *ctrl_handler;
struct device *dev;
const struct camera_common_frmfmt *frmfmt;
const struct camera_common_colorfmt *colorfmt;
struct dentry *debugdir;
struct camera_common_power_rail *power;
struct v4l2_subdev subdev;
struct v4l2_ctrl **ctrls;
struct sensor_properties sensor_props;
/* TODO: cleanup neeeded once all the sensors adapt new framework */
struct tegracam_ctrl_handler *tegracam_ctrl_hdl;
struct regmap *regmap;
struct camera_common_pdata *pdata;
/* TODO: cleanup needed for priv once all the sensors adapt new framework */
void *priv;
int numctrls;
int csi_port;
int numlanes;
int mode;
int mode_prop_idx;
int numfmts;
int def_mode, def_width, def_height;
int def_clk_freq;
int fmt_width, fmt_height;
int sensor_mode_id;
bool use_sensor_mode_id;
bool override_enable;
u32 version;
};
struct camera_common_focuser_data;
struct camera_common_focuser_ops {
int (*power_on)(struct camera_common_focuser_data *s_data);
int (*power_off)(struct camera_common_focuser_data *s_data);
int (*load_config)(struct camera_common_focuser_data *s_data);
int (*ctrls_init)(struct camera_common_focuser_data *s_data);
};
struct camera_common_focuser_data {
struct camera_common_focuser_ops *ops;
struct v4l2_ctrl_handler *ctrl_handler;
struct v4l2_subdev subdev;
struct v4l2_ctrl **ctrls;
struct device *dev;
struct nv_focuser_config config;
void *priv;
int pwr_dev;
int def_position;
};
static inline void msleep_range(unsigned int delay_base)
{
usleep_range(delay_base * 1000, delay_base * 1000 + 500);
}
static inline struct camera_common_data *to_camera_common_data(
const struct device *dev)
{
if (sensor_common_parse_num_modes(dev))
return container_of(dev_get_drvdata(dev),
struct camera_common_data, subdev);
return NULL;
}
static inline struct camera_common_focuser_data *to_camera_common_focuser_data(
const struct device *dev)
{
return container_of(dev_get_drvdata(dev),
struct camera_common_focuser_data, subdev);
}
int camera_common_g_ctrl(struct camera_common_data *s_data,
struct v4l2_control *control);
int camera_common_regulator_get(struct device *dev,
struct regulator **vreg, const char *vreg_name);
int camera_common_parse_clocks(struct device *dev,
struct camera_common_pdata *pdata);
int camera_common_parse_ports(struct device *dev,
struct camera_common_data *s_data);
int camera_common_mclk_enable(struct camera_common_data *s_data);
void camera_common_mclk_disable(struct camera_common_data *s_data);
int camera_common_debugfs_show(struct seq_file *s, void *unused);
ssize_t camera_common_debugfs_write(
struct file *file,
char const __user *buf,
size_t count,
loff_t *offset);
int camera_common_debugfs_open(struct inode *inode, struct file *file);
void camera_common_remove_debugfs(struct camera_common_data *s_data);
void camera_common_create_debugfs(struct camera_common_data *s_data,
const char *name);
const struct camera_common_colorfmt *camera_common_find_datafmt(
unsigned int code);
int camera_common_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code);
int camera_common_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
unsigned int *code);
int camera_common_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf);
int camera_common_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf);
int camera_common_g_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf);
int camera_common_enum_framesizes(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse);
int camera_common_enum_frameintervals(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_interval_enum *fie);
int camera_common_set_power(struct camera_common_data *data, int on);
int camera_common_s_power(struct v4l2_subdev *sd, int on);
void camera_common_dpd_disable(struct camera_common_data *s_data);
void camera_common_dpd_enable(struct camera_common_data *s_data);
int camera_common_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg);
int camera_common_get_framesync(struct v4l2_subdev *sd,
struct camera_common_framesync *vshs);
/* Common initialize and cleanup for camera */
int camera_common_initialize(struct camera_common_data *s_data,
const char *dev_name);
void camera_common_cleanup(struct camera_common_data *s_data);
/* Focuser */
int camera_common_focuser_init(struct camera_common_focuser_data *s_data);
int camera_common_focuser_s_power(struct v4l2_subdev *sd, int on);
const struct camera_common_colorfmt *camera_common_find_pixelfmt(
unsigned int pix_fmt);
/* common control layer init */
int tegracam_ctrl_set_overrides(struct tegracam_ctrl_handler *handler);
int tegracam_ctrl_handler_init(struct tegracam_ctrl_handler *handler);
int tegracam_init_ctrl_ranges(struct tegracam_ctrl_handler *handler);
int tegracam_init_ctrl_ranges_by_mode(
struct tegracam_ctrl_handler *handler,
u32 modeidx);
/* Regmap / RTCPU I2C driver interface */
struct tegra_i2c_rtcpu_sensor;
struct tegra_i2c_rtcpu_config;
struct camera_common_i2c {
struct regmap *regmap;
struct tegra_i2c_rtcpu_sensor *rt_sensor;
};
int camera_common_i2c_init(
struct camera_common_i2c *sensor,
struct i2c_client *client,
struct regmap_config *regmap_config,
const struct tegra_i2c_rtcpu_config *rtcpu_config);
int camera_common_i2c_aggregate(
struct camera_common_i2c *sensor,
bool start);
int camera_common_i2c_set_frame_id(
struct camera_common_i2c *sensor,
int frame_id);
int camera_common_i2c_read_reg8(
struct camera_common_i2c *sensor,
unsigned int addr,
u8 *data,
unsigned int count);
int camera_common_i2c_write_reg8(
struct camera_common_i2c *sensor,
unsigned int addr,
const u8 *data,
unsigned int count);
int camera_common_i2c_write_table_8(
struct camera_common_i2c *sensor,
const struct reg_8 table[],
const struct reg_8 override_list[],
int num_override_regs, u16 wait_ms_addr, u16 end_addr);
#endif /* __camera_common__ */

View File

@ -0,0 +1,181 @@
/**
* TEGRA_V4L2_CAMERA.h - utilities for tegra camera driver
*
* Copyright (c) 2017-2019, NVIDIA Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __TEGRA_V4L2_CAMERA__
#define __TEGRA_V4L2_CAMERA__
#include <linux/v4l2-controls.h>
#define TEGRA_CAMERA_CID_BASE (V4L2_CTRL_CLASS_CAMERA | 0x2000)
#define TEGRA_CAMERA_CID_FRAME_LENGTH (TEGRA_CAMERA_CID_BASE+0)
#define TEGRA_CAMERA_CID_COARSE_TIME (TEGRA_CAMERA_CID_BASE+1)
#define TEGRA_CAMERA_CID_COARSE_TIME_SHORT (TEGRA_CAMERA_CID_BASE+2)
#define TEGRA_CAMERA_CID_GROUP_HOLD (TEGRA_CAMERA_CID_BASE+3)
#define TEGRA_CAMERA_CID_HDR_EN (TEGRA_CAMERA_CID_BASE+4)
#define TEGRA_CAMERA_CID_EEPROM_DATA (TEGRA_CAMERA_CID_BASE+5)
#define TEGRA_CAMERA_CID_OTP_DATA (TEGRA_CAMERA_CID_BASE+6)
#define TEGRA_CAMERA_CID_FUSE_ID (TEGRA_CAMERA_CID_BASE+7)
#define TEGRA_CAMERA_CID_SENSOR_MODE_ID (TEGRA_CAMERA_CID_BASE+8)
#define TEGRA_CAMERA_CID_GAIN (TEGRA_CAMERA_CID_BASE+9)
#define TEGRA_CAMERA_CID_EXPOSURE (TEGRA_CAMERA_CID_BASE+10)
#define TEGRA_CAMERA_CID_FRAME_RATE (TEGRA_CAMERA_CID_BASE+11)
#define TEGRA_CAMERA_CID_EXPOSURE_SHORT (TEGRA_CAMERA_CID_BASE+12)
#define TEGRA_CAMERA_CID_SENSOR_CONFIG (TEGRA_CAMERA_CID_BASE+50)
#define TEGRA_CAMERA_CID_SENSOR_MODE_BLOB (TEGRA_CAMERA_CID_BASE+51)
#define TEGRA_CAMERA_CID_SENSOR_CONTROL_BLOB (TEGRA_CAMERA_CID_BASE+52)
#define TEGRA_CAMERA_CID_VI_BYPASS_MODE (TEGRA_CAMERA_CID_BASE+100)
#define TEGRA_CAMERA_CID_OVERRIDE_ENABLE (TEGRA_CAMERA_CID_BASE+101)
#define TEGRA_CAMERA_CID_VI_HEIGHT_ALIGN (TEGRA_CAMERA_CID_BASE+102)
#define TEGRA_CAMERA_CID_VI_SIZE_ALIGN (TEGRA_CAMERA_CID_BASE+103)
#define TEGRA_CAMERA_CID_WRITE_ISPFORMAT (TEGRA_CAMERA_CID_BASE+104)
#define TEGRA_CAMERA_CID_SENSOR_SIGNAL_PROPERTIES (TEGRA_CAMERA_CID_BASE+105)
#define TEGRA_CAMERA_CID_SENSOR_IMAGE_PROPERTIES (TEGRA_CAMERA_CID_BASE+106)
#define TEGRA_CAMERA_CID_SENSOR_CONTROL_PROPERTIES (TEGRA_CAMERA_CID_BASE+107)
#define TEGRA_CAMERA_CID_SENSOR_DV_TIMINGS (TEGRA_CAMERA_CID_BASE+108)
#define TEGRA_CAMERA_CID_LOW_LATENCY (TEGRA_CAMERA_CID_BASE+109)
/* Custom Controls */
#define V4L2_CID_GAIN_RED V4L2_CID_USER_BASE
#define V4L2_CID_GAIN_GREENR V4L2_CID_USER_BASE + 1
#define V4L2_CID_GAIN_GREENB V4L2_CID_USER_BASE + 2
#define V4L2_CID_GAIN_BLUE V4L2_CID_USER_BASE + 3
/**
* This is temporary with the current v4l2 infrastructure
* currently discussing with upstream maintainers our proposals and
* better approaches to resolve this
*/
#define TEGRA_CAMERA_CID_SENSOR_MODES (TEGRA_CAMERA_CID_BASE + 130)
#define MAX_BUFFER_SIZE 32
#define MAX_CID_CONTROLS 32
#define MAX_NUM_SENSOR_MODES 30
#define OF_MAX_STR_LEN 256
#define OF_SENSORMODE_PREFIX ("mode")
/*
* Scaling factor for converting a Q10.22 fixed point value
* back to its original floating point value
*/
#define FIXED_POINT_SCALING_FACTOR (1ULL << 22)
#define TEGRA_CAM_MAX_STRING_CONTROLS 8
#define TEGRA_CAM_STRING_CTRL_EEPROM_INDEX 0
#define TEGRA_CAM_STRING_CTRL_FUSEID_INDEX 1
#define TEGRA_CAM_STRING_CTRL_OTP_INDEX 2
#define CSI_PHY_MODE_DPHY 0
#define CSI_PHY_MODE_CPHY 1
#define SLVS_EC 2
struct unpackedU64 {
__u32 high;
__u32 low;
};
union __u64val {
struct unpackedU64 unpacked;
__u64 val;
};
struct sensor_signal_properties {
__u32 readout_orientation;
__u32 num_lanes;
__u32 mclk_freq;
union __u64val pixel_clock;
__u32 cil_settletime;
__u32 discontinuous_clk;
__u32 dpcm_enable;
__u32 tegra_sinterface;
__u32 phy_mode;
__u32 deskew_initial_enable;
__u32 deskew_periodic_enable;
union __u64val serdes_pixel_clock;
__u32 reserved[2];
};
struct sensor_image_properties {
__u32 width;
__u32 height;
__u32 line_length;
__u32 pixel_format;
__u32 embedded_metadata_height;
__u32 reserved[11];
};
struct sensor_dv_timings {
__u32 hfrontporch;
__u32 hsync;
__u32 hbackporch;
__u32 vfrontporch;
__u32 vsync;
__u32 vbackporch;
__u32 reserved[10];
};
struct sensor_control_properties {
__u32 gain_factor;
__u32 framerate_factor;
__u32 inherent_gain;
__u32 min_gain_val;
__u32 max_gain_val;
__u32 min_hdr_ratio;
__u32 max_hdr_ratio;
__u32 min_framerate;
__u32 max_framerate;
union __u64val min_exp_time;
union __u64val max_exp_time;
__u32 step_gain_val;
__u32 step_framerate;
__u32 exposure_factor;
union __u64val step_exp_time;
__u32 default_gain;
__u32 default_framerate;
union __u64val default_exp_time;
__u32 reserved[10];
};
struct sensor_mode_properties {
struct sensor_signal_properties signal_properties;
struct sensor_image_properties image_properties;
struct sensor_control_properties control_properties;
struct sensor_dv_timings dv_timings;
};
#define SENSOR_SIGNAL_PROPERTIES_CID_SIZE \
(sizeof(struct sensor_signal_properties) / sizeof(__u32))
#define SENSOR_IMAGE_PROPERTIES_CID_SIZE \
(sizeof(struct sensor_image_properties) / sizeof(__u32))
#define SENSOR_CONTROL_PROPERTIES_CID_SIZE \
(sizeof(struct sensor_control_properties) / sizeof(__u32))
#define SENSOR_DV_TIMINGS_CID_SIZE \
(sizeof(struct sensor_dv_timings) / sizeof(__u32))
#define SENSOR_MODE_PROPERTIES_CID_SIZE \
(sizeof(struct sensor_mode_properties) / sizeof(__u32))
#define SENSOR_CONFIG_SIZE \
(sizeof(struct sensor_cfg) / sizeof(__u32))
#define SENSOR_MODE_BLOB_SIZE \
(sizeof(struct sensor_blob) / sizeof(__u32))
#define SENSOR_CTRL_BLOB_SIZE \
(sizeof(struct sensor_blob) / sizeof(__u32))
#endif /* __TEGRA_V4L2_CAMERA__ */

View File

@ -1,29 +0,0 @@
#!/bin/bash
initial_gain=0
initial_exposure_time=0
while true; do sleep 0.5;
# Read center camera controls
echo `v4l2-ctl -d /dev/video0 --get-ctrl=gain --get-ctrl=exposure` > controls
awk '{print $2}' controls > get_control
actual_gain=`cat get_control`
awk '{print $4}' controls > get_control
actual_exposure_time=`cat get_control`
# Print controls
#echo -e "\n**Center Camera Controls**"
#cat controls
# Remove temp files
rm controls get_control
# Set R/L camera controls manually
if [ $actual_gain -ne $initial_gain ]; then
v4l2-ctl -d /dev/video1 --set-ctrl=gain=$actual_gain
fi
if [ $actual_exposure_time -ne $initial_exposure_time ]; then
v4l2-ctl -d /dev/video1 --set-ctrl=exposure=$actual_exposure_time
fi
# Define new initial value
initial_gain=$actual_gain
initial_exposure_time=$actual_exposure_time
done