Skip to content

Commit 28ca77c

Browse files
Aidan MacDonaldsre
authored andcommitted
power: supply: axp20x_usb_power: Simplify USB current limit handling
Handle the USB current limit with a lookup table and regmap field, which minimizes code duplication. Invalid or unlimited values are denoted by -1 entries, and can't be selected from userspace. Signed-off-by: Aidan MacDonald <aidanmacdonald.0x0@gmail.com> Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
1 parent 67fce59 commit 28ca77c

1 file changed

Lines changed: 57 additions & 115 deletions

File tree

drivers/power/supply/axp20x_usb_power.c

Lines changed: 57 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,6 @@
3737
#define AXP20X_VBUS_VHOLD_uV(b) (4000000 + (((b) >> 3) & 7) * 100000)
3838
#define AXP20X_VBUS_VHOLD_MASK GENMASK(5, 3)
3939
#define AXP20X_VBUS_VHOLD_OFFSET 3
40-
#define AXP20X_VBUS_CLIMIT_MASK 3
41-
#define AXP20X_VBUS_CLIMIT_900mA 0
42-
#define AXP20X_VBUS_CLIMIT_500mA 1
43-
#define AXP20X_VBUS_CLIMIT_100mA 2
44-
#define AXP20X_VBUS_CLIMIT_NONE 3
45-
46-
#define AXP813_VBUS_CLIMIT_900mA 0
47-
#define AXP813_VBUS_CLIMIT_1500mA 1
48-
#define AXP813_VBUS_CLIMIT_2000mA 2
49-
#define AXP813_VBUS_CLIMIT_2500mA 3
5040

5141
#define AXP20X_ADC_EN1_VBUS_CURR BIT(2)
5242
#define AXP20X_ADC_EN1_VBUS_VOLT BIT(3)
@@ -61,10 +51,21 @@
6151
*/
6252
#define DEBOUNCE_TIME msecs_to_jiffies(50)
6353

54+
struct axp_data {
55+
const struct power_supply_desc *power_desc;
56+
const char * const *irq_names;
57+
unsigned int num_irq_names;
58+
enum axp20x_variants axp20x_id;
59+
const int *curr_lim_table;
60+
struct reg_field curr_lim_fld;
61+
};
62+
6463
struct axp20x_usb_power {
6564
struct regmap *regmap;
65+
struct regmap_field *curr_lim_fld;
6666
struct power_supply *supply;
6767
enum axp20x_variants axp20x_id;
68+
const struct axp_data *axp_data;
6869
struct iio_channel *vbus_v;
6970
struct iio_channel *vbus_i;
7071
struct delayed_work vbus_detect;
@@ -121,60 +122,6 @@ static void axp20x_usb_power_poll_vbus(struct work_struct *work)
121122
mod_delayed_work(system_power_efficient_wq, &power->vbus_detect, DEBOUNCE_TIME);
122123
}
123124

124-
static int axp20x_get_current_max(struct axp20x_usb_power *power, int *val)
125-
{
126-
unsigned int v;
127-
int ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v);
128-
129-
if (ret)
130-
return ret;
131-
132-
switch (v & AXP20X_VBUS_CLIMIT_MASK) {
133-
case AXP20X_VBUS_CLIMIT_100mA:
134-
if (power->axp20x_id == AXP221_ID)
135-
*val = -1; /* No 100mA limit */
136-
else
137-
*val = 100000;
138-
break;
139-
case AXP20X_VBUS_CLIMIT_500mA:
140-
*val = 500000;
141-
break;
142-
case AXP20X_VBUS_CLIMIT_900mA:
143-
*val = 900000;
144-
break;
145-
case AXP20X_VBUS_CLIMIT_NONE:
146-
*val = -1;
147-
break;
148-
}
149-
150-
return 0;
151-
}
152-
153-
static int axp813_get_current_max(struct axp20x_usb_power *power, int *val)
154-
{
155-
unsigned int v;
156-
int ret = regmap_read(power->regmap, AXP20X_VBUS_IPSOUT_MGMT, &v);
157-
158-
if (ret)
159-
return ret;
160-
161-
switch (v & AXP20X_VBUS_CLIMIT_MASK) {
162-
case AXP813_VBUS_CLIMIT_900mA:
163-
*val = 900000;
164-
break;
165-
case AXP813_VBUS_CLIMIT_1500mA:
166-
*val = 1500000;
167-
break;
168-
case AXP813_VBUS_CLIMIT_2000mA:
169-
*val = 2000000;
170-
break;
171-
case AXP813_VBUS_CLIMIT_2500mA:
172-
*val = 2500000;
173-
break;
174-
}
175-
return 0;
176-
}
177-
178125
static int axp20x_usb_power_get_property(struct power_supply *psy,
179126
enum power_supply_property psp, union power_supply_propval *val)
180127
{
@@ -213,9 +160,12 @@ static int axp20x_usb_power_get_property(struct power_supply *psy,
213160
val->intval = ret * 1700; /* 1 step = 1.7 mV */
214161
return 0;
215162
case POWER_SUPPLY_PROP_CURRENT_MAX:
216-
if (power->axp20x_id == AXP813_ID)
217-
return axp813_get_current_max(power, &val->intval);
218-
return axp20x_get_current_max(power, &val->intval);
163+
ret = regmap_field_read(power->curr_lim_fld, &v);
164+
if (ret)
165+
return ret;
166+
167+
val->intval = power->axp_data->curr_lim_table[v];
168+
return 0;
219169
case POWER_SUPPLY_PROP_CURRENT_NOW:
220170
if (IS_ENABLED(CONFIG_AXP20X_ADC)) {
221171
ret = iio_read_channel_processed(power->vbus_i,
@@ -316,50 +266,17 @@ static int axp20x_usb_power_set_voltage_min(struct axp20x_usb_power *power,
316266
return -EINVAL;
317267
}
318268

319-
static int axp813_usb_power_set_current_max(struct axp20x_usb_power *power,
320-
int intval)
269+
static int axp20x_usb_power_set_current_max(struct axp20x_usb_power *power, int intval)
321270
{
322-
int val;
271+
const unsigned int max = GENMASK(power->axp_data->curr_lim_fld.msb,
272+
power->axp_data->curr_lim_fld.lsb);
323273

324-
switch (intval) {
325-
case 900000:
326-
return regmap_update_bits(power->regmap,
327-
AXP20X_VBUS_IPSOUT_MGMT,
328-
AXP20X_VBUS_CLIMIT_MASK,
329-
AXP813_VBUS_CLIMIT_900mA);
330-
case 1500000:
331-
case 2000000:
332-
case 2500000:
333-
val = (intval - 1000000) / 500000;
334-
return regmap_update_bits(power->regmap,
335-
AXP20X_VBUS_IPSOUT_MGMT,
336-
AXP20X_VBUS_CLIMIT_MASK, val);
337-
default:
274+
if (intval == -1)
338275
return -EINVAL;
339-
}
340276

341-
return -EINVAL;
342-
}
343-
344-
static int axp20x_usb_power_set_current_max(struct axp20x_usb_power *power,
345-
int intval)
346-
{
347-
int val;
348-
349-
switch (intval) {
350-
case 100000:
351-
if (power->axp20x_id == AXP221_ID)
352-
return -EINVAL;
353-
fallthrough;
354-
case 500000:
355-
case 900000:
356-
val = (900000 - intval) / 400000;
357-
return regmap_update_bits(power->regmap,
358-
AXP20X_VBUS_IPSOUT_MGMT,
359-
AXP20X_VBUS_CLIMIT_MASK, val);
360-
default:
361-
return -EINVAL;
362-
}
277+
for (unsigned int i = 0; i <= max; ++i)
278+
if (power->axp_data->curr_lim_table[i] == intval)
279+
return regmap_field_write(power->curr_lim_fld, i);
363280

364281
return -EINVAL;
365282
}
@@ -380,9 +297,6 @@ static int axp20x_usb_power_set_property(struct power_supply *psy,
380297
return axp20x_usb_power_set_voltage_min(power, val->intval);
381298

382299
case POWER_SUPPLY_PROP_CURRENT_MAX:
383-
if (power->axp20x_id == AXP813_ID)
384-
return axp813_usb_power_set_current_max(power,
385-
val->intval);
386300
return axp20x_usb_power_set_current_max(power, val->intval);
387301

388302
default:
@@ -461,39 +375,61 @@ static const char * const axp22x_irq_names[] = {
461375
"VBUS_REMOVAL",
462376
};
463377

464-
struct axp_data {
465-
const struct power_supply_desc *power_desc;
466-
const char * const *irq_names;
467-
unsigned int num_irq_names;
468-
enum axp20x_variants axp20x_id;
378+
static int axp20x_usb_curr_lim_table[] = {
379+
900000,
380+
500000,
381+
100000,
382+
-1,
383+
};
384+
385+
static int axp221_usb_curr_lim_table[] = {
386+
900000,
387+
500000,
388+
-1,
389+
-1,
390+
};
391+
392+
static int axp813_usb_curr_lim_table[] = {
393+
900000,
394+
1500000,
395+
2000000,
396+
2500000,
469397
};
470398

471399
static const struct axp_data axp202_data = {
472400
.power_desc = &axp20x_usb_power_desc,
473401
.irq_names = axp20x_irq_names,
474402
.num_irq_names = ARRAY_SIZE(axp20x_irq_names),
475403
.axp20x_id = AXP202_ID,
404+
.curr_lim_table = axp20x_usb_curr_lim_table,
405+
.curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1),
476406
};
477407

478408
static const struct axp_data axp221_data = {
479409
.power_desc = &axp22x_usb_power_desc,
480410
.irq_names = axp22x_irq_names,
481411
.num_irq_names = ARRAY_SIZE(axp22x_irq_names),
482412
.axp20x_id = AXP221_ID,
413+
.curr_lim_table = axp221_usb_curr_lim_table,
414+
.curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1),
483415
};
484416

485417
static const struct axp_data axp223_data = {
486418
.power_desc = &axp22x_usb_power_desc,
487419
.irq_names = axp22x_irq_names,
488420
.num_irq_names = ARRAY_SIZE(axp22x_irq_names),
489421
.axp20x_id = AXP223_ID,
422+
.curr_lim_table = axp20x_usb_curr_lim_table,
423+
.curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1),
490424
};
491425

492426
static const struct axp_data axp813_data = {
493427
.power_desc = &axp22x_usb_power_desc,
494428
.irq_names = axp22x_irq_names,
495429
.num_irq_names = ARRAY_SIZE(axp22x_irq_names),
496430
.axp20x_id = AXP813_ID,
431+
.curr_lim_table = axp813_usb_curr_lim_table,
432+
.curr_lim_fld = REG_FIELD(AXP20X_VBUS_IPSOUT_MGMT, 0, 1),
497433
};
498434

499435
#ifdef CONFIG_PM_SLEEP
@@ -592,9 +528,15 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
592528
platform_set_drvdata(pdev, power);
593529

594530
power->axp20x_id = axp_data->axp20x_id;
531+
power->axp_data = axp_data;
595532
power->regmap = axp20x->regmap;
596533
power->num_irqs = axp_data->num_irq_names;
597534

535+
power->curr_lim_fld = devm_regmap_field_alloc(&pdev->dev, power->regmap,
536+
axp_data->curr_lim_fld);
537+
if (IS_ERR(power->curr_lim_fld))
538+
return PTR_ERR(power->curr_lim_fld);
539+
598540
ret = devm_delayed_work_autocancel(&pdev->dev, &power->vbus_detect,
599541
axp20x_usb_power_poll_vbus);
600542
if (ret)

0 commit comments

Comments
 (0)