brintos

brintos / linux-shallow public Read only

0
0
Text · 5.3 KiB · 98ade07 Raw
193 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Charging control driver for the Wilco EC4 *5 * Copyright 2019 Google LLC6 *7 * See Documentation/ABI/testing/sysfs-class-power and8 * Documentation/ABI/testing/sysfs-class-power-wilco for userspace interface9 * and other info.10 */11 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>16 17#define DRV_NAME "wilco-charger"18 19/* Property IDs and related EC constants */20#define PID_CHARGE_MODE		0x071021#define PID_CHARGE_LOWER_LIMIT	0x071122#define PID_CHARGE_UPPER_LIMIT	0x071223 24enum charge_mode {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 */31};32 33#define CHARGE_LOWER_LIMIT_MIN	5034#define CHARGE_LOWER_LIMIT_MAX	9535#define CHARGE_UPPER_LIMIT_MIN	5536#define CHARGE_UPPER_LIMIT_MAX	10037 38/* Convert from POWER_SUPPLY_PROP_CHARGE_TYPE value to the EC's charge mode */39static int psp_val_to_charge_mode(int psp_val)40{41	switch (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;54	default:55		return -EINVAL;56	}57}58 59/* Convert from EC's charge mode to POWER_SUPPLY_PROP_CHARGE_TYPE value */60static int charge_mode_to_psp_val(enum charge_mode mode)61{62	switch (mode) {63	case CHARGE_MODE_AC:64		return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;65	case CHARGE_MODE_EXP:66		return POWER_SUPPLY_CHARGE_TYPE_FAST;67	case CHARGE_MODE_STD: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;75	default:76		return -EINVAL;77	}78}79 80static 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,84};85 86static int wilco_charge_get_property(struct power_supply *psy,87				     enum power_supply_property psp,88				     union power_supply_propval *val)89{90	struct wilco_ec_device *ec = power_supply_get_drvdata(psy);91	u32 property_id;92	int ret;93	u8 raw;94 95	switch (psp) {96	case POWER_SUPPLY_PROP_CHARGE_TYPE:97		property_id = PID_CHARGE_MODE;98		break;99	case POWER_SUPPLY_PROP_CHARGE_CONTROL_START_THRESHOLD:100		property_id = PID_CHARGE_LOWER_LIMIT;101		break;102	case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:103		property_id = PID_CHARGE_UPPER_LIMIT;104		break;105	default:106		return -EINVAL;107	}108 109	ret = wilco_ec_get_byte_property(ec, property_id, &raw);110	if (ret < 0)111		return ret;112	if (property_id == PID_CHARGE_MODE) {113		ret = charge_mode_to_psp_val(raw);114		if (ret < 0)115			return -EBADMSG;116		raw = ret;117	}118	val->intval = raw;119 120	return 0;121}122 123static int wilco_charge_set_property(struct power_supply *psy,124				     enum power_supply_property psp,125				     const union power_supply_propval *val)126{127	struct wilco_ec_device *ec = power_supply_get_drvdata(psy);128	int mode;129 130	switch (psp) {131	case POWER_SUPPLY_PROP_CHARGE_TYPE:132		mode = psp_val_to_charge_mode(val->intval);133		if (mode < 0)134			return -EINVAL;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)139			return -EINVAL;140		return wilco_ec_set_byte_property(ec, PID_CHARGE_LOWER_LIMIT,141						  val->intval);142	case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:143		if (val->intval < CHARGE_UPPER_LIMIT_MIN ||144		    val->intval > CHARGE_UPPER_LIMIT_MAX)145			return -EINVAL;146		return wilco_ec_set_byte_property(ec, PID_CHARGE_UPPER_LIMIT,147						  val->intval);148	default:149		return -EINVAL;150	}151}152 153static int wilco_charge_property_is_writeable(struct power_supply *psy,154					      enum power_supply_property psp)155{156	return 1;157}158 159static 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,165	.name			= DRV_NAME,166	.type			= POWER_SUPPLY_TYPE_MAINS,167};168 169static int wilco_charge_probe(struct platform_device *pdev)170{171	struct wilco_ec_device *ec = dev_get_drvdata(pdev->dev.parent);172	struct power_supply_config psy_cfg = {};173	struct power_supply *psy;174 175	psy_cfg.drv_data = ec;176	psy = devm_power_supply_register(&pdev->dev, &wilco_ps_desc, &psy_cfg);177 178	return PTR_ERR_OR_ZERO(psy);179}180 181static struct platform_driver wilco_charge_driver = {182	.probe	= wilco_charge_probe,183	.driver = {184		.name = DRV_NAME,185	}186};187module_platform_driver(wilco_charge_driver);188 189MODULE_ALIAS("platform:" DRV_NAME);190MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>");191MODULE_LICENSE("GPL v2");192MODULE_DESCRIPTION("Wilco EC charge control driver");193