Skip to content

Commit de58556

Browse files
ukleinekUwe Kleine-König
authored andcommitted
pwm: pca9685: Use bulk write to atomicially update registers
The output of a PWM channel is configured by four register values. Write them in a single i2c transaction to ensure glitch free updates. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com> Link: https://lore.kernel.org/r/bfa8c0267c9ec059d0d77f146998d564654c75ca.1753784092.git.u.kleine-koenig@baylibre.com Signed-off-by: Uwe Kleine-König <ukleinek@kernel.org>
1 parent ca478d8 commit de58556

File tree

1 file changed

+29
-17
lines changed

1 file changed

+29
-17
lines changed

drivers/pwm/pwm-pca9685.c

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@
6161
#define MODE1_SUB2 BIT(2)
6262
#define MODE1_SUB1 BIT(3)
6363
#define MODE1_SLEEP BIT(4)
64+
#define MODE1_AI BIT(5)
65+
6466
#define MODE2_INVRT BIT(4)
6567
#define MODE2_OUTDRV BIT(2)
6668

@@ -131,6 +133,19 @@ static int pca9685_write_reg(struct pwm_chip *chip, unsigned int reg, unsigned i
131133
return err;
132134
}
133135

136+
static int pca9685_write_4reg(struct pwm_chip *chip, unsigned int reg, u8 val[4])
137+
{
138+
struct pca9685 *pca = to_pca(chip);
139+
struct device *dev = pwmchip_parent(chip);
140+
int err;
141+
142+
err = regmap_bulk_write(pca->regmap, reg, val, 4);
143+
if (err)
144+
dev_err(dev, "regmap_write to register 0x%x failed: %pe\n", reg, ERR_PTR(err));
145+
146+
return err;
147+
}
148+
134149
/* Helper function to set the duty cycle ratio to duty/4096 (e.g. duty=2048 -> 50%) */
135150
static void pca9685_pwm_set_duty(struct pwm_chip *chip, int channel, unsigned int duty)
136151
{
@@ -143,12 +158,10 @@ static void pca9685_pwm_set_duty(struct pwm_chip *chip, int channel, unsigned in
143158
return;
144159
} else if (duty >= PCA9685_COUNTER_RANGE) {
145160
/* Set the full ON bit and clear the full OFF bit */
146-
pca9685_write_reg(chip, REG_ON_H(channel), LED_FULL);
147-
pca9685_write_reg(chip, REG_OFF_H(channel), 0);
161+
pca9685_write_4reg(chip, REG_ON_L(channel), (u8[4]){ 0, LED_FULL, 0, 0 });
148162
return;
149163
}
150164

151-
152165
if (pwm->state.usage_power && channel < PCA9685_MAXCHAN) {
153166
/*
154167
* If usage_power is set, the pca9685 driver will phase shift
@@ -163,12 +176,9 @@ static void pca9685_pwm_set_duty(struct pwm_chip *chip, int channel, unsigned in
163176

164177
off = (on + duty) % PCA9685_COUNTER_RANGE;
165178

166-
/* Set ON time (clears full ON bit) */
167-
pca9685_write_reg(chip, REG_ON_L(channel), on & 0xff);
168-
pca9685_write_reg(chip, REG_ON_H(channel), (on >> 8) & 0xf);
169-
/* Set OFF time (clears full OFF bit) */
170-
pca9685_write_reg(chip, REG_OFF_L(channel), off & 0xff);
171-
pca9685_write_reg(chip, REG_OFF_H(channel), (off >> 8) & 0xf);
179+
/* implicitly clear full ON and full OFF bit */
180+
pca9685_write_4reg(chip, REG_ON_L(channel),
181+
(u8[4]){ on & 0xff, (on >> 8) & 0xf, off & 0xff, (off >> 8) & 0xf });
172182
}
173183

174184
static unsigned int pca9685_pwm_get_duty(struct pwm_chip *chip, int channel)
@@ -543,9 +553,8 @@ static int pca9685_pwm_probe(struct i2c_client *client)
543553

544554
mutex_init(&pca->lock);
545555

546-
ret = pca9685_read_reg(chip, PCA9685_MODE2, &reg);
547-
if (ret)
548-
return ret;
556+
/* clear MODE2_OCH */
557+
reg = 0;
549558

550559
if (device_property_read_bool(&client->dev, "invert"))
551560
reg |= MODE2_INVRT;
@@ -561,16 +570,19 @@ static int pca9685_pwm_probe(struct i2c_client *client)
561570
if (ret)
562571
return ret;
563572

564-
/* Disable all LED ALLCALL and SUBx addresses to avoid bus collisions */
573+
/*
574+
* Disable all LED ALLCALL and SUBx addresses to avoid bus collisions,
575+
* enable Auto-Increment.
576+
*/
565577
pca9685_read_reg(chip, PCA9685_MODE1, &reg);
566578
reg &= ~(MODE1_ALLCALL | MODE1_SUB1 | MODE1_SUB2 | MODE1_SUB3);
579+
reg |= MODE1_AI;
567580
pca9685_write_reg(chip, PCA9685_MODE1, reg);
568581

569582
/* Reset OFF/ON registers to POR default */
570-
pca9685_write_reg(chip, PCA9685_ALL_LED_OFF_L, 0);
571-
pca9685_write_reg(chip, PCA9685_ALL_LED_OFF_H, LED_FULL);
572-
pca9685_write_reg(chip, PCA9685_ALL_LED_ON_L, 0);
573-
pca9685_write_reg(chip, PCA9685_ALL_LED_ON_H, LED_FULL);
583+
ret = pca9685_write_4reg(chip, PCA9685_ALL_LED_ON_L, (u8[]){ 0, LED_FULL, 0, LED_FULL });
584+
if (ret < 0)
585+
return dev_err_probe(&client->dev, ret, "Failed to reset ON/OFF registers\n");
574586

575587
chip->ops = &pca9685_pwm_ops;
576588

0 commit comments

Comments
 (0)