@@ -103,6 +103,70 @@ static int regulator_modify_register(const struct device *dev,
103
103
return i2c_reg_write_byte_dt (& conf -> i2c , reg , reg_current );
104
104
}
105
105
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
+
106
170
107
171
/**
108
172
* Part of the extended regulator consumer API
@@ -159,59 +223,17 @@ int regulator_is_supported_voltage(const struct device *dev,
159
223
*/
160
224
int regulator_set_voltage (const struct device * dev , int min_uV , int max_uV )
161
225
{
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 );
187
227
}
188
228
229
+
189
230
/**
190
231
* Part of the extended regulator consumer API
191
232
* Gets the current output voltage in uV
192
233
*/
193
234
int regulator_get_voltage (const struct device * dev )
194
235
{
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 );
215
237
}
216
238
217
239
/**
@@ -271,6 +293,126 @@ int regulator_get_current_limit(const struct device *dev)
271
293
return data -> current_levels [i ].uA ;
272
294
}
273
295
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
+
274
416
/*
275
417
* Part of the extended regulator consumer API
276
418
* switches the regulator to a given mode. This API will apply a mode for
0 commit comments