Hi all,
We are porting IMX307 sensor driver to Jetson Nano L4T 32.4.3
IMX307 is 1920x1080, 30 FPS, 4 lanes, 12bit
IMX307 works as master mode, it means the the master clock INCK of IMX307 is from an external oscillator(74.25MHZ)
The driver probes OK, We use following command to capture frame:
v4l2-ctl --set-fmt-video=width=1920,height=1080,pixelformat=RG12 --stream-mmap --stream-count=1 -d /dev/video0 --stream-to=1.raw
But the streaming fails.Attempt to get one frame enters into probably infinite loop with the following error messages:
[10194.466296] imx307 6-001a: imx307_start_streaming: start stream
[10194.478825] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 0
[10194.512285] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 1
[10194.580067] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 2
[10194.612573] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 4
[10194.679537] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 5
[10194.712510] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 7
[10194.746640] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 8
[10194.813202] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 9
[10194.879899] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 11
[10194.913219] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 13
[10194.979387] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 14
[10195.012316] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 16
[10195.079283] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 17
[10195.145877] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 19
[10195.179180] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 21
[10195.212870] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 22
[10195.279267] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 23
[10195.312868] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 25
[10195.379277] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 26
[10195.412583] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 28
[10195.480060] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 29
[10195.512735] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 31
[10195.545874] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 32
[10195.579541] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 33
[10195.612435] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 34
[10195.679975] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 35
[10195.712441] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 37
[10195.813183] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 38
[10195.845499] vi 54080000.vi: tegra_channel_error_status:error 4000 frame 41
[10196.082801] video4linux video0: tegra_channel_capture_done: MW_ACK_DONE syncpoint time out!0
[10196.101994] vi 54080000.vi: TEGRA_CSI_PIXEL_PARSER_STATUS 0x00004015
[10196.102016] vi 54080000.vi: TEGRA_CSI_CIL_STATUS 0x00000000
[10196.102140] vi 54080000.vi: TEGRA_CSI_CILX_STATUS 0x00000000
[10196.102263] vi 54080000.vi: cil_settingtime was autocalculated
[10196.102291] vi 54080000.vi: csi clock settle time: 13, cil settle time: 10
[10196.102448] imx307 6-001a: imx307_stop_streaming: stop stream
[10196.178303] imx307 6-001a: imx307_power_off: power off
Here is our device tree for imx307
/*
* Copyright (c) 2018-2019, NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* 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 <dt-bindings/media/camera.h>
#include <dt-bindings/platform/t210/t210.h>
/ {
host1x {
vi_base: vi {
num-channels = <1>;
ports {
#address-cells = <1>;
#size-cells = <0>;
vi_port0: port@0 {
reg = <0>;
rbpcv2_imx307_vi_in0: endpoint {
port-index = <0>;
bus-width = <4>;
remote-endpoint = <&rbpcv2_imx307_csi_out0>;
};
};
};
};
csi_base: nvcsi {
num-channels = <1>;
#address-cells = <1>;
#size-cells = <0>;
csi_chan0: channel@0 {
reg = <0>;
ports {
#address-cells = <1>;
#size-cells = <0>;
csi_chan0_port0: port@0 {
reg = <0>;
rbpcv2_imx307_csi_in0: endpoint@0 {
port-index = <0>;
bus-width = <4>;
remote-endpoint = <&rbpcv2_imx307_out0>;
};
};
csi_chan0_port1: port@1 {
reg = <1>;
rbpcv2_imx307_csi_out0: endpoint@1 {
remote-endpoint = <&rbpcv2_imx307_vi_in0>;
};
};
};
};
};
i2c@546c0000 {
imx307_single_cam0: rbpcv2_imx307_a@34 {
compatible = "nvidia,imx307";
/* I2C device address */
reg = <0x1a>;
/* V4L2 device node location */
devnode = "video0";
/* Physical dimensions of sensor */
physical_w = "3.680";
physical_h = "2.760";
sensor_model = "imx307";
use_sensor_mode_id = "true";
#if 0
clocks = <&tegra_car TEGRA210_CLK_CLK_OUT_3>;
clock-names = "clk_out_3";
clock-frequency = <24000000>;
mclk = "clk_out_3";
#endif
/**
* ==== Modes ====
* A modeX node is required to support v4l2 driver
* implementation with NVIDIA camera software stack
*
* == Signal properties ==
*
* phy_mode = "";
* PHY mode used by the MIPI lanes for this device
*
* tegra_sinterface = "";
* CSI Serial interface connected to tegra
* Incase of virtual HW devices, use virtual
* For SW emulated devices, use host
*
* pix_clk_hz = "";
* Sensor pixel clock used for calculations like exposure and framerate
*
* readout_orientation = "0";
* Based on camera module orientation.
* Only change readout_orientation if you specifically
* Program a different readout order for this mode
*
* == Image format Properties ==
*
* active_w = "";
* Pixel active region width
*
* active_h = "";
* Pixel active region height
*
* pixel_t = "";
* The sensor readout pixel pattern
*
* line_length = "";
* Pixel line length (width) for sensor mode.
*
* == Source Control Settings ==
*
* Gain factor used to convert fixed point integer to float
* Gain range [min_gain/gain_factor, max_gain/gain_factor]
* Gain step [step_gain/gain_factor is the smallest step that can be configured]
* Default gain [Default gain to be initialized for the control.
* use min_gain_val as default for optimal results]
* Framerate factor used to convert fixed point integer to float
* Framerate range [min_framerate/framerate_factor, max_framerate/framerate_factor]
* Framerate step [step_framerate/framerate_factor is the smallest step that can be configured]
* Default Framerate [Default framerate to be initialized for the control.
* use max_framerate to get required performance]
* Exposure factor used to convert fixed point integer to float
* For convenience use 1 sec = 1000000us as conversion factor
* Exposure range [min_exp_time/exposure_factor, max_exp_time/exposure_factor]
* Exposure step [step_exp_time/exposure_factor is the smallest step that can be configured]
* Default Exposure Time [Default exposure to be initialized for the control.
* Set default exposure based on the default_framerate for optimal exposure settings]
*
* gain_factor = ""; (integer factor used for floating to fixed point conversion)
* min_gain_val = ""; (ceil to integer)
* max_gain_val = ""; (ceil to integer)
* step_gain_val = ""; (ceil to integer)
* default_gain = ""; (ceil to integer)
* Gain limits for mode
*
* exposure_factor = ""; (integer factor used for floating to fixed point conversion)
* min_exp_time = ""; (ceil to integer)
* max_exp_time = ""; (ceil to integer)
* step_exp_time = ""; (ceil to integer)
* default_exp_time = ""; (ceil to integer)
* Exposure Time limits for mode (sec)
*
* framerate_factor = ""; (integer factor used for floating to fixed point conversion)
* min_framerate = ""; (ceil to integer)
* max_framerate = ""; (ceil to integer)
* step_framerate = ""; (ceil to integer)
* default_framerate = ""; (ceil to integer)
* Framerate limits for mode (fps)
*
* embedded_metadata_height = "";
* Sensor embedded metadata height in units of rows.
* If sensor does not support embedded metadata value should be 0.
*/
mode0 { /* IMX307_MODE_1920x1080_30FPS */
#if 1
//mclk_khz = "24000";
mclk_khz = "74250";
num_lanes = "4";
tegra_sinterface = "serial_a";
phy_mode = "DPHY";
discontinuous_clk = "no";
dpcm_enable = "false";
cil_settletime = "0";
dynamic_pixel_bit_depth = "12";
csi_pixel_bit_depth = "12";
mode_type = "bayer";
pixel_phase = "rggb";
//pixel_t = "bayer_rggb";
active_w = "1920";
active_h = "1080";
readout_orientation = "0";
line_length = "1945";
inherent_gain = "1";
mclk_multiplier = "9.33";
//pix_clk_hz = "110000000";
pix_clk_hz = "74250000";
gain_factor = "10";
exposure_factor = "1000000";
min_gain_val = "0"; /* 0dB */
max_gain_val = "480"; /* 48dB */
step_gain_val = "3"; /* 0.3 */
default_gain = "0";
min_hdr_ratio = "1";
max_hdr_ratio = "1";
framerate_factor = "1000000";
min_framerate = "1500000";
max_framerate = "30000000"; /* 30 */
step_framerate = "1";
default_framerate = "30000000"; /* 30.0 fps */
min_exp_time = "30"; /* us */
max_exp_time = "660000"; /* us */
step_exp_time = "1";
default_exp_time = "33334"; /* us */
embedded_metadata_height = "0";
#endif
};
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
rbpcv2_imx307_out0: endpoint {
port-index = <0>;
bus-width = <4>;
remote-endpoint = <&rbpcv2_imx307_csi_in0>;
};
};
};
};
};
};
lens_imx307@RBPCV2 {
min_focus_distance = "0.0";
hyper_focal = "0.0";
focal_length = "3.04";
f_number = "2.0";
aperture = "0.0";
};
};
/ {
tcp: tegra-camera-platform {
compatible = "nvidia, tegra-camera-platform";
/**
* Physical settings to calculate max ISO BW
*
* num_csi_lanes = <>;
* Total number of CSI lanes when all cameras are active
*
* max_lane_speed = <>;
* Max lane speed in Kbit/s
*
* min_bits_per_pixel = <>;
* Min bits per pixel
*
* vi_peak_byte_per_pixel = <>;
* Max byte per pixel for the VI ISO case
*
* vi_bw_margin_pct = <>;
* Vi bandwidth margin in percentage
*
* max_pixel_rate = <>;
* Max pixel rate in Kpixel/s for the ISP ISO case
*
* isp_peak_byte_per_pixel = <>;
* Max byte per pixel for the ISP ISO case
*
* isp_bw_margin_pct = <>;
* Isp bandwidth margin in percentage
*/
num_csi_lanes = <4>;
max_lane_speed = <1500000>;
min_bits_per_pixel = <12>;
vi_peak_byte_per_pixel = <2>;
vi_bw_margin_pct = <25>;
max_pixel_rate = <34000>;
isp_peak_byte_per_pixel = <5>;
isp_bw_margin_pct = <25>;
/**
* The general guideline for naming badge_info contains 3 parts, and is as follows,
* The first part is the camera_board_id for the module; if the module is in a FFD
* platform, then use the platform name for this part.
* The second part contains the position of the module, ex. "rear" or "front".
* The third part contains the last 6 characters of a part number which is found
* in the module's specsheet from the vendor.
*/
modules {
cam_module0: module0 {
badge = "porg_front_RBPCV2";
position = "front";
orientation = "1";
cam_module0_drivernode0: drivernode0 {
pcl_id = "v4l2_sensor";
devname = "imx307 6-0010";
proc-device-tree = "/proc/device-tree/host1x/i2c@546c0000/rbpcv2_imx307_a@34";
};
cam_module0_drivernode1: drivernode1 {
pcl_id = "v4l2_lens";
proc-device-tree = "/proc/device-tree/lens_imx307@RBPCV2/";
};
};
};
};
};
imx307.c
/*
* imx307.c - imx307 sensor 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/>.
*/
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <media/tegra_v4l2_camera.h>
#include <media/tegracam_core.h>
#include <media/imx307.h>
#include "../platform/tegra/camera/camera_gpio.h"
#include "imx307_mode_tbls.h"
/* imx307 - sensor parameter limits */
#define IMX307_MIN_GAIN 0x00
#define IMX307_MAX_GAIN 0xff
#define IMX307_MIN_FRAME_LENGTH 0x0100
#define IMX307_MAX_FRAME_LENGTH 0xffff
#define IMX307_MIN_COARSE_EXPOSURE 0x0001
#define IMX307_MAX_COARSE_DIFF 0x0004
/* imx307 sensor register address */
#define IMX307_MODEL_ID_ADDR_MSB 0x0000
#define IMX307_MODEL_ID_ADDR_LSB 0x0001
#define IMX307_GAIN_ADDR 0x3014
#define IMX307_FRAME_LENGTH_ADDR_MSB 0x0160
#define IMX307_FRAME_LENGTH_ADDR_LSB 0x0161
#define IMX307_COARSE_INTEG_TIME_ADDR_MSB 0x015a
#define IMX307_COARSE_INTEG_TIME_ADDR_LSB 0x015b
#define IMX307_FINE_INTEG_TIME_ADDR_MSB 0x0388
#define IMX307_FINE_INTEG_TIME_ADDR_LSB 0x0389
static const struct of_device_id imx307_of_match[] = {
{ .compatible = "nvidia,imx307", },
{ },
};
MODULE_DEVICE_TABLE(of, imx307_of_match);
static const u32 ctrl_cid_list[] = {
TEGRA_CAMERA_CID_GAIN,
TEGRA_CAMERA_CID_EXPOSURE,
TEGRA_CAMERA_CID_FRAME_RATE,
TEGRA_CAMERA_CID_SENSOR_MODE_ID,
};
struct imx307 {
struct i2c_client *i2c_client;
struct v4l2_subdev *subdev;
u16 fine_integ_time;
u32 frame_length;
struct camera_common_data *s_data;
struct tegracam_device *tc_dev;
};
static const struct regmap_config sensor_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.cache_type = REGCACHE_RBTREE,
// .use_single_rw = true,
};
static inline void imx307_get_frame_length_regs(imx307_reg *regs,
u32 frame_length)
{
regs->addr = IMX307_FRAME_LENGTH_ADDR_MSB;
regs->val = (frame_length >> 8) & 0xff;
(regs + 1)->addr = IMX307_FRAME_LENGTH_ADDR_LSB;
(regs + 1)->val = (frame_length) & 0xff;
}
static inline void imx307_get_coarse_integ_time_regs(imx307_reg *regs,
u32 coarse_time)
{
regs->addr = IMX307_COARSE_INTEG_TIME_ADDR_MSB;
regs->val = (coarse_time >> 8) & 0xff;
(regs + 1)->addr = IMX307_COARSE_INTEG_TIME_ADDR_LSB;
(regs + 1)->val = (coarse_time) & 0xff;
}
static inline void imx307_get_gain_reg(imx307_reg *reg, u8 gain)
{
reg->addr = IMX307_GAIN_ADDR;
reg->val = gain & 0xff;
}
static inline int imx307_read_reg(struct camera_common_data *s_data,
u16 addr, u8 *val)
{
int err = 0;
u32 reg_val = 0;
err = regmap_read(s_data->regmap, addr, ®_val);
*val = reg_val & 0xff;
return err;
}
static inline int imx307_write_reg(struct camera_common_data *s_data,
u16 addr, u8 val)
{
int err = 0;
err = regmap_write(s_data->regmap, addr, val);
if (err)
dev_err(s_data->dev, "%s: i2c write failed, 0x%x = %x",
__func__, addr, val);
return err;
}
static int imx307_read_table(struct imx307 *priv, const imx307_reg table[])
{
u8 reg_val[2];
while(table->addr != IMX307_TABLE_END)
{
if(table->addr == IMX307_TABLE_WAIT_MS)
{
table++;
continue;
}
imx307_read_reg(priv->s_data,table->addr,®_val[0]);
printk("imx307 reg 0x%x val 0x%02x\n",table->addr,reg_val[0]);
table++;
}
return 0;
}
static int imx307_write_table(struct imx307 *priv, const imx307_reg table[])
{
return regmap_util_write_table_8(priv->s_data->regmap, table, NULL, 0,
IMX307_TABLE_WAIT_MS, IMX307_TABLE_END);
}
static int imx307_set_group_hold(struct tegracam_device *tc_dev, bool val)
{
/* imx307 does not support group hold */
return 0;
}
static int imx307_set_gain(struct tegracam_device *tc_dev, s64 val)
{
#if 0
struct camera_common_data *s_data = tc_dev->s_data;
struct device *dev = s_data->dev;
const struct sensor_mode_properties *mode =
&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];
int err = 0;
imx307_reg gain_reg;
s16 gain;
if (val < mode->control_properties.min_gain_val)
val = mode->control_properties.min_gain_val;
else if (val > mode->control_properties.max_gain_val)
val = mode->control_properties.max_gain_val;
/* translate value (from normalized analog gain) */
gain = (s16)((256 * mode->control_properties.gain_factor) / val);
gain = 256 - gain;
if (gain < IMX307_MIN_GAIN)
gain = IMX307_MAX_GAIN;
else if (gain > IMX307_MAX_GAIN)
gain = IMX307_MAX_GAIN;
dev_dbg(dev, "%s: val: %lld (/%d) [times], gain: %u\n",
__func__, val, mode->control_properties.gain_factor, gain);
imx307_get_gain_reg(&gain_reg, (u8)gain);
err = imx307_write_reg(s_data, gain_reg.addr, gain_reg.val);
if (err)
dev_dbg(dev, "%s: gain control error\n", __func__);
#endif
return 0;
}
static int imx307_set_frame_rate(struct tegracam_device *tc_dev, s64 val)
{
#if 0
struct camera_common_data *s_data = tc_dev->s_data;
struct imx307 *priv = (struct imx307 *)tc_dev->priv;
struct device *dev = tc_dev->dev;
const struct sensor_mode_properties *mode =
&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];
int err = 0;
imx307_reg fl_regs[2];
u32 frame_length;
int i;
frame_length = (u32)(mode->signal_properties.pixel_clock.val *
(u64)mode->control_properties.framerate_factor /
mode->image_properties.line_length / val);
if (frame_length < IMX307_MIN_FRAME_LENGTH)
frame_length = IMX307_MIN_FRAME_LENGTH;
else if (frame_length > IMX307_MAX_FRAME_LENGTH)
frame_length = IMX307_MAX_FRAME_LENGTH;
dev_dbg(dev,
"%s: val: %llde-6 [fps], frame_length: %u [lines]\n",
__func__, val, frame_length);
imx307_get_frame_length_regs(fl_regs, frame_length);
for (i = 0; i < 2; i++) {
err = imx307_write_reg(s_data, fl_regs[i].addr, fl_regs[i].val);
if (err) {
dev_dbg(dev,
"%s: frame_length control error\n", __func__);
return err;
}
}
priv->frame_length = frame_length;
#endif
return 0;
}
static int imx307_set_exposure(struct tegracam_device *tc_dev, s64 val)
{
#if 0
struct camera_common_data *s_data = tc_dev->s_data;
struct imx307 *priv = (struct imx307 *)tc_dev->priv;
struct device *dev = tc_dev->dev;
const struct sensor_mode_properties *mode =
&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];
int err = 0;
imx307_reg ct_regs[2];
const s32 max_coarse_time = priv->frame_length - IMX307_MAX_COARSE_DIFF;
const s32 fine_integ_time_factor = priv->fine_integ_time *
mode->control_properties.exposure_factor /
mode->signal_properties.pixel_clock.val;
u32 coarse_time;
int i;
coarse_time = (val - fine_integ_time_factor)
* mode->signal_properties.pixel_clock.val
/ mode->control_properties.exposure_factor
/ mode->image_properties.line_length;
if (coarse_time < IMX307_MIN_COARSE_EXPOSURE)
coarse_time = IMX307_MIN_COARSE_EXPOSURE;
else if (coarse_time > max_coarse_time) {
coarse_time = max_coarse_time;
dev_dbg(dev,
"%s: exposure limited by frame_length: %d [lines]\n",
__func__, max_coarse_time);
}
dev_dbg(dev, "%s: val: %lld [us], coarse_time: %d [lines]\n",
__func__, val, coarse_time);
imx307_get_coarse_integ_time_regs(ct_regs, coarse_time);
for (i = 0; i < 2; i++) {
err = imx307_write_reg(s_data, ct_regs[i].addr, ct_regs[i].val);
if (err) {
dev_dbg(dev,
"%s: coarse_time control error\n", __func__);
return err;
}
}
#endif
return 0;
}
static struct tegracam_ctrl_ops imx307_ctrl_ops = {
.numctrls = ARRAY_SIZE(ctrl_cid_list),
.ctrl_cid_list = ctrl_cid_list,
.set_gain = imx307_set_gain,
.set_exposure = imx307_set_exposure,
.set_frame_rate = imx307_set_frame_rate,
.set_group_hold = imx307_set_group_hold,
};
static int imx307_power_on(struct camera_common_data *s_data)
{
int err = 0;
struct camera_common_power_rail *pw = s_data->power;
struct camera_common_pdata *pdata = s_data->pdata;
struct device *dev = s_data->dev;
dev_info(dev, "%s: power on\n", __func__);
if (pdata && pdata->power_on) {
err = pdata->power_on(pw);
if (err)
dev_err(dev, "%s failed.\n", __func__);
else
pw->state = SWITCH_ON;
return err;
}
if (pw->reset_gpio) {
if (gpio_cansleep(pw->reset_gpio))
gpio_set_value_cansleep(pw->reset_gpio, 0);
else
gpio_set_value(pw->reset_gpio, 0);
}
if (unlikely(!(pw->avdd || pw->iovdd || pw->dvdd)))
goto skip_power_seqn;
usleep_range(10, 20);
if (pw->avdd) {
err = regulator_enable(pw->avdd);
if (err)
goto imx307_avdd_fail;
}
if (pw->iovdd) {
err = regulator_enable(pw->iovdd);
if (err)
goto imx307_iovdd_fail;
}
if (pw->dvdd) {
err = regulator_enable(pw->dvdd);
if (err)
goto imx307_dvdd_fail;
}
usleep_range(10, 20);
skip_power_seqn:
if (pw->reset_gpio) {
if (gpio_cansleep(pw->reset_gpio))
gpio_set_value_cansleep(pw->reset_gpio, 1);
else
gpio_set_value(pw->reset_gpio, 1);
}
/* Need to wait for t4 + t5 + t9 time as per the data sheet */
/* t4 - 200us, t5 - 21.2ms, t9 - 1.2ms */
usleep_range(23000, 23100);
pw->state = SWITCH_ON;
return 0;
imx307_dvdd_fail:
regulator_disable(pw->iovdd);
imx307_iovdd_fail:
regulator_disable(pw->avdd);
imx307_avdd_fail:
dev_err(dev, "%s failed.\n", __func__);
return -ENODEV;
}
static int imx307_power_off(struct camera_common_data *s_data)
{
int err = 0;
struct camera_common_power_rail *pw = s_data->power;
struct camera_common_pdata *pdata = s_data->pdata;
struct device *dev = s_data->dev;
dev_info(dev, "%s: power off\n", __func__);
return 0;
if (pdata && pdata->power_off) {
err = pdata->power_off(pw);
if (err) {
dev_err(dev, "%s failed.\n", __func__);
return err;
}
} else {
if (pw->reset_gpio) {
if (gpio_cansleep(pw->reset_gpio))
gpio_set_value_cansleep(pw->reset_gpio, 0);
else
gpio_set_value(pw->reset_gpio, 0);
}
usleep_range(10, 10);
if (pw->dvdd)
regulator_disable(pw->dvdd);
if (pw->iovdd)
regulator_disable(pw->iovdd);
if (pw->avdd)
regulator_disable(pw->avdd);
}
pw->state = SWITCH_OFF;
return 0;
}
static int imx307_power_put(struct tegracam_device *tc_dev)
{
struct camera_common_data *s_data = tc_dev->s_data;
struct camera_common_power_rail *pw = s_data->power;
if (unlikely(!pw))
return -EFAULT;
if (likely(pw->dvdd))
devm_regulator_put(pw->dvdd);
if (likely(pw->avdd))
devm_regulator_put(pw->avdd);
if (likely(pw->iovdd))
devm_regulator_put(pw->iovdd);
pw->dvdd = NULL;
pw->avdd = NULL;
pw->iovdd = NULL;
if (likely(pw->reset_gpio))
gpio_free(pw->reset_gpio);
return 0;
}
static int imx307_power_get(struct tegracam_device *tc_dev)
{
struct device *dev = tc_dev->dev;
struct camera_common_data *s_data = tc_dev->s_data;
struct camera_common_power_rail *pw = s_data->power;
struct camera_common_pdata *pdata = s_data->pdata;
struct clk *parent;
int err = 0;
if (!pdata) {
dev_err(dev, "pdata missing\n");
return -EFAULT;
}
/* Sensor MCLK (aka. INCK) */
if (pdata->mclk_name) {
pw->mclk = devm_clk_get(dev, pdata->mclk_name);
if (IS_ERR(pw->mclk)) {
dev_err(dev, "unable to get clock %s\n",
pdata->mclk_name);
return PTR_ERR(pw->mclk);
}
if (pdata->parentclk_name) {
parent = devm_clk_get(dev, pdata->parentclk_name);
if (IS_ERR(parent)) {
dev_err(dev, "unable to get parent clock %s",
pdata->parentclk_name);
} else
clk_set_parent(pw->mclk, parent);
}
}
/* analog 2.8v */
if (pdata->regulators.avdd)
err |= camera_common_regulator_get(dev,
&pw->avdd, pdata->regulators.avdd);
/* IO 1.8v */
if (pdata->regulators.iovdd)
err |= camera_common_regulator_get(dev,
&pw->iovdd, pdata->regulators.iovdd);
/* dig 1.2v */
if (pdata->regulators.dvdd)
err |= camera_common_regulator_get(dev,
&pw->dvdd, pdata->regulators.dvdd);
if (err) {
dev_err(dev, "%s: unable to get regulator(s)\n", __func__);
goto done;
}
/* Reset or ENABLE GPIO */
pw->reset_gpio = pdata->reset_gpio;
err = gpio_request(pw->reset_gpio, "cam_reset_gpio");
if (err < 0) {
dev_err(dev, "%s: unable to request reset_gpio (%d)\n",
__func__, err);
goto done;
}
done:
pw->state = SWITCH_OFF;
return err;
}
static struct camera_common_pdata *imx307_parse_dt(
struct tegracam_device *tc_dev)
{
struct device *dev = tc_dev->dev;
struct device_node *np = dev->of_node;
struct camera_common_pdata *board_priv_pdata;
const struct of_device_id *match;
struct camera_common_pdata *ret = NULL;
int err = 0;
int gpio;
if (!np)
return NULL;
match = of_match_device(imx307_of_match, dev);
if (!match) {
dev_err(dev, "Failed to find matching dt id\n");
return NULL;
}
board_priv_pdata = devm_kzalloc(dev,
sizeof(*board_priv_pdata), GFP_KERNEL);
if (!board_priv_pdata)
return NULL;
gpio = of_get_named_gpio(np, "reset-gpios", 0);
if (gpio < 0) {
if (gpio == -EPROBE_DEFER)
ret = ERR_PTR(-EPROBE_DEFER);
dev_err(dev, "reset-gpios not found\n");
goto error;
}
board_priv_pdata->reset_gpio = (unsigned int)gpio;
err = of_property_read_string(np, "mclk", &board_priv_pdata->mclk_name);
if (err)
dev_dbg(dev, "mclk name not present, "
"assume sensor driven externally\n");
err = of_property_read_string(np, "avdd-reg",
&board_priv_pdata->regulators.avdd);
err |= of_property_read_string(np, "iovdd-reg",
&board_priv_pdata->regulators.iovdd);
err |= of_property_read_string(np, "dvdd-reg",
&board_priv_pdata->regulators.dvdd);
if (err)
dev_dbg(dev, "avdd, iovdd and/or dvdd reglrs. not present, "
"assume sensor powered independently\n");
board_priv_pdata->has_eeprom =
of_property_read_bool(np, "has-eeprom");
return board_priv_pdata;
error:
devm_kfree(dev, board_priv_pdata);
return ret;
}
static int imx307_set_mode(struct tegracam_device *tc_dev)
{
struct imx307 *priv = (struct imx307 *)tegracam_get_privdata(tc_dev);
struct camera_common_data *s_data = tc_dev->s_data;
struct device *dev = tc_dev->dev;
int err = 0;
dev_info(dev, "%s: setmod %d \n", __func__,s_data->mode);
err = imx307_write_table(priv, mode_table[IMX307_MODE_COMMON]);
if (err)
return err;
err = imx307_write_table(priv, mode_table[s_data->mode]);
if (err)
return err;
return 0;
}
static int imx307_start_streaming(struct tegracam_device *tc_dev)
{
struct device *dev = tc_dev->dev;
struct imx307 *priv = (struct imx307 *)tegracam_get_privdata(tc_dev);
dev_info(dev, "%s: start stream\n", __func__);
return imx307_write_table(priv, mode_table[IMX307_START_STREAM]);
}
static int imx307_stop_streaming(struct tegracam_device *tc_dev)
{
struct device *dev = tc_dev->dev;
int err;
struct imx307 *priv = (struct imx307 *)tegracam_get_privdata(tc_dev);
dev_info(dev, "%s: stop stream\n", __func__);
err = imx307_write_table(priv, mode_table[IMX307_STOP_STREAM]);
usleep_range(50000, 51000);
return err;
}
static struct camera_common_sensor_ops imx307_common_ops = {
.numfrmfmts = ARRAY_SIZE(imx307_frmfmt),
.frmfmt_table = imx307_frmfmt,
.power_on = imx307_power_on,
.power_off = imx307_power_off,
.write_reg = imx307_write_reg,
.read_reg = imx307_read_reg,
.parse_dt = imx307_parse_dt,
.power_get = imx307_power_get,
.power_put = imx307_power_put,
.set_mode = imx307_set_mode,
.start_streaming = imx307_start_streaming,
.stop_streaming = imx307_stop_streaming,
};
static int imx307_board_setup(struct imx307 *priv)
{
struct camera_common_data *s_data = priv->s_data;
struct camera_common_pdata *pdata = s_data->pdata;
struct device *dev = s_data->dev;
u8 reg_val[2];
int err = 0;
if (pdata->mclk_name) {
err = camera_common_mclk_enable(s_data);
if (err) {
dev_err(dev, "error turning on mclk (%d)\n", err);
goto done;
}
}
err = imx307_power_on(s_data);
if (err) {
dev_err(dev, "error during power on sensor (%d)\n", err);
goto err_power_on;
}
err_power_on:
if (pdata->mclk_name)
camera_common_mclk_disable(s_data);
done:
return err;
}
static int imx307_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
dev_dbg(&client->dev, "%s:\n", __func__);
return 0;
}
static const struct v4l2_subdev_internal_ops imx307_subdev_internal_ops = {
.open = imx307_open,
};
static int imx307_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct tegracam_device *tc_dev;
struct imx307 *priv;
int err;
#if 1
struct device_node *np= dev->of_node;
do
{
printk("name %s \n",np->name);
printk("fame %s \n",np->full_name);
of_node_put(np);
}while((np = of_get_next_parent(np)));
#endif
dev_dbg(dev, "probing v4l2 sensor at addr 0x%0x\n", client->addr);
dev_info(dev, "probing v4l2 sensor at addr 0x%0x\n", client->addr);
if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
return -EINVAL;
priv = devm_kzalloc(dev,
sizeof(struct imx307), GFP_KERNEL);
if (!priv)
return -ENOMEM;
tc_dev = devm_kzalloc(dev,
sizeof(struct tegracam_device), GFP_KERNEL);
if (!tc_dev)
return -ENOMEM;
priv->i2c_client = tc_dev->client = client;
tc_dev->dev = dev;
strncpy(tc_dev->name, "imx307", sizeof(tc_dev->name));
tc_dev->dev_regmap_config = &sensor_regmap_config;
tc_dev->sensor_ops = &imx307_common_ops;
tc_dev->v4l2sd_internal_ops = &imx307_subdev_internal_ops;
tc_dev->tcctrl_ops = &imx307_ctrl_ops;
err = tegracam_device_register(tc_dev);
if (err) {
dev_err(dev, "tegra camera driver registration failed\n");
return err;
}
priv->tc_dev = tc_dev;
priv->s_data = tc_dev->s_data;
priv->subdev = &tc_dev->s_data->subdev;
tegracam_set_privdata(tc_dev, (void *)priv);
err = imx307_board_setup(priv);
if (err) {
dev_err(dev, "board setup failed\n");
return err;
}
err = tegracam_v4l2subdev_register(tc_dev, true);
if (err) {
dev_err(dev, "tegra camera subdev registration failed\n");
return err;
}
dev_info(dev, "detected imx307 sensor\n");
return 0;
}
static int imx307_remove(struct i2c_client *client)
{
struct camera_common_data *s_data = to_camera_common_data(&client->dev);
struct imx307 *priv = (struct imx307 *)s_data->priv;
tegracam_v4l2subdev_unregister(priv->tc_dev);
tegracam_device_unregister(priv->tc_dev);
return 0;
}
static const struct i2c_device_id imx307_id[] = {
{ "imx307", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, imx307_id);
static struct i2c_driver imx307_i2c_driver = {
.driver = {
.name = "imx307",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(imx307_of_match),
},
.probe = imx307_probe,
.remove = imx307_remove,
.id_table = imx307_id,
};
module_i2c_driver(imx307_i2c_driver);
MODULE_DESCRIPTION("Media Controller driver for Sony IMX307");
MODULE_AUTHOR("NVIDIA Corporation");
MODULE_LICENSE("GPL v2");
imx307_mode_tbls.h
/*
* imx307.c - imx307 sensor 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/>.
*/
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <media/tegra_v4l2_camera.h>
#include <media/tegracam_core.h>
#include <media/imx307.h>
#include "../platform/tegra/camera/camera_gpio.h"
#include "imx307_mode_tbls.h"
/* imx307 - sensor parameter limits */
#define IMX307_MIN_GAIN 0x00
#define IMX307_MAX_GAIN 0xff
#define IMX307_MIN_FRAME_LENGTH 0x0100
#define IMX307_MAX_FRAME_LENGTH 0xffff
#define IMX307_MIN_COARSE_EXPOSURE 0x0001
#define IMX307_MAX_COARSE_DIFF 0x0004
/* imx307 sensor register address */
#define IMX307_MODEL_ID_ADDR_MSB 0x0000
#define IMX307_MODEL_ID_ADDR_LSB 0x0001
#define IMX307_GAIN_ADDR 0x3014
#define IMX307_FRAME_LENGTH_ADDR_MSB 0x0160
#define IMX307_FRAME_LENGTH_ADDR_LSB 0x0161
#define IMX307_COARSE_INTEG_TIME_ADDR_MSB 0x015a
#define IMX307_COARSE_INTEG_TIME_ADDR_LSB 0x015b
#define IMX307_FINE_INTEG_TIME_ADDR_MSB 0x0388
#define IMX307_FINE_INTEG_TIME_ADDR_LSB 0x0389
static const struct of_device_id imx307_of_match[] = {
{ .compatible = "nvidia,imx307", },
{ },
};
MODULE_DEVICE_TABLE(of, imx307_of_match);
static const u32 ctrl_cid_list[] = {
TEGRA_CAMERA_CID_GAIN,
TEGRA_CAMERA_CID_EXPOSURE,
TEGRA_CAMERA_CID_FRAME_RATE,
TEGRA_CAMERA_CID_SENSOR_MODE_ID,
};
struct imx307 {
struct i2c_client *i2c_client;
struct v4l2_subdev *subdev;
u16 fine_integ_time;
u32 frame_length;
struct camera_common_data *s_data;
struct tegracam_device *tc_dev;
};
static const struct regmap_config sensor_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.cache_type = REGCACHE_RBTREE,
// .use_single_rw = true,
};
static inline void imx307_get_frame_length_regs(imx307_reg *regs,
u32 frame_length)
{
regs->addr = IMX307_FRAME_LENGTH_ADDR_MSB;
regs->val = (frame_length >> 8) & 0xff;
(regs + 1)->addr = IMX307_FRAME_LENGTH_ADDR_LSB;
(regs + 1)->val = (frame_length) & 0xff;
}
static inline void imx307_get_coarse_integ_time_regs(imx307_reg *regs,
u32 coarse_time)
{
regs->addr = IMX307_COARSE_INTEG_TIME_ADDR_MSB;
regs->val = (coarse_time >> 8) & 0xff;
(regs + 1)->addr = IMX307_COARSE_INTEG_TIME_ADDR_LSB;
(regs + 1)->val = (coarse_time) & 0xff;
}
static inline void imx307_get_gain_reg(imx307_reg *reg, u8 gain)
{
reg->addr = IMX307_GAIN_ADDR;
reg->val = gain & 0xff;
}
static inline int imx307_read_reg(struct camera_common_data *s_data,
u16 addr, u8 *val)
{
int err = 0;
u32 reg_val = 0;
err = regmap_read(s_data->regmap, addr, ®_val);
*val = reg_val & 0xff;
return err;
}
static inline int imx307_write_reg(struct camera_common_data *s_data,
u16 addr, u8 val)
{
int err = 0;
err = regmap_write(s_data->regmap, addr, val);
if (err)
dev_err(s_data->dev, "%s: i2c write failed, 0x%x = %x",
__func__, addr, val);
return err;
}
static int imx307_read_table(struct imx307 *priv, const imx307_reg table[])
{
u8 reg_val[2];
while(table->addr != IMX307_TABLE_END)
{
if(table->addr == IMX307_TABLE_WAIT_MS)
{
table++;
continue;
}
imx307_read_reg(priv->s_data,table->addr,®_val[0]);
printk("imx307 reg 0x%x val 0x%02x\n",table->addr,reg_val[0]);
table++;
}
return 0;
}
static int imx307_write_table(struct imx307 *priv, const imx307_reg table[])
{
return regmap_util_write_table_8(priv->s_data->regmap, table, NULL, 0,
IMX307_TABLE_WAIT_MS, IMX307_TABLE_END);
}
static int imx307_set_group_hold(struct tegracam_device *tc_dev, bool val)
{
/* imx307 does not support group hold */
return 0;
}
static int imx307_set_gain(struct tegracam_device *tc_dev, s64 val)
{
#if 0
struct camera_common_data *s_data = tc_dev->s_data;
struct device *dev = s_data->dev;
const struct sensor_mode_properties *mode =
&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];
int err = 0;
imx307_reg gain_reg;
s16 gain;
if (val < mode->control_properties.min_gain_val)
val = mode->control_properties.min_gain_val;
else if (val > mode->control_properties.max_gain_val)
val = mode->control_properties.max_gain_val;
/* translate value (from normalized analog gain) */
gain = (s16)((256 * mode->control_properties.gain_factor) / val);
gain = 256 - gain;
if (gain < IMX307_MIN_GAIN)
gain = IMX307_MAX_GAIN;
else if (gain > IMX307_MAX_GAIN)
gain = IMX307_MAX_GAIN;
dev_dbg(dev, "%s: val: %lld (/%d) [times], gain: %u\n",
__func__, val, mode->control_properties.gain_factor, gain);
imx307_get_gain_reg(&gain_reg, (u8)gain);
err = imx307_write_reg(s_data, gain_reg.addr, gain_reg.val);
if (err)
dev_dbg(dev, "%s: gain control error\n", __func__);
#endif
return 0;
}
static int imx307_set_frame_rate(struct tegracam_device *tc_dev, s64 val)
{
#if 0
struct camera_common_data *s_data = tc_dev->s_data;
struct imx307 *priv = (struct imx307 *)tc_dev->priv;
struct device *dev = tc_dev->dev;
const struct sensor_mode_properties *mode =
&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];
int err = 0;
imx307_reg fl_regs[2];
u32 frame_length;
int i;
frame_length = (u32)(mode->signal_properties.pixel_clock.val *
(u64)mode->control_properties.framerate_factor /
mode->image_properties.line_length / val);
if (frame_length < IMX307_MIN_FRAME_LENGTH)
frame_length = IMX307_MIN_FRAME_LENGTH;
else if (frame_length > IMX307_MAX_FRAME_LENGTH)
frame_length = IMX307_MAX_FRAME_LENGTH;
dev_dbg(dev,
"%s: val: %llde-6 [fps], frame_length: %u [lines]\n",
__func__, val, frame_length);
imx307_get_frame_length_regs(fl_regs, frame_length);
for (i = 0; i < 2; i++) {
err = imx307_write_reg(s_data, fl_regs[i].addr, fl_regs[i].val);
if (err) {
dev_dbg(dev,
"%s: frame_length control error\n", __func__);
return err;
}
}
priv->frame_length = frame_length;
#endif
return 0;
}
static int imx307_set_exposure(struct tegracam_device *tc_dev, s64 val)
{
#if 0
struct camera_common_data *s_data = tc_dev->s_data;
struct imx307 *priv = (struct imx307 *)tc_dev->priv;
struct device *dev = tc_dev->dev;
const struct sensor_mode_properties *mode =
&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];
int err = 0;
imx307_reg ct_regs[2];
const s32 max_coarse_time = priv->frame_length - IMX307_MAX_COARSE_DIFF;
const s32 fine_integ_time_factor = priv->fine_integ_time *
mode->control_properties.exposure_factor /
mode->signal_properties.pixel_clock.val;
u32 coarse_time;
int i;
coarse_time = (val - fine_integ_time_factor)
* mode->signal_properties.pixel_clock.val
/ mode->control_properties.exposure_factor
/ mode->image_properties.line_length;
if (coarse_time < IMX307_MIN_COARSE_EXPOSURE)
coarse_time = IMX307_MIN_COARSE_EXPOSURE;
else if (coarse_time > max_coarse_time) {
coarse_time = max_coarse_time;
dev_dbg(dev,
"%s: exposure limited by frame_length: %d [lines]\n",
__func__, max_coarse_time);
}
dev_dbg(dev, "%s: val: %lld [us], coarse_time: %d [lines]\n",
__func__, val, coarse_time);
imx307_get_coarse_integ_time_regs(ct_regs, coarse_time);
for (i = 0; i < 2; i++) {
err = imx307_write_reg(s_data, ct_regs[i].addr, ct_regs[i].val);
if (err) {
dev_dbg(dev,
"%s: coarse_time control error\n", __func__);
return err;
}
}
#endif
return 0;
}
static struct tegracam_ctrl_ops imx307_ctrl_ops = {
.numctrls = ARRAY_SIZE(ctrl_cid_list),
.ctrl_cid_list = ctrl_cid_list,
.set_gain = imx307_set_gain,
.set_exposure = imx307_set_exposure,
.set_frame_rate = imx307_set_frame_rate,
.set_group_hold = imx307_set_group_hold,
};
static int imx307_power_on(struct camera_common_data *s_data)
{
int err = 0;
struct camera_common_power_rail *pw = s_data->power;
struct camera_common_pdata *pdata = s_data->pdata;
struct device *dev = s_data->dev;
dev_info(dev, "%s: power on\n", __func__);
if (pdata && pdata->power_on) {
err = pdata->power_on(pw);
if (err)
dev_err(dev, "%s failed.\n", __func__);
else
pw->state = SWITCH_ON;
return err;
}
if (pw->reset_gpio) {
if (gpio_cansleep(pw->reset_gpio))
gpio_set_value_cansleep(pw->reset_gpio, 0);
else
gpio_set_value(pw->reset_gpio, 0);
}
if (unlikely(!(pw->avdd || pw->iovdd || pw->dvdd)))
goto skip_power_seqn;
usleep_range(10, 20);
if (pw->avdd) {
err = regulator_enable(pw->avdd);
if (err)
goto imx307_avdd_fail;
}
if (pw->iovdd) {
err = regulator_enable(pw->iovdd);
if (err)
goto imx307_iovdd_fail;
}
if (pw->dvdd) {
err = regulator_enable(pw->dvdd);
if (err)
goto imx307_dvdd_fail;
}
usleep_range(10, 20);
skip_power_seqn:
if (pw->reset_gpio) {
if (gpio_cansleep(pw->reset_gpio))
gpio_set_value_cansleep(pw->reset_gpio, 1);
else
gpio_set_value(pw->reset_gpio, 1);
}
/* Need to wait for t4 + t5 + t9 time as per the data sheet */
/* t4 - 200us, t5 - 21.2ms, t9 - 1.2ms */
usleep_range(23000, 23100);
pw->state = SWITCH_ON;
return 0;
imx307_dvdd_fail:
regulator_disable(pw->iovdd);
imx307_iovdd_fail:
regulator_disable(pw->avdd);
imx307_avdd_fail:
dev_err(dev, "%s failed.\n", __func__);
return -ENODEV;
}
static int imx307_power_off(struct camera_common_data *s_data)
{
int err = 0;
struct camera_common_power_rail *pw = s_data->power;
struct camera_common_pdata *pdata = s_data->pdata;
struct device *dev = s_data->dev;
dev_info(dev, "%s: power off\n", __func__);
return 0;
if (pdata && pdata->power_off) {
err = pdata->power_off(pw);
if (err) {
dev_err(dev, "%s failed.\n", __func__);
return err;
}
} else {
if (pw->reset_gpio) {
if (gpio_cansleep(pw->reset_gpio))
gpio_set_value_cansleep(pw->reset_gpio, 0);
else
gpio_set_value(pw->reset_gpio, 0);
}
usleep_range(10, 10);
if (pw->dvdd)
regulator_disable(pw->dvdd);
if (pw->iovdd)
regulator_disable(pw->iovdd);
if (pw->avdd)
regulator_disable(pw->avdd);
}
pw->state = SWITCH_OFF;
return 0;
}
static int imx307_power_put(struct tegracam_device *tc_dev)
{
struct camera_common_data *s_data = tc_dev->s_data;
struct camera_common_power_rail *pw = s_data->power;
if (unlikely(!pw))
return -EFAULT;
if (likely(pw->dvdd))
devm_regulator_put(pw->dvdd);
if (likely(pw->avdd))
devm_regulator_put(pw->avdd);
if (likely(pw->iovdd))
devm_regulator_put(pw->iovdd);
pw->dvdd = NULL;
pw->avdd = NULL;
pw->iovdd = NULL;
if (likely(pw->reset_gpio))
gpio_free(pw->reset_gpio);
return 0;
}
static int imx307_power_get(struct tegracam_device *tc_dev)
{
struct device *dev = tc_dev->dev;
struct camera_common_data *s_data = tc_dev->s_data;
struct camera_common_power_rail *pw = s_data->power;
struct camera_common_pdata *pdata = s_data->pdata;
struct clk *parent;
int err = 0;
if (!pdata) {
dev_err(dev, "pdata missing\n");
return -EFAULT;
}
/* Sensor MCLK (aka. INCK) */
if (pdata->mclk_name) {
pw->mclk = devm_clk_get(dev, pdata->mclk_name);
if (IS_ERR(pw->mclk)) {
dev_err(dev, "unable to get clock %s\n",
pdata->mclk_name);
return PTR_ERR(pw->mclk);
}
if (pdata->parentclk_name) {
parent = devm_clk_get(dev, pdata->parentclk_name);
if (IS_ERR(parent)) {
dev_err(dev, "unable to get parent clock %s",
pdata->parentclk_name);
} else
clk_set_parent(pw->mclk, parent);
}
}
/* analog 2.8v */
if (pdata->regulators.avdd)
err |= camera_common_regulator_get(dev,
&pw->avdd, pdata->regulators.avdd);
/* IO 1.8v */
if (pdata->regulators.iovdd)
err |= camera_common_regulator_get(dev,
&pw->iovdd, pdata->regulators.iovdd);
/* dig 1.2v */
if (pdata->regulators.dvdd)
err |= camera_common_regulator_get(dev,
&pw->dvdd, pdata->regulators.dvdd);
if (err) {
dev_err(dev, "%s: unable to get regulator(s)\n", __func__);
goto done;
}
/* Reset or ENABLE GPIO */
pw->reset_gpio = pdata->reset_gpio;
err = gpio_request(pw->reset_gpio, "cam_reset_gpio");
if (err < 0) {
dev_err(dev, "%s: unable to request reset_gpio (%d)\n",
__func__, err);
goto done;
}
done:
pw->state = SWITCH_OFF;
return err;
}
static struct camera_common_pdata *imx307_parse_dt(
struct tegracam_device *tc_dev)
{
struct device *dev = tc_dev->dev;
struct device_node *np = dev->of_node;
struct camera_common_pdata *board_priv_pdata;
const struct of_device_id *match;
struct camera_common_pdata *ret = NULL;
int err = 0;
int gpio;
if (!np)
return NULL;
match = of_match_device(imx307_of_match, dev);
if (!match) {
dev_err(dev, "Failed to find matching dt id\n");
return NULL;
}
board_priv_pdata = devm_kzalloc(dev,
sizeof(*board_priv_pdata), GFP_KERNEL);
if (!board_priv_pdata)
return NULL;
gpio = of_get_named_gpio(np, "reset-gpios", 0);
if (gpio < 0) {
if (gpio == -EPROBE_DEFER)
ret = ERR_PTR(-EPROBE_DEFER);
dev_err(dev, "reset-gpios not found\n");
goto error;
}
board_priv_pdata->reset_gpio = (unsigned int)gpio;
err = of_property_read_string(np, "mclk", &board_priv_pdata->mclk_name);
if (err)
dev_dbg(dev, "mclk name not present, "
"assume sensor driven externally\n");
err = of_property_read_string(np, "avdd-reg",
&board_priv_pdata->regulators.avdd);
err |= of_property_read_string(np, "iovdd-reg",
&board_priv_pdata->regulators.iovdd);
err |= of_property_read_string(np, "dvdd-reg",
&board_priv_pdata->regulators.dvdd);
if (err)
dev_dbg(dev, "avdd, iovdd and/or dvdd reglrs. not present, "
"assume sensor powered independently\n");
board_priv_pdata->has_eeprom =
of_property_read_bool(np, "has-eeprom");
return board_priv_pdata;
error:
devm_kfree(dev, board_priv_pdata);
return ret;
}
static int imx307_set_mode(struct tegracam_device *tc_dev)
{
struct imx307 *priv = (struct imx307 *)tegracam_get_privdata(tc_dev);
struct camera_common_data *s_data = tc_dev->s_data;
struct device *dev = tc_dev->dev;
int err = 0;
dev_info(dev, "%s: setmod %d \n", __func__,s_data->mode);
err = imx307_write_table(priv, mode_table[IMX307_MODE_COMMON]);
if (err)
return err;
err = imx307_write_table(priv, mode_table[s_data->mode]);
if (err)
return err;
return 0;
}
static int imx307_start_streaming(struct tegracam_device *tc_dev)
{
struct device *dev = tc_dev->dev;
struct imx307 *priv = (struct imx307 *)tegracam_get_privdata(tc_dev);
dev_info(dev, "%s: start stream\n", __func__);
return imx307_write_table(priv, mode_table[IMX307_START_STREAM]);
}
static int imx307_stop_streaming(struct tegracam_device *tc_dev)
{
struct device *dev = tc_dev->dev;
int err;
struct imx307 *priv = (struct imx307 *)tegracam_get_privdata(tc_dev);
dev_info(dev, "%s: stop stream\n", __func__);
err = imx307_write_table(priv, mode_table[IMX307_STOP_STREAM]);
usleep_range(50000, 51000);
return err;
}
static struct camera_common_sensor_ops imx307_common_ops = {
.numfrmfmts = ARRAY_SIZE(imx307_frmfmt),
.frmfmt_table = imx307_frmfmt,
.power_on = imx307_power_on,
.power_off = imx307_power_off,
.write_reg = imx307_write_reg,
.read_reg = imx307_read_reg,
.parse_dt = imx307_parse_dt,
.power_get = imx307_power_get,
.power_put = imx307_power_put,
.set_mode = imx307_set_mode,
.start_streaming = imx307_start_streaming,
.stop_streaming = imx307_stop_streaming,
};
static int imx307_board_setup(struct imx307 *priv)
{
struct camera_common_data *s_data = priv->s_data;
struct camera_common_pdata *pdata = s_data->pdata;
struct device *dev = s_data->dev;
u8 reg_val[2];
int err = 0;
if (pdata->mclk_name) {
err = camera_common_mclk_enable(s_data);
if (err) {
dev_err(dev, "error turning on mclk (%d)\n", err);
goto done;
}
}
err = imx307_power_on(s_data);
if (err) {
dev_err(dev, "error during power on sensor (%d)\n", err);
goto err_power_on;
}
err_power_on:
if (pdata->mclk_name)
camera_common_mclk_disable(s_data);
done:
return err;
}
static int imx307_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
dev_dbg(&client->dev, "%s:\n", __func__);
return 0;
}
static const struct v4l2_subdev_internal_ops imx307_subdev_internal_ops = {
.open = imx307_open,
};
static int imx307_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct tegracam_device *tc_dev;
struct imx307 *priv;
int err;
#if 1
struct device_node *np= dev->of_node;
do
{
printk("name %s \n",np->name);
printk("fame %s \n",np->full_name);
of_node_put(np);
}while((np = of_get_next_parent(np)));
#endif
dev_dbg(dev, "probing v4l2 sensor at addr 0x%0x\n", client->addr);
dev_info(dev, "probing v4l2 sensor at addr 0x%0x\n", client->addr);
if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
return -EINVAL;
priv = devm_kzalloc(dev,
sizeof(struct imx307), GFP_KERNEL);
if (!priv)
return -ENOMEM;
tc_dev = devm_kzalloc(dev,
sizeof(struct tegracam_device), GFP_KERNEL);
if (!tc_dev)
return -ENOMEM;
priv->i2c_client = tc_dev->client = client;
tc_dev->dev = dev;
strncpy(tc_dev->name, "imx307", sizeof(tc_dev->name));
tc_dev->dev_regmap_config = &sensor_regmap_config;
tc_dev->sensor_ops = &imx307_common_ops;
tc_dev->v4l2sd_internal_ops = &imx307_subdev_internal_ops;
tc_dev->tcctrl_ops = &imx307_ctrl_ops;
err = tegracam_device_register(tc_dev);
if (err) {
dev_err(dev, "tegra camera driver registration failed\n");
return err;
}
priv->tc_dev = tc_dev;
priv->s_data = tc_dev->s_data;
priv->subdev = &tc_dev->s_data->subdev;
tegracam_set_privdata(tc_dev, (void *)priv);
err = imx307_board_setup(priv);
if (err) {
dev_err(dev, "board setup failed\n");
return err;
}
err = tegracam_v4l2subdev_register(tc_dev, true);
if (err) {
dev_err(dev, "tegra camera subdev registration failed\n");
return err;
}
dev_info(dev, "detected imx307 sensor\n");
return 0;
}
static int imx307_remove(struct i2c_client *client)
{
struct camera_common_data *s_data = to_camera_common_data(&client->dev);
struct imx307 *priv = (struct imx307 *)s_data->priv;
tegracam_v4l2subdev_unregister(priv->tc_dev);
tegracam_device_unregister(priv->tc_dev);
return 0;
}
static const struct i2c_device_id imx307_id[] = {
{ "imx307", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, imx307_id);
static struct i2c_driver imx307_i2c_driver = {
.driver = {
.name = "imx307",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(imx307_of_match),
},
.probe = imx307_probe,
.remove = imx307_remove,
.id_table = imx307_id,
};
module_i2c_driver(imx307_i2c_driver);
MODULE_DESCRIPTION("Media Controller driver for Sony IMX307");
MODULE_AUTHOR("NVIDIA Corporation");
MODULE_LICENSE("GPL v2");