media: i2c: sc401ai: add support thunder boot
Signed-off-by: LongChang Ma <chad.ma@rock-chips.com> Change-Id: I1608a9341ddc772aaa72002e1b9c7361235908c0
This commit is contained in:
+79
-18
@@ -9,6 +9,7 @@
|
||||
* V0.0X01.0X03 fix gain range.
|
||||
* V0.0X01.0X04 add enum_frame_interval function.
|
||||
* V0.0X01.0X05 add quick stream on/off
|
||||
* V0.0X01.0X06 support thunder boot function.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
@@ -31,8 +32,9 @@
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include "../platform/rockchip/isp/rkisp_tb_helper.h"
|
||||
|
||||
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x05)
|
||||
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x06)
|
||||
|
||||
#ifndef V4L2_CID_DIGITAL_GAIN
|
||||
#define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN
|
||||
@@ -173,6 +175,8 @@ struct sc401ai {
|
||||
const char *module_name;
|
||||
const char *len_name;
|
||||
u32 cur_vts;
|
||||
bool is_thunderboot;
|
||||
bool is_first_streamoff;
|
||||
struct preisp_hdrae_exp_s init_hdrae_exp;
|
||||
};
|
||||
|
||||
@@ -447,6 +451,8 @@ static const s64 link_freq_menu_items[] = {
|
||||
SC401AI_LINK_FREQ_630,
|
||||
};
|
||||
|
||||
static int __sc401ai_power_on(struct sc401ai *sc401ai);
|
||||
|
||||
/* Write registers up to 4 at a time */
|
||||
static int sc401ai_write_reg(struct i2c_client *client, u16 reg,
|
||||
u32 len, u32 val)
|
||||
@@ -624,6 +630,11 @@ static int sc401ai_set_gain_reg(struct sc401ai *sc401ai, u32 gain)
|
||||
DIG_Fine_gain_reg = abs(800 * gain / (Dcg_gainx100 * Coarse_gain *
|
||||
DIG_gain) / ANA_Fine_gainx64);
|
||||
|
||||
if (sc401ai->is_thunderboot && rkisp_tb_get_state() == RKISP_TB_NG) {
|
||||
sc401ai->is_thunderboot = false;
|
||||
__sc401ai_power_on(sc401ai);
|
||||
}
|
||||
|
||||
ret = sc401ai_write_reg(sc401ai->client,
|
||||
SC401AI_REG_DIG_GAIN,
|
||||
SC401AI_REG_VALUE_08BIT,
|
||||
@@ -989,23 +1000,31 @@ static int __sc401ai_start_stream(struct sc401ai *sc401ai)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sc401ai_write_array(sc401ai->client, sc401ai->cur_mode->reg_list);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!sc401ai->is_thunderboot) {
|
||||
ret = sc401ai_write_array(sc401ai->client, sc401ai->cur_mode->reg_list);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* In case these controls are set before streaming */
|
||||
ret = __v4l2_ctrl_handler_setup(&sc401ai->ctrl_handler);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* In case these controls are set before streaming */
|
||||
ret = __v4l2_ctrl_handler_setup(&sc401ai->ctrl_handler);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return sc401ai_write_reg(sc401ai->client,
|
||||
SC401AI_REG_CTRL_MODE,
|
||||
SC401AI_REG_VALUE_08BIT,
|
||||
SC401AI_MODE_STREAMING);
|
||||
SC401AI_REG_CTRL_MODE,
|
||||
SC401AI_REG_VALUE_08BIT,
|
||||
SC401AI_MODE_STREAMING);
|
||||
|
||||
}
|
||||
|
||||
static int __sc401ai_stop_stream(struct sc401ai *sc401ai)
|
||||
{
|
||||
if (sc401ai->is_thunderboot) {
|
||||
sc401ai->is_first_streamoff = true;
|
||||
pm_runtime_put(&sc401ai->client->dev);
|
||||
}
|
||||
|
||||
return sc401ai_write_reg(sc401ai->client,
|
||||
SC401AI_REG_CTRL_MODE,
|
||||
SC401AI_REG_VALUE_08BIT,
|
||||
@@ -1024,6 +1043,10 @@ static int sc401ai_s_stream(struct v4l2_subdev *sd, int on)
|
||||
goto unlock_and_return;
|
||||
|
||||
if (on) {
|
||||
if (sc401ai->is_thunderboot && rkisp_tb_get_state() == RKISP_TB_NG) {
|
||||
sc401ai->is_thunderboot = false;
|
||||
__sc401ai_power_on(sc401ai);
|
||||
}
|
||||
ret = pm_runtime_get_sync(&client->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
@@ -1115,6 +1138,10 @@ static int __sc401ai_power_on(struct sc401ai *sc401ai)
|
||||
dev_err(dev, "Failed to enable xvclk\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (sc401ai->is_thunderboot)
|
||||
return 0;
|
||||
|
||||
if (!IS_ERR(sc401ai->reset_gpio))
|
||||
gpiod_set_value_cansleep(sc401ai->reset_gpio, 0);
|
||||
|
||||
@@ -1153,6 +1180,15 @@ static void __sc401ai_power_off(struct sc401ai *sc401ai)
|
||||
int ret;
|
||||
struct device *dev = &sc401ai->client->dev;
|
||||
|
||||
if (sc401ai->is_thunderboot) {
|
||||
if (sc401ai->is_first_streamoff) {
|
||||
sc401ai->is_thunderboot = false;
|
||||
sc401ai->is_first_streamoff = false;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!IS_ERR(sc401ai->pwdn_gpio))
|
||||
gpiod_set_value_cansleep(sc401ai->pwdn_gpio, 0);
|
||||
clk_disable_unprepare(sc401ai->xvclk);
|
||||
@@ -1491,6 +1527,11 @@ static int sc401ai_check_sensor_id(struct sc401ai *sc401ai,
|
||||
u32 id = 0;
|
||||
int ret;
|
||||
|
||||
if (sc401ai->is_thunderboot) {
|
||||
dev_info(dev, "Enable thunderboot mode, skip sensor id check\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = sc401ai_read_reg(client, SC401AI_REG_CHIP_ID,
|
||||
SC401AI_REG_VALUE_16BIT, &id);
|
||||
if (id != CHIP_ID) {
|
||||
@@ -1549,6 +1590,8 @@ static int sc401ai_probe(struct i2c_client *client,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sc401ai->is_thunderboot = IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP);
|
||||
|
||||
sc401ai->client = client;
|
||||
for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
|
||||
if (hdr_mode == supported_modes[i].hdr_mode) {
|
||||
@@ -1565,13 +1608,23 @@ static int sc401ai_probe(struct i2c_client *client,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sc401ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(sc401ai->reset_gpio))
|
||||
dev_warn(dev, "Failed to get reset-gpios\n");
|
||||
if (sc401ai->is_thunderboot) {
|
||||
sc401ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS);
|
||||
if (IS_ERR(sc401ai->reset_gpio))
|
||||
dev_warn(dev, "Failed to get reset-gpios\n");
|
||||
|
||||
sc401ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(sc401ai->pwdn_gpio))
|
||||
dev_warn(dev, "Failed to get pwdn-gpios\n");
|
||||
sc401ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_ASIS);
|
||||
if (IS_ERR(sc401ai->pwdn_gpio))
|
||||
dev_warn(dev, "Failed to get pwdn-gpios\n");
|
||||
} else {
|
||||
sc401ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(sc401ai->reset_gpio))
|
||||
dev_warn(dev, "Failed to get reset-gpios\n");
|
||||
|
||||
sc401ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(sc401ai->pwdn_gpio))
|
||||
dev_warn(dev, "Failed to get pwdn-gpios\n");
|
||||
}
|
||||
|
||||
sc401ai->pinctrl = devm_pinctrl_get(dev);
|
||||
if (!IS_ERR(sc401ai->pinctrl)) {
|
||||
@@ -1646,7 +1699,10 @@ static int sc401ai_probe(struct i2c_client *client,
|
||||
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_idle(dev);
|
||||
if (sc401ai->is_thunderboot)
|
||||
pm_runtime_get_sync(dev);
|
||||
else
|
||||
pm_runtime_idle(dev);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1718,7 +1774,12 @@ static void __exit sensor_mod_exit(void)
|
||||
i2c_del_driver(&sc401ai_i2c_driver);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP) && !defined(CONFIG_INITCALL_ASYNC)
|
||||
subsys_initcall(sensor_mod_init);
|
||||
#else
|
||||
device_initcall_sync(sensor_mod_init);
|
||||
#endif
|
||||
|
||||
module_exit(sensor_mod_exit);
|
||||
|
||||
MODULE_DESCRIPTION("smartsens sc401ai sensor driver");
|
||||
|
||||
Reference in New Issue
Block a user