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 */
30 CHARGE_MODE_LONGLIFE
= 6, /* Used for Long Life */
33 #define CHARGE_LOWER_LIMIT_MIN 50
34 #define CHARGE_LOWER_LIMIT_MAX 95
35 #define CHARGE_UPPER_LIMIT_MIN 55
36 #define CHARGE_UPPER_LIMIT_MAX 100
38 /* Convert from POWER_SUPPLY_PROP_CHARGE_TYPE value to the EC's charge mode */
39 static int psp_val_to_charge_mode(int psp_val
)
42 case POWER_SUPPLY_CHARGE_TYPE_TRICKLE
:
43 return CHARGE_MODE_AC
;
44 case POWER_SUPPLY_CHARGE_TYPE_FAST
:
45 return CHARGE_MODE_EXP
;
46 case POWER_SUPPLY_CHARGE_TYPE_STANDARD
:
47 return CHARGE_MODE_STD
;
48 case POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE
:
49 return CHARGE_MODE_AUTO
;
50 case POWER_SUPPLY_CHARGE_TYPE_CUSTOM
:
51 return CHARGE_MODE_CUSTOM
;
52 case POWER_SUPPLY_CHARGE_TYPE_LONGLIFE
:
53 return CHARGE_MODE_LONGLIFE
;
59 /* Convert from EC's charge mode to POWER_SUPPLY_PROP_CHARGE_TYPE value */
60 static int charge_mode_to_psp_val(enum charge_mode mode
)
64 return POWER_SUPPLY_CHARGE_TYPE_TRICKLE
;
66 return POWER_SUPPLY_CHARGE_TYPE_FAST
;
68 return POWER_SUPPLY_CHARGE_TYPE_STANDARD
;
69 case CHARGE_MODE_AUTO
:
70 return POWER_SUPPLY_CHARGE_TYPE_ADAPTIVE
;
71 case CHARGE_MODE_CUSTOM
:
72 return POWER_SUPPLY_CHARGE_TYPE_CUSTOM
;
73 case CHARGE_MODE_LONGLIFE
:
74 return POWER_SUPPLY_CHARGE_TYPE_LONGLIFE
;
80 static enum power_supply_property wilco_charge_props
[] = {
81 POWER_SUPPLY_PROP_CHARGE_TYPE
,
82 POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD
,
83 POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD
,
86 static int wilco_charge_get_property(struct power_supply
*psy
,
87 enum power_supply_property psp
,
88 union power_supply_propval
*val
)
90 struct wilco_ec_device
*ec
= power_supply_get_drvdata(psy
);
96 case POWER_SUPPLY_PROP_CHARGE_TYPE
:
97 property_id
= PID_CHARGE_MODE
;
99 case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD
:
100 property_id
= PID_CHARGE_LOWER_LIMIT
;
102 case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD
:
103 property_id
= PID_CHARGE_UPPER_LIMIT
;
109 ret
= wilco_ec_get_byte_property(ec
, property_id
, &raw
);
112 if (property_id
== PID_CHARGE_MODE
) {
113 ret
= charge_mode_to_psp_val(raw
);
123 static int wilco_charge_set_property(struct power_supply
*psy
,
124 enum power_supply_property psp
,
125 const union power_supply_propval
*val
)
127 struct wilco_ec_device
*ec
= power_supply_get_drvdata(psy
);
131 case POWER_SUPPLY_PROP_CHARGE_TYPE
:
132 mode
= psp_val_to_charge_mode(val
->intval
);
135 return wilco_ec_set_byte_property(ec
, PID_CHARGE_MODE
, mode
);
136 case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD
:
137 if (val
->intval
< CHARGE_LOWER_LIMIT_MIN
||
138 val
->intval
> CHARGE_LOWER_LIMIT_MAX
)
140 return wilco_ec_set_byte_property(ec
, PID_CHARGE_LOWER_LIMIT
,
142 case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD
:
143 if (val
->intval
< CHARGE_UPPER_LIMIT_MIN
||
144 val
->intval
> CHARGE_UPPER_LIMIT_MAX
)
146 return wilco_ec_set_byte_property(ec
, PID_CHARGE_UPPER_LIMIT
,
153 static int wilco_charge_property_is_writeable(struct power_supply
*psy
,
154 enum power_supply_property psp
)
159 static const struct power_supply_desc wilco_ps_desc
= {
160 .properties
= wilco_charge_props
,
161 .num_properties
= ARRAY_SIZE(wilco_charge_props
),
162 .get_property
= wilco_charge_get_property
,
163 .set_property
= wilco_charge_set_property
,
164 .property_is_writeable
= wilco_charge_property_is_writeable
,
166 .type
= POWER_SUPPLY_TYPE_MAINS
,
169 static int wilco_charge_probe(struct platform_device
*pdev
)
171 struct wilco_ec_device
*ec
= dev_get_drvdata(pdev
->dev
.parent
);
172 struct power_supply_config psy_cfg
= {};
173 struct power_supply
*psy
;
175 psy_cfg
.drv_data
= ec
;
176 psy
= devm_power_supply_register(&pdev
->dev
, &wilco_ps_desc
, &psy_cfg
);
178 return PTR_ERR_OR_ZERO(psy
);
181 static struct platform_driver wilco_charge_driver
= {
182 .probe
= wilco_charge_probe
,
187 module_platform_driver(wilco_charge_driver
);
189 MODULE_ALIAS("platform:" DRV_NAME
);
190 MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>");
191 MODULE_LICENSE("GPL v2");
192 MODULE_DESCRIPTION("Wilco EC charge control driver");