.. | .. |
---|
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 |
---|
.. | .. |
---|
1889 | 1952 | } |
---|
1890 | 1953 | |
---|
1891 | 1954 | #ifdef CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP |
---|
1892 | | -static u32 rk_cam_hdr; |
---|
1893 | | -static u32 rk_cam_w; |
---|
1894 | | -static u32 rk_cam_h; |
---|
1895 | | -static u32 rk_cam_fps; |
---|
1896 | | - |
---|
1897 | | -static int __init __maybe_unused rk_cam_hdr_setup(char *str) |
---|
1898 | | -{ |
---|
1899 | | - int ret = 0; |
---|
1900 | | - unsigned long val = 0; |
---|
1901 | | - |
---|
1902 | | - ret = kstrtoul(str, 0, &val); |
---|
1903 | | - if (!ret) |
---|
1904 | | - rk_cam_hdr = (u32)val; |
---|
1905 | | - else |
---|
1906 | | - pr_err("get rk_cam_hdr fail\n"); |
---|
1907 | | - return 1; |
---|
1908 | | -} |
---|
1909 | | - |
---|
1910 | | -static int __init __maybe_unused rk_cam_w_setup(char *str) |
---|
1911 | | -{ |
---|
1912 | | - int ret = 0; |
---|
1913 | | - unsigned long val = 0; |
---|
1914 | | - |
---|
1915 | | - ret = kstrtoul(str, 0, &val); |
---|
1916 | | - if (!ret) |
---|
1917 | | - rk_cam_w = (u32)val; |
---|
1918 | | - else |
---|
1919 | | - pr_err("get rk_cam_w fail\n"); |
---|
1920 | | - return 1; |
---|
1921 | | -} |
---|
1922 | | - |
---|
1923 | | -static int __init __maybe_unused rk_cam_h_setup(char *str) |
---|
1924 | | -{ |
---|
1925 | | - int ret = 0; |
---|
1926 | | - unsigned long val = 0; |
---|
1927 | | - |
---|
1928 | | - ret = kstrtoul(str, 0, &val); |
---|
1929 | | - if (!ret) |
---|
1930 | | - rk_cam_h = (u32)val; |
---|
1931 | | - else |
---|
1932 | | - pr_err("get rk_cam_h fail\n"); |
---|
1933 | | - return 1; |
---|
1934 | | -} |
---|
1935 | | - |
---|
1936 | | -static int __init __maybe_unused rk_cam_fps_setup(char *str) |
---|
1937 | | -{ |
---|
1938 | | - int ret = 0; |
---|
1939 | | - unsigned long val = 0; |
---|
1940 | | - |
---|
1941 | | - ret = kstrtoul(str, 0, &val); |
---|
1942 | | - if (!ret) |
---|
1943 | | - rk_cam_fps = (u32)val; |
---|
1944 | | - else |
---|
1945 | | - pr_err("get rk_cam_fps fail\n"); |
---|
1946 | | - return 1; |
---|
1947 | | -} |
---|
1948 | | - |
---|
1949 | | -__setup("rk_cam_hdr=", rk_cam_hdr_setup); |
---|
1950 | | -__setup("rk_cam_w=", rk_cam_w_setup); |
---|
1951 | | -__setup("rk_cam_h=", rk_cam_h_setup); |
---|
1952 | | -__setup("rk_cam_fps=", rk_cam_fps_setup); |
---|
1953 | | - |
---|
1954 | 1955 | static void find_terminal_resolution(struct sc200ai *sc200ai) |
---|
1955 | 1956 | { |
---|
1956 | 1957 | int i = 0; |
---|
1957 | 1958 | const struct sc200ai_mode *mode = NULL; |
---|
1958 | | - const struct sc200ai_mode *fit_mode = NULL; |
---|
1959 | | - u32 cur_fps = 0; |
---|
1960 | | - u32 dst_fps = 0; |
---|
1961 | | - 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(); |
---|
1962 | 1962 | |
---|
1963 | | - if (rk_cam_w == 0 || rk_cam_h == 0 || |
---|
1964 | | - rk_cam_fps == 0) |
---|
| 1963 | + if (rk_cam_w == 0 || rk_cam_h == 0) |
---|
1965 | 1964 | goto err_find_res; |
---|
1966 | 1965 | |
---|
1967 | | - dst_fps = rk_cam_fps; |
---|
1968 | 1966 | for (i = 0; i < ARRAY_SIZE(supported_modes); i++) { |
---|
1969 | 1967 | mode = &supported_modes[i]; |
---|
1970 | | - cur_fps = mode->max_fps.denominator / mode->max_fps.numerator; |
---|
1971 | 1968 | if (mode->width == rk_cam_w && mode->height == rk_cam_h && |
---|
1972 | 1969 | mode->hdr_mode == rk_cam_hdr) { |
---|
1973 | | - if (cur_fps == dst_fps) { |
---|
1974 | | - sc200ai->cur_mode = mode; |
---|
1975 | | - return; |
---|
1976 | | - } |
---|
1977 | | - if (cur_fps >= dst_fps) { |
---|
1978 | | - if (fit_mode) { |
---|
1979 | | - tmp_fps = fit_mode->max_fps.denominator / fit_mode->max_fps.numerator; |
---|
1980 | | - if (tmp_fps - dst_fps > cur_fps - dst_fps) |
---|
1981 | | - fit_mode = mode; |
---|
1982 | | - } else { |
---|
1983 | | - fit_mode = mode; |
---|
1984 | | - } |
---|
1985 | | - } |
---|
| 1970 | + sc200ai->cur_mode = mode; |
---|
| 1971 | + return; |
---|
1986 | 1972 | } |
---|
1987 | 1973 | } |
---|
1988 | | - if (fit_mode) { |
---|
1989 | | - sc200ai->cur_mode = fit_mode; |
---|
1990 | | - return; |
---|
1991 | | - } |
---|
1992 | 1974 | err_find_res: |
---|
1993 | | - dev_err(&sc200ai->client->dev, "not match %dx%d@%dfps mode %d\n!", |
---|
1994 | | - 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); |
---|
1995 | 1977 | sc200ai->cur_mode = &supported_modes[0]; |
---|
1996 | 1978 | } |
---|
1997 | 1979 | #else |
---|
.. | .. |
---|
2057 | 2039 | return -EINVAL; |
---|
2058 | 2040 | } |
---|
2059 | 2041 | |
---|
2060 | | - 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); |
---|
2061 | 2043 | if (IS_ERR(sc200ai->reset_gpio)) |
---|
2062 | 2044 | dev_warn(dev, "Failed to get reset-gpios\n"); |
---|
2063 | 2045 | |
---|
2064 | | - 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); |
---|
2065 | 2047 | if (IS_ERR(sc200ai->pwdn_gpio)) |
---|
2066 | 2048 | dev_warn(dev, "Failed to get pwdn-gpios\n"); |
---|
2067 | 2049 | |
---|
.. | .. |
---|
2117 | 2099 | goto err_power_off; |
---|
2118 | 2100 | #endif |
---|
2119 | 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 | + |
---|
2120 | 2109 | memset(facing, 0, sizeof(facing)); |
---|
2121 | 2110 | if (strcmp(sc200ai->module_facing, "back") == 0) |
---|
2122 | 2111 | facing[0] = 'b'; |
---|
.. | .. |
---|
2167 | 2156 | v4l2_ctrl_handler_free(&sc200ai->ctrl_handler); |
---|
2168 | 2157 | mutex_destroy(&sc200ai->mutex); |
---|
2169 | 2158 | |
---|
| 2159 | + cam_sw_deinit(sc200ai->cam_sw_inf); |
---|
| 2160 | + |
---|
2170 | 2161 | pm_runtime_disable(&client->dev); |
---|
2171 | 2162 | if (!pm_runtime_status_suspended(&client->dev)) |
---|
2172 | 2163 | __sc200ai_power_off(sc200ai); |
---|