| .. | .. |
|---|
| 11 | 11 | * V0.0X01.0X05 add quick stream on/off. |
|---|
| 12 | 12 | * V0.0X01.0X06 fix set vflip/hflip failed bug. |
|---|
| 13 | 13 | * V0.0X01.0X07 |
|---|
| 14 | | - * 1. fix set double times exposue value failed issue. |
|---|
| 15 | | - * 2. add some debug info. |
|---|
| 14 | + * 1. fix set double times exposue value failed issue. |
|---|
| 15 | + * 2. add some debug info. |
|---|
| 16 | + * V0.0X01.0X08 |
|---|
| 17 | + * 1. add support wakeup & sleep for aov function |
|---|
| 18 | + * 2. using 60fps output default |
|---|
| 16 | 19 | */ |
|---|
| 17 | 20 | |
|---|
| 18 | 21 | #include <linux/clk.h> |
|---|
| .. | .. |
|---|
| 34 | 37 | #include <media/v4l2-subdev.h> |
|---|
| 35 | 38 | #include <linux/pinctrl/consumer.h> |
|---|
| 36 | 39 | #include "../platform/rockchip/isp/rkisp_tb_helper.h" |
|---|
| 40 | +#include "cam-tb-setup.h" |
|---|
| 41 | +#include "cam-sleep-wakeup.h" |
|---|
| 37 | 42 | |
|---|
| 38 | | -#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x07) |
|---|
| 43 | +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x08) |
|---|
| 39 | 44 | |
|---|
| 40 | 45 | #ifndef V4L2_CID_DIGITAL_GAIN |
|---|
| 41 | 46 | #define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN |
|---|
| .. | .. |
|---|
| 179 | 184 | bool is_thunderboot; |
|---|
| 180 | 185 | bool is_first_streamoff; |
|---|
| 181 | 186 | struct preisp_hdrae_exp_s init_hdrae_exp; |
|---|
| 187 | + struct cam_sw_info *cam_sw_inf; |
|---|
| 182 | 188 | }; |
|---|
| 183 | 189 | |
|---|
| 184 | 190 | #define to_sc200ai(sd) container_of(sd, struct sc200ai, subdev) |
|---|
| .. | .. |
|---|
| 611 | 617 | .height = 1080, |
|---|
| 612 | 618 | .max_fps = { |
|---|
| 613 | 619 | .numerator = 10000, |
|---|
| 614 | | - .denominator = 300000, |
|---|
| 615 | | - }, |
|---|
| 616 | | - .exp_def = 0x0080, |
|---|
| 617 | | - .hts_def = 0x44C * 2, |
|---|
| 618 | | - .vts_def = 0x0465, |
|---|
| 619 | | - .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, |
|---|
| 620 | | - .reg_list = sc200ai_linear_10_1920x1080_30fps_regs, |
|---|
| 621 | | - .hdr_mode = NO_HDR, |
|---|
| 622 | | - .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, |
|---|
| 623 | | - }, { |
|---|
| 624 | | - .width = 1920, |
|---|
| 625 | | - .height = 1080, |
|---|
| 626 | | - .max_fps = { |
|---|
| 627 | | - .numerator = 10000, |
|---|
| 628 | 620 | .denominator = 600000, |
|---|
| 629 | 621 | }, |
|---|
| 630 | 622 | .exp_def = 0x0080, |
|---|
| .. | .. |
|---|
| 634 | 626 | .reg_list = sc200ai_linear_10_1920x1080_60fps_regs, |
|---|
| 635 | 627 | .hdr_mode = NO_HDR, |
|---|
| 636 | 628 | .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, |
|---|
| 637 | | - }, { |
|---|
| 629 | + }, |
|---|
| 630 | + { |
|---|
| 631 | + .width = 1920, |
|---|
| 632 | + .height = 1080, |
|---|
| 633 | + .max_fps = { |
|---|
| 634 | + .numerator = 10000, |
|---|
| 635 | + .denominator = 300000, |
|---|
| 636 | + }, |
|---|
| 637 | + .exp_def = 0x0080, |
|---|
| 638 | + .hts_def = 0x44C * 2, |
|---|
| 639 | + .vts_def = 0x0465, |
|---|
| 640 | + .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, |
|---|
| 641 | + .reg_list = sc200ai_linear_10_1920x1080_30fps_regs, |
|---|
| 642 | + .hdr_mode = NO_HDR, |
|---|
| 643 | + .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, |
|---|
| 644 | + }, |
|---|
| 645 | + { |
|---|
| 638 | 646 | .width = 1920, |
|---|
| 639 | 647 | .height = 1080, |
|---|
| 640 | 648 | .max_fps = { |
|---|
| .. | .. |
|---|
| 1215 | 1223 | break; |
|---|
| 1216 | 1224 | case PREISP_CMD_SET_HDRAE_EXP: |
|---|
| 1217 | 1225 | sc200ai_set_hdrae(sc200ai, arg); |
|---|
| 1226 | + if (sc200ai->cam_sw_inf) |
|---|
| 1227 | + memcpy(&sc200ai->cam_sw_inf->hdr_ae, (struct preisp_hdrae_exp_s *)(arg), |
|---|
| 1228 | + sizeof(struct preisp_hdrae_exp_s)); |
|---|
| 1218 | 1229 | break; |
|---|
| 1219 | 1230 | case RKMODULE_SET_QUICK_STREAM: |
|---|
| 1220 | 1231 | |
|---|
| 1221 | 1232 | stream = *((u32 *)arg); |
|---|
| 1222 | 1233 | |
|---|
| 1223 | | - if (stream) |
|---|
| 1234 | + if (stream) { |
|---|
| 1235 | + gpiod_set_value_cansleep(sc200ai->pwdn_gpio, 1); |
|---|
| 1224 | 1236 | ret = sc200ai_write_reg(sc200ai->client, SC200AI_REG_CTRL_MODE, |
|---|
| 1225 | 1237 | SC200AI_REG_VALUE_08BIT, SC200AI_MODE_STREAMING); |
|---|
| 1226 | | - else |
|---|
| 1238 | + } else { |
|---|
| 1227 | 1239 | ret = sc200ai_write_reg(sc200ai->client, SC200AI_REG_CTRL_MODE, |
|---|
| 1228 | 1240 | SC200AI_REG_VALUE_08BIT, SC200AI_MODE_SW_STANDBY); |
|---|
| 1241 | + gpiod_set_value_cansleep(sc200ai->pwdn_gpio, 0); |
|---|
| 1242 | + } |
|---|
| 1229 | 1243 | break; |
|---|
| 1230 | 1244 | case RKMODULE_GET_CHANNEL_INFO: |
|---|
| 1231 | 1245 | ch_info = (struct rkmodule_channel_info *)arg; |
|---|
| .. | .. |
|---|
| 1512 | 1526 | dev_err(dev, "Failed to enable xvclk\n"); |
|---|
| 1513 | 1527 | return ret; |
|---|
| 1514 | 1528 | } |
|---|
| 1529 | + |
|---|
| 1530 | + cam_sw_regulator_bulk_init(sc200ai->cam_sw_inf, SC200AI_NUM_SUPPLIES, sc200ai->supplies); |
|---|
| 1531 | + |
|---|
| 1515 | 1532 | if (sc200ai->is_thunderboot) |
|---|
| 1516 | 1533 | return 0; |
|---|
| 1517 | 1534 | |
|---|
| .. | .. |
|---|
| 1576 | 1593 | regulator_bulk_disable(SC200AI_NUM_SUPPLIES, sc200ai->supplies); |
|---|
| 1577 | 1594 | } |
|---|
| 1578 | 1595 | |
|---|
| 1596 | +#if IS_REACHABLE(CONFIG_VIDEO_CAM_SLEEP_WAKEUP) |
|---|
| 1597 | +static int __maybe_unused sc200ai_resume(struct device *dev) |
|---|
| 1598 | +{ |
|---|
| 1599 | + int ret; |
|---|
| 1600 | + struct i2c_client *client = to_i2c_client(dev); |
|---|
| 1601 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); |
|---|
| 1602 | + struct sc200ai *sc200ai = to_sc200ai(sd); |
|---|
| 1603 | + |
|---|
| 1604 | + cam_sw_prepare_wakeup(sc200ai->cam_sw_inf, dev); |
|---|
| 1605 | + |
|---|
| 1606 | + usleep_range(4000, 5000); |
|---|
| 1607 | + cam_sw_write_array(sc200ai->cam_sw_inf); |
|---|
| 1608 | + |
|---|
| 1609 | + if (__v4l2_ctrl_handler_setup(&sc200ai->ctrl_handler)) |
|---|
| 1610 | + dev_err(dev, "__v4l2_ctrl_handler_setup fail!"); |
|---|
| 1611 | + |
|---|
| 1612 | + if (sc200ai->has_init_exp && sc200ai->cur_mode != NO_HDR) { // hdr mode |
|---|
| 1613 | + ret = sc200ai_ioctl(&sc200ai->subdev, PREISP_CMD_SET_HDRAE_EXP, |
|---|
| 1614 | + &sc200ai->cam_sw_inf->hdr_ae); |
|---|
| 1615 | + if (ret) { |
|---|
| 1616 | + dev_err(&sc200ai->client->dev, "set exp fail in hdr mode\n"); |
|---|
| 1617 | + return ret; |
|---|
| 1618 | + } |
|---|
| 1619 | + } |
|---|
| 1620 | + return 0; |
|---|
| 1621 | +} |
|---|
| 1622 | + |
|---|
| 1623 | +static int __maybe_unused sc200ai_suspend(struct device *dev) |
|---|
| 1624 | +{ |
|---|
| 1625 | + struct i2c_client *client = to_i2c_client(dev); |
|---|
| 1626 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); |
|---|
| 1627 | + struct sc200ai *sc200ai = to_sc200ai(sd); |
|---|
| 1628 | + |
|---|
| 1629 | + cam_sw_write_array_cb_init(sc200ai->cam_sw_inf, client, |
|---|
| 1630 | + (void *)sc200ai->cur_mode->reg_list, |
|---|
| 1631 | + (sensor_write_array)sc200ai_write_array); |
|---|
| 1632 | + cam_sw_prepare_sleep(sc200ai->cam_sw_inf); |
|---|
| 1633 | + |
|---|
| 1634 | + return 0; |
|---|
| 1635 | +} |
|---|
| 1636 | +#else |
|---|
| 1637 | +#define sc200ai_resume NULL |
|---|
| 1638 | +#define sc200ai_suspend NULL |
|---|
| 1639 | +#endif |
|---|
| 1640 | + |
|---|
| 1579 | 1641 | static int sc200ai_runtime_resume(struct device *dev) |
|---|
| 1580 | 1642 | { |
|---|
| 1581 | 1643 | struct i2c_client *client = to_i2c_client(dev); |
|---|
| .. | .. |
|---|
| 1636 | 1698 | static const struct dev_pm_ops sc200ai_pm_ops = { |
|---|
| 1637 | 1699 | SET_RUNTIME_PM_OPS(sc200ai_runtime_suspend, |
|---|
| 1638 | 1700 | sc200ai_runtime_resume, NULL) |
|---|
| 1701 | + SET_LATE_SYSTEM_SLEEP_PM_OPS(sc200ai_suspend, sc200ai_resume) |
|---|
| 1639 | 1702 | }; |
|---|
| 1640 | 1703 | |
|---|
| 1641 | 1704 | #ifdef CONFIG_VIDEO_V4L2_SUBDEV_API |
|---|
| .. | .. |
|---|
| 1744 | 1807 | & 0xff); |
|---|
| 1745 | 1808 | if (!ret) |
|---|
| 1746 | 1809 | sc200ai->cur_vts = ctrl->val + sc200ai->cur_mode->height; |
|---|
| 1747 | | - if (sc200ai->cur_vts != sc200ai->cur_mode->vts_def) |
|---|
| 1748 | | - sc200ai_modify_fps_info(sc200ai); |
|---|
| 1810 | + sc200ai_modify_fps_info(sc200ai); |
|---|
| 1749 | 1811 | break; |
|---|
| 1750 | 1812 | case V4L2_CID_TEST_PATTERN: |
|---|
| 1751 | 1813 | ret = sc200ai_enable_test_pattern(sc200ai, ctrl->val); |
|---|
| .. | .. |
|---|
| 1890 | 1952 | } |
|---|
| 1891 | 1953 | |
|---|
| 1892 | 1954 | #ifdef CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP |
|---|
| 1893 | | -static u32 rk_cam_hdr; |
|---|
| 1894 | | -static u32 rk_cam_w; |
|---|
| 1895 | | -static u32 rk_cam_h; |
|---|
| 1896 | | -static u32 rk_cam_fps; |
|---|
| 1897 | | - |
|---|
| 1898 | | -static int __init __maybe_unused rk_cam_hdr_setup(char *str) |
|---|
| 1899 | | -{ |
|---|
| 1900 | | - int ret = 0; |
|---|
| 1901 | | - unsigned long val = 0; |
|---|
| 1902 | | - |
|---|
| 1903 | | - ret = kstrtoul(str, 0, &val); |
|---|
| 1904 | | - if (!ret) |
|---|
| 1905 | | - rk_cam_hdr = (u32)val; |
|---|
| 1906 | | - else |
|---|
| 1907 | | - pr_err("get rk_cam_hdr fail\n"); |
|---|
| 1908 | | - return 1; |
|---|
| 1909 | | -} |
|---|
| 1910 | | - |
|---|
| 1911 | | -static int __init __maybe_unused rk_cam_w_setup(char *str) |
|---|
| 1912 | | -{ |
|---|
| 1913 | | - int ret = 0; |
|---|
| 1914 | | - unsigned long val = 0; |
|---|
| 1915 | | - |
|---|
| 1916 | | - ret = kstrtoul(str, 0, &val); |
|---|
| 1917 | | - if (!ret) |
|---|
| 1918 | | - rk_cam_w = (u32)val; |
|---|
| 1919 | | - else |
|---|
| 1920 | | - pr_err("get rk_cam_w fail\n"); |
|---|
| 1921 | | - return 1; |
|---|
| 1922 | | -} |
|---|
| 1923 | | - |
|---|
| 1924 | | -static int __init __maybe_unused rk_cam_h_setup(char *str) |
|---|
| 1925 | | -{ |
|---|
| 1926 | | - int ret = 0; |
|---|
| 1927 | | - unsigned long val = 0; |
|---|
| 1928 | | - |
|---|
| 1929 | | - ret = kstrtoul(str, 0, &val); |
|---|
| 1930 | | - if (!ret) |
|---|
| 1931 | | - rk_cam_h = (u32)val; |
|---|
| 1932 | | - else |
|---|
| 1933 | | - pr_err("get rk_cam_h fail\n"); |
|---|
| 1934 | | - return 1; |
|---|
| 1935 | | -} |
|---|
| 1936 | | - |
|---|
| 1937 | | -static int __init __maybe_unused rk_cam_fps_setup(char *str) |
|---|
| 1938 | | -{ |
|---|
| 1939 | | - int ret = 0; |
|---|
| 1940 | | - unsigned long val = 0; |
|---|
| 1941 | | - |
|---|
| 1942 | | - ret = kstrtoul(str, 0, &val); |
|---|
| 1943 | | - if (!ret) |
|---|
| 1944 | | - rk_cam_fps = (u32)val; |
|---|
| 1945 | | - else |
|---|
| 1946 | | - pr_err("get rk_cam_fps fail\n"); |
|---|
| 1947 | | - return 1; |
|---|
| 1948 | | -} |
|---|
| 1949 | | - |
|---|
| 1950 | | -__setup("rk_cam_hdr=", rk_cam_hdr_setup); |
|---|
| 1951 | | -__setup("rk_cam_w=", rk_cam_w_setup); |
|---|
| 1952 | | -__setup("rk_cam_h=", rk_cam_h_setup); |
|---|
| 1953 | | -__setup("rk_cam_fps=", rk_cam_fps_setup); |
|---|
| 1954 | | - |
|---|
| 1955 | 1955 | static void find_terminal_resolution(struct sc200ai *sc200ai) |
|---|
| 1956 | 1956 | { |
|---|
| 1957 | 1957 | int i = 0; |
|---|
| 1958 | 1958 | const struct sc200ai_mode *mode = NULL; |
|---|
| 1959 | | - const struct sc200ai_mode *fit_mode = NULL; |
|---|
| 1960 | | - u32 cur_fps = 0; |
|---|
| 1961 | | - u32 dst_fps = 0; |
|---|
| 1962 | | - u32 tmp_fps = 0; |
|---|
| 1959 | + u32 rk_cam_hdr = get_rk_cam_hdr(); |
|---|
| 1960 | + u32 rk_cam_w = get_rk_cam_w(); |
|---|
| 1961 | + u32 rk_cam_h = get_rk_cam_h(); |
|---|
| 1963 | 1962 | |
|---|
| 1964 | | - if (rk_cam_w == 0 || rk_cam_h == 0 || |
|---|
| 1965 | | - rk_cam_fps == 0) |
|---|
| 1963 | + if (rk_cam_w == 0 || rk_cam_h == 0) |
|---|
| 1966 | 1964 | goto err_find_res; |
|---|
| 1967 | 1965 | |
|---|
| 1968 | | - dst_fps = rk_cam_fps; |
|---|
| 1969 | 1966 | for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { |
|---|
| 1970 | 1967 | mode = &supported_modes[i]; |
|---|
| 1971 | | - cur_fps = mode->max_fps.denominator / mode->max_fps.numerator; |
|---|
| 1972 | 1968 | if (mode->width == rk_cam_w && mode->height == rk_cam_h && |
|---|
| 1973 | 1969 | mode->hdr_mode == rk_cam_hdr) { |
|---|
| 1974 | | - if (cur_fps == dst_fps) { |
|---|
| 1975 | | - sc200ai->cur_mode = mode; |
|---|
| 1976 | | - return; |
|---|
| 1977 | | - } |
|---|
| 1978 | | - if (cur_fps >= dst_fps) { |
|---|
| 1979 | | - if (fit_mode) { |
|---|
| 1980 | | - tmp_fps = fit_mode->max_fps.denominator / fit_mode->max_fps.numerator; |
|---|
| 1981 | | - if (tmp_fps - dst_fps > cur_fps - dst_fps) |
|---|
| 1982 | | - fit_mode = mode; |
|---|
| 1983 | | - } else { |
|---|
| 1984 | | - fit_mode = mode; |
|---|
| 1985 | | - } |
|---|
| 1986 | | - } |
|---|
| 1970 | + sc200ai->cur_mode = mode; |
|---|
| 1971 | + return; |
|---|
| 1987 | 1972 | } |
|---|
| 1988 | 1973 | } |
|---|
| 1989 | | - if (fit_mode) { |
|---|
| 1990 | | - sc200ai->cur_mode = fit_mode; |
|---|
| 1991 | | - return; |
|---|
| 1992 | | - } |
|---|
| 1993 | 1974 | err_find_res: |
|---|
| 1994 | | - dev_err(&sc200ai->client->dev, "not match %dx%d@%dfps mode %d\n!", |
|---|
| 1995 | | - rk_cam_w, rk_cam_h, dst_fps, rk_cam_hdr); |
|---|
| 1975 | + dev_err(&sc200ai->client->dev, "not match %dx%d mode %d\n!", |
|---|
| 1976 | + rk_cam_w, rk_cam_h, rk_cam_hdr); |
|---|
| 1996 | 1977 | sc200ai->cur_mode = &supported_modes[0]; |
|---|
| 1997 | 1978 | } |
|---|
| 1998 | 1979 | #else |
|---|
| .. | .. |
|---|
| 2058 | 2039 | return -EINVAL; |
|---|
| 2059 | 2040 | } |
|---|
| 2060 | 2041 | |
|---|
| 2061 | | - sc200ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS); |
|---|
| 2042 | + sc200ai->reset_gpio = devm_gpiod_get(dev, "reset", sc200ai->is_thunderboot ? GPIOD_ASIS : GPIOD_OUT_LOW); |
|---|
| 2062 | 2043 | if (IS_ERR(sc200ai->reset_gpio)) |
|---|
| 2063 | 2044 | dev_warn(dev, "Failed to get reset-gpios\n"); |
|---|
| 2064 | 2045 | |
|---|
| 2065 | | - sc200ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_ASIS); |
|---|
| 2046 | + sc200ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", sc200ai->is_thunderboot ? GPIOD_ASIS : GPIOD_OUT_LOW); |
|---|
| 2066 | 2047 | if (IS_ERR(sc200ai->pwdn_gpio)) |
|---|
| 2067 | 2048 | dev_warn(dev, "Failed to get pwdn-gpios\n"); |
|---|
| 2068 | 2049 | |
|---|
| .. | .. |
|---|
| 2118 | 2099 | goto err_power_off; |
|---|
| 2119 | 2100 | #endif |
|---|
| 2120 | 2101 | |
|---|
| 2102 | + if (!sc200ai->cam_sw_inf) { |
|---|
| 2103 | + sc200ai->cam_sw_inf = cam_sw_init(); |
|---|
| 2104 | + cam_sw_clk_init(sc200ai->cam_sw_inf, sc200ai->xvclk, SC200AI_XVCLK_FREQ); |
|---|
| 2105 | + cam_sw_reset_pin_init(sc200ai->cam_sw_inf, sc200ai->reset_gpio, 0); |
|---|
| 2106 | + cam_sw_pwdn_pin_init(sc200ai->cam_sw_inf, sc200ai->pwdn_gpio, 1); |
|---|
| 2107 | + } |
|---|
| 2108 | + |
|---|
| 2121 | 2109 | memset(facing, 0, sizeof(facing)); |
|---|
| 2122 | 2110 | if (strcmp(sc200ai->module_facing, "back") == 0) |
|---|
| 2123 | 2111 | facing[0] = 'b'; |
|---|
| .. | .. |
|---|
| 2168 | 2156 | v4l2_ctrl_handler_free(&sc200ai->ctrl_handler); |
|---|
| 2169 | 2157 | mutex_destroy(&sc200ai->mutex); |
|---|
| 2170 | 2158 | |
|---|
| 2159 | + cam_sw_deinit(sc200ai->cam_sw_inf); |
|---|
| 2160 | + |
|---|
| 2171 | 2161 | pm_runtime_disable(&client->dev); |
|---|
| 2172 | 2162 | if (!pm_runtime_status_suspended(&client->dev)) |
|---|
| 2173 | 2163 | __sc200ai_power_off(sc200ai); |
|---|