From 2f7c68cb55ecb7331f2381deb497c27155f32faf Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Wed, 03 Jan 2024 09:43:39 +0000 Subject: [PATCH] update kernel to 5.10.198 --- kernel/drivers/media/i2c/maxim4c/maxim4c_drv.c | 188 +++++++++++++++++++++++++++++++++++++++------- 1 files changed, 159 insertions(+), 29 deletions(-) diff --git a/kernel/drivers/media/i2c/maxim4c/maxim4c_drv.c b/kernel/drivers/media/i2c/maxim4c/maxim4c_drv.c index 88924dc..c543c62 100644 --- a/kernel/drivers/media/i2c/maxim4c/maxim4c_drv.c +++ b/kernel/drivers/media/i2c/maxim4c/maxim4c_drv.c @@ -22,6 +22,26 @@ * 5. power control: local by pwdn gpio, remote by pocen gpio * 6. local pwdn on/off enable depend on MAXIM4C_LOCAL_DES_ON_OFF_EN * + * V2.02.00 + * 1. Force all MIPI clocks running Setting in csi out enable. + * 2. Pattern mode force_clock_out_en default enable. + * + * V2.03.00 + * 1. remote device add the maxim4c prefix to driver name. + * + * V2.04.04 + * 1. Add regulator supplier dependencies. + * 2. Add config ssc-ratio property + * 3. Add debugfs entry to change MIPI timing + * 4. Use PM runtime autosuspend feature + * 5. Fix unbalanced disabling for PoC regulator + * 6. MIPI VC count does not affected by data lane count + * + * V2.05.00 + * 1. local device power on add some delay for i2c normal access. + * 2. enable hot plug detect for partial links are locked. + * 3. remote device hot plug init disable lock irq. + * */ #include <linux/clk.h> #include <linux/i2c.h> @@ -51,9 +71,14 @@ #include "maxim4c_api.h" -#define DRIVER_VERSION KERNEL_VERSION(2, 0x01, 0x00) +#define DRIVER_VERSION KERNEL_VERSION(2, 0x05, 0x00) #define MAXIM4C_XVCLK_FREQ 25000000 + +static const char *const maxim4c_supply_names[MAXIM4C_NUM_SUPPLIES] = { + "vcc1v2", + "vcc1v8", +}; static int maxim4c_check_local_chipid(maxim4c_t *maxim4c) { @@ -83,8 +108,8 @@ return 0; } } else { + // if chipid is unexpected, retry dev_err(dev, "Unexpected maxim chipid = %02x\n", chipid); - return -ENODEV; } } } @@ -115,7 +140,7 @@ queue_delayed_work(maxim4c->hot_plug_work.state_check_wq, &maxim4c->hot_plug_work.state_d_work, - msecs_to_jiffies(50)); + msecs_to_jiffies(100)); } mutex_unlock(&maxim4c->mutex); @@ -189,7 +214,13 @@ if (curr_lock_state & MAXIM4C_LINK_MASK_A) { dev_info(dev, "Link A plug in\n"); + if (maxim4c->hot_plug_irq > 0) + disable_irq(maxim4c->hot_plug_irq); + maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_A); + + if (maxim4c->hot_plug_irq > 0) + enable_irq(maxim4c->hot_plug_irq); maxim4c_video_pipe_linkid_enable(maxim4c, link_id, true); } else { @@ -205,7 +236,13 @@ if (curr_lock_state & MAXIM4C_LINK_MASK_B) { dev_info(dev, "Link B plug in\n"); + if (maxim4c->hot_plug_irq > 0) + disable_irq(maxim4c->hot_plug_irq); + maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_B); + + if (maxim4c->hot_plug_irq > 0) + enable_irq(maxim4c->hot_plug_irq); maxim4c_video_pipe_linkid_enable(maxim4c, link_id, true); } else { @@ -221,7 +258,13 @@ if (curr_lock_state & MAXIM4C_LINK_MASK_C) { dev_info(dev, "Link C plug in\n"); + if (maxim4c->hot_plug_irq > 0) + disable_irq(maxim4c->hot_plug_irq); + maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_C); + + if (maxim4c->hot_plug_irq > 0) + enable_irq(maxim4c->hot_plug_irq); maxim4c_video_pipe_linkid_enable(maxim4c, link_id, true); } else { @@ -237,7 +280,13 @@ if (curr_lock_state & MAXIM4C_LINK_MASK_D) { dev_info(dev, "Link D plug in\n"); + if (maxim4c->hot_plug_irq > 0) + disable_irq(maxim4c->hot_plug_irq); + maxim4c_remote_devices_init(maxim4c, MAXIM4C_LINK_MASK_D); + + if (maxim4c->hot_plug_irq > 0) + enable_irq(maxim4c->hot_plug_irq); maxim4c_video_pipe_linkid_enable(maxim4c, link_id, true); } else { @@ -253,10 +302,32 @@ } else { queue_delayed_work(maxim4c->hot_plug_work.state_check_wq, &maxim4c->hot_plug_work.state_d_work, - msecs_to_jiffies(100)); + msecs_to_jiffies(200)); } mutex_unlock(&maxim4c->mutex); +} + +int maxim4c_hot_plug_detect_work_start(maxim4c_t *maxim4c) +{ + struct device *dev = &maxim4c->client->dev; + u8 link_lock_state = 0, link_enable_mask = 0; + + link_lock_state = maxim4c->link_lock_state; + link_enable_mask = maxim4c->gmsl_link.link_enable_mask; + + if (link_lock_state != link_enable_mask) { + dev_info(dev, "%s: link_lock = 0x%02x, link_mask = 0x%02x\n", + __func__, link_lock_state, link_enable_mask); + + maxim4c->hot_plug_state = MAXIM4C_HOT_PLUG_OUT; + + queue_delayed_work(maxim4c->hot_plug_work.state_check_wq, + &maxim4c->hot_plug_work.state_d_work, + msecs_to_jiffies(200)); + } + + return 0; } static int maxim4c_lock_state_work_init(maxim4c_t *maxim4c) @@ -295,13 +366,20 @@ static int maxim4c_local_device_power_on(maxim4c_t *maxim4c) { struct device *dev = &maxim4c->client->dev; + int ret; + + ret = regulator_bulk_enable(MAXIM4C_NUM_SUPPLIES, maxim4c->supplies); + if (ret < 0) { + dev_err(dev, "Failed to enable regulators\n"); + return -EINVAL; + } if (!IS_ERR(maxim4c->pwdn_gpio)) { dev_info(dev, "local device pwdn gpio on\n"); gpiod_set_value_cansleep(maxim4c->pwdn_gpio, 1); - usleep_range(5000, 10000); + usleep_range(10000, 11000); } return 0; @@ -310,24 +388,30 @@ static void maxim4c_local_device_power_off(maxim4c_t *maxim4c) { struct device *dev = &maxim4c->client->dev; + int ret; if (!IS_ERR(maxim4c->pwdn_gpio)) { dev_info(dev, "local device pwdn gpio off\n"); gpiod_set_value_cansleep(maxim4c->pwdn_gpio, 0); } + + ret = regulator_bulk_disable(MAXIM4C_NUM_SUPPLIES, maxim4c->supplies); + if (ret < 0) { + dev_warn(dev, "Failed to disable regulators\n"); + } } static int maxim4c_remote_device_power_on(maxim4c_t *maxim4c) { struct device *dev = &maxim4c->client->dev; + int ret; - // remote PoC enable - if (!IS_ERR(maxim4c->pocen_gpio)) { - dev_info(dev, "remote device pocen gpio on\n"); - - gpiod_set_value_cansleep(maxim4c->pocen_gpio, 1); - usleep_range(5000, 10000); + dev_dbg(dev, "Turn PoC on\n"); + ret = regulator_enable(maxim4c->poc_regulator); + if (ret < 0) { + dev_err(dev, "Unable to turn PoC on\n"); + return ret; } return 0; @@ -336,13 +420,12 @@ static int maxim4c_remote_device_power_off(maxim4c_t *maxim4c) { struct device *dev = &maxim4c->client->dev; + int ret; - // remote PoC enable - if (!IS_ERR(maxim4c->pocen_gpio)) { - dev_info(dev, "remote device pocen gpio off\n"); - - gpiod_set_value_cansleep(maxim4c->pocen_gpio, 0); - } + dev_dbg(dev, "Turn PoC off\n"); + ret = regulator_disable(maxim4c->poc_regulator); + if (ret < 0) + dev_warn(dev, "Unable to turn PoC off\n"); return 0; } @@ -574,6 +657,7 @@ maxim4c_t *maxim4c = NULL; u32 chip_id; int ret = 0; + unsigned int i; dev_info(dev, "driver version: %02x.%02x.%02x", DRIVER_VERSION >> 16, (DRIVER_VERSION & 0xff00) >> 8, DRIVER_VERSION & 0x00ff); @@ -613,20 +697,53 @@ maxim4c->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_OUT_LOW); if (IS_ERR(maxim4c->pwdn_gpio)) dev_warn(dev, "Failed to get pwdn-gpios, maybe no use\n"); - - maxim4c->pocen_gpio = devm_gpiod_get(dev, "pocen", GPIOD_OUT_LOW); - if (IS_ERR(maxim4c->pocen_gpio)) - dev_warn(dev, "Failed to get pocen-gpios\n"); + else + usleep_range(1000, 1100); maxim4c->lock_gpio = devm_gpiod_get(dev, "lock", GPIOD_IN); if (IS_ERR(maxim4c->lock_gpio)) dev_warn(dev, "Failed to get lock-gpios\n"); + + for (i = 0; i < MAXIM4C_NUM_SUPPLIES; i++) + maxim4c->supplies[i].supply = maxim4c_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, MAXIM4C_NUM_SUPPLIES, + maxim4c->supplies); + if (ret < 0) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "Unable to get supply regulators\n"); + else + dev_warn(dev, "Get PoC regulator deferred\n"); + return ret; + } + + maxim4c->poc_regulator = devm_regulator_get(dev, "poc"); + if (IS_ERR(maxim4c->poc_regulator)) { + if (PTR_ERR(maxim4c->poc_regulator) != -EPROBE_DEFER) + dev_err(dev, "Unable to get PoC regulator (%ld)\n", + PTR_ERR(maxim4c->poc_regulator)); + else + dev_err(dev, "Get PoC regulator deferred\n"); + + ret = PTR_ERR(maxim4c->poc_regulator); +#if !MAXIM4C_TEST_PATTERN + return ret; +#endif + } mutex_init(&maxim4c->mutex); ret = maxim4c_local_device_power_on(maxim4c); if (ret) goto err_destroy_mutex; + + ret = maxim4c_remote_device_power_on(maxim4c); + if (ret) + dev_warn(dev, "Power on PoC regulator failed\n"); + + pm_runtime_set_active(dev); + pm_runtime_get_noresume(dev); + pm_runtime_enable(dev); ret = maxim4c_check_local_chipid(maxim4c); if (ret) @@ -651,9 +768,10 @@ goto err_power_off; #endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */ - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - pm_runtime_idle(dev); + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); return 0; #endif /* MAXIM4C_TEST_PATTERN */ @@ -661,28 +779,38 @@ maxim4c_module_data_init(maxim4c); maxim4c_module_parse_dt(maxim4c); + ret = maxim4c_dbgfs_init(maxim4c); + if (ret) + goto err_subdev_deinit; + #if (MAXIM4C_LOCAL_DES_ON_OFF_EN == 0) ret = maxim4c_module_hw_init(maxim4c); if (ret) - goto err_subdev_deinit; + goto err_dbgfs_deinit; #endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */ ret = maxim4c_remote_mfd_add_devices(maxim4c); if (ret) - goto err_subdev_deinit; + goto err_dbgfs_deinit; maxim4c_lock_irq_init(maxim4c); maxim4c_lock_state_work_init(maxim4c); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - pm_runtime_idle(dev); + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); return 0; +err_dbgfs_deinit: + maxim4c_dbgfs_deinit(maxim4c); err_subdev_deinit: maxim4c_v4l2_subdev_deinit(maxim4c); err_power_off: + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + maxim4c_remote_device_power_off(maxim4c); maxim4c_local_device_power_off(maxim4c); err_destroy_mutex: mutex_destroy(&maxim4c->mutex); @@ -696,6 +824,8 @@ maxim4c_lock_state_work_deinit(maxim4c); + maxim4c_dbgfs_deinit(maxim4c); + maxim4c_v4l2_subdev_deinit(maxim4c); mutex_destroy(&maxim4c->mutex); -- Gitblit v1.6.2