Message ID | 1452242773-18887-2-git-send-email-wenyou.yang@atmel.com (mailing list archive) |
---|---|
State | Not Applicable, archived |
Headers | show |
2016-01-08 17:46 GMT+09:00 Wenyou Yang <wenyou.yang@atmel.com>: > This patch adds new driver for Active-semi ACT8945A ActivePath > charger (part of ACT8945A MFD driver) providing power supply class > information to userspace. > > The driver is configured through DTS (battery and system related > settings) and sysfs entries (timers and input over-voltage threshold). > > Signed-off-by: Wenyou Yang <wenyou.yang@atmel.com> > --- > > Changes in v2: > 1./ Substitute of_property_read_bool() for of_get_property(). > 2./ Substitute devm_power_supply_register() for power_supply_register(). > 3./ Use module_platform_driver(), instead of subsys_initcall(). > 4./ Substitute MODULE_LICENSE("GPL") for MODULE_LICENSE("GPL v2"). > > drivers/power/Kconfig | 7 + > drivers/power/Makefile | 1 + > drivers/power/act8945a_charger.c | 386 ++++++++++++++++++++++++++++++++++++++ > 3 files changed, 394 insertions(+) > create mode 100644 drivers/power/act8945a_charger.c > > diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig > index 1ddd13c..ae75211 100644 > --- a/drivers/power/Kconfig > +++ b/drivers/power/Kconfig > @@ -75,6 +75,13 @@ config BATTERY_88PM860X > help > Say Y here to enable battery monitor for Marvell 88PM860x chip. > > +config BATTERY_ACT8945A > + tristate "Active-semi ACT8945A charger driver" > + depends on MFD_ACT8945A > + help > + Say Y here to enable support for power supply provided by > + Active-semi ActivePath ACT8945A charger. > + > config BATTERY_DS2760 > tristate "DS2760 battery driver (HP iPAQ & others)" > depends on W1 && W1_SLAVE_DS2760 > diff --git a/drivers/power/Makefile b/drivers/power/Makefile > index 0e4eab5..e46b75d 100644 > --- a/drivers/power/Makefile > +++ b/drivers/power/Makefile > @@ -17,6 +17,7 @@ obj-$(CONFIG_WM8350_POWER) += wm8350_power.o > obj-$(CONFIG_TEST_POWER) += test_power.o > > obj-$(CONFIG_BATTERY_88PM860X) += 88pm860x_battery.o > +obj-$(CONFIG_BATTERY_ACT8945A) += act8945a_charger.o > obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o > obj-$(CONFIG_BATTERY_DS2780) += ds2780_battery.o > obj-$(CONFIG_BATTERY_DS2781) += ds2781_battery.o > diff --git a/drivers/power/act8945a_charger.c b/drivers/power/act8945a_charger.c > new file mode 100644 > index 0000000..fe9c19f > --- /dev/null > +++ b/drivers/power/act8945a_charger.c > @@ -0,0 +1,386 @@ > +/* > + * Power supply driver for the Active-semi ACT8945A PMIC > + * > + * Copyright (C) 2015 Atmel Corporation > + * Wenyou Yang <wenyou.yang@atmel.com> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + */ > + > +#include <linux/module.h> > +#include <linux/mfd/act8945a.h> > +#include <linux/of.h> > +#include <linux/of_gpio.h> > +#include <linux/platform_device.h> > +#include <linux/power_supply.h> > +#include <linux/regmap.h> > + > +static const char *act8945a_charger_model = "ACT8945A"; > +static const char *act8945a_charger_manufacturer = "Active-semi"; > + > +/** > + * ACT8945A Charger Register Map > + */ > + > +/* 0x70: Reserved */ > +#define ACT8945A_APCH_CFG 0x71 > +#define ACT8945A_APCH_STATUS 0x78 > +#define ACT8945A_APCH_CTRL 0x79 > +#define ACT8945A_APCH_STATE 0x7A > + > +/* ACT8945A_APCH_CFG */ > +#define APCH_CFG_OVPSET (0x03 << 0) > +#define APCH_CFG_OVPSET_6V6 (0x0 << 0) > +#define APCH_CFG_OVPSET_7V (0x1 << 0) > +#define APCH_CFG_OVPSET_7V5 (0x2 << 0) > +#define APCH_CFG_OVPSET_8V (0x3 << 0) > +#define APCH_CFG_PRETIMO (0x03 << 2) > +#define APCH_CFG_PRETIMO_40_MIN (0x0 << 2) > +#define APCH_CFG_PRETIMO_60_MIN (0x1 << 2) > +#define APCH_CFG_PRETIMO_80_MIN (0x2 << 2) > +#define APCH_CFG_PRETIMO_DISABLED (0x3 << 2) > +#define APCH_CFG_TOTTIMO (0x03 << 4) > +#define APCH_CFG_TOTTIMO_3_HOUR (0x0 << 4) > +#define APCH_CFG_TOTTIMO_4_HOUR (0x1 << 4) > +#define APCH_CFG_TOTTIMO_5_HOUR (0x2 << 4) > +#define APCH_CFG_TOTTIMO_DISABLED (0x3 << 4) > +#define APCH_CFG_SUSCHG (0x01 << 7) > + > +#define APCH_STATUS_CHGDAT (0x01 << 0) > +#define APCH_STATUS_INDAT (0x01 << 1) > +#define APCH_STATUS_TEMPDAT (0x01 << 2) > +#define APCH_STATUS_TIMRDAT (0x01 << 3) > +#define APCH_STATUS_CHGSTAT (0x01 << 4) > +#define APCH_STATUS_INSTAT (0x01 << 5) > +#define APCH_STATUS_TEMPSTAT (0x01 << 6) > +#define APCH_STATUS_TIMRSTAT (0x01 << 7) > + > +#define APCH_CTRL_CHGEOCOUT (0x01 << 0) > +#define APCH_CTRL_INDIS (0x01 << 1) > +#define APCH_CTRL_TEMPOUT (0x01 << 2) > +#define APCH_CTRL_TIMRPRE (0x01 << 3) > +#define APCH_CTRL_CHGEOCIN (0x01 << 4) > +#define APCH_CTRL_INCON (0x01 << 5) > +#define APCH_CTRL_TEMPIN (0x01 << 6) > +#define APCH_CTRL_TIMRTOT (0x01 << 7) > + > +#define APCH_STATE_ACINSTAT (0x01 << 1) > +#define APCH_STATE_CSTATE (0x03 << 4) > +#define APCH_STATE_CSTATE_SHIFT 4 > +#define APCH_STATE_CSTATE_DISABLED 0x00 > +#define APCH_STATE_CSTATE_EOC 0x01 > +#define APCH_STATE_CSTATE_FAST 0x02 > +#define APCH_STATE_CSTATE_PRE 0x03 > + > +struct act8945a_charger { > + struct device *dev; > + struct act8945a_dev *act8945a_dev; > + struct power_supply *psy; > + > + u32 tolal_time_out; > + u32 pre_time_out; > + u32 input_voltage_threshold; > + bool battery_temperature; > + int chglev_pin; > + int chglev_value; > +}; > + > +static int act8945a_get_charger_state(struct regmap *regmap, int *val) > +{ > + int ret; > + unsigned int status, state; > + > + ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status); > + if (ret < 0) > + return ret; > + > + ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state); > + if (ret < 0) > + return ret; > + > + state &= APCH_STATE_CSTATE; > + state >>= APCH_STATE_CSTATE_SHIFT; > + > + if (state == APCH_STATE_CSTATE_EOC) { > + if (status & APCH_STATUS_CHGDAT) > + *val = POWER_SUPPLY_STATUS_FULL; > + else > + *val = POWER_SUPPLY_STATUS_NOT_CHARGING; > + } else if ((state == APCH_STATE_CSTATE_FAST) || > + (state == APCH_STATE_CSTATE_PRE)) { > + *val = POWER_SUPPLY_STATUS_CHARGING; > + } else { > + *val = POWER_SUPPLY_STATUS_NOT_CHARGING; > + } > + > + return 0; > +} > + > +static int act8945a_get_charge_type(struct regmap *regmap, int *val) > +{ > + int ret; > + unsigned int state; > + > + ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state); > + if (ret < 0) > + return ret; > + > + state &= APCH_STATE_CSTATE; > + state >>= APCH_STATE_CSTATE_SHIFT; > + > + switch (state) { > + case APCH_STATE_CSTATE_PRE: > + *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; > + break; > + case APCH_STATE_CSTATE_FAST: > + *val = POWER_SUPPLY_CHARGE_TYPE_FAST; > + break; > + case APCH_STATE_CSTATE_EOC: > + case APCH_STATE_CSTATE_DISABLED: > + default: > + *val = POWER_SUPPLY_CHARGE_TYPE_NONE; > + } > + > + return 0; > +} > + > +static int act8945a_get_battery_health(struct act8945a_charger *charger, > + struct regmap *regmap, int *val) > +{ > + int ret; > + unsigned int status; > + > + ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status); > + if (ret < 0) > + return ret; > + > + if (charger->battery_temperature && !(status & APCH_STATUS_TEMPDAT)) > + *val = POWER_SUPPLY_HEALTH_OVERHEAT; > + else if (!(status & APCH_STATUS_INDAT)) > + *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE; > + else if (status & APCH_STATUS_TIMRDAT) > + *val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; > + else > + *val = POWER_SUPPLY_HEALTH_GOOD; > + > + return 0; > +} > + > +static enum power_supply_property act8945a_charger_props[] = { > + POWER_SUPPLY_PROP_STATUS, > + POWER_SUPPLY_PROP_CHARGE_TYPE, > + POWER_SUPPLY_PROP_TECHNOLOGY, > + POWER_SUPPLY_PROP_HEALTH, > + POWER_SUPPLY_PROP_MODEL_NAME, > + POWER_SUPPLY_PROP_MANUFACTURER > +}; > + > +static int act8945a_charger_get_property(struct power_supply *psy, > + enum power_supply_property prop, > + union power_supply_propval *val) > +{ > + struct act8945a_charger *charger = power_supply_get_drvdata(psy); > + struct regmap *regmap = charger->act8945a_dev->regmap; > + int ret = 0; > + > + switch (prop) { > + case POWER_SUPPLY_PROP_STATUS: > + ret = act8945a_get_charger_state(regmap, &val->intval); > + break; > + case POWER_SUPPLY_PROP_CHARGE_TYPE: > + ret = act8945a_get_charge_type(regmap, &val->intval); > + break; > + case POWER_SUPPLY_PROP_TECHNOLOGY: > + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; > + break; > + case POWER_SUPPLY_PROP_HEALTH: > + ret = act8945a_get_battery_health(charger, > + regmap, &val->intval); > + break; > + case POWER_SUPPLY_PROP_MODEL_NAME: > + val->strval = act8945a_charger_model; > + break; > + case POWER_SUPPLY_PROP_MANUFACTURER: > + val->strval = act8945a_charger_manufacturer; > + break; > + default: > + return -EINVAL; > + } > + > + return ret; > +} > + > +static const struct power_supply_desc act8945a_charger_desc = { > + .name = "act8945a-charger", > + .type = POWER_SUPPLY_TYPE_BATTERY, > + .get_property = act8945a_charger_get_property, > + .properties = act8945a_charger_props, > + .num_properties = ARRAY_SIZE(act8945a_charger_props), > +}; > + > +#define DEFAULT_TOTAL_TIME_OUT 3 > +#define DEFAULT_PRE_TIME_OUT 40 > +#define DEFAULT_INPUT_OVP_THRESHOLD 6600 > + > +static int act8945a_charger_parse_dt(struct device *dev, > + struct act8945a_charger *charger) > +{ > + struct device_node *np = dev->of_node; > + enum of_gpio_flags flags; > + > + if (!np) { > + dev_err(dev, "no charger of node\n"); > + return -EINVAL; > + } > + > + charger->chglev_pin = of_get_named_gpio_flags(np, > + "active-semi,chglev-gpio", 0, &flags); > + > + charger->chglev_value = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; > + > + charger->battery_temperature = of_property_read_bool(np, > + "active-semi,battery_temperature"); > + > + if (of_property_read_u32(np, "active-semi,input_voltage_threshold", > + &charger->input_voltage_threshold)) > + charger->input_voltage_threshold = DEFAULT_PRE_TIME_OUT; > + > + if (of_property_read_u32(np, "active-semi,precondition_timeout", > + &charger->pre_time_out)) > + charger->pre_time_out = DEFAULT_PRE_TIME_OUT; > + > + if (of_property_read_u32(np, "active-semi,total_timeout", > + &charger->tolal_time_out)) > + charger->tolal_time_out = DEFAULT_TOTAL_TIME_OUT; > + > + return 0; > +} > + > +static int act8945a_charger_config(struct act8945a_charger *charger) > +{ > + struct regmap *regmap = charger->act8945a_dev->regmap; > + u8 value = 0; > + > + if (gpio_is_valid(charger->chglev_pin)) > + gpio_set_value(charger->chglev_pin, charger->chglev_value); > + > + switch (charger->input_voltage_threshold) { > + case 8000: > + value |= APCH_CFG_OVPSET_8V; > + break; > + case 7500: > + value |= APCH_CFG_OVPSET_7V5; > + break; > + case 7000: > + value |= APCH_CFG_OVPSET_7V; > + break; > + case 6600: > + default: > + value |= APCH_CFG_OVPSET_6V6; > + break; > + } > + > + switch (charger->pre_time_out) { > + case 60: > + value |= APCH_CFG_PRETIMO_60_MIN; > + break; > + case 80: > + value |= APCH_CFG_PRETIMO_80_MIN; > + break; > + case 0: > + value |= APCH_CFG_PRETIMO_DISABLED; > + break; > + case 40: > + default: > + value |= APCH_CFG_PRETIMO_40_MIN; > + break; > + } > + > + switch (charger->tolal_time_out) { > + case 4: > + value |= APCH_CFG_TOTTIMO_4_HOUR; > + break; > + case 5: > + value |= APCH_CFG_TOTTIMO_5_HOUR; > + break; > + case 0: > + value |= APCH_CFG_TOTTIMO_DISABLED; > + break; > + case 3: > + default: > + value |= APCH_CFG_TOTTIMO_3_HOUR; > + break; > + } > + > + return regmap_write(regmap, ACT8945A_APCH_CFG, value); > +} > + > +static int act8945a_charger_probe(struct platform_device *pdev) > +{ > + struct act8945a_dev *act8945a_dev = dev_get_drvdata(pdev->dev.parent); > + struct act8945a_charger *charger; > + struct power_supply_config psy_cfg = {}; > + int ret; > + > + charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL); > + if (!charger) > + return -ENOMEM; > + > + platform_set_drvdata(pdev, charger); > + > + charger->dev = &pdev->dev; > + charger->act8945a_dev = act8945a_dev; > + > + ret = act8945a_charger_parse_dt(&pdev->dev, charger); > + if (ret) > + return ret; > + > + ret = act8945a_charger_config(charger); > + if (ret) > + return ret; > + > + psy_cfg.of_node = pdev->dev.of_node; > + psy_cfg.drv_data = charger; > + > + charger->psy = devm_power_supply_register(&pdev->dev, > + &act8945a_charger_desc, > + &psy_cfg); > + if (IS_ERR(charger->psy)) { > + dev_err(act8945a_dev->dev, "failed to register power supply\n"); > + return PTR_ERR(charger->psy); > + } > + > + dev_info(act8945a_dev->dev, "charger driver registered\n"); > + > + return 0; > +} > + > +static int act8945a_charger_remove(struct platform_device *pdev) > +{ > + struct act8945a_charger *charger = platform_get_drvdata(pdev); > + > + power_supply_unregister(charger->psy); > The point of devm-like functions is to get rid of error and removal paths. This won't work... actually this should oops. Have you tested unbinding of driver? Best regards, Krzysztof -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
SGkgS3J6eXN6dG9mLA0KDQo+IC0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQo+IEZyb206IGsu a296bG93c2tpLmtAZ21haWwuY29tIFttYWlsdG86ay5rb3psb3dza2kua0BnbWFpbC5jb21dIE9u IEJlaGFsZiBPZg0KPiBLcnp5c3p0b2YgS296bG93c2tpDQo+IFNlbnQ6IDIwMTblubQx5pyIOOaX pSAyMDoxNw0KPiBUbzogWWFuZywgV2VueW91IDxXZW55b3UuWWFuZ0BhdG1lbC5jb20+DQo+IENj OiBTZWJhc3RpYW4gUmVpY2hlbCA8c3JlQGtlcm5lbC5vcmc+OyBEbWl0cnkgRXJlbWluLVNvbGVu aWtvdg0KPiA8ZGJhcnlzaGtvdkBnbWFpbC5jb20+OyBEYXZpZCBXb29kaG91c2UgPGR3bXcyQGlu ZnJhZGVhZC5vcmc+OyBSb2INCj4gSGVycmluZyA8cm9iaCtkdEBrZXJuZWwub3JnPjsgUGF3ZWwg TW9sbCA8cGF3ZWwubW9sbEBhcm0uY29tPjsgTWFyaw0KPiBSdXRsYW5kIDxtYXJrLnJ1dGxhbmRA YXJtLmNvbT47IElhbiBDYW1wYmVsbCA8aWpjK2RldmljZXRyZWVAaGVsbGlvbi5vcmcudWs+Ow0K PiBLdW1hciBHYWxhIDxnYWxha0Bjb2RlYXVyb3JhLm9yZz47IEZlcnJlLCBOaWNvbGFzDQo+IDxO aWNvbGFzLkZFUlJFQGF0bWVsLmNvbT47IGxpbnV4LWFybS1rZXJuZWxAbGlzdHMuaW5mcmFkZWFk Lm9yZzsgbGludXgtDQo+IGtlcm5lbEB2Z2VyLmtlcm5lbC5vcmc7IGxpbnV4LXBtQHZnZXIua2Vy bmVsLm9yZw0KPiBTdWJqZWN0OiBSZTogW1BBVENIIHYyIDEvMl0gcG93ZXI6IGFjdDg5NDVhOiBh ZGQgY2hhcmdlciBkcml2ZXIgZm9yIEFDVDg5NDVBDQo+IA0KPiAyMDE2LTAxLTA4IDE3OjQ2IEdN VCswOTowMCBXZW55b3UgWWFuZyA8d2VueW91LnlhbmdAYXRtZWwuY29tPjoNCj4gPiBUaGlzIHBh dGNoIGFkZHMgbmV3IGRyaXZlciBmb3IgQWN0aXZlLXNlbWkgQUNUODk0NUEgQWN0aXZlUGF0aCBj aGFyZ2VyDQo+ID4gKHBhcnQgb2YgQUNUODk0NUEgTUZEIGRyaXZlcikgcHJvdmlkaW5nIHBvd2Vy IHN1cHBseSBjbGFzcyBpbmZvcm1hdGlvbg0KPiA+IHRvIHVzZXJzcGFjZS4NCj4gPg0KPiA+IFRo ZSBkcml2ZXIgaXMgY29uZmlndXJlZCB0aHJvdWdoIERUUyAoYmF0dGVyeSBhbmQgc3lzdGVtIHJl bGF0ZWQNCj4gPiBzZXR0aW5ncykgYW5kIHN5c2ZzIGVudHJpZXMgKHRpbWVycyBhbmQgaW5wdXQg b3Zlci12b2x0YWdlIHRocmVzaG9sZCkuDQo+ID4NCj4gPiBTaWduZWQtb2ZmLWJ5OiBXZW55b3Ug WWFuZyA8d2VueW91LnlhbmdAYXRtZWwuY29tPg0KPiA+IC0tLQ0KPiA+DQo+ID4gQ2hhbmdlcyBp biB2MjoNCj4gPiAgMS4vIFN1YnN0aXR1dGUgb2ZfcHJvcGVydHlfcmVhZF9ib29sKCkgZm9yIG9m X2dldF9wcm9wZXJ0eSgpLg0KPiA+ICAyLi8gU3Vic3RpdHV0ZSBkZXZtX3Bvd2VyX3N1cHBseV9y ZWdpc3RlcigpIGZvciBwb3dlcl9zdXBwbHlfcmVnaXN0ZXIoKS4NCj4gPiAgMy4vIFVzZSBtb2R1 bGVfcGxhdGZvcm1fZHJpdmVyKCksIGluc3RlYWQgb2Ygc3Vic3lzX2luaXRjYWxsKCkuDQo+ID4g IDQuLyBTdWJzdGl0dXRlIE1PRFVMRV9MSUNFTlNFKCJHUEwiKSBmb3IgTU9EVUxFX0xJQ0VOU0Uo IkdQTCB2MiIpLg0KPiA+DQo+ID4gIGRyaXZlcnMvcG93ZXIvS2NvbmZpZyAgICAgICAgICAgIHwg ICAgNyArDQo+ID4gIGRyaXZlcnMvcG93ZXIvTWFrZWZpbGUgICAgICAgICAgIHwgICAgMSArDQo+ ID4gIGRyaXZlcnMvcG93ZXIvYWN0ODk0NWFfY2hhcmdlci5jIHwgIDM4Ng0KPiA+ICsrKysrKysr KysrKysrKysrKysrKysrKysrKysrKysrKysrKysrDQo+ID4gIDMgZmlsZXMgY2hhbmdlZCwgMzk0 IGluc2VydGlvbnMoKykNCj4gPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvcG93ZXIvYWN0 ODk0NWFfY2hhcmdlci5jDQo+ID4NCj4gPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9wb3dlci9LY29u ZmlnIGIvZHJpdmVycy9wb3dlci9LY29uZmlnIGluZGV4DQo+ID4gMWRkZDEzYy4uYWU3NTIxMSAx MDA2NDQNCj4gPiAtLS0gYS9kcml2ZXJzL3Bvd2VyL0tjb25maWcNCj4gPiArKysgYi9kcml2ZXJz L3Bvd2VyL0tjb25maWcNCj4gPiBAQCAtNzUsNiArNzUsMTMgQEAgY29uZmlnIEJBVFRFUllfODhQ TTg2MFgNCj4gPiAgICAgICAgIGhlbHANCj4gPiAgICAgICAgICAgU2F5IFkgaGVyZSB0byBlbmFi bGUgYmF0dGVyeSBtb25pdG9yIGZvciBNYXJ2ZWxsIDg4UE04NjB4IGNoaXAuDQo+ID4NCj4gPiAr Y29uZmlnIEJBVFRFUllfQUNUODk0NUENCj4gPiArICAgICAgIHRyaXN0YXRlICJBY3RpdmUtc2Vt aSBBQ1Q4OTQ1QSBjaGFyZ2VyIGRyaXZlciINCj4gPiArICAgICAgIGRlcGVuZHMgb24gTUZEX0FD VDg5NDVBDQo+ID4gKyAgICAgICBoZWxwDQo+ID4gKyAgICAgICAgIFNheSBZIGhlcmUgdG8gZW5h YmxlIHN1cHBvcnQgZm9yIHBvd2VyIHN1cHBseSBwcm92aWRlZCBieQ0KPiA+ICsgICAgICAgICBB Y3RpdmUtc2VtaSBBY3RpdmVQYXRoIEFDVDg5NDVBIGNoYXJnZXIuDQo+ID4gKw0KPiA+ICBjb25m aWcgQkFUVEVSWV9EUzI3NjANCj4gPiAgICAgICAgIHRyaXN0YXRlICJEUzI3NjAgYmF0dGVyeSBk cml2ZXIgKEhQIGlQQVEgJiBvdGhlcnMpIg0KPiA+ICAgICAgICAgZGVwZW5kcyBvbiBXMSAmJiBX MV9TTEFWRV9EUzI3NjAgZGlmZiAtLWdpdA0KPiA+IGEvZHJpdmVycy9wb3dlci9NYWtlZmlsZSBi L2RyaXZlcnMvcG93ZXIvTWFrZWZpbGUgaW5kZXgNCj4gPiAwZTRlYWI1Li5lNDZiNzVkIDEwMDY0 NA0KPiA+IC0tLSBhL2RyaXZlcnMvcG93ZXIvTWFrZWZpbGUNCj4gPiArKysgYi9kcml2ZXJzL3Bv d2VyL01ha2VmaWxlDQo+ID4gQEAgLTE3LDYgKzE3LDcgQEAgb2JqLSQoQ09ORklHX1dNODM1MF9Q T1dFUikgICAgKz0NCj4gd204MzUwX3Bvd2VyLm8NCj4gPiAgb2JqLSQoQ09ORklHX1RFU1RfUE9X RVIpICAgICAgICs9IHRlc3RfcG93ZXIubw0KPiA+DQo+ID4gIG9iai0kKENPTkZJR19CQVRURVJZ Xzg4UE04NjBYKSArPSA4OHBtODYweF9iYXR0ZXJ5Lm8NCj4gPiArb2JqLSQoQ09ORklHX0JBVFRF UllfQUNUODk0NUEpICs9IGFjdDg5NDVhX2NoYXJnZXIubw0KPiA+ICBvYmotJChDT05GSUdfQkFU VEVSWV9EUzI3NjApICAgKz0gZHMyNzYwX2JhdHRlcnkubw0KPiA+ICBvYmotJChDT05GSUdfQkFU VEVSWV9EUzI3ODApICAgKz0gZHMyNzgwX2JhdHRlcnkubw0KPiA+ICBvYmotJChDT05GSUdfQkFU VEVSWV9EUzI3ODEpICAgKz0gZHMyNzgxX2JhdHRlcnkubw0KPiA+IGRpZmYgLS1naXQgYS9kcml2 ZXJzL3Bvd2VyL2FjdDg5NDVhX2NoYXJnZXIuYw0KPiA+IGIvZHJpdmVycy9wb3dlci9hY3Q4OTQ1 YV9jaGFyZ2VyLmMNCj4gPiBuZXcgZmlsZSBtb2RlIDEwMDY0NA0KPiA+IGluZGV4IDAwMDAwMDAu LmZlOWMxOWYNCj4gPiAtLS0gL2Rldi9udWxsDQo+ID4gKysrIGIvZHJpdmVycy9wb3dlci9hY3Q4 OTQ1YV9jaGFyZ2VyLmMNCj4gPiBAQCAtMCwwICsxLDM4NiBAQA0KPiA+ICsvKg0KPiA+ICsgKiBQ b3dlciBzdXBwbHkgZHJpdmVyIGZvciB0aGUgQWN0aXZlLXNlbWkgQUNUODk0NUEgUE1JQw0KPiA+ ICsgKg0KPiA+ICsgKiBDb3B5cmlnaHQgKEMpIDIwMTUgQXRtZWwgQ29ycG9yYXRpb24NCj4gPiAr ICogICAgICAgICAgICAgICAgICAgV2VueW91IFlhbmcgPHdlbnlvdS55YW5nQGF0bWVsLmNvbT4N Cj4gPiArICoNCj4gPiArICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4g cmVkaXN0cmlidXRlIGl0IGFuZC9vcg0KPiA+ICttb2RpZnkNCj4gPiArICogaXQgdW5kZXIgdGhl IHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQNCj4g PiArYnkNCj4gPiArICogdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyIHZlcnNp b24gMiBvZiB0aGUgTGljZW5zZSwgb3INCj4gPiArICogKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0 ZXIgdmVyc2lvbi4NCj4gPiArICoNCj4gPiArICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVk IGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsDQo+ID4gKyAqIGJ1dCBXSVRIT1VU IEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mDQo+ID4g KyAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4g IFNlZQ0KPiB0aGUNCj4gPiArICogR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUg ZGV0YWlscy4NCj4gPiArICovDQo+ID4gKw0KPiA+ICsjaW5jbHVkZSA8bGludXgvbW9kdWxlLmg+ DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9tZmQvYWN0ODk0NWEuaD4NCj4gPiArI2luY2x1ZGUgPGxp bnV4L29mLmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9vZl9ncGlvLmg+DQo+ID4gKyNpbmNsdWRl IDxsaW51eC9wbGF0Zm9ybV9kZXZpY2UuaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L3Bvd2VyX3N1 cHBseS5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvcmVnbWFwLmg+DQo+ID4gKw0KPiA+ICtzdGF0 aWMgY29uc3QgY2hhciAqYWN0ODk0NWFfY2hhcmdlcl9tb2RlbCA9ICJBQ1Q4OTQ1QSI7IHN0YXRp YyBjb25zdA0KPiA+ICtjaGFyICphY3Q4OTQ1YV9jaGFyZ2VyX21hbnVmYWN0dXJlciA9ICJBY3Rp dmUtc2VtaSI7DQo+ID4gKw0KPiA+ICsvKioNCj4gPiArICogQUNUODk0NUEgQ2hhcmdlciBSZWdp c3RlciBNYXANCj4gPiArICovDQo+ID4gKw0KPiA+ICsvKiAweDcwOiBSZXNlcnZlZCAqLw0KPiA+ ICsjZGVmaW5lIEFDVDg5NDVBX0FQQ0hfQ0ZHICAgICAgICAgICAgICAweDcxDQo+ID4gKyNkZWZp bmUgQUNUODk0NUFfQVBDSF9TVEFUVVMgICAgICAgICAgIDB4NzgNCj4gPiArI2RlZmluZSBBQ1Q4 OTQ1QV9BUENIX0NUUkwgICAgICAgICAgICAgMHg3OQ0KPiA+ICsjZGVmaW5lIEFDVDg5NDVBX0FQ Q0hfU1RBVEUgICAgICAgICAgICAweDdBDQo+ID4gKw0KPiA+ICsvKiBBQ1Q4OTQ1QV9BUENIX0NG RyAqLw0KPiA+ICsjZGVmaW5lIEFQQ0hfQ0ZHX09WUFNFVCAgICAgICAgICAgICAgICAoMHgwMyA8 PCAwKQ0KPiA+ICsjZGVmaW5lICAgICAgICAgICAgICAgIEFQQ0hfQ0ZHX09WUFNFVF82VjYgICAg ICgweDAgPDwgMCkNCj4gPiArI2RlZmluZSAgICAgICAgICAgICAgICBBUENIX0NGR19PVlBTRVRf N1YgICAgICAoMHgxIDw8IDApDQo+ID4gKyNkZWZpbmUgICAgICAgICAgICAgICAgQVBDSF9DRkdf T1ZQU0VUXzdWNSAgICAgKDB4MiA8PCAwKQ0KPiA+ICsjZGVmaW5lICAgICAgICAgICAgICAgIEFQ Q0hfQ0ZHX09WUFNFVF84ViAgICAgICgweDMgPDwgMCkNCj4gPiArI2RlZmluZSBBUENIX0NGR19Q UkVUSU1PICAgICAgICgweDAzIDw8IDIpDQo+ID4gKyNkZWZpbmUgICAgICAgICAgICAgICAgQVBD SF9DRkdfUFJFVElNT180MF9NSU4gICAgICAgICAoMHgwIDw8IDIpDQo+ID4gKyNkZWZpbmUgICAg ICAgICAgICAgICAgQVBDSF9DRkdfUFJFVElNT182MF9NSU4gICAgICAgICAoMHgxIDw8IDIpDQo+ ID4gKyNkZWZpbmUgICAgICAgICAgICAgICAgQVBDSF9DRkdfUFJFVElNT184MF9NSU4gICAgICAg ICAoMHgyIDw8IDIpDQo+ID4gKyNkZWZpbmUgICAgICAgICAgICAgICAgQVBDSF9DRkdfUFJFVElN T19ESVNBQkxFRCAgICAgICAoMHgzIDw8IDIpDQo+ID4gKyNkZWZpbmUgQVBDSF9DRkdfVE9UVElN TyAgICAgICAoMHgwMyA8PCA0KQ0KPiA+ICsjZGVmaW5lICAgICAgICAgICAgICAgIEFQQ0hfQ0ZH X1RPVFRJTU9fM19IT1VSICAgICAgICAgKDB4MCA8PCA0KQ0KPiA+ICsjZGVmaW5lICAgICAgICAg ICAgICAgIEFQQ0hfQ0ZHX1RPVFRJTU9fNF9IT1VSICAgICAgICAgKDB4MSA8PCA0KQ0KPiA+ICsj ZGVmaW5lICAgICAgICAgICAgICAgIEFQQ0hfQ0ZHX1RPVFRJTU9fNV9IT1VSICAgICAgICAgKDB4 MiA8PCA0KQ0KPiA+ICsjZGVmaW5lICAgICAgICAgICAgICAgIEFQQ0hfQ0ZHX1RPVFRJTU9fRElT QUJMRUQgICAgICAgKDB4MyA8PCA0KQ0KPiA+ICsjZGVmaW5lIEFQQ0hfQ0ZHX1NVU0NIRyAgICAg ICAgICAgICAgICAoMHgwMSA8PCA3KQ0KPiA+ICsNCj4gPiArI2RlZmluZSBBUENIX1NUQVRVU19D SEdEQVQgICAgICgweDAxIDw8IDApDQo+ID4gKyNkZWZpbmUgQVBDSF9TVEFUVVNfSU5EQVQgICAg ICAoMHgwMSA8PCAxKQ0KPiA+ICsjZGVmaW5lIEFQQ0hfU1RBVFVTX1RFTVBEQVQgICAgKDB4MDEg PDwgMikNCj4gPiArI2RlZmluZSBBUENIX1NUQVRVU19USU1SREFUICAgICgweDAxIDw8IDMpDQo+ ID4gKyNkZWZpbmUgQVBDSF9TVEFUVVNfQ0hHU1RBVCAgICAoMHgwMSA8PCA0KQ0KPiA+ICsjZGVm aW5lIEFQQ0hfU1RBVFVTX0lOU1RBVCAgICAgKDB4MDEgPDwgNSkNCj4gPiArI2RlZmluZSBBUENI X1NUQVRVU19URU1QU1RBVCAgICgweDAxIDw8IDYpDQo+ID4gKyNkZWZpbmUgQVBDSF9TVEFUVVNf VElNUlNUQVQgICAoMHgwMSA8PCA3KQ0KPiA+ICsNCj4gPiArI2RlZmluZSBBUENIX0NUUkxfQ0hH RU9DT1VUICAgICgweDAxIDw8IDApDQo+ID4gKyNkZWZpbmUgQVBDSF9DVFJMX0lORElTICAgICAg ICAgICAgICAgICgweDAxIDw8IDEpDQo+ID4gKyNkZWZpbmUgQVBDSF9DVFJMX1RFTVBPVVQgICAg ICAoMHgwMSA8PCAyKQ0KPiA+ICsjZGVmaW5lIEFQQ0hfQ1RSTF9USU1SUFJFICAgICAgKDB4MDEg PDwgMykNCj4gPiArI2RlZmluZSBBUENIX0NUUkxfQ0hHRU9DSU4gICAgICgweDAxIDw8IDQpDQo+ ID4gKyNkZWZpbmUgQVBDSF9DVFJMX0lOQ09OICAgICAgICAgICAgICAgICgweDAxIDw8IDUpDQo+ ID4gKyNkZWZpbmUgQVBDSF9DVFJMX1RFTVBJTiAgICAgICAoMHgwMSA8PCA2KQ0KPiA+ICsjZGVm aW5lIEFQQ0hfQ1RSTF9USU1SVE9UICAgICAgKDB4MDEgPDwgNykNCj4gPiArDQo+ID4gKyNkZWZp bmUgQVBDSF9TVEFURV9BQ0lOU1RBVCAgICAoMHgwMSA8PCAxKQ0KPiA+ICsjZGVmaW5lIEFQQ0hf U1RBVEVfQ1NUQVRFICAgICAgKDB4MDMgPDwgNCkNCj4gPiArI2RlZmluZSBBUENIX1NUQVRFX0NT VEFURV9TSElGVCAgICAgICAgICAgICAgICA0DQo+ID4gKyNkZWZpbmUgICAgICAgICAgICAgICAg QVBDSF9TVEFURV9DU1RBVEVfRElTQUJMRUQgICAgICAweDAwDQo+ID4gKyNkZWZpbmUgICAgICAg ICAgICAgICAgQVBDSF9TVEFURV9DU1RBVEVfRU9DICAgICAgICAgICAweDAxDQo+ID4gKyNkZWZp bmUgICAgICAgICAgICAgICAgQVBDSF9TVEFURV9DU1RBVEVfRkFTVCAgICAgICAgICAweDAyDQo+ ID4gKyNkZWZpbmUgICAgICAgICAgICAgICAgQVBDSF9TVEFURV9DU1RBVEVfUFJFICAgICAgICAg ICAweDAzDQo+ID4gKw0KPiA+ICtzdHJ1Y3QgYWN0ODk0NWFfY2hhcmdlciB7DQo+ID4gKyAgICAg ICBzdHJ1Y3QgZGV2aWNlICpkZXY7DQo+ID4gKyAgICAgICBzdHJ1Y3QgYWN0ODk0NWFfZGV2ICph Y3Q4OTQ1YV9kZXY7DQo+ID4gKyAgICAgICBzdHJ1Y3QgcG93ZXJfc3VwcGx5ICpwc3k7DQo+ID4g Kw0KPiA+ICsgICAgICAgdTMyIHRvbGFsX3RpbWVfb3V0Ow0KPiA+ICsgICAgICAgdTMyIHByZV90 aW1lX291dDsNCj4gPiArICAgICAgIHUzMiBpbnB1dF92b2x0YWdlX3RocmVzaG9sZDsNCj4gPiAr ICAgICAgIGJvb2wgYmF0dGVyeV90ZW1wZXJhdHVyZTsNCj4gPiArICAgICAgIGludCBjaGdsZXZf cGluOw0KPiA+ICsgICAgICAgaW50IGNoZ2xldl92YWx1ZTsNCj4gPiArfTsNCj4gPiArDQo+ID4g K3N0YXRpYyBpbnQgYWN0ODk0NWFfZ2V0X2NoYXJnZXJfc3RhdGUoc3RydWN0IHJlZ21hcCAqcmVn bWFwLCBpbnQNCj4gPiArKnZhbCkgew0KPiA+ICsgICAgICAgaW50IHJldDsNCj4gPiArICAgICAg IHVuc2lnbmVkIGludCBzdGF0dXMsIHN0YXRlOw0KPiA+ICsNCj4gPiArICAgICAgIHJldCA9IHJl Z21hcF9yZWFkKHJlZ21hcCwgQUNUODk0NUFfQVBDSF9TVEFUVVMsICZzdGF0dXMpOw0KPiA+ICsg ICAgICAgaWYgKHJldCA8IDApDQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiByZXQ7DQo+ID4g Kw0KPiA+ICsgICAgICAgcmV0ID0gcmVnbWFwX3JlYWQocmVnbWFwLCBBQ1Q4OTQ1QV9BUENIX1NU QVRFLCAmc3RhdGUpOw0KPiA+ICsgICAgICAgaWYgKHJldCA8IDApDQo+ID4gKyAgICAgICAgICAg ICAgIHJldHVybiByZXQ7DQo+ID4gKw0KPiA+ICsgICAgICAgc3RhdGUgJj0gQVBDSF9TVEFURV9D U1RBVEU7DQo+ID4gKyAgICAgICBzdGF0ZSA+Pj0gQVBDSF9TVEFURV9DU1RBVEVfU0hJRlQ7DQo+ ID4gKw0KPiA+ICsgICAgICAgaWYgKHN0YXRlID09IEFQQ0hfU1RBVEVfQ1NUQVRFX0VPQykgew0K PiA+ICsgICAgICAgICAgICAgICBpZiAoc3RhdHVzICYgQVBDSF9TVEFUVVNfQ0hHREFUKQ0KPiA+ ICsgICAgICAgICAgICAgICAgICAgICAgICp2YWwgPSBQT1dFUl9TVVBQTFlfU1RBVFVTX0ZVTEw7 DQo+ID4gKyAgICAgICAgICAgICAgIGVsc2UNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAq dmFsID0gUE9XRVJfU1VQUExZX1NUQVRVU19OT1RfQ0hBUkdJTkc7DQo+ID4gKyAgICAgICB9IGVs c2UgaWYgKChzdGF0ZSA9PSBBUENIX1NUQVRFX0NTVEFURV9GQVNUKSB8fA0KPiA+ICsgICAgICAg ICAgICAgICAgICAoc3RhdGUgPT0gQVBDSF9TVEFURV9DU1RBVEVfUFJFKSkgew0KPiA+ICsgICAg ICAgICAgICAgICAqdmFsID0gUE9XRVJfU1VQUExZX1NUQVRVU19DSEFSR0lORzsNCj4gPiArICAg ICAgIH0gZWxzZSB7DQo+ID4gKyAgICAgICAgICAgICAgICp2YWwgPSBQT1dFUl9TVVBQTFlfU1RB VFVTX05PVF9DSEFSR0lORzsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICByZXR1 cm4gMDsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGludCBhY3Q4OTQ1YV9nZXRfY2hhcmdl X3R5cGUoc3RydWN0IHJlZ21hcCAqcmVnbWFwLCBpbnQgKnZhbCkNCj4gPiArew0KPiA+ICsgICAg ICAgaW50IHJldDsNCj4gPiArICAgICAgIHVuc2lnbmVkIGludCBzdGF0ZTsNCj4gPiArDQo+ID4g KyAgICAgICByZXQgPSByZWdtYXBfcmVhZChyZWdtYXAsIEFDVDg5NDVBX0FQQ0hfU1RBVEUsICZz dGF0ZSk7DQo+ID4gKyAgICAgICBpZiAocmV0IDwgMCkNCj4gPiArICAgICAgICAgICAgICAgcmV0 dXJuIHJldDsNCj4gPiArDQo+ID4gKyAgICAgICBzdGF0ZSAmPSBBUENIX1NUQVRFX0NTVEFURTsN Cj4gPiArICAgICAgIHN0YXRlID4+PSBBUENIX1NUQVRFX0NTVEFURV9TSElGVDsNCj4gPiArDQo+ ID4gKyAgICAgICBzd2l0Y2ggKHN0YXRlKSB7DQo+ID4gKyAgICAgICBjYXNlIEFQQ0hfU1RBVEVf Q1NUQVRFX1BSRToNCj4gPiArICAgICAgICAgICAgICAgKnZhbCA9IFBPV0VSX1NVUFBMWV9DSEFS R0VfVFlQRV9UUklDS0xFOw0KPiA+ICsgICAgICAgICAgICAgICBicmVhazsNCj4gPiArICAgICAg IGNhc2UgQVBDSF9TVEFURV9DU1RBVEVfRkFTVDoNCj4gPiArICAgICAgICAgICAgICAgKnZhbCA9 IFBPV0VSX1NVUFBMWV9DSEFSR0VfVFlQRV9GQVNUOw0KPiA+ICsgICAgICAgICAgICAgICBicmVh azsNCj4gPiArICAgICAgIGNhc2UgQVBDSF9TVEFURV9DU1RBVEVfRU9DOg0KPiA+ICsgICAgICAg Y2FzZSBBUENIX1NUQVRFX0NTVEFURV9ESVNBQkxFRDoNCj4gPiArICAgICAgIGRlZmF1bHQ6DQo+ ID4gKyAgICAgICAgICAgICAgICp2YWwgPSBQT1dFUl9TVVBQTFlfQ0hBUkdFX1RZUEVfTk9ORTsN Cj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gMDsNCj4gPiArfQ0KPiA+ ICsNCj4gPiArc3RhdGljIGludCBhY3Q4OTQ1YV9nZXRfYmF0dGVyeV9oZWFsdGgoc3RydWN0IGFj dDg5NDVhX2NoYXJnZXIgKmNoYXJnZXIsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICBzdHJ1Y3QgcmVnbWFwICpyZWdtYXAsIGludCAqdmFsKQ0KPiA+ICt7DQo+ID4g KyAgICAgICBpbnQgcmV0Ow0KPiA+ICsgICAgICAgdW5zaWduZWQgaW50IHN0YXR1czsNCj4gPiAr DQo+ID4gKyAgICAgICByZXQgPSByZWdtYXBfcmVhZChyZWdtYXAsIEFDVDg5NDVBX0FQQ0hfU1RB VFVTLCAmc3RhdHVzKTsNCj4gPiArICAgICAgIGlmIChyZXQgPCAwKQ0KPiA+ICsgICAgICAgICAg ICAgICByZXR1cm4gcmV0Ow0KPiA+ICsNCj4gPiArICAgICAgIGlmIChjaGFyZ2VyLT5iYXR0ZXJ5 X3RlbXBlcmF0dXJlICYmICEoc3RhdHVzICYNCj4gQVBDSF9TVEFUVVNfVEVNUERBVCkpDQo+ID4g KyAgICAgICAgICAgICAgICp2YWwgPSBQT1dFUl9TVVBQTFlfSEVBTFRIX09WRVJIRUFUOw0KPiA+ ICsgICAgICAgZWxzZSBpZiAoIShzdGF0dXMgJiBBUENIX1NUQVRVU19JTkRBVCkpDQo+ID4gKyAg ICAgICAgICAgICAgICp2YWwgPSBQT1dFUl9TVVBQTFlfSEVBTFRIX09WRVJWT0xUQUdFOw0KPiA+ ICsgICAgICAgZWxzZSBpZiAoc3RhdHVzICYgQVBDSF9TVEFUVVNfVElNUkRBVCkNCj4gPiArICAg ICAgICAgICAgICAgKnZhbCA9IFBPV0VSX1NVUFBMWV9IRUFMVEhfU0FGRVRZX1RJTUVSX0VYUElS RTsNCj4gPiArICAgICAgIGVsc2UNCj4gPiArICAgICAgICAgICAgICAgKnZhbCA9IFBPV0VSX1NV UFBMWV9IRUFMVEhfR09PRDsNCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gMDsNCj4gPiArfQ0K PiA+ICsNCj4gPiArc3RhdGljIGVudW0gcG93ZXJfc3VwcGx5X3Byb3BlcnR5IGFjdDg5NDVhX2No YXJnZXJfcHJvcHNbXSA9IHsNCj4gPiArICAgICAgIFBPV0VSX1NVUFBMWV9QUk9QX1NUQVRVUywN Cj4gPiArICAgICAgIFBPV0VSX1NVUFBMWV9QUk9QX0NIQVJHRV9UWVBFLA0KPiA+ICsgICAgICAg UE9XRVJfU1VQUExZX1BST1BfVEVDSE5PTE9HWSwNCj4gPiArICAgICAgIFBPV0VSX1NVUFBMWV9Q Uk9QX0hFQUxUSCwNCj4gPiArICAgICAgIFBPV0VSX1NVUFBMWV9QUk9QX01PREVMX05BTUUsDQo+ ID4gKyAgICAgICBQT1dFUl9TVVBQTFlfUFJPUF9NQU5VRkFDVFVSRVIgfTsNCj4gPiArDQo+ID4g K3N0YXRpYyBpbnQgYWN0ODk0NWFfY2hhcmdlcl9nZXRfcHJvcGVydHkoc3RydWN0IHBvd2VyX3N1 cHBseSAqcHN5LA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVudW0g cG93ZXJfc3VwcGx5X3Byb3BlcnR5IHByb3AsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgdW5pb24gcG93ZXJfc3VwcGx5X3Byb3B2YWwgKnZhbCkgew0KPiA+ICsgICAg ICAgc3RydWN0IGFjdDg5NDVhX2NoYXJnZXIgKmNoYXJnZXIgPSBwb3dlcl9zdXBwbHlfZ2V0X2Ry dmRhdGEocHN5KTsNCj4gPiArICAgICAgIHN0cnVjdCByZWdtYXAgKnJlZ21hcCA9IGNoYXJnZXIt PmFjdDg5NDVhX2Rldi0+cmVnbWFwOw0KPiA+ICsgICAgICAgaW50IHJldCA9IDA7DQo+ID4gKw0K PiA+ICsgICAgICAgc3dpdGNoIChwcm9wKSB7DQo+ID4gKyAgICAgICBjYXNlIFBPV0VSX1NVUFBM WV9QUk9QX1NUQVRVUzoNCj4gPiArICAgICAgICAgICAgICAgcmV0ID0gYWN0ODk0NWFfZ2V0X2No YXJnZXJfc3RhdGUocmVnbWFwLCAmdmFsLT5pbnR2YWwpOw0KPiA+ICsgICAgICAgICAgICAgICBi cmVhazsNCj4gPiArICAgICAgIGNhc2UgUE9XRVJfU1VQUExZX1BST1BfQ0hBUkdFX1RZUEU6DQo+ ID4gKyAgICAgICAgICAgICAgIHJldCA9IGFjdDg5NDVhX2dldF9jaGFyZ2VfdHlwZShyZWdtYXAs ICZ2YWwtPmludHZhbCk7DQo+ID4gKyAgICAgICAgICAgICAgIGJyZWFrOw0KPiA+ICsgICAgICAg Y2FzZSBQT1dFUl9TVVBQTFlfUFJPUF9URUNITk9MT0dZOg0KPiA+ICsgICAgICAgICAgICAgICB2 YWwtPmludHZhbCA9IFBPV0VSX1NVUFBMWV9URUNITk9MT0dZX0xJT047DQo+ID4gKyAgICAgICAg ICAgICAgIGJyZWFrOw0KPiA+ICsgICAgICAgY2FzZSBQT1dFUl9TVVBQTFlfUFJPUF9IRUFMVEg6 DQo+ID4gKyAgICAgICAgICAgICAgIHJldCA9IGFjdDg5NDVhX2dldF9iYXR0ZXJ5X2hlYWx0aChj aGFyZ2VyLA0KPiA+ICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgcmVnbWFwLCAmdmFsLT5pbnR2YWwpOw0KPiA+ICsgICAgICAgICAgICAgICBicmVhazsN Cj4gPiArICAgICAgIGNhc2UgUE9XRVJfU1VQUExZX1BST1BfTU9ERUxfTkFNRToNCj4gPiArICAg ICAgICAgICAgICAgdmFsLT5zdHJ2YWwgPSBhY3Q4OTQ1YV9jaGFyZ2VyX21vZGVsOw0KPiA+ICsg ICAgICAgICAgICAgICBicmVhazsNCj4gPiArICAgICAgIGNhc2UgUE9XRVJfU1VQUExZX1BST1Bf TUFOVUZBQ1RVUkVSOg0KPiA+ICsgICAgICAgICAgICAgICB2YWwtPnN0cnZhbCA9IGFjdDg5NDVh X2NoYXJnZXJfbWFudWZhY3R1cmVyOw0KPiA+ICsgICAgICAgICAgICAgICBicmVhazsNCj4gPiAr ICAgICAgIGRlZmF1bHQ6DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiAtRUlOVkFMOw0KPiA+ ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiByZXQ7DQo+ID4gK30NCj4gPiAr DQo+ID4gK3N0YXRpYyBjb25zdCBzdHJ1Y3QgcG93ZXJfc3VwcGx5X2Rlc2MgYWN0ODk0NWFfY2hh cmdlcl9kZXNjID0gew0KPiA+ICsgICAgICAgLm5hbWUgICAgICAgICAgID0gImFjdDg5NDVhLWNo YXJnZXIiLA0KPiA+ICsgICAgICAgLnR5cGUgICAgICAgICAgID0gUE9XRVJfU1VQUExZX1RZUEVf QkFUVEVSWSwNCj4gPiArICAgICAgIC5nZXRfcHJvcGVydHkgICA9IGFjdDg5NDVhX2NoYXJnZXJf Z2V0X3Byb3BlcnR5LA0KPiA+ICsgICAgICAgLnByb3BlcnRpZXMgICAgID0gYWN0ODk0NWFfY2hh cmdlcl9wcm9wcywNCj4gPiArICAgICAgIC5udW1fcHJvcGVydGllcyA9IEFSUkFZX1NJWkUoYWN0 ODk0NWFfY2hhcmdlcl9wcm9wcyksDQo+ID4gK307DQo+ID4gKw0KPiA+ICsjZGVmaW5lIERFRkFV TFRfVE9UQUxfVElNRV9PVVQgICAgICAgICAzDQo+ID4gKyNkZWZpbmUgREVGQVVMVF9QUkVfVElN RV9PVVQgICAgICAgICAgIDQwDQo+ID4gKyNkZWZpbmUgREVGQVVMVF9JTlBVVF9PVlBfVEhSRVNI T0xEICAgIDY2MDANCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgYWN0ODk0NWFfY2hhcmdlcl9wYXJz ZV9kdChzdHJ1Y3QgZGV2aWNlICpkZXYsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgc3RydWN0IGFjdDg5NDVhX2NoYXJnZXIgKmNoYXJnZXIpDQo+ID4gK3sNCj4gPiAr ICAgICAgIHN0cnVjdCBkZXZpY2Vfbm9kZSAqbnAgPSBkZXYtPm9mX25vZGU7DQo+ID4gKyAgICAg ICBlbnVtIG9mX2dwaW9fZmxhZ3MgZmxhZ3M7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKCFucCkg ew0KPiA+ICsgICAgICAgICAgICAgICBkZXZfZXJyKGRldiwgIm5vIGNoYXJnZXIgb2Ygbm9kZVxu Iik7DQo+ID4gKyAgICAgICAgICAgICAgIHJldHVybiAtRUlOVkFMOw0KPiA+ICsgICAgICAgfQ0K PiA+ICsNCj4gPiArICAgICAgIGNoYXJnZXItPmNoZ2xldl9waW4gPSBvZl9nZXRfbmFtZWRfZ3Bp b19mbGFncyhucCwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJhY3RpdmUt c2VtaSxjaGdsZXYtZ3BpbyIsIDAsICZmbGFncyk7DQo+ID4gKw0KPiA+ICsgICAgICAgY2hhcmdl ci0+Y2hnbGV2X3ZhbHVlID0gKGZsYWdzID09IE9GX0dQSU9fQUNUSVZFX0xPVykgPyAwIDogMTsN Cj4gPiArDQo+ID4gKyAgICAgICBjaGFyZ2VyLT5iYXR0ZXJ5X3RlbXBlcmF0dXJlID0gb2ZfcHJv cGVydHlfcmVhZF9ib29sKG5wLA0KPiA+ICsNCj4gPiArICJhY3RpdmUtc2VtaSxiYXR0ZXJ5X3Rl bXBlcmF0dXJlIik7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKG9mX3Byb3BlcnR5X3JlYWRfdTMy KG5wLCAiYWN0aXZlLXNlbWksaW5wdXRfdm9sdGFnZV90aHJlc2hvbGQiLA0KPiA+ICsgICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICZjaGFyZ2VyLT5pbnB1dF92b2x0YWdlX3RocmVzaG9s ZCkpDQo+ID4gKyAgICAgICAgICAgICAgIGNoYXJnZXItPmlucHV0X3ZvbHRhZ2VfdGhyZXNob2xk ID0NCj4gPiArIERFRkFVTFRfUFJFX1RJTUVfT1VUOw0KPiA+ICsNCj4gPiArICAgICAgIGlmIChv Zl9wcm9wZXJ0eV9yZWFkX3UzMihucCwgImFjdGl2ZS1zZW1pLHByZWNvbmRpdGlvbl90aW1lb3V0 IiwNCj4gPiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAmY2hhcmdlci0+cHJlX3Rp bWVfb3V0KSkNCj4gPiArICAgICAgICAgICAgICAgY2hhcmdlci0+cHJlX3RpbWVfb3V0ID0gREVG QVVMVF9QUkVfVElNRV9PVVQ7DQo+ID4gKw0KPiA+ICsgICAgICAgaWYgKG9mX3Byb3BlcnR5X3Jl YWRfdTMyKG5wLCAiYWN0aXZlLXNlbWksdG90YWxfdGltZW91dCIsDQo+ID4gKyAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgJmNoYXJnZXItPnRvbGFsX3RpbWVfb3V0KSkNCj4gPiArICAg ICAgICAgICAgICAgY2hhcmdlci0+dG9sYWxfdGltZV9vdXQgPSBERUZBVUxUX1RPVEFMX1RJTUVf T1VUOw0KPiA+ICsNCj4gPiArICAgICAgIHJldHVybiAwOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtz dGF0aWMgaW50IGFjdDg5NDVhX2NoYXJnZXJfY29uZmlnKHN0cnVjdCBhY3Q4OTQ1YV9jaGFyZ2Vy ICpjaGFyZ2VyKQ0KPiA+ICt7DQo+ID4gKyAgICAgICBzdHJ1Y3QgcmVnbWFwICpyZWdtYXAgPSBj aGFyZ2VyLT5hY3Q4OTQ1YV9kZXYtPnJlZ21hcDsNCj4gPiArICAgICAgIHU4IHZhbHVlID0gMDsN Cj4gPiArDQo+ID4gKyAgICAgICBpZiAoZ3Bpb19pc192YWxpZChjaGFyZ2VyLT5jaGdsZXZfcGlu KSkNCj4gPiArICAgICAgICAgICAgICAgZ3Bpb19zZXRfdmFsdWUoY2hhcmdlci0+Y2hnbGV2X3Bp biwNCj4gPiArIGNoYXJnZXItPmNoZ2xldl92YWx1ZSk7DQo+ID4gKw0KPiA+ICsgICAgICAgc3dp dGNoIChjaGFyZ2VyLT5pbnB1dF92b2x0YWdlX3RocmVzaG9sZCkgew0KPiA+ICsgICAgICAgY2Fz ZSA4MDAwOg0KPiA+ICsgICAgICAgICAgICAgICB2YWx1ZSB8PSBBUENIX0NGR19PVlBTRVRfOFY7 DQo+ID4gKyAgICAgICAgICAgICAgIGJyZWFrOw0KPiA+ICsgICAgICAgY2FzZSA3NTAwOg0KPiA+ ICsgICAgICAgICAgICAgICB2YWx1ZSB8PSBBUENIX0NGR19PVlBTRVRfN1Y1Ow0KPiA+ICsgICAg ICAgICAgICAgICBicmVhazsNCj4gPiArICAgICAgIGNhc2UgNzAwMDoNCj4gPiArICAgICAgICAg ICAgICAgdmFsdWUgfD0gQVBDSF9DRkdfT1ZQU0VUXzdWOw0KPiA+ICsgICAgICAgICAgICAgICBi cmVhazsNCj4gPiArICAgICAgIGNhc2UgNjYwMDoNCj4gPiArICAgICAgIGRlZmF1bHQ6DQo+ID4g KyAgICAgICAgICAgICAgIHZhbHVlIHw9IEFQQ0hfQ0ZHX09WUFNFVF82VjY7DQo+ID4gKyAgICAg ICAgICAgICAgIGJyZWFrOw0KPiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIHN3aXRj aCAoY2hhcmdlci0+cHJlX3RpbWVfb3V0KSB7DQo+ID4gKyAgICAgICBjYXNlIDYwOg0KPiA+ICsg ICAgICAgICAgICAgICB2YWx1ZSB8PSBBUENIX0NGR19QUkVUSU1PXzYwX01JTjsNCj4gPiArICAg ICAgICAgICAgICAgYnJlYWs7DQo+ID4gKyAgICAgICBjYXNlIDgwOg0KPiA+ICsgICAgICAgICAg ICAgICB2YWx1ZSB8PSBBUENIX0NGR19QUkVUSU1PXzgwX01JTjsNCj4gPiArICAgICAgICAgICAg ICAgYnJlYWs7DQo+ID4gKyAgICAgICBjYXNlIDA6DQo+ID4gKyAgICAgICAgICAgICAgIHZhbHVl IHw9IEFQQ0hfQ0ZHX1BSRVRJTU9fRElTQUJMRUQ7DQo+ID4gKyAgICAgICAgICAgICAgIGJyZWFr Ow0KPiA+ICsgICAgICAgY2FzZSA0MDoNCj4gPiArICAgICAgIGRlZmF1bHQ6DQo+ID4gKyAgICAg ICAgICAgICAgIHZhbHVlIHw9IEFQQ0hfQ0ZHX1BSRVRJTU9fNDBfTUlOOw0KPiA+ICsgICAgICAg ICAgICAgICBicmVhazsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICBzd2l0Y2gg KGNoYXJnZXItPnRvbGFsX3RpbWVfb3V0KSB7DQo+ID4gKyAgICAgICBjYXNlIDQ6DQo+ID4gKyAg ICAgICAgICAgICAgIHZhbHVlIHw9IEFQQ0hfQ0ZHX1RPVFRJTU9fNF9IT1VSOw0KPiA+ICsgICAg ICAgICAgICAgICBicmVhazsNCj4gPiArICAgICAgIGNhc2UgNToNCj4gPiArICAgICAgICAgICAg ICAgdmFsdWUgfD0gQVBDSF9DRkdfVE9UVElNT181X0hPVVI7DQo+ID4gKyAgICAgICAgICAgICAg IGJyZWFrOw0KPiA+ICsgICAgICAgY2FzZSAwOg0KPiA+ICsgICAgICAgICAgICAgICB2YWx1ZSB8 PSBBUENIX0NGR19UT1RUSU1PX0RJU0FCTEVEOw0KPiA+ICsgICAgICAgICAgICAgICBicmVhazsN Cj4gPiArICAgICAgIGNhc2UgMzoNCj4gPiArICAgICAgIGRlZmF1bHQ6DQo+ID4gKyAgICAgICAg ICAgICAgIHZhbHVlIHw9IEFQQ0hfQ0ZHX1RPVFRJTU9fM19IT1VSOw0KPiA+ICsgICAgICAgICAg ICAgICBicmVhazsNCj4gPiArICAgICAgIH0NCj4gPiArDQo+ID4gKyAgICAgICByZXR1cm4gcmVn bWFwX3dyaXRlKHJlZ21hcCwgQUNUODk0NUFfQVBDSF9DRkcsIHZhbHVlKTsgfQ0KPiA+ICsNCj4g PiArc3RhdGljIGludCBhY3Q4OTQ1YV9jaGFyZ2VyX3Byb2JlKHN0cnVjdCBwbGF0Zm9ybV9kZXZp Y2UgKnBkZXYpIHsNCj4gPiArICAgICAgIHN0cnVjdCBhY3Q4OTQ1YV9kZXYgKmFjdDg5NDVhX2Rl diA9IGRldl9nZXRfZHJ2ZGF0YShwZGV2LT5kZXYucGFyZW50KTsNCj4gPiArICAgICAgIHN0cnVj dCBhY3Q4OTQ1YV9jaGFyZ2VyICpjaGFyZ2VyOw0KPiA+ICsgICAgICAgc3RydWN0IHBvd2VyX3N1 cHBseV9jb25maWcgcHN5X2NmZyA9IHt9Ow0KPiA+ICsgICAgICAgaW50IHJldDsNCj4gPiArDQo+ ID4gKyAgICAgICBjaGFyZ2VyID0gZGV2bV9remFsbG9jKCZwZGV2LT5kZXYsIHNpemVvZigqY2hh cmdlciksIEdGUF9LRVJORUwpOw0KPiA+ICsgICAgICAgaWYgKCFjaGFyZ2VyKQ0KPiA+ICsgICAg ICAgICAgICAgICByZXR1cm4gLUVOT01FTTsNCj4gPiArDQo+ID4gKyAgICAgICBwbGF0Zm9ybV9z ZXRfZHJ2ZGF0YShwZGV2LCBjaGFyZ2VyKTsNCj4gPiArDQo+ID4gKyAgICAgICBjaGFyZ2VyLT5k ZXYgPSAmcGRldi0+ZGV2Ow0KPiA+ICsgICAgICAgY2hhcmdlci0+YWN0ODk0NWFfZGV2ID0gYWN0 ODk0NWFfZGV2Ow0KPiA+ICsNCj4gPiArICAgICAgIHJldCA9IGFjdDg5NDVhX2NoYXJnZXJfcGFy c2VfZHQoJnBkZXYtPmRldiwgY2hhcmdlcik7DQo+ID4gKyAgICAgICBpZiAocmV0KQ0KPiA+ICsg ICAgICAgICAgICAgICByZXR1cm4gcmV0Ow0KPiA+ICsNCj4gPiArICAgICAgIHJldCA9IGFjdDg5 NDVhX2NoYXJnZXJfY29uZmlnKGNoYXJnZXIpOw0KPiA+ICsgICAgICAgaWYgKHJldCkNCj4gPiAr ICAgICAgICAgICAgICAgcmV0dXJuIHJldDsNCj4gPiArDQo+ID4gKyAgICAgICBwc3lfY2ZnLm9m X25vZGUgPSBwZGV2LT5kZXYub2Zfbm9kZTsNCj4gPiArICAgICAgIHBzeV9jZmcuZHJ2X2RhdGEg PSBjaGFyZ2VyOw0KPiA+ICsNCj4gPiArICAgICAgIGNoYXJnZXItPnBzeSA9IGRldm1fcG93ZXJf c3VwcGx5X3JlZ2lzdGVyKCZwZGV2LT5kZXYsDQo+ID4gKyAgICAgICAgICAgICAgICAgICAgICAg ICAgICAgICAgICAgICAgICAgICAgJmFjdDg5NDVhX2NoYXJnZXJfZGVzYywNCj4gPiArICAgICAg ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAmcHN5X2NmZyk7DQo+ID4gKyAg ICAgICBpZiAoSVNfRVJSKGNoYXJnZXItPnBzeSkpIHsNCj4gPiArICAgICAgICAgICAgICAgZGV2 X2VycihhY3Q4OTQ1YV9kZXYtPmRldiwgImZhaWxlZCB0byByZWdpc3RlciBwb3dlciBzdXBwbHlc biIpOw0KPiA+ICsgICAgICAgICAgICAgICByZXR1cm4gUFRSX0VSUihjaGFyZ2VyLT5wc3kpOw0K PiA+ICsgICAgICAgfQ0KPiA+ICsNCj4gPiArICAgICAgIGRldl9pbmZvKGFjdDg5NDVhX2Rldi0+ ZGV2LCAiY2hhcmdlciBkcml2ZXIgcmVnaXN0ZXJlZFxuIik7DQo+ID4gKw0KPiA+ICsgICAgICAg cmV0dXJuIDA7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgYWN0ODk0NWFfY2hhcmdl cl9yZW1vdmUoc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldikgew0KPiA+ICsgICAgICAgc3Ry dWN0IGFjdDg5NDVhX2NoYXJnZXIgKmNoYXJnZXIgPSBwbGF0Zm9ybV9nZXRfZHJ2ZGF0YShwZGV2 KTsNCj4gPiArDQo+ID4gKyAgICAgICBwb3dlcl9zdXBwbHlfdW5yZWdpc3RlcihjaGFyZ2VyLT5w c3kpOw0KPiA+DQo+IA0KPiBUaGUgcG9pbnQgb2YgZGV2bS1saWtlIGZ1bmN0aW9ucyBpcyB0byBn ZXQgcmlkIG9mIGVycm9yIGFuZCByZW1vdmFsIHBhdGhzLiBUaGlzDQo+IHdvbid0IHdvcmsuLi4g YWN0dWFsbHkgdGhpcyBzaG91bGQgb29wcy4gSGF2ZSB5b3UgdGVzdGVkIHVuYmluZGluZyBvZiBk cml2ZXI/DQoNClNvcnJ5IGFib3V0IGl0Lg0KDQpJIGZvcmdvdCBkbyB0aGlzIHRlc3QgZm9yIHYy Lg0KDQpJIHdpbGwgcmVtb3ZlIGl0IGluIHRoZSBuZXh0IHZlcmlvbi4NCg0KPiANCj4gQmVzdCBy ZWdhcmRzLA0KPiBLcnp5c3p0b2YNCg0KDQpCZXN0IFJlZ2FyZHMsDQpXZW55b3UgWWFuZw0K -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 1ddd13c..ae75211 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -75,6 +75,13 @@ config BATTERY_88PM860X help Say Y here to enable battery monitor for Marvell 88PM860x chip. +config BATTERY_ACT8945A + tristate "Active-semi ACT8945A charger driver" + depends on MFD_ACT8945A + help + Say Y here to enable support for power supply provided by + Active-semi ActivePath ACT8945A charger. + config BATTERY_DS2760 tristate "DS2760 battery driver (HP iPAQ & others)" depends on W1 && W1_SLAVE_DS2760 diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 0e4eab5..e46b75d 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_WM8350_POWER) += wm8350_power.o obj-$(CONFIG_TEST_POWER) += test_power.o obj-$(CONFIG_BATTERY_88PM860X) += 88pm860x_battery.o +obj-$(CONFIG_BATTERY_ACT8945A) += act8945a_charger.o obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o obj-$(CONFIG_BATTERY_DS2780) += ds2780_battery.o obj-$(CONFIG_BATTERY_DS2781) += ds2781_battery.o diff --git a/drivers/power/act8945a_charger.c b/drivers/power/act8945a_charger.c new file mode 100644 index 0000000..fe9c19f --- /dev/null +++ b/drivers/power/act8945a_charger.c @@ -0,0 +1,386 @@ +/* + * Power supply driver for the Active-semi ACT8945A PMIC + * + * Copyright (C) 2015 Atmel Corporation + * Wenyou Yang <wenyou.yang@atmel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/mfd/act8945a.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/platform_device.h> +#include <linux/power_supply.h> +#include <linux/regmap.h> + +static const char *act8945a_charger_model = "ACT8945A"; +static const char *act8945a_charger_manufacturer = "Active-semi"; + +/** + * ACT8945A Charger Register Map + */ + +/* 0x70: Reserved */ +#define ACT8945A_APCH_CFG 0x71 +#define ACT8945A_APCH_STATUS 0x78 +#define ACT8945A_APCH_CTRL 0x79 +#define ACT8945A_APCH_STATE 0x7A + +/* ACT8945A_APCH_CFG */ +#define APCH_CFG_OVPSET (0x03 << 0) +#define APCH_CFG_OVPSET_6V6 (0x0 << 0) +#define APCH_CFG_OVPSET_7V (0x1 << 0) +#define APCH_CFG_OVPSET_7V5 (0x2 << 0) +#define APCH_CFG_OVPSET_8V (0x3 << 0) +#define APCH_CFG_PRETIMO (0x03 << 2) +#define APCH_CFG_PRETIMO_40_MIN (0x0 << 2) +#define APCH_CFG_PRETIMO_60_MIN (0x1 << 2) +#define APCH_CFG_PRETIMO_80_MIN (0x2 << 2) +#define APCH_CFG_PRETIMO_DISABLED (0x3 << 2) +#define APCH_CFG_TOTTIMO (0x03 << 4) +#define APCH_CFG_TOTTIMO_3_HOUR (0x0 << 4) +#define APCH_CFG_TOTTIMO_4_HOUR (0x1 << 4) +#define APCH_CFG_TOTTIMO_5_HOUR (0x2 << 4) +#define APCH_CFG_TOTTIMO_DISABLED (0x3 << 4) +#define APCH_CFG_SUSCHG (0x01 << 7) + +#define APCH_STATUS_CHGDAT (0x01 << 0) +#define APCH_STATUS_INDAT (0x01 << 1) +#define APCH_STATUS_TEMPDAT (0x01 << 2) +#define APCH_STATUS_TIMRDAT (0x01 << 3) +#define APCH_STATUS_CHGSTAT (0x01 << 4) +#define APCH_STATUS_INSTAT (0x01 << 5) +#define APCH_STATUS_TEMPSTAT (0x01 << 6) +#define APCH_STATUS_TIMRSTAT (0x01 << 7) + +#define APCH_CTRL_CHGEOCOUT (0x01 << 0) +#define APCH_CTRL_INDIS (0x01 << 1) +#define APCH_CTRL_TEMPOUT (0x01 << 2) +#define APCH_CTRL_TIMRPRE (0x01 << 3) +#define APCH_CTRL_CHGEOCIN (0x01 << 4) +#define APCH_CTRL_INCON (0x01 << 5) +#define APCH_CTRL_TEMPIN (0x01 << 6) +#define APCH_CTRL_TIMRTOT (0x01 << 7) + +#define APCH_STATE_ACINSTAT (0x01 << 1) +#define APCH_STATE_CSTATE (0x03 << 4) +#define APCH_STATE_CSTATE_SHIFT 4 +#define APCH_STATE_CSTATE_DISABLED 0x00 +#define APCH_STATE_CSTATE_EOC 0x01 +#define APCH_STATE_CSTATE_FAST 0x02 +#define APCH_STATE_CSTATE_PRE 0x03 + +struct act8945a_charger { + struct device *dev; + struct act8945a_dev *act8945a_dev; + struct power_supply *psy; + + u32 tolal_time_out; + u32 pre_time_out; + u32 input_voltage_threshold; + bool battery_temperature; + int chglev_pin; + int chglev_value; +}; + +static int act8945a_get_charger_state(struct regmap *regmap, int *val) +{ + int ret; + unsigned int status, state; + + ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status); + if (ret < 0) + return ret; + + ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state); + if (ret < 0) + return ret; + + state &= APCH_STATE_CSTATE; + state >>= APCH_STATE_CSTATE_SHIFT; + + if (state == APCH_STATE_CSTATE_EOC) { + if (status & APCH_STATUS_CHGDAT) + *val = POWER_SUPPLY_STATUS_FULL; + else + *val = POWER_SUPPLY_STATUS_NOT_CHARGING; + } else if ((state == APCH_STATE_CSTATE_FAST) || + (state == APCH_STATE_CSTATE_PRE)) { + *val = POWER_SUPPLY_STATUS_CHARGING; + } else { + *val = POWER_SUPPLY_STATUS_NOT_CHARGING; + } + + return 0; +} + +static int act8945a_get_charge_type(struct regmap *regmap, int *val) +{ + int ret; + unsigned int state; + + ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state); + if (ret < 0) + return ret; + + state &= APCH_STATE_CSTATE; + state >>= APCH_STATE_CSTATE_SHIFT; + + switch (state) { + case APCH_STATE_CSTATE_PRE: + *val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; + break; + case APCH_STATE_CSTATE_FAST: + *val = POWER_SUPPLY_CHARGE_TYPE_FAST; + break; + case APCH_STATE_CSTATE_EOC: + case APCH_STATE_CSTATE_DISABLED: + default: + *val = POWER_SUPPLY_CHARGE_TYPE_NONE; + } + + return 0; +} + +static int act8945a_get_battery_health(struct act8945a_charger *charger, + struct regmap *regmap, int *val) +{ + int ret; + unsigned int status; + + ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status); + if (ret < 0) + return ret; + + if (charger->battery_temperature && !(status & APCH_STATUS_TEMPDAT)) + *val = POWER_SUPPLY_HEALTH_OVERHEAT; + else if (!(status & APCH_STATUS_INDAT)) + *val = POWER_SUPPLY_HEALTH_OVERVOLTAGE; + else if (status & APCH_STATUS_TIMRDAT) + *val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE; + else + *val = POWER_SUPPLY_HEALTH_GOOD; + + return 0; +} + +static enum power_supply_property act8945a_charger_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER +}; + +static int act8945a_charger_get_property(struct power_supply *psy, + enum power_supply_property prop, + union power_supply_propval *val) +{ + struct act8945a_charger *charger = power_supply_get_drvdata(psy); + struct regmap *regmap = charger->act8945a_dev->regmap; + int ret = 0; + + switch (prop) { + case POWER_SUPPLY_PROP_STATUS: + ret = act8945a_get_charger_state(regmap, &val->intval); + break; + case POWER_SUPPLY_PROP_CHARGE_TYPE: + ret = act8945a_get_charge_type(regmap, &val->intval); + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + break; + case POWER_SUPPLY_PROP_HEALTH: + ret = act8945a_get_battery_health(charger, + regmap, &val->intval); + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = act8945a_charger_model; + break; + case POWER_SUPPLY_PROP_MANUFACTURER: + val->strval = act8945a_charger_manufacturer; + break; + default: + return -EINVAL; + } + + return ret; +} + +static const struct power_supply_desc act8945a_charger_desc = { + .name = "act8945a-charger", + .type = POWER_SUPPLY_TYPE_BATTERY, + .get_property = act8945a_charger_get_property, + .properties = act8945a_charger_props, + .num_properties = ARRAY_SIZE(act8945a_charger_props), +}; + +#define DEFAULT_TOTAL_TIME_OUT 3 +#define DEFAULT_PRE_TIME_OUT 40 +#define DEFAULT_INPUT_OVP_THRESHOLD 6600 + +static int act8945a_charger_parse_dt(struct device *dev, + struct act8945a_charger *charger) +{ + struct device_node *np = dev->of_node; + enum of_gpio_flags flags; + + if (!np) { + dev_err(dev, "no charger of node\n"); + return -EINVAL; + } + + charger->chglev_pin = of_get_named_gpio_flags(np, + "active-semi,chglev-gpio", 0, &flags); + + charger->chglev_value = (flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1; + + charger->battery_temperature = of_property_read_bool(np, + "active-semi,battery_temperature"); + + if (of_property_read_u32(np, "active-semi,input_voltage_threshold", + &charger->input_voltage_threshold)) + charger->input_voltage_threshold = DEFAULT_PRE_TIME_OUT; + + if (of_property_read_u32(np, "active-semi,precondition_timeout", + &charger->pre_time_out)) + charger->pre_time_out = DEFAULT_PRE_TIME_OUT; + + if (of_property_read_u32(np, "active-semi,total_timeout", + &charger->tolal_time_out)) + charger->tolal_time_out = DEFAULT_TOTAL_TIME_OUT; + + return 0; +} + +static int act8945a_charger_config(struct act8945a_charger *charger) +{ + struct regmap *regmap = charger->act8945a_dev->regmap; + u8 value = 0; + + if (gpio_is_valid(charger->chglev_pin)) + gpio_set_value(charger->chglev_pin, charger->chglev_value); + + switch (charger->input_voltage_threshold) { + case 8000: + value |= APCH_CFG_OVPSET_8V; + break; + case 7500: + value |= APCH_CFG_OVPSET_7V5; + break; + case 7000: + value |= APCH_CFG_OVPSET_7V; + break; + case 6600: + default: + value |= APCH_CFG_OVPSET_6V6; + break; + } + + switch (charger->pre_time_out) { + case 60: + value |= APCH_CFG_PRETIMO_60_MIN; + break; + case 80: + value |= APCH_CFG_PRETIMO_80_MIN; + break; + case 0: + value |= APCH_CFG_PRETIMO_DISABLED; + break; + case 40: + default: + value |= APCH_CFG_PRETIMO_40_MIN; + break; + } + + switch (charger->tolal_time_out) { + case 4: + value |= APCH_CFG_TOTTIMO_4_HOUR; + break; + case 5: + value |= APCH_CFG_TOTTIMO_5_HOUR; + break; + case 0: + value |= APCH_CFG_TOTTIMO_DISABLED; + break; + case 3: + default: + value |= APCH_CFG_TOTTIMO_3_HOUR; + break; + } + + return regmap_write(regmap, ACT8945A_APCH_CFG, value); +} + +static int act8945a_charger_probe(struct platform_device *pdev) +{ + struct act8945a_dev *act8945a_dev = dev_get_drvdata(pdev->dev.parent); + struct act8945a_charger *charger; + struct power_supply_config psy_cfg = {}; + int ret; + + charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL); + if (!charger) + return -ENOMEM; + + platform_set_drvdata(pdev, charger); + + charger->dev = &pdev->dev; + charger->act8945a_dev = act8945a_dev; + + ret = act8945a_charger_parse_dt(&pdev->dev, charger); + if (ret) + return ret; + + ret = act8945a_charger_config(charger); + if (ret) + return ret; + + psy_cfg.of_node = pdev->dev.of_node; + psy_cfg.drv_data = charger; + + charger->psy = devm_power_supply_register(&pdev->dev, + &act8945a_charger_desc, + &psy_cfg); + if (IS_ERR(charger->psy)) { + dev_err(act8945a_dev->dev, "failed to register power supply\n"); + return PTR_ERR(charger->psy); + } + + dev_info(act8945a_dev->dev, "charger driver registered\n"); + + return 0; +} + +static int act8945a_charger_remove(struct platform_device *pdev) +{ + struct act8945a_charger *charger = platform_get_drvdata(pdev); + + power_supply_unregister(charger->psy); + + return 0; +} + +static struct platform_driver act8945a_charger_driver = { + .driver = { + .name = "act8945a-charger", + }, + .probe = act8945a_charger_probe, + .remove = act8945a_charger_remove, +}; +module_platform_driver(act8945a_charger_driver); + +MODULE_DESCRIPTION("Active-semi ACT8945A ActivePath charger driver"); +MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>"); +MODULE_LICENSE("GPL");
This patch adds new driver for Active-semi ACT8945A ActivePath charger (part of ACT8945A MFD driver) providing power supply class information to userspace. The driver is configured through DTS (battery and system related settings) and sysfs entries (timers and input over-voltage threshold). Signed-off-by: Wenyou Yang <wenyou.yang@atmel.com> --- Changes in v2: 1./ Substitute of_property_read_bool() for of_get_property(). 2./ Substitute devm_power_supply_register() for power_supply_register(). 3./ Use module_platform_driver(), instead of subsys_initcall(). 4./ Substitute MODULE_LICENSE("GPL") for MODULE_LICENSE("GPL v2"). drivers/power/Kconfig | 7 + drivers/power/Makefile | 1 + drivers/power/act8945a_charger.c | 386 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 394 insertions(+) create mode 100644 drivers/power/act8945a_charger.c