brintos

brintos / linux-shallow public Read only

0
0
Text · 12.5 KiB · b3d8b1c Raw
540 lines · c
1// SPDX-License-Identifier: GPL-2.02// Copyright (C) 2018 Spreadtrum Communications Inc.3 4#include <linux/module.h>5#include <linux/platform_device.h>6#include <linux/power_supply.h>7#include <linux/usb/phy.h>8#include <linux/regmap.h>9#include <linux/notifier.h>10#include <linux/of.h>11 12/* PMIC global registers definition */13#define SC2731_CHARGE_STATUS		0xedc14#define SC2731_CHARGE_FULL		BIT(4)15#define SC2731_MODULE_EN1		0xc0c16#define SC2731_CHARGE_EN		BIT(5)17 18/* SC2731 switch charger registers definition */19#define SC2731_CHG_CFG0			0x020#define SC2731_CHG_CFG1			0x421#define SC2731_CHG_CFG2			0x822#define SC2731_CHG_CFG3			0xc23#define SC2731_CHG_CFG4			0x1024#define SC2731_CHG_CFG5			0x2825 26/* SC2731_CHG_CFG0 register definition */27#define SC2731_PRECHG_RNG_SHIFT		1128#define SC2731_PRECHG_RNG_MASK		GENMASK(12, 11)29 30#define SC2731_TERMINATION_VOL_MASK	GENMASK(2, 1)31#define SC2731_TERMINATION_VOL_SHIFT	132#define SC2731_TERMINATION_VOL_CAL_MASK	GENMASK(8, 3)33#define SC2731_TERMINATION_VOL_CAL_SHIFT	334#define SC2731_TERMINATION_CUR_MASK	GENMASK(2, 0)35 36#define SC2731_CC_EN			BIT(13)37#define SC2731_CHARGER_PD		BIT(0)38 39/* SC2731_CHG_CFG1 register definition */40#define SC2731_CUR_MASK			GENMASK(5, 0)41 42/* SC2731_CHG_CFG5 register definition */43#define SC2731_CUR_LIMIT_SHIFT		844#define SC2731_CUR_LIMIT_MASK		GENMASK(9, 8)45 46/* Default current definition (unit is mA) */47#define SC2731_CURRENT_LIMIT_100	10048#define SC2731_CURRENT_LIMIT_500	50049#define SC2731_CURRENT_LIMIT_900	90050#define SC2731_CURRENT_LIMIT_2000	200051#define SC2731_CURRENT_PRECHG		45052#define SC2731_CURRENT_STEP		5053 54struct sc2731_charger_info {55	struct device *dev;56	struct regmap *regmap;57	struct usb_phy *usb_phy;58	struct notifier_block usb_notify;59	struct power_supply *psy_usb;60	struct work_struct work;61	struct mutex lock;62	bool charging;63	u32 base;64	u32 limit;65};66 67static void sc2731_charger_stop_charge(struct sc2731_charger_info *info)68{69	regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG0,70			   SC2731_CC_EN, 0);71 72	regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG0,73			   SC2731_CHARGER_PD, SC2731_CHARGER_PD);74}75 76static int sc2731_charger_start_charge(struct sc2731_charger_info *info)77{78	int ret;79 80	/* Enable charger constant current mode */81	ret = regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG0,82				 SC2731_CC_EN, SC2731_CC_EN);83	if (ret)84		return ret;85 86	/* Start charging */87	return regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG0,88				  SC2731_CHARGER_PD, 0);89}90 91static int sc2731_charger_set_current_limit(struct sc2731_charger_info *info,92					    u32 limit)93{94	u32 val;95 96	if (limit <= SC2731_CURRENT_LIMIT_100)97		val = 0;98	else if (limit <= SC2731_CURRENT_LIMIT_500)99		val = 3;100	else if (limit <= SC2731_CURRENT_LIMIT_900)101		val = 2;102	else103		val = 1;104 105	return regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG5,106				  SC2731_CUR_LIMIT_MASK,107				  val << SC2731_CUR_LIMIT_SHIFT);108}109 110static int sc2731_charger_set_current(struct sc2731_charger_info *info, u32 cur)111{112	u32 val;113	int ret;114 115	if (cur > SC2731_CURRENT_LIMIT_2000)116		cur = SC2731_CURRENT_LIMIT_2000;117	else if (cur < SC2731_CURRENT_PRECHG)118		cur = SC2731_CURRENT_PRECHG;119 120	/* Calculate the step value, each step is 50 mA */121	val = (cur - SC2731_CURRENT_PRECHG) / SC2731_CURRENT_STEP;122 123	/* Set pre-charge current as 450 mA */124	ret = regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG0,125				 SC2731_PRECHG_RNG_MASK,126				 0x3 << SC2731_PRECHG_RNG_SHIFT);127	if (ret)128		return ret;129 130	return regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG1,131				  SC2731_CUR_MASK, val);132}133 134static int sc2731_charger_get_status(struct sc2731_charger_info *info)135{136	u32 val;137	int ret;138 139	ret = regmap_read(info->regmap, SC2731_CHARGE_STATUS, &val);140	if (ret)141		return ret;142 143	if (val & SC2731_CHARGE_FULL)144		return POWER_SUPPLY_STATUS_FULL;145 146	return POWER_SUPPLY_STATUS_CHARGING;147}148 149static int sc2731_charger_get_current(struct sc2731_charger_info *info,150				      u32 *cur)151{152	int ret;153	u32 val;154 155	ret = regmap_read(info->regmap, info->base + SC2731_CHG_CFG1, &val);156	if (ret)157		return ret;158 159	val &= SC2731_CUR_MASK;160	*cur = val * SC2731_CURRENT_STEP + SC2731_CURRENT_PRECHG;161 162	return 0;163}164 165static int sc2731_charger_get_current_limit(struct sc2731_charger_info *info,166					    u32 *cur)167{168	int ret;169	u32 val;170 171	ret = regmap_read(info->regmap, info->base + SC2731_CHG_CFG5, &val);172	if (ret)173		return ret;174 175	val = (val & SC2731_CUR_LIMIT_MASK) >> SC2731_CUR_LIMIT_SHIFT;176 177	switch (val) {178	case 0:179		*cur = SC2731_CURRENT_LIMIT_100;180		break;181 182	case 1:183		*cur = SC2731_CURRENT_LIMIT_2000;184		break;185 186	case 2:187		*cur = SC2731_CURRENT_LIMIT_900;188		break;189 190	case 3:191		*cur = SC2731_CURRENT_LIMIT_500;192		break;193 194	default:195		return -EINVAL;196	}197 198	return 0;199}200 201static int202sc2731_charger_usb_set_property(struct power_supply *psy,203				enum power_supply_property psp,204				const union power_supply_propval *val)205{206	struct sc2731_charger_info *info = power_supply_get_drvdata(psy);207	int ret;208 209	mutex_lock(&info->lock);210 211	if (!info->charging) {212		mutex_unlock(&info->lock);213		return -ENODEV;214	}215 216	switch (psp) {217	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:218		ret = sc2731_charger_set_current(info, val->intval / 1000);219		if (ret < 0)220			dev_err(info->dev, "set charge current failed\n");221		break;222 223	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:224		ret = sc2731_charger_set_current_limit(info,225						       val->intval / 1000);226		if (ret < 0)227			dev_err(info->dev, "set input current limit failed\n");228		break;229 230	default:231		ret = -EINVAL;232	}233 234	mutex_unlock(&info->lock);235	return ret;236}237 238static int sc2731_charger_usb_get_property(struct power_supply *psy,239					   enum power_supply_property psp,240					   union power_supply_propval *val)241{242	struct sc2731_charger_info *info = power_supply_get_drvdata(psy);243	int ret = 0;244	u32 cur;245 246	mutex_lock(&info->lock);247 248	switch (psp) {249	case POWER_SUPPLY_PROP_STATUS:250		if (info->charging)251			val->intval = sc2731_charger_get_status(info);252		else253			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;254		break;255 256	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:257		if (!info->charging) {258			val->intval = 0;259		} else {260			ret = sc2731_charger_get_current(info, &cur);261			if (ret)262				goto out;263 264			val->intval = cur * 1000;265		}266		break;267 268	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:269		if (!info->charging) {270			val->intval = 0;271		} else {272			ret = sc2731_charger_get_current_limit(info, &cur);273			if (ret)274				goto out;275 276			val->intval = cur * 1000;277		}278		break;279 280	default:281		ret = -EINVAL;282	}283 284out:285	mutex_unlock(&info->lock);286	return ret;287}288 289static int sc2731_charger_property_is_writeable(struct power_supply *psy,290						enum power_supply_property psp)291{292	int ret;293 294	switch (psp) {295	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:296	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:297		ret = 1;298		break;299 300	default:301		ret = 0;302	}303 304	return ret;305}306 307static enum power_supply_property sc2731_usb_props[] = {308	POWER_SUPPLY_PROP_STATUS,309	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,310	POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,311};312 313static const struct power_supply_desc sc2731_charger_desc = {314	.name			= "sc2731_charger",315	.type			= POWER_SUPPLY_TYPE_USB,316	.properties		= sc2731_usb_props,317	.num_properties		= ARRAY_SIZE(sc2731_usb_props),318	.get_property		= sc2731_charger_usb_get_property,319	.set_property		= sc2731_charger_usb_set_property,320	.property_is_writeable	= sc2731_charger_property_is_writeable,321};322 323static void sc2731_charger_work(struct work_struct *data)324{325	struct sc2731_charger_info *info =326		container_of(data, struct sc2731_charger_info, work);327	int ret;328 329	mutex_lock(&info->lock);330 331	if (info->limit > 0 && !info->charging) {332		/* set current limitation and start to charge */333		ret = sc2731_charger_set_current_limit(info, info->limit);334		if (ret)335			goto out;336 337		ret = sc2731_charger_set_current(info, info->limit);338		if (ret)339			goto out;340 341		ret = sc2731_charger_start_charge(info);342		if (ret)343			goto out;344 345		info->charging = true;346	} else if (!info->limit && info->charging) {347		/* Stop charging */348		info->charging = false;349		sc2731_charger_stop_charge(info);350	}351 352out:353	mutex_unlock(&info->lock);354}355 356static int sc2731_charger_usb_change(struct notifier_block *nb,357				     unsigned long limit, void *data)358{359	struct sc2731_charger_info *info =360		container_of(nb, struct sc2731_charger_info, usb_notify);361 362	info->limit = limit;363 364	schedule_work(&info->work);365 366	return NOTIFY_OK;367}368 369static int sc2731_charger_hw_init(struct sc2731_charger_info *info)370{371	struct power_supply_battery_info *bat_info;372	u32 term_currrent, term_voltage, cur_val, vol_val;373	int ret;374 375	/* Enable charger module */376	ret = regmap_update_bits(info->regmap, SC2731_MODULE_EN1,377				 SC2731_CHARGE_EN, SC2731_CHARGE_EN);378	if (ret)379		return ret;380 381	ret = power_supply_get_battery_info(info->psy_usb, &bat_info);382	if (ret) {383		dev_warn(info->dev, "no battery information is supplied\n");384 385		/*386		 * If no battery information is supplied, we should set387		 * default charge termination current to 120 mA, and default388		 * charge termination voltage to 4.35V.389		 */390		cur_val = 0x2;391		vol_val = 0x1;392	} else {393		term_currrent = bat_info->charge_term_current_ua / 1000;394 395		if (term_currrent <= 90)396			cur_val = 0;397		else if (term_currrent >= 265)398			cur_val = 0x7;399		else400			cur_val = ((term_currrent - 90) / 25) + 1;401 402		term_voltage = bat_info->constant_charge_voltage_max_uv / 1000;403 404		if (term_voltage > 4500)405			term_voltage = 4500;406 407		if (term_voltage > 4200)408			vol_val = (term_voltage - 4200) / 100;409		else410			vol_val = 0;411 412		power_supply_put_battery_info(info->psy_usb, bat_info);413	}414 415	/* Set charge termination current */416	ret = regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG2,417				 SC2731_TERMINATION_CUR_MASK, cur_val);418	if (ret)419		goto error;420 421	/* Set charge termination voltage */422	ret = regmap_update_bits(info->regmap, info->base + SC2731_CHG_CFG0,423				 SC2731_TERMINATION_VOL_MASK |424				 SC2731_TERMINATION_VOL_CAL_MASK,425				 (vol_val << SC2731_TERMINATION_VOL_SHIFT) |426				 (0x6 << SC2731_TERMINATION_VOL_CAL_SHIFT));427	if (ret)428		goto error;429 430	return 0;431 432error:433	regmap_update_bits(info->regmap, SC2731_MODULE_EN1, SC2731_CHARGE_EN, 0);434	return ret;435}436 437static void sc2731_charger_detect_status(struct sc2731_charger_info *info)438{439	unsigned int min, max;440 441	/*442	 * If the USB charger status has been USB_CHARGER_PRESENT before443	 * registering the notifier, we should start to charge with getting444	 * the charge current.445	 */446	if (info->usb_phy->chg_state != USB_CHARGER_PRESENT)447		return;448 449	usb_phy_get_charger_current(info->usb_phy, &min, &max);450	info->limit = min;451 452	schedule_work(&info->work);453}454 455static int sc2731_charger_probe(struct platform_device *pdev)456{457	struct device_node *np = pdev->dev.of_node;458	struct sc2731_charger_info *info;459	struct power_supply_config charger_cfg = { };460	int ret;461 462	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);463	if (!info)464		return -ENOMEM;465 466	mutex_init(&info->lock);467	info->dev = &pdev->dev;468	INIT_WORK(&info->work, sc2731_charger_work);469 470	info->regmap = dev_get_regmap(pdev->dev.parent, NULL);471	if (!info->regmap) {472		dev_err(&pdev->dev, "failed to get charger regmap\n");473		return -ENODEV;474	}475 476	ret = of_property_read_u32(np, "reg", &info->base);477	if (ret) {478		dev_err(&pdev->dev, "failed to get register address\n");479		return -ENODEV;480	}481 482	charger_cfg.drv_data = info;483	charger_cfg.of_node = np;484	info->psy_usb = devm_power_supply_register(&pdev->dev,485						   &sc2731_charger_desc,486						   &charger_cfg);487	if (IS_ERR(info->psy_usb)) {488		dev_err(&pdev->dev, "failed to register power supply\n");489		return PTR_ERR(info->psy_usb);490	}491 492	ret = sc2731_charger_hw_init(info);493	if (ret)494		return ret;495 496	info->usb_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "phys", 0);497	if (IS_ERR(info->usb_phy)) {498		dev_err(&pdev->dev, "failed to find USB phy\n");499		return PTR_ERR(info->usb_phy);500	}501 502	info->usb_notify.notifier_call = sc2731_charger_usb_change;503	ret = usb_register_notifier(info->usb_phy, &info->usb_notify);504	if (ret) {505		dev_err(&pdev->dev, "failed to register notifier: %d\n", ret);506		return ret;507	}508 509	sc2731_charger_detect_status(info);510 511	return 0;512}513 514static void sc2731_charger_remove(struct platform_device *pdev)515{516	struct sc2731_charger_info *info = platform_get_drvdata(pdev);517 518	usb_unregister_notifier(info->usb_phy, &info->usb_notify);519}520 521static const struct of_device_id sc2731_charger_of_match[] = {522	{ .compatible = "sprd,sc2731-charger", },523	{ }524};525MODULE_DEVICE_TABLE(of, sc2731_charger_of_match);526 527static struct platform_driver sc2731_charger_driver = {528	.driver = {529		.name = "sc2731-charger",530		.of_match_table = sc2731_charger_of_match,531	},532	.probe = sc2731_charger_probe,533	.remove_new = sc2731_charger_remove,534};535 536module_platform_driver(sc2731_charger_driver);537 538MODULE_DESCRIPTION("Spreadtrum SC2731 Charger Driver");539MODULE_LICENSE("GPL v2");540