Skip to content

Commit f10ec43

Browse files
danieldegrassecarlescufi
authored andcommitted
drivers: regulator: add mode specific configuration functions for PMIC
Add mode specific PMIC configuration functions, to allow consumers to configure target voltages of each regulator mode. This will allow users to enable or disable, as well as set target voltages for regulator modes without actually entering that mode. This feature can be useful for power managment applications where the consumer may want to switch the regulator to low power mode at a later time. Signed-off-by: Daniel DeGrasse <[email protected]>
1 parent 92c40db commit f10ec43

File tree

2 files changed

+234
-45
lines changed

2 files changed

+234
-45
lines changed

drivers/regulator/regulator_pmic.c

Lines changed: 187 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,70 @@ static int regulator_modify_register(const struct device *dev,
103103
return i2c_reg_write_byte_dt(&conf->i2c, reg, reg_current);
104104
}
105105

106+
/*
107+
* Internal helper function- gets the voltage from a regulator, with an
108+
* offset applied to the vsel_reg. Useful to support reading voltages
109+
* in another target mode
110+
*/
111+
static int regulator_get_voltage_offset(const struct device *dev, uint32_t off)
112+
{
113+
const struct regulator_config *config = dev->config;
114+
struct regulator_data *data = dev->data;
115+
int rc, i = 0;
116+
uint8_t raw_reg;
117+
118+
rc = regulator_read_register(dev, config->vsel_reg + off, &raw_reg);
119+
if (rc) {
120+
return rc;
121+
}
122+
raw_reg &= config->vsel_mask;
123+
/* Locate the voltage value in the voltage table */
124+
while (i < config->num_voltages &&
125+
raw_reg != data->voltages[i].reg_val){
126+
i++;
127+
}
128+
if (i == config->num_voltages) {
129+
LOG_WRN("Regulator vsel reg has unknown value");
130+
return -EIO;
131+
}
132+
return data->voltages[i].uV;
133+
}
134+
135+
/**
136+
* Internal helper function- sets the voltage for a regulator, with an
137+
* offset applied to the vsel_reg. Useful to support setting voltages in
138+
* another target mode.
139+
*/
140+
static int regulator_set_voltage_offset(const struct device *dev, int min_uV,
141+
int max_uV, uint32_t off)
142+
{
143+
const struct regulator_config *config = dev->config;
144+
struct regulator_data *data = dev->data;
145+
int i = 0;
146+
147+
if (!regulator_is_supported_voltage(dev, min_uV, max_uV) ||
148+
min_uV > max_uV) {
149+
return -EINVAL;
150+
}
151+
/* Find closest supported voltage */
152+
while (i < config->num_voltages && min_uV > data->voltages[i].uV) {
153+
i++;
154+
}
155+
if (data->voltages[i].uV > max_uV) {
156+
LOG_DBG("Regulator could not satisfy voltage range, too narrow");
157+
return -EINVAL;
158+
}
159+
if (i == config->num_voltages) {
160+
LOG_WRN("Regulator could not locate supported voltage,"
161+
"but voltage is in range.");
162+
return -EINVAL;
163+
}
164+
LOG_DBG("Setting regulator %s to %duV", dev->name,
165+
data->voltages[i].uV);
166+
return regulator_modify_register(dev, config->vsel_reg + off,
167+
config->vsel_mask, data->voltages[i].reg_val);
168+
}
169+
106170

107171
/**
108172
* Part of the extended regulator consumer API
@@ -159,59 +223,17 @@ int regulator_is_supported_voltage(const struct device *dev,
159223
*/
160224
int regulator_set_voltage(const struct device *dev, int min_uV, int max_uV)
161225
{
162-
const struct regulator_config *config = dev->config;
163-
struct regulator_data *data = dev->data;
164-
int i = 0;
165-
166-
if (!regulator_is_supported_voltage(dev, min_uV, max_uV) ||
167-
min_uV > max_uV) {
168-
return -EINVAL;
169-
}
170-
/* Find closest supported voltage */
171-
while (i < config->num_voltages && min_uV > data->voltages[i].uV) {
172-
i++;
173-
}
174-
if (data->voltages[i].uV > max_uV) {
175-
LOG_DBG("Regulator could not satisfy voltage range, too narrow");
176-
return -EINVAL;
177-
}
178-
if (i == config->num_voltages) {
179-
LOG_WRN("Regulator could not locate supported voltage,"
180-
"but voltage is in range.");
181-
return -EINVAL;
182-
}
183-
LOG_DBG("Setting regulator %s to %duV", dev->name,
184-
data->voltages[i].uV);
185-
return regulator_modify_register(dev, config->vsel_reg,
186-
config->vsel_mask, data->voltages[i].reg_val);
226+
return regulator_set_voltage_offset(dev, min_uV, max_uV, 0);
187227
}
188228

229+
189230
/**
190231
* Part of the extended regulator consumer API
191232
* Gets the current output voltage in uV
192233
*/
193234
int regulator_get_voltage(const struct device *dev)
194235
{
195-
const struct regulator_config *config = dev->config;
196-
struct regulator_data *data = dev->data;
197-
int rc, i = 0;
198-
uint8_t raw_reg;
199-
200-
rc = regulator_read_register(dev, config->vsel_reg, &raw_reg);
201-
if (rc) {
202-
return rc;
203-
}
204-
raw_reg &= config->vsel_mask;
205-
/* Locate the voltage value in the voltage table */
206-
while (i < config->num_voltages &&
207-
raw_reg != data->voltages[i].reg_val){
208-
i++;
209-
}
210-
if (i == config->num_voltages) {
211-
LOG_WRN("Regulator vsel reg has unknown value");
212-
return -EIO;
213-
}
214-
return data->voltages[i].uV;
236+
return regulator_get_voltage_offset(dev, 0);
215237
}
216238

217239
/**
@@ -271,6 +293,126 @@ int regulator_get_current_limit(const struct device *dev)
271293
return data->current_levels[i].uA;
272294
}
273295

296+
/*
297+
* Part of the extended regulator consumer API.
298+
* sets the target voltage for a given regulator mode. This mode does
299+
* not need to be the active mode. This API can be used to configure
300+
* voltages for a mode, then the regulator can be switched to that mode
301+
* with the regulator_set_mode api
302+
*/
303+
int regulator_set_mode_voltage(const struct device *dev, uint32_t mode,
304+
uint32_t min_uV, uint32_t max_uV)
305+
{
306+
const struct regulator_config *config = dev->config;
307+
uint8_t i, sel_off;
308+
309+
if (config->num_modes == 0) {
310+
return -ENOTSUP;
311+
}
312+
313+
/* Search for mode ID in allowed modes. */
314+
for (i = 0 ; i < config->num_modes; i++) {
315+
if (config->allowed_modes[i] == mode) {
316+
break;
317+
}
318+
}
319+
if (i == config->num_modes) {
320+
/* Mode was not found */
321+
return -EINVAL;
322+
}
323+
sel_off = ((mode & PMIC_MODE_OFFSET_MASK) >> PMIC_MODE_OFFSET_SHIFT);
324+
return regulator_set_voltage_offset(dev, min_uV, max_uV, sel_off);
325+
}
326+
327+
/*
328+
* Part of the extended regulator consumer API.
329+
* Disables the regulator in a given mode. Does not implement the
330+
* onoff service, as this is incompatible with multiple mode operation
331+
*/
332+
int regulator_mode_disable(const struct device *dev, uint32_t mode)
333+
{
334+
const struct regulator_config *config = dev->config;
335+
uint8_t i, sel_off, dis_val;
336+
337+
if (config->num_modes == 0) {
338+
return -ENOTSUP;
339+
}
340+
341+
/* Search for mode ID in allowed modes. */
342+
for (i = 0 ; i < config->num_modes; i++) {
343+
if (config->allowed_modes[i] == mode) {
344+
break;
345+
}
346+
}
347+
if (i == config->num_modes) {
348+
/* Mode was not found */
349+
return -EINVAL;
350+
}
351+
sel_off = ((mode & PMIC_MODE_OFFSET_MASK) >> PMIC_MODE_OFFSET_SHIFT);
352+
dis_val = config->enable_inverted ? config->enable_val : 0;
353+
return regulator_modify_register(dev, config->enable_reg + sel_off,
354+
config->enable_mask, dis_val);
355+
}
356+
357+
/*
358+
* Part of the extended regulator consumer API.
359+
* Enables the regulator in a given mode. Does not implement the
360+
* onoff service, as this is incompatible with multiple mode operation
361+
*/
362+
int regulator_mode_enable(const struct device *dev, uint32_t mode)
363+
{
364+
const struct regulator_config *config = dev->config;
365+
uint8_t i, sel_off, en_val;
366+
367+
if (config->num_modes == 0) {
368+
return -ENOTSUP;
369+
}
370+
371+
/* Search for mode ID in allowed modes. */
372+
for (i = 0 ; i < config->num_modes; i++) {
373+
if (config->allowed_modes[i] == mode) {
374+
break;
375+
}
376+
}
377+
if (i == config->num_modes) {
378+
/* Mode was not found */
379+
return -EINVAL;
380+
}
381+
sel_off = ((mode & PMIC_MODE_OFFSET_MASK) >> PMIC_MODE_OFFSET_SHIFT);
382+
en_val = config->enable_inverted ? 0 : config->enable_val;
383+
return regulator_modify_register(dev, config->enable_reg + sel_off,
384+
config->enable_mask, en_val);
385+
}
386+
387+
/*
388+
* Part of the extended regulator consumer API.
389+
* gets the target voltage for a given regulator mode. This mode does
390+
* not need to be the active mode. This API can be used to read voltages
391+
* from a regulator mode other than the default.
392+
*/
393+
int regulator_get_mode_voltage(const struct device *dev, uint32_t mode)
394+
{
395+
const struct regulator_config *config = dev->config;
396+
uint8_t i, sel_off;
397+
398+
if (config->num_modes == 0) {
399+
return -ENOTSUP;
400+
}
401+
402+
/* Search for mode ID in allowed modes. */
403+
for (i = 0 ; i < config->num_modes; i++) {
404+
if (config->allowed_modes[i] == mode) {
405+
break;
406+
}
407+
}
408+
if (i == config->num_modes) {
409+
/* Mode was not found */
410+
return -EINVAL;
411+
}
412+
sel_off = ((mode & PMIC_MODE_OFFSET_MASK) >> PMIC_MODE_OFFSET_SHIFT);
413+
return regulator_get_voltage_offset(dev, sel_off);
414+
}
415+
274416
/*
275417
* Part of the extended regulator consumer API
276418
* switches the regulator to a given mode. This API will apply a mode for

include/zephyr/drivers/regulator/consumer.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,53 @@ int regulator_get_current_limit(const struct device *dev);
114114
*/
115115
int regulator_set_mode(const struct device *dev, uint32_t mode);
116116

117+
/**
118+
* @brief Set target voltage for regulator mode
119+
* Part of the extended regulator consumer API.
120+
* sets the target voltage for a given regulator mode. This mode does
121+
* not need to be the active mode. This API can be used to configure
122+
* voltages for a mode, then the regulator can be switched to that mode
123+
* with the regulator_set_mode api.
124+
* @param dev: regulator to set voltage for
125+
* @param mode: target mode to configure voltage for
126+
* @param min_uV: minimum voltage acceptable, in uV
127+
* @param max_uV: maximum voltage acceptable, in uV
128+
* @return 0 on success, or errno on error
129+
*/
130+
int regulator_set_mode_voltage(const struct device *dev, uint32_t mode,
131+
uint32_t min_uV, uint32_t max_uV);
132+
133+
/**
134+
* @brief Get target voltage for regulator mode
135+
* Part of the extended regulator consumer API.
136+
* gets the target voltage for a given regulator mode. This mode does
137+
* not need to be the active mode. This API can be used to read voltages
138+
* from a regulator mode other than the default.
139+
* @param dev: regulator to query voltage from
140+
* @param mode: target mode to query voltage from
141+
* @return voltage level in uV
142+
*/
143+
int regulator_get_mode_voltage(const struct device *dev, uint32_t mode);
144+
145+
/**
146+
* @brief Disable regulator for a given mode
147+
* Part of the extended regulator consumer API.
148+
* Disables the regulator in a given mode. Does not implement the
149+
* onoff service, as this is incompatible with multiple mode operation
150+
* @param dev: regulator to disable
151+
* @param mode: mode to change regulator state in
152+
*/
153+
int regulator_mode_disable(const struct device *dev, uint32_t mode);
154+
155+
/**
156+
* @brief Enable regulator for a given mode
157+
* Part of the extended regulator consumer API.
158+
* Enables the regulator in a given mode. Does not implement the
159+
* onoff service, as this is incompatible with multiple mode operation
160+
* @param dev: regulator to enable
161+
* @param mode: mode to change regulator state in
162+
*/
163+
int regulator_mode_enable(const struct device *dev, uint32_t mode);
117164

118165
#ifdef __cplusplus
119166
}

0 commit comments

Comments
 (0)