Commit 74bfe151 authored by Hans de Goede's avatar Hans de Goede Committed by Mauro Carvalho Chehab
Browse files

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: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@kernel.org>
parent 9bad7640
Loading
Loading
Loading
Loading
+65 −21
Original line number Diff line number Diff line
@@ -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,
		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,
		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,
		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,
		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,
		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)