diff --git a/drivers/media/i2c/max96712.c b/drivers/media/i2c/max96712.c index f1a8dbace008..d5795f52e0d2 100644 --- a/drivers/media/i2c/max96712.c +++ b/drivers/media/i2c/max96712.c @@ -11,6 +11,8 @@ * support modes enable select. * auto initial deskew enable configure. * frame sync period enable configure. + * V1.3.00 t_lpx timing adjust from 53.4ns to 106.7ns. + * mipi dpll predef rate set api. * */ @@ -38,13 +40,13 @@ #include #include -#define DRIVER_VERSION KERNEL_VERSION(1, 0x02, 0x00) +#define DRIVER_VERSION KERNEL_VERSION(1, 0x03, 0x00) #ifndef V4L2_CID_DIGITAL_GAIN #define V4L2_CID_DIGITAL_GAIN V4L2_CID_GAIN #endif -#define MAX96712_LINK_FREQ_1000MHZ 1000000000UL +#define MAX96712_LINK_FREQ_MHZ(x) ((x) * 1000000UL) #define MAX96712_XVCLK_FREQ 25000000 #define MAX96712_CHIP_ID 0xA0 @@ -242,16 +244,7 @@ static const struct regval max96712_mipi_4lane_1920x1440_30fps[] = { { 0x29, 0x090A, 0xc0, 0x00 }, // MIPI PHY 0: 4 lanes, DPHY, 2bit VC { 0x29, 0x094A, 0xc0, 0x00 }, // MIPI PHY 1: 4 lanes, DPHY, 2bit VC // Turn on MIPI PHYs - { 0x29, 0x08A2, 0x30, 0x00 }, // Enable MIPI PHY 0/1 - // Hold DPLL in reset (config_soft_rst_n = 0) before changing the rate - { 0x29, 0x1C00, 0xf4, 0x00 }, - { 0x29, 0x1D00, 0xf4, 0x00 }, - // Set Data rate to be 2000Mbps/lane for port A and enable software override - { 0x29, 0x0415, 0x34, 0x00 }, // Enable freq fine tuning, 2000Mbps - { 0x29, 0x0418, 0x34, 0x00 }, // Enable freq fine tuning, 2000Mbps - // Release reset to DPLL (config_soft_rst_n = 1) - { 0x29, 0x1C00, 0xf5, 0x00 }, - { 0x29, 0x1D00, 0xf5, 0x00 }, + { 0x29, 0x08A2, 0x34, 0x00 }, // Enable MIPI PHY 0/1, t_lpx = 106.7ns // YUV422 8bit software override for all pipes since connected GMSL1 is under parallel mode { 0x29, 0x040B, 0x80, 0x00 }, // pipe 0 bpp=0x10: Datatypes = 0x22, 0x1E, 0x2E { 0x29, 0x040E, 0x5e, 0x00 }, // pipe 0 DT=0x1E: YUV422 8-bit @@ -278,7 +271,7 @@ static const struct max96712_mode supported_modes_4lane[] = { .denominator = 300000, }, .reg_list = max96712_mipi_4lane_1920x1440_30fps, - .link_freq_idx = 0, + .link_freq_idx = 10, .bus_fmt = MEDIA_BUS_FMT_UYVY8_2X8, .bpp = 16, .vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0, @@ -288,8 +281,34 @@ static const struct max96712_mode supported_modes_4lane[] = { }, }; +/* link freq = index * MAX96712_LINK_FREQ_MHZ(50) */ static const s64 link_freq_items[] = { - MAX96712_LINK_FREQ_1000MHZ, + MAX96712_LINK_FREQ_MHZ(0), + MAX96712_LINK_FREQ_MHZ(50), + MAX96712_LINK_FREQ_MHZ(100), + MAX96712_LINK_FREQ_MHZ(150), + MAX96712_LINK_FREQ_MHZ(200), + MAX96712_LINK_FREQ_MHZ(250), + MAX96712_LINK_FREQ_MHZ(300), + MAX96712_LINK_FREQ_MHZ(350), + MAX96712_LINK_FREQ_MHZ(400), + MAX96712_LINK_FREQ_MHZ(450), + MAX96712_LINK_FREQ_MHZ(500), + MAX96712_LINK_FREQ_MHZ(550), + MAX96712_LINK_FREQ_MHZ(600), + MAX96712_LINK_FREQ_MHZ(650), + MAX96712_LINK_FREQ_MHZ(700), + MAX96712_LINK_FREQ_MHZ(750), + MAX96712_LINK_FREQ_MHZ(800), + MAX96712_LINK_FREQ_MHZ(850), + MAX96712_LINK_FREQ_MHZ(900), + MAX96712_LINK_FREQ_MHZ(950), + MAX96712_LINK_FREQ_MHZ(1000), + MAX96712_LINK_FREQ_MHZ(1050), + MAX96712_LINK_FREQ_MHZ(1100), + MAX96712_LINK_FREQ_MHZ(1150), + MAX96712_LINK_FREQ_MHZ(1200), + MAX96712_LINK_FREQ_MHZ(1250), }; /* Write registers up to 4 at a time */ @@ -589,6 +608,108 @@ static irqreturn_t max96712_hot_plug_detect_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +static int __maybe_unused max96712_dphy_dpll_predef_set(struct i2c_client *client, + u32 link_freq_mhz) +{ + int ret = 0; + u8 dpll_val = 0, dpll_lock = 0; + u8 mipi_tx_phy_enable = 0; + + ret = max96712_read_reg(client, MAX96712_I2C_ADDR, + 0x08A2, MAX96712_REG_VALUE_08BIT, &mipi_tx_phy_enable); + if (ret) + return ret; + mipi_tx_phy_enable = (mipi_tx_phy_enable & 0xF0) >> 4; + + dev_info(&client->dev, "DPLL predef set: mipi_tx_phy_enable = 0x%02x, link_freq_mhz = %d\n", + mipi_tx_phy_enable, link_freq_mhz); + + // dphy max data rate is 2500MHz + if (link_freq_mhz > (2500 >> 1)) + link_freq_mhz = (2500 >> 1); + + dpll_val = DIV_ROUND_UP(link_freq_mhz * 2, 100) & 0x1F; + // Disable software override for frequency fine tuning + dpll_val |= BIT(5); + + // MIPI PHY0 + if (mipi_tx_phy_enable & BIT(0)) { + // Hold DPLL in reset (config_soft_rst_n = 0) before changing the rate + ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, + 0x1C00, + MAX96712_REG_VALUE_08BIT, + 0xf4); + // Set data rate and enable software override + ret |= max96712_update_reg_bits(client, MAX96712_I2C_ADDR, + 0x0415, 0x3F, dpll_val); + // Release reset to DPLL (config_soft_rst_n = 1) + ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, + 0x1C00, + MAX96712_REG_VALUE_08BIT, + 0xf5); + } + + // MIPI PHY1 + if (mipi_tx_phy_enable & BIT(1)) { + // Hold DPLL in reset (config_soft_rst_n = 0) before changing the rate + ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, + 0x1D00, + MAX96712_REG_VALUE_08BIT, + 0xf4); + // Set data rate and enable software override + ret |= max96712_update_reg_bits(client, MAX96712_I2C_ADDR, + 0x0418, 0x3F, dpll_val); + // Release reset to DPLL (config_soft_rst_n = 1) + ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, + 0x1D00, + MAX96712_REG_VALUE_08BIT, + 0xf5); + } + + // MIPI PHY2 + if (mipi_tx_phy_enable & BIT(2)) { + // Hold DPLL in reset (config_soft_rst_n = 0) before changing the rate + ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, + 0x1E00, + MAX96712_REG_VALUE_08BIT, + 0xf4); + // Set data rate and enable software override + ret |= max96712_update_reg_bits(client, MAX96712_I2C_ADDR, + 0x041B, 0x3F, dpll_val); + // Release reset to DPLL (config_soft_rst_n = 1) + ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, + 0x1E00, + MAX96712_REG_VALUE_08BIT, + 0xf5); + } + + // MIPI PHY3 + if (mipi_tx_phy_enable & BIT(3)) { + // Hold DPLL in reset (config_soft_rst_n = 0) before changing the rate + ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, + 0x1F00, + MAX96712_REG_VALUE_08BIT, + 0xf4); + // Set data rate and enable software override + ret |= max96712_update_reg_bits(client, MAX96712_I2C_ADDR, + 0x041E, 0x3F, dpll_val); + // Release reset to DPLL (config_soft_rst_n = 1) + ret |= max96712_write_reg(client, MAX96712_I2C_ADDR, + 0x1F00, + MAX96712_REG_VALUE_08BIT, + 0xf5); + } + + ret |= max96712_read_reg(client, MAX96712_I2C_ADDR, + 0x0400, MAX96712_REG_VALUE_08BIT, &dpll_lock); + if (ret) + return ret; + + dev_info(&client->dev, "DPLL predef set: dpll_lock = 0x%02x\n", dpll_lock); + + return ret; +} + static int max96712_auto_init_deskew(struct i2c_client *client, u32 deskew_mask) { int ret = 0; @@ -1070,6 +1191,7 @@ static long max96712_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd, static int __max96712_start_stream(struct max96712 *max96712) { int ret; + u32 link_freq_mhz, link_freq_idx; ret = max96712_check_link_lock_state(max96712); if (ret) @@ -1090,6 +1212,12 @@ static int __max96712_start_stream(struct max96712 *max96712) return ret; } + link_freq_idx = max96712->cur_mode->link_freq_idx; + link_freq_mhz = (u32)div_s64(link_freq_items[link_freq_idx], 1000000L); + ret = max96712_dphy_dpll_predef_set(max96712->client, link_freq_mhz); + if (ret) + return ret; + if (max96712->frame_sync_period != 0) { ret = max96712_frame_sync_period(max96712->client, max96712->frame_sync_period); @@ -1201,10 +1329,10 @@ static int __max96712_power_on(struct max96712 *max96712) u32 delay_us; struct device *dev = &max96712->client->dev; - if (!IS_ERR(max96712->power_gpio)) + if (!IS_ERR(max96712->power_gpio)) { gpiod_set_value_cansleep(max96712->power_gpio, 1); - - usleep_range(1000, 2000); + usleep_range(5000, 10000); + } if (!IS_ERR_OR_NULL(max96712->pins_default)) { ret = pinctrl_select_state(max96712->pinctrl, @@ -1221,10 +1349,11 @@ static int __max96712_power_on(struct max96712 *max96712) dev_err(dev, "Failed to enable regulators\n"); goto disable_clk; } - if (!IS_ERR(max96712->reset_gpio)) + if (!IS_ERR(max96712->reset_gpio)) { gpiod_set_value_cansleep(max96712->reset_gpio, 1); + usleep_range(500, 1000); + } - usleep_range(500, 1000); if (!IS_ERR(max96712->pwdn_gpio)) gpiod_set_value_cansleep(max96712->pwdn_gpio, 1); @@ -1258,10 +1387,11 @@ static void __max96712_power_off(struct max96712 *max96712) if (ret < 0) dev_dbg(dev, "could not set pins\n"); } - if (!IS_ERR(max96712->power_gpio)) - gpiod_set_value_cansleep(max96712->power_gpio, 0); regulator_bulk_disable(MAX96712_NUM_SUPPLIES, max96712->supplies); + + if (!IS_ERR(max96712->power_gpio)) + gpiod_set_value_cansleep(max96712->power_gpio, 0); } static int max96712_runtime_resume(struct device *dev) @@ -1332,7 +1462,7 @@ static int max96712_g_mbus_config(struct v4l2_subdev *sd, unsigned int pad, u8 data_lanes = max96712->bus_cfg.bus.mipi_csi2.num_data_lanes; val |= V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; - val |= 1 << (data_lanes - 1); + val |= (1 << (data_lanes - 1)); switch (data_lanes) { case 4: val |= V4L2_MBUS_CSI2_CHANNEL_3;