| .. | .. |
|---|
| 114 | 114 | #define MIRROR_BIT_MASK (BIT(1) | BIT(2)) |
|---|
| 115 | 115 | #define FLIP_BIT_MASK (BIT(6) | BIT(5)) |
|---|
| 116 | 116 | |
|---|
| 117 | | -enum sc4238_max_pad { |
|---|
| 118 | | - PAD0, |
|---|
| 119 | | - PAD1, |
|---|
| 120 | | - PAD2, |
|---|
| 121 | | - PAD3, |
|---|
| 122 | | - PAD_MAX, |
|---|
| 123 | | -}; |
|---|
| 124 | | - |
|---|
| 125 | 117 | struct regval { |
|---|
| 126 | 118 | u16 addr; |
|---|
| 127 | 119 | u8 val; |
|---|
| .. | .. |
|---|
| 167 | 159 | struct v4l2_ctrl *h_flip; |
|---|
| 168 | 160 | struct v4l2_ctrl *v_flip; |
|---|
| 169 | 161 | struct mutex mutex; |
|---|
| 162 | + struct v4l2_fract cur_fps; |
|---|
| 170 | 163 | bool streaming; |
|---|
| 171 | 164 | bool power_on; |
|---|
| 172 | 165 | const struct sc4238_mode *cur_mode; |
|---|
| .. | .. |
|---|
| 1581 | 1574 | mode->pixel_rate); |
|---|
| 1582 | 1575 | __v4l2_ctrl_s_ctrl(sc4238->link_freq, |
|---|
| 1583 | 1576 | mode->link_freq); |
|---|
| 1577 | + sc4238->cur_fps = mode->max_fps; |
|---|
| 1578 | + sc4238->cur_vts = mode->vts_def; |
|---|
| 1584 | 1579 | } |
|---|
| 1585 | 1580 | |
|---|
| 1586 | 1581 | mutex_unlock(&sc4238->mutex); |
|---|
| .. | .. |
|---|
| 1674 | 1669 | struct sc4238 *sc4238 = to_sc4238(sd); |
|---|
| 1675 | 1670 | const struct sc4238_mode *mode = sc4238->cur_mode; |
|---|
| 1676 | 1671 | |
|---|
| 1677 | | - mutex_lock(&sc4238->mutex); |
|---|
| 1678 | | - fi->interval = mode->max_fps; |
|---|
| 1679 | | - mutex_unlock(&sc4238->mutex); |
|---|
| 1672 | + if (sc4238->streaming) |
|---|
| 1673 | + fi->interval = sc4238->cur_fps; |
|---|
| 1674 | + else |
|---|
| 1675 | + fi->interval = mode->max_fps; |
|---|
| 1680 | 1676 | |
|---|
| 1681 | 1677 | return 0; |
|---|
| 1682 | 1678 | } |
|---|
| 1683 | 1679 | |
|---|
| 1684 | | -static int sc4238_g_mbus_config(struct v4l2_subdev *sd, |
|---|
| 1680 | +static int sc4238_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id, |
|---|
| 1685 | 1681 | struct v4l2_mbus_config *config) |
|---|
| 1686 | 1682 | { |
|---|
| 1687 | 1683 | struct sc4238 *sc4238 = to_sc4238(sd); |
|---|
| .. | .. |
|---|
| 1698 | 1694 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK | |
|---|
| 1699 | 1695 | V4L2_MBUS_CSI2_CHANNEL_1; |
|---|
| 1700 | 1696 | |
|---|
| 1701 | | - config->type = V4L2_MBUS_CSI2; |
|---|
| 1697 | + config->type = V4L2_MBUS_CSI2_DPHY; |
|---|
| 1702 | 1698 | config->flags = val; |
|---|
| 1703 | 1699 | |
|---|
| 1704 | 1700 | return 0; |
|---|
| .. | .. |
|---|
| 1884 | 1880 | return ret; |
|---|
| 1885 | 1881 | } |
|---|
| 1886 | 1882 | |
|---|
| 1883 | +static int sc4238_get_channel_info(struct sc4238 *sc4238, struct rkmodule_channel_info *ch_info) |
|---|
| 1884 | +{ |
|---|
| 1885 | + if (ch_info->index < PAD0 || ch_info->index >= PAD_MAX) |
|---|
| 1886 | + return -EINVAL; |
|---|
| 1887 | + ch_info->vc = sc4238->cur_mode->vc[ch_info->index]; |
|---|
| 1888 | + ch_info->width = sc4238->cur_mode->width; |
|---|
| 1889 | + ch_info->height = sc4238->cur_mode->height; |
|---|
| 1890 | + ch_info->bus_fmt = sc4238->cur_mode->bus_fmt; |
|---|
| 1891 | + return 0; |
|---|
| 1892 | +} |
|---|
| 1893 | + |
|---|
| 1887 | 1894 | static long sc4238_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) |
|---|
| 1888 | 1895 | { |
|---|
| 1889 | 1896 | struct sc4238 *sc4238 = to_sc4238(sd); |
|---|
| 1890 | 1897 | struct rkmodule_hdr_cfg *hdr_cfg; |
|---|
| 1898 | + struct rkmodule_channel_info *ch_info; |
|---|
| 1891 | 1899 | long ret = 0; |
|---|
| 1892 | 1900 | u32 i, h, w; |
|---|
| 1893 | 1901 | u32 stream = 0; |
|---|
| .. | .. |
|---|
| 1923 | 1931 | __v4l2_ctrl_modify_range(sc4238->vblank, h, |
|---|
| 1924 | 1932 | SC4238_VTS_MAX - sc4238->cur_mode->height, |
|---|
| 1925 | 1933 | 1, h); |
|---|
| 1934 | + sc4238->cur_fps = sc4238->cur_mode->max_fps; |
|---|
| 1935 | + sc4238->cur_vts = sc4238->cur_mode->vts_def; |
|---|
| 1926 | 1936 | dev_info(&sc4238->client->dev, |
|---|
| 1927 | 1937 | "sensor mode: %d\n", |
|---|
| 1928 | 1938 | sc4238->cur_mode->hdr_mode); |
|---|
| .. | .. |
|---|
| 1947 | 1957 | ret = sc4238_write_reg(sc4238->client, SC4238_REG_CTRL_MODE, |
|---|
| 1948 | 1958 | SC4238_REG_VALUE_08BIT, SC4238_MODE_SW_STANDBY); |
|---|
| 1949 | 1959 | break; |
|---|
| 1960 | + case RKMODULE_GET_CHANNEL_INFO: |
|---|
| 1961 | + ch_info = (struct rkmodule_channel_info *)arg; |
|---|
| 1962 | + ret = sc4238_get_channel_info(sc4238, ch_info); |
|---|
| 1963 | + break; |
|---|
| 1950 | 1964 | default: |
|---|
| 1951 | 1965 | ret = -ENOIOCTLCMD; |
|---|
| 1952 | 1966 | break; |
|---|
| .. | .. |
|---|
| 1964 | 1978 | struct rkmodule_awb_cfg *cfg; |
|---|
| 1965 | 1979 | struct rkmodule_hdr_cfg *hdr; |
|---|
| 1966 | 1980 | struct preisp_hdrae_exp_s *hdrae; |
|---|
| 1981 | + struct rkmodule_channel_info *ch_info; |
|---|
| 1967 | 1982 | long ret; |
|---|
| 1968 | 1983 | u32 stream = 0; |
|---|
| 1969 | 1984 | |
|---|
| .. | .. |
|---|
| 1976 | 1991 | } |
|---|
| 1977 | 1992 | |
|---|
| 1978 | 1993 | ret = sc4238_ioctl(sd, cmd, inf); |
|---|
| 1979 | | - if (!ret) |
|---|
| 1994 | + if (!ret) { |
|---|
| 1980 | 1995 | ret = copy_to_user(up, inf, sizeof(*inf)); |
|---|
| 1996 | + if (ret) |
|---|
| 1997 | + ret = -EFAULT; |
|---|
| 1998 | + } |
|---|
| 1981 | 1999 | kfree(inf); |
|---|
| 1982 | 2000 | break; |
|---|
| 1983 | 2001 | case RKMODULE_AWB_CFG: |
|---|
| .. | .. |
|---|
| 1990 | 2008 | ret = copy_from_user(cfg, up, sizeof(*cfg)); |
|---|
| 1991 | 2009 | if (!ret) |
|---|
| 1992 | 2010 | ret = sc4238_ioctl(sd, cmd, cfg); |
|---|
| 2011 | + else |
|---|
| 2012 | + ret = -EFAULT; |
|---|
| 1993 | 2013 | kfree(cfg); |
|---|
| 1994 | 2014 | break; |
|---|
| 1995 | 2015 | case RKMODULE_GET_HDR_CFG: |
|---|
| .. | .. |
|---|
| 2000 | 2020 | } |
|---|
| 2001 | 2021 | |
|---|
| 2002 | 2022 | ret = sc4238_ioctl(sd, cmd, hdr); |
|---|
| 2003 | | - if (!ret) |
|---|
| 2023 | + if (!ret) { |
|---|
| 2004 | 2024 | ret = copy_to_user(up, hdr, sizeof(*hdr)); |
|---|
| 2025 | + if (ret) |
|---|
| 2026 | + ret = -EFAULT; |
|---|
| 2027 | + } |
|---|
| 2005 | 2028 | kfree(hdr); |
|---|
| 2006 | 2029 | break; |
|---|
| 2007 | 2030 | case RKMODULE_SET_HDR_CFG: |
|---|
| .. | .. |
|---|
| 2014 | 2037 | ret = copy_from_user(hdr, up, sizeof(*hdr)); |
|---|
| 2015 | 2038 | if (!ret) |
|---|
| 2016 | 2039 | ret = sc4238_ioctl(sd, cmd, hdr); |
|---|
| 2040 | + else |
|---|
| 2041 | + ret = -EFAULT; |
|---|
| 2017 | 2042 | kfree(hdr); |
|---|
| 2018 | 2043 | break; |
|---|
| 2019 | 2044 | case PREISP_CMD_SET_HDRAE_EXP: |
|---|
| .. | .. |
|---|
| 2026 | 2051 | ret = copy_from_user(hdrae, up, sizeof(*hdrae)); |
|---|
| 2027 | 2052 | if (!ret) |
|---|
| 2028 | 2053 | ret = sc4238_ioctl(sd, cmd, hdrae); |
|---|
| 2054 | + else |
|---|
| 2055 | + ret = -EFAULT; |
|---|
| 2029 | 2056 | kfree(hdrae); |
|---|
| 2030 | 2057 | break; |
|---|
| 2031 | 2058 | case RKMODULE_SET_QUICK_STREAM: |
|---|
| 2032 | 2059 | ret = copy_from_user(&stream, up, sizeof(u32)); |
|---|
| 2033 | 2060 | if (!ret) |
|---|
| 2034 | 2061 | ret = sc4238_ioctl(sd, cmd, &stream); |
|---|
| 2062 | + else |
|---|
| 2063 | + ret = -EFAULT; |
|---|
| 2064 | + break; |
|---|
| 2065 | + case RKMODULE_GET_CHANNEL_INFO: |
|---|
| 2066 | + ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL); |
|---|
| 2067 | + if (!ch_info) { |
|---|
| 2068 | + ret = -ENOMEM; |
|---|
| 2069 | + return ret; |
|---|
| 2070 | + } |
|---|
| 2071 | + |
|---|
| 2072 | + ret = sc4238_ioctl(sd, cmd, ch_info); |
|---|
| 2073 | + if (!ret) { |
|---|
| 2074 | + ret = copy_to_user(up, ch_info, sizeof(*ch_info)); |
|---|
| 2075 | + if (ret) |
|---|
| 2076 | + ret = -EFAULT; |
|---|
| 2077 | + } |
|---|
| 2078 | + kfree(ch_info); |
|---|
| 2035 | 2079 | break; |
|---|
| 2036 | 2080 | default: |
|---|
| 2037 | 2081 | ret = -ENOIOCTLCMD; |
|---|
| .. | .. |
|---|
| 2345 | 2389 | static const struct v4l2_subdev_video_ops sc4238_video_ops = { |
|---|
| 2346 | 2390 | .s_stream = sc4238_s_stream, |
|---|
| 2347 | 2391 | .g_frame_interval = sc4238_g_frame_interval, |
|---|
| 2348 | | - .g_mbus_config = sc4238_g_mbus_config, |
|---|
| 2349 | 2392 | }; |
|---|
| 2350 | 2393 | |
|---|
| 2351 | 2394 | static const struct v4l2_subdev_pad_ops sc4238_pad_ops = { |
|---|
| .. | .. |
|---|
| 2354 | 2397 | .enum_frame_interval = sc4238_enum_frame_interval, |
|---|
| 2355 | 2398 | .get_fmt = sc4238_get_fmt, |
|---|
| 2356 | 2399 | .set_fmt = sc4238_set_fmt, |
|---|
| 2400 | + .get_mbus_config = sc4238_g_mbus_config, |
|---|
| 2357 | 2401 | }; |
|---|
| 2358 | 2402 | |
|---|
| 2359 | 2403 | static const struct v4l2_subdev_ops sc4238_subdev_ops = { |
|---|
| .. | .. |
|---|
| 2361 | 2405 | .video = &sc4238_video_ops, |
|---|
| 2362 | 2406 | .pad = &sc4238_pad_ops, |
|---|
| 2363 | 2407 | }; |
|---|
| 2408 | + |
|---|
| 2409 | +static void sc4238_modify_fps_info(struct sc4238 *sc4238) |
|---|
| 2410 | +{ |
|---|
| 2411 | + const struct sc4238_mode *mode = sc4238->cur_mode; |
|---|
| 2412 | + |
|---|
| 2413 | + sc4238->cur_fps.denominator = mode->max_fps.denominator * mode->vts_def / |
|---|
| 2414 | + sc4238->cur_vts; |
|---|
| 2415 | +} |
|---|
| 2364 | 2416 | |
|---|
| 2365 | 2417 | static int sc4238_set_ctrl(struct v4l2_ctrl *ctrl) |
|---|
| 2366 | 2418 | { |
|---|
| .. | .. |
|---|
| 2432 | 2484 | ctrl->val + sc4238->cur_mode->height); |
|---|
| 2433 | 2485 | if (ret == 0) |
|---|
| 2434 | 2486 | sc4238->cur_vts = ctrl->val + sc4238->cur_mode->height; |
|---|
| 2487 | + sc4238_modify_fps_info(sc4238); |
|---|
| 2435 | 2488 | dev_dbg(&client->dev, "set vblank 0x%x\n", |
|---|
| 2436 | 2489 | ctrl->val); |
|---|
| 2437 | 2490 | break; |
|---|
| .. | .. |
|---|
| 2565 | 2618 | |
|---|
| 2566 | 2619 | sc4238->subdev.ctrl_handler = handler; |
|---|
| 2567 | 2620 | sc4238->has_init_exp = false; |
|---|
| 2621 | + sc4238->cur_fps = mode->max_fps; |
|---|
| 2622 | + sc4238->cur_vts = mode->vts_def; |
|---|
| 2568 | 2623 | |
|---|
| 2569 | 2624 | return 0; |
|---|
| 2570 | 2625 | |
|---|