Skip to content

Commit 2b3ed70

Browse files
rriveramcruscarlescufi
authored andcommitted
regulator: cp9314: Adds support for HW I2C Lock feature
Adds support for the control port write-lock feature introduced in revision B1. The write-lock feature minimizes the risk of spurious I2C writes flipping sensitive bits during device operation by blocking writes to some or all of the register map. If desired, the write-lock must be set in hardware by biasing PGPIO2 appropriately and setting the cirrus,hw-i2c-lock flag in the devicetree entry. Signed-off-by: Ricardo Rivera-Matos <[email protected]>
1 parent a684c36 commit 2b3ed70

File tree

1 file changed

+133
-0
lines changed

1 file changed

+133
-0
lines changed

drivers/regulator/regulator_cp9314.c

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ LOG_MODULE_REGISTER(CP9314, CONFIG_REGULATOR_LOG_LEVEL);
8585
#define CP9314_REG_LION_CFG_3 0x34
8686
#define CP9314_LB_MIN_FREQ_SEL_0 GENMASK(7, 6)
8787
#define CP9314_MODE_CTRL_UPDATE_BW_1 GENMASK(5, 3)
88+
#define CP9314_ALLOW_HW_I2C_LOCK BIT(0)
8889

8990
#define CP9314_REG_LB_CTRL 0x38
9091
#define CP9314_LB1_DELTA_CFG_1 GENMASK(6, 3)
@@ -152,6 +153,8 @@ LOG_MODULE_REGISTER(CP9314, CONFIG_REGULATOR_LOG_LEVEL);
152153
#define CP9314_PTE_2_OTP_1 0x0
153154
#define CP9314_PTE_2_OTP_2 0x1
154155

156+
#define CP9314_REG_BACKDOOR_CTRL 0x8C
157+
155158
#define CP9314_FAULT1_STS 0x9A
156159
#define CP9314_VIN_OV_STS BIT(4)
157160

@@ -192,17 +195,25 @@ enum cp9314_sync_roles {
192195
CP9314_ROLE_STANDALONE,
193196
};
194197

198+
enum cp9314_backdoor_keys {
199+
CP9314_BACKDOOR_LOCKED_KEY = 0x0,
200+
CP9314_BACKDOOR_PUBLIC_KEY = 0x0F,
201+
};
202+
195203
struct regulator_cp9314_config {
196204
struct regulator_common_config common;
197205
struct i2c_dt_spec i2c;
198206
struct gpio_dt_spec en_pin;
199207
struct gpio_dt_spec pgood_pin;
200208
uint8_t initial_op_mode_idx;
209+
bool hw_i2c_lock;
201210
};
202211

203212
struct regulator_cp9314_data {
204213
struct regulator_common_data data;
205214
enum cp9314_sync_roles sync_role;
215+
uint8_t backdoor_key;
216+
bool allow_hw_i2c_lock;
206217
};
207218

208219
struct cp9314_reg_patch {
@@ -284,14 +295,75 @@ static int regulator_cp9314_get_error_flags(const struct device *dev,
284295
return 0;
285296
}
286297

298+
static int regulator_cp9314_write_lock(const struct device *dev,
299+
const enum cp9314_backdoor_keys key)
300+
{
301+
const struct regulator_cp9314_config *config = dev->config;
302+
struct regulator_cp9314_data *data = dev->data;
303+
int ret;
304+
305+
if (data->allow_hw_i2c_lock == 0U) {
306+
ret = i2c_reg_update_byte_dt(&config->i2c, CP9314_REG_LION_CFG_3,
307+
CP9314_ALLOW_HW_I2C_LOCK, CP9314_ALLOW_HW_I2C_LOCK);
308+
if (ret < 0) {
309+
return ret;
310+
}
311+
312+
data->allow_hw_i2c_lock = true;
313+
}
314+
315+
if ((uint8_t)key == data->backdoor_key) {
316+
return 0;
317+
} else {
318+
return i2c_reg_write_byte_dt(&config->i2c, CP9314_REG_BACKDOOR_CTRL, (uint8_t)key);
319+
}
320+
}
321+
322+
static int regulator_cp9314_write_lock_init(const struct device *dev)
323+
{
324+
const struct regulator_cp9314_config *config = dev->config;
325+
struct regulator_cp9314_data *data = dev->data;
326+
uint8_t value;
327+
int ret;
328+
329+
ret = i2c_reg_read_byte_dt(&config->i2c, CP9314_REG_LION_CFG_3, &value);
330+
if (ret < 0) {
331+
return ret;
332+
}
333+
334+
data->allow_hw_i2c_lock = FIELD_GET(CP9314_ALLOW_HW_I2C_LOCK, value);
335+
336+
ret = i2c_reg_read_byte_dt(&config->i2c, CP9314_REG_BACKDOOR_CTRL, &data->backdoor_key);
337+
if (ret < 0) {
338+
return ret;
339+
}
340+
341+
return 0;
342+
}
343+
287344
static int regulator_cp9314_disable(const struct device *dev)
288345
{
289346
const struct regulator_cp9314_config *config = dev->config;
347+
int ret;
290348

291349
if (config->en_pin.port != NULL) {
292350
return gpio_pin_set_dt(&config->en_pin, 0);
293351
}
294352

353+
if (config->hw_i2c_lock != 0U) {
354+
ret = regulator_cp9314_write_lock(dev, CP9314_BACKDOOR_PUBLIC_KEY);
355+
if (ret < 0) {
356+
return ret;
357+
}
358+
359+
ret = i2c_reg_update_byte_dt(&config->i2c, CP9314_REG_CTRL1, CP9314_CP_EN, 0);
360+
if (ret < 0) {
361+
return ret;
362+
}
363+
364+
return regulator_cp9314_write_lock(dev, CP9314_BACKDOOR_LOCKED_KEY);
365+
}
366+
295367
return i2c_reg_update_byte_dt(&config->i2c, CP9314_REG_CTRL1, CP9314_CP_EN, 0);
296368
}
297369

@@ -301,6 +373,13 @@ static int regulator_cp9314_enable(const struct device *dev)
301373
uint8_t value;
302374
int ret;
303375

376+
if (config->hw_i2c_lock != 0U) {
377+
ret = regulator_cp9314_write_lock(dev, CP9314_BACKDOOR_PUBLIC_KEY);
378+
if (ret < 0) {
379+
return ret;
380+
}
381+
}
382+
304383
ret = i2c_reg_read_byte_dt(&config->i2c, CP9314_REG_CONVERTER, &value);
305384
if (ret < 0) {
306385
return ret;
@@ -353,6 +432,13 @@ static int regulator_cp9314_enable(const struct device *dev)
353432
}
354433
}
355434

435+
if (config->hw_i2c_lock != 0U) {
436+
ret = regulator_cp9314_write_lock(dev, CP9314_BACKDOOR_LOCKED_KEY);
437+
if (ret < 0) {
438+
return ret;
439+
}
440+
}
441+
356442
return 0;
357443
}
358444

@@ -403,6 +489,19 @@ static int cp9314_do_soft_reset(const struct device *dev)
403489
const struct regulator_cp9314_config *config = dev->config;
404490
int ret;
405491

492+
if (config->hw_i2c_lock != 0U) {
493+
ret = regulator_cp9314_write_lock(dev, CP9314_BACKDOOR_PUBLIC_KEY);
494+
if (ret < 0) {
495+
return ret;
496+
}
497+
498+
ret = i2c_reg_update_byte_dt(&config->i2c, CP9314_REG_LION_CFG_3,
499+
CP9314_ALLOW_HW_I2C_LOCK, 0);
500+
if (ret < 0) {
501+
return ret;
502+
}
503+
}
504+
406505
ret = i2c_reg_write_byte_dt(&config->i2c, CP9314_REG_CRUS_CTRL, CP9314_CRUS_KEY_SOFT_RESET);
407506
if (ret < 0) {
408507
return ret;
@@ -416,6 +515,13 @@ static int cp9314_do_soft_reset(const struct device *dev)
416515

417516
k_msleep(CP9314_SOFT_RESET_DELAY_MSEC);
418517

518+
if (config->hw_i2c_lock != 0U) {
519+
ret = regulator_cp9314_write_lock_init(dev);
520+
if (ret < 0) {
521+
return ret;
522+
}
523+
}
524+
419525
return 0;
420526
}
421527

@@ -507,11 +613,30 @@ static int regulator_cp9314_init(const struct device *dev)
507613
k_usleep(CP9314_EN_DEBOUNCE_USEC);
508614
}
509615

616+
if (config->hw_i2c_lock != 0U) {
617+
ret = regulator_cp9314_write_lock_init(dev);
618+
if (ret < 0) {
619+
return ret;
620+
}
621+
} else {
622+
data->allow_hw_i2c_lock = 0;
623+
}
624+
510625
ret = cp9314_do_soft_reset(dev);
511626
if (ret < 0) {
512627
return ret;
513628
}
514629

630+
if (data->allow_hw_i2c_lock != 0U) {
631+
ret = i2c_reg_update_byte_dt(&config->i2c, CP9314_REG_LION_CFG_3,
632+
CP9314_ALLOW_HW_I2C_LOCK, 0x0);
633+
if (ret < 0) {
634+
return ret;
635+
}
636+
637+
data->allow_hw_i2c_lock = false;
638+
}
639+
515640
ret = i2c_reg_read_byte_dt(&config->i2c, CP9314_REG_BC_STS_C, &value);
516641
if (ret < 0) {
517642
return ret;
@@ -597,6 +722,13 @@ static int regulator_cp9314_init(const struct device *dev)
597722
}
598723
}
599724

725+
if (config->hw_i2c_lock != 0U) {
726+
ret = regulator_cp9314_write_lock(dev, CP9314_BACKDOOR_LOCKED_KEY);
727+
if (ret < 0) {
728+
return ret;
729+
}
730+
}
731+
600732
regulator_common_data_init(dev);
601733

602734
return regulator_common_init(dev, false);
@@ -618,6 +750,7 @@ static const struct regulator_driver_api api = {
618750
.pgood_pin = GPIO_DT_SPEC_INST_GET_OR(inst, cirrus_pgood_gpios, {}), \
619751
.initial_op_mode_idx = \
620752
DT_INST_ENUM_IDX_OR(inst, cirrus_initial_switched_capacitor_mode, -1) + 1, \
753+
.hw_i2c_lock = DT_INST_PROP(inst, cirrus_hw_i2c_lock), \
621754
}; \
622755
\
623756
DEVICE_DT_INST_DEFINE(inst, regulator_cp9314_init, NULL, &data_##inst, &config_##inst, \

0 commit comments

Comments
 (0)