drivers/media/i2c/dw9719.c

Source file repositories/reference/linux-study-clean/drivers/media/i2c/dw9719.c

File Facts

System
Linux kernel
Corpus path
drivers/media/i2c/dw9719.c
Extension
.c
Size
12911 bytes
Lines
478
Domain
Driver Families
Bucket
drivers/media
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct dw9719_device {
	struct v4l2_subdev sd;
	struct device *dev;
	struct regmap *regmap;
	struct regulator *regulator;
	enum dw9719_model model;
	u32 mode_low_bits;
	u32 sac_mode;
	u32 vcm_freq;

	struct dw9719_v4l2_ctrls {
		struct v4l2_ctrl_handler handler;
		struct v4l2_ctrl *focus;
	} ctrls;
};

static int dw9719_power_down(struct dw9719_device *dw9719)
{
	u32 reg_pwr = dw9719->model == DW9718S ? DW9718S_PD : DW9719_CONTROL;

	/*
	 * Worth engaging the internal SHUTDOWN mode especially due to the
	 * regulator being potentially shared with other devices.
	 */
	if (cci_write(dw9719->regmap, reg_pwr, DW9719_SHUTDOWN, NULL))
		dev_err(dw9719->dev, "Error writing to power register\n");
	return regulator_disable(dw9719->regulator);
}

static int dw9719_power_up(struct dw9719_device *dw9719, bool detect)
{
	u32 reg_pwr = dw9719->model == DW9718S ? DW9718S_PD : DW9719_CONTROL;
	u64 val;
	int ret;
	int err;

	ret = regulator_enable(dw9719->regulator);
	if (ret)
		return ret;

	/*
	 * Need 100us to transition from SHUTDOWN to STANDBY.
	 * Jiggle the SCL pin to wake up the device (even when the regulator is
	 * shared) and wait double the time to be sure, as 100us is not enough
	 * at least on the DW9718S as found on the motorola-nora smartphone,
	 * then retry the write.
	 */
	cci_write(dw9719->regmap, reg_pwr, DW9719_STANDBY, NULL);
	/* the jiggle is expected to fail, don't even log that as error */
	fsleep(200);
	cci_write(dw9719->regmap, reg_pwr, DW9719_STANDBY, &ret);

	if (detect) {
		/* These models do not have an INFO register */
		switch (dw9719->model) {
		case DW9718S:
			dw9719->sac_mode = DW9718S_DEFAULT_SAC;
			dw9719->vcm_freq = DW9718S_DEFAULT_VCM_FREQ;
			goto props;
		case DW9800K:
			dw9719->sac_mode = DW9800K_DEFAULT_SAC;
			dw9719->vcm_freq = DW9800K_DEFAULT_VCM_FREQ;
			goto props;
		default:
			break;
		}

		ret = cci_read(dw9719->regmap, DW9719_INFO, &val, NULL);
		if (ret < 0)
			return ret;

		switch (val) {
		case DW9719_ID:
			dw9719->model = DW9719;
			dw9719->mode_low_bits = 0x00;
			dw9719->sac_mode = DW9719_DEFAULT_SAC;
			dw9719->vcm_freq = DW9719_DEFAULT_VCM_FREQ;
			break;
		case DW9761_ID:
			dw9719->model = DW9761;
			dw9719->mode_low_bits = 0x01;
			dw9719->sac_mode = DW9761_DEFAULT_SAC;
			dw9719->vcm_freq = DW9761_DEFAULT_VCM_FREQ;
			break;
		default:
			dev_err(dw9719->dev,
				"Error unknown device id 0x%02llx\n", val);
			return -ENXIO;
		}

Annotation

Implementation Notes