.. | .. |
---|
26 | 26 | #include <linux/version.h> |
---|
27 | 27 | #include <linux/videodev2.h> |
---|
28 | 28 | #include <linux/workqueue.h> |
---|
| 29 | +#include <linux/rk_hdmirx_class.h> |
---|
29 | 30 | #include <media/v4l2-controls_rockchip.h> |
---|
30 | 31 | #include <media/v4l2-ctrls.h> |
---|
31 | 32 | #include <media/v4l2-device.h> |
---|
.. | .. |
---|
54 | 55 | #define EDID_BLOCK_SIZE 128 |
---|
55 | 56 | |
---|
56 | 57 | #define RK628_CSI_LINK_FREQ_LOW 350000000 |
---|
57 | | -#define RK628_CSI_LINK_FREQ_HIGH 400000000 |
---|
| 58 | +#define RK628_CSI_LINK_FREQ_HIGH 600000000 |
---|
58 | 59 | #define RK628_CSI_PIXEL_RATE_LOW 400000000 |
---|
59 | 60 | #define RK628_CSI_PIXEL_RATE_HIGH 600000000 |
---|
60 | | -#define MIPI_DATARATE_MBPS_LOW 750 |
---|
| 61 | +#define MIPI_DATARATE_MBPS_LOW 700 |
---|
61 | 62 | #define MIPI_DATARATE_MBPS_HIGH 1250 |
---|
62 | 63 | |
---|
63 | 64 | #define POLL_INTERVAL_MS 1000 |
---|
.. | .. |
---|
126 | 127 | bool hpd_output_inverted; |
---|
127 | 128 | bool avi_rcv_rdy; |
---|
128 | 129 | bool vid_ints_en; |
---|
| 130 | + bool continues_clk; |
---|
129 | 131 | struct rk628_hdcp hdcp; |
---|
130 | 132 | bool i2s_enable_default; |
---|
131 | 133 | HAUDINFO audio_info; |
---|
132 | 134 | struct rk628_combtxphy *txphy; |
---|
133 | 135 | struct rk628_dsi dsi; |
---|
134 | 136 | const struct rk628_plat_data *plat_data; |
---|
| 137 | + struct device *classdev; |
---|
135 | 138 | }; |
---|
136 | 139 | |
---|
137 | 140 | struct rk628_csi_mode { |
---|
.. | .. |
---|
152 | 155 | .type = V4L2_DV_BT_656_1120, |
---|
153 | 156 | /* keep this initialization for compatibility with GCC < 4.4.6 */ |
---|
154 | 157 | .reserved = { 0 }, |
---|
155 | | - V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 400000000, |
---|
| 158 | + V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 600000000, |
---|
156 | 159 | V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | |
---|
157 | 160 | V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, |
---|
158 | 161 | V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_INTERLACED | |
---|
.. | .. |
---|
194 | 197 | 0x16, 0x20, 0x58, 0x2C, 0x25, 0x00, 0xC0, 0x6C, |
---|
195 | 198 | 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, |
---|
196 | 199 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC1, |
---|
| 200 | +}; |
---|
| 201 | + |
---|
| 202 | +static struct rkmodule_csi_dphy_param rk3588_dcphy_param = { |
---|
| 203 | + .vendor = PHY_VENDOR_SAMSUNG, |
---|
| 204 | + .lp_vol_ref = 0, |
---|
| 205 | + .lp_hys_sw = {3, 0, 0, 0}, |
---|
| 206 | + .lp_escclk_pol_sel = {1, 0, 0, 0}, |
---|
| 207 | + .skew_data_cal_clk = {0, 3, 3, 3}, |
---|
| 208 | + .clk_hs_term_sel = 2, |
---|
| 209 | + .data_hs_term_sel = {2, 2, 2, 2}, |
---|
| 210 | + .reserved = {0}, |
---|
197 | 211 | }; |
---|
198 | 212 | |
---|
199 | 213 | static const struct rk628_csi_mode supported_modes[] = { |
---|
.. | .. |
---|
492 | 506 | mutex_lock(&csi->confctl_mutex); |
---|
493 | 507 | csi->avi_rcv_rdy = false; |
---|
494 | 508 | plugin = tx_5v_power_present(sd); |
---|
| 509 | + v4l2_ctrl_s_ctrl(csi->detect_tx_5v_ctrl, plugin); |
---|
495 | 510 | v4l2_dbg(1, debug, sd, "%s: 5v_det:%d\n", __func__, plugin); |
---|
496 | 511 | if (plugin) { |
---|
497 | 512 | rk628_csi_enable_interrupts(sd, false); |
---|
.. | .. |
---|
872 | 887 | BYPASS_SELECT(1)); |
---|
873 | 888 | rk628_i2c_write(csi->rk628, CSITX_CONFIG_DONE, CONFIG_DONE_IMD); |
---|
874 | 889 | rk628_i2c_write(csi->rk628, CSITX_SYS_CTRL2, VOP_WHOLE_FRM_EN | VSYNC_ENABLE); |
---|
875 | | - rk628_i2c_update_bits(csi->rk628, CSITX_SYS_CTRL3_IMD, |
---|
| 890 | + if (csi->continues_clk) |
---|
| 891 | + rk628_i2c_update_bits(csi->rk628, CSITX_SYS_CTRL3_IMD, |
---|
| 892 | + CONT_MODE_CLK_CLR_MASK | |
---|
| 893 | + CONT_MODE_CLK_SET_MASK | |
---|
| 894 | + NON_CONTINUOUS_MODE_MASK, |
---|
| 895 | + CONT_MODE_CLK_CLR(0) | |
---|
| 896 | + CONT_MODE_CLK_SET(1) | |
---|
| 897 | + NON_CONTINUOUS_MODE(0)); |
---|
| 898 | + else |
---|
| 899 | + rk628_i2c_update_bits(csi->rk628, CSITX_SYS_CTRL3_IMD, |
---|
876 | 900 | CONT_MODE_CLK_CLR_MASK | |
---|
877 | 901 | CONT_MODE_CLK_SET_MASK | |
---|
878 | 902 | NON_CONTINUOUS_MODE_MASK, |
---|
.. | .. |
---|
1476 | 1500 | return 0; |
---|
1477 | 1501 | } |
---|
1478 | 1502 | |
---|
1479 | | -static int rk628_csi_get_ctrl(struct v4l2_ctrl *ctrl) |
---|
1480 | | -{ |
---|
1481 | | - int ret = -1; |
---|
1482 | | - struct rk628_csi *csi = container_of(ctrl->handler, struct rk628_csi, |
---|
1483 | | - hdl); |
---|
1484 | | - struct v4l2_subdev *sd = &(csi->sd); |
---|
1485 | | - |
---|
1486 | | - if (ctrl->id == V4L2_CID_DV_RX_POWER_PRESENT) { |
---|
1487 | | - ret = tx_5v_power_present(sd); |
---|
1488 | | - *ctrl->p_new.p_s32 = ret; |
---|
1489 | | - } |
---|
1490 | | - |
---|
1491 | | - return ret; |
---|
1492 | | -} |
---|
1493 | | - |
---|
1494 | 1503 | static int rk628_csi_enum_frame_sizes(struct v4l2_subdev *sd, |
---|
1495 | 1504 | struct v4l2_subdev_pad_config *cfg, |
---|
1496 | 1505 | struct v4l2_subdev_frame_size_enum *fse) |
---|
.. | .. |
---|
1541 | 1550 | format->format.field = csi->timings.bt.interlaced ? |
---|
1542 | 1551 | V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE; |
---|
1543 | 1552 | mutex_unlock(&csi->confctl_mutex); |
---|
| 1553 | + |
---|
| 1554 | + if (((csi->timings.bt.width == 3840) && (csi->timings.bt.height == 2160)) || |
---|
| 1555 | + csi->csi_lanes_in_use <= 2) { |
---|
| 1556 | + v4l2_dbg(1, debug, sd, |
---|
| 1557 | + "%s res wxh:%dx%d, link freq:%llu, pixrate:%u\n", |
---|
| 1558 | + __func__, csi->timings.bt.width, csi->timings.bt.height, |
---|
| 1559 | + link_freq_menu_items[1], RK628_CSI_PIXEL_RATE_HIGH); |
---|
| 1560 | + __v4l2_ctrl_s_ctrl(csi->link_freq, 1); |
---|
| 1561 | + __v4l2_ctrl_s_ctrl_int64(csi->pixel_rate, |
---|
| 1562 | + RK628_CSI_PIXEL_RATE_HIGH); |
---|
| 1563 | + } else { |
---|
| 1564 | + v4l2_dbg(1, debug, sd, |
---|
| 1565 | + "%s res wxh:%dx%d, link freq:%llu, pixrate:%u\n", |
---|
| 1566 | + __func__, csi->timings.bt.width, csi->timings.bt.height, |
---|
| 1567 | + link_freq_menu_items[0], RK628_CSI_PIXEL_RATE_LOW); |
---|
| 1568 | + __v4l2_ctrl_s_ctrl(csi->link_freq, 0); |
---|
| 1569 | + __v4l2_ctrl_s_ctrl_int64(csi->pixel_rate, |
---|
| 1570 | + RK628_CSI_PIXEL_RATE_LOW); |
---|
| 1571 | + } |
---|
1544 | 1572 | |
---|
1545 | 1573 | v4l2_dbg(1, debug, sd, "%s: fmt code:%d, w:%d, h:%d, field code:%d\n", |
---|
1546 | 1574 | __func__, format->format.code, format->format.width, |
---|
.. | .. |
---|
1614 | 1642 | csi->mbus_fmt_code = format->format.code; |
---|
1615 | 1643 | mode = rk628_csi_find_best_fit(format); |
---|
1616 | 1644 | csi->cur_mode = mode; |
---|
1617 | | - |
---|
1618 | | - if ((mode->width == 3840) && (mode->height == 2160)) { |
---|
1619 | | - v4l2_dbg(1, debug, sd, |
---|
1620 | | - "%s res wxh:%dx%d, link freq:%llu, pixrate:%u\n", |
---|
1621 | | - __func__, mode->width, mode->height, |
---|
1622 | | - link_freq_menu_items[1], RK628_CSI_PIXEL_RATE_HIGH); |
---|
1623 | | - __v4l2_ctrl_s_ctrl(csi->link_freq, 1); |
---|
1624 | | - __v4l2_ctrl_s_ctrl_int64(csi->pixel_rate, |
---|
1625 | | - RK628_CSI_PIXEL_RATE_HIGH); |
---|
1626 | | - } else { |
---|
1627 | | - v4l2_dbg(1, debug, sd, |
---|
1628 | | - "%s res wxh:%dx%d, link freq:%llu, pixrate:%u\n", |
---|
1629 | | - __func__, mode->width, mode->height, |
---|
1630 | | - link_freq_menu_items[0], RK628_CSI_PIXEL_RATE_LOW); |
---|
1631 | | - __v4l2_ctrl_s_ctrl(csi->link_freq, 0); |
---|
1632 | | - __v4l2_ctrl_s_ctrl_int64(csi->pixel_rate, |
---|
1633 | | - RK628_CSI_PIXEL_RATE_LOW); |
---|
1634 | | - } |
---|
1635 | 1645 | |
---|
1636 | 1646 | enable_stream(sd, false); |
---|
1637 | 1647 | |
---|
.. | .. |
---|
1778 | 1788 | { |
---|
1779 | 1789 | struct rk628_csi *csi = to_csi(sd); |
---|
1780 | 1790 | long ret = 0; |
---|
| 1791 | + struct rkmodule_csi_dphy_param *dphy_param; |
---|
1781 | 1792 | |
---|
1782 | 1793 | switch (cmd) { |
---|
1783 | 1794 | case RKMODULE_GET_MODULE_INFO: |
---|
1784 | 1795 | rk628_csi_get_module_inf(csi, (struct rkmodule_inf *)arg); |
---|
| 1796 | + break; |
---|
| 1797 | + case RKMODULE_GET_HDMI_MODE: |
---|
| 1798 | + *(int *)arg = RKMODULE_HDMIIN_MODE; |
---|
| 1799 | + break; |
---|
| 1800 | + case RKMODULE_SET_CSI_DPHY_PARAM: |
---|
| 1801 | + dphy_param = (struct rkmodule_csi_dphy_param *)arg; |
---|
| 1802 | + if (dphy_param->vendor == PHY_VENDOR_SAMSUNG) |
---|
| 1803 | + rk3588_dcphy_param = *dphy_param; |
---|
| 1804 | + v4l2_dbg(1, debug, sd, |
---|
| 1805 | + "sensor set dphy param\n"); |
---|
| 1806 | + break; |
---|
| 1807 | + case RKMODULE_GET_CSI_DPHY_PARAM: |
---|
| 1808 | + dphy_param = (struct rkmodule_csi_dphy_param *)arg; |
---|
| 1809 | + *dphy_param = rk3588_dcphy_param; |
---|
| 1810 | + |
---|
| 1811 | + v4l2_dbg(1, debug, sd, |
---|
| 1812 | + "sensor get dphy param\n"); |
---|
1785 | 1813 | break; |
---|
1786 | 1814 | default: |
---|
1787 | 1815 | ret = -ENOIOCTLCMD; |
---|
.. | .. |
---|
1811 | 1839 | rk628_txphy_set_bus_width(csi->rk628, bus_width); |
---|
1812 | 1840 | rk628_txphy_set_mode(csi->rk628, PHY_MODE_VIDEO_MIPI); |
---|
1813 | 1841 | |
---|
| 1842 | + if (csi->lane_mbps == MIPI_DATARATE_MBPS_HIGH) |
---|
| 1843 | + mipi_dphy_init_hsmanual(csi->rk628, true); |
---|
| 1844 | + else |
---|
| 1845 | + mipi_dphy_init_hsmanual(csi->rk628, false); |
---|
1814 | 1846 | mipi_dphy_init_hsfreqrange(csi->rk628, csi->lane_mbps); |
---|
1815 | 1847 | usleep_range(1500, 2000); |
---|
1816 | 1848 | rk628_txphy_power_on(csi->rk628); |
---|
.. | .. |
---|
1840 | 1872 | void __user *up = compat_ptr(arg); |
---|
1841 | 1873 | struct rkmodule_inf *inf; |
---|
1842 | 1874 | long ret; |
---|
| 1875 | + int *seq; |
---|
| 1876 | + struct rkmodule_csi_dphy_param *dphy_param; |
---|
1843 | 1877 | |
---|
1844 | 1878 | switch (cmd) { |
---|
1845 | 1879 | case RKMODULE_GET_MODULE_INFO: |
---|
.. | .. |
---|
1857 | 1891 | } |
---|
1858 | 1892 | kfree(inf); |
---|
1859 | 1893 | break; |
---|
| 1894 | + case RKMODULE_GET_HDMI_MODE: |
---|
| 1895 | + seq = kzalloc(sizeof(*seq), GFP_KERNEL); |
---|
| 1896 | + if (!seq) { |
---|
| 1897 | + ret = -ENOMEM; |
---|
| 1898 | + return ret; |
---|
| 1899 | + } |
---|
1860 | 1900 | |
---|
| 1901 | + ret = rk628_csi_ioctl(sd, cmd, seq); |
---|
| 1902 | + if (!ret) { |
---|
| 1903 | + ret = copy_to_user(up, seq, sizeof(*seq)); |
---|
| 1904 | + if (ret) |
---|
| 1905 | + ret = -EFAULT; |
---|
| 1906 | + } |
---|
| 1907 | + kfree(seq); |
---|
| 1908 | + break; |
---|
| 1909 | + case RKMODULE_SET_CSI_DPHY_PARAM: |
---|
| 1910 | + dphy_param = kzalloc(sizeof(*dphy_param), GFP_KERNEL); |
---|
| 1911 | + if (!dphy_param) { |
---|
| 1912 | + ret = -ENOMEM; |
---|
| 1913 | + return ret; |
---|
| 1914 | + } |
---|
| 1915 | + |
---|
| 1916 | + ret = copy_from_user(dphy_param, up, sizeof(*dphy_param)); |
---|
| 1917 | + if (!ret) |
---|
| 1918 | + ret = rk628_csi_ioctl(sd, cmd, dphy_param); |
---|
| 1919 | + else |
---|
| 1920 | + ret = -EFAULT; |
---|
| 1921 | + kfree(dphy_param); |
---|
| 1922 | + break; |
---|
| 1923 | + case RKMODULE_GET_CSI_DPHY_PARAM: |
---|
| 1924 | + dphy_param = kzalloc(sizeof(*dphy_param), GFP_KERNEL); |
---|
| 1925 | + if (!dphy_param) { |
---|
| 1926 | + ret = -ENOMEM; |
---|
| 1927 | + return ret; |
---|
| 1928 | + } |
---|
| 1929 | + |
---|
| 1930 | + ret = rk628_csi_ioctl(sd, cmd, dphy_param); |
---|
| 1931 | + if (!ret) { |
---|
| 1932 | + ret = copy_to_user(up, dphy_param, sizeof(*dphy_param)); |
---|
| 1933 | + if (ret) |
---|
| 1934 | + ret = -EFAULT; |
---|
| 1935 | + } |
---|
| 1936 | + kfree(dphy_param); |
---|
| 1937 | + break; |
---|
1861 | 1938 | default: |
---|
1862 | 1939 | ret = -ENOIOCTLCMD; |
---|
1863 | 1940 | break; |
---|
.. | .. |
---|
1866 | 1943 | return ret; |
---|
1867 | 1944 | } |
---|
1868 | 1945 | #endif |
---|
1869 | | - |
---|
1870 | | -static const struct v4l2_ctrl_ops rk628_csi_ctrl_ops = { |
---|
1871 | | - .g_volatile_ctrl = rk628_csi_get_ctrl, |
---|
1872 | | -}; |
---|
1873 | 1946 | |
---|
1874 | 1947 | static const struct v4l2_subdev_core_ops rk628_csi_core_ops = { |
---|
1875 | 1948 | .interrupt_service_routine = rk628_csi_isr, |
---|
.. | .. |
---|
1971 | 2044 | int ret = -EINVAL; |
---|
1972 | 2045 | bool hdcp1x_enable = false, i2s_enable_default = false; |
---|
1973 | 2046 | bool scaler_en = false; |
---|
| 2047 | + bool continues_clk = false; |
---|
1974 | 2048 | |
---|
1975 | 2049 | csi->soc_24M = devm_clk_get(dev, "soc_24M"); |
---|
1976 | 2050 | if (csi->soc_24M == ERR_PTR(-ENOENT)) |
---|
.. | .. |
---|
1986 | 2060 | if (IS_ERR(csi->enable_gpio)) { |
---|
1987 | 2061 | ret = PTR_ERR(csi->enable_gpio); |
---|
1988 | 2062 | dev_err(dev, "failed to request enable GPIO: %d\n", ret); |
---|
1989 | | - return ret; |
---|
| 2063 | + goto clk_put; |
---|
1990 | 2064 | } |
---|
1991 | 2065 | |
---|
1992 | 2066 | csi->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); |
---|
1993 | 2067 | if (IS_ERR(csi->reset_gpio)) { |
---|
1994 | 2068 | ret = PTR_ERR(csi->reset_gpio); |
---|
1995 | 2069 | dev_err(dev, "failed to request reset GPIO: %d\n", ret); |
---|
1996 | | - return ret; |
---|
| 2070 | + goto clk_put; |
---|
1997 | 2071 | } |
---|
1998 | 2072 | |
---|
1999 | 2073 | csi->power_gpio = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_HIGH); |
---|
2000 | 2074 | if (IS_ERR(csi->power_gpio)) { |
---|
2001 | 2075 | dev_err(dev, "failed to get power gpio\n"); |
---|
2002 | 2076 | ret = PTR_ERR(csi->power_gpio); |
---|
2003 | | - return ret; |
---|
| 2077 | + goto clk_put; |
---|
2004 | 2078 | } |
---|
2005 | 2079 | |
---|
2006 | 2080 | csi->plugin_det_gpio = devm_gpiod_get_optional(dev, "plugin-det", |
---|
.. | .. |
---|
2008 | 2082 | if (IS_ERR(csi->plugin_det_gpio)) { |
---|
2009 | 2083 | dev_err(dev, "failed to get hdmirx det gpio\n"); |
---|
2010 | 2084 | ret = PTR_ERR(csi->plugin_det_gpio); |
---|
2011 | | - return ret; |
---|
| 2085 | + goto clk_put; |
---|
2012 | 2086 | } |
---|
2013 | 2087 | |
---|
2014 | 2088 | if (csi->enable_gpio) { |
---|
.. | .. |
---|
2043 | 2117 | if (of_property_read_bool(dev->of_node, "scaler-en")) |
---|
2044 | 2118 | scaler_en = true; |
---|
2045 | 2119 | |
---|
| 2120 | + if (of_property_read_bool(dev->of_node, "continues-clk")) |
---|
| 2121 | + continues_clk = true; |
---|
| 2122 | + |
---|
2046 | 2123 | ep = of_graph_get_next_endpoint(dev->of_node, NULL); |
---|
2047 | 2124 | if (!ep) { |
---|
2048 | 2125 | dev_err(dev, "missing endpoint node\n"); |
---|
2049 | | - return -EINVAL; |
---|
| 2126 | + ret = -EINVAL; |
---|
| 2127 | + goto clk_put; |
---|
2050 | 2128 | } |
---|
2051 | 2129 | |
---|
2052 | 2130 | ret = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(ep), &endpoint); |
---|
.. | .. |
---|
2067 | 2145 | csi->scaler_en = scaler_en; |
---|
2068 | 2146 | if (csi->scaler_en) |
---|
2069 | 2147 | csi->timings = dst_timing; |
---|
| 2148 | + csi->continues_clk = continues_clk; |
---|
2070 | 2149 | |
---|
2071 | 2150 | csi->rxphy_pwron = false; |
---|
2072 | 2151 | csi->txphy_pwron = false; |
---|
.. | .. |
---|
2080 | 2159 | v4l2_fwnode_endpoint_free(&endpoint); |
---|
2081 | 2160 | put_node: |
---|
2082 | 2161 | of_node_put(ep); |
---|
| 2162 | +clk_put: |
---|
| 2163 | + clk_disable_unprepare(csi->soc_24M); |
---|
2083 | 2164 | |
---|
2084 | 2165 | return ret; |
---|
2085 | 2166 | } |
---|
.. | .. |
---|
2108 | 2189 | {} |
---|
2109 | 2190 | }; |
---|
2110 | 2191 | MODULE_DEVICE_TABLE(of, rk628_csi_of_match); |
---|
| 2192 | + |
---|
| 2193 | +static bool tx_5v_power_present(struct v4l2_subdev *sd); |
---|
| 2194 | + |
---|
| 2195 | +static ssize_t audio_rate_show(struct device *dev, |
---|
| 2196 | + struct device_attribute *attr, char *buf) |
---|
| 2197 | +{ |
---|
| 2198 | + struct rk628_csi *csi = dev_get_drvdata(dev); |
---|
| 2199 | + |
---|
| 2200 | + return snprintf(buf, PAGE_SIZE, "%d", rk628_hdmirx_audio_fs(csi->audio_info)); |
---|
| 2201 | +} |
---|
| 2202 | + |
---|
| 2203 | +static ssize_t audio_present_show(struct device *dev, |
---|
| 2204 | + struct device_attribute *attr, char *buf) |
---|
| 2205 | +{ |
---|
| 2206 | + struct rk628_csi *csi = dev_get_drvdata(dev); |
---|
| 2207 | + |
---|
| 2208 | + return snprintf(buf, PAGE_SIZE, "%d", |
---|
| 2209 | + tx_5v_power_present(&csi->sd) ? |
---|
| 2210 | + rk628_hdmirx_audio_present(csi->audio_info) : 0); |
---|
| 2211 | +} |
---|
| 2212 | + |
---|
| 2213 | +static DEVICE_ATTR_RO(audio_rate); |
---|
| 2214 | +static DEVICE_ATTR_RO(audio_present); |
---|
| 2215 | + |
---|
| 2216 | +static struct attribute *rk628_attrs[] = { |
---|
| 2217 | + &dev_attr_audio_rate.attr, |
---|
| 2218 | + &dev_attr_audio_present.attr, |
---|
| 2219 | + NULL |
---|
| 2220 | +}; |
---|
| 2221 | +ATTRIBUTE_GROUPS(rk628); |
---|
2111 | 2222 | |
---|
2112 | 2223 | static int rk628_csi_probe(struct i2c_client *client, |
---|
2113 | 2224 | const struct i2c_device_id *id) |
---|
.. | .. |
---|
2203 | 2314 | V4L2_CID_PIXEL_RATE, 0, RK628_CSI_PIXEL_RATE_HIGH, 1, |
---|
2204 | 2315 | RK628_CSI_PIXEL_RATE_HIGH); |
---|
2205 | 2316 | csi->detect_tx_5v_ctrl = v4l2_ctrl_new_std(&csi->hdl, |
---|
2206 | | - &rk628_csi_ctrl_ops, V4L2_CID_DV_RX_POWER_PRESENT, |
---|
| 2317 | + NULL, V4L2_CID_DV_RX_POWER_PRESENT, |
---|
2207 | 2318 | 0, 1, 0, 0); |
---|
2208 | | - if (csi->detect_tx_5v_ctrl) |
---|
2209 | | - csi->detect_tx_5v_ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; |
---|
2210 | 2319 | |
---|
2211 | 2320 | /* custom controls */ |
---|
2212 | 2321 | csi->audio_sampling_rate_ctrl = v4l2_ctrl_new_custom(&csi->hdl, |
---|
.. | .. |
---|
2255 | 2364 | goto err_hdl; |
---|
2256 | 2365 | } |
---|
2257 | 2366 | |
---|
| 2367 | + csi->classdev = device_create_with_groups(rk_hdmirx_class(), |
---|
| 2368 | + dev, MKDEV(0, 0), |
---|
| 2369 | + csi, |
---|
| 2370 | + rk628_groups, |
---|
| 2371 | + "rk628"); |
---|
| 2372 | + if (IS_ERR(csi->classdev)) |
---|
| 2373 | + goto err_hdl; |
---|
| 2374 | + |
---|
2258 | 2375 | INIT_DELAYED_WORK(&csi->delayed_work_enable_hotplug, |
---|
2259 | 2376 | rk628_csi_delayed_work_enable_hotplug); |
---|
2260 | 2377 | INIT_DELAYED_WORK(&csi->delayed_work_res_change, |
---|