| .. | .. |
|---|
| 23 | 23 | * V0.0X01.0X06 |
|---|
| 24 | 24 | * 1. support DOL3 10bit 20fps 1485Mbps |
|---|
| 25 | 25 | * 2. fixed linkfreq error |
|---|
| 26 | + * V0.0X01.0X07 |
|---|
| 27 | + * 1. fix set_fmt & ioctl get mode unmatched issue. |
|---|
| 28 | + * 2. need to set default vblank when change format. |
|---|
| 29 | + * 3. enum all supported mode mbus_code, not just cur_mode. |
|---|
| 30 | + * V0.0X01.0X08 |
|---|
| 31 | + * 1. add dcphy param for hdrx2 mode. |
|---|
| 26 | 32 | */ |
|---|
| 27 | 33 | |
|---|
| 28 | 34 | #define DEBUG |
|---|
| .. | .. |
|---|
| 46 | 52 | #include <linux/rk-preisp.h> |
|---|
| 47 | 53 | #include "../platform/rockchip/isp/rkisp_tb_helper.h" |
|---|
| 48 | 54 | |
|---|
| 49 | | -#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x06) |
|---|
| 55 | +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x08) |
|---|
| 50 | 56 | |
|---|
| 51 | 57 | #ifndef V4L2_CID_DIGITAL_GAIN |
|---|
| 52 | 58 | #define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN |
|---|
| .. | .. |
|---|
| 169 | 175 | |
|---|
| 170 | 176 | #define IMX415_NUM_SUPPLIES ARRAY_SIZE(imx415_supply_names) |
|---|
| 171 | 177 | |
|---|
| 172 | | -enum imx415_max_pad { |
|---|
| 173 | | - PAD0, /* link to isp */ |
|---|
| 174 | | - PAD1, /* link to csi wr0 | hdr x2:L x3:M */ |
|---|
| 175 | | - PAD2, /* link to csi wr1 | hdr x3:L */ |
|---|
| 176 | | - PAD3, /* link to csi wr2 | hdr x2:M x3:S */ |
|---|
| 177 | | - PAD_MAX, |
|---|
| 178 | | -}; |
|---|
| 179 | | - |
|---|
| 180 | 178 | struct regval { |
|---|
| 181 | 179 | u16 addr; |
|---|
| 182 | 180 | u8 val; |
|---|
| .. | .. |
|---|
| 234 | 232 | u32 cur_vts; |
|---|
| 235 | 233 | bool has_init_exp; |
|---|
| 236 | 234 | struct preisp_hdrae_exp_s init_hdrae_exp; |
|---|
| 235 | +}; |
|---|
| 236 | + |
|---|
| 237 | +static struct rkmodule_csi_dphy_param dcphy_param = { |
|---|
| 238 | + .vendor = PHY_VENDOR_SAMSUNG, |
|---|
| 239 | + .lp_vol_ref = 6, |
|---|
| 240 | + .lp_hys_sw = {3, 0, 0, 0}, |
|---|
| 241 | + .lp_escclk_pol_sel = {1, 1, 1, 1}, |
|---|
| 242 | + .skew_data_cal_clk = {0, 3, 3, 3}, |
|---|
| 243 | + .clk_hs_term_sel = 2, |
|---|
| 244 | + .data_hs_term_sel = {2, 2, 2, 2}, |
|---|
| 245 | + .reserved = {0}, |
|---|
| 237 | 246 | }; |
|---|
| 238 | 247 | |
|---|
| 239 | 248 | #define to_imx415(sd) container_of(sd, struct imx415, subdev) |
|---|
| .. | .. |
|---|
| 769 | 778 | .hdr_mode = NO_HDR, |
|---|
| 770 | 779 | .mipi_freq_idx = 1, |
|---|
| 771 | 780 | .bpp = 10, |
|---|
| 781 | + .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, |
|---|
| 772 | 782 | }, |
|---|
| 773 | 783 | { |
|---|
| 774 | 784 | .bus_fmt = MEDIA_BUS_FMT_SGBRG10_1X10, |
|---|
| .. | .. |
|---|
| 862 | 872 | .hdr_mode = NO_HDR, |
|---|
| 863 | 873 | .mipi_freq_idx = 1, |
|---|
| 864 | 874 | .bpp = 12, |
|---|
| 875 | + .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, |
|---|
| 865 | 876 | }, |
|---|
| 866 | 877 | { |
|---|
| 867 | 878 | .bus_fmt = MEDIA_BUS_FMT_SGBRG12_1X12, |
|---|
| .. | .. |
|---|
| 929 | 940 | .hdr_mode = NO_HDR, |
|---|
| 930 | 941 | .mipi_freq_idx = 0, |
|---|
| 931 | 942 | .bpp = 12, |
|---|
| 943 | + .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, |
|---|
| 932 | 944 | }, |
|---|
| 933 | 945 | { |
|---|
| 934 | 946 | .bus_fmt = MEDIA_BUS_FMT_SGBRG12_1X12, |
|---|
| .. | .. |
|---|
| 1059 | 1071 | |
|---|
| 1060 | 1072 | for (i = 0; i < imx415->cfg_num; i++) { |
|---|
| 1061 | 1073 | dist = imx415_get_reso_dist(&supported_modes[i], framefmt); |
|---|
| 1062 | | - if ((cur_best_fit_dist == -1 || dist <= cur_best_fit_dist) && |
|---|
| 1074 | + if ((cur_best_fit_dist == -1 || dist < cur_best_fit_dist) && |
|---|
| 1063 | 1075 | supported_modes[i].bus_fmt == framefmt->code) { |
|---|
| 1064 | 1076 | cur_best_fit_dist = dist; |
|---|
| 1065 | 1077 | cur_best_fit = i; |
|---|
| 1066 | 1078 | } |
|---|
| 1067 | 1079 | } |
|---|
| 1080 | + dev_info(&imx415->client->dev, "%s: cur_best_fit(%d)", |
|---|
| 1081 | + __func__, cur_best_fit); |
|---|
| 1068 | 1082 | |
|---|
| 1069 | 1083 | return &supported_modes[cur_best_fit]; |
|---|
| 1070 | 1084 | } |
|---|
| .. | .. |
|---|
| 1118 | 1132 | __v4l2_ctrl_modify_range(imx415->vblank, vblank_min, |
|---|
| 1119 | 1133 | IMX415_VTS_MAX - mode->height, |
|---|
| 1120 | 1134 | 1, vblank_def); |
|---|
| 1135 | + __v4l2_ctrl_s_ctrl(imx415->vblank, vblank_def); |
|---|
| 1121 | 1136 | __v4l2_ctrl_s_ctrl(imx415->link_freq, mode->mipi_freq_idx); |
|---|
| 1122 | 1137 | pixel_rate = (u32)link_freq_items[mode->mipi_freq_idx] / mode->bpp * 2 * IMX415_4LANES; |
|---|
| 1123 | 1138 | __v4l2_ctrl_s_ctrl_int64(imx415->pixel_rate, |
|---|
| 1124 | 1139 | pixel_rate); |
|---|
| 1125 | 1140 | } |
|---|
| 1141 | + dev_info(&imx415->client->dev, "%s: mode->mipi_freq_idx(%d)", |
|---|
| 1142 | + __func__, mode->mipi_freq_idx); |
|---|
| 1126 | 1143 | |
|---|
| 1127 | 1144 | mutex_unlock(&imx415->mutex); |
|---|
| 1128 | 1145 | |
|---|
| .. | .. |
|---|
| 1165 | 1182 | { |
|---|
| 1166 | 1183 | struct imx415 *imx415 = to_imx415(sd); |
|---|
| 1167 | 1184 | |
|---|
| 1168 | | - if (code->index != 0) |
|---|
| 1185 | + if (code->index >= imx415->cfg_num) |
|---|
| 1169 | 1186 | return -EINVAL; |
|---|
| 1170 | | - code->code = imx415->cur_mode->bus_fmt; |
|---|
| 1187 | + |
|---|
| 1188 | + code->code = supported_modes[code->index].bus_fmt; |
|---|
| 1171 | 1189 | |
|---|
| 1172 | 1190 | return 0; |
|---|
| 1173 | 1191 | } |
|---|
| .. | .. |
|---|
| 1198 | 1216 | struct imx415 *imx415 = to_imx415(sd); |
|---|
| 1199 | 1217 | const struct imx415_mode *mode = imx415->cur_mode; |
|---|
| 1200 | 1218 | |
|---|
| 1201 | | - mutex_lock(&imx415->mutex); |
|---|
| 1202 | 1219 | fi->interval = mode->max_fps; |
|---|
| 1203 | | - mutex_unlock(&imx415->mutex); |
|---|
| 1204 | 1220 | |
|---|
| 1205 | 1221 | return 0; |
|---|
| 1206 | 1222 | } |
|---|
| 1207 | 1223 | |
|---|
| 1208 | | -static int imx415_g_mbus_config(struct v4l2_subdev *sd, |
|---|
| 1224 | +static int imx415_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad_id, |
|---|
| 1209 | 1225 | struct v4l2_mbus_config *config) |
|---|
| 1210 | 1226 | { |
|---|
| 1211 | 1227 | struct imx415 *imx415 = to_imx415(sd); |
|---|
| .. | .. |
|---|
| 1219 | 1235 | val |= V4L2_MBUS_CSI2_CHANNEL_1; |
|---|
| 1220 | 1236 | if (mode->hdr_mode == HDR_X3) |
|---|
| 1221 | 1237 | val |= V4L2_MBUS_CSI2_CHANNEL_2; |
|---|
| 1222 | | - config->type = V4L2_MBUS_CSI2; |
|---|
| 1238 | + config->type = V4L2_MBUS_CSI2_DPHY; |
|---|
| 1223 | 1239 | config->flags = val; |
|---|
| 1224 | 1240 | |
|---|
| 1225 | 1241 | return 0; |
|---|
| .. | .. |
|---|
| 1650 | 1666 | return ret; |
|---|
| 1651 | 1667 | } |
|---|
| 1652 | 1668 | |
|---|
| 1669 | +static int imx415_get_channel_info(struct imx415 *imx415, struct rkmodule_channel_info *ch_info) |
|---|
| 1670 | +{ |
|---|
| 1671 | + if (ch_info->index < PAD0 || ch_info->index >= PAD_MAX) |
|---|
| 1672 | + return -EINVAL; |
|---|
| 1673 | + ch_info->vc = imx415->cur_mode->vc[ch_info->index]; |
|---|
| 1674 | + ch_info->width = imx415->cur_mode->width; |
|---|
| 1675 | + ch_info->height = imx415->cur_mode->height; |
|---|
| 1676 | + ch_info->bus_fmt = imx415->cur_mode->bus_fmt; |
|---|
| 1677 | + return 0; |
|---|
| 1678 | +} |
|---|
| 1679 | + |
|---|
| 1653 | 1680 | static long imx415_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) |
|---|
| 1654 | 1681 | { |
|---|
| 1655 | 1682 | struct imx415 *imx415 = to_imx415(sd); |
|---|
| 1656 | 1683 | struct rkmodule_hdr_cfg *hdr; |
|---|
| 1684 | + struct rkmodule_channel_info *ch_info; |
|---|
| 1657 | 1685 | u32 i, h, w, stream; |
|---|
| 1658 | 1686 | long ret = 0; |
|---|
| 1659 | 1687 | const struct imx415_mode *mode; |
|---|
| 1660 | 1688 | u64 pixel_rate = 0; |
|---|
| 1689 | + struct rkmodule_csi_dphy_param *dphy_param; |
|---|
| 1661 | 1690 | |
|---|
| 1662 | 1691 | switch (cmd) { |
|---|
| 1663 | 1692 | case PREISP_CMD_SET_HDRAE_EXP: |
|---|
| .. | .. |
|---|
| 1706 | 1735 | } |
|---|
| 1707 | 1736 | w = mode->hts_def - imx415->cur_mode->width; |
|---|
| 1708 | 1737 | h = mode->vts_def - mode->height; |
|---|
| 1738 | + mutex_lock(&imx415->mutex); |
|---|
| 1709 | 1739 | __v4l2_ctrl_modify_range(imx415->hblank, w, w, 1, w); |
|---|
| 1710 | 1740 | __v4l2_ctrl_modify_range(imx415->vblank, h, |
|---|
| 1711 | 1741 | IMX415_VTS_MAX - mode->height, |
|---|
| .. | .. |
|---|
| 1714 | 1744 | pixel_rate = (u32)link_freq_items[mode->mipi_freq_idx] / mode->bpp * 2 * IMX415_4LANES; |
|---|
| 1715 | 1745 | __v4l2_ctrl_s_ctrl_int64(imx415->pixel_rate, |
|---|
| 1716 | 1746 | pixel_rate); |
|---|
| 1747 | + mutex_unlock(&imx415->mutex); |
|---|
| 1717 | 1748 | } |
|---|
| 1718 | 1749 | break; |
|---|
| 1719 | 1750 | case RKMODULE_SET_QUICK_STREAM: |
|---|
| .. | .. |
|---|
| 1733 | 1764 | else |
|---|
| 1734 | 1765 | *((u32 *)arg) = BRL_BINNING; |
|---|
| 1735 | 1766 | break; |
|---|
| 1767 | + case RKMODULE_GET_CHANNEL_INFO: |
|---|
| 1768 | + ch_info = (struct rkmodule_channel_info *)arg; |
|---|
| 1769 | + ret = imx415_get_channel_info(imx415, ch_info); |
|---|
| 1770 | + break; |
|---|
| 1771 | + case RKMODULE_GET_CSI_DPHY_PARAM: |
|---|
| 1772 | + if (imx415->cur_mode->hdr_mode == HDR_X2) { |
|---|
| 1773 | + dphy_param = (struct rkmodule_csi_dphy_param *)arg; |
|---|
| 1774 | + if (dphy_param->vendor == dcphy_param.vendor) |
|---|
| 1775 | + *dphy_param = dcphy_param; |
|---|
| 1776 | + dev_info(&imx415->client->dev, |
|---|
| 1777 | + "get sensor dphy param\n"); |
|---|
| 1778 | + } else |
|---|
| 1779 | + ret = -EINVAL; |
|---|
| 1780 | + break; |
|---|
| 1736 | 1781 | default: |
|---|
| 1737 | 1782 | ret = -ENOIOCTLCMD; |
|---|
| 1738 | 1783 | break; |
|---|
| .. | .. |
|---|
| 1750 | 1795 | struct rkmodule_awb_cfg *cfg; |
|---|
| 1751 | 1796 | struct rkmodule_hdr_cfg *hdr; |
|---|
| 1752 | 1797 | struct preisp_hdrae_exp_s *hdrae; |
|---|
| 1798 | + struct rkmodule_channel_info *ch_info; |
|---|
| 1753 | 1799 | long ret; |
|---|
| 1754 | 1800 | u32 stream; |
|---|
| 1755 | 1801 | u32 brl = 0; |
|---|
| 1802 | + struct rkmodule_csi_dphy_param *dphy_param; |
|---|
| 1756 | 1803 | |
|---|
| 1757 | 1804 | switch (cmd) { |
|---|
| 1758 | 1805 | case RKMODULE_GET_MODULE_INFO: |
|---|
| .. | .. |
|---|
| 1841 | 1888 | return -EFAULT; |
|---|
| 1842 | 1889 | } |
|---|
| 1843 | 1890 | break; |
|---|
| 1891 | + case RKMODULE_GET_CHANNEL_INFO: |
|---|
| 1892 | + ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL); |
|---|
| 1893 | + if (!ch_info) { |
|---|
| 1894 | + ret = -ENOMEM; |
|---|
| 1895 | + return ret; |
|---|
| 1896 | + } |
|---|
| 1897 | + |
|---|
| 1898 | + ret = imx415_ioctl(sd, cmd, ch_info); |
|---|
| 1899 | + if (!ret) { |
|---|
| 1900 | + ret = copy_to_user(up, ch_info, sizeof(*ch_info)); |
|---|
| 1901 | + if (ret) |
|---|
| 1902 | + ret = -EFAULT; |
|---|
| 1903 | + } |
|---|
| 1904 | + kfree(ch_info); |
|---|
| 1905 | + break; |
|---|
| 1906 | + case RKMODULE_GET_CSI_DPHY_PARAM: |
|---|
| 1907 | + dphy_param = kzalloc(sizeof(*dphy_param), GFP_KERNEL); |
|---|
| 1908 | + if (!dphy_param) { |
|---|
| 1909 | + ret = -ENOMEM; |
|---|
| 1910 | + return ret; |
|---|
| 1911 | + } |
|---|
| 1912 | + |
|---|
| 1913 | + ret = imx415_ioctl(sd, cmd, dphy_param); |
|---|
| 1914 | + if (!ret) { |
|---|
| 1915 | + ret = copy_to_user(up, dphy_param, sizeof(*dphy_param)); |
|---|
| 1916 | + if (ret) |
|---|
| 1917 | + ret = -EFAULT; |
|---|
| 1918 | + } |
|---|
| 1919 | + kfree(dphy_param); |
|---|
| 1920 | + break; |
|---|
| 1921 | + |
|---|
| 1844 | 1922 | default: |
|---|
| 1845 | 1923 | ret = -ENOIOCTLCMD; |
|---|
| 1846 | 1924 | break; |
|---|
| .. | .. |
|---|
| 1896 | 1974 | struct i2c_client *client = imx415->client; |
|---|
| 1897 | 1975 | int ret = 0; |
|---|
| 1898 | 1976 | |
|---|
| 1899 | | - dev_dbg(&imx415->client->dev, "s_stream: %d. %dx%d, hdr: %d, bpp: %d\n", |
|---|
| 1977 | + dev_info(&imx415->client->dev, "s_stream: %d. %dx%d, hdr: %d, bpp: %d\n", |
|---|
| 1900 | 1978 | on, imx415->cur_mode->width, imx415->cur_mode->height, |
|---|
| 1901 | 1979 | imx415->cur_mode->hdr_mode, imx415->cur_mode->bpp); |
|---|
| 1902 | 1980 | |
|---|
| .. | .. |
|---|
| 2051 | 2129 | regulator_bulk_disable(IMX415_NUM_SUPPLIES, imx415->supplies); |
|---|
| 2052 | 2130 | } |
|---|
| 2053 | 2131 | |
|---|
| 2054 | | -static int imx415_runtime_resume(struct device *dev) |
|---|
| 2132 | +static int __maybe_unused imx415_runtime_resume(struct device *dev) |
|---|
| 2055 | 2133 | { |
|---|
| 2056 | 2134 | struct i2c_client *client = to_i2c_client(dev); |
|---|
| 2057 | 2135 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
|---|
| .. | .. |
|---|
| 2060 | 2138 | return __imx415_power_on(imx415); |
|---|
| 2061 | 2139 | } |
|---|
| 2062 | 2140 | |
|---|
| 2063 | | -static int imx415_runtime_suspend(struct device *dev) |
|---|
| 2141 | +static int __maybe_unused imx415_runtime_suspend(struct device *dev) |
|---|
| 2064 | 2142 | { |
|---|
| 2065 | 2143 | struct i2c_client *client = to_i2c_client(dev); |
|---|
| 2066 | 2144 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
|---|
| .. | .. |
|---|
| 2175 | 2253 | static const struct v4l2_subdev_video_ops imx415_video_ops = { |
|---|
| 2176 | 2254 | .s_stream = imx415_s_stream, |
|---|
| 2177 | 2255 | .g_frame_interval = imx415_g_frame_interval, |
|---|
| 2178 | | - .g_mbus_config = imx415_g_mbus_config, |
|---|
| 2179 | 2256 | }; |
|---|
| 2180 | 2257 | |
|---|
| 2181 | 2258 | static const struct v4l2_subdev_pad_ops imx415_pad_ops = { |
|---|
| .. | .. |
|---|
| 2185 | 2262 | .get_fmt = imx415_get_fmt, |
|---|
| 2186 | 2263 | .set_fmt = imx415_set_fmt, |
|---|
| 2187 | 2264 | .get_selection = imx415_get_selection, |
|---|
| 2265 | + .get_mbus_config = imx415_g_mbus_config, |
|---|
| 2188 | 2266 | }; |
|---|
| 2189 | 2267 | |
|---|
| 2190 | 2268 | static const struct v4l2_subdev_ops imx415_subdev_ops = { |
|---|
| .. | .. |
|---|
| 2223 | 2301 | switch (ctrl->id) { |
|---|
| 2224 | 2302 | case V4L2_CID_EXPOSURE: |
|---|
| 2225 | 2303 | if (imx415->cur_mode->hdr_mode != NO_HDR) |
|---|
| 2226 | | - return ret; |
|---|
| 2304 | + goto ctrl_end; |
|---|
| 2227 | 2305 | shr0 = imx415->cur_vts - ctrl->val; |
|---|
| 2228 | 2306 | ret = imx415_write_reg(imx415->client, IMX415_LF_EXPO_REG_L, |
|---|
| 2229 | 2307 | IMX415_REG_VALUE_08BIT, |
|---|
| .. | .. |
|---|
| 2239 | 2317 | break; |
|---|
| 2240 | 2318 | case V4L2_CID_ANALOGUE_GAIN: |
|---|
| 2241 | 2319 | if (imx415->cur_mode->hdr_mode != NO_HDR) |
|---|
| 2242 | | - return ret; |
|---|
| 2320 | + goto ctrl_end; |
|---|
| 2243 | 2321 | ret = imx415_write_reg(imx415->client, IMX415_LF_GAIN_REG_H, |
|---|
| 2244 | 2322 | IMX415_REG_VALUE_08BIT, |
|---|
| 2245 | 2323 | IMX415_FETCH_GAIN_H(ctrl->val)); |
|---|
| .. | .. |
|---|
| 2308 | 2386 | break; |
|---|
| 2309 | 2387 | } |
|---|
| 2310 | 2388 | |
|---|
| 2389 | +ctrl_end: |
|---|
| 2311 | 2390 | pm_runtime_put(&client->dev); |
|---|
| 2312 | 2391 | |
|---|
| 2313 | 2392 | return ret; |
|---|
| .. | .. |
|---|
| 2337 | 2416 | V4L2_CID_LINK_FREQ, |
|---|
| 2338 | 2417 | ARRAY_SIZE(link_freq_items) - 1, 0, |
|---|
| 2339 | 2418 | link_freq_items); |
|---|
| 2340 | | - __v4l2_ctrl_s_ctrl(imx415->link_freq, mode->mipi_freq_idx); |
|---|
| 2419 | + v4l2_ctrl_s_ctrl(imx415->link_freq, mode->mipi_freq_idx); |
|---|
| 2341 | 2420 | |
|---|
| 2342 | 2421 | /* pixel rate = link frequency * 2 * lanes / BITS_PER_SAMPLE */ |
|---|
| 2343 | 2422 | pixel_rate = (u32)link_freq_items[mode->mipi_freq_idx] / mode->bpp * 2 * IMX415_4LANES; |
|---|