.. | .. |
---|
9 | 9 | * V0.0X01.0X03 fix gain range. |
---|
10 | 10 | * V0.0X01.0X04 add enum_frame_interval function. |
---|
11 | 11 | * V0.0X01.0X05 add quick stream on/off |
---|
| 12 | + * V0.0X01.0X06 support thunder boot function. |
---|
12 | 13 | */ |
---|
13 | 14 | |
---|
14 | 15 | #include <linux/clk.h> |
---|
.. | .. |
---|
31 | 32 | #include <media/v4l2-ctrls.h> |
---|
32 | 33 | #include <media/v4l2-subdev.h> |
---|
33 | 34 | #include <linux/pinctrl/consumer.h> |
---|
| 35 | +#include "../platform/rockchip/isp/rkisp_tb_helper.h" |
---|
34 | 36 | |
---|
35 | | -#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x05) |
---|
| 37 | +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x06) |
---|
36 | 38 | |
---|
37 | 39 | #ifndef V4L2_CID_DIGITAL_GAIN |
---|
38 | 40 | #define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN |
---|
.. | .. |
---|
173 | 175 | const char *module_name; |
---|
174 | 176 | const char *len_name; |
---|
175 | 177 | u32 cur_vts; |
---|
| 178 | + bool is_thunderboot; |
---|
| 179 | + bool is_first_streamoff; |
---|
176 | 180 | struct preisp_hdrae_exp_s init_hdrae_exp; |
---|
177 | 181 | }; |
---|
178 | 182 | |
---|
.. | .. |
---|
447 | 451 | SC401AI_LINK_FREQ_630, |
---|
448 | 452 | }; |
---|
449 | 453 | |
---|
| 454 | +static int __sc401ai_power_on(struct sc401ai *sc401ai); |
---|
| 455 | + |
---|
450 | 456 | /* Write registers up to 4 at a time */ |
---|
451 | 457 | static int sc401ai_write_reg(struct i2c_client *client, u16 reg, |
---|
452 | 458 | u32 len, u32 val) |
---|
.. | .. |
---|
623 | 629 | else |
---|
624 | 630 | DIG_Fine_gain_reg = abs(800 * gain / (Dcg_gainx100 * Coarse_gain * |
---|
625 | 631 | DIG_gain) / ANA_Fine_gainx64); |
---|
| 632 | + |
---|
| 633 | + if (sc401ai->is_thunderboot && rkisp_tb_get_state() == RKISP_TB_NG) { |
---|
| 634 | + sc401ai->is_thunderboot = false; |
---|
| 635 | + __sc401ai_power_on(sc401ai); |
---|
| 636 | + } |
---|
626 | 637 | |
---|
627 | 638 | ret = sc401ai_write_reg(sc401ai->client, |
---|
628 | 639 | SC401AI_REG_DIG_GAIN, |
---|
.. | .. |
---|
989 | 1000 | { |
---|
990 | 1001 | int ret; |
---|
991 | 1002 | |
---|
992 | | - ret = sc401ai_write_array(sc401ai->client, sc401ai->cur_mode->reg_list); |
---|
993 | | - if (ret) |
---|
994 | | - return ret; |
---|
| 1003 | + if (!sc401ai->is_thunderboot) { |
---|
| 1004 | + ret = sc401ai_write_array(sc401ai->client, sc401ai->cur_mode->reg_list); |
---|
| 1005 | + if (ret) |
---|
| 1006 | + return ret; |
---|
995 | 1007 | |
---|
996 | | - /* In case these controls are set before streaming */ |
---|
997 | | - ret = __v4l2_ctrl_handler_setup(&sc401ai->ctrl_handler); |
---|
998 | | - if (ret) |
---|
999 | | - return ret; |
---|
| 1008 | + /* In case these controls are set before streaming */ |
---|
| 1009 | + ret = __v4l2_ctrl_handler_setup(&sc401ai->ctrl_handler); |
---|
| 1010 | + if (ret) |
---|
| 1011 | + return ret; |
---|
| 1012 | + } |
---|
1000 | 1013 | |
---|
1001 | 1014 | return sc401ai_write_reg(sc401ai->client, |
---|
1002 | | - SC401AI_REG_CTRL_MODE, |
---|
1003 | | - SC401AI_REG_VALUE_08BIT, |
---|
1004 | | - SC401AI_MODE_STREAMING); |
---|
| 1015 | + SC401AI_REG_CTRL_MODE, |
---|
| 1016 | + SC401AI_REG_VALUE_08BIT, |
---|
| 1017 | + SC401AI_MODE_STREAMING); |
---|
| 1018 | + |
---|
1005 | 1019 | } |
---|
1006 | 1020 | |
---|
1007 | 1021 | static int __sc401ai_stop_stream(struct sc401ai *sc401ai) |
---|
1008 | 1022 | { |
---|
| 1023 | + if (sc401ai->is_thunderboot) { |
---|
| 1024 | + sc401ai->is_first_streamoff = true; |
---|
| 1025 | + pm_runtime_put(&sc401ai->client->dev); |
---|
| 1026 | + } |
---|
| 1027 | + |
---|
1009 | 1028 | return sc401ai_write_reg(sc401ai->client, |
---|
1010 | 1029 | SC401AI_REG_CTRL_MODE, |
---|
1011 | 1030 | SC401AI_REG_VALUE_08BIT, |
---|
.. | .. |
---|
1024 | 1043 | goto unlock_and_return; |
---|
1025 | 1044 | |
---|
1026 | 1045 | if (on) { |
---|
| 1046 | + if (sc401ai->is_thunderboot && rkisp_tb_get_state() == RKISP_TB_NG) { |
---|
| 1047 | + sc401ai->is_thunderboot = false; |
---|
| 1048 | + __sc401ai_power_on(sc401ai); |
---|
| 1049 | + } |
---|
1027 | 1050 | ret = pm_runtime_get_sync(&client->dev); |
---|
1028 | 1051 | if (ret < 0) { |
---|
1029 | 1052 | pm_runtime_put_noidle(&client->dev); |
---|
.. | .. |
---|
1115 | 1138 | dev_err(dev, "Failed to enable xvclk\n"); |
---|
1116 | 1139 | return ret; |
---|
1117 | 1140 | } |
---|
| 1141 | + |
---|
| 1142 | + if (sc401ai->is_thunderboot) |
---|
| 1143 | + return 0; |
---|
| 1144 | + |
---|
1118 | 1145 | if (!IS_ERR(sc401ai->reset_gpio)) |
---|
1119 | 1146 | gpiod_set_value_cansleep(sc401ai->reset_gpio, 0); |
---|
1120 | 1147 | |
---|
.. | .. |
---|
1152 | 1179 | { |
---|
1153 | 1180 | int ret; |
---|
1154 | 1181 | struct device *dev = &sc401ai->client->dev; |
---|
| 1182 | + |
---|
| 1183 | + if (sc401ai->is_thunderboot) { |
---|
| 1184 | + if (sc401ai->is_first_streamoff) { |
---|
| 1185 | + sc401ai->is_thunderboot = false; |
---|
| 1186 | + sc401ai->is_first_streamoff = false; |
---|
| 1187 | + } else { |
---|
| 1188 | + return; |
---|
| 1189 | + } |
---|
| 1190 | + } |
---|
1155 | 1191 | |
---|
1156 | 1192 | if (!IS_ERR(sc401ai->pwdn_gpio)) |
---|
1157 | 1193 | gpiod_set_value_cansleep(sc401ai->pwdn_gpio, 0); |
---|
.. | .. |
---|
1491 | 1527 | u32 id = 0; |
---|
1492 | 1528 | int ret; |
---|
1493 | 1529 | |
---|
| 1530 | + if (sc401ai->is_thunderboot) { |
---|
| 1531 | + dev_info(dev, "Enable thunderboot mode, skip sensor id check\n"); |
---|
| 1532 | + return 0; |
---|
| 1533 | + } |
---|
| 1534 | + |
---|
1494 | 1535 | ret = sc401ai_read_reg(client, SC401AI_REG_CHIP_ID, |
---|
1495 | 1536 | SC401AI_REG_VALUE_16BIT, &id); |
---|
1496 | 1537 | if (id != CHIP_ID) { |
---|
.. | .. |
---|
1549 | 1590 | return -EINVAL; |
---|
1550 | 1591 | } |
---|
1551 | 1592 | |
---|
| 1593 | + sc401ai->is_thunderboot = IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP); |
---|
| 1594 | + |
---|
1552 | 1595 | sc401ai->client = client; |
---|
1553 | 1596 | for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { |
---|
1554 | 1597 | if (hdr_mode == supported_modes[i].hdr_mode) { |
---|
.. | .. |
---|
1565 | 1608 | return -EINVAL; |
---|
1566 | 1609 | } |
---|
1567 | 1610 | |
---|
1568 | | - sc401ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); |
---|
1569 | | - if (IS_ERR(sc401ai->reset_gpio)) |
---|
1570 | | - dev_warn(dev, "Failed to get reset-gpios\n"); |
---|
| 1611 | + if (sc401ai->is_thunderboot) { |
---|
| 1612 | + sc401ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS); |
---|
| 1613 | + if (IS_ERR(sc401ai->reset_gpio)) |
---|
| 1614 | + dev_warn(dev, "Failed to get reset-gpios\n"); |
---|
1571 | 1615 | |
---|
1572 | | - sc401ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW); |
---|
1573 | | - if (IS_ERR(sc401ai->pwdn_gpio)) |
---|
1574 | | - dev_warn(dev, "Failed to get pwdn-gpios\n"); |
---|
| 1616 | + sc401ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_ASIS); |
---|
| 1617 | + if (IS_ERR(sc401ai->pwdn_gpio)) |
---|
| 1618 | + dev_warn(dev, "Failed to get pwdn-gpios\n"); |
---|
| 1619 | + } else { |
---|
| 1620 | + sc401ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); |
---|
| 1621 | + if (IS_ERR(sc401ai->reset_gpio)) |
---|
| 1622 | + dev_warn(dev, "Failed to get reset-gpios\n"); |
---|
| 1623 | + |
---|
| 1624 | + sc401ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW); |
---|
| 1625 | + if (IS_ERR(sc401ai->pwdn_gpio)) |
---|
| 1626 | + dev_warn(dev, "Failed to get pwdn-gpios\n"); |
---|
| 1627 | + } |
---|
1575 | 1628 | |
---|
1576 | 1629 | sc401ai->pinctrl = devm_pinctrl_get(dev); |
---|
1577 | 1630 | if (!IS_ERR(sc401ai->pinctrl)) { |
---|
.. | .. |
---|
1646 | 1699 | |
---|
1647 | 1700 | pm_runtime_set_active(dev); |
---|
1648 | 1701 | pm_runtime_enable(dev); |
---|
1649 | | - pm_runtime_idle(dev); |
---|
| 1702 | + if (sc401ai->is_thunderboot) |
---|
| 1703 | + pm_runtime_get_sync(dev); |
---|
| 1704 | + else |
---|
| 1705 | + pm_runtime_idle(dev); |
---|
1650 | 1706 | |
---|
1651 | 1707 | return 0; |
---|
1652 | 1708 | |
---|
.. | .. |
---|
1718 | 1774 | i2c_del_driver(&sc401ai_i2c_driver); |
---|
1719 | 1775 | } |
---|
1720 | 1776 | |
---|
| 1777 | +#if defined(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP) && !defined(CONFIG_INITCALL_ASYNC) |
---|
| 1778 | +subsys_initcall(sensor_mod_init); |
---|
| 1779 | +#else |
---|
1721 | 1780 | device_initcall_sync(sensor_mod_init); |
---|
| 1781 | +#endif |
---|
| 1782 | + |
---|
1722 | 1783 | module_exit(sensor_mod_exit); |
---|
1723 | 1784 | |
---|
1724 | 1785 | MODULE_DESCRIPTION("smartsens sc401ai sensor driver"); |
---|