[PATCH v3 2/3] media: i2c: dw9719: Update DW9800K driver

From: Griffin Kroah-Hartman

Date: Thu Nov 05 2026 - 05:30:21 EST


The previous DW9800K driver code was created without access to a
datasheet for the part, now that we have one we can clean up some
misunderstandings and add some features for further expandability.

More specifically:

Previously we were blindly writing registers to their downstream values,
Now we know what the correct default values of SAC and SACT, and write
to the correct bits as specified from the datasheet.

We found that the device does indeed have an ID, and add it to the
switch statement when setting up the default device properties.

The largest change would be the implementation of "Ringing," this is
actually an internal switch bit used to differentiate whether the SAC
(smart actuator control) modes are enabled. if the "ringing" bit is
zero, then actuator modes DIRECT and LSC are available(based on the
value written to the Mode register). If the bit is 1, SAC2-SAC5 are
available.

For the devices we tested this driver on, no new values are being
written, but now the option for further use of the DW9800k is available
to others if they wish to do so.

Fixes: 083f7f0dce16 ("media: i2c: dw9719: Add DW9800K support")
Signed-off-by: Griffin Kroah-Hartman <griffin.kroah@xxxxxxxxxxxxx>
---
drivers/media/i2c/dw9719.c | 65 +++++++++++++++++++++++++++++++++++++++-------
1 file changed, 56 insertions(+), 9 deletions(-)

diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c
index 3b7ba88fd67c044ef9005a0aac6a5d26ab939a90..3b99c5492522c33e0aeadb9fe7e9b49f777b9470 100644
--- a/drivers/media/i2c/dw9719.c
+++ b/drivers/media/i2c/dw9719.c
@@ -68,9 +68,18 @@
#define DW9761_VCM_PRELOAD CCI_REG8(8)
#define DW9761_DEFAULT_VCM_PRELOAD 0x73

-#define DW9800K_DEFAULT_SAC 1
+#define DW9800K_ID 0xEB
+#define DW9800K_DEFAULT_SAC 3
#define DW9800K_MODE_SAC_SHIFT 6
-#define DW9800K_DEFAULT_VCM_FREQ 0x10
+
+#define DW9800K_RESONANCE CCI_REG8(7)
+
+#define DW9800K_DEFAULT_DIV 0x01
+#define DW9800K_DIV_SHIFT 6
+#define DW9800K_DIV_LOW_SHIFT 2
+
+#define DW9800K_DEFAULT_SACT 0x20
+

#define to_dw9719_device(x) container_of(x, struct dw9719_device, sd)

@@ -90,6 +99,7 @@ struct dw9719_device {
u32 mode_low_bits;
u32 sac_mode;
u32 vcm_freq;
+ u32 sac_time;

struct dw9719_v4l2_ctrls {
struct v4l2_ctrl_handler handler;
@@ -140,10 +150,6 @@ static int dw9719_power_up(struct dw9719_device *dw9719, bool detect)
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;
}
@@ -165,6 +171,11 @@ static int dw9719_power_up(struct dw9719_device *dw9719, bool detect)
dw9719->sac_mode = DW9761_DEFAULT_SAC;
dw9719->vcm_freq = DW9761_DEFAULT_VCM_FREQ;
break;
+ case DW9800K_ID:
+ dw9719->sac_mode = DW9800K_DEFAULT_SAC;
+ dw9719->vcm_freq = DW9800K_DEFAULT_DIV;
+ dw9719->sac_time = DW9800K_DEFAULT_SACT;
+ break;
default:
dev_err(dw9719->dev,
"Error unknown device id 0x%02llx\n", val);
@@ -185,14 +196,50 @@ static int dw9719_power_up(struct dw9719_device *dw9719, bool detect)
/* Optional indication of VCM prescale */
device_property_read_u32(dw9719->dev, "dongwoon,vcm-prescale",
&dw9719->vcm_freq);
+
+ /* Optional indication of SAC timing */
+ device_property_read_u32(dw9719->dev, "dongwoon,timing-control",
+ &dw9719->sac_time);
}

switch (dw9719->model) {
case DW9800K:
- cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_ENABLE_RINGING, &ret);
+ int ring, sac;
+
+ /*
+ * Enable ringing for SAC3-SAC5
+ *
+ * sac_mode reg Mode
+ * ===========================
+ * 0 0X Direct
+ * 1 1X LSC
+ * 2 00 SAC2
+ * 3 01 SAC3
+ * 4 10 SAC4
+ * 5 11 SAC5
+ */
+ switch (dw9719->sac_mode) {
+ case 0:
+ ring = 0;
+ sac = 0;
+ break;
+ case 1:
+ ring = 0;
+ sac = 2;
+ break;
+ default:
+ ring = DW9719_ENABLE_RINGING;
+ sac = dw9719->sac_mode - 2;
+ break;
+ }
+ cci_write(dw9719->regmap, DW9719_CONTROL, ring, &ret);
+ /* DIV is 3 bits split over the bottom bit in reg 6 and the top 2 bits in reg 7 */
cci_write(dw9719->regmap, DW9719_MODE,
- dw9719->sac_mode << DW9800K_MODE_SAC_SHIFT, &ret);
- cci_write(dw9719->regmap, DW9719_VCM_FREQ, dw9719->vcm_freq, &ret);
+ (sac << DW9800K_MODE_SAC_SHIFT) |
+ (dw9719->vcm_freq >> DW9800K_DIV_LOW_SHIFT), &ret);
+ cci_write(dw9719->regmap, DW9800K_RESONANCE,
+ (dw9719->vcm_freq << DW9800K_DIV_SHIFT) |
+ dw9719->sac_time, &ret);
break;
case DW9718S:
/* Datasheet says [OCP/UVLO] should be disabled below 2.5V */

--
2.43.0