Files
linux-nv-oot/drivers/media/i2c/nv_hawk_owl.c
Praveen AC f62619388d t23x:Add virtual i2c mux support & enable IMU.
This change consists of following changes:
1> Add Virtual i2c-mux driver support for P3762.
2> Ser/Dser reg programming to map 1st Hawk's respective MFP's.
   Accel (MFP0) Ser --> Deser (MFP5)
   Gyro (MFP3) Ser --> Deser (MFP7)
3> Disable IMU's for 2nd,3rd & 4th Hawk.
4> Code cleanup.

Bug 4146784

Change-Id: I3f69bd57b1368451d8e2db06366a57b06b5ff0f4
Signed-off-by: Praveen AC <pac@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2971156
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-by: Ankur Pawar <ankurp@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
2023-09-01 12:52:13 -07:00

1516 lines
43 KiB
C

// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
/*
* nv_hawk_owl.c.c - ar0234 sensor driver
*/
#define DEBUG 0
#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/max9295.h>
#include <media/max9296.h>
#include <media/tegracam_core.h>
#include "hawk_owl_mode_tbls.h"
#include <linux/ktime.h>
#define CHANNEL_N 13
#define MAX_RADIAL_COEFFICIENTS 6
#define MAX_TANGENTIAL_COEFFICIENTS 2
#define MAX_FISHEYE_COEFFICIENTS 6
#define CAMERA_MAX_SN_LENGTH 32
#define MAX_RLS_COLOR_CHANNELS 4
#define MAX_RLS_BREAKPOINTS 6
#define OWL_CHANNEL 1
#define HAWK_CHANNEL 0
#define EXTERNAL_FSYNC 1
#define INTERNAL_FSYNC 2
extern int max96712_write_reg_Dser(int slaveAddr,int channel,
u16 addr, u8 val);
extern int max96712_read_reg_Dser(int slaveAddr,int channel,
u16 addr, unsigned int *val);
#define AR0234_MIN_GAIN (1)
#define AR0234_MAX_GAIN (8)
#define AR0234_MAX_GAIN_REG (0x40)
#define AR0234_DEFAULT_FRAME_LENGTH (1224)
#define AR0234_COARSE_TIME_SHS1_ADDR 0x3012
#define AR0234_ANALOG_GAIN 0x3060
int owl_links;
int hawk_links;
static const struct of_device_id ar0234_of_match[] = {
{.compatible = "nvidia,ar0234_hawk_owl",},
{ },
};
MODULE_DEVICE_TABLE(of, ar0234_of_match);
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_EEPROM_DATA,
TEGRA_CAMERA_CID_HDR_EN,
TEGRA_CAMERA_CID_SENSOR_MODE_ID,
TEGRA_CAMERA_CID_STEREO_EEPROM,
};
// Coefficients as per distortion model (wide FOV) being used
typedef struct
{
// Radial coefficients count
u32 coeff_count;
// Radial coefficients
float k[MAX_FISHEYE_COEFFICIENTS];
// 0 -> equidistant, 1 -> equisolid, 2 -> orthographic, 3 -> stereographic
u32 mapping_type;
} fisheye_lens_distortion_coeff;
// Coefficients as per distortion model being used
typedef struct
{
// Radial coefficients count
u32 radial_coeff_count;
// Radial coefficients
float k[MAX_RADIAL_COEFFICIENTS];
// Tangential coefficients count
u32 tangential_coeff_count;
// Tangential coefficients
float p[MAX_TANGENTIAL_COEFFICIENTS];
} polynomial_lens_distortion_coeff;
/*
* Stereo Eeprom Data
*/
typedef struct
{
// Width and height of image in pixels
u32 width, height;
// Focal length in pixels
float fx, fy;
float skew;
// Principal point (optical center) in pixels
float cx, cy;
/*
* Structure for distortion coefficients as per the model being used
* 0: pinhole, assuming polynomial distortion
* 1: fisheye, assuming fisheye distortion)
* 2: ocam (omini-directional)
*/
u32 distortion_type;
union distortion_coefficients {
polynomial_lens_distortion_coeff poly;
fisheye_lens_distortion_coeff fisheye;
} dist_coeff;
} camera_intrinsics;
/*
* Extrinsic parameters shared by camera and IMU.
* All rotation + translation with respect to the same reference point
*/
typedef struct
{
/*
* Rotation parameter expressed in Rodrigues notation
* angle = sqrt(rx^2+ry^2+rz^2)
* unit axis = [rx,ry,rz]/angle
*/
float rx, ry, rz;
// Translation parameter from one camera to another parameter
float tx, ty, tz;
} camera_extrinsics;
typedef struct
{
// 3D vector to add to accelerometer readings
float linear_acceleration_bias[3];
// 3D vector to add to gyroscope readings
float angular_velocity_bias[3];
// gravity acceleration
float gravity_acceleration[3];
// Extrinsic structure for IMU device
camera_extrinsics extr;
// Noise model parameters
float update_rate;
float linear_acceleration_noise_density;
float linear_acceleration_random_walk;
float angular_velocity_noise_density;
float angular_velocity_random_walk;
} imu_params;
typedef struct {
// Image height
u16 image_height;
// Image width
u16 image_width;
// Number of color channels
u8 n_channels;
// Coordinate x of center point
float rls_x0[MAX_RLS_COLOR_CHANNELS];
// Coordinate y of center point
float rls_y0[MAX_RLS_COLOR_CHANNELS];
// Ellipse xx parameter
double ekxx[MAX_RLS_COLOR_CHANNELS];
// Ellipse xy parameter
double ekxy[MAX_RLS_COLOR_CHANNELS];
// Ellipse yx parameter
double ekyx[MAX_RLS_COLOR_CHANNELS];
// Ellipse yy parameter
double ekyy[MAX_RLS_COLOR_CHANNELS];
// Number of breakpoints in LSC radial transfer function
u8 rls_n_points;
// LSC radial transfer function X
float rls_rad_tf_x[MAX_RLS_COLOR_CHANNELS][MAX_RLS_BREAKPOINTS];
// LSC radial transfer function Y
float rls_rad_tf_y[MAX_RLS_COLOR_CHANNELS][MAX_RLS_BREAKPOINTS];
// LSC radial transfer function slope
float rls_rad_tf_slope[MAX_RLS_COLOR_CHANNELS][MAX_RLS_BREAKPOINTS];
// rScale parameter
u8 r_scale;
} radial_lsc_params;
typedef struct
{
// Intrinsic structure for camera device
camera_intrinsics cam_intr;
// Extrinsic structure for camera device
camera_extrinsics cam_extr;
// Flag for IMU availability
u8 imu_present;
// Intrinsic structure for IMU
imu_params imu;
// HAWK module serial number
u8 serial_number[CAMERA_MAX_SN_LENGTH];
// Radial Lens Shading Correction parameters
radial_lsc_params rls;
} NvCamSyncSensorCalibData;
typedef struct
{
/**
* EEPROM layout version
*/
u32 version;
/**
* Factory Blob Flag, to set when factory flashed and reset to 0
* when user modified
*/
u32 factory_data;
/**
* Intrinsic structure for camera device
*/
camera_intrinsics left_cam_intr;
camera_intrinsics right_cam_intr;
/**
* Extrinsic structure for camera device
*/
camera_extrinsics cam_extr;
/**
* Flag for IMU 0-absent, 1-present
*/
u8 imu_present;
/**
* Intrinsic structure for IMU
*/
imu_params imu;
// HAWK module serial number
u8 serial_number[CAMERA_MAX_SN_LENGTH];
// Radial Lens Shading Correction parameters
radial_lsc_params left_rls;
radial_lsc_params right_rls;
} LiEeprom_Content_Struct;
struct ar0234 {
struct camera_common_eeprom_data eeprom[AR0234_EEPROM_NUM_BLOCKS];
u8 eeprom_buf[AR0234_EEPROM_SIZE];
struct i2c_client *i2c_client;
const struct i2c_device_id *id;
struct v4l2_subdev *subdev;
u32 frame_length;
struct camera_common_data *s_data;
struct tegracam_device *tc_dev;
u32 channel;
u32 sync_sensor_index;
const char *sensor_name;
NvCamSyncSensorCalibData EepromCalib;
};
static const struct regmap_config sensor_regmap_config = {
.reg_bits = 16,
.val_bits = 16,
.cache_type = REGCACHE_RBTREE,
};
static inline void ar0234_get_coarse_time_regs_shs1(ar0234_reg *regs,
u16 coarse_time)
{
regs->addr = AR0234_COARSE_TIME_SHS1_ADDR;
regs->val = (coarse_time) & 0xffff;
}
static inline void ar0234_get_gain_reg(ar0234_reg *regs,
u16 gain)
{
regs->addr = AR0234_ANALOG_GAIN;
regs->val = (gain) & 0xffff;
}
static int test_mode;
module_param(test_mode, int, 0644);
static inline int ar0234_read_reg(struct camera_common_data *s_data,
u16 addr, u16 *val)
{
int err = 0;
u32 reg_val = 0;
err = regmap_read(s_data->regmap, addr, &reg_val);
*val = reg_val & 0xFFFF;
return err;
}
static int ar0234_write_reg(struct camera_common_data *s_data,
u16 addr, u16 val)
{
int err = 0;
struct device *dev = s_data->dev;
err = regmap_write(s_data->regmap, addr, val);
if (err)
dev_err(dev, "%s:i2c write failed, 0x%x = %x\n",
__func__, addr, val);
return err;
}
static int ar0234_write_table(struct ar0234 *priv,
const struct index_reg_8 table[])
{
struct tegracam_device *tc_dev = priv->tc_dev;
struct device *dev = tc_dev->dev;
int i = 0;
int ret = 0;
int retry = 5;
int retry_seraddr = 0x84;
dev_dbg(dev, "%s: channel %d, ", __func__, priv->channel);
while (table[i].source != 0x00) {
if (table[i].source == 0x06) {
retry = 1;
if (table[i].addr == AR0234_TABLE_WAIT_MS)
{
dev_err(dev, "%s: sleep 500\n", __func__);
msleep(table[i].val);
i++;
continue;
}
retry_sensor:
ret = ar0234_write_reg(priv->s_data, table[i].addr, table[i].val);
if (ret) {
retry--;
if (retry > 0) {
dev_warn(dev, "ar0234_write_reg: try %d\n", retry);
msleep(4);
goto retry_sensor;
}
return -1;
} else {
if (0x301a == table[i].addr || 0x3060 == table[i].addr)
msleep(100);
}
} else {
retry = 5;
if (priv->channel == CHANNEL_N)
{
i++;
continue;
}
retry_serdes:
/* To handle sync sensor i2c trans */
if (2 == priv->sync_sensor_index)
ret = max96712_write_reg_Dser(table[i].source,
0/*channel-num*/, table[i].addr, (u8)table[i].val);
else
ret = max96712_write_reg_Dser(table[i].source,
priv->channel, table[i].addr, (u8)table[i].val);
/* To handle ser address change from 0x80 to 0x84
* after link enable at deser*/
if (ret && (0x80 == table[i].source)) {
ret = max96712_write_reg_Dser(retry_seraddr,
priv->channel, table[i].addr, (u8)table[i].val);
}
if (ret && (table[i].addr != 0x0000))
{
retry--;
if (retry > 0) {
dev_warn(dev, "max96712_write_reg_Dser: try %d\n", retry);
msleep(4);
goto retry_serdes;
}
return -1;
}
if (0x0010 == table[i].addr || 0x0000 == table[i].addr ||
0x0006 == table[i].addr || 0x0018 == table[i].addr)
msleep(300);
else
msleep(10);
}
i++;
}
return 0;
}
static int ar0234_hawk_link_check(struct ar0234 *priv)
{
unsigned int linkA = 0;
unsigned int linkB = 0;
unsigned int linkC = 0;
unsigned int linkD = 0;
if ((1 == priv->channel)) {
max96712_read_reg_Dser(0x52, OWL_CHANNEL, 0x1A, &linkA);
max96712_read_reg_Dser(0x52, OWL_CHANNEL, 0x0A, &linkB);
max96712_read_reg_Dser(0x52, OWL_CHANNEL, 0x0B, &linkC);
max96712_read_reg_Dser(0x52, OWL_CHANNEL, 0x0C, &linkD);
} else if ((!priv->channel) || (2 == priv->sync_sensor_index)) {
max96712_read_reg_Dser(0x52, HAWK_CHANNEL, 0x1A, &linkA);
max96712_read_reg_Dser(0x52, HAWK_CHANNEL, 0x0A, &linkB);
max96712_read_reg_Dser(0x52, HAWK_CHANNEL, 0x0B, &linkC);
max96712_read_reg_Dser(0x52, HAWK_CHANNEL, 0x0C, &linkD);
}
pr_info("%s: linA=%x, linB=%x, linC=%x, linD=%x\n",__func__, linkA, linkB, linkC, linkD);
if((linkB & 0x8) && (linkA & 0x8) && (linkC & 0x8) && (linkD & 0x8)) {
return 4;
} else if((linkB & 0x8) && (linkA & 0x8) && (linkC & 0x8) ){
return 3;
} else if((linkB & 0x8) && (linkA & 0x8)){
return 2;
} else if(linkA & 0x8) {
return 1;
} else {
return 0;
}
}
static int sensor_name_to_enum(struct ar0234 *priv)
{
if (!strcmp(priv->sensor_name, "OWL1"))
return OWL1;
else if (!strcmp(priv->sensor_name, "OWL2"))
return OWL2;
else if (!strcmp(priv->sensor_name, "OWL3"))
return OWL3;
else if (!strcmp(priv->sensor_name, "OWL4"))
return OWL4;
else if (!strcmp(priv->sensor_name, "HAWK1"))
return HAWK1;
else if (!strcmp(priv->sensor_name, "HAWK2"))
return HAWK2;
else if (!strcmp(priv->sensor_name, "HAWK3"))
return HAWK3;
else if (!strcmp(priv->sensor_name, "HAWK4"))
return HAWK4;
else
pr_err("%s: Sensor name %s is not matching!!\n",__func__,priv->sensor_name);
return -1;
}
static int ar0234_hawk_owl_i2ctrans(struct ar0234 *priv)
{
int err = 0;
if(ar0234_hawk_link_check(priv) == 4) {
err = ar0234_write_table(priv, hawk_owl_i2ctrans_table[sensor_name_to_enum(priv)]);
} else if(ar0234_hawk_link_check(priv) == 3) {
err = ar0234_write_table(priv, hawk_owl_i2ctrans_table[sensor_name_to_enum(priv)]);
} else if(ar0234_hawk_link_check(priv) == 2) {
err = ar0234_write_table(priv, hawk_owl_i2ctrans_table[sensor_name_to_enum(priv)]);
} else if(ar0234_hawk_link_check(priv) == 1) {
err = ar0234_write_table(priv, hawk_owl_i2ctrans_table[sensor_name_to_enum(priv)]);
}
return err;
}
static int hawk_owl_ser_i2c_trans(struct camera_common_data *s_data)
{
int err = 0;
struct ar0234 *priv = (struct ar0234 *) s_data->priv;
struct device *dev = s_data->dev;
static int haw_flag = 0, owl_flag = 0;
/* Serializer i2c address trans */
if(ar0234_hawk_link_check(priv) == 4) {
if ((1 == priv->channel) && !owl_flag) {
err = ar0234_write_table(priv, i2c_address_trans_owl_Quad_ser);
if (err) {
dev_err(dev,"%s: Failed to do i2c address trans..\n",__func__);
} else {
dev_info(dev,"%s: Successfully done I2c address trans..\n",__func__);
}
owl_flag++;
} else if ((!priv->channel) && !haw_flag) {
err = ar0234_write_table(priv, i2c_address_trans_hawk_Quad_ser);
if (err) {
dev_err(dev,"%s: Failed to do i2c address trans..\n",__func__);
} else {
dev_info(dev,"%s: Successfully done I2c address trans..\n",__func__);
}
haw_flag++;
}
} else if(ar0234_hawk_link_check(priv) == 3) {
if ((1 == priv->channel) && !owl_flag) {
err = ar0234_write_table(priv, i2c_address_trans_owl_Triple_ser);
if (err) {
dev_err(dev,"%s: Failed to do i2c address trans..\n",__func__);
} else {
dev_info(dev,"%s: Successfully done I2c address trans..\n",__func__);
}
owl_flag++;
} else if ((!priv->channel) && !haw_flag) {
err = ar0234_write_table(priv, i2c_address_trans_hawk_Triple_ser);
if (err) {
dev_err(dev,"%s: Failed to do i2c address trans..\n",__func__);
} else {
dev_info(dev,"%s: Successfully done I2c address trans..\n",__func__);
}
haw_flag++;
}
} else if(ar0234_hawk_link_check(priv) == 2) {
if ((1 == priv->channel) && !owl_flag) {
err = ar0234_write_table(priv, i2c_address_trans_owl_Dual_ser);
if (err) {
dev_err(dev,"%s: Failed to do i2c address trans..\n",__func__);
} else {
dev_info(dev,"%s: Successfully done I2c address trans..\n",__func__);
}
owl_flag++;
} else if ((!priv->channel) && !haw_flag) {
err = ar0234_write_table(priv, i2c_address_trans_hawk_Dual_ser);
if (err) {
dev_err(dev,"%s: Failed to do i2c address trans..\n",__func__);
} else {
dev_info(dev,"%s: Successfully done I2c address trans..\n",__func__);
}
haw_flag++;
}
} else if(ar0234_hawk_link_check(priv) == 1) {
if ((1 == priv->channel) && !owl_flag) {
err = ar0234_write_table(priv, i2c_address_trans_owl_Single_ser);
if (err) {
dev_err(dev,"%s: Failed to do i2c address trans..\n",__func__);
} else {
dev_info(dev,"%s: Successfully done I2c address trans..\n",__func__);
}
owl_flag++;
} else if ((!priv->channel) && !haw_flag) {
err = ar0234_write_table(priv, i2c_address_trans_hawk_Single_ser);
if (err) {
dev_err(dev,"%s: Failed to do i2c address trans..\n",__func__);
} else {
dev_info(dev,"%s: Successfully done I2c address trans..\n",__func__);
}
haw_flag++;
}
}
return err;
}
static int ar0234_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;
struct ar0234 *priv = (struct ar0234 *) s_data->priv;
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 > 0)
gpio_set_value(pw->reset_gpio, 1);
usleep_range(1000, 2000);
pw->state = SWITCH_ON;
/*i2c address trans for Hawk & Owl*/
err = ar0234_hawk_owl_i2ctrans(priv);
return err;
}
static int ar0234_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_err(dev, "%s:\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;
}
power_off_done:
pw->state = SWITCH_OFF;
return 0;
}
static int ar0234_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;
const char *mclk_name;
const char *parentclk_name;
struct clk *parent;
int err = 0;
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);
}
if (!err) {
pw->reset_gpio = pdata->reset_gpio;
pw->af_gpio = pdata->af_gpio;
pw->pwdn_gpio = pdata->pwdn_gpio;
}
pw->state = SWITCH_OFF;
return err;
}
static int ar0234_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;
return 0;
}
static int ar0234_set_group_hold(struct tegracam_device *tc_dev, bool val)
{
struct device *dev = tc_dev->dev;
int err = 0;
if (err) {
dev_err(dev,
"%s: Group hold control error\n", __func__);
return err;
}
return 0;
}
static int ar0234_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;
ar0234_reg reg_list[1];
int err;
u16 gain = (u16)val;
u16 gain_reg = 0;
if (val < 200) {
gain_reg = (32 * (1000 - (100000/gain)))/1000;
} else if (val < 400 && val >= 200) {
gain = gain /2;
gain_reg = (16 * (1000 - (100000/gain)))/1000 * 2;
gain_reg = gain_reg + 0x10;
} else if (val < 800 && val >= 400) {
gain = gain / 4;
gain_reg = (32 * (1000 - (100000/gain)))/1000;
gain_reg = gain_reg + 0x20;
} else if (val < 1600 && val >= 800) {
gain = gain /8;
gain_reg = (16 * (1000 - (100000/gain)))/1000 * 2;
gain_reg = gain_reg + 0x30;
} else if (val >= 1600) {
gain_reg = 0x40;
}
if (gain > AR0234_MAX_GAIN_REG)
gain = AR0234_MAX_GAIN_REG;
ar0234_get_gain_reg(reg_list, gain_reg);
err = ar0234_write_reg(s_data, reg_list[0].addr,
reg_list[0].val);
if (err)
goto fail;
return 0;
fail:
dev_err(dev, "%s: GAIN control error\n", __func__);
return err;
}
static int ar0234_set_frame_rate(struct tegracam_device *tc_dev, s64 val)
{
struct ar0234 *priv = (struct ar0234 *)tegracam_get_privdata(tc_dev);
if (val == 30000000) { //30fps full resolution
max96712_write_reg_Dser(0x52, priv->channel, 0x04A5, 0x35);
max96712_write_reg_Dser(0x52, priv->channel, 0x04A6, 0xB7);
max96712_write_reg_Dser(0x52, priv->channel, 0x04A7, 0x0C);
priv->frame_length = 0xC20;
} else if (val == 60000000) {//60fps full resolution
max96712_write_reg_Dser(0x52, priv->channel, 0x04A5, 0x9A);
max96712_write_reg_Dser(0x52, priv->channel, 0x04A6, 0x5B);
max96712_write_reg_Dser(0x52, priv->channel, 0x04A7, 0x06);
priv->frame_length = 0x610;
} else if (val == 120000000) {//120fps binning resolution
max96712_write_reg_Dser(0x52, priv->channel, 0x04A5, 0xCD);
max96712_write_reg_Dser(0x52, priv->channel, 0x04A6, 0x2D);
max96712_write_reg_Dser(0x52, priv->channel, 0x04A7, 0x03);
priv->frame_length = 0x308;
}
return 0;
}
static int ar0234_set_exposure(struct tegracam_device *tc_dev, s64 val)
{
struct ar0234 *priv = (struct ar0234 *)tegracam_get_privdata(tc_dev);
struct camera_common_data *s_data = tc_dev->s_data;
const struct sensor_mode_properties *mode =
&s_data->sensor_props.sensor_modes[s_data->mode];
ar0234_reg reg_list[1];
int err;
u32 coarse_time;
u32 shs1;
if (priv->frame_length == 0)
priv->frame_length = AR0234_DEFAULT_FRAME_LENGTH;
coarse_time = mode->signal_properties.pixel_clock.val *
val / mode->image_properties.line_length /
mode->control_properties.exposure_factor;
if (coarse_time > priv->frame_length)
coarse_time = priv->frame_length;
shs1 = coarse_time;
/* 0 and 1 are prohibited */
if (shs1 < 2)
shs1 = 2;
ar0234_get_coarse_time_regs_shs1(reg_list, shs1);
err = ar0234_write_reg(priv->s_data, reg_list[0].addr,
reg_list[0].val);
if (err)
goto fail;
return 0;
fail:
dev_err(&priv->i2c_client->dev,
"%s: set coarse time error\n", __func__);
return err;
}
static int ar0234_fill_string_ctrl(struct tegracam_device *tc_dev,
struct v4l2_ctrl *ctrl)
{
struct ar0234 *priv = tc_dev->priv;
int i, ret;
switch (ctrl->id) {
case TEGRA_CAMERA_CID_EEPROM_DATA:
for (i = 0; i < AR0234_EEPROM_SIZE; i++) {
ret = sprintf(&ctrl->p_new.p_char[i*2], "%02x",
priv->eeprom_buf[i]);
if (ret < 0)
return -EINVAL;
}
break;
default:
return -EINVAL;
}
ctrl->p_cur.p_char = ctrl->p_new.p_char;
return 0;
}
static int ar0234_fill_eeprom(struct tegracam_device *tc_dev,
struct v4l2_ctrl *ctrl)
{
struct ar0234 *priv = tc_dev->priv;
LiEeprom_Content_Struct *tmp;
u32 test = 0;
switch (ctrl->id) {
case TEGRA_CAMERA_CID_STEREO_EEPROM:
tmp = kmalloc(sizeof(LiEeprom_Content_Struct),
GFP_KERNEL);
if (tmp == NULL)
return -ENOMEM;
memset(&(priv->EepromCalib), 0, sizeof(NvCamSyncSensorCalibData));
memset(ctrl->p_new.p, 0, sizeof(NvCamSyncSensorCalibData));
memcpy(tmp, priv->eeprom_buf, sizeof(LiEeprom_Content_Struct));
if (priv->sync_sensor_index == 1) {
priv->EepromCalib.cam_intr = tmp->left_cam_intr;
} else if (priv->sync_sensor_index == 2) {
priv->EepromCalib.cam_intr = tmp->right_cam_intr;
} else {
priv->EepromCalib.cam_intr = tmp->left_cam_intr;
}
priv->EepromCalib.cam_extr = tmp->cam_extr;
priv->EepromCalib.imu_present = tmp->imu_present;
priv->EepromCalib.imu = tmp->imu;
memcpy(priv->EepromCalib.serial_number, tmp->serial_number,
CAMERA_MAX_SN_LENGTH);
if (priv->sync_sensor_index == 1)
priv->EepromCalib.rls = tmp->left_rls;
else if (priv->sync_sensor_index == 2)
priv->EepromCalib.rls = tmp->right_rls;
else
priv->EepromCalib.rls = tmp->left_rls;
memcpy(ctrl->p_new.p, (u8 *)&(priv->EepromCalib),
sizeof(NvCamSyncSensorCalibData));
kfree(tmp);
break;
default:
return -EINVAL;
}
memcpy(&test, &(priv->EepromCalib.cam_intr.fx), 4);
ctrl->p_cur.p = ctrl->p_new.p;
return 0;
}
static struct tegracam_ctrl_ops ar0234_ctrl_ops = {
.numctrls = ARRAY_SIZE(ctrl_cid_list),
.ctrl_cid_list = ctrl_cid_list,
.string_ctrl_size = {AR0234_EEPROM_STR_SIZE},
.compound_ctrl_size = {sizeof(NvCamSyncSensorCalibData)},
.set_gain = ar0234_set_gain,
.set_exposure = ar0234_set_exposure,
.set_exposure_short = ar0234_set_exposure,
.set_frame_rate = ar0234_set_frame_rate,
.set_group_hold = ar0234_set_group_hold,
.fill_string_ctrl = ar0234_fill_string_ctrl,
.fill_compound_ctrl = ar0234_fill_eeprom,
};
static struct camera_common_pdata *ar0234_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 err;
int gpio = 0;
if (!node)
return NULL;
match = of_match_device(ar0234_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);
err = of_property_read_string(node, "mclk",
&board_priv_pdata->mclk_name);
if (err)
dev_err(dev, "mclk not in DT\n");
board_priv_pdata->reset_gpio = of_get_named_gpio(node,
"reset-gpios", 0);
gpio_direction_output(board_priv_pdata->reset_gpio, 1);
board_priv_pdata->pwdn_gpio = of_get_named_gpio(node,
"pwdn-gpios", 0);
gpio_direction_output(board_priv_pdata->pwdn_gpio, 1);
gpio = of_get_named_gpio(node,
"pwr-gpios", 0);
gpio_direction_output(gpio, 1);
board_priv_pdata->has_eeprom =
of_property_read_bool(node, "has-eeprom");
if (board_priv_pdata->has_eeprom) {
err = of_property_read_u32(node, "eeprom-addr", &board_priv_pdata->eeprom_id_addr);
if (err)
dev_err(dev, "Failed to read eeprom addr\n");
}
return board_priv_pdata;
}
static int ar0234_set_mode(struct tegracam_device *tc_dev)
{
struct ar0234 *priv = (struct ar0234 *)tegracam_get_privdata(tc_dev);
struct camera_common_data *s_data = tc_dev->s_data;
struct device *dev = tc_dev->dev;
const struct of_device_id *match;
int err = 0;
match = of_match_device(ar0234_of_match, dev);
if (!match) {
dev_err(dev, "Failed to find matching dt id\n");
return -EINVAL;
}
err = ar0234_write_table(priv, mode_table[AR0234_MODE_STOP_STREAM]);
if (err)
return err;
if (s_data->mode_prop_idx < 0)
return -EINVAL;
dev_err(dev, "%s: mode index:%d\n", __func__,s_data->mode_prop_idx);
/* Moved the sensor mode table write during probe time, to reduce Stream on time */
return 0;
}
static int ar0234_start_streaming(struct tegracam_device *tc_dev)
{
struct ar0234 *priv = (struct ar0234 *)tegracam_get_privdata(tc_dev);
int err;
if (test_mode) {
err = ar0234_write_table(priv,
mode_table[AR0234_MODE_TEST_PATTERN]);
if (err)
return err;
}
err = ar0234_write_table(priv,
mode_table[AR0234_MODE_START_STREAM]);
if (err)
return err;
return 0;
}
static int ar0234_stop_streaming(struct tegracam_device *tc_dev)
{
struct ar0234 *priv = (struct ar0234 *)tegracam_get_privdata(tc_dev);
int err;
err = ar0234_write_table(priv, mode_table[AR0234_MODE_STOP_STREAM]);
if (err)
return err;
return 0;
}
static struct camera_common_sensor_ops ar0234_common_ops = {
.numfrmfmts = ARRAY_SIZE(ar0234_frmfmt),
.frmfmt_table = ar0234_frmfmt,
.power_on = ar0234_power_on,
.power_off = ar0234_power_off,
.parse_dt = ar0234_parse_dt,
.power_get = ar0234_power_get,
.power_put = ar0234_power_put,
.set_mode = ar0234_set_mode,
.start_streaming = ar0234_start_streaming,
.stop_streaming = ar0234_stop_streaming,
};
static int ar0234_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
dev_err(&client->dev, "%s:\n", __func__);
return 0;
}
static int ar0234_eeprom_device_release(struct ar0234 *priv)
{
int i;
for (i = 0; i < AR0234_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 const struct v4l2_subdev_internal_ops ar0234_subdev_internal_ops = {
.open = ar0234_open,
};
static int ar0234_eeprom_device_init(struct ar0234 *priv)
{
struct camera_common_pdata *pdata = priv->s_data->pdata;
char *dev_name = "eeprom_ar0234";
static struct regmap_config eeprom_regmap_config = {
.reg_bits = 8,
.val_bits = 8
};
int i;
int err;
if (!pdata->has_eeprom)
return -EINVAL;
for (i = 0; i < AR0234_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));
/* assign the EEPROM addrs which is read from DT */
priv->eeprom[i].brd.addr = pdata->eeprom_id_addr + i;
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
priv->eeprom[i].i2c_client = i2c_new_device(
priv->eeprom[i].adap, &priv->eeprom[i].brd);
#else
priv->eeprom[i].i2c_client = i2c_new_client_device(
priv->eeprom[i].adap, &priv->eeprom[i].brd);
#endif
if (!priv->eeprom[i].i2c_client) {
pr_err("%s: Failed to probe EEPORM at addr = 0x%x \n",
__func__, priv->eeprom[i].brd.addr);
return 0;
}
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);
ar0234_eeprom_device_release(priv);
return err;
}
}
return 0;
}
static int ar0234_read_eeprom(struct ar0234 *priv)
{
int err, i;
for (i = 0; i < AR0234_EEPROM_NUM_BLOCKS; i++) {
err = regmap_bulk_read(priv->eeprom[i].regmap, 0,
&priv->eeprom_buf[i * AR0234_EEPROM_BLOCK_SIZE],
AR0234_EEPROM_BLOCK_SIZE);
if (err) {
return err;
}
}
#if DEBUG
/* Print added, Remove later */
for (i = 0; i < AR0234_EEPROM_BLOCK_SIZE; i+=8) {
pr_err("%02x %02x %02x %02x %02x %02x %02x %02x",priv->eeprom_buf[i+0],\
priv->eeprom_buf[i+1],priv->eeprom_buf[i+2],priv->eeprom_buf[i+3],\
priv->eeprom_buf[i+4],priv->eeprom_buf[i+5],priv->eeprom_buf[i+6],
priv->eeprom_buf[i+7]);
pr_err("\n");
}
#endif
return 0;
}
static int ar0234_board_setup(struct ar0234 *priv)
{
struct camera_common_data *s_data = priv->s_data;
struct device *dev = s_data->dev;
bool eeprom_ctrl = 0;
int err = 0;
dev_err(dev, "%s++\n", __func__);
/* eeprom interface */
err = ar0234_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;
}
if (eeprom_ctrl) {
err = ar0234_read_eeprom(priv);
if (err) {
dev_err(dev,
"Error %d reading eeprom\n", err);
goto error;
}
}
error:
ar0234_power_off(s_data);
camera_common_mclk_disable(s_data);
return err;
}
static int ar0234_hawk_owl_EEPROM_address_trans(struct ar0234 *priv)
{
int err = 0;
if(ar0234_hawk_link_check(priv) == 4) {
err = ar0234_write_table(priv, hawk_owl_eeprom_i2ctrans_table[sensor_name_to_enum(priv)]);
} else if(ar0234_hawk_link_check(priv) == 3) {
err = ar0234_write_table(priv, hawk_owl_eeprom_i2ctrans_table[sensor_name_to_enum(priv)]);
} else if(ar0234_hawk_link_check(priv) == 2) {
err = ar0234_write_table(priv, hawk_owl_eeprom_i2ctrans_table[sensor_name_to_enum(priv)]);
} else if(ar0234_hawk_link_check(priv) == 1) {
err = ar0234_write_table(priv, hawk_owl_eeprom_i2ctrans_table[sensor_name_to_enum(priv)]);
}
return err;
}
static int max96712_fsync_program(const struct index_reg_8 table[], int channel)
{
int ret = 0;
int i = 0;
int retry = 5;
while (table[i].source != 0x00) {
retry_serdes:
ret = max96712_write_reg_Dser(table[i].source,
channel, table[i].addr, (u8)table[i].val);
if (ret && (table[i].addr != 0x0000))
{
retry--;
if (retry > 0) {
pr_err("max96712_write_reg_Dser: try %d\n", retry);
msleep(4);
goto retry_serdes;
}
return -1;
}
if (0x0010 == table[i].addr || 0x0000 == table[i].addr ||
0x0006 == table[i].addr || 0x0018 == table[i].addr)
msleep(300);
else
msleep(10);
i++;
}
return ret;
}
static int owl_internal_fsync(void)
{
int err = 0;
switch(owl_links) {
case QUAD_LINK:
err = max96712_fsync_program(Owl_QuadLink_Dser_InFsync, OWL_CHANNEL);
if (err)
pr_err("%s: Failed to set internal fsync for OWL\n",__func__);
else
pr_info("%s: Successfully set internal fsync for OWL\n",__func__);
break;
case TRIPLE_LINK:
err = max96712_fsync_program(Owl_TripleLink_Dser_InFsync, OWL_CHANNEL);
if (err)
pr_err("%s: Failed to set internal fsync for OWL\n",__func__);
else
pr_info("%s: Successfully set internal fsync for OWL\n",__func__);
break;
case DUAL_LINK:
err = max96712_fsync_program(Owl_DualLink_Dser_InFsync, OWL_CHANNEL);
if (err)
pr_err("%s: Failed to set internal fsync for OWL\n",__func__);
else
pr_info("%s: Successfully set internal fsync for OWL\n",__func__);
break;
case SINGLE_LINK:
err = max96712_fsync_program(Owl_SingleLink_Dser_InFsync, OWL_CHANNEL);
if (err)
pr_err("%s: Failed to set internal fsync for OWL\n",__func__);
else
pr_info("%s: Successfully set internal fsync for OWL\n",__func__);
break;
default:
pr_err("%s: not matching to any link type %d\n", __func__, owl_links);
break;
}
return err;
}
static int owl_external_fsync(void)
{
int err = 0;
switch(owl_links) {
case QUAD_LINK:
err = max96712_fsync_program(Owl_QuadLink_Dser_ExFsync, OWL_CHANNEL);
if (err)
pr_err("%s: Failed to set external fsync for OWL\n",__func__);
else
pr_info("%s: Successfully set external fsync for OWL\n",__func__);
break;
case TRIPLE_LINK:
err = max96712_fsync_program(Owl_TripleLink_Dser_ExFsync, OWL_CHANNEL);
if (err)
pr_err("%s: Failed to set external fsync for OWL\n",__func__);
else
pr_info("%s: Successfully set external fsync for OWL\n",__func__);
break;
case DUAL_LINK:
err = max96712_fsync_program(Owl_DualLink_Dser_ExFsync, OWL_CHANNEL);
if (err)
pr_err("%s: Failed to set external fsync for OWL\n",__func__);
else
pr_info("%s: Successfully set external fsync for OWL\n",__func__);
break;
case SINGLE_LINK:
err = max96712_fsync_program(Owl_SingleLink_Dser_ExFsync, OWL_CHANNEL);
if (err)
pr_err("%s: Failed to set external fsync for OWL\n",__func__);
else
pr_info("%s: Successfully set external fsync for OWL\n",__func__);
break;
default:
pr_err("%s: not matching to any link type %d\n", __func__, owl_links);
break;
}
return err;
}
static int hawk_internal_fsync(void)
{
int err = 0;
switch(hawk_links) {
case QUAD_LINK:
err = max96712_fsync_program(Hawk_QuadLink_Dser_InFsync, HAWK_CHANNEL);
if (err)
pr_err("%s: Failed to set internal fsync for HAWK\n",__func__);
else
pr_info("%s: Successfully set internal fsync for HAWK\n",__func__);
break;
case TRIPLE_LINK:
err = max96712_fsync_program(Hawk_TripleLink_Dser_InFsync, HAWK_CHANNEL);
if (err)
pr_err("%s: Failed to set internal fsync for HAWK\n",__func__);
else
pr_info("%s: Successfully set internal fsync for HAWK\n",__func__);
break;
case DUAL_LINK:
err = max96712_fsync_program(Hawk_DualLink_Dser_InFsync, HAWK_CHANNEL);
if (err)
pr_err("%s: Failed to set internal fsync for HAWK\n",__func__);
else
pr_info("%s: Successfully set internal fsync for HAWK\n",__func__);
break;
case SINGLE_LINK:
err = max96712_fsync_program(Hawk_SingleLink_Dser_InFsync, HAWK_CHANNEL);
if (err)
pr_err("%s: Failed to set internal fsync for HAWK\n",__func__);
else
pr_info("%s: Successfully set internal fsync for HAWK\n",__func__);
break;
default:
pr_err("%s: not matching to any link type %d\n", __func__, hawk_links);
break;
}
return err;
}
static int hawk_external_fsync(void)
{
int err = 0;
switch (hawk_links) {
case QUAD_LINK:
err = max96712_fsync_program(Hawk_QuadLink_Dser_ExFsync, HAWK_CHANNEL);
if (err)
pr_err("%s: Failed to set external fsync for HAWK\n",__func__);
else
pr_info("%s: Successfully set external fsync for HAWK\n",__func__);
break;
case TRIPLE_LINK:
err = max96712_fsync_program(Hawk_TripleLink_Dser_ExFsync, HAWK_CHANNEL);
if (err)
pr_err("%s: Failed to set external fsync for HAWK\n",__func__);
else
pr_info("%s: Successfully set external fsync for HAWK\n",__func__);
break;
case DUAL_LINK:
err = max96712_fsync_program(Hawk_DualLink_Dser_ExFsync, HAWK_CHANNEL);
if (err)
pr_err("%s: Failed to set external fsync for HAWK\n",__func__);
else
pr_info("%s: Successfully set external fsync for HAWK\n",__func__);
break;
case SINGLE_LINK:
err = max96712_fsync_program(Hawk_SingleLink_Dser_ExFsync, HAWK_CHANNEL);
if (err)
pr_err("%s: Failed to set external fsync for HAWK\n",__func__);
else
pr_info("%s: Successfully set external fsync for HAWK\n",__func__);
break;
default:
pr_err("%s: not matching to any link type %d\n", __func__, hawk_links);
break;
}
return err;
}
int Hawk_Owl_Fsync_program(int fsync_type)
{
int err = 0;
switch (fsync_type)
{
case EXTERNAL_FSYNC:
err = owl_external_fsync();
if (err)
pr_err("%s: Failed to set external fsync for OWLs!! err = %d\n", __func__,err);
err = hawk_external_fsync();
if (err)
pr_err("%s: Failed to set external fsync for HAWKS!! err = %d\n", __func__,err);
break;
case INTERNAL_FSYNC:
err = owl_internal_fsync();
if (err)
pr_err("%s: Failed to set internal fsync for OWLs!! err = %d\n", __func__,err);
err = hawk_internal_fsync();
if (err)
pr_err("%s: Failed to set internal fsync for HAWKS!! err = %d\n", __func__,err);
break;
default:
pr_err("%s: not supported fsync_type = %d\n", __func__, fsync_type);
break;
}
return err;
}
EXPORT_SYMBOL(Hawk_Owl_Fsync_program);
static int ar0234_hawk_owl_deser_ser_program(struct ar0234 *priv)
{
int err = 0;
static int hawk_flag = 0, owl_flag = 0;
struct camera_common_data *s_data = priv->s_data;
struct device *dev = s_data->dev;
if(ar0234_hawk_link_check(priv) == 4) {
if ((1 == priv->channel) && (!owl_flag)) {
err = ar0234_write_table(priv, mode_table[AR0234_MODE_OWL_QUADLINK_DSER_SER]);
if (err)
dev_err(dev,"%s: Failed to do OWL mode table..\n",__func__);
else
dev_info(dev,"%s: Successfully done OWL mode table ..\n",__func__);
owl_flag++;
owl_links = QUAD_LINK;
}
if ((!priv->channel) && !hawk_flag) {
err = ar0234_write_table(priv, mode_table[AR0234_MODE_HAWK_QUADLINK_DSER_SER]);
if (err)
dev_err(dev,"%s: Failed to do Hawk mode table..\n",__func__);
else
dev_info(dev,"%s: Successfully done Hawk mode table ..\n",__func__);
hawk_flag++;
hawk_links = QUAD_LINK;
}
} else if(ar0234_hawk_link_check(priv) == 3) {
if ((1 == priv->channel) && (!owl_flag)) {
err = ar0234_write_table(priv, mode_table[AR0234_MODE_OWL_TRIPLELINK_DSER_SER]);
if (err)
dev_err(dev,"%s: Failed to do OWL mode table..\n",__func__);
else
dev_info(dev,"%s: Successfully done OWL mode table ..\n",__func__);
owl_flag++;
owl_links = TRIPLE_LINK;
}
if ((!priv->channel) && !hawk_flag) {
err = ar0234_write_table(priv, mode_table[AR0234_MODE_HAWK_TRIPLELINK_DSER_SER]);
if (err)
dev_err(dev,"%s: Failed to do Hawk mode table..\n",__func__);
else
dev_info(dev,"%s: Successfully done Hawk mode table ..\n",__func__);
hawk_flag++;
hawk_links = TRIPLE_LINK;
}
} else if(ar0234_hawk_link_check(priv) == 2) {
if ((1 == priv->channel) && (!owl_flag)) {
err = ar0234_write_table(priv, mode_table[AR0234_MODE_OWL_DUALLINK_DSER_SER]);
if (err)
dev_err(dev,"%s: Failed to do OWL mode table..\n",__func__);
else
dev_info(dev,"%s: Successfully done OWL mode table ..\n",__func__);
owl_flag++;
owl_links = DUAL_LINK;
}
if ((!priv->channel) && !hawk_flag) {
err = ar0234_write_table(priv, mode_table[AR0234_MODE_HAWK_DUALLINK_DSER_SER]);
if (err)
dev_err(dev,"%s: Failed to do Hawk mode table..\n",__func__);
else
dev_info(dev,"%s: Successfully done Hawk mode table ..\n",__func__);
hawk_flag++;
hawk_links = DUAL_LINK;
}
} else if(ar0234_hawk_link_check(priv) == 1) {
if ((1 == priv->channel) && (!owl_flag)) {
err = ar0234_write_table(priv, mode_table[AR0234_MODE_OWL_SINGLELINK_DSER_SER]);
if (err)
dev_err(dev,"%s: Failed to do OWL mode table..\n",__func__);
else
dev_info(dev,"%s: Successfully done OWL mode table ..\n",__func__);
owl_flag++;
owl_links = SINGLE_LINK;
}
if ((!priv->channel) && !hawk_flag) {
err = ar0234_write_table(priv, mode_table[AR0234_MODE_HAWK_SINGLELINK_DSER_SER]);
if (err)
dev_err(dev,"%s: Failed to do Hawk mode table..\n",__func__);
else
dev_info(dev,"%s: Successfully done Hawk mode table ..\n",__func__);
hawk_flag++;
hawk_links = SINGLE_LINK;
}
}
return err;
}
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
static int ar0234_probe(struct i2c_client *client)
#else
static int ar0234_probe(struct i2c_client *client,
const struct i2c_device_id *id)
#endif
{
struct device *dev = &client->dev;
struct device_node *node = dev->of_node;
struct tegracam_device *tc_dev;
struct ar0234 *priv;
const char *str;
int err;
dev_info(dev, "probing v4l2 sensor.\n");
if (!IS_ENABLED(CONFIG_OF) || !node)
return -EINVAL;
priv = devm_kzalloc(dev, sizeof(struct ar0234), GFP_KERNEL);
if (!priv) {
dev_err(dev, "unable to allocate memory!\n");
return -ENOMEM;
}
tc_dev = devm_kzalloc(dev,
sizeof(struct tegracam_device), GFP_KERNEL);
if (!tc_dev)
return -ENOMEM;
err = of_property_read_string(node, "channel", &str);
if (err)
dev_err(dev, "channel not found\n");
priv->channel = str[0] - 'a';
dev_info(dev, "%s: channel %d\n", __func__, priv->channel);
err = of_property_read_string(node, "sync_sensor", &priv->sensor_name);
if (err)
dev_err(dev, "sync_sensor not found\n");
dev_info(dev,"%s: sync_sensor = %s \n", __func__, priv->sensor_name);
err = of_property_read_u32(node, "sync_sensor_index",
&priv->sync_sensor_index);
if (err)
dev_err(dev, "sync name index not in DT\n");
priv->i2c_client = tc_dev->client = client;
tc_dev->dev = dev;
strncpy(tc_dev->name, "ar0234", sizeof(tc_dev->name));
tc_dev->dev_regmap_config = &sensor_regmap_config;
tc_dev->sensor_ops = &ar0234_common_ops;
tc_dev->v4l2sd_internal_ops = &ar0234_subdev_internal_ops;
tc_dev->tcctrl_ops = &ar0234_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);
/* Serializer i2c address trans */
err = hawk_owl_ser_i2c_trans(tc_dev->s_data);
if (err) {
dev_err(&client->dev,"Failed to enable gpio/ to do serializer i2c address trans\n");
goto un_register;
}
err = ar0234_power_on(tc_dev->s_data);
if (err) {
dev_err(&client->dev,"Failed to power on\n");
goto un_register;
}
msleep(100);
err = ar0234_write_table(priv, mode_table[AR0234_MODE_STOP_STREAM]);
if (err) {
dev_err(&client->dev,"ar0234 detect error\n");
goto un_register;
}
msleep(100);
/* Deser/ser programming */
err = ar0234_hawk_owl_deser_ser_program(priv);
if (err) {
dev_err(&client->dev,"Failed to program deser/ser\n");
goto un_register;
}
/* i2c address trans for EEPROM access */
err = ar0234_hawk_owl_EEPROM_address_trans(priv);
if (err) {
dev_err(&client->dev,"Failed to do EEPROM i2c address trans\n");
goto un_register;
}
err = ar0234_board_setup(priv);
if (err) {
dev_err(dev, "board setup failed\n");
goto release_eeprom;
}
/* Un-register i2c client for EEPROM,
* so we can re-use i2c address for 2nd sensor of HAWK module */
ar0234_eeprom_device_release(priv);
/* re-i2c address trans for Hawk & Owl sensors */
err = ar0234_hawk_owl_i2ctrans(priv);
if (err) {
dev_err(dev, "failed to do re-i2c address translation\n");
goto un_register;
}
/* Set Internal fsync as default mode */
err = Hawk_Owl_Fsync_program(INTERNAL_FSYNC);
if (err) {
dev_err(dev, "Failed to set Internal Fsync !!\n");
}
/* Fix-me: This change is temp fix.*/
/* Once other modes are added will move back to set_mode call */
/* Write sensor mode table */
err = ar0234_write_table(priv, mode_table[0]);
if (err)
dev_err(dev, "Failed to write mode table\n");
err = tegracam_v4l2subdev_register(tc_dev, true);
if (err) {
dev_err(dev, "tegra camera subdev registration failed\n");
goto un_register;
}
dev_err(&client->dev, "Detected AR0234 sensor\n");
return 0;
release_eeprom:
ar0234_eeprom_device_release(priv);
un_register:
tegracam_device_unregister(tc_dev);
return err;
}
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
static int ar0234_remove(struct i2c_client *client)
#else
static void ar0234_remove(struct i2c_client *client)
#endif
{
struct camera_common_data *s_data = to_camera_common_data(&client->dev);
struct ar0234 *priv = (struct ar0234 *)s_data->priv;
if (!s_data)
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
return -EINVAL;
#else
return;
#endif
tegracam_v4l2subdev_unregister(priv->tc_dev);
tegracam_device_unregister(priv->tc_dev);
ar0234_eeprom_device_release(priv);
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
return 0;
#endif
}
static const struct i2c_device_id ar0234_id[] = {
{ "ar0234", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ar0234_id);
static struct i2c_driver ar0234_i2c_driver = {
.driver = {
.name = "ar0234",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(ar0234_of_match),
},
.probe = ar0234_probe,
.remove = ar0234_remove,
.id_table = ar0234_id,
};
module_i2c_driver(ar0234_i2c_driver);
MODULE_DESCRIPTION("Media Controller driver for Sony AR0234");
MODULE_AUTHOR("NVIDIA Corporation");
MODULE_AUTHOR("Praveen AC <pac@nvidia.com");
MODULE_LICENSE("GPL v2");