I’d like to control reset pin and mclk of CAM1.
I have a pcb board that can contect two modules at once but the types of each module are different.
CAM0 has 2 CSI Lane and CAM1 has 4 CSI Lane.
First of all, I want to test each of them seperately.
When I’ve tested CAM0 side, it’ok but I can’t control CAM1.
CAM0 is ok so I want to test CAM1 without CAM0.
After I will confirm that CAM1 is ok, I’m going to try to controll all of them.
I modified source code and device-tree as below.
Device-tree :
#define CAM1_RST_L TEGRA_MAIN_GPIO(R, 1)
#define CAM1_PWDN TEGRA_MAIN_GPIO(L, 6)
/ {
i2c@3180000 {
s5k4hayx_e@2d {
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 CAM1_RST_L GPIO_ACTIVE_HIGH>;
pwdn-gpios = <&tegra_main_gpio CAM1_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;Device-tree is below :
output-low;
gpios = <CAM1_RST_L 0 CAM1_PWDN 0>;
label = "cam1-rst", "cam1-pwdn";
};
};
};
source code :
static struct camera_common_pdata *s5k4hayx_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;
if (!node)
return NULL;
match = of_match_device(s5k4hayx_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;
}
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;
}
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;
}
// 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");
return board_priv_pdata;
error:
devm_kfree(dev, board_priv_pdata);
return ret;
}
static int s5k4hayx_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;
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) {
printk(KERN_DEBUG "pdata->use_cam_gpio : true\n");
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;
return err;
}
Please let me know what is wrong or missing.
Thanks.