mirror of https://gitee.com/openkylin/linux.git
power supply and reset changes for the v4.14 series
* New chip/feature support - bq27xxx: support updating battery config from DT - bq24190: support loading battery charge info from DT - LTC2941: add LTC2942/LTC2944 support - max17042: add ACPI support - max1721x: new driver * Misc - Move bq27xxx w1 driver from w1 into power-supply subsystem - Introduce power_supply_set_input_current_limit_from_supplier - constify stuff - some minor fixes -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE72YNB0Y/i3JqeVQT2O7X88g7+poFAlmxSSQACgkQ2O7X88g7 +ppf2xAAliDRdNPuxpKu69syiX+iNPaPHTqRXd41sAJlEX2IYv/avcoNFcGySplR gJYdlbx2Qd86aBaMf92h4tGihk2iNa87It9xkA+JgO3wNoKiZ+b5lk///IDk8aDF 8sknSTXJtGYse0jwBRKTT4cL1ZW/g10heUxPr8AiX8nL4QhMf0TIxXawWQteAZDE dDz/UEAqbINooD5HtP716Z0e3U6FyWTqFc6UzuR+n8c6wC6n/JA6h91ASAHUmExT aH1JuQyrmucBp8cLhP01ThSkoIdGbcZM7nJ3WQBlfDricFJXa/yThug/mHvjztJX 3U1UOZBqsb/LL9Dh5hl/D3+i+7qI29KCyUZiYUrwoiSjxM/AtOB2t4cAWmU7+PnJ V3coYC1s2DlwYcLIUiyE2zmVWIDcOuuOJhQjCdpUBTPvz83nQ0v5oXMn7VnQmWlO 8Z/IRWnW90v2D2iHmSPAwFG3ATfH0pAP8G/4Wrudti+ymSxAhXaLqQcj3HHjKjvI 3CEGOPAN9Opuof7SfkIVuoOjPzazx5GUpAZQKi8LS87KRdXN4ics3vbNB6VBDR50 FzVhJJZBTeAOJCDogInuu4gDa0L5Ikfdkhqc+nvNfcdsE2k3H8Nb//+UPiPnfgEA mEFyp9gaY08/3ylDEHxp3N/W7POrL4QelTjv0dvdKW70i7KtWpA= =iy5f -----END PGP SIGNATURE----- Merge tag 'for-v4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply Pull power supply and reset changes from Sebastian Reichel: "New chip/feature support: - bq27xxx: support updating battery config from DT - bq24190: support loading battery charge info from DT - LTC2941: add LTC2942/LTC2944 support - max17042: add ACPI support - max1721x: new driver Misc: - Move bq27xxx w1 driver from w1 into power-supply subsystem - Introduce power_supply_set_input_current_limit_from_supplier - constify stuff - some minor fixes" * tag 'for-v4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (39 commits) power: supply: bq27xxx: enable writing capacity values for bq27421 power: supply: bq24190_charger: Get input_current_limit from our supplier power: supply: bq24190_charger: Export 5V boost converter as regulator power: supply: bq24190_charger: Add power_supply_battery_info support power: supply: bq24190_charger: Add property system-minimum-microvolt power: supply: bq24190_charger: Enable devicetree config dt-bindings: power: supply: Add docs for TI BQ24190 battery charger power: supply: bq27xxx: Remove duplicate chip data arrays power: supply: bq27xxx: Enable data memory update for certain chips power: supply: bq27xxx: Add chip IDs for previously shadowed chips power: supply: bq27xxx: Create single chip data table power: supply: bq24190_charger: Add ti,bq24192i to devicetree table power: supply: bq24190_charger: Add input_current_limit property power: supply: Add power_supply_set_input_current_limit_from_supplier helper power: supply: max17042_battery: Fix compiler warning power: supply: core: Delete two error messages for a failed memory allocation in power_supply_check_supplies() power: supply: make device_attribute const power: supply: max17042_battery: Fix ACPI interrupt issues power: supply: max17042_battery: Add support for ACPI enumeration power: supply: lp8788: Make several arrays static const * const ...
This commit is contained in:
commit
0ce5c79f38
|
@ -0,0 +1,51 @@
|
|||
TI BQ24190 Li-Ion Battery Charger
|
||||
|
||||
Required properties:
|
||||
- compatible: contains one of the following:
|
||||
* "ti,bq24190"
|
||||
* "ti,bq24192i"
|
||||
- reg: integer, I2C address of the charger.
|
||||
- interrupts[-extended]: configuration for charger INT pin.
|
||||
|
||||
Optional properties:
|
||||
- monitored-battery: phandle of battery characteristics devicetree node
|
||||
The charger uses the following battery properties:
|
||||
+ precharge-current-microamp: maximum charge current during precharge
|
||||
phase (typically 20% of battery capacity).
|
||||
+ charge-term-current-microamp: a charge cycle terminates when the
|
||||
battery voltage is above recharge threshold, and the current is below
|
||||
this setting (typically 10% of battery capacity).
|
||||
See also Documentation/devicetree/bindings/power/supply/battery.txt
|
||||
- ti,system-minimum-microvolt: when power is connected and the battery is below
|
||||
minimum system voltage, the system will be regulated above this setting.
|
||||
|
||||
Notes:
|
||||
- Some circuit boards wire the chip's "OTG" pin high (enabling 500mA default
|
||||
charge current on USB SDP ports, among other features). To simulate this on
|
||||
boards that wire the pin to a GPIO, set a gpio-hog.
|
||||
|
||||
Example:
|
||||
|
||||
bat: battery {
|
||||
compatible = "simple-battery";
|
||||
precharge-current-microamp = <256000>;
|
||||
charge-term-current-microamp = <128000>;
|
||||
// etc.
|
||||
};
|
||||
|
||||
bq24190: charger@6a {
|
||||
compatible = "ti,bq24190";
|
||||
reg = <0x6a>;
|
||||
interrupts-extended = <&gpiochip 10 IRQ_TYPE_EDGE_FALLING>;
|
||||
monitored-battery = <&bat>;
|
||||
ti,system-minimum-microvolt = <3200000>;
|
||||
};
|
||||
|
||||
&twl_gpio {
|
||||
otg {
|
||||
gpio-hog;
|
||||
gpios = <6 0>;
|
||||
output-high;
|
||||
line-name = "otg-gpio";
|
||||
};
|
||||
};
|
|
@ -1,13 +1,14 @@
|
|||
binding for LTC2941 and LTC2943 battery gauges
|
||||
binding for LTC2941, LTC2942, LTC2943 and LTC2944 battery gauges
|
||||
|
||||
Both the LTC2941 and LTC2943 measure battery capacity.
|
||||
The LTC2943 is compatible with the LTC2941, it adds voltage and
|
||||
temperature monitoring, and uses a slightly different conversion
|
||||
formula for the charge counter.
|
||||
All chips measure battery capacity.
|
||||
The LTC2942 is pin compatible with the LTC2941, it adds voltage and
|
||||
temperature monitoring, and is runtime detected. LTC2943 and LTC2944
|
||||
is software compatible, uses a slightly different conversion formula
|
||||
for the charge counter and adds voltage, current and temperature monitoring.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should contain "lltc,ltc2941" or "lltc,ltc2943" which also
|
||||
indicates the type of I2C chip attached.
|
||||
- compatible: Should contain "lltc,ltc2941", "lltc,ltc2942", "lltc,ltc2943"
|
||||
or "lltc,ltc2944" which also indicates the type of I2C chip attached.
|
||||
- reg: The 7-bit I2C address.
|
||||
- lltc,resistor-sense: The sense resistor value in milli-ohms. Can be a 32-bit
|
||||
negative value when the battery has been connected to the wrong end of the
|
||||
|
|
|
@ -171,8 +171,8 @@ static u32 at91_shdwc_get_wakeup_input(struct platform_device *pdev,
|
|||
|
||||
for_each_child_of_node(np, cnp) {
|
||||
if (of_property_read_u32(cnp, "reg", &wk_input)) {
|
||||
dev_warn(&pdev->dev, "reg property is missing for %s\n",
|
||||
cnp->full_name);
|
||||
dev_warn(&pdev->dev, "reg property is missing for %pOF\n",
|
||||
cnp);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -198,6 +198,15 @@ config BATTERY_BQ27XXX_I2C
|
|||
Say Y here to enable support for batteries with BQ27xxx chips
|
||||
connected over an I2C bus.
|
||||
|
||||
config BATTERY_BQ27XXX_HDQ
|
||||
tristate "BQ27xxx HDQ support"
|
||||
depends on BATTERY_BQ27XXX
|
||||
depends on W1
|
||||
default y
|
||||
help
|
||||
Say Y here to enable support for batteries with BQ27xxx chips
|
||||
connected over an HDQ bus.
|
||||
|
||||
config BATTERY_BQ27XXX_DT_UPDATES_NVM
|
||||
bool "BQ27xxx support for update of NVM/flash data memory"
|
||||
depends on BATTERY_BQ27XXX_I2C
|
||||
|
@ -313,6 +322,19 @@ config BATTERY_MAX17042
|
|||
with MAX17042. This driver also supports max17047/50 chips which are
|
||||
improved version of max17042.
|
||||
|
||||
config BATTERY_MAX1721X
|
||||
tristate "MAX17211/MAX17215 standalone gas-gauge"
|
||||
depends on W1
|
||||
select REGMAP_W1
|
||||
help
|
||||
MAX1721x is fuel-gauge systems for lithium-ion (Li+) batteries
|
||||
in handheld and portable equipment. MAX17211 used with single cell
|
||||
battery. MAX17215 designed for muticell battery. Both them have
|
||||
OneWire (W1) host interface.
|
||||
|
||||
Say Y here to enable support for the MAX17211/MAX17215 standalone
|
||||
battery gas-gauge.
|
||||
|
||||
config BATTERY_Z2
|
||||
tristate "Z2 battery driver"
|
||||
depends on I2C && MACH_ZIPIT2
|
||||
|
@ -365,6 +387,7 @@ config BATTERY_RX51
|
|||
config CHARGER_CPCAP
|
||||
tristate "CPCAP PMIC Charger Driver"
|
||||
depends on MFD_CPCAP && IIO
|
||||
depends on OMAP_USB2 || (!OMAP_USB2 && COMPILE_TEST)
|
||||
default MFD_CPCAP
|
||||
help
|
||||
Say Y to enable support for CPCAP PMIC charger driver for Motorola
|
||||
|
|
|
@ -38,12 +38,14 @@ obj-$(CONFIG_BATTERY_SBS) += sbs-battery.o
|
|||
obj-$(CONFIG_CHARGER_SBS) += sbs-charger.o
|
||||
obj-$(CONFIG_BATTERY_BQ27XXX) += bq27xxx_battery.o
|
||||
obj-$(CONFIG_BATTERY_BQ27XXX_I2C) += bq27xxx_battery_i2c.o
|
||||
obj-$(CONFIG_BATTERY_BQ27XXX_HDQ) += bq27xxx_battery_hdq.o
|
||||
obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o
|
||||
obj-$(CONFIG_BATTERY_DA9052) += da9052-battery.o
|
||||
obj-$(CONFIG_CHARGER_DA9150) += da9150-charger.o
|
||||
obj-$(CONFIG_BATTERY_DA9150) += da9150-fg.o
|
||||
obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
|
||||
obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
|
||||
obj-$(CONFIG_BATTERY_MAX1721X) += max1721x_battery.o
|
||||
obj-$(CONFIG_BATTERY_Z2) += z2_battery.o
|
||||
obj-$(CONFIG_BATTERY_RT5033) += rt5033_battery.o
|
||||
obj-$(CONFIG_CHARGER_RT9455) += rt9455_charger.o
|
||||
|
|
|
@ -596,9 +596,9 @@ static int act8945a_charger_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
|
||||
irq = of_irq_get(pdev->dev.of_node, 0);
|
||||
if (irq == -EPROBE_DEFER) {
|
||||
if (irq <= 0) {
|
||||
dev_err(&pdev->dev, "failed to find IRQ number\n");
|
||||
return -EPROBE_DEFER;
|
||||
return irq ?: -ENXIO;
|
||||
}
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, irq, act8945a_status_changed,
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/power/bq24190_charger.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
|
@ -43,6 +46,8 @@
|
|||
#define BQ24190_REG_POC_CHG_CONFIG_OTG 0x2
|
||||
#define BQ24190_REG_POC_SYS_MIN_MASK (BIT(3) | BIT(2) | BIT(1))
|
||||
#define BQ24190_REG_POC_SYS_MIN_SHIFT 1
|
||||
#define BQ24190_REG_POC_SYS_MIN_MIN 3000
|
||||
#define BQ24190_REG_POC_SYS_MIN_MAX 3700
|
||||
#define BQ24190_REG_POC_BOOST_LIM_MASK BIT(0)
|
||||
#define BQ24190_REG_POC_BOOST_LIM_SHIFT 0
|
||||
|
||||
|
@ -57,9 +62,13 @@
|
|||
#define BQ24190_REG_PCTCC_IPRECHG_MASK (BIT(7) | BIT(6) | BIT(5) | \
|
||||
BIT(4))
|
||||
#define BQ24190_REG_PCTCC_IPRECHG_SHIFT 4
|
||||
#define BQ24190_REG_PCTCC_IPRECHG_MIN 128
|
||||
#define BQ24190_REG_PCTCC_IPRECHG_MAX 2048
|
||||
#define BQ24190_REG_PCTCC_ITERM_MASK (BIT(3) | BIT(2) | BIT(1) | \
|
||||
BIT(0))
|
||||
#define BQ24190_REG_PCTCC_ITERM_SHIFT 0
|
||||
#define BQ24190_REG_PCTCC_ITERM_MIN 128
|
||||
#define BQ24190_REG_PCTCC_ITERM_MAX 2048
|
||||
|
||||
#define BQ24190_REG_CVC 0x04 /* Charge Voltage Control */
|
||||
#define BQ24190_REG_CVC_VREG_MASK (BIT(7) | BIT(6) | BIT(5) | \
|
||||
|
@ -156,9 +165,13 @@ struct bq24190_dev_info {
|
|||
struct extcon_dev *extcon;
|
||||
struct notifier_block extcon_nb;
|
||||
struct delayed_work extcon_work;
|
||||
struct delayed_work input_current_limit_work;
|
||||
char model_name[I2C_NAME_SIZE];
|
||||
bool initialized;
|
||||
bool irq_event;
|
||||
u16 sys_min;
|
||||
u16 iprechg;
|
||||
u16 iterm;
|
||||
struct mutex f_reg_lock;
|
||||
u8 f_reg;
|
||||
u8 ss_reg;
|
||||
|
@ -504,15 +517,112 @@ static int bq24190_sysfs_create_group(struct bq24190_dev_info *bdi)
|
|||
static inline void bq24190_sysfs_remove_group(struct bq24190_dev_info *bdi) {}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* According to the "Host Mode and default Mode" section of the
|
||||
* manual, a write to any register causes the bq24190 to switch
|
||||
* from default mode to host mode. It will switch back to default
|
||||
* mode after a WDT timeout unless the WDT is turned off as well.
|
||||
* So, by simply turning off the WDT, we accomplish both with the
|
||||
* same write.
|
||||
*/
|
||||
static int bq24190_set_mode_host(struct bq24190_dev_info *bdi)
|
||||
#ifdef CONFIG_REGULATOR
|
||||
static int bq24190_set_charge_mode(struct regulator_dev *dev, u8 val)
|
||||
{
|
||||
struct bq24190_dev_info *bdi = rdev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_get_sync(bdi->dev);
|
||||
if (ret < 0) {
|
||||
dev_warn(bdi->dev, "pm_runtime_get failed: %i\n", ret);
|
||||
pm_runtime_put_noidle(bdi->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = bq24190_write_mask(bdi, BQ24190_REG_POC,
|
||||
BQ24190_REG_POC_CHG_CONFIG_MASK,
|
||||
BQ24190_REG_POC_CHG_CONFIG_SHIFT, val);
|
||||
|
||||
pm_runtime_mark_last_busy(bdi->dev);
|
||||
pm_runtime_put_autosuspend(bdi->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bq24190_vbus_enable(struct regulator_dev *dev)
|
||||
{
|
||||
return bq24190_set_charge_mode(dev, BQ24190_REG_POC_CHG_CONFIG_OTG);
|
||||
}
|
||||
|
||||
static int bq24190_vbus_disable(struct regulator_dev *dev)
|
||||
{
|
||||
return bq24190_set_charge_mode(dev, BQ24190_REG_POC_CHG_CONFIG_CHARGE);
|
||||
}
|
||||
|
||||
static int bq24190_vbus_is_enabled(struct regulator_dev *dev)
|
||||
{
|
||||
struct bq24190_dev_info *bdi = rdev_get_drvdata(dev);
|
||||
int ret;
|
||||
u8 val;
|
||||
|
||||
ret = pm_runtime_get_sync(bdi->dev);
|
||||
if (ret < 0) {
|
||||
dev_warn(bdi->dev, "pm_runtime_get failed: %i\n", ret);
|
||||
pm_runtime_put_noidle(bdi->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = bq24190_read_mask(bdi, BQ24190_REG_POC,
|
||||
BQ24190_REG_POC_CHG_CONFIG_MASK,
|
||||
BQ24190_REG_POC_CHG_CONFIG_SHIFT, &val);
|
||||
|
||||
pm_runtime_mark_last_busy(bdi->dev);
|
||||
pm_runtime_put_autosuspend(bdi->dev);
|
||||
|
||||
return ret ? ret : val == BQ24190_REG_POC_CHG_CONFIG_OTG;
|
||||
}
|
||||
|
||||
static const struct regulator_ops bq24190_vbus_ops = {
|
||||
.enable = bq24190_vbus_enable,
|
||||
.disable = bq24190_vbus_disable,
|
||||
.is_enabled = bq24190_vbus_is_enabled,
|
||||
};
|
||||
|
||||
static const struct regulator_desc bq24190_vbus_desc = {
|
||||
.name = "usb_otg_vbus",
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.owner = THIS_MODULE,
|
||||
.ops = &bq24190_vbus_ops,
|
||||
.fixed_uV = 5000000,
|
||||
.n_voltages = 1,
|
||||
};
|
||||
|
||||
static const struct regulator_init_data bq24190_vbus_init_data = {
|
||||
.constraints = {
|
||||
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
|
||||
},
|
||||
};
|
||||
|
||||
static int bq24190_register_vbus_regulator(struct bq24190_dev_info *bdi)
|
||||
{
|
||||
struct bq24190_platform_data *pdata = bdi->dev->platform_data;
|
||||
struct regulator_config cfg = { };
|
||||
struct regulator_dev *reg;
|
||||
int ret = 0;
|
||||
|
||||
cfg.dev = bdi->dev;
|
||||
if (pdata && pdata->regulator_init_data)
|
||||
cfg.init_data = pdata->regulator_init_data;
|
||||
else
|
||||
cfg.init_data = &bq24190_vbus_init_data;
|
||||
cfg.driver_data = bdi;
|
||||
reg = devm_regulator_register(bdi->dev, &bq24190_vbus_desc, &cfg);
|
||||
if (IS_ERR(reg)) {
|
||||
ret = PTR_ERR(reg);
|
||||
dev_err(bdi->dev, "Can't register regulator: %d\n", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static int bq24190_register_vbus_regulator(struct bq24190_dev_info *bdi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int bq24190_set_config(struct bq24190_dev_info *bdi)
|
||||
{
|
||||
int ret;
|
||||
u8 v;
|
||||
|
@ -523,9 +633,52 @@ static int bq24190_set_mode_host(struct bq24190_dev_info *bdi)
|
|||
|
||||
bdi->watchdog = ((v & BQ24190_REG_CTTC_WATCHDOG_MASK) >>
|
||||
BQ24190_REG_CTTC_WATCHDOG_SHIFT);
|
||||
|
||||
/*
|
||||
* According to the "Host Mode and default Mode" section of the
|
||||
* manual, a write to any register causes the bq24190 to switch
|
||||
* from default mode to host mode. It will switch back to default
|
||||
* mode after a WDT timeout unless the WDT is turned off as well.
|
||||
* So, by simply turning off the WDT, we accomplish both with the
|
||||
* same write.
|
||||
*/
|
||||
v &= ~BQ24190_REG_CTTC_WATCHDOG_MASK;
|
||||
|
||||
return bq24190_write(bdi, BQ24190_REG_CTTC, v);
|
||||
ret = bq24190_write(bdi, BQ24190_REG_CTTC, v);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (bdi->sys_min) {
|
||||
v = bdi->sys_min / 100 - 30; // manual section 9.5.1.2, table 9
|
||||
ret = bq24190_write_mask(bdi, BQ24190_REG_POC,
|
||||
BQ24190_REG_POC_SYS_MIN_MASK,
|
||||
BQ24190_REG_POC_SYS_MIN_SHIFT,
|
||||
v);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (bdi->iprechg) {
|
||||
v = bdi->iprechg / 128 - 1; // manual section 9.5.1.4, table 11
|
||||
ret = bq24190_write_mask(bdi, BQ24190_REG_PCTCC,
|
||||
BQ24190_REG_PCTCC_IPRECHG_MASK,
|
||||
BQ24190_REG_PCTCC_IPRECHG_SHIFT,
|
||||
v);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (bdi->iterm) {
|
||||
v = bdi->iterm / 128 - 1; // manual section 9.5.1.4, table 11
|
||||
ret = bq24190_write_mask(bdi, BQ24190_REG_PCTCC,
|
||||
BQ24190_REG_PCTCC_ITERM_MASK,
|
||||
BQ24190_REG_PCTCC_ITERM_SHIFT,
|
||||
v);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bq24190_register_reset(struct bq24190_dev_info *bdi)
|
||||
|
@ -773,6 +926,38 @@ static int bq24190_charger_set_temp_alert_max(struct bq24190_dev_info *bdi,
|
|||
return bq24190_battery_set_temp_alert_max(bdi, val);
|
||||
}
|
||||
|
||||
static int bq24190_charger_get_precharge(struct bq24190_dev_info *bdi,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
u8 v;
|
||||
int ret;
|
||||
|
||||
ret = bq24190_read_mask(bdi, BQ24190_REG_PCTCC,
|
||||
BQ24190_REG_PCTCC_IPRECHG_MASK,
|
||||
BQ24190_REG_PCTCC_IPRECHG_SHIFT, &v);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val->intval = ++v * 128 * 1000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bq24190_charger_get_charge_term(struct bq24190_dev_info *bdi,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
u8 v;
|
||||
int ret;
|
||||
|
||||
ret = bq24190_read_mask(bdi, BQ24190_REG_PCTCC,
|
||||
BQ24190_REG_PCTCC_ITERM_MASK,
|
||||
BQ24190_REG_PCTCC_ITERM_SHIFT, &v);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val->intval = ++v * 128 * 1000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bq24190_charger_get_current(struct bq24190_dev_info *bdi,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
|
@ -865,6 +1050,33 @@ static int bq24190_charger_set_voltage(struct bq24190_dev_info *bdi,
|
|||
ARRAY_SIZE(bq24190_cvc_vreg_values), val->intval);
|
||||
}
|
||||
|
||||
static int bq24190_charger_get_iinlimit(struct bq24190_dev_info *bdi,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
int iinlimit, ret;
|
||||
|
||||
ret = bq24190_get_field_val(bdi, BQ24190_REG_ISC,
|
||||
BQ24190_REG_ISC_IINLIM_MASK,
|
||||
BQ24190_REG_ISC_IINLIM_SHIFT,
|
||||
bq24190_isc_iinlim_values,
|
||||
ARRAY_SIZE(bq24190_isc_iinlim_values), &iinlimit);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
val->intval = iinlimit;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bq24190_charger_set_iinlimit(struct bq24190_dev_info *bdi,
|
||||
const union power_supply_propval *val)
|
||||
{
|
||||
return bq24190_set_field_val(bdi, BQ24190_REG_ISC,
|
||||
BQ24190_REG_ISC_IINLIM_MASK,
|
||||
BQ24190_REG_ISC_IINLIM_SHIFT,
|
||||
bq24190_isc_iinlim_values,
|
||||
ARRAY_SIZE(bq24190_isc_iinlim_values), val->intval);
|
||||
}
|
||||
|
||||
static int bq24190_charger_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp, union power_supply_propval *val)
|
||||
{
|
||||
|
@ -893,6 +1105,12 @@ static int bq24190_charger_get_property(struct power_supply *psy,
|
|||
case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
|
||||
ret = bq24190_charger_get_temp_alert_max(bdi, val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
|
||||
ret = bq24190_charger_get_precharge(bdi, val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
|
||||
ret = bq24190_charger_get_charge_term(bdi, val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
|
||||
ret = bq24190_charger_get_current(bdi, val);
|
||||
break;
|
||||
|
@ -905,6 +1123,9 @@ static int bq24190_charger_get_property(struct power_supply *psy,
|
|||
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
|
||||
ret = bq24190_charger_get_voltage_max(bdi, val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
|
||||
ret = bq24190_charger_get_iinlimit(bdi, val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_SCOPE:
|
||||
val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
|
||||
ret = 0;
|
||||
|
@ -956,6 +1177,9 @@ static int bq24190_charger_set_property(struct power_supply *psy,
|
|||
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
|
||||
ret = bq24190_charger_set_voltage(bdi, val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
|
||||
ret = bq24190_charger_set_iinlimit(bdi, val);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
@ -977,6 +1201,7 @@ static int bq24190_charger_property_is_writeable(struct power_supply *psy,
|
|||
case POWER_SUPPLY_PROP_CHARGE_TYPE:
|
||||
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
|
||||
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
|
||||
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
|
||||
ret = 1;
|
||||
break;
|
||||
default:
|
||||
|
@ -986,16 +1211,45 @@ static int bq24190_charger_property_is_writeable(struct power_supply *psy,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void bq24190_input_current_limit_work(struct work_struct *work)
|
||||
{
|
||||
struct bq24190_dev_info *bdi =
|
||||
container_of(work, struct bq24190_dev_info,
|
||||
input_current_limit_work.work);
|
||||
|
||||
power_supply_set_input_current_limit_from_supplier(bdi->charger);
|
||||
}
|
||||
|
||||
/* Sync the input-current-limit with our parent supply (if we have one) */
|
||||
static void bq24190_charger_external_power_changed(struct power_supply *psy)
|
||||
{
|
||||
struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy);
|
||||
|
||||
/*
|
||||
* The Power-Good detection may take up to 220ms, sometimes
|
||||
* the external charger detection is quicker, and the bq24190 will
|
||||
* reset to iinlim based on its own charger detection (which is not
|
||||
* hooked up when using external charger detection) resulting in a
|
||||
* too low default 500mA iinlim. Delay setting the input-current-limit
|
||||
* for 300ms to avoid this.
|
||||
*/
|
||||
queue_delayed_work(system_wq, &bdi->input_current_limit_work,
|
||||
msecs_to_jiffies(300));
|
||||
}
|
||||
|
||||
static enum power_supply_property bq24190_charger_properties[] = {
|
||||
POWER_SUPPLY_PROP_CHARGE_TYPE,
|
||||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
|
||||
POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
|
||||
POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
|
||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
|
||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
|
||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
|
||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
|
||||
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
|
||||
POWER_SUPPLY_PROP_SCOPE,
|
||||
POWER_SUPPLY_PROP_MODEL_NAME,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
|
@ -1013,6 +1267,7 @@ static const struct power_supply_desc bq24190_charger_desc = {
|
|||
.get_property = bq24190_charger_get_property,
|
||||
.set_property = bq24190_charger_set_property,
|
||||
.property_is_writeable = bq24190_charger_property_is_writeable,
|
||||
.external_power_changed = bq24190_charger_external_power_changed,
|
||||
};
|
||||
|
||||
/* Battery power supply property routines */
|
||||
|
@ -1460,13 +1715,50 @@ static int bq24190_hw_init(struct bq24190_dev_info *bdi)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = bq24190_set_mode_host(bdi);
|
||||
ret = bq24190_set_config(bdi);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return bq24190_read(bdi, BQ24190_REG_SS, &bdi->ss_reg);
|
||||
}
|
||||
|
||||
static int bq24190_get_config(struct bq24190_dev_info *bdi)
|
||||
{
|
||||
const char * const s = "ti,system-minimum-microvolt";
|
||||
struct power_supply_battery_info info = {};
|
||||
int v;
|
||||
|
||||
if (device_property_read_u32(bdi->dev, s, &v) == 0) {
|
||||
v /= 1000;
|
||||
if (v >= BQ24190_REG_POC_SYS_MIN_MIN
|
||||
&& v <= BQ24190_REG_POC_SYS_MIN_MAX)
|
||||
bdi->sys_min = v;
|
||||
else
|
||||
dev_warn(bdi->dev, "invalid value for %s: %u\n", s, v);
|
||||
}
|
||||
|
||||
if (bdi->dev->of_node &&
|
||||
!power_supply_get_battery_info(bdi->charger, &info)) {
|
||||
v = info.precharge_current_ua / 1000;
|
||||
if (v >= BQ24190_REG_PCTCC_IPRECHG_MIN
|
||||
&& v <= BQ24190_REG_PCTCC_IPRECHG_MAX)
|
||||
bdi->iprechg = v;
|
||||
else
|
||||
dev_warn(bdi->dev, "invalid value for battery:precharge-current-microamp: %d\n",
|
||||
v);
|
||||
|
||||
v = info.charge_term_current_ua / 1000;
|
||||
if (v >= BQ24190_REG_PCTCC_ITERM_MIN
|
||||
&& v <= BQ24190_REG_PCTCC_ITERM_MAX)
|
||||
bdi->iterm = v;
|
||||
else
|
||||
dev_warn(bdi->dev, "invalid value for battery:charge-term-current-microamp: %d\n",
|
||||
v);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bq24190_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
|
@ -1494,10 +1786,12 @@ static int bq24190_probe(struct i2c_client *client,
|
|||
mutex_init(&bdi->f_reg_lock);
|
||||
bdi->f_reg = 0;
|
||||
bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */
|
||||
INIT_DELAYED_WORK(&bdi->input_current_limit_work,
|
||||
bq24190_input_current_limit_work);
|
||||
|
||||
i2c_set_clientdata(client, bdi);
|
||||
|
||||
if (!client->irq) {
|
||||
if (client->irq <= 0) {
|
||||
dev_err(dev, "Can't get irq info\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -1530,13 +1824,8 @@ static int bq24190_probe(struct i2c_client *client,
|
|||
goto out_pmrt;
|
||||
}
|
||||
|
||||
ret = bq24190_hw_init(bdi);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Hardware init failed\n");
|
||||
goto out_pmrt;
|
||||
}
|
||||
|
||||
charger_cfg.drv_data = bdi;
|
||||
charger_cfg.of_node = dev->of_node;
|
||||
charger_cfg.supplied_to = bq24190_charger_supplied_to;
|
||||
charger_cfg.num_supplicants = ARRAY_SIZE(bq24190_charger_supplied_to),
|
||||
bdi->charger = power_supply_register(dev, &bq24190_charger_desc,
|
||||
|
@ -1560,8 +1849,20 @@ static int bq24190_probe(struct i2c_client *client,
|
|||
}
|
||||
}
|
||||
|
||||
ret = bq24190_get_config(bdi);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Can't get devicetree config\n");
|
||||
goto out_charger;
|
||||
}
|
||||
|
||||
ret = bq24190_hw_init(bdi);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Hardware init failed\n");
|
||||
goto out_charger;
|
||||
}
|
||||
|
||||
ret = bq24190_sysfs_create_group(bdi);
|
||||
if (ret) {
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Can't create sysfs entries\n");
|
||||
goto out_charger;
|
||||
}
|
||||
|
@ -1577,6 +1878,10 @@ static int bq24190_probe(struct i2c_client *client,
|
|||
goto out_sysfs;
|
||||
}
|
||||
|
||||
ret = bq24190_register_vbus_regulator(bdi);
|
||||
if (ret < 0)
|
||||
goto out_sysfs;
|
||||
|
||||
if (bdi->extcon) {
|
||||
INIT_DELAYED_WORK(&bdi->extcon_work, bq24190_extcon_work);
|
||||
bdi->extcon_nb.notifier_call = bq24190_extcon_event;
|
||||
|
@ -1704,7 +2009,7 @@ static __maybe_unused int bq24190_pm_resume(struct device *dev)
|
|||
}
|
||||
|
||||
bq24190_register_reset(bdi);
|
||||
bq24190_set_mode_host(bdi);
|
||||
bq24190_set_config(bdi);
|
||||
bq24190_read(bdi, BQ24190_REG_SS, &bdi->ss_reg);
|
||||
|
||||
if (error >= 0) {
|
||||
|
@ -1736,6 +2041,7 @@ MODULE_DEVICE_TABLE(i2c, bq24190_i2c_ids);
|
|||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id bq24190_of_match[] = {
|
||||
{ .compatible = "ti,bq24190", },
|
||||
{ .compatible = "ti,bq24192i", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bq24190_of_match);
|
||||
|
|
|
@ -58,8 +58,6 @@
|
|||
|
||||
#include <linux/power/bq27xxx_battery.h>
|
||||
|
||||
#define DRIVER_VERSION "1.2.0"
|
||||
|
||||
#define BQ27XXX_MANUFACTURER "Texas Instruments"
|
||||
|
||||
/* BQ27XXX Flags */
|
||||
|
@ -132,8 +130,8 @@ enum bq27xxx_reg_index {
|
|||
[BQ27XXX_DM_CKSUM] = 0x60
|
||||
|
||||
/* Register mappings */
|
||||
static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
|
||||
[BQ27000] = {
|
||||
static u8
|
||||
bq27000_regs[BQ27XXX_REG_MAX] = {
|
||||
[BQ27XXX_REG_CTRL] = 0x00,
|
||||
[BQ27XXX_REG_TEMP] = 0x06,
|
||||
[BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR,
|
||||
|
@ -157,7 +155,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
|
|||
[BQ27XXX_DM_DATA] = INVALID_REG_ADDR,
|
||||
[BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR,
|
||||
},
|
||||
[BQ27010] = {
|
||||
bq27010_regs[BQ27XXX_REG_MAX] = {
|
||||
[BQ27XXX_REG_CTRL] = 0x00,
|
||||
[BQ27XXX_REG_TEMP] = 0x06,
|
||||
[BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR,
|
||||
|
@ -181,7 +179,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
|
|||
[BQ27XXX_DM_DATA] = INVALID_REG_ADDR,
|
||||
[BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR,
|
||||
},
|
||||
[BQ2750X] = {
|
||||
bq2750x_regs[BQ27XXX_REG_MAX] = {
|
||||
[BQ27XXX_REG_CTRL] = 0x00,
|
||||
[BQ27XXX_REG_TEMP] = 0x06,
|
||||
[BQ27XXX_REG_INT_TEMP] = 0x28,
|
||||
|
@ -201,7 +199,31 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
|
|||
[BQ27XXX_REG_AP] = INVALID_REG_ADDR,
|
||||
BQ27XXX_DM_REG_ROWS,
|
||||
},
|
||||
[BQ2751X] = {
|
||||
#define bq2751x_regs bq27510g3_regs
|
||||
#define bq2752x_regs bq27510g3_regs
|
||||
bq27500_regs[BQ27XXX_REG_MAX] = {
|
||||
[BQ27XXX_REG_CTRL] = 0x00,
|
||||
[BQ27XXX_REG_TEMP] = 0x06,
|
||||
[BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR,
|
||||
[BQ27XXX_REG_VOLT] = 0x08,
|
||||
[BQ27XXX_REG_AI] = 0x14,
|
||||
[BQ27XXX_REG_FLAGS] = 0x0a,
|
||||
[BQ27XXX_REG_TTE] = 0x16,
|
||||
[BQ27XXX_REG_TTF] = 0x18,
|
||||
[BQ27XXX_REG_TTES] = 0x1c,
|
||||
[BQ27XXX_REG_TTECP] = 0x26,
|
||||
[BQ27XXX_REG_NAC] = 0x0c,
|
||||
[BQ27XXX_REG_FCC] = 0x12,
|
||||
[BQ27XXX_REG_CYCT] = 0x2a,
|
||||
[BQ27XXX_REG_AE] = 0x22,
|
||||
[BQ27XXX_REG_SOC] = 0x2c,
|
||||
[BQ27XXX_REG_DCAP] = 0x3c,
|
||||
[BQ27XXX_REG_AP] = 0x24,
|
||||
BQ27XXX_DM_REG_ROWS,
|
||||
},
|
||||
#define bq27510g1_regs bq27500_regs
|
||||
#define bq27510g2_regs bq27500_regs
|
||||
bq27510g3_regs[BQ27XXX_REG_MAX] = {
|
||||
[BQ27XXX_REG_CTRL] = 0x00,
|
||||
[BQ27XXX_REG_TEMP] = 0x06,
|
||||
[BQ27XXX_REG_INT_TEMP] = 0x28,
|
||||
|
@ -221,87 +243,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
|
|||
[BQ27XXX_REG_AP] = INVALID_REG_ADDR,
|
||||
BQ27XXX_DM_REG_ROWS,
|
||||
},
|
||||
[BQ27500] = {
|
||||
[BQ27XXX_REG_CTRL] = 0x00,
|
||||
[BQ27XXX_REG_TEMP] = 0x06,
|
||||
[BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR,
|
||||
[BQ27XXX_REG_VOLT] = 0x08,
|
||||
[BQ27XXX_REG_AI] = 0x14,
|
||||
[BQ27XXX_REG_FLAGS] = 0x0a,
|
||||
[BQ27XXX_REG_TTE] = 0x16,
|
||||
[BQ27XXX_REG_TTF] = 0x18,
|
||||
[BQ27XXX_REG_TTES] = 0x1c,
|
||||
[BQ27XXX_REG_TTECP] = 0x26,
|
||||
[BQ27XXX_REG_NAC] = 0x0c,
|
||||
[BQ27XXX_REG_FCC] = 0x12,
|
||||
[BQ27XXX_REG_CYCT] = 0x2a,
|
||||
[BQ27XXX_REG_AE] = 0x22,
|
||||
[BQ27XXX_REG_SOC] = 0x2c,
|
||||
[BQ27XXX_REG_DCAP] = 0x3c,
|
||||
[BQ27XXX_REG_AP] = 0x24,
|
||||
BQ27XXX_DM_REG_ROWS,
|
||||
},
|
||||
[BQ27510G1] = {
|
||||
[BQ27XXX_REG_CTRL] = 0x00,
|
||||
[BQ27XXX_REG_TEMP] = 0x06,
|
||||
[BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR,
|
||||
[BQ27XXX_REG_VOLT] = 0x08,
|
||||
[BQ27XXX_REG_AI] = 0x14,
|
||||
[BQ27XXX_REG_FLAGS] = 0x0a,
|
||||
[BQ27XXX_REG_TTE] = 0x16,
|
||||
[BQ27XXX_REG_TTF] = 0x18,
|
||||
[BQ27XXX_REG_TTES] = 0x1c,
|
||||
[BQ27XXX_REG_TTECP] = 0x26,
|
||||
[BQ27XXX_REG_NAC] = 0x0c,
|
||||
[BQ27XXX_REG_FCC] = 0x12,
|
||||
[BQ27XXX_REG_CYCT] = 0x2a,
|
||||
[BQ27XXX_REG_AE] = 0x22,
|
||||
[BQ27XXX_REG_SOC] = 0x2c,
|
||||
[BQ27XXX_REG_DCAP] = 0x3c,
|
||||
[BQ27XXX_REG_AP] = 0x24,
|
||||
BQ27XXX_DM_REG_ROWS,
|
||||
},
|
||||
[BQ27510G2] = {
|
||||
[BQ27XXX_REG_CTRL] = 0x00,
|
||||
[BQ27XXX_REG_TEMP] = 0x06,
|
||||
[BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR,
|
||||
[BQ27XXX_REG_VOLT] = 0x08,
|
||||
[BQ27XXX_REG_AI] = 0x14,
|
||||
[BQ27XXX_REG_FLAGS] = 0x0a,
|
||||
[BQ27XXX_REG_TTE] = 0x16,
|
||||
[BQ27XXX_REG_TTF] = 0x18,
|
||||
[BQ27XXX_REG_TTES] = 0x1c,
|
||||
[BQ27XXX_REG_TTECP] = 0x26,
|
||||
[BQ27XXX_REG_NAC] = 0x0c,
|
||||
[BQ27XXX_REG_FCC] = 0x12,
|
||||
[BQ27XXX_REG_CYCT] = 0x2a,
|
||||
[BQ27XXX_REG_AE] = 0x22,
|
||||
[BQ27XXX_REG_SOC] = 0x2c,
|
||||
[BQ27XXX_REG_DCAP] = 0x3c,
|
||||
[BQ27XXX_REG_AP] = 0x24,
|
||||
BQ27XXX_DM_REG_ROWS,
|
||||
},
|
||||
[BQ27510G3] = {
|
||||
[BQ27XXX_REG_CTRL] = 0x00,
|
||||
[BQ27XXX_REG_TEMP] = 0x06,
|
||||
[BQ27XXX_REG_INT_TEMP] = 0x28,
|
||||
[BQ27XXX_REG_VOLT] = 0x08,
|
||||
[BQ27XXX_REG_AI] = 0x14,
|
||||
[BQ27XXX_REG_FLAGS] = 0x0a,
|
||||
[BQ27XXX_REG_TTE] = 0x16,
|
||||
[BQ27XXX_REG_TTF] = INVALID_REG_ADDR,
|
||||
[BQ27XXX_REG_TTES] = 0x1a,
|
||||
[BQ27XXX_REG_TTECP] = INVALID_REG_ADDR,
|
||||
[BQ27XXX_REG_NAC] = 0x0c,
|
||||
[BQ27XXX_REG_FCC] = 0x12,
|
||||
[BQ27XXX_REG_CYCT] = 0x1e,
|
||||
[BQ27XXX_REG_AE] = INVALID_REG_ADDR,
|
||||
[BQ27XXX_REG_SOC] = 0x20,
|
||||
[BQ27XXX_REG_DCAP] = 0x2e,
|
||||
[BQ27XXX_REG_AP] = INVALID_REG_ADDR,
|
||||
BQ27XXX_DM_REG_ROWS,
|
||||
},
|
||||
[BQ27520G1] = {
|
||||
bq27520g1_regs[BQ27XXX_REG_MAX] = {
|
||||
[BQ27XXX_REG_CTRL] = 0x00,
|
||||
[BQ27XXX_REG_TEMP] = 0x06,
|
||||
[BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR,
|
||||
|
@ -321,7 +263,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
|
|||
[BQ27XXX_REG_AP] = 0x24,
|
||||
BQ27XXX_DM_REG_ROWS,
|
||||
},
|
||||
[BQ27520G2] = {
|
||||
bq27520g2_regs[BQ27XXX_REG_MAX] = {
|
||||
[BQ27XXX_REG_CTRL] = 0x00,
|
||||
[BQ27XXX_REG_TEMP] = 0x06,
|
||||
[BQ27XXX_REG_INT_TEMP] = 0x36,
|
||||
|
@ -341,7 +283,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
|
|||
[BQ27XXX_REG_AP] = 0x24,
|
||||
BQ27XXX_DM_REG_ROWS,
|
||||
},
|
||||
[BQ27520G3] = {
|
||||
bq27520g3_regs[BQ27XXX_REG_MAX] = {
|
||||
[BQ27XXX_REG_CTRL] = 0x00,
|
||||
[BQ27XXX_REG_TEMP] = 0x06,
|
||||
[BQ27XXX_REG_INT_TEMP] = 0x36,
|
||||
|
@ -361,7 +303,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
|
|||
[BQ27XXX_REG_AP] = 0x24,
|
||||
BQ27XXX_DM_REG_ROWS,
|
||||
},
|
||||
[BQ27520G4] = {
|
||||
bq27520g4_regs[BQ27XXX_REG_MAX] = {
|
||||
[BQ27XXX_REG_CTRL] = 0x00,
|
||||
[BQ27XXX_REG_TEMP] = 0x06,
|
||||
[BQ27XXX_REG_INT_TEMP] = 0x28,
|
||||
|
@ -381,7 +323,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
|
|||
[BQ27XXX_REG_AP] = INVALID_REG_ADDR,
|
||||
BQ27XXX_DM_REG_ROWS,
|
||||
},
|
||||
[BQ27530] = {
|
||||
bq27530_regs[BQ27XXX_REG_MAX] = {
|
||||
[BQ27XXX_REG_CTRL] = 0x00,
|
||||
[BQ27XXX_REG_TEMP] = 0x06,
|
||||
[BQ27XXX_REG_INT_TEMP] = 0x32,
|
||||
|
@ -401,7 +343,8 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
|
|||
[BQ27XXX_REG_AP] = 0x24,
|
||||
BQ27XXX_DM_REG_ROWS,
|
||||
},
|
||||
[BQ27541] = {
|
||||
#define bq27531_regs bq27530_regs
|
||||
bq27541_regs[BQ27XXX_REG_MAX] = {
|
||||
[BQ27XXX_REG_CTRL] = 0x00,
|
||||
[BQ27XXX_REG_TEMP] = 0x06,
|
||||
[BQ27XXX_REG_INT_TEMP] = 0x28,
|
||||
|
@ -421,7 +364,10 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
|
|||
[BQ27XXX_REG_AP] = 0x24,
|
||||
BQ27XXX_DM_REG_ROWS,
|
||||
},
|
||||
[BQ27545] = {
|
||||
#define bq27542_regs bq27541_regs
|
||||
#define bq27546_regs bq27541_regs
|
||||
#define bq27742_regs bq27541_regs
|
||||
bq27545_regs[BQ27XXX_REG_MAX] = {
|
||||
[BQ27XXX_REG_CTRL] = 0x00,
|
||||
[BQ27XXX_REG_TEMP] = 0x06,
|
||||
[BQ27XXX_REG_INT_TEMP] = 0x28,
|
||||
|
@ -441,7 +387,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
|
|||
[BQ27XXX_REG_AP] = 0x24,
|
||||
BQ27XXX_DM_REG_ROWS,
|
||||
},
|
||||
[BQ27421] = {
|
||||
bq27421_regs[BQ27XXX_REG_MAX] = {
|
||||
[BQ27XXX_REG_CTRL] = 0x00,
|
||||
[BQ27XXX_REG_TEMP] = 0x02,
|
||||
[BQ27XXX_REG_INT_TEMP] = 0x1e,
|
||||
|
@ -460,10 +406,12 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = {
|
|||
[BQ27XXX_REG_DCAP] = 0x3c,
|
||||
[BQ27XXX_REG_AP] = 0x18,
|
||||
BQ27XXX_DM_REG_ROWS,
|
||||
},
|
||||
};
|
||||
};
|
||||
#define bq27425_regs bq27421_regs
|
||||
#define bq27441_regs bq27421_regs
|
||||
#define bq27621_regs bq27421_regs
|
||||
|
||||
static enum power_supply_property bq27000_battery_props[] = {
|
||||
static enum power_supply_property bq27000_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
|
@ -485,7 +433,7 @@ static enum power_supply_property bq27000_battery_props[] = {
|
|||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
|
||||
static enum power_supply_property bq27010_battery_props[] = {
|
||||
static enum power_supply_property bq27010_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
|
@ -505,43 +453,11 @@ static enum power_supply_property bq27010_battery_props[] = {
|
|||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
|
||||
static enum power_supply_property bq2750x_battery_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
POWER_SUPPLY_PROP_CAPACITY,
|
||||
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
|
||||
POWER_SUPPLY_PROP_TEMP,
|
||||
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
|
||||
POWER_SUPPLY_PROP_TECHNOLOGY,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL,
|
||||
POWER_SUPPLY_PROP_CHARGE_NOW,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
|
||||
POWER_SUPPLY_PROP_CYCLE_COUNT,
|
||||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
#define bq2750x_props bq27510g3_props
|
||||
#define bq2751x_props bq27510g3_props
|
||||
#define bq2752x_props bq27510g3_props
|
||||
|
||||
static enum power_supply_property bq2751x_battery_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
POWER_SUPPLY_PROP_CAPACITY,
|
||||
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
|
||||
POWER_SUPPLY_PROP_TEMP,
|
||||
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
|
||||
POWER_SUPPLY_PROP_TECHNOLOGY,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL,
|
||||
POWER_SUPPLY_PROP_CHARGE_NOW,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
|
||||
POWER_SUPPLY_PROP_CYCLE_COUNT,
|
||||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
|
||||
static enum power_supply_property bq27500_battery_props[] = {
|
||||
static enum power_supply_property bq27500_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
|
@ -561,50 +477,10 @@ static enum power_supply_property bq27500_battery_props[] = {
|
|||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
#define bq27510g1_props bq27500_props
|
||||
#define bq27510g2_props bq27500_props
|
||||
|
||||
static enum power_supply_property bq27510g1_battery_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
POWER_SUPPLY_PROP_CAPACITY,
|
||||
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
|
||||
POWER_SUPPLY_PROP_TEMP,
|
||||
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
|
||||
POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
|
||||
POWER_SUPPLY_PROP_TECHNOLOGY,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL,
|
||||
POWER_SUPPLY_PROP_CHARGE_NOW,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
|
||||
POWER_SUPPLY_PROP_CYCLE_COUNT,
|
||||
POWER_SUPPLY_PROP_ENERGY_NOW,
|
||||
POWER_SUPPLY_PROP_POWER_AVG,
|
||||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
|
||||
static enum power_supply_property bq27510g2_battery_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
POWER_SUPPLY_PROP_CAPACITY,
|
||||
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
|
||||
POWER_SUPPLY_PROP_TEMP,
|
||||
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
|
||||
POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
|
||||
POWER_SUPPLY_PROP_TECHNOLOGY,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL,
|
||||
POWER_SUPPLY_PROP_CHARGE_NOW,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
|
||||
POWER_SUPPLY_PROP_CYCLE_COUNT,
|
||||
POWER_SUPPLY_PROP_ENERGY_NOW,
|
||||
POWER_SUPPLY_PROP_POWER_AVG,
|
||||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
|
||||
static enum power_supply_property bq27510g3_battery_props[] = {
|
||||
static enum power_supply_property bq27510g3_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
|
@ -622,7 +498,7 @@ static enum power_supply_property bq27510g3_battery_props[] = {
|
|||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
|
||||
static enum power_supply_property bq27520g1_battery_props[] = {
|
||||
static enum power_supply_property bq27520g1_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
|
@ -642,28 +518,9 @@ static enum power_supply_property bq27520g1_battery_props[] = {
|
|||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
|
||||
static enum power_supply_property bq27520g2_battery_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
POWER_SUPPLY_PROP_CAPACITY,
|
||||
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
|
||||
POWER_SUPPLY_PROP_TEMP,
|
||||
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
|
||||
POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
|
||||
POWER_SUPPLY_PROP_TECHNOLOGY,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL,
|
||||
POWER_SUPPLY_PROP_CHARGE_NOW,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
|
||||
POWER_SUPPLY_PROP_CYCLE_COUNT,
|
||||
POWER_SUPPLY_PROP_ENERGY_NOW,
|
||||
POWER_SUPPLY_PROP_POWER_AVG,
|
||||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
#define bq27520g2_props bq27500_props
|
||||
|
||||
static enum power_supply_property bq27520g3_battery_props[] = {
|
||||
static enum power_supply_property bq27520g3_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
|
@ -683,7 +540,7 @@ static enum power_supply_property bq27520g3_battery_props[] = {
|
|||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
|
||||
static enum power_supply_property bq27520g4_battery_props[] = {
|
||||
static enum power_supply_property bq27520g4_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
|
@ -700,7 +557,7 @@ static enum power_supply_property bq27520g4_battery_props[] = {
|
|||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
|
||||
static enum power_supply_property bq27530_battery_props[] = {
|
||||
static enum power_supply_property bq27530_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
|
@ -717,8 +574,9 @@ static enum power_supply_property bq27530_battery_props[] = {
|
|||
POWER_SUPPLY_PROP_CYCLE_COUNT,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
#define bq27531_props bq27530_props
|
||||
|
||||
static enum power_supply_property bq27541_battery_props[] = {
|
||||
static enum power_supply_property bq27541_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
|
@ -736,8 +594,11 @@ static enum power_supply_property bq27541_battery_props[] = {
|
|||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
#define bq27542_props bq27541_props
|
||||
#define bq27546_props bq27541_props
|
||||
#define bq27742_props bq27541_props
|
||||
|
||||
static enum power_supply_property bq27545_battery_props[] = {
|
||||
static enum power_supply_property bq27545_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
|
@ -755,7 +616,7 @@ static enum power_supply_property bq27545_battery_props[] = {
|
|||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
|
||||
static enum power_supply_property bq27421_battery_props[] = {
|
||||
static enum power_supply_property bq27421_props[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
|
@ -769,33 +630,138 @@ static enum power_supply_property bq27421_battery_props[] = {
|
|||
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
#define bq27425_props bq27421_props
|
||||
#define bq27441_props bq27421_props
|
||||
#define bq27621_props bq27421_props
|
||||
|
||||
#define BQ27XXX_PROP(_id, _prop) \
|
||||
[_id] = { \
|
||||
.props = _prop, \
|
||||
.size = ARRAY_SIZE(_prop), \
|
||||
}
|
||||
struct bq27xxx_dm_reg {
|
||||
u8 subclass_id;
|
||||
u8 offset;
|
||||
u8 bytes;
|
||||
u16 min, max;
|
||||
};
|
||||
|
||||
enum bq27xxx_dm_reg_id {
|
||||
BQ27XXX_DM_DESIGN_CAPACITY = 0,
|
||||
BQ27XXX_DM_DESIGN_ENERGY,
|
||||
BQ27XXX_DM_TERMINATE_VOLTAGE,
|
||||
};
|
||||
|
||||
#define bq27000_dm_regs 0
|
||||
#define bq27010_dm_regs 0
|
||||
#define bq2750x_dm_regs 0
|
||||
#define bq2751x_dm_regs 0
|
||||
#define bq2752x_dm_regs 0
|
||||
|
||||
#if 0 /* not yet tested */
|
||||
static struct bq27xxx_dm_reg bq27500_dm_regs[] = {
|
||||
[BQ27XXX_DM_DESIGN_CAPACITY] = { 48, 10, 2, 0, 65535 },
|
||||
[BQ27XXX_DM_DESIGN_ENERGY] = { }, /* missing on chip */
|
||||
[BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 48, 2, 1000, 32767 },
|
||||
};
|
||||
#else
|
||||
#define bq27500_dm_regs 0
|
||||
#endif
|
||||
|
||||
/* todo create data memory definitions from datasheets and test on chips */
|
||||
#define bq27510g1_dm_regs 0
|
||||
#define bq27510g2_dm_regs 0
|
||||
#define bq27510g3_dm_regs 0
|
||||
#define bq27520g1_dm_regs 0
|
||||
#define bq27520g2_dm_regs 0
|
||||
#define bq27520g3_dm_regs 0
|
||||
#define bq27520g4_dm_regs 0
|
||||
#define bq27530_dm_regs 0
|
||||
#define bq27531_dm_regs 0
|
||||
#define bq27541_dm_regs 0
|
||||
#define bq27542_dm_regs 0
|
||||
#define bq27546_dm_regs 0
|
||||
#define bq27742_dm_regs 0
|
||||
|
||||
#if 0 /* not yet tested */
|
||||
static struct bq27xxx_dm_reg bq27545_dm_regs[] = {
|
||||
[BQ27XXX_DM_DESIGN_CAPACITY] = { 48, 23, 2, 0, 32767 },
|
||||
[BQ27XXX_DM_DESIGN_ENERGY] = { 48, 25, 2, 0, 32767 },
|
||||
[BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 67, 2, 2800, 3700 },
|
||||
};
|
||||
#else
|
||||
#define bq27545_dm_regs 0
|
||||
#endif
|
||||
|
||||
static struct bq27xxx_dm_reg bq27421_dm_regs[] = {
|
||||
[BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 10, 2, 0, 8000 },
|
||||
[BQ27XXX_DM_DESIGN_ENERGY] = { 82, 12, 2, 0, 32767 },
|
||||
[BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 16, 2, 2500, 3700 },
|
||||
};
|
||||
|
||||
static struct bq27xxx_dm_reg bq27425_dm_regs[] = {
|
||||
[BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 12, 2, 0, 32767 },
|
||||
[BQ27XXX_DM_DESIGN_ENERGY] = { 82, 14, 2, 0, 32767 },
|
||||
[BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 18, 2, 2800, 3700 },
|
||||
};
|
||||
|
||||
#if 0 /* not yet tested */
|
||||
#define bq27441_dm_regs bq27421_dm_regs
|
||||
#else
|
||||
#define bq27441_dm_regs 0
|
||||
#endif
|
||||
|
||||
#if 0 /* not yet tested */
|
||||
static struct bq27xxx_dm_reg bq27621_dm_regs[] = {
|
||||
[BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 3, 2, 0, 8000 },
|
||||
[BQ27XXX_DM_DESIGN_ENERGY] = { 82, 5, 2, 0, 32767 },
|
||||
[BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 9, 2, 2500, 3700 },
|
||||
};
|
||||
#else
|
||||
#define bq27621_dm_regs 0
|
||||
#endif
|
||||
|
||||
#define BQ27XXX_O_ZERO 0x00000001
|
||||
#define BQ27XXX_O_OTDC 0x00000002
|
||||
#define BQ27XXX_O_UTOT 0x00000004
|
||||
#define BQ27XXX_O_CFGUP 0x00000008
|
||||
#define BQ27XXX_O_RAM 0x00000010
|
||||
|
||||
#define BQ27XXX_DATA(ref, key, opt) { \
|
||||
.opts = (opt), \
|
||||
.unseal_key = key, \
|
||||
.regs = ref##_regs, \
|
||||
.dm_regs = ref##_dm_regs, \
|
||||
.props = ref##_props, \
|
||||
.props_size = ARRAY_SIZE(ref##_props) }
|
||||
|
||||
static struct {
|
||||
u32 opts;
|
||||
u32 unseal_key;
|
||||
u8 *regs;
|
||||
struct bq27xxx_dm_reg *dm_regs;
|
||||
enum power_supply_property *props;
|
||||
size_t size;
|
||||
} bq27xxx_battery_props[] = {
|
||||
BQ27XXX_PROP(BQ27000, bq27000_battery_props),
|
||||
BQ27XXX_PROP(BQ27010, bq27010_battery_props),
|
||||
BQ27XXX_PROP(BQ2750X, bq2750x_battery_props),
|
||||
BQ27XXX_PROP(BQ2751X, bq2751x_battery_props),
|
||||
BQ27XXX_PROP(BQ27500, bq27500_battery_props),
|
||||
BQ27XXX_PROP(BQ27510G1, bq27510g1_battery_props),
|
||||
BQ27XXX_PROP(BQ27510G2, bq27510g2_battery_props),
|
||||
BQ27XXX_PROP(BQ27510G3, bq27510g3_battery_props),
|
||||
BQ27XXX_PROP(BQ27520G1, bq27520g1_battery_props),
|
||||
BQ27XXX_PROP(BQ27520G2, bq27520g2_battery_props),
|
||||
BQ27XXX_PROP(BQ27520G3, bq27520g3_battery_props),
|
||||
BQ27XXX_PROP(BQ27520G4, bq27520g4_battery_props),
|
||||
BQ27XXX_PROP(BQ27530, bq27530_battery_props),
|
||||
BQ27XXX_PROP(BQ27541, bq27541_battery_props),
|
||||
BQ27XXX_PROP(BQ27545, bq27545_battery_props),
|
||||
BQ27XXX_PROP(BQ27421, bq27421_battery_props),
|
||||
size_t props_size;
|
||||
} bq27xxx_chip_data[] = {
|
||||
[BQ27000] = BQ27XXX_DATA(bq27000, 0 , BQ27XXX_O_ZERO),
|
||||
[BQ27010] = BQ27XXX_DATA(bq27010, 0 , BQ27XXX_O_ZERO),
|
||||
[BQ2750X] = BQ27XXX_DATA(bq2750x, 0 , BQ27XXX_O_OTDC),
|
||||
[BQ2751X] = BQ27XXX_DATA(bq2751x, 0 , BQ27XXX_O_OTDC),
|
||||
[BQ2752X] = BQ27XXX_DATA(bq2752x, 0 , BQ27XXX_O_OTDC),
|
||||
[BQ27500] = BQ27XXX_DATA(bq27500, 0x04143672, BQ27XXX_O_OTDC),
|
||||
[BQ27510G1] = BQ27XXX_DATA(bq27510g1, 0 , BQ27XXX_O_OTDC),
|
||||
[BQ27510G2] = BQ27XXX_DATA(bq27510g2, 0 , BQ27XXX_O_OTDC),
|
||||
[BQ27510G3] = BQ27XXX_DATA(bq27510g3, 0 , BQ27XXX_O_OTDC),
|
||||
[BQ27520G1] = BQ27XXX_DATA(bq27520g1, 0 , BQ27XXX_O_OTDC),
|
||||
[BQ27520G2] = BQ27XXX_DATA(bq27520g2, 0 , BQ27XXX_O_OTDC),
|
||||
[BQ27520G3] = BQ27XXX_DATA(bq27520g3, 0 , BQ27XXX_O_OTDC),
|
||||
[BQ27520G4] = BQ27XXX_DATA(bq27520g4, 0 , BQ27XXX_O_OTDC),
|
||||
[BQ27530] = BQ27XXX_DATA(bq27530, 0 , BQ27XXX_O_UTOT),
|
||||
[BQ27531] = BQ27XXX_DATA(bq27531, 0 , BQ27XXX_O_UTOT),
|
||||
[BQ27541] = BQ27XXX_DATA(bq27541, 0 , BQ27XXX_O_OTDC),
|
||||
[BQ27542] = BQ27XXX_DATA(bq27542, 0 , BQ27XXX_O_OTDC),
|
||||
[BQ27546] = BQ27XXX_DATA(bq27546, 0 , BQ27XXX_O_OTDC),
|
||||
[BQ27742] = BQ27XXX_DATA(bq27742, 0 , BQ27XXX_O_OTDC),
|
||||
[BQ27545] = BQ27XXX_DATA(bq27545, 0x04143672, BQ27XXX_O_OTDC),
|
||||
[BQ27421] = BQ27XXX_DATA(bq27421, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM),
|
||||
[BQ27425] = BQ27XXX_DATA(bq27425, 0x04143672, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP),
|
||||
[BQ27441] = BQ27XXX_DATA(bq27441, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM),
|
||||
[BQ27621] = BQ27XXX_DATA(bq27621, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM),
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(bq27xxx_list_lock);
|
||||
|
@ -805,13 +771,6 @@ static LIST_HEAD(bq27xxx_battery_devices);
|
|||
|
||||
#define BQ27XXX_DM_SZ 32
|
||||
|
||||
struct bq27xxx_dm_reg {
|
||||
u8 subclass_id;
|
||||
u8 offset;
|
||||
u8 bytes;
|
||||
u16 min, max;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct bq27xxx_dm_buf - chip data memory buffer
|
||||
* @class: data memory subclass_id
|
||||
|
@ -844,12 +803,6 @@ static inline u16 *bq27xxx_dm_reg_ptr(struct bq27xxx_dm_buf *buf,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
enum bq27xxx_dm_reg_id {
|
||||
BQ27XXX_DM_DESIGN_CAPACITY = 0,
|
||||
BQ27XXX_DM_DESIGN_ENERGY,
|
||||
BQ27XXX_DM_TERMINATE_VOLTAGE,
|
||||
};
|
||||
|
||||
static const char * const bq27xxx_dm_reg_name[] = {
|
||||
[BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity",
|
||||
[BQ27XXX_DM_DESIGN_ENERGY] = "design-energy",
|
||||
|
@ -1092,9 +1045,9 @@ static void bq27xxx_battery_update_dm_block(struct bq27xxx_device_info *di,
|
|||
}
|
||||
|
||||
#ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM
|
||||
if (!di->ram_chip && !bq27xxx_dt_to_nvm) {
|
||||
if (!(di->opts & BQ27XXX_O_RAM) && !bq27xxx_dt_to_nvm) {
|
||||
#else
|
||||
if (!di->ram_chip) {
|
||||
if (!(di->opts & BQ27XXX_O_RAM)) {
|
||||
#endif
|
||||
/* devicetree and NVM differ; defer to NVM */
|
||||
dev_warn(di->dev, "%s has %u; update to %u disallowed "
|
||||
|
@ -1130,7 +1083,7 @@ static int bq27xxx_battery_cfgupdate_priv(struct bq27xxx_device_info *di, bool a
|
|||
return ret;
|
||||
} while (!!(ret & BQ27XXX_FLAG_CFGUP) != active && --try);
|
||||
|
||||
if (!try) {
|
||||
if (!try && di->chip != BQ27425) { // 425 has a bug
|
||||
dev_err(di->dev, "timed out waiting for cfgupdate flag %d\n", active);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -1162,7 +1115,7 @@ static inline int bq27xxx_battery_soft_reset(struct bq27xxx_device_info *di)
|
|||
static int bq27xxx_battery_write_dm_block(struct bq27xxx_device_info *di,
|
||||
struct bq27xxx_dm_buf *buf)
|
||||
{
|
||||
bool cfgup = di->chip == BQ27421; /* assume related chips need cfgupdate */
|
||||
bool cfgup = di->opts & BQ27XXX_O_CFGUP;
|
||||
int ret;
|
||||
|
||||
if (!buf->dirty)
|
||||
|
@ -1261,7 +1214,7 @@ static void bq27xxx_battery_set_config(struct bq27xxx_device_info *di,
|
|||
|
||||
bq27xxx_battery_seal(di);
|
||||
|
||||
if (updated && di->chip != BQ27421) { /* not a cfgupdate chip, so reset */
|
||||
if (updated && !(di->opts & BQ27XXX_O_CFGUP)) {
|
||||
bq27xxx_write(di, BQ27XXX_REG_CTRL, BQ27XXX_RESET, false);
|
||||
BQ27XXX_MSLEEP(300); /* reset time is not documented */
|
||||
}
|
||||
|
@ -1328,7 +1281,7 @@ static int bq27xxx_battery_read_soc(struct bq27xxx_device_info *di)
|
|||
{
|
||||
int soc;
|
||||
|
||||
if (di->chip == BQ27000 || di->chip == BQ27010)
|
||||
if (di->opts & BQ27XXX_O_ZERO)
|
||||
soc = bq27xxx_read(di, BQ27XXX_REG_SOC, true);
|
||||
else
|
||||
soc = bq27xxx_read(di, BQ27XXX_REG_SOC, false);
|
||||
|
@ -1354,7 +1307,7 @@ static int bq27xxx_battery_read_charge(struct bq27xxx_device_info *di, u8 reg)
|
|||
return charge;
|
||||
}
|
||||
|
||||
if (di->chip == BQ27000 || di->chip == BQ27010)
|
||||
if (di->opts & BQ27XXX_O_ZERO)
|
||||
charge *= BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS;
|
||||
else
|
||||
charge *= 1000;
|
||||
|
@ -1370,7 +1323,7 @@ static inline int bq27xxx_battery_read_nac(struct bq27xxx_device_info *di)
|
|||
{
|
||||
int flags;
|
||||
|
||||
if (di->chip == BQ27000 || di->chip == BQ27010) {
|
||||
if (di->opts & BQ27XXX_O_ZERO) {
|
||||
flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, true);
|
||||
if (flags >= 0 && (flags & BQ27000_FLAG_CI))
|
||||
return -ENODATA;
|
||||
|
@ -1396,7 +1349,7 @@ static int bq27xxx_battery_read_dcap(struct bq27xxx_device_info *di)
|
|||
{
|
||||
int dcap;
|
||||
|
||||
if (di->chip == BQ27000 || di->chip == BQ27010)
|
||||
if (di->opts & BQ27XXX_O_ZERO)
|
||||
dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, true);
|
||||
else
|
||||
dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, false);
|
||||
|
@ -1406,7 +1359,7 @@ static int bq27xxx_battery_read_dcap(struct bq27xxx_device_info *di)
|
|||
return dcap;
|
||||
}
|
||||
|
||||
if (di->chip == BQ27000 || di->chip == BQ27010)
|
||||
if (di->opts & BQ27XXX_O_ZERO)
|
||||
dcap = (dcap << 8) * BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS;
|
||||
else
|
||||
dcap *= 1000;
|
||||
|
@ -1428,7 +1381,7 @@ static int bq27xxx_battery_read_energy(struct bq27xxx_device_info *di)
|
|||
return ae;
|
||||
}
|
||||
|
||||
if (di->chip == BQ27000 || di->chip == BQ27010)
|
||||
if (di->opts & BQ27XXX_O_ZERO)
|
||||
ae *= BQ27XXX_POWER_CONSTANT / BQ27XXX_RS;
|
||||
else
|
||||
ae *= 1000;
|
||||
|
@ -1450,7 +1403,7 @@ static int bq27xxx_battery_read_temperature(struct bq27xxx_device_info *di)
|
|||
return temp;
|
||||
}
|
||||
|
||||
if (di->chip == BQ27000 || di->chip == BQ27010)
|
||||
if (di->opts & BQ27XXX_O_ZERO)
|
||||
temp = 5 * temp / 2;
|
||||
|
||||
return temp;
|
||||
|
@ -1507,7 +1460,7 @@ static int bq27xxx_battery_read_pwr_avg(struct bq27xxx_device_info *di)
|
|||
return tval;
|
||||
}
|
||||
|
||||
if (di->chip == BQ27000 || di->chip == BQ27010)
|
||||
if (di->opts & BQ27XXX_O_ZERO)
|
||||
return (tval * BQ27XXX_POWER_CONSTANT) / BQ27XXX_RS;
|
||||
else
|
||||
return tval;
|
||||
|
@ -1518,26 +1471,12 @@ static int bq27xxx_battery_read_pwr_avg(struct bq27xxx_device_info *di)
|
|||
*/
|
||||
static bool bq27xxx_battery_overtemp(struct bq27xxx_device_info *di, u16 flags)
|
||||
{
|
||||
switch (di->chip) {
|
||||
case BQ2750X:
|
||||
case BQ2751X:
|
||||
case BQ27500:
|
||||
case BQ27510G1:
|
||||
case BQ27510G2:
|
||||
case BQ27510G3:
|
||||
case BQ27520G1:
|
||||
case BQ27520G2:
|
||||
case BQ27520G3:
|
||||
case BQ27520G4:
|
||||
case BQ27541:
|
||||
case BQ27545:
|
||||
if (di->opts & BQ27XXX_O_OTDC)
|
||||
return flags & (BQ27XXX_FLAG_OTC | BQ27XXX_FLAG_OTD);
|
||||
case BQ27530:
|
||||
case BQ27421:
|
||||
if (di->opts & BQ27XXX_O_UTOT)
|
||||
return flags & BQ27XXX_FLAG_OT;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1545,7 +1484,7 @@ static bool bq27xxx_battery_overtemp(struct bq27xxx_device_info *di, u16 flags)
|
|||
*/
|
||||
static bool bq27xxx_battery_undertemp(struct bq27xxx_device_info *di, u16 flags)
|
||||
{
|
||||
if (di->chip == BQ27530 || di->chip == BQ27421)
|
||||
if (di->opts & BQ27XXX_O_UTOT)
|
||||
return flags & BQ27XXX_FLAG_UT;
|
||||
|
||||
return false;
|
||||
|
@ -1556,7 +1495,7 @@ static bool bq27xxx_battery_undertemp(struct bq27xxx_device_info *di, u16 flags)
|
|||
*/
|
||||
static bool bq27xxx_battery_dead(struct bq27xxx_device_info *di, u16 flags)
|
||||
{
|
||||
if (di->chip == BQ27000 || di->chip == BQ27010)
|
||||
if (di->opts & BQ27XXX_O_ZERO)
|
||||
return flags & (BQ27000_FLAG_EDV1 | BQ27000_FLAG_EDVF);
|
||||
else
|
||||
return flags & (BQ27XXX_FLAG_SOC1 | BQ27XXX_FLAG_SOCF);
|
||||
|
@ -1569,7 +1508,7 @@ static bool bq27xxx_battery_dead(struct bq27xxx_device_info *di, u16 flags)
|
|||
static int bq27xxx_battery_read_health(struct bq27xxx_device_info *di)
|
||||
{
|
||||
int flags;
|
||||
bool has_singe_flag = di->chip == BQ27000 || di->chip == BQ27010;
|
||||
bool has_singe_flag = di->opts & BQ27XXX_O_ZERO;
|
||||
|
||||
flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, has_singe_flag);
|
||||
if (flags < 0) {
|
||||
|
@ -1591,8 +1530,8 @@ static int bq27xxx_battery_read_health(struct bq27xxx_device_info *di)
|
|||
void bq27xxx_battery_update(struct bq27xxx_device_info *di)
|
||||
{
|
||||
struct bq27xxx_reg_cache cache = {0, };
|
||||
bool has_ci_flag = di->chip == BQ27000 || di->chip == BQ27010;
|
||||
bool has_singe_flag = di->chip == BQ27000 || di->chip == BQ27010;
|
||||
bool has_ci_flag = di->opts & BQ27XXX_O_ZERO;
|
||||
bool has_singe_flag = di->opts & BQ27XXX_O_ZERO;
|
||||
|
||||
cache.flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, has_singe_flag);
|
||||
if ((cache.flags & 0xff) == 0xff)
|
||||
|
@ -1670,7 +1609,7 @@ static int bq27xxx_battery_current(struct bq27xxx_device_info *di,
|
|||
return curr;
|
||||
}
|
||||
|
||||
if (di->chip == BQ27000 || di->chip == BQ27010) {
|
||||
if (di->opts & BQ27XXX_O_ZERO) {
|
||||
flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, true);
|
||||
if (flags & BQ27000_FLAG_CHGS) {
|
||||
dev_dbg(di->dev, "negative current!\n");
|
||||
|
@ -1691,7 +1630,7 @@ static int bq27xxx_battery_status(struct bq27xxx_device_info *di,
|
|||
{
|
||||
int status;
|
||||
|
||||
if (di->chip == BQ27000 || di->chip == BQ27010) {
|
||||
if (di->opts & BQ27XXX_O_ZERO) {
|
||||
if (di->cache.flags & BQ27000_FLAG_FC)
|
||||
status = POWER_SUPPLY_STATUS_FULL;
|
||||
else if (di->cache.flags & BQ27000_FLAG_CHGS)
|
||||
|
@ -1719,7 +1658,7 @@ static int bq27xxx_battery_capacity_level(struct bq27xxx_device_info *di,
|
|||
{
|
||||
int level;
|
||||
|
||||
if (di->chip == BQ27000 || di->chip == BQ27010) {
|
||||
if (di->opts & BQ27XXX_O_ZERO) {
|
||||
if (di->cache.flags & BQ27000_FLAG_FC)
|
||||
level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
|
||||
else if (di->cache.flags & BQ27000_FLAG_EDV1)
|
||||
|
@ -1884,7 +1823,11 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
|
|||
|
||||
INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll);
|
||||
mutex_init(&di->lock);
|
||||
di->regs = bq27xxx_regs[di->chip];
|
||||
|
||||
di->regs = bq27xxx_chip_data[di->chip].regs;
|
||||
di->unseal_key = bq27xxx_chip_data[di->chip].unseal_key;
|
||||
di->dm_regs = bq27xxx_chip_data[di->chip].dm_regs;
|
||||
di->opts = bq27xxx_chip_data[di->chip].opts;
|
||||
|
||||
psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL);
|
||||
if (!psy_desc)
|
||||
|
@ -1892,8 +1835,8 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
|
|||
|
||||
psy_desc->name = di->name;
|
||||
psy_desc->type = POWER_SUPPLY_TYPE_BATTERY;
|
||||
psy_desc->properties = bq27xxx_battery_props[di->chip].props;
|
||||
psy_desc->num_properties = bq27xxx_battery_props[di->chip].size;
|
||||
psy_desc->properties = bq27xxx_chip_data[di->chip].props;
|
||||
psy_desc->num_properties = bq27xxx_chip_data[di->chip].props_size;
|
||||
psy_desc->get_property = bq27xxx_battery_get_property;
|
||||
psy_desc->external_power_changed = bq27xxx_external_power_changed;
|
||||
|
||||
|
@ -1903,8 +1846,6 @@ int bq27xxx_battery_setup(struct bq27xxx_device_info *di)
|
|||
return PTR_ERR(di->bat);
|
||||
}
|
||||
|
||||
dev_info(di->dev, "support ver. %s enabled\n", DRIVER_VERSION);
|
||||
|
||||
bq27xxx_battery_settings(di);
|
||||
bq27xxx_battery_update(di);
|
||||
|
||||
|
@ -1938,110 +1879,6 @@ void bq27xxx_battery_teardown(struct bq27xxx_device_info *di)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(bq27xxx_battery_teardown);
|
||||
|
||||
static int bq27xxx_battery_platform_read(struct bq27xxx_device_info *di, u8 reg,
|
||||
bool single)
|
||||
{
|
||||
struct device *dev = di->dev;
|
||||
struct bq27xxx_platform_data *pdata = dev->platform_data;
|
||||
unsigned int timeout = 3;
|
||||
int upper, lower;
|
||||
int temp;
|
||||
|
||||
if (!single) {
|
||||
/* Make sure the value has not changed in between reading the
|
||||
* lower and the upper part */
|
||||
upper = pdata->read(dev, reg + 1);
|
||||
do {
|
||||
temp = upper;
|
||||
if (upper < 0)
|
||||
return upper;
|
||||
|
||||
lower = pdata->read(dev, reg);
|
||||
if (lower < 0)
|
||||
return lower;
|
||||
|
||||
upper = pdata->read(dev, reg + 1);
|
||||
} while (temp != upper && --timeout);
|
||||
|
||||
if (timeout == 0)
|
||||
return -EIO;
|
||||
|
||||
return (upper << 8) | lower;
|
||||
}
|
||||
|
||||
return pdata->read(dev, reg);
|
||||
}
|
||||
|
||||
static int bq27xxx_battery_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bq27xxx_device_info *di;
|
||||
struct bq27xxx_platform_data *pdata = pdev->dev.platform_data;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "no platform_data supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pdata->read) {
|
||||
dev_err(&pdev->dev, "no hdq read callback supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pdata->chip) {
|
||||
dev_err(&pdev->dev, "no device supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
di = devm_kzalloc(&pdev->dev, sizeof(*di), GFP_KERNEL);
|
||||
if (!di)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, di);
|
||||
|
||||
di->dev = &pdev->dev;
|
||||
di->chip = pdata->chip;
|
||||
di->name = pdata->name ?: dev_name(&pdev->dev);
|
||||
di->bus.read = bq27xxx_battery_platform_read;
|
||||
|
||||
return bq27xxx_battery_setup(di);
|
||||
}
|
||||
|
||||
static int bq27xxx_battery_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct bq27xxx_device_info *di = platform_get_drvdata(pdev);
|
||||
|
||||
bq27xxx_battery_teardown(di);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct platform_device_id bq27xxx_battery_platform_id_table[] = {
|
||||
{ "bq27000-battery", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, bq27xxx_battery_platform_id_table);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id bq27xxx_battery_platform_of_match_table[] = {
|
||||
{ .compatible = "ti,bq27000" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bq27xxx_battery_platform_of_match_table);
|
||||
#endif
|
||||
|
||||
static struct platform_driver bq27xxx_battery_platform_driver = {
|
||||
.probe = bq27xxx_battery_platform_probe,
|
||||
.remove = bq27xxx_battery_platform_remove,
|
||||
.driver = {
|
||||
.name = "bq27000-battery",
|
||||
.of_match_table = of_match_ptr(bq27xxx_battery_platform_of_match_table),
|
||||
},
|
||||
.id_table = bq27xxx_battery_platform_id_table,
|
||||
};
|
||||
module_platform_driver(bq27xxx_battery_platform_driver);
|
||||
|
||||
MODULE_ALIAS("platform:bq27000-battery");
|
||||
|
||||
MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
|
||||
MODULE_DESCRIPTION("BQ27xxx battery monitor driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* BQ27xxx battery monitor HDQ/1-wire driver
|
||||
*
|
||||
* Copyright (C) 2007-2017 Texas Instruments Incorporated - http://www.ti.com/
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/power/bq27xxx_battery.h>
|
||||
|
||||
#include <linux/w1.h>
|
||||
|
||||
#define W1_FAMILY_BQ27000 0x01
|
||||
|
||||
#define HDQ_CMD_READ (0 << 7)
|
||||
#define HDQ_CMD_WRITE (1 << 7)
|
||||
|
||||
static int F_ID;
|
||||
module_param(F_ID, int, S_IRUSR);
|
||||
MODULE_PARM_DESC(F_ID, "1-wire slave FID for BQ27xxx device");
|
||||
|
||||
static int w1_bq27000_read(struct w1_slave *sl, unsigned int reg)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
mutex_lock(&sl->master->bus_mutex);
|
||||
w1_write_8(sl->master, HDQ_CMD_READ | reg);
|
||||
val = w1_read_8(sl->master);
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int bq27xxx_battery_hdq_read(struct bq27xxx_device_info *di, u8 reg,
|
||||
bool single)
|
||||
{
|
||||
struct w1_slave *sl = dev_to_w1_slave(di->dev);
|
||||
unsigned int timeout = 3;
|
||||
int upper, lower;
|
||||
int temp;
|
||||
|
||||
if (!single) {
|
||||
/*
|
||||
* Make sure the value has not changed in between reading the
|
||||
* lower and the upper part
|
||||
*/
|
||||
upper = w1_bq27000_read(sl, reg + 1);
|
||||
do {
|
||||
temp = upper;
|
||||
if (upper < 0)
|
||||
return upper;
|
||||
|
||||
lower = w1_bq27000_read(sl, reg);
|
||||
if (lower < 0)
|
||||
return lower;
|
||||
|
||||
upper = w1_bq27000_read(sl, reg + 1);
|
||||
} while (temp != upper && --timeout);
|
||||
|
||||
if (timeout == 0)
|
||||
return -EIO;
|
||||
|
||||
return (upper << 8) | lower;
|
||||
}
|
||||
|
||||
return w1_bq27000_read(sl, reg);
|
||||
}
|
||||
|
||||
static int bq27xxx_battery_hdq_add_slave(struct w1_slave *sl)
|
||||
{
|
||||
struct bq27xxx_device_info *di;
|
||||
|
||||
di = devm_kzalloc(&sl->dev, sizeof(*di), GFP_KERNEL);
|
||||
if (!di)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(&sl->dev, di);
|
||||
|
||||
di->dev = &sl->dev;
|
||||
di->chip = BQ27000;
|
||||
di->name = "bq27000-battery";
|
||||
di->bus.read = bq27xxx_battery_hdq_read;
|
||||
|
||||
return bq27xxx_battery_setup(di);
|
||||
}
|
||||
|
||||
static void bq27xxx_battery_hdq_remove_slave(struct w1_slave *sl)
|
||||
{
|
||||
struct bq27xxx_device_info *di = dev_get_drvdata(&sl->dev);
|
||||
|
||||
bq27xxx_battery_teardown(di);
|
||||
}
|
||||
|
||||
static struct w1_family_ops bq27xxx_battery_hdq_fops = {
|
||||
.add_slave = bq27xxx_battery_hdq_add_slave,
|
||||
.remove_slave = bq27xxx_battery_hdq_remove_slave,
|
||||
};
|
||||
|
||||
static struct w1_family bq27xxx_battery_hdq_family = {
|
||||
.fid = W1_FAMILY_BQ27000,
|
||||
.fops = &bq27xxx_battery_hdq_fops,
|
||||
};
|
||||
|
||||
static int __init bq27xxx_battery_hdq_init(void)
|
||||
{
|
||||
if (F_ID)
|
||||
bq27xxx_battery_hdq_family.fid = F_ID;
|
||||
|
||||
return w1_register_family(&bq27xxx_battery_hdq_family);
|
||||
}
|
||||
module_init(bq27xxx_battery_hdq_init);
|
||||
|
||||
static void __exit bq27xxx_battery_hdq_exit(void)
|
||||
{
|
||||
w1_unregister_family(&bq27xxx_battery_hdq_family);
|
||||
}
|
||||
module_exit(bq27xxx_battery_hdq_exit);
|
||||
|
||||
MODULE_AUTHOR("Texas Instruments Ltd");
|
||||
MODULE_DESCRIPTION("BQ27xxx battery monitor HDQ/1-wire driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_BQ27000));
|
|
@ -230,7 +230,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
|
|||
{ "bq27210", BQ27010 },
|
||||
{ "bq27500", BQ2750X },
|
||||
{ "bq27510", BQ2751X },
|
||||
{ "bq27520", BQ2751X },
|
||||
{ "bq27520", BQ2752X },
|
||||
{ "bq27500-1", BQ27500 },
|
||||
{ "bq27510g1", BQ27510G1 },
|
||||
{ "bq27510g2", BQ27510G2 },
|
||||
|
@ -240,16 +240,16 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
|
|||
{ "bq27520g3", BQ27520G3 },
|
||||
{ "bq27520g4", BQ27520G4 },
|
||||
{ "bq27530", BQ27530 },
|
||||
{ "bq27531", BQ27530 },
|
||||
{ "bq27531", BQ27531 },
|
||||
{ "bq27541", BQ27541 },
|
||||
{ "bq27542", BQ27541 },
|
||||
{ "bq27546", BQ27541 },
|
||||
{ "bq27742", BQ27541 },
|
||||
{ "bq27542", BQ27542 },
|
||||
{ "bq27546", BQ27546 },
|
||||
{ "bq27742", BQ27742 },
|
||||
{ "bq27545", BQ27545 },
|
||||
{ "bq27421", BQ27421 },
|
||||
{ "bq27425", BQ27421 },
|
||||
{ "bq27441", BQ27421 },
|
||||
{ "bq27621", BQ27421 },
|
||||
{ "bq27425", BQ27425 },
|
||||
{ "bq27441", BQ27441 },
|
||||
{ "bq27621", BQ27621 },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, bq27xxx_i2c_id_table);
|
||||
|
|
|
@ -1632,8 +1632,7 @@ static int charger_manager_probe(struct platform_device *pdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
cm = devm_kzalloc(&pdev->dev,
|
||||
sizeof(struct charger_manager), GFP_KERNEL);
|
||||
cm = devm_kzalloc(&pdev->dev, sizeof(*cm), GFP_KERNEL);
|
||||
if (!cm)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -1645,12 +1644,14 @@ static int charger_manager_probe(struct platform_device *pdev)
|
|||
/* Initialize alarm timer */
|
||||
if (alarmtimer_get_rtcdev()) {
|
||||
cm_timer = devm_kzalloc(cm->dev, sizeof(*cm_timer), GFP_KERNEL);
|
||||
if (!cm_timer)
|
||||
return -ENOMEM;
|
||||
alarm_init(cm_timer, ALARM_BOOTTIME, cm_timer_func);
|
||||
}
|
||||
|
||||
/*
|
||||
* The following two do not need to be errors.
|
||||
* Users may intentionally ignore those two features.
|
||||
* Some of the following do not need to be errors.
|
||||
* Users may intentionally ignore those features.
|
||||
*/
|
||||
if (desc->fullbatt_uV == 0) {
|
||||
dev_info(&pdev->dev, "Ignoring full-battery voltage threshold as it is not supplied\n");
|
||||
|
|
|
@ -663,7 +663,7 @@ static ssize_t ds2780_write_param_eeprom_bin(struct file *filp,
|
|||
return count;
|
||||
}
|
||||
|
||||
static struct bin_attribute ds2780_param_eeprom_bin_attr = {
|
||||
static const struct bin_attribute ds2780_param_eeprom_bin_attr = {
|
||||
.attr = {
|
||||
.name = "param_eeprom",
|
||||
.mode = S_IRUGO | S_IWUSR,
|
||||
|
@ -708,7 +708,7 @@ static ssize_t ds2780_write_user_eeprom_bin(struct file *filp,
|
|||
return count;
|
||||
}
|
||||
|
||||
static struct bin_attribute ds2780_user_eeprom_bin_attr = {
|
||||
static const struct bin_attribute ds2780_user_eeprom_bin_attr = {
|
||||
.attr = {
|
||||
.name = "user_eeprom",
|
||||
.mode = S_IRUGO | S_IWUSR,
|
||||
|
|
|
@ -665,7 +665,7 @@ static ssize_t ds2781_write_param_eeprom_bin(struct file *filp,
|
|||
return count;
|
||||
}
|
||||
|
||||
static struct bin_attribute ds2781_param_eeprom_bin_attr = {
|
||||
static const struct bin_attribute ds2781_param_eeprom_bin_attr = {
|
||||
.attr = {
|
||||
.name = "param_eeprom",
|
||||
.mode = S_IRUGO | S_IWUSR,
|
||||
|
@ -711,7 +711,7 @@ static ssize_t ds2781_write_user_eeprom_bin(struct file *filp,
|
|||
return count;
|
||||
}
|
||||
|
||||
static struct bin_attribute ds2781_user_eeprom_bin_attr = {
|
||||
static const struct bin_attribute ds2781_user_eeprom_bin_attr = {
|
||||
.attr = {
|
||||
.name = "user_eeprom",
|
||||
.mode = S_IRUGO | S_IWUSR,
|
||||
|
|
|
@ -626,7 +626,7 @@ static ssize_t lp8788_show_charger_status(struct device *dev,
|
|||
{
|
||||
struct lp8788_charger *pchg = dev_get_drvdata(dev);
|
||||
enum lp8788_charging_state state;
|
||||
char *desc[LP8788_MAX_CHG_STATE] = {
|
||||
static const char * const desc[LP8788_MAX_CHG_STATE] = {
|
||||
[LP8788_OFF] = "CHARGER OFF",
|
||||
[LP8788_WARM_UP] = "WARM UP",
|
||||
[LP8788_LOW_INPUT] = "LOW INPUT STATE",
|
||||
|
@ -650,8 +650,10 @@ static ssize_t lp8788_show_eoc_time(struct device *dev,
|
|||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct lp8788_charger *pchg = dev_get_drvdata(dev);
|
||||
char *stime[] = { "400ms", "5min", "10min", "15min",
|
||||
"20min", "25min", "30min", "No timeout" };
|
||||
static const char * const stime[] = {
|
||||
"400ms", "5min", "10min", "15min",
|
||||
"20min", "25min", "30min", "No timeout"
|
||||
};
|
||||
u8 val;
|
||||
|
||||
lp8788_read_byte(pchg->lp, LP8788_CHG_EOC, &val);
|
||||
|
@ -665,9 +667,13 @@ static ssize_t lp8788_show_eoc_level(struct device *dev,
|
|||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct lp8788_charger *pchg = dev_get_drvdata(dev);
|
||||
char *abs_level[] = { "25mA", "49mA", "75mA", "98mA" };
|
||||
char *relative_level[] = { "5%", "10%", "15%", "20%" };
|
||||
char *level;
|
||||
static const char * const abs_level[] = {
|
||||
"25mA", "49mA", "75mA", "98mA"
|
||||
};
|
||||
static const char * const relative_level[] = {
|
||||
"5%", "10%", "15%", "20%"
|
||||
};
|
||||
const char *level;
|
||||
u8 val;
|
||||
u8 mode;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* I2C client/driver for the Linear Technology LTC2941 and LTC2943
|
||||
* Battery Gas Gauge IC
|
||||
* I2C client/driver for the Linear Technology LTC2941, LTC2942, LTC2943
|
||||
* and LTC2944 Battery Gas Gauge IC
|
||||
*
|
||||
* Copyright (C) 2014 Topic Embedded Systems
|
||||
*
|
||||
|
@ -34,35 +34,39 @@ enum ltc294x_reg {
|
|||
LTC294X_REG_CONTROL = 0x01,
|
||||
LTC294X_REG_ACC_CHARGE_MSB = 0x02,
|
||||
LTC294X_REG_ACC_CHARGE_LSB = 0x03,
|
||||
LTC294X_REG_THRESH_HIGH_MSB = 0x04,
|
||||
LTC294X_REG_THRESH_HIGH_LSB = 0x05,
|
||||
LTC294X_REG_THRESH_LOW_MSB = 0x06,
|
||||
LTC294X_REG_THRESH_LOW_LSB = 0x07,
|
||||
LTC294X_REG_VOLTAGE_MSB = 0x08,
|
||||
LTC294X_REG_VOLTAGE_LSB = 0x09,
|
||||
LTC294X_REG_CURRENT_MSB = 0x0E,
|
||||
LTC294X_REG_CURRENT_LSB = 0x0F,
|
||||
LTC294X_REG_TEMPERATURE_MSB = 0x14,
|
||||
LTC294X_REG_TEMPERATURE_LSB = 0x15,
|
||||
LTC294X_REG_VOLTAGE_MSB = 0x08,
|
||||
LTC294X_REG_VOLTAGE_LSB = 0x09,
|
||||
LTC2942_REG_TEMPERATURE_MSB = 0x0C,
|
||||
LTC2942_REG_TEMPERATURE_LSB = 0x0D,
|
||||
LTC2943_REG_CURRENT_MSB = 0x0E,
|
||||
LTC2943_REG_CURRENT_LSB = 0x0F,
|
||||
LTC2943_REG_TEMPERATURE_MSB = 0x14,
|
||||
LTC2943_REG_TEMPERATURE_LSB = 0x15,
|
||||
};
|
||||
|
||||
#define LTC2943_REG_CONTROL_MODE_MASK (BIT(7) | BIT(6))
|
||||
#define LTC2943_REG_CONTROL_MODE_SCAN BIT(7)
|
||||
enum ltc294x_id {
|
||||
LTC2941_ID,
|
||||
LTC2942_ID,
|
||||
LTC2943_ID,
|
||||
LTC2944_ID,
|
||||
};
|
||||
|
||||
#define LTC2941_REG_STATUS_CHIP_ID BIT(7)
|
||||
|
||||
#define LTC2942_REG_CONTROL_MODE_SCAN (BIT(7) | BIT(6))
|
||||
#define LTC2943_REG_CONTROL_MODE_SCAN BIT(7)
|
||||
#define LTC294X_REG_CONTROL_PRESCALER_MASK (BIT(5) | BIT(4) | BIT(3))
|
||||
#define LTC294X_REG_CONTROL_SHUTDOWN_MASK (BIT(0))
|
||||
#define LTC294X_REG_CONTROL_PRESCALER_SET(x) \
|
||||
((x << 3) & LTC294X_REG_CONTROL_PRESCALER_MASK)
|
||||
#define LTC294X_REG_CONTROL_ALCC_CONFIG_DISABLED 0
|
||||
|
||||
#define LTC2941_NUM_REGS 0x08
|
||||
#define LTC2943_NUM_REGS 0x18
|
||||
|
||||
struct ltc294x_info {
|
||||
struct i2c_client *client; /* I2C Client pointer */
|
||||
struct power_supply *supply; /* Supply pointer */
|
||||
struct power_supply_desc supply_desc; /* Supply description */
|
||||
struct delayed_work work; /* Work scheduler */
|
||||
unsigned long num_regs; /* Number of registers (chip type) */
|
||||
enum ltc294x_id id; /* Chip type */
|
||||
int charge; /* Last charge register content */
|
||||
int r_sense; /* mOhm */
|
||||
int Qlsb; /* nAh */
|
||||
|
@ -145,9 +149,18 @@ static int ltc294x_reset(const struct ltc294x_info *info, int prescaler_exp)
|
|||
|
||||
control = LTC294X_REG_CONTROL_PRESCALER_SET(prescaler_exp) |
|
||||
LTC294X_REG_CONTROL_ALCC_CONFIG_DISABLED;
|
||||
/* Put the 2943 into "monitor" mode, so it measures every 10 sec */
|
||||
if (info->num_regs == LTC2943_NUM_REGS)
|
||||
/* Put device into "monitor" mode */
|
||||
switch (info->id) {
|
||||
case LTC2942_ID: /* 2942 measures every 2 sec */
|
||||
control |= LTC2942_REG_CONTROL_MODE_SCAN;
|
||||
break;
|
||||
case LTC2943_ID:
|
||||
case LTC2944_ID: /* 2943 and 2944 measure every 10 sec */
|
||||
control |= LTC2943_REG_CONTROL_MODE_SCAN;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (value != control) {
|
||||
ret = ltc294x_write_regs(info->client,
|
||||
|
@ -252,7 +265,24 @@ static int ltc294x_get_voltage(const struct ltc294x_info *info, int *val)
|
|||
ret = ltc294x_read_regs(info->client,
|
||||
LTC294X_REG_VOLTAGE_MSB, &datar[0], 2);
|
||||
value = (datar[0] << 8) | datar[1];
|
||||
*val = ((value * 23600) / 0xFFFF) * 1000; /* in uV */
|
||||
switch (info->id) {
|
||||
case LTC2943_ID:
|
||||
value *= 23600 * 2;
|
||||
value /= 0xFFFF;
|
||||
value *= 1000 / 2;
|
||||
break;
|
||||
case LTC2944_ID:
|
||||
value *= 70800 / 5*4;
|
||||
value /= 0xFFFF;
|
||||
value *= 1000 * 5/4;
|
||||
break;
|
||||
default:
|
||||
value *= 6000 * 10;
|
||||
value /= 0xFFFF;
|
||||
value *= 1000 / 10;
|
||||
break;
|
||||
}
|
||||
*val = value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -263,27 +293,38 @@ static int ltc294x_get_current(const struct ltc294x_info *info, int *val)
|
|||
s32 value;
|
||||
|
||||
ret = ltc294x_read_regs(info->client,
|
||||
LTC294X_REG_CURRENT_MSB, &datar[0], 2);
|
||||
LTC2943_REG_CURRENT_MSB, &datar[0], 2);
|
||||
value = (datar[0] << 8) | datar[1];
|
||||
value -= 0x7FFF;
|
||||
if (info->id == LTC2944_ID)
|
||||
value *= 64000;
|
||||
else
|
||||
value *= 60000;
|
||||
/* Value is in range -32k..+32k, r_sense is usually 10..50 mOhm,
|
||||
* the formula below keeps everything in s32 range while preserving
|
||||
* enough digits */
|
||||
*val = 1000 * ((60000 * value) / (info->r_sense * 0x7FFF)); /* in uA */
|
||||
*val = 1000 * (value / (info->r_sense * 0x7FFF)); /* in uA */
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ltc294x_get_temperature(const struct ltc294x_info *info, int *val)
|
||||
{
|
||||
enum ltc294x_reg reg;
|
||||
int ret;
|
||||
u8 datar[2];
|
||||
u32 value;
|
||||
|
||||
ret = ltc294x_read_regs(info->client,
|
||||
LTC294X_REG_TEMPERATURE_MSB, &datar[0], 2);
|
||||
value = (datar[0] << 8) | datar[1];
|
||||
/* Full-scale is 510 Kelvin, convert to centidegrees */
|
||||
*val = (((51000 * value) / 0xFFFF) - 27215);
|
||||
if (info->id == LTC2942_ID) {
|
||||
reg = LTC2942_REG_TEMPERATURE_MSB;
|
||||
value = 60000; /* Full-scale is 600 Kelvin */
|
||||
} else {
|
||||
reg = LTC2943_REG_TEMPERATURE_MSB;
|
||||
value = 51000; /* Full-scale is 510 Kelvin */
|
||||
}
|
||||
ret = ltc294x_read_regs(info->client, reg, &datar[0], 2);
|
||||
value *= (datar[0] << 8) | datar[1];
|
||||
/* Convert to centidegrees */
|
||||
*val = value / 0xFFFF - 27215;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -357,8 +398,8 @@ static enum power_supply_property ltc294x_properties[] = {
|
|||
POWER_SUPPLY_PROP_CHARGE_COUNTER,
|
||||
POWER_SUPPLY_PROP_CHARGE_NOW,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
POWER_SUPPLY_PROP_TEMP,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
};
|
||||
|
||||
static int ltc294x_i2c_remove(struct i2c_client *client)
|
||||
|
@ -375,10 +416,11 @@ static int ltc294x_i2c_probe(struct i2c_client *client,
|
|||
{
|
||||
struct power_supply_config psy_cfg = {};
|
||||
struct ltc294x_info *info;
|
||||
struct device_node *np;
|
||||
int ret;
|
||||
u32 prescaler_exp;
|
||||
s32 r_sense;
|
||||
struct device_node *np;
|
||||
u8 status;
|
||||
|
||||
info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
|
||||
if (info == NULL)
|
||||
|
@ -388,7 +430,7 @@ static int ltc294x_i2c_probe(struct i2c_client *client,
|
|||
|
||||
np = of_node_get(client->dev.of_node);
|
||||
|
||||
info->num_regs = (unsigned long)of_device_get_match_data(&client->dev);
|
||||
info->id = (enum ltc294x_id)of_device_get_match_data(&client->dev);
|
||||
info->supply_desc.name = np->name;
|
||||
|
||||
/* r_sense can be negative, when sense+ is connected to the battery
|
||||
|
@ -409,7 +451,7 @@ static int ltc294x_i2c_probe(struct i2c_client *client,
|
|||
prescaler_exp = LTC2941_MAX_PRESCALER_EXP;
|
||||
}
|
||||
|
||||
if (info->num_regs == LTC2943_NUM_REGS) {
|
||||
if (info->id == LTC2943_ID) {
|
||||
if (prescaler_exp > LTC2943_MAX_PRESCALER_EXP)
|
||||
prescaler_exp = LTC2943_MAX_PRESCALER_EXP;
|
||||
info->Qlsb = ((340 * 50000) / r_sense) /
|
||||
|
@ -421,21 +463,39 @@ static int ltc294x_i2c_probe(struct i2c_client *client,
|
|||
(128 / (1 << prescaler_exp));
|
||||
}
|
||||
|
||||
/* Read status register to check for LTC2942 */
|
||||
if (info->id == LTC2941_ID || info->id == LTC2942_ID) {
|
||||
ret = ltc294x_read_regs(client, LTC294X_REG_STATUS, &status, 1);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev,
|
||||
"Could not read status register\n");
|
||||
return ret;
|
||||
}
|
||||
if (status & LTC2941_REG_STATUS_CHIP_ID)
|
||||
info->id = LTC2941_ID;
|
||||
else
|
||||
info->id = LTC2942_ID;
|
||||
}
|
||||
|
||||
info->client = client;
|
||||
info->supply_desc.type = POWER_SUPPLY_TYPE_BATTERY;
|
||||
info->supply_desc.properties = ltc294x_properties;
|
||||
if (info->num_regs >= LTC294X_REG_TEMPERATURE_LSB)
|
||||
switch (info->id) {
|
||||
case LTC2944_ID:
|
||||
case LTC2943_ID:
|
||||
info->supply_desc.num_properties =
|
||||
ARRAY_SIZE(ltc294x_properties);
|
||||
else if (info->num_regs >= LTC294X_REG_CURRENT_LSB)
|
||||
break;
|
||||
case LTC2942_ID:
|
||||
info->supply_desc.num_properties =
|
||||
ARRAY_SIZE(ltc294x_properties) - 1;
|
||||
else if (info->num_regs >= LTC294X_REG_VOLTAGE_LSB)
|
||||
info->supply_desc.num_properties =
|
||||
ARRAY_SIZE(ltc294x_properties) - 2;
|
||||
else
|
||||
break;
|
||||
case LTC2941_ID:
|
||||
default:
|
||||
info->supply_desc.num_properties =
|
||||
ARRAY_SIZE(ltc294x_properties) - 3;
|
||||
break;
|
||||
}
|
||||
info->supply_desc.get_property = ltc294x_get_property;
|
||||
info->supply_desc.set_property = ltc294x_set_property;
|
||||
info->supply_desc.property_is_writeable = ltc294x_property_is_writeable;
|
||||
|
@ -492,8 +552,10 @@ static SIMPLE_DEV_PM_OPS(ltc294x_pm_ops, ltc294x_suspend, ltc294x_resume);
|
|||
|
||||
|
||||
static const struct i2c_device_id ltc294x_i2c_id[] = {
|
||||
{"ltc2941", LTC2941_NUM_REGS},
|
||||
{"ltc2943", LTC2943_NUM_REGS},
|
||||
{ "ltc2941", LTC2941_ID, },
|
||||
{ "ltc2942", LTC2942_ID, },
|
||||
{ "ltc2943", LTC2943_ID, },
|
||||
{ "ltc2944", LTC2944_ID, },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ltc294x_i2c_id);
|
||||
|
@ -501,11 +563,19 @@ MODULE_DEVICE_TABLE(i2c, ltc294x_i2c_id);
|
|||
static const struct of_device_id ltc294x_i2c_of_match[] = {
|
||||
{
|
||||
.compatible = "lltc,ltc2941",
|
||||
.data = (void *)LTC2941_NUM_REGS
|
||||
.data = (void *)LTC2941_ID,
|
||||
},
|
||||
{
|
||||
.compatible = "lltc,ltc2942",
|
||||
.data = (void *)LTC2942_ID,
|
||||
},
|
||||
{
|
||||
.compatible = "lltc,ltc2943",
|
||||
.data = (void *)LTC2943_NUM_REGS
|
||||
.data = (void *)LTC2943_ID,
|
||||
},
|
||||
{
|
||||
.compatible = "lltc,ltc2944",
|
||||
.data = (void *)LTC2944_ID,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
@ -525,5 +595,5 @@ module_i2c_driver(ltc294x_driver);
|
|||
|
||||
MODULE_AUTHOR("Auryn Verwegen, Topic Embedded Systems");
|
||||
MODULE_AUTHOR("Mike Looijmans, Topic Embedded Products");
|
||||
MODULE_DESCRIPTION("LTC2941/LTC2943 Battery Gas Gauge IC driver");
|
||||
MODULE_DESCRIPTION("LTC2941/LTC2942/LTC2943/LTC2944 Battery Gas Gauge IC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* This driver is based on max17040_battery.c
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -982,6 +983,8 @@ static int max17042_probe(struct i2c_client *client,
|
|||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
||||
const struct power_supply_desc *max17042_desc = &max17042_psy_desc;
|
||||
struct power_supply_config psy_cfg = {};
|
||||
const struct acpi_device_id *acpi_id = NULL;
|
||||
struct device *dev = &client->dev;
|
||||
struct max17042_chip *chip;
|
||||
int ret;
|
||||
int i;
|
||||
|
@ -995,7 +998,15 @@ static int max17042_probe(struct i2c_client *client,
|
|||
return -ENOMEM;
|
||||
|
||||
chip->client = client;
|
||||
chip->chip_type = id->driver_data;
|
||||
if (id) {
|
||||
chip->chip_type = id->driver_data;
|
||||
} else {
|
||||
acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
|
||||
if (!acpi_id)
|
||||
return -ENODEV;
|
||||
|
||||
chip->chip_type = acpi_id->driver_data;
|
||||
}
|
||||
chip->regmap = devm_regmap_init_i2c(client, &max17042_regmap_config);
|
||||
if (IS_ERR(chip->regmap)) {
|
||||
dev_err(&client->dev, "Failed to initialize regmap\n");
|
||||
|
@ -1039,11 +1050,18 @@ static int max17042_probe(struct i2c_client *client,
|
|||
}
|
||||
|
||||
if (client->irq) {
|
||||
unsigned int flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
|
||||
|
||||
/*
|
||||
* On ACPI systems the IRQ may be handled by ACPI-event code,
|
||||
* so we need to share (if the ACPI code is willing to share).
|
||||
*/
|
||||
if (acpi_id)
|
||||
flags |= IRQF_SHARED | IRQF_PROBE_SHARED;
|
||||
|
||||
ret = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
NULL,
|
||||
max17042_thread_handler,
|
||||
IRQF_TRIGGER_FALLING |
|
||||
IRQF_ONESHOT,
|
||||
max17042_thread_handler, flags,
|
||||
chip->battery->desc->name,
|
||||
chip);
|
||||
if (!ret) {
|
||||
|
@ -1053,10 +1071,13 @@ static int max17042_probe(struct i2c_client *client,
|
|||
max17042_set_soc_threshold(chip, 1);
|
||||
} else {
|
||||
client->irq = 0;
|
||||
dev_err(&client->dev, "%s(): cannot get IRQ\n",
|
||||
__func__);
|
||||
if (ret != -EBUSY)
|
||||
dev_err(&client->dev, "Failed to get IRQ\n");
|
||||
}
|
||||
}
|
||||
/* Not able to update the charge threshold when exceeded? -> disable */
|
||||
if (!client->irq)
|
||||
regmap_write(chip->regmap, MAX17042_SALRT_Th, 0xff00);
|
||||
|
||||
regmap_read(chip->regmap, MAX17042_STATUS, &val);
|
||||
if (val & STATUS_POR_BIT) {
|
||||
|
@ -1104,6 +1125,14 @@ static int max17042_resume(struct device *dev)
|
|||
static SIMPLE_DEV_PM_OPS(max17042_pm_ops, max17042_suspend,
|
||||
max17042_resume);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id max17042_acpi_match[] = {
|
||||
{ "MAX17047", MAXIM_DEVICE_TYPE_MAX17047 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, max17042_acpi_match);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id max17042_dt_match[] = {
|
||||
{ .compatible = "maxim,max17042" },
|
||||
|
@ -1125,6 +1154,7 @@ MODULE_DEVICE_TABLE(i2c, max17042_id);
|
|||
static struct i2c_driver max17042_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "max17042",
|
||||
.acpi_match_table = ACPI_PTR(max17042_acpi_match),
|
||||
.of_match_table = of_match_ptr(max17042_dt_match),
|
||||
.pm = &max17042_pm_ops,
|
||||
},
|
||||
|
|
|
@ -0,0 +1,448 @@
|
|||
/*
|
||||
* 1-Wire implementation for Maxim Semiconductor
|
||||
* MAX7211/MAX17215 stanalone fuel gauge chip
|
||||
*
|
||||
* Copyright (C) 2017 Radioavionica Corporation
|
||||
* Author: Alex A. Mihaylov <minimumlaw@rambler.ru>
|
||||
*
|
||||
* Use consistent with the GNU GPL is permitted,
|
||||
* provided that this copyright notice is
|
||||
* preserved in its entirety in all copies and derived works.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/w1.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/power_supply.h>
|
||||
|
||||
#define W1_MAX1721X_FAMILY_ID 0x26
|
||||
#define DEF_DEV_NAME_MAX17211 "MAX17211"
|
||||
#define DEF_DEV_NAME_MAX17215 "MAX17215"
|
||||
#define DEF_DEV_NAME_UNKNOWN "UNKNOWN"
|
||||
#define DEF_MFG_NAME "MAXIM"
|
||||
|
||||
#define PSY_MAX_NAME_LEN 32
|
||||
|
||||
/* Number of valid register addresses in W1 mode */
|
||||
#define MAX1721X_MAX_REG_NR 0x1EF
|
||||
|
||||
/* Factory settings (nonvilatile registers) (W1 specific) */
|
||||
#define MAX1721X_REG_NRSENSE 0x1CF /* RSense in 10^-5 Ohm */
|
||||
/* Strings */
|
||||
#define MAX1721X_REG_MFG_STR 0x1CC
|
||||
#define MAX1721X_REG_MFG_NUMB 3
|
||||
#define MAX1721X_REG_DEV_STR 0x1DB
|
||||
#define MAX1721X_REG_DEV_NUMB 5
|
||||
/* HEX Strings */
|
||||
#define MAX1721X_REG_SER_HEX 0x1D8
|
||||
|
||||
/* MAX172XX Output Registers for W1 chips */
|
||||
#define MAX172XX_REG_STATUS 0x000 /* status reg */
|
||||
#define MAX172XX_BAT_PRESENT (1<<4) /* battery connected bit */
|
||||
#define MAX172XX_REG_DEVNAME 0x021 /* chip config */
|
||||
#define MAX172XX_DEV_MASK 0x000F /* chip type mask */
|
||||
#define MAX172X1_DEV 0x0001
|
||||
#define MAX172X5_DEV 0x0005
|
||||
#define MAX172XX_REG_TEMP 0x008 /* Temperature */
|
||||
#define MAX172XX_REG_BATT 0x0DA /* Battery voltage */
|
||||
#define MAX172XX_REG_CURRENT 0x00A /* Actual current */
|
||||
#define MAX172XX_REG_AVGCURRENT 0x00B /* Average current */
|
||||
#define MAX172XX_REG_REPSOC 0x006 /* Percentage of charge */
|
||||
#define MAX172XX_REG_DESIGNCAP 0x018 /* Design capacity */
|
||||
#define MAX172XX_REG_REPCAP 0x005 /* Average capacity */
|
||||
#define MAX172XX_REG_TTE 0x011 /* Time to empty */
|
||||
#define MAX172XX_REG_TTF 0x020 /* Time to full */
|
||||
|
||||
struct max17211_device_info {
|
||||
char name[PSY_MAX_NAME_LEN];
|
||||
struct power_supply *bat;
|
||||
struct power_supply_desc bat_desc;
|
||||
struct device *w1_dev;
|
||||
struct regmap *regmap;
|
||||
/* battery design format */
|
||||
unsigned int rsense; /* in tenths uOhm */
|
||||
char DeviceName[2 * MAX1721X_REG_DEV_NUMB + 1];
|
||||
char ManufacturerName[2 * MAX1721X_REG_MFG_NUMB + 1];
|
||||
char SerialNumber[13]; /* see get_sn_str() later for comment */
|
||||
};
|
||||
|
||||
/* Convert regs value to power_supply units */
|
||||
|
||||
static inline int max172xx_time_to_ps(unsigned int reg)
|
||||
{
|
||||
return reg * 5625 / 1000; /* in sec. */
|
||||
}
|
||||
|
||||
static inline int max172xx_percent_to_ps(unsigned int reg)
|
||||
{
|
||||
return reg / 256; /* in percent from 0 to 100 */
|
||||
}
|
||||
|
||||
static inline int max172xx_voltage_to_ps(unsigned int reg)
|
||||
{
|
||||
return reg * 1250; /* in uV */
|
||||
}
|
||||
|
||||
static inline int max172xx_capacity_to_ps(unsigned int reg)
|
||||
{
|
||||
return reg * 500; /* in uAh */
|
||||
}
|
||||
|
||||
/*
|
||||
* Current and temperature is signed values, so unsigned regs
|
||||
* value must be converted to signed type
|
||||
*/
|
||||
|
||||
static inline int max172xx_temperature_to_ps(unsigned int reg)
|
||||
{
|
||||
int val = (int16_t)(reg);
|
||||
|
||||
return val * 10 / 256; /* in tenths of deg. C */
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculating current registers resolution:
|
||||
*
|
||||
* RSense stored in 10^-5 Ohm, so mesaurment voltage must be
|
||||
* in 10^-11 Volts for get current in uA.
|
||||
* 16 bit current reg fullscale +/-51.2mV is 102400 uV.
|
||||
* So: 102400 / 65535 * 10^5 = 156252
|
||||
*/
|
||||
static inline int max172xx_current_to_voltage(unsigned int reg)
|
||||
{
|
||||
int val = (int16_t)(reg);
|
||||
|
||||
return val * 156252;
|
||||
}
|
||||
|
||||
|
||||
static inline struct max17211_device_info *
|
||||
to_device_info(struct power_supply *psy)
|
||||
{
|
||||
return power_supply_get_drvdata(psy);
|
||||
}
|
||||
|
||||
static int max1721x_battery_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct max17211_device_info *info = to_device_info(psy);
|
||||
unsigned int reg = 0;
|
||||
int ret = 0;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_PRESENT:
|
||||
/*
|
||||
* POWER_SUPPLY_PROP_PRESENT will always readable via
|
||||
* sysfs interface. Value return 0 if battery not
|
||||
* present or unaccesable via W1.
|
||||
*/
|
||||
val->intval =
|
||||
regmap_read(info->regmap, MAX172XX_REG_STATUS,
|
||||
®) ? 0 : !(reg & MAX172XX_BAT_PRESENT);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CAPACITY:
|
||||
ret = regmap_read(info->regmap, MAX172XX_REG_REPSOC, ®);
|
||||
val->intval = max172xx_percent_to_ps(reg);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
ret = regmap_read(info->regmap, MAX172XX_REG_BATT, ®);
|
||||
val->intval = max172xx_voltage_to_ps(reg);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
|
||||
ret = regmap_read(info->regmap, MAX172XX_REG_DESIGNCAP, ®);
|
||||
val->intval = max172xx_capacity_to_ps(reg);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_AVG:
|
||||
ret = regmap_read(info->regmap, MAX172XX_REG_REPCAP, ®);
|
||||
val->intval = max172xx_capacity_to_ps(reg);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
|
||||
ret = regmap_read(info->regmap, MAX172XX_REG_TTE, ®);
|
||||
val->intval = max172xx_time_to_ps(reg);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
|
||||
ret = regmap_read(info->regmap, MAX172XX_REG_TTF, ®);
|
||||
val->intval = max172xx_time_to_ps(reg);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TEMP:
|
||||
ret = regmap_read(info->regmap, MAX172XX_REG_TEMP, ®);
|
||||
val->intval = max172xx_temperature_to_ps(reg);
|
||||
break;
|
||||
/* We need signed current, so must cast info->rsense to signed type */
|
||||
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
||||
ret = regmap_read(info->regmap, MAX172XX_REG_CURRENT, ®);
|
||||
val->intval =
|
||||
max172xx_current_to_voltage(reg) / (int)info->rsense;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CURRENT_AVG:
|
||||
ret = regmap_read(info->regmap, MAX172XX_REG_AVGCURRENT, ®);
|
||||
val->intval =
|
||||
max172xx_current_to_voltage(reg) / (int)info->rsense;
|
||||
break;
|
||||
/*
|
||||
* Strings already received and inited by probe.
|
||||
* We do dummy read for check battery still available.
|
||||
*/
|
||||
case POWER_SUPPLY_PROP_MODEL_NAME:
|
||||
ret = regmap_read(info->regmap, MAX1721X_REG_DEV_STR, ®);
|
||||
val->strval = info->DeviceName;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_MANUFACTURER:
|
||||
ret = regmap_read(info->regmap, MAX1721X_REG_MFG_STR, ®);
|
||||
val->strval = info->ManufacturerName;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_SERIAL_NUMBER:
|
||||
ret = regmap_read(info->regmap, MAX1721X_REG_SER_HEX, ®);
|
||||
val->strval = info->SerialNumber;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static enum power_supply_property max1721x_battery_props[] = {
|
||||
/* int */
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_CAPACITY,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
|
||||
POWER_SUPPLY_PROP_CHARGE_AVG,
|
||||
POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
|
||||
POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
|
||||
POWER_SUPPLY_PROP_TEMP,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_AVG,
|
||||
/* strings */
|
||||
POWER_SUPPLY_PROP_MODEL_NAME,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
POWER_SUPPLY_PROP_SERIAL_NUMBER,
|
||||
};
|
||||
|
||||
static int get_string(struct max17211_device_info *info,
|
||||
uint16_t reg, uint8_t nr, char *str)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
if (!str || !(reg == MAX1721X_REG_MFG_STR ||
|
||||
reg == MAX1721X_REG_DEV_STR))
|
||||
return -EFAULT;
|
||||
|
||||
while (nr--) {
|
||||
if (regmap_read(info->regmap, reg++, &val))
|
||||
return -EFAULT;
|
||||
*str++ = val>>8 & 0x00FF;
|
||||
*str++ = val & 0x00FF;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Maxim say: Serial number is a hex string up to 12 hex characters */
|
||||
static int get_sn_string(struct max17211_device_info *info, char *str)
|
||||
{
|
||||
unsigned int val[3];
|
||||
|
||||
if (!str)
|
||||
return -EFAULT;
|
||||
|
||||
if (regmap_read(info->regmap, MAX1721X_REG_SER_HEX, &val[0]))
|
||||
return -EFAULT;
|
||||
if (regmap_read(info->regmap, MAX1721X_REG_SER_HEX + 1, &val[1]))
|
||||
return -EFAULT;
|
||||
if (regmap_read(info->regmap, MAX1721X_REG_SER_HEX + 2, &val[2]))
|
||||
return -EFAULT;
|
||||
|
||||
snprintf(str, 13, "%04X%04X%04X", val[0], val[1], val[2]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* MAX1721x registers description for w1-regmap
|
||||
*/
|
||||
static const struct regmap_range max1721x_allow_range[] = {
|
||||
regmap_reg_range(0, 0xDF), /* volatile data */
|
||||
regmap_reg_range(0x180, 0x1DF), /* non-volatile memory */
|
||||
regmap_reg_range(0x1E0, 0x1EF), /* non-volatile history (unused) */
|
||||
};
|
||||
|
||||
static const struct regmap_range max1721x_deny_range[] = {
|
||||
/* volatile data unused registers */
|
||||
regmap_reg_range(0x24, 0x26),
|
||||
regmap_reg_range(0x30, 0x31),
|
||||
regmap_reg_range(0x33, 0x34),
|
||||
regmap_reg_range(0x37, 0x37),
|
||||
regmap_reg_range(0x3B, 0x3C),
|
||||
regmap_reg_range(0x40, 0x41),
|
||||
regmap_reg_range(0x43, 0x44),
|
||||
regmap_reg_range(0x47, 0x49),
|
||||
regmap_reg_range(0x4B, 0x4C),
|
||||
regmap_reg_range(0x4E, 0xAF),
|
||||
regmap_reg_range(0xB1, 0xB3),
|
||||
regmap_reg_range(0xB5, 0xB7),
|
||||
regmap_reg_range(0xBF, 0xD0),
|
||||
regmap_reg_range(0xDB, 0xDB),
|
||||
/* hole between volatile and non-volatile registers */
|
||||
regmap_reg_range(0xE0, 0x17F),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table max1721x_regs = {
|
||||
.yes_ranges = max1721x_allow_range,
|
||||
.n_yes_ranges = ARRAY_SIZE(max1721x_allow_range),
|
||||
.no_ranges = max1721x_deny_range,
|
||||
.n_no_ranges = ARRAY_SIZE(max1721x_deny_range),
|
||||
};
|
||||
|
||||
/*
|
||||
* Model Gauge M5 Algorithm output register
|
||||
* Volatile data (must not be cached)
|
||||
*/
|
||||
static const struct regmap_range max1721x_volatile_allow[] = {
|
||||
regmap_reg_range(0, 0xDF),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table max1721x_volatile_regs = {
|
||||
.yes_ranges = max1721x_volatile_allow,
|
||||
.n_yes_ranges = ARRAY_SIZE(max1721x_volatile_allow),
|
||||
};
|
||||
|
||||
/*
|
||||
* W1-regmap config
|
||||
*/
|
||||
static const struct regmap_config max1721x_regmap_w1_config = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 16,
|
||||
.rd_table = &max1721x_regs,
|
||||
.volatile_table = &max1721x_volatile_regs,
|
||||
.max_register = MAX1721X_MAX_REG_NR,
|
||||
};
|
||||
|
||||
static int devm_w1_max1721x_add_device(struct w1_slave *sl)
|
||||
{
|
||||
struct power_supply_config psy_cfg = {};
|
||||
struct max17211_device_info *info;
|
||||
|
||||
info = devm_kzalloc(&sl->dev, sizeof(*info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
sl->family_data = (void *)info;
|
||||
info->w1_dev = &sl->dev;
|
||||
|
||||
/*
|
||||
* power_supply class battery name translated from W1 slave device
|
||||
* unical ID (look like 26-0123456789AB) to "max1721x-0123456789AB\0"
|
||||
* so, 26 (device family) correcpondent to max1721x devices.
|
||||
* Device name still unical for any numbers connected devices.
|
||||
*/
|
||||
snprintf(info->name, sizeof(info->name),
|
||||
"max1721x-%012X", (unsigned int)sl->reg_num.id);
|
||||
info->bat_desc.name = info->name;
|
||||
|
||||
/*
|
||||
* FixMe: battery device name exceed max len for thermal_zone device
|
||||
* name and translation to thermal_zone must be disabled.
|
||||
*/
|
||||
info->bat_desc.no_thermal = true;
|
||||
info->bat_desc.type = POWER_SUPPLY_TYPE_BATTERY;
|
||||
info->bat_desc.properties = max1721x_battery_props;
|
||||
info->bat_desc.num_properties = ARRAY_SIZE(max1721x_battery_props);
|
||||
info->bat_desc.get_property = max1721x_battery_get_property;
|
||||
psy_cfg.drv_data = info;
|
||||
|
||||
/* regmap init */
|
||||
info->regmap = devm_regmap_init_w1(info->w1_dev,
|
||||
&max1721x_regmap_w1_config);
|
||||
if (IS_ERR(info->regmap)) {
|
||||
int err = PTR_ERR(info->regmap);
|
||||
|
||||
dev_err(info->w1_dev, "Failed to allocate register map: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* rsense init */
|
||||
info->rsense = 0;
|
||||
if (regmap_read(info->regmap, MAX1721X_REG_NRSENSE, &info->rsense)) {
|
||||
dev_err(info->w1_dev, "Can't read RSense. Hardware error.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!info->rsense) {
|
||||
dev_warn(info->w1_dev, "RSenese not calibrated, set 10 mOhms!\n");
|
||||
info->rsense = 1000; /* in regs in 10^-5 */
|
||||
}
|
||||
dev_info(info->w1_dev, "RSense: %d mOhms.\n", info->rsense / 100);
|
||||
|
||||
if (get_string(info, MAX1721X_REG_MFG_STR,
|
||||
MAX1721X_REG_MFG_NUMB, info->ManufacturerName)) {
|
||||
dev_err(info->w1_dev, "Can't read manufacturer. Hardware error.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!info->ManufacturerName[0])
|
||||
strncpy(info->ManufacturerName, DEF_MFG_NAME,
|
||||
2 * MAX1721X_REG_MFG_NUMB);
|
||||
|
||||
if (get_string(info, MAX1721X_REG_DEV_STR,
|
||||
MAX1721X_REG_DEV_NUMB, info->DeviceName)) {
|
||||
dev_err(info->w1_dev, "Can't read device. Hardware error.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!info->DeviceName[0]) {
|
||||
unsigned int dev_name;
|
||||
|
||||
if (regmap_read(info->regmap,
|
||||
MAX172XX_REG_DEVNAME, &dev_name)) {
|
||||
dev_err(info->w1_dev, "Can't read device name reg.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
switch (dev_name & MAX172XX_DEV_MASK) {
|
||||
case MAX172X1_DEV:
|
||||
strncpy(info->DeviceName, DEF_DEV_NAME_MAX17211,
|
||||
2 * MAX1721X_REG_DEV_NUMB);
|
||||
break;
|
||||
case MAX172X5_DEV:
|
||||
strncpy(info->DeviceName, DEF_DEV_NAME_MAX17215,
|
||||
2 * MAX1721X_REG_DEV_NUMB);
|
||||
break;
|
||||
default:
|
||||
strncpy(info->DeviceName, DEF_DEV_NAME_UNKNOWN,
|
||||
2 * MAX1721X_REG_DEV_NUMB);
|
||||
}
|
||||
}
|
||||
|
||||
if (get_sn_string(info, info->SerialNumber)) {
|
||||
dev_err(info->w1_dev, "Can't read serial. Hardware error.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
info->bat = devm_power_supply_register(&sl->dev, &info->bat_desc,
|
||||
&psy_cfg);
|
||||
if (IS_ERR(info->bat)) {
|
||||
dev_err(info->w1_dev, "failed to register battery\n");
|
||||
return PTR_ERR(info->bat);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct w1_family_ops w1_max1721x_fops = {
|
||||
.add_slave = devm_w1_max1721x_add_device,
|
||||
};
|
||||
|
||||
static struct w1_family w1_max1721x_family = {
|
||||
.fid = W1_MAX1721X_FAMILY_ID,
|
||||
.fops = &w1_max1721x_fops,
|
||||
};
|
||||
|
||||
module_w1_family(w1_max1721x_family);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Alex A. Mihaylov <minimumlaw@rambler.ru>");
|
||||
MODULE_DESCRIPTION("Maxim MAX17211/MAX17215 Fuel Gauage IC driver");
|
||||
MODULE_ALIAS("w1-family-" __stringify(W1_MAX1721X_FAMILY_ID));
|
|
@ -535,7 +535,7 @@ static ssize_t olpc_bat_eeprom_read(struct file *filp, struct kobject *kobj,
|
|||
return count;
|
||||
}
|
||||
|
||||
static struct bin_attribute olpc_bat_eeprom = {
|
||||
static const struct bin_attribute olpc_bat_eeprom = {
|
||||
.attr = {
|
||||
.name = "eeprom",
|
||||
.mode = S_IRUGO,
|
||||
|
@ -559,7 +559,7 @@ static ssize_t olpc_bat_error_read(struct device *dev,
|
|||
return sprintf(buf, "%d\n", ec_byte);
|
||||
}
|
||||
|
||||
static struct device_attribute olpc_bat_error = {
|
||||
static const struct device_attribute olpc_bat_error = {
|
||||
.attr = {
|
||||
.name = "error",
|
||||
.mode = S_IRUGO,
|
||||
|
|
|
@ -254,7 +254,7 @@ static struct attribute *pcf50633_mbc_sysfs_entries[] = {
|
|||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group mbc_attr_group = {
|
||||
static const struct attribute_group mbc_attr_group = {
|
||||
.name = NULL, /* put in device directory */
|
||||
.attrs = pcf50633_mbc_sysfs_entries,
|
||||
};
|
||||
|
|
|
@ -259,18 +259,14 @@ static int power_supply_check_supplies(struct power_supply *psy)
|
|||
/* All supplies found, allocate char ** array for filling */
|
||||
psy->supplied_from = devm_kzalloc(&psy->dev, sizeof(psy->supplied_from),
|
||||
GFP_KERNEL);
|
||||
if (!psy->supplied_from) {
|
||||
dev_err(&psy->dev, "Couldn't allocate memory for supply list\n");
|
||||
if (!psy->supplied_from)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*psy->supplied_from = devm_kzalloc(&psy->dev,
|
||||
sizeof(char *) * (cnt - 1),
|
||||
GFP_KERNEL);
|
||||
if (!*psy->supplied_from) {
|
||||
dev_err(&psy->dev, "Couldn't allocate memory for supply list\n");
|
||||
if (!*psy->supplied_from)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return power_supply_populate_supplied_from(psy);
|
||||
}
|
||||
|
@ -314,11 +310,12 @@ static int __power_supply_am_i_supplied(struct device *dev, void *_data)
|
|||
struct power_supply *epsy = dev_get_drvdata(dev);
|
||||
struct psy_am_i_supplied_data *data = _data;
|
||||
|
||||
data->count++;
|
||||
if (__power_supply_is_supplied_by(epsy, data->psy))
|
||||
if (__power_supply_is_supplied_by(epsy, data->psy)) {
|
||||
data->count++;
|
||||
if (!epsy->desc->get_property(epsy, POWER_SUPPLY_PROP_ONLINE,
|
||||
&ret))
|
||||
return ret.intval;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -374,6 +371,47 @@ int power_supply_is_system_supplied(void)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(power_supply_is_system_supplied);
|
||||
|
||||
static int __power_supply_get_supplier_max_current(struct device *dev,
|
||||
void *data)
|
||||
{
|
||||
union power_supply_propval ret = {0,};
|
||||
struct power_supply *epsy = dev_get_drvdata(dev);
|
||||
struct power_supply *psy = data;
|
||||
|
||||
if (__power_supply_is_supplied_by(epsy, psy))
|
||||
if (!epsy->desc->get_property(epsy,
|
||||
POWER_SUPPLY_PROP_CURRENT_MAX,
|
||||
&ret))
|
||||
return ret.intval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int power_supply_set_input_current_limit_from_supplier(struct power_supply *psy)
|
||||
{
|
||||
union power_supply_propval val = {0,};
|
||||
int curr;
|
||||
|
||||
if (!psy->desc->set_property)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* This function is not intended for use with a supply with multiple
|
||||
* suppliers, we simply pick the first supply to report a non 0
|
||||
* max-current.
|
||||
*/
|
||||
curr = class_for_each_device(power_supply_class, NULL, psy,
|
||||
__power_supply_get_supplier_max_current);
|
||||
if (curr <= 0)
|
||||
return (curr == 0) ? -ENODEV : curr;
|
||||
|
||||
val.intval = curr;
|
||||
|
||||
return psy->desc->set_property(psy,
|
||||
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, &val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(power_supply_set_input_current_limit_from_supplier);
|
||||
|
||||
int power_supply_set_battery_charged(struct power_supply *psy)
|
||||
{
|
||||
if (atomic_read(&psy->use_cnt) >= 0 &&
|
||||
|
|
|
@ -12,25 +12,21 @@
|
|||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/stat.h>
|
||||
|
||||
#include <linux/power/sbs-battery.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stat.h>
|
||||
|
||||
enum {
|
||||
REG_MANUFACTURER_DATA,
|
||||
|
@ -60,8 +56,8 @@ enum {
|
|||
#define BATTERY_MODE_OFFSET 0x03
|
||||
#define BATTERY_MODE_MASK 0x8000
|
||||
enum sbs_battery_mode {
|
||||
BATTERY_MODE_AMPS,
|
||||
BATTERY_MODE_WATTS
|
||||
BATTERY_MODE_AMPS = 0,
|
||||
BATTERY_MODE_WATTS = 0x8000
|
||||
};
|
||||
|
||||
/* manufacturer access defines */
|
||||
|
@ -532,6 +528,8 @@ static enum sbs_battery_mode sbs_set_battery_mode(struct i2c_client *client,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
return original_val & BATTERY_MODE_MASK;
|
||||
}
|
||||
|
||||
|
|
|
@ -148,10 +148,4 @@ config W1_SLAVE_DS28E04
|
|||
|
||||
If you are unsure, say N.
|
||||
|
||||
config W1_SLAVE_BQ27000
|
||||
tristate "BQ27000 slave support"
|
||||
help
|
||||
Say Y here if you want to use a hdq
|
||||
bq27000 slave support.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -16,5 +16,4 @@ obj-$(CONFIG_W1_SLAVE_DS2438) += w1_ds2438.o
|
|||
obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o
|
||||
obj-$(CONFIG_W1_SLAVE_DS2780) += w1_ds2780.o
|
||||
obj-$(CONFIG_W1_SLAVE_DS2781) += w1_ds2781.o
|
||||
obj-$(CONFIG_W1_SLAVE_BQ27000) += w1_bq27000.o
|
||||
obj-$(CONFIG_W1_SLAVE_DS28E04) += w1_ds28e04.o
|
||||
|
|
|
@ -1,117 +0,0 @@
|
|||
/*
|
||||
* drivers/w1/slaves/w1_bq27000.c
|
||||
*
|
||||
* Copyright (C) 2007 Texas Instruments, Inc.
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public License
|
||||
* version 2. This program is licensed "as is" without any warranty of any
|
||||
* kind, whether express or implied.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/power/bq27xxx_battery.h>
|
||||
|
||||
#include <linux/w1.h>
|
||||
|
||||
#define W1_FAMILY_BQ27000 0x01
|
||||
|
||||
#define HDQ_CMD_READ (0)
|
||||
#define HDQ_CMD_WRITE (1<<7)
|
||||
|
||||
static int F_ID;
|
||||
module_param(F_ID, int, S_IRUSR);
|
||||
MODULE_PARM_DESC(F_ID, "1-wire slave FID for BQ device");
|
||||
|
||||
static int w1_bq27000_read(struct device *dev, unsigned int reg)
|
||||
{
|
||||
u8 val;
|
||||
struct w1_slave *sl = container_of(dev->parent, struct w1_slave, dev);
|
||||
|
||||
mutex_lock(&sl->master->bus_mutex);
|
||||
w1_write_8(sl->master, HDQ_CMD_READ | reg);
|
||||
val = w1_read_8(sl->master);
|
||||
mutex_unlock(&sl->master->bus_mutex);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static struct bq27xxx_platform_data bq27000_battery_info = {
|
||||
.read = w1_bq27000_read,
|
||||
.name = "bq27000-battery",
|
||||
.chip = BQ27000,
|
||||
};
|
||||
|
||||
static int w1_bq27000_add_slave(struct w1_slave *sl)
|
||||
{
|
||||
int ret;
|
||||
struct platform_device *pdev;
|
||||
|
||||
pdev = platform_device_alloc("bq27000-battery", -1);
|
||||
if (!pdev) {
|
||||
ret = -ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
ret = platform_device_add_data(pdev,
|
||||
&bq27000_battery_info,
|
||||
sizeof(bq27000_battery_info));
|
||||
if (ret)
|
||||
goto pdev_add_failed;
|
||||
pdev->dev.parent = &sl->dev;
|
||||
|
||||
ret = platform_device_add(pdev);
|
||||
if (ret)
|
||||
goto pdev_add_failed;
|
||||
|
||||
dev_set_drvdata(&sl->dev, pdev);
|
||||
|
||||
goto success;
|
||||
|
||||
pdev_add_failed:
|
||||
platform_device_put(pdev);
|
||||
success:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void w1_bq27000_remove_slave(struct w1_slave *sl)
|
||||
{
|
||||
struct platform_device *pdev = dev_get_drvdata(&sl->dev);
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
}
|
||||
|
||||
static struct w1_family_ops w1_bq27000_fops = {
|
||||
.add_slave = w1_bq27000_add_slave,
|
||||
.remove_slave = w1_bq27000_remove_slave,
|
||||
};
|
||||
|
||||
static struct w1_family w1_bq27000_family = {
|
||||
.fid = W1_FAMILY_BQ27000,
|
||||
.fops = &w1_bq27000_fops,
|
||||
};
|
||||
|
||||
static int __init w1_bq27000_init(void)
|
||||
{
|
||||
if (F_ID)
|
||||
w1_bq27000_family.fid = F_ID;
|
||||
|
||||
return w1_register_family(&w1_bq27000_family);
|
||||
}
|
||||
|
||||
static void __exit w1_bq27000_exit(void)
|
||||
{
|
||||
w1_unregister_family(&w1_bq27000_family);
|
||||
}
|
||||
|
||||
module_init(w1_bq27000_init);
|
||||
module_exit(w1_bq27000_exit);
|
||||
|
||||
MODULE_AUTHOR("Texas Instruments Ltd");
|
||||
MODULE_DESCRIPTION("HDQ/1-wire slave driver bq27000 battery monitor chip");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_BQ27000));
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Platform data for the TI bq24190 battery charger driver.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _BQ24190_CHARGER_H_
|
||||
#define _BQ24190_CHARGER_H_
|
||||
|
||||
#include <linux/regulator/machine.h>
|
||||
|
||||
struct bq24190_platform_data {
|
||||
const struct regulator_init_data *regulator_init_data;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -6,6 +6,7 @@ enum bq27xxx_chip {
|
|||
BQ27010, /* bq27010, bq27210 */
|
||||
BQ2750X, /* bq27500 deprecated alias */
|
||||
BQ2751X, /* bq27510, bq27520 deprecated alias */
|
||||
BQ2752X,
|
||||
BQ27500, /* bq27500/1 */
|
||||
BQ27510G1, /* bq27510G1 */
|
||||
BQ27510G2, /* bq27510G2 */
|
||||
|
@ -15,26 +16,16 @@ enum bq27xxx_chip {
|
|||
BQ27520G3, /* bq27520G3 */
|
||||
BQ27520G4, /* bq27520G4 */
|
||||
BQ27530, /* bq27530, bq27531 */
|
||||
BQ27531,
|
||||
BQ27541, /* bq27541, bq27542, bq27546, bq27742 */
|
||||
BQ27542,
|
||||
BQ27546,
|
||||
BQ27742,
|
||||
BQ27545, /* bq27545 */
|
||||
BQ27421, /* bq27421, bq27425, bq27441, bq27621 */
|
||||
};
|
||||
|
||||
/**
|
||||
* struct bq27xxx_plaform_data - Platform data for bq27xxx devices
|
||||
* @name: Name of the battery.
|
||||
* @chip: Chip class number of this device.
|
||||
* @read: HDQ read callback.
|
||||
* This function should provide access to the HDQ bus the battery is
|
||||
* connected to.
|
||||
* The first parameter is a pointer to the battery device, the second the
|
||||
* register to be read. The return value should either be the content of
|
||||
* the passed register or an error value.
|
||||
*/
|
||||
struct bq27xxx_platform_data {
|
||||
const char *name;
|
||||
enum bq27xxx_chip chip;
|
||||
int (*read)(struct device *dev, unsigned int);
|
||||
BQ27425,
|
||||
BQ27441,
|
||||
BQ27621,
|
||||
};
|
||||
|
||||
struct bq27xxx_device_info;
|
||||
|
@ -63,7 +54,7 @@ struct bq27xxx_device_info {
|
|||
struct device *dev;
|
||||
int id;
|
||||
enum bq27xxx_chip chip;
|
||||
bool ram_chip;
|
||||
u32 opts;
|
||||
const char *name;
|
||||
struct bq27xxx_dm_reg *dm_regs;
|
||||
u32 unseal_key;
|
||||
|
|
|
@ -332,6 +332,8 @@ extern int power_supply_get_battery_info(struct power_supply *psy,
|
|||
struct power_supply_battery_info *info);
|
||||
extern void power_supply_changed(struct power_supply *psy);
|
||||
extern int power_supply_am_i_supplied(struct power_supply *psy);
|
||||
extern int power_supply_set_input_current_limit_from_supplier(
|
||||
struct power_supply *psy);
|
||||
extern int power_supply_set_battery_charged(struct power_supply *psy);
|
||||
|
||||
#ifdef CONFIG_POWER_SUPPLY
|
||||
|
|
Loading…
Reference in New Issue