Hi.
I’m trying to add a custom module(imx000) based on ov5693.
I modified source file and device-trees but I can’t access I2C to sensor.
Sensor slave address of my module is 0x20 so I set to 0x10 in device tree.
Now, I’m able to search it like this.
However, when I’m trying to access it, it fails.
ubuntu@ubuntu-desktop:~$ i2cdetect -l
i2c-3 i2c 3190000.i2c I2C adapter
i2c-1 i2c c240000.i2c I2C adapter
i2c-8 i2c 31e0000.i2c I2C adapter
i2c-6 i2c 31c0000.i2c I2C adapter
i2c-4 i2c Tegra BPMP I2C adapter I2C adapter
i2c-2 i2c 3180000.i2c I2C adapter
i2c-0 i2c 3160000.i2c I2C adapter
i2c-7 i2c c250000.i2c I2C adapter
i2c-5 i2c 31b0000.i2c I2C adapter
ubuntu@ubuntu-desktop:~$ i2cdetect -r -y 2
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: UU -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- 53 -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
ubuntu@ubuntu-desktop:~$ i2cdump -f -y 2 0x10
No size specified (using byte-data access)
0 1 2 3 4 5 6 7 8 9 a b c d e f 0123456789abcdef
00: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
10: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
20: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
30: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
40: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
50: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
60: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
70: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
80: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
90: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
a0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
b0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
c0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
d0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
e0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
f0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XXXXXXXXXXXXXXXX
ubuntu@ubuntu-desktop:~$ i2cget -f -y 2 0x10 0x01
Error: Read failed
ubuntu@ubuntu-desktop:~$ i2cget -f -y 2 0x53 0x01
0x00
For testing purpose, camera settings are omitted in source code.
I just want to check whether I2C works well or not in this step.
ubuntu@ubuntu-desktop:~$ lsmod
Module Size Used by
bnep 16562 2
zram 26166 4
overlay 48691 0
fuse 103841 5
bcmdhd 934274 0
cfg80211 589351 1 bcmdhd
spidev 13282 0
imx000 31381 0
nvgpu 1575721 33
bluedroid_pm 13912 0
ip_tables 19441 0
x_tables 28951 1 ip_tables
ubuntu@ubuntu-desktop:~$ ls -al /dev/v*
crw-rw----+ 1 root video 81, 1 4월 9 12:08 /dev/v4l-subdev0
crw-rw----+ 1 root video 81, 2 4월 9 12:08 /dev/v4l-subdev1
crw-rw---- 1 root tty 7, 0 4월 9 12:08 /dev/vcs
crw-rw---- 1 root tty 7, 1 4월 9 12:08 /dev/vcs1
crw-rw---- 1 root tty 7, 2 4월 9 12:08 /dev/vcs2
crw-rw---- 1 root tty 7, 3 4월 9 12:08 /dev/vcs3
crw-rw---- 1 root tty 7, 4 4월 9 12:08 /dev/vcs4
crw-rw---- 1 root tty 7, 5 4월 9 12:08 /dev/vcs5
crw-rw---- 1 root tty 7, 6 4월 9 12:08 /dev/vcs6
crw-rw---- 1 root tty 7, 7 4월 9 12:09 /dev/vcs7
crw-rw---- 1 root tty 7, 128 4월 9 12:08 /dev/vcsa
crw-rw---- 1 root tty 7, 129 4월 9 12:08 /dev/vcsa1
crw-rw---- 1 root tty 7, 130 4월 9 12:08 /dev/vcsa2
crw-rw---- 1 root tty 7, 131 4월 9 12:08 /dev/vcsa3
crw-rw---- 1 root tty 7, 132 4월 9 12:08 /dev/vcsa4
crw-rw---- 1 root tty 7, 133 4월 9 12:08 /dev/vcsa5
crw-rw---- 1 root tty 7, 134 4월 9 12:08 /dev/vcsa6
crw-rw---- 1 root tty 7, 135 4월 9 12:09 /dev/vcsa7
crw------- 1 root root 10, 137 4월 9 12:08 /dev/vhci
crw-rw----+ 1 root video 81, 0 4월 9 12:08 /dev/video0
/dev/v4l:
total 0
drwxr-xr-x 3 root root 60 4월 9 12:08 .
drwxr-xr-x 18 root root 7900 4월 9 12:12 ..
drwxr-xr-x 2 root root 60 4월 9 12:08 by-path
/dev/vfio:
total 0
drwxr-xr-x 2 root root 60 1월 1 1970 .
drwxr-xr-x 18 root root 7900 4월 9 12:12 ..
crw-rw-rw- 1 root root 10, 196 4월 9 12:08 vfio
ubuntu@ubuntu-desktop:~$ media-ctl -p -d /dev/media0
Media controller API version 0.1.0
Media device information
------------------------
driver tegra-vi4
model NVIDIA Tegra Video Input Device
serial
bus info
hw revision 0x3
driver version 0.0.0
Device topology
- entity 1: 150c0000.nvcsi--1 (2 pads, 2 links)
type V4L2 subdev subtype Unknown flags 0
device node name /dev/v4l-subdev0
pad0: Sink
<- "imx000 2-0010":0 [ENABLED]
pad1: Source
-> "vi-output, imx000 2-0010":0 [ENABLED]
- entity 4: imx000 2-0010 (1 pad, 1 link)
type V4L2 subdev subtype Sensor flags 0
device node name /dev/v4l-subdev1
pad0: Source
[fmt:SBGGR10_1X10/2592x1944 field:none colorspace:srgb]
-> "150c0000.nvcsi--1":0 [ENABLED]
- entity 6: vi-output, imx000 2-0010 (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video0
pad0: Sink
<- "150c0000.nvcsi--1":1 [ENABLED]
Please help me what is wrong.
Here is my source code below.
Linux_for_Tegra/hardware/nvidia/platform/t18x/quill/kernel-dts/tegra186-quill-p3310-1000-a00-00-base.dts :
#include <t18x-common-platforms/tegra186-quill-common-p3310-1000-a00.dtsi>
#include <t18x-common-platforms/tegra186-quill-power-tree-p3310-1000-a00-00.dtsi>
//#include <t18x-common-platforms/tegra186-quill-camera-modules.dtsi>
#include <t18x-common-modules/tegra186-display-e3320-1000-a00.dtsi>
#include <t18x-common-modules/tegra186-camera-imx000-a00.dtsi> // new
/* comms dtsi file should be included after gpio dtsi file */
#include <t18x-common-platforms/tegra186-quill-comms.dtsi>
#include <t18x-common-plugin-manager/tegra186-quill-p3310-1000-a00-plugin-manager.dtsi>
#include <t18x-common-modules/tegra186-super-module-e2614-p2597-1000-a00.dtsi>
#include <t18x-common-plugin-manager/tegra186-quill-display-plugin-manager.dtsi>
#include <t18x-common-prod/tegra186-priv-quill-p3310-1000-a00-prod.dtsi>
//#include <t18x-common-plugin-manager/tegra186-quill-camera-plugin-manager.dtsi>
Linux_for_Tegra/hardware/nvidia/platform/t18x/quill/kernel-dts/tegra186-quill-p3310-1000-c03-00-base.dts :
#include "tegra186-quill-p3310-1000-a00-00-base.dts"
#include <t18x-common-platforms/tegra186-quill-camera-imx000-a00.dtsi>
Linux_for_Tegra/kernel/nvidia/drivers/media/i2c/imx000.c (modified based on ov5693) :
static const u32 ctrl_cid_list[] = {
// TEGRA_CAMERA_CID_GAIN,
// TEGRA_CAMERA_CID_EXPOSURE,
// TEGRA_CAMERA_CID_EXPOSURE_SHORT,
// TEGRA_CAMERA_CID_FRAME_RATE,
TEGRA_CAMERA_CID_GROUP_HOLD,
// TEGRA_CAMERA_CID_HDR_EN,
// TEGRA_CAMERA_CID_EEPROM_DATA,
// TEGRA_CAMERA_CID_OTP_DATA,
// TEGRA_CAMERA_CID_FUSE_ID,
};
struct imx000 {
struct camera_common_eeprom_data eeprom[IMX000_EEPROM_NUM_BLOCKS];
// u8 eeprom_buf[IMX000_EEPROM_SIZE];
// u8 otp_buf[IMX000_OTP_SIZE];
struct i2c_client *i2c_client;
struct v4l2_subdev *subdev;
u8 fuse_id[IMX000_FUSE_ID_SIZE];
const char *devname;
struct dentry *debugfs_dir;
struct mutex streaming_lock;
bool streaming;
s32 group_hold_prev;
u32 frame_length;
bool group_hold_en;
struct camera_common_i2c i2c_dev;
struct camera_common_data *s_data;
struct tegracam_device *tc_dev;
};
static struct regmap_config imx000_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
};
static inline void imx000_get_frame_length_regs(imx000_reg *regs,
u32 frame_length)
{
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
regs->addr = IMX000_FRAME_LENGTH_ADDR_MSB;
regs->val = (frame_length >> 8) & 0xff;
(regs + 1)->addr = IMX000_FRAME_LENGTH_ADDR_LSB;
(regs + 1)->val = (frame_length) & 0xff;
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
}
static inline void imx000_get_coarse_time_regs(imx000_reg *regs,
u32 coarse_time)
{
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
regs->addr = IMX000_COARSE_TIME_ADDR_1;
regs->val = (coarse_time >> 12) & 0xff;
(regs + 1)->addr = IMX000_COARSE_TIME_ADDR_2;
(regs + 1)->val = (coarse_time >> 4) & 0xff;
(regs + 2)->addr = IMX000_COARSE_TIME_ADDR_3;
(regs + 2)->val = (coarse_time & 0xf) << 4;
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
}
static inline void imx000_get_coarse_time_short_regs(imx000_reg *regs,
u32 coarse_time)
{
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
regs->addr = IMX000_COARSE_TIME_SHORT_ADDR_1;
regs->val = (coarse_time >> 12) & 0xff;
(regs + 1)->addr = IMX000_COARSE_TIME_SHORT_ADDR_2;
(regs + 1)->val = (coarse_time >> 4) & 0xff;
(regs + 2)->addr = IMX000_COARSE_TIME_SHORT_ADDR_3;
(regs + 2)->val = (coarse_time & 0xf) << 4;
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
}
static inline void imx000_get_gain_regs(imx000_reg *regs,
u16 gain)
{
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
regs->addr = IMX000_GAIN_ADDR_MSB;
regs->val = (gain >> 8) & 0xff;
(regs + 1)->addr = IMX000_GAIN_ADDR_LSB;
(regs + 1)->val = (gain) & 0xff;
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
}
static int test_mode;
module_param(test_mode, int, 0644);
static inline int imx000_read_reg(struct camera_common_data *s_data,
u16 addr, u8 *val)
{
int err = 0;
u32 reg_val = 0;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
err = regmap_read(s_data->regmap, addr, ®_val);
*val = reg_val & 0xFF;
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
return err;
}
static int imx000_write_reg(struct camera_common_data *s_data, u16 addr, u8 val)
{
int err;
struct device *dev = s_data->dev;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
err = regmap_write(s_data->regmap, addr, val);
if (err)
dev_err(dev, "%s: i2c write failed, 0x%x = %x\n",
__func__, addr, val);
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
return err;
}
static int imx000_write_table(struct imx000 *priv,
const imx000_reg table[])
{
struct camera_common_data *s_data = priv->s_data;
int ret;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
ret = regmap_util_write_table_8(s_data->regmap,
table,
NULL, 0,
IMX000_TABLE_WAIT_MS,
IMX000_TABLE_END);
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
return ret;
}
static void imx000_gpio_set(struct camera_common_data *s_data,
unsigned int gpio, int val)
{
struct camera_common_pdata *pdata = s_data->pdata;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
if (pdata && pdata->use_cam_gpio)
cam_gpio_ctrl(s_data->dev, gpio, val, 1);
else {
if (gpio_cansleep(gpio))
gpio_set_value_cansleep(gpio, val);
else
gpio_set_value(gpio, val);
}
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
}
static int imx000_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;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
dev_dbg(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;
}
/* sleeps calls in the sequence below are for internal device
* signal propagation as specified by sensor vendor
*/
if (pw->avdd)
err = regulator_enable(pw->avdd);
if (err)
goto imx000_avdd_fail;
if (pw->iovdd)
err = regulator_enable(pw->iovdd);
if (err)
goto imx000_iovdd_fail;
usleep_range(1, 2);
if (gpio_is_valid(pw->pwdn_gpio))
imx000_gpio_set(s_data, pw->pwdn_gpio, 1);
/*
* datasheet 2.9: reset requires ~2ms settling time
* a power on reset is generated after core power becomes stable
*/
usleep_range(2000, 2010);
if (gpio_is_valid(pw->reset_gpio))
imx000_gpio_set(s_data, pw->reset_gpio, 1);
/* datasheet fig 2-9: t3 */
usleep_range(2000, 2010);
pw->state = SWITCH_ON;
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
return 0;
imx000_iovdd_fail:
regulator_disable(pw->avdd);
imx000_avdd_fail:
dev_err(dev, "%s failed.\n", __func__);
return -ENODEV;
}
static int imx000_power_off(struct camera_common_data *s_data)
{
int err = 0;
struct camera_common_power_rail *pw = s_data->power;
struct device *dev = s_data->dev;
struct camera_common_pdata *pdata = s_data->pdata;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
dev_dbg(dev, "%s: power off\n", __func__);
if (pdata && pdata->power_off) {
err = pdata->power_off(pw);
if (!err) {
goto power_off_done;
} else {
dev_err(dev, "%s failed.\n", __func__);
return err;
}
}
/* sleeps calls in the sequence below are for internal device
* signal propagation as specified by sensor vendor
*/
usleep_range(21, 25);
if (gpio_is_valid(pw->pwdn_gpio))
imx000_gpio_set(s_data, pw->pwdn_gpio, 0);
usleep_range(1, 2);
if (gpio_is_valid(pw->reset_gpio))
imx000_gpio_set(s_data, pw->reset_gpio, 0);
/* datasheet 2.9: reset requires ~2ms settling time*/
usleep_range(2000, 2010);
if (pw->iovdd)
regulator_disable(pw->iovdd);
if (pw->avdd)
regulator_disable(pw->avdd);
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
power_off_done:
pw->state = SWITCH_OFF;
return 0;
}
static int imx000_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;
struct camera_common_pdata *pdata = s_data->pdata;
struct device *dev = tc_dev->dev;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
if (unlikely(!pw))
return -EFAULT;
if (pdata && pdata->use_cam_gpio)
cam_gpio_deregister(dev, pw->pwdn_gpio);
else {
if (gpio_is_valid(pw->pwdn_gpio))
gpio_free(pw->pwdn_gpio);
if (gpio_is_valid(pw->reset_gpio))
gpio_free(pw->reset_gpio);
}
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
return 0;
}
static int imx000_power_get(struct tegracam_device *tc_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 device *dev = tc_dev->dev;
const char *mclk_name;
const char *parentclk_name;
struct clk *parent;
int err = 0, ret = 0;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
if (!pdata) {
dev_err(dev, "pdata missing\n");
return -EFAULT;
}
mclk_name = pdata->mclk_name ?
pdata->mclk_name : "cam_mclk1";
pw->mclk = devm_clk_get(dev, mclk_name);
if (IS_ERR(pw->mclk)) {
dev_err(dev, "unable to get clock %s\n", mclk_name);
return PTR_ERR(pw->mclk);
}
parentclk_name = pdata->parentclk_name;
if (parentclk_name) {
parent = devm_clk_get(dev, parentclk_name);
if (IS_ERR(parent)) {
dev_err(dev, "unable to get parent clcok %s",
parentclk_name);
} else
clk_set_parent(pw->mclk, parent);
}
/* analog 2.8v */
err |= camera_common_regulator_get(dev,
&pw->avdd, pdata->regulators.avdd);
/* IO 1.8v */
err |= camera_common_regulator_get(dev,
&pw->iovdd, pdata->regulators.iovdd);
// digital 1.2v
err |= camera_common_regulator_get(dev,
&pw->dvdd, pdata->regulators.dvdd);
if (!err) {
pw->reset_gpio = pdata->reset_gpio;
pw->pwdn_gpio = pdata->pwdn_gpio;
}
if (pdata->use_cam_gpio) {
err = cam_gpio_register(dev, pw->pwdn_gpio);
if (err)
dev_err(dev, "%s ERR can't register cam gpio %u!\n",
__func__, pw->pwdn_gpio);
} else {
if (gpio_is_valid(pw->pwdn_gpio)) {
ret = gpio_request(pw->pwdn_gpio, "cam_pwdn_gpio");
if (ret < 0) {
dev_dbg(dev, "%s can't request pwdn_gpio %d\n",
__func__, ret);
}
gpio_direction_output(pw->pwdn_gpio, 1);
}
if (gpio_is_valid(pw->reset_gpio)) {
ret = gpio_request(pw->reset_gpio, "cam_reset_gpio");
if (ret < 0) {
dev_dbg(dev, "%s can't request reset_gpio %d\n",
__func__, ret);
}
gpio_direction_output(pw->reset_gpio, 1);
}
}
pw->state = SWITCH_OFF;
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
return err;
}
/*static int imx000_set_gain(struct tegracam_device *tc_dev, s64 val);
static int imx000_set_frame_rate(struct tegracam_device *tc_dev, s64 val);
static int imx000_set_exposure(struct tegracam_device *tc_dev, s64 val);
static int imx000_set_exposure_short(struct tegracam_device *tc_dev, s64 val);*/
static const struct of_device_id imx000_of_match[] = {
{
.compatible = "nvidia,imx000",
},
{ },
};
static int imx000_set_group_hold(struct tegracam_device *tc_dev, bool val)
{
int err;
struct imx000 *priv = tc_dev->priv;
int gh_prev = switch_ctrl_qmenu[priv->group_hold_prev];
struct device *dev = tc_dev->dev;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
if (priv->group_hold_en == true && gh_prev == SWITCH_OFF) {
camera_common_i2c_aggregate(&priv->i2c_dev, true);
/* enter group hold */
err = imx000_write_reg(priv->s_data,
IMX000_GROUP_HOLD_ADDR, val);
if (err)
goto fail;
priv->group_hold_prev = 1;
dev_dbg(dev, "%s: enter group hold\n", __func__);
} else if (priv->group_hold_en == false && gh_prev == SWITCH_ON) {
/* leave group hold */
err = imx000_write_reg(priv->s_data,
IMX000_GROUP_HOLD_ADDR, 0x11);
if (err)
goto fail;
err = imx000_write_reg(priv->s_data,
IMX000_GROUP_HOLD_ADDR, 0x61);
if (err)
goto fail;
camera_common_i2c_aggregate(&priv->i2c_dev, false);
priv->group_hold_prev = 0;
dev_dbg(dev, "%s: leave group hold\n", __func__);
}
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
return 0;
fail:
dev_dbg(dev, "%s: Group hold control error\n", __func__);
return err;
}
/*static int imx000_set_gain(struct tegracam_device *tc_dev, s64 val)
{
struct camera_common_data *s_data = tc_dev->s_data;
struct imx000 *priv = (struct imx000 *)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];
imx000_reg reg_list[2];
int err;
u16 gain;
int i;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
if (!priv->group_hold_prev)
imx000_set_group_hold(tc_dev, 1);
// translate value
gain = (u16) (((val * 16) +
(mode->control_properties.gain_factor / 2)) /
mode->control_properties.gain_factor);
imx000_get_gain_regs(reg_list, gain);
dev_dbg(dev, "%s: gain %d val: %lld\n", __func__, gain, val);
for (i = 0; i < 2; i++) {
err = imx000_write_reg(s_data, reg_list[i].addr,
reg_list[i].val);
if (err)
goto fail;
}
printk(KERN_DEBUG "%s: gain %d val: %lld\n", __func__, gain, val);
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
return 0;
fail:
dev_dbg(dev, "%s: GAIN control error\n", __func__);
return err;
}
static int imx000_set_frame_rate(struct tegracam_device *tc_dev, s64 val)
{
struct camera_common_data *s_data = tc_dev->s_data;
struct device *dev = tc_dev->dev;
struct imx000 *priv = tc_dev->priv;
const struct sensor_mode_properties *mode =
&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];
imx000_reg reg_list[2];
int err;
u32 frame_length;
int i;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
if (!priv->group_hold_prev)
imx000_set_group_hold(tc_dev, 1);
frame_length = mode->signal_properties.pixel_clock.val *
mode->control_properties.framerate_factor /
mode->image_properties.line_length / val;
imx000_get_frame_length_regs(reg_list, frame_length);
dev_dbg(dev, "%s: val: %d\n", __func__, frame_length);
for (i = 0; i < 2; i++) {
err = imx000_write_reg(s_data, reg_list[i].addr,
reg_list[i].val);
if (err)
goto fail;
}
priv->frame_length = frame_length;
printk(KERN_DEBUG "frame_length : %d\n", frame_length);
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
return 0;
fail:
dev_dbg(dev, "%s: FRAME_LENGTH control error\n", __func__);
return err;
}
static int imx000_set_exposure(struct tegracam_device *tc_dev, s64 val)
{
struct camera_common_data *s_data = tc_dev->s_data;
struct device *dev = tc_dev->dev;
struct imx000 *priv = tc_dev->priv;
const s32 max_coarse_time = priv->frame_length - IMX000_MAX_COARSE_DIFF;
const struct sensor_mode_properties *mode =
&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];
imx000_reg reg_list[3];
int err;
u32 coarse_time;
int i;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
if (!priv->group_hold_prev)
imx000_set_group_hold(tc_dev, 1);
coarse_time = (u32)(((mode->signal_properties.pixel_clock.val*val)
/mode->image_properties.line_length)/
mode->control_properties.exposure_factor);
if (coarse_time < IMX000_MIN_EXPOSURE_COARSE)
coarse_time = IMX000_MIN_EXPOSURE_COARSE;
else if (coarse_time > max_coarse_time)
coarse_time = max_coarse_time;
imx000_get_coarse_time_regs(reg_list, coarse_time);
dev_dbg(dev, "%s: val: %d\n", __func__, coarse_time);
for (i = 0; i < 3; i++) {
err = imx000_write_reg(s_data, reg_list[i].addr,
reg_list[i].val);
if (err)
goto fail;
}
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
return 0;
fail:
dev_dbg(dev, "%s: COARSE_TIME control error\n", __func__);
return err;
}
static int imx000_set_exposure_short(struct tegracam_device *tc_dev, s64 val)
{
struct camera_common_data *s_data = tc_dev->s_data;
struct device *dev = tc_dev->dev;
struct imx000 *priv = tc_dev->priv;
const struct sensor_mode_properties *mode =
&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];
imx000_reg reg_list[3];
int err;
struct v4l2_control hdr_control;
int hdr_en;
u32 coarse_time_short;
int i;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
if (!priv->group_hold_prev)
imx000_set_group_hold(tc_dev, 1);
// check hdr enable ctrl
hdr_control.id = TEGRA_CAMERA_CID_HDR_EN;
err = camera_common_g_ctrl(s_data, &hdr_control);
if (err < 0) {
dev_err(dev, "could not find device ctrl.\n");
return err;
}
hdr_en = switch_ctrl_qmenu[hdr_control.value];
if (hdr_en == SWITCH_OFF)
return 0;
coarse_time_short = (u32)(((mode->signal_properties.pixel_clock.val*val)
/mode->image_properties.line_length)
/mode->control_properties.exposure_factor);
imx000_get_coarse_time_short_regs(reg_list, coarse_time_short);
dev_dbg(dev, "%s: val: %d\n", __func__, coarse_time_short);
for (i = 0; i < 3; i++) {
err = imx000_write_reg(s_data, reg_list[i].addr,
reg_list[i].val);
if (err)
goto fail;
}
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
return 0;
fail:
dev_dbg(dev, "%s: COARSE_TIME_SHORT control error\n", __func__);
return err;
}
static int imx000_fill_string_ctrl(struct tegracam_device *tc_dev,
struct v4l2_ctrl *ctrl)
{
struct imx000 *priv = tc_dev->priv;
int i;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
switch (ctrl->id) {
case TEGRA_CAMERA_CID_EEPROM_DATA:
for (i = 0; i < IMX000_EEPROM_SIZE; i++)
sprintf(&ctrl->p_new.p_char[i*2], "%02x",
priv->eeprom_buf[i]);
break;
case TEGRA_CAMERA_CID_OTP_DATA:
for (i = 0; i < IMX000_OTP_SIZE; i++)
sprintf(&ctrl->p_new.p_char[i*2], "%02x",
priv->otp_buf[i]);
break;
case TEGRA_CAMERA_CID_FUSE_ID:
for (i = 0; i < IMX000_FUSE_ID_SIZE; i++)
sprintf(&ctrl->p_new.p_char[i*2], "%02x",
priv->fuse_id[i]);
printk(KERN_DEBUG "ISM Camera Test : FuseID => %s\n", ctrl->p_new.p_char);
break;
default:
return -EINVAL;
}
ctrl->p_cur.p_char = ctrl->p_new.p_char;
return 0;
}
static int imx000_eeprom_device_release(struct imx000 *priv)
{
int i;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
for (i = 0; i < IMX000_EEPROM_NUM_BLOCKS; i++) {
if (priv->eeprom[i].i2c_client != NULL) {
i2c_unregister_device(priv->eeprom[i].i2c_client);
priv->eeprom[i].i2c_client = NULL;
}
}
return 0;
}
static int imx000_eeprom_device_init(struct imx000 *priv)
{
struct camera_common_pdata *pdata = priv->s_data->pdata;
char *dev_name = "eeprom_imx000";
static struct regmap_config eeprom_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
int i;
int err;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
if (!pdata->has_eeprom)
return -EINVAL;
for (i = 0; i < IMX000_EEPROM_NUM_BLOCKS; i++) {
priv->eeprom[i].adap = i2c_get_adapter(
priv->i2c_client->adapter->nr);
memset(&priv->eeprom[i].brd, 0, sizeof(priv->eeprom[i].brd));
strncpy(priv->eeprom[i].brd.type, dev_name,
sizeof(priv->eeprom[i].brd.type));
priv->eeprom[i].brd.addr = IMX000_EEPROM_ADDRESS + i;
priv->eeprom[i].i2c_client = i2c_new_device(
priv->eeprom[i].adap, &priv->eeprom[i].brd);
priv->eeprom[i].regmap = devm_regmap_init_i2c(
priv->eeprom[i].i2c_client, &eeprom_regmap_config);
if (IS_ERR(priv->eeprom[i].regmap)) {
err = PTR_ERR(priv->eeprom[i].regmap);
imx000_eeprom_device_release(priv);
return err;
}
}
return 0;
}
static int imx000_read_eeprom(struct imx000 *priv)
{
int err, i;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
for (i = 0; i < IMX000_EEPROM_NUM_BLOCKS; i++) {
err = regmap_bulk_read(priv->eeprom[i].regmap, 0,
&priv->eeprom_buf[i * IMX000_EEPROM_BLOCK_SIZE],
IMX000_EEPROM_BLOCK_SIZE);
if (err)
return err;
}
return 0;
}
static int imx000_read_otp_bank(struct imx000 *priv,
u8 *buf, int bank, u16 addr, int size)
{
int err;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
// sleeps calls in the sequence below are for internal device
// signal propagation as specified by sensor vendor
usleep_range(10000, 11000);
mutex_lock(&priv->streaming_lock);
err = imx000_write_table(priv, mode_table[IMX000_MODE_START_STREAM]);
if (err) {
mutex_unlock(&priv->streaming_lock);
return err;
} else {
priv->streaming = true;
mutex_unlock(&priv->streaming_lock);
}
err = imx000_write_reg(priv->s_data, IMX000_OTP_BANK_SELECT_ADDR,
0xC0 | bank);
if (err)
return err;
err = imx000_write_reg(priv->s_data, IMX000_OTP_LOAD_CTRL_ADDR, 0x01);
if (err)
return err;
usleep_range(10000, 11000);
err = regmap_bulk_read(priv->s_data->regmap, addr, buf, size);
if (err)
return err;
mutex_lock(&priv->streaming_lock);
err = imx000_write_table(priv, mode_table[IMX000_MODE_STOP_STREAM]);
if (err) {
mutex_unlock(&priv->streaming_lock);
return err;
} else {
priv->streaming = false;
mutex_unlock(&priv->streaming_lock);
}
return 0;
}
static int imx000_otp_setup(struct imx000 *priv)
{
struct device *dev = priv->s_data->dev;
int err = 0;
int i;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
for (i = 0; i < IMX000_OTP_NUM_BANKS; i++) {
err = imx000_read_otp_bank(priv,
&priv->otp_buf[i
* IMX000_OTP_BANK_SIZE],
i,
IMX000_OTP_BANK_START_ADDR,
IMX000_OTP_BANK_SIZE);
if (err) {
dev_err(dev, "could not read otp bank\n");
goto ret;
}
}
ret:
return err;
}
static int imx000_fuse_id_setup(struct imx000 *priv)
{
struct device *dev = priv->s_data->dev;
int err;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
err = imx000_read_otp_bank(priv,
&priv->fuse_id[0],
IMX000_FUSE_ID_OTP_BANK,
IMX000_FUSE_ID_OTP_START_ADDR,
IMX000_FUSE_ID_SIZE);
if (err) {
dev_err(dev, "could not read otp bank\n");
goto ret;
}
ret:
return err;
}*/
MODULE_DEVICE_TABLE(of, imx000_of_match);
static struct camera_common_pdata *imx000_parse_dt(struct tegracam_device
*tc_dev)
{
struct device *dev = tc_dev->dev;
struct device_node *node = dev->of_node;
struct camera_common_pdata *board_priv_pdata;
const struct of_device_id *match;
int gpio;
int err;
struct camera_common_pdata *ret = NULL;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
if (!node)
return NULL;
match = of_match_device(imx000_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;
err = camera_common_parse_clocks(dev,
board_priv_pdata);
if (err) {
dev_err(dev, "Failed to find clocks\n");
goto error;
}
err = of_property_read_string(node, "dvdd-reg",
&board_priv_pdata->regulators.dvdd);
if (err) {
dev_err(dev, "dvdd-reg not in DT\n");
goto error;
}
gpio = of_get_named_gpio(node, "pwdn-gpios", 0);
if (gpio < 0) {
if (gpio == -EPROBE_DEFER) {
ret = ERR_PTR(-EPROBE_DEFER);
goto error;
}
gpio = 0;
}
board_priv_pdata->pwdn_gpio = (unsigned int)gpio;
gpio = of_get_named_gpio(node, "reset-gpios", 0);
if (gpio < 0) {
/* reset-gpio is not absolutely needed */
if (gpio == -EPROBE_DEFER) {
ret = ERR_PTR(-EPROBE_DEFER);
goto error;
}
dev_dbg(dev, "reset gpios not in DT\n");
gpio = 0;
}
board_priv_pdata->reset_gpio = (unsigned int)gpio;
board_priv_pdata->use_cam_gpio =
of_property_read_bool(node, "cam, use-cam-gpio");
err = of_property_read_string(node, "avdd-reg",
&board_priv_pdata->regulators.avdd);
if (err) {
dev_err(dev, "avdd-reg not in DT\n");
goto error;
}
err = of_property_read_string(node, "iovdd-reg",
&board_priv_pdata->regulators.iovdd);
if (err) {
dev_err(dev, "iovdd-reg not in DT\n");
goto error;
}
board_priv_pdata->has_eeprom =
of_property_read_bool(node, "has-eeprom");
board_priv_pdata->v_flip = of_property_read_bool(node, "vertical-flip");
board_priv_pdata->h_mirror = of_property_read_bool(node,
"horizontal-mirror");
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
return board_priv_pdata;
error:
devm_kfree(dev, board_priv_pdata);
return ret;
}
static int imx000_set_mode(struct tegracam_device *tc_dev)
{
struct imx000 *priv = (struct imx000 *)tegracam_get_privdata(tc_dev);
struct camera_common_data *s_data = tc_dev->s_data;
int err;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
err = imx000_write_table(priv, mode_table[s_data->mode_prop_idx]);
if (err)
return err;
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
return 0;
}
static int imx000_start_streaming(struct tegracam_device *tc_dev)
{
struct imx000 *priv = (struct imx000 *)tegracam_get_privdata(tc_dev);
struct camera_common_data *s_data = tc_dev->s_data;
struct camera_common_pdata *pdata = s_data->pdata;
struct device *dev = s_data->dev;
int err;
u8 val;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
mutex_lock(&priv->streaming_lock);
err = imx000_write_table(priv, mode_table[IMX000_MODE_START_STREAM]);
if (err) {
mutex_unlock(&priv->streaming_lock);
goto exit;
} else {
priv->streaming = true;
mutex_unlock(&priv->streaming_lock);
}
if (pdata->v_flip) {
imx000_read_reg(s_data, IMX000_TIMING_REG20, &val);
imx000_write_reg(s_data, IMX000_TIMING_REG20,
val | VERTICAL_FLIP);
}
if (pdata->h_mirror) {
imx000_read_reg(s_data, IMX000_TIMING_REG21, &val);
imx000_write_reg(s_data, IMX000_TIMING_REG21,
val | HORIZONTAL_MIRROR_MASK);
} else {
imx000_read_reg(s_data, IMX000_TIMING_REG21, &val);
imx000_write_reg(s_data, IMX000_TIMING_REG21,
val & (~HORIZONTAL_MIRROR_MASK));
}
if (test_mode)
err = imx000_write_table(priv,
mode_table[IMX000_MODE_TEST_PATTERN]);
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
return 0;
exit:
dev_err(dev, "%s: error starting stream\n", __func__);
return err;
}
static int imx000_stop_streaming(struct tegracam_device *tc_dev)
{
struct camera_common_data *s_data = tc_dev->s_data;
struct imx000 *priv = (struct imx000 *)tegracam_get_privdata(tc_dev);
struct device *dev = s_data->dev;
u32 frame_time;
int err;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
mutex_lock(&priv->streaming_lock);
err = imx000_write_table(priv,
mode_table[IMX000_MODE_STOP_STREAM]);
if (err) {
mutex_unlock(&priv->streaming_lock);
goto exit;
} else {
priv->streaming = false;
mutex_unlock(&priv->streaming_lock);
}
/*
* Wait for one frame to make sure sensor is set to
* software standby in V-blank
*
* frame_time = frame length rows * Tline
* Tline = line length / pixel clock (in MHz)
*/
frame_time = priv->frame_length *
IMX000_DEFAULT_LINE_LENGTH / IMX000_DEFAULT_PIXEL_CLOCK;
usleep_range(frame_time, frame_time + 1000);
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
return 0;
exit:
dev_err(dev, "%s: error stopping stream\n", __func__);
return err;
}
static struct camera_common_sensor_ops imx000_common_ops = {
.numfrmfmts = ARRAY_SIZE(imx000_frmfmt),
.frmfmt_table = imx000_frmfmt,
.power_on = imx000_power_on,
.power_off = imx000_power_off,
.write_reg = imx000_write_reg,
.read_reg = imx000_read_reg,
.parse_dt = imx000_parse_dt,
.power_get = imx000_power_get,
.power_put = imx000_power_put,
.set_mode = imx000_set_mode,
.start_streaming = imx000_start_streaming,
.stop_streaming = imx000_stop_streaming,
};
static int imx000_debugfs_streaming_show(void *data, u64 *val)
{
struct imx000 *priv = data;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
mutex_lock(&priv->streaming_lock);
*val = priv->streaming;
mutex_unlock(&priv->streaming_lock);
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
return 0;
}
static int imx000_debugfs_streaming_write(void *data, u64 val)
{
int err = 0;
struct imx000 *priv = data;
struct i2c_client *client = priv->i2c_client;
bool enable = (val != 0);
int mode_index = enable ?
(IMX000_MODE_START_STREAM) : (IMX000_MODE_STOP_STREAM);
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
dev_info(&client->dev, "%s: %s sensor\n",
__func__, (enable ? "enabling" : "disabling"));
mutex_lock(&priv->streaming_lock);
err = imx000_write_table(priv, mode_table[mode_index]);
if (err) {
dev_err(&client->dev, "%s: error setting sensor streaming\n",
__func__);
goto done;
}
priv->streaming = enable;
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
done:
mutex_unlock(&priv->streaming_lock);
return err;
}
DEFINE_SIMPLE_ATTRIBUTE(imx000_debugfs_streaming_fops,
imx000_debugfs_streaming_show,
imx000_debugfs_streaming_write,
"%lld\n");
static void imx000_debugfs_remove(struct imx000 *priv);
static int imx000_debugfs_create(struct imx000 *priv)
{
int err = 0;
struct i2c_client *client = priv->i2c_client;
const char *devnode;
char debugfs_dir[16];
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
err = of_property_read_string(client->dev.of_node, "devnode", &devnode);
if (err) {
dev_err(&client->dev, "devnode not in DT\n");
return err;
}
snprintf(debugfs_dir, sizeof(debugfs_dir), "camera-%s", devnode);
priv->debugfs_dir = debugfs_create_dir(debugfs_dir, NULL);
if (priv->debugfs_dir == NULL)
return -ENOMEM;
if (!debugfs_create_file("streaming", 0644, priv->debugfs_dir, priv,
&imx000_debugfs_streaming_fops))
goto error;
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
return 0;
error:
imx000_debugfs_remove(priv);
return -ENOMEM;
}
static struct tegracam_ctrl_ops imx000_ctrl_ops = {
.numctrls = ARRAY_SIZE(ctrl_cid_list),
.ctrl_cid_list = ctrl_cid_list,
// .string_ctrl_size = {IMX000_EEPROM_STR_SIZE,
// IMX000_FUSE_ID_STR_SIZE,
// IMX000_OTP_STR_SIZE},
// .set_gain = imx000_set_gain,
// .set_exposure = imx000_set_exposure,
// .set_exposure_short = imx000_set_exposure_short,
// .set_frame_rate = imx000_set_frame_rate,
.set_group_hold = imx000_set_group_hold,
// .fill_string_ctrl = imx000_fill_string_ctrl,
};
static int imx000_board_setup(struct imx000 *priv)
{
struct camera_common_data *s_data = priv->s_data;
struct device *dev = s_data->dev;
// bool eeprom_ctrl = 0;
int err = 0;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
dev_dbg(dev, "%s++\n", __func__);
// eeprom interface
/* err = imx000_eeprom_device_init(priv);
if (err && s_data->pdata->has_eeprom)
dev_err(dev,
"Failed to allocate eeprom reg map: %d\n", err);
eeprom_ctrl = !err;*/
err = camera_common_mclk_enable(s_data);
if (err) {
dev_err(dev,
"Error %d turning on mclk\n", err);
return err;
}
err = imx000_power_on(s_data);
if (err) {
dev_err(dev,
"Error %d during power on sensor\n", err);
return err;
}
/* if (eeprom_ctrl) {
err = imx000_read_eeprom(priv);
if (err) {
dev_err(dev,
"Error %d reading eeprom\n", err);
goto error;
}
}
err = imx000_otp_setup(priv);
if (err) {
dev_err(dev,
"Error %d reading otp data\n", err);
goto error;
}
err = imx000_fuse_id_setup(priv);
if (err) {
dev_err(dev,
"Error %d reading fuse id data\n", err);
goto error;
}
error:
imx000_power_off(s_data);
camera_common_mclk_disable(s_data);*/
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
return err;
}
static void imx000_debugfs_remove(struct imx000 *priv)
{
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
debugfs_remove_recursive(priv->debugfs_dir);
priv->debugfs_dir = NULL;
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
}
static int imx000_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
dev_dbg(&client->dev, "%s:\n", __func__);
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
return 0;
}
static const struct v4l2_subdev_internal_ops imx000_subdev_internal_ops = {
.open = imx000_open,
};
static int imx000_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct device_node *node = client->dev.of_node;
struct tegracam_device *tc_dev;
struct imx000 *priv;
int err;
const struct of_device_id *match;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
dev_info(dev, "probing v4l2 sensor.\n");
match = of_match_device(imx000_of_match, dev);
if (!match) {
dev_err(dev, "No device match found\n");
return -ENODEV;
}
if (!IS_ENABLED(CONFIG_OF) || !node)
return -EINVAL;
priv = devm_kzalloc(dev,
sizeof(struct imx000), 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, "imx000", sizeof(tc_dev->name));
tc_dev->dev_regmap_config = &imx000_regmap_config;
tc_dev->sensor_ops = &imx000_common_ops;
tc_dev->v4l2sd_internal_ops = &imx000_subdev_internal_ops;
tc_dev->tcctrl_ops = &imx000_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);
mutex_init(&priv->streaming_lock);
err = imx000_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;
}
err = imx000_debugfs_create(priv);
if (err) {
dev_err(dev, "error creating debugfs interface");
imx000_debugfs_remove(priv);
return err;
}
dev_dbg(dev, "Detected IMX000 sensor\n");
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
return 0;
}
static int
imx000_remove(struct i2c_client *client)
{
struct camera_common_data *s_data = to_camera_common_data(&client->dev);
struct imx000 *priv = (struct imx000 *)s_data->priv;
PRINT_FUNC_NAME_2_KERN_LOG_STT(__func__);
imx000_debugfs_remove(priv);
tegracam_v4l2subdev_unregister(priv->tc_dev);
imx000_power_put(priv->tc_dev);
tegracam_device_unregister(priv->tc_dev);
//imx000_eeprom_device_release(priv);
mutex_destroy(&priv->streaming_lock);
PRINT_FUNC_NAME_2_KERN_LOG_END(__func__);
return 0;
}
static const struct i2c_device_id imx000_id[] = {
{ "imx000", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, imx000_id);
static struct i2c_driver imx000_i2c_driver = {
.driver = {
.name = "imx000",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(imx000_of_match),
},
.probe = imx000_probe,
.remove = imx000_remove,
.id_table = imx000_id,
};
module_i2c_driver(imx000_i2c_driver);
MODULE_DESCRIPTION("Media Controller driver for isMedia IMX000");
MODULE_AUTHOR("NVIDIA Corporation");
MODULE_LICENSE("GPL v2");
Linux_for_Tegra/hardware/nvidia/platform/t18x/common/kernel-dts/t18x-common-platforms/tegra186-quill-camera-imx000-a00.dtsi :
i2c@3180000 {
imx001_a@10 {
/* Define any required hw resources needed by driver */
/* ie. clocks, io pins, power sources */
/* mclk-index indicates the index of the */
/* mclk-name with in the clock-names array */
clocks = <&tegra_car TEGRA186_CLK_EXTPERIPH1>,
<&tegra_car TEGRA186_CLK_PLLP_OUT0>;
clock-names = "extperiph1", "pllp_grtba";
mclk = "extperiph1";
clock-frequency = <24000000>;
reset-gpios = <&tegra_main_gpio CAM0_RST_L GPIO_ACTIVE_HIGH>;
pwdn-gpios = <&tegra_main_gpio CAM0_PWDN GPIO_ACTIVE_HIGH>;
vana-supply = <&en_vdd_cam_hv_2v8>;
vif-supply = <&en_vdd_cam>;
vdig-supply = <&en_vdd_cam_1v2>;
};
};
gpio@2200000 {
camera-control-output-low {
gpio-hog;
output-low;
gpios = <CAM0_RST_L 0 CAM0_PWDN 0>;
label = "cam0-rst", "cam0-pwdn";
};
};
Linux_for_Tegra/hardware/nvidia/platform/t18x/common/kernel-dts/t18x-common-modules/tegra186-camera-imx000-a00.dtsi :
host1x {
vi@15700000 {
num-channels = <1>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
imx000_vi_in0: endpoint {
port-index = <0>;
bus-width = <2>;
remote-endpoint = <&imx000_csi_out0>;
};
};
};
};
nvcsi@150c0000 {
num-channels = <1>;
#address-cells = <1>;
#size-cells = <0>;
channel@0 {
reg = <0>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
imx000_csi_in0: endpoint@0 {
port-index = <0>;
bus-width = <2>;
remote-endpoint = <&imx000_imx001_out0>;
};
};
port@1 {
reg = <1>;
imx000_csi_out0: endpoint@1 {
remote-endpoint = <&imx000_vi_in0>;
};
};
};
};
};
};
i2c@3180000 {
imx001_a@10 {
compatible = "nvidia,imx000";
/* I2C device address */
reg = <0x10>;
/* V4L2 device node location */
devnode = "video0";
/* Physical dimensions of sensor */
physical_w = "3.674";
physical_h = "2.738";
/* Define any required hw resources needed by driver */
/* ie. clocks, io pins, power sources */
avdd-reg = "vana";
iovdd-reg = "vif";
dvdd-reg = "vdig";
/* Sensor output flip settings */
vertical-flip = "true";
mode0 { // OV5693_MODE_2592X1944
mclk_khz = "24000";
num_lanes = "2";
tegra_sinterface = "serial_a";
phy_mode = "DPHY";
discontinuous_clk = "yes";
dpcm_enable = "false";
cil_settletime = "0";
active_w = "2592";
active_h = "1944";
mode_type = "bayer";
pixel_phase = "bggr";
csi_pixel_bit_depth = "10";
readout_orientation = "90";
line_length = "2688";
inherent_gain = "1";
mclk_multiplier = "6.67";
pix_clk_hz = "160000000";
gain_factor = "10";
min_gain_val = "10";/* 1DB*/
max_gain_val = "160";/* 16DB*/
step_gain_val = "1";
default_gain = "10";
min_hdr_ratio = "1";
max_hdr_ratio = "1";
framerate_factor = "1000000";
min_framerate = "1816577";/*1.816577 */
max_framerate = "30000000";/*30*/
step_framerate = "1";
default_framerate = "30000000";
exposure_factor = "1000000";
min_exp_time = "34";/* us */
max_exp_time = "550385";/* us */
step_exp_time = "1";
default_exp_time = "33334";/* us */
embedded_metadata_height = "0";
};
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
imx000_imx001_out0: endpoint {
port-index = <0>;
bus-width = <2>;
remote-endpoint = <&imx000_csi_in0>;
};
};
};
};
};
imx000_lens_imx001@P5V27C {
min_focus_distance = "0.0";
hyper_focal = "0.0";
focal_length = "2.67";
f_number = "2.0";
aperture = "2.0";
};
tegra-camera-platform {
compatible = "nvidia, tegra-camera-platform";
num_csi_lanes = <2>;
max_lane_speed = <1500000>;
min_bits_per_pixel = <10>;
vi_peak_byte_per_pixel = <2>;
vi_bw_margin_pct = <25>;
max_pixel_rate = <160000>;
isp_peak_byte_per_pixel = <5>;
isp_bw_margin_pct = <25>;
modules {
module0 {
badge = "imx000_front_P5V27C";
position = "rear";
orientation = "1";
drivernode0 {
/* Declare PCL support driver (classically known as guid) */
pcl_id = "v4l2_sensor";
/* Driver v4l2 device name */
devname = "imx000 2-0010";
/* Declare the device-tree hierarchy to driver instance */
proc-device-tree = "/proc/device-tree/i2c@3180000/imx001_a@10";
};
drivernode1 {
/* Declare PCL support driver (classically known as guid) */
pcl_id = "v4l2_lens";
proc-device-tree = "/proc/device-tree/e3326_lens_imx001@P5V27C/";
};
};
};
};
I’m waiting for someone who knows about this.
Thank you in advance.