1 // SPDX-License-Identifier: GPL-2.0
3 * Charging control driver for the Wilco EC
5 * Copyright 2019 Google LLC
7 * See Documentation/ABI/testing/sysfs-class-power and
8 * Documentation/ABI/testing/sysfs-class-power-wilco for userspace interface
12 #include <linux/module.h>
13 #include <linux/platform_device.h>
14 #include <linux/platform_data/wilco-ec.h>
15 #include <linux/power_supply.h>
17 #define DRV_NAME "wilco-charger"
19 /* Property IDs and related EC constants */
20 #define PID_CHARGE_MODE 0x0710
21 #define PID_CHARGE_LOWER_LIMIT 0x0711
22 #define PID_CHARGE_UPPER_LIMIT 0x0712
25 CHARGE_MODE_STD
= 1, /* Used for Standard */
26 CHARGE_MODE_EXP
= 2, /* Express Charge, used for Fast */
27 CHARGE_MODE_AC
= 3, /* Mostly AC use, used for Trickle */
28 CHARGE_MODE_AUTO
= 4, /* Used for Adaptive */
29 CHARGE_MODE_CUSTOM
= 5, /* Used for Custom */
32 #define CHARGE_LOWER_LIMIT_MIN 50
33 #define CHARGE_LOWER_LIMIT_MAX 95
34 #define CHARGE_UPPER_LIMIT_MIN 55
35 #define CHARGE_UPPER_LIMIT_MAX 100
37 /* Convert from POWER_SUPPLY_PROP_CHARGE_TYPE value to the EC's charge mode */
38 static int psp_val_to_charge_mode(int psp_val
)
41 case POWER_SUPPLY_CHARGE_TYPE_TRICKLE
:
42 return CHARGE_MODE_AC
;
43 case POWER_SUPPLY_CHARGE_TYPE_FAST
:
44 return CHARGE_MODE_EXP
;
45 case POWER_SUPPLY_CHARGE_TYPE_STANDARD
:
46 return CHARGE_MODE_STD
;
47 case POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE
:
48 return CHARGE_MODE_AUTO
;
49 case POWER_SUPPLY_CHARGE_TYPE_CUSTOM
:
50 return CHARGE_MODE_CUSTOM
;
56 /* Convert from EC's charge mode to POWER_SUPPLY_PROP_CHARGE_TYPE value */
57 static int charge_mode_to_psp_val(enum charge_mode mode
)
61 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE
;
63 return POWER_SUPPLY_CHARGE_TYPE_FAST
;
65 return POWER_SUPPLY_CHARGE_TYPE_STANDARD
;
66 case CHARGE_MODE_AUTO
:
67 return POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE
;
68 case CHARGE_MODE_CUSTOM
:
69 return POWER_SUPPLY_CHARGE_TYPE_CUSTOM
;
75 static enum power_supply_property wilco_charge_props
[] = {
76 POWER_SUPPLY_PROP_CHARGE_TYPE
,
77 POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD
,
78 POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD
,
81 static int wilco_charge_get_property(struct power_supply
*psy
,
82 enum power_supply_property psp
,
83 union power_supply_propval
*val
)
85 struct wilco_ec_device
*ec
= power_supply_get_drvdata(psy
);
91 case POWER_SUPPLY_PROP_CHARGE_TYPE
:
92 property_id
= PID_CHARGE_MODE
;
94 case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD
:
95 property_id
= PID_CHARGE_LOWER_LIMIT
;
97 case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD
:
98 property_id
= PID_CHARGE_UPPER_LIMIT
;
104 ret
= wilco_ec_get_byte_property(ec
, property_id
, &raw
);
107 if (property_id
== PID_CHARGE_MODE
) {
108 ret
= charge_mode_to_psp_val(raw
);
118 static int wilco_charge_set_property(struct power_supply
*psy
,
119 enum power_supply_property psp
,
120 const union power_supply_propval
*val
)
122 struct wilco_ec_device
*ec
= power_supply_get_drvdata(psy
);
126 case POWER_SUPPLY_PROP_CHARGE_TYPE
:
127 mode
= psp_val_to_charge_mode(val
->intval
);
130 return wilco_ec_set_byte_property(ec
, PID_CHARGE_MODE
, mode
);
131 case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD
:
132 if (val
->intval
< CHARGE_LOWER_LIMIT_MIN
||
133 val
->intval
> CHARGE_LOWER_LIMIT_MAX
)
135 return wilco_ec_set_byte_property(ec
, PID_CHARGE_LOWER_LIMIT
,
137 case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD
:
138 if (val
->intval
< CHARGE_UPPER_LIMIT_MIN
||
139 val
->intval
> CHARGE_UPPER_LIMIT_MAX
)
141 return wilco_ec_set_byte_property(ec
, PID_CHARGE_UPPER_LIMIT
,
148 static int wilco_charge_property_is_writeable(struct power_supply
*psy
,
149 enum power_supply_property psp
)
154 static const struct power_supply_desc wilco_ps_desc
= {
155 .properties
= wilco_charge_props
,
156 .num_properties
= ARRAY_SIZE(wilco_charge_props
),
157 .get_property
= wilco_charge_get_property
,
158 .set_property
= wilco_charge_set_property
,
159 .property_is_writeable
= wilco_charge_property_is_writeable
,
161 .type
= POWER_SUPPLY_TYPE_MAINS
,
164 static int wilco_charge_probe(struct platform_device
*pdev
)
166 struct wilco_ec_device
*ec
= dev_get_drvdata(pdev
->dev
.parent
);
167 struct power_supply_config psy_cfg
= {};
168 struct power_supply
*psy
;
170 psy_cfg
.drv_data
= ec
;
171 psy
= devm_power_supply_register(&pdev
->dev
, &wilco_ps_desc
, &psy_cfg
);
173 return PTR_ERR_OR_ZERO(psy
);
176 static struct platform_driver wilco_charge_driver
= {
177 .probe
= wilco_charge_probe
,
182 module_platform_driver(wilco_charge_driver
);
184 MODULE_ALIAS("platform:" DRV_NAME
);
185 MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>");
186 MODULE_LICENSE("GPL v2");
187 MODULE_DESCRIPTION("Wilco EC charge control driver");