diff options
author | Hans de Goede <hdegoede@redhat.com> | 2022-01-17 00:52:00 +0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@kernel.org> | 2022-02-08 08:28:37 +0300 |
commit | 74bfe151d0aa06c76d35ae5ee02f6897240a2094 (patch) | |
tree | 4d69461212cd2d8fab5e645450cc9ff1bccf72ca | |
parent | 9bad7640dcd64d7054601b0f43b52a0af387413f (diff) | |
download | linux-74bfe151d0aa06c76d35ae5ee02f6897240a2094.tar.xz |
media: atomisp_gmin_platform: Add enable-count to gmin_[v1p8|v2p8]_ctrl()
On devices with 2 sensors the 2 sensors may get probed simultaneously
and the v1p8 and v2p8 regulators are ususally shared between the
2 sensors.
This means that the probe() function of sensor 1 may end up calling
gmin_v1p8_ctrl(..., false) turning the regulator off while sensor 2's
probe() function still needs it to be on, causing the probe() of
sensor 2 to sometimes fail.
Fix this by adding an enable-count for both regulators and only
disabling them again when that goes to 0.
Note all this really should be converted to use the standard kernel
regulator framework, I have doing this on my long term TODO list,
this fix is only meant as a temporary workaround for the issue.
Link: https://lore.kernel.org/linux-media/20220116215204.307649-6-hdegoede@redhat.com
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
-rw-r--r-- | drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c | 86 |
1 files changed, 65 insertions, 21 deletions
diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index a29e5086ffe1..960c64ecdfe4 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -118,6 +118,10 @@ static const char *pmic_name[] = { [PMIC_CRYSTALCOVE] = "Crystal Cove PMIC", }; +static DEFINE_MUTEX(gmin_regulator_mutex); +static int gmin_v1p8_enable_count; +static int gmin_v2p8_enable_count; + /* The atomisp uses type==0 for the end-of-list marker, so leave space. */ static struct intel_v4l2_subdev_table pdata_subdevs[MAX_SUBDEVS + 1]; @@ -851,38 +855,58 @@ static int gmin_v1p8_ctrl(struct v4l2_subdev *subdev, int on) gs->v1p8_on = on; + ret = 0; + mutex_lock(&gmin_regulator_mutex); + if (on) { + gmin_v1p8_enable_count++; + if (gmin_v1p8_enable_count > 1) + goto out; /* Already on */ + } else { + gmin_v1p8_enable_count--; + if (gmin_v1p8_enable_count > 0) + goto out; /* Still needed */ + } + if (gs->v1p8_gpio >= 0) gpio_set_value(gs->v1p8_gpio, on); if (gs->v1p8_reg) { regulator_set_voltage(gs->v1p8_reg, 1800000, 1800000); if (on) - return regulator_enable(gs->v1p8_reg); + ret = regulator_enable(gs->v1p8_reg); else - return regulator_disable(gs->v1p8_reg); + ret = regulator_disable(gs->v1p8_reg); + + goto out; } switch (pmic_id) { case PMIC_AXP: if (on) - return axp_v1p8_on(subdev->dev, gs); + ret = axp_v1p8_on(subdev->dev, gs); else - return axp_v1p8_off(subdev->dev, gs); + ret = axp_v1p8_off(subdev->dev, gs); + break; case PMIC_TI: value = on ? LDO_1P8V_ON : LDO_1P8V_OFF; - return gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, - LDO10_REG, value, 0xff); + ret = gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, + LDO10_REG, value, 0xff); + break; case PMIC_CRYSTALCOVE: value = on ? CRYSTAL_ON : CRYSTAL_OFF; - return gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, - CRYSTAL_1P8V_REG, value, 0xff); + ret = gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, + CRYSTAL_1P8V_REG, value, 0xff); + break; default: - dev_err(subdev->dev, "Couldn't set power mode for v1p2\n"); + dev_err(subdev->dev, "Couldn't set power mode for v1p8\n"); + ret = -EINVAL; } - return -EINVAL; +out: + mutex_unlock(&gmin_regulator_mutex); + return ret; } static int gmin_v2p8_ctrl(struct v4l2_subdev *subdev, int on) @@ -908,37 +932,57 @@ static int gmin_v2p8_ctrl(struct v4l2_subdev *subdev, int on) return 0; gs->v2p8_on = on; + ret = 0; + mutex_lock(&gmin_regulator_mutex); + if (on) { + gmin_v2p8_enable_count++; + if (gmin_v2p8_enable_count > 1) + goto out; /* Already on */ + } else { + gmin_v2p8_enable_count--; + if (gmin_v2p8_enable_count > 0) + goto out; /* Still needed */ + } + if (gs->v2p8_gpio >= 0) gpio_set_value(gs->v2p8_gpio, on); if (gs->v2p8_reg) { regulator_set_voltage(gs->v2p8_reg, 2900000, 2900000); if (on) - return regulator_enable(gs->v2p8_reg); + ret = regulator_enable(gs->v2p8_reg); else - return regulator_disable(gs->v2p8_reg); + ret = regulator_disable(gs->v2p8_reg); + + goto out; } switch (pmic_id) { case PMIC_AXP: - return axp_regulator_set(subdev->dev, gs, ALDO1_SEL_REG, - ALDO1_2P8V, ALDO1_CTRL3_REG, - ALDO1_CTRL3_SHIFT, on); + ret = axp_regulator_set(subdev->dev, gs, ALDO1_SEL_REG, + ALDO1_2P8V, ALDO1_CTRL3_REG, + ALDO1_CTRL3_SHIFT, on); + break; case PMIC_TI: value = on ? LDO_2P8V_ON : LDO_2P8V_OFF; - return gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, - LDO9_REG, value, 0xff); + ret = gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, + LDO9_REG, value, 0xff); + break; case PMIC_CRYSTALCOVE: value = on ? CRYSTAL_ON : CRYSTAL_OFF; - return gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, - CRYSTAL_2P8V_REG, value, 0xff); + ret = gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, + CRYSTAL_2P8V_REG, value, 0xff); + break; default: - dev_err(subdev->dev, "Couldn't set power mode for v1p2\n"); + dev_err(subdev->dev, "Couldn't set power mode for v2p8\n"); + ret = -EINVAL; } - return -EINVAL; +out: + mutex_unlock(&gmin_regulator_mutex); + return ret; } static int gmin_acpi_pm_ctrl(struct v4l2_subdev *subdev, int on) |