提交 36a1624d 编写于 作者: L Linus Torvalds

Merge tag 'for-4.2' of git://git.infradead.org/battery-2.6

Pull power supply and reset updates from Sebastian Reichel:

 - new charger drivers: BQ24257, BQ25890, AXP288, RT9455

 - MAX17042 battery: add health & temperature support

 - BQ2415x charger: add ACPI support

 - misc fixes and cleanups

* tag 'for-4.2' of git://git.infradead.org/battery-2.6: (32 commits)
  power_supply: Correct kerneldoc copy paste errors
  wm831x_power: Fix off-by-one at free_irq()
  power_supply: rt9455_charger: Fix error reported by static analysis tool
  power_supply: bq24257: use flags argument of devm_gpiod_get
  power_supply: bq25890: use flags argument of devm_gpiod_get
  sbs-battery: add option to always register battery
  power: Add devm_power_supply_get_by_phandle() helper function
  power_supply: max17042: Add OF support for setting thresholds
  power_supply: sysfs: Bring back write to writeable properties
  power_supply: rt9455_charger: Check if CONFIG_USB_PHY is enabled
  power: reset: gpio-restart: increase priority slightly
  power_supply: bq25890: make chip_id int
  power_supply: Add support for Richtek RT9455 battery charger
  Documentation: devicetree: Add Richtek RT9455 bindings
  of: Add vendor prefix for Richtek Technology Corporation
  power_supply: 88pm860x_charger: Do not call free_irq() twice
  power: bq24190_charger: Change first_time flag reset condition
  power: axp288_charger: axp288 charger driver
  power: max17042_battery: add HEALTH and TEMP_* properties support
  power_supply: Add support for TI BQ25890 charger chip
  ...
Binding for TI bq24257 Li-Ion Charger
Required properties:
- compatible: Should contain one of the following:
* "ti,bq24257"
- reg: integer, i2c address of the device.
- ti,battery-regulation-voltage: integer, maximum charging voltage in uV.
- ti,charge-current: integer, maximum charging current in uA.
- ti,termination-current: integer, charge will be terminated when current in
constant-voltage phase drops below this value (in uA).
Example:
bq24257 {
compatible = "ti,bq24257";
reg = <0x6a>;
ti,battery-regulation-voltage = <4200000>;
ti,charge-current = <1000000>;
ti,termination-current = <50000>;
};
Binding for TI bq25890 Li-Ion Charger
Required properties:
- compatible: Should contain one of the following:
* "ti,bq25890"
- reg: integer, i2c address of the device.
- ti,battery-regulation-voltage: integer, maximum charging voltage (in uV);
- ti,charge-current: integer, maximum charging current (in uA);
- ti,termination-current: integer, charge will be terminated when current in
constant-voltage phase drops below this value (in uA);
- ti,precharge-current: integer, maximum charge current during precharge
phase (in uA);
- ti,minimum-sys-voltage: integer, when battery is charging and it is below
minimum system voltage, the system will be regulated above
minimum-sys-voltage setting (in uV);
- ti,boost-voltage: integer, VBUS voltage level in boost mode (in uV);
- ti,boost-max-current: integer, maximum allowed current draw in boost mode
(in uA).
Optional properties:
- ti,boost-low-freq: boolean, if present boost mode frequency will be 500kHz,
otherwise 1.5MHz;
- ti,use-ilim-pin: boolean, if present the ILIM resistor will be used and the
input current will be the lower between the resistor setting and the IINLIM
register setting;
- ti,thermal-regulation-threshold: integer, temperature above which the charge
current is lowered, to avoid overheating (in degrees Celsius). If omitted,
the default setting will be used (120 degrees);
Example:
bq25890 {
compatible = "ti,bq25890";
reg = <0x6a>;
ti,battery-regulation-voltage = <4200000>;
ti,charge-current = <1000000>;
ti,termination-current = <50000>;
ti,precharge-current = <128000>;
ti,minimum-sys-voltage = <3600000>;
ti,boost-voltage = <5000000>;
ti,boost-max-current = <1000000>;
ti,use-ilim-pin;
ti,thermal-regulation-threshold = <120>;
};
Binding for Richtek rt9455 battery charger
Required properties:
- compatible: it should contain one of the following:
"richtek,rt9455".
- reg: integer, i2c address of the device.
- interrupt-parent: the phandle for the interrupt controller that
services interrupts for this device.
- interrupts: interrupt mapping for GPIO IRQ, it should be
configured with IRQ_TYPE_LEVEL_LOW flag.
- richtek,output-charge-current: integer, output current from the charger to the
battery, in uA.
- richtek,end-of-charge-percentage: integer, percent of the output charge current.
When the current in constant-voltage phase drops
below output_charge_current x end-of-charge-percentage,
charge is terminated.
- richtek,battery-regulation-voltage: integer, maximum battery voltage in uV.
- richtek,boost-output-voltage: integer, maximum voltage provided to consumer
devices, when the charger is in boost mode, in uV.
Optional properties:
- richtek,min-input-voltage-regulation: integer, input voltage level in uV, used to
decrease voltage level when the over current
of the input power source occurs.
This prevents input voltage drop due to insufficient
current provided by the power source.
Default: 4500000 uV (4.5V)
- richtek,avg-input-current-regulation: integer, input current value in uA drained by the
charger from the power source.
Default: 500000 uA (500mA)
Example:
rt9455@22 {
compatible = "richtek,rt9455";
reg = <0x22>;
interrupt-parent = <&gpio1>;
interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
richtek,output-charge-current = <500000>;
richtek,end-of-charge-percentage = <10>;
richtek,battery-regulation-voltage = <4200000>;
richtek,boost-output-voltage = <5050000>;
richtek,min-input-voltage-regulation = <4500000>;
richtek,avg-input-current-regulation = <500000>;
};
......@@ -9,10 +9,23 @@ Optional properties :
(datasheet-recommended value is 10000).
Defining this property enables current-sense functionality.
Optional threshold properties :
If skipped the condition won't be reported.
- maxim,cold-temp : Temperature threshold to report battery
as cold (in tenths of degree Celsius).
- maxim,over-heat-temp : Temperature threshold to report battery
as over heated (in tenths of degree Celsius).
- maxim,dead-volt : Voltage threshold to report battery
as dead (in mV).
- maxim,over-volt : Voltage threshold to report battery
as over voltage (in mV).
Example:
battery-charger@36 {
compatible = "maxim,max17042";
reg = <0x36>;
maxim,rsns-microohm = <10000>;
maxim,over-heat-temp = <600>;
maxim,over-volt = <4300>;
};
......@@ -161,6 +161,7 @@ ralink Mediatek/Ralink Technology Corp.
ramtron Ramtron International
realtek Realtek Semiconductor Corp.
renesas Renesas Electronics Corporation
richtek Richtek Technology Corporation
ricoh Ricoh Co. Ltd.
rockchip Fuzhou Rockchip Electronics Co., Ltd
samsung Samsung Semiconductor
......
......@@ -742,7 +742,6 @@ static int pm860x_charger_remove(struct platform_device *pdev)
int i;
power_supply_unregister(info->usb);
free_irq(info->irq[0], info);
for (i = 0; i < info->irq_nums; i++)
free_irq(info->irq[i], info);
return 0;
......
......@@ -204,6 +204,13 @@ config CHARGER_DA9150
This driver can also be built as a module. If so, the module will be
called da9150-charger.
config AXP288_CHARGER
tristate "X-Powers AXP288 Charger"
depends on MFD_AXP20X && EXTCON_AXP288
help
Say yes here to have support X-Power AXP288 power management IC (PMIC)
integrated charger.
config AXP288_FUEL_GAUGE
tristate "X-Powers AXP288 Fuel Gauge"
depends on MFD_AXP20X && IIO
......@@ -388,12 +395,26 @@ config CHARGER_BQ24190
help
Say Y to enable support for the TI BQ24190 battery charger.
config CHARGER_BQ24257
tristate "TI BQ24257 battery charger driver"
depends on I2C && GPIOLIB
depends on REGMAP_I2C
help
Say Y to enable support for the TI BQ24257 battery charger.
config CHARGER_BQ24735
tristate "TI BQ24735 battery charger support"
depends on I2C && GPIOLIB
help
Say Y to enable support for the TI BQ24735 battery charger.
config CHARGER_BQ25890
tristate "TI BQ25890 battery charger driver"
depends on I2C && GPIOLIB
select REGMAP_I2C
help
Say Y to enable support for the TI BQ25890 battery charger.
config CHARGER_SMB347
tristate "Summit Microelectronics SMB347 Battery Charger"
depends on I2C
......@@ -439,6 +460,13 @@ config BATTERY_RT5033
The fuelgauge calculates and determines the battery state of charge
according to battery open circuit voltage.
config CHARGER_RT9455
tristate "Richtek RT9455 battery charger driver"
depends on I2C && GPIOLIB
select REGMAP_I2C
help
Say Y to enable support for Richtek RT9455 battery charger.
source "drivers/power/reset/Kconfig"
endif # POWER_SUPPLY
......
......@@ -37,6 +37,7 @@ obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
obj-$(CONFIG_BATTERY_Z2) += z2_battery.o
obj-$(CONFIG_BATTERY_RT5033) += rt5033_battery.o
obj-$(CONFIG_CHARGER_RT9455) += rt9455_charger.o
obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o
obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o
obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o
......@@ -58,9 +59,12 @@ obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o
obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o
obj-$(CONFIG_CHARGER_BQ24257) += bq24257_charger.o
obj-$(CONFIG_CHARGER_BQ24735) += bq24735-charger.o
obj-$(CONFIG_CHARGER_BQ25890) += bq25890_charger.o
obj-$(CONFIG_POWER_AVS) += avs/
obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o
obj-$(CONFIG_POWER_RESET) += reset/
obj-$(CONFIG_AXP288_FUEL_GAUGE) += axp288_fuel_gauge.o
obj-$(CONFIG_AXP288_CHARGER) += axp288_charger.o
此差异已折叠。
......@@ -1117,7 +1117,7 @@ static int axp288_fuel_gauge_probe(struct platform_device *pdev)
return ret;
}
static struct platform_device_id axp288_fg_id_table[] = {
static const struct platform_device_id axp288_fg_id_table[] = {
{ .name = DEV_NAME },
{},
};
......
......@@ -35,6 +35,7 @@
#include <linux/idr.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/power/bq2415x_charger.h>
......@@ -631,7 +632,7 @@ static int bq2415x_set_charge_current(struct bq2415x_device *bq, int mA)
int val;
if (bq->init_data.resistor_sense <= 0)
return -ENOSYS;
return -EINVAL;
val = (mA * bq->init_data.resistor_sense - 37400) / 6800;
if (val < 0)
......@@ -650,7 +651,7 @@ static int bq2415x_get_charge_current(struct bq2415x_device *bq)
int ret;
if (bq->init_data.resistor_sense <= 0)
return -ENOSYS;
return -EINVAL;
ret = bq2415x_i2c_read_mask(bq, BQ2415X_REG_CURRENT,
BQ2415X_MASK_VI_CHRG, BQ2415X_SHIFT_VI_CHRG);
......@@ -665,7 +666,7 @@ static int bq2415x_set_termination_current(struct bq2415x_device *bq, int mA)
int val;
if (bq->init_data.resistor_sense <= 0)
return -ENOSYS;
return -EINVAL;
val = (mA * bq->init_data.resistor_sense - 3400) / 3400;
if (val < 0)
......@@ -684,7 +685,7 @@ static int bq2415x_get_termination_current(struct bq2415x_device *bq)
int ret;
if (bq->init_data.resistor_sense <= 0)
return -ENOSYS;
return -EINVAL;
ret = bq2415x_i2c_read_mask(bq, BQ2415X_REG_CURRENT,
BQ2415X_MASK_VI_TERM, BQ2415X_SHIFT_VI_TERM);
......@@ -1166,7 +1167,7 @@ static ssize_t bq2415x_sysfs_set_mode(struct device *dev,
if (strncmp(buf, "auto", 4) == 0) {
if (bq->automode < 0)
return -ENOSYS;
return -EINVAL;
bq->automode = 1;
mode = bq->reported_mode;
} else if (strncmp(buf, "off", 3) == 0) {
......@@ -1530,13 +1531,14 @@ static int bq2415x_probe(struct i2c_client *client,
{
int ret;
int num;
char *name;
char *name = NULL;
struct bq2415x_device *bq;
struct device_node *np = client->dev.of_node;
struct bq2415x_platform_data *pdata = client->dev.platform_data;
const struct acpi_device_id *acpi_id = NULL;
if (!np && !pdata) {
dev_err(&client->dev, "platform data missing\n");
if (!np && !pdata && !ACPI_HANDLE(&client->dev)) {
dev_err(&client->dev, "Neither devicetree, nor platform data, nor ACPI support\n");
return -ENODEV;
}
......@@ -1547,7 +1549,14 @@ static int bq2415x_probe(struct i2c_client *client,
if (num < 0)
return num;
name = kasprintf(GFP_KERNEL, "%s-%d", id->name, num);
if (id) {
name = kasprintf(GFP_KERNEL, "%s-%d", id->name, num);
} else if (ACPI_HANDLE(&client->dev)) {
acpi_id =
acpi_match_device(client->dev.driver->acpi_match_table,
&client->dev);
name = kasprintf(GFP_KERNEL, "%s-%d", acpi_id->id, num);
}
if (!name) {
dev_err(&client->dev, "failed to allocate device name\n");
ret = -ENOMEM;
......@@ -1556,63 +1565,72 @@ static int bq2415x_probe(struct i2c_client *client,
bq = devm_kzalloc(&client->dev, sizeof(*bq), GFP_KERNEL);
if (!bq) {
dev_err(&client->dev, "failed to allocate device data\n");
ret = -ENOMEM;
goto error_2;
}
if (np) {
bq->notify_psy = power_supply_get_by_phandle(np, "ti,usb-charger-detection");
bq->notify_psy = power_supply_get_by_phandle(np,
"ti,usb-charger-detection");
if (IS_ERR(bq->notify_psy)) {
dev_info(&client->dev,
"no 'ti,usb-charger-detection' property (err=%ld)\n",
"no 'ti,usb-charger-detection' property (err=%ld)\n",
PTR_ERR(bq->notify_psy));
bq->notify_psy = NULL;
} else if (!bq->notify_psy) {
ret = -EPROBE_DEFER;
goto error_2;
}
}
else if (pdata->notify_device)
} else if (pdata && pdata->notify_device) {
bq->notify_psy = power_supply_get_by_name(pdata->notify_device);
else
} else {
bq->notify_psy = NULL;
}
i2c_set_clientdata(client, bq);
bq->id = num;
bq->dev = &client->dev;
bq->chip = id->driver_data;
if (id)
bq->chip = id->driver_data;
else if (ACPI_HANDLE(bq->dev))
bq->chip = acpi_id->driver_data;
bq->name = name;
bq->mode = BQ2415X_MODE_OFF;
bq->reported_mode = BQ2415X_MODE_OFF;
bq->autotimer = 0;
bq->automode = 0;
if (np) {
ret = of_property_read_u32(np, "ti,current-limit",
&bq->init_data.current_limit);
if (np || ACPI_HANDLE(bq->dev)) {
ret = device_property_read_u32(bq->dev,
"ti,current-limit",
&bq->init_data.current_limit);
if (ret)
goto error_3;
ret = of_property_read_u32(np, "ti,weak-battery-voltage",
&bq->init_data.weak_battery_voltage);
ret = device_property_read_u32(bq->dev,
"ti,weak-battery-voltage",
&bq->init_data.weak_battery_voltage);
if (ret)
goto error_3;
ret = of_property_read_u32(np, "ti,battery-regulation-voltage",
ret = device_property_read_u32(bq->dev,
"ti,battery-regulation-voltage",
&bq->init_data.battery_regulation_voltage);
if (ret)
goto error_3;
ret = of_property_read_u32(np, "ti,charge-current",
&bq->init_data.charge_current);
ret = device_property_read_u32(bq->dev,
"ti,charge-current",
&bq->init_data.charge_current);
if (ret)
goto error_3;
ret = of_property_read_u32(np, "ti,termination-current",
ret = device_property_read_u32(bq->dev,
"ti,termination-current",
&bq->init_data.termination_current);
if (ret)
goto error_3;
ret = of_property_read_u32(np, "ti,resistor-sense",
&bq->init_data.resistor_sense);
ret = device_property_read_u32(bq->dev,
"ti,resistor-sense",
&bq->init_data.resistor_sense);
if (ret)
goto error_3;
} else {
......@@ -1648,7 +1666,8 @@ static int bq2415x_probe(struct i2c_client *client,
}
/* Query for initial reported_mode and set it */
bq2415x_notifier_call(&bq->nb, PSY_EVENT_PROP_CHANGED, bq->notify_psy);
bq2415x_notifier_call(&bq->nb, PSY_EVENT_PROP_CHANGED,
bq->notify_psy);
bq2415x_set_mode(bq, bq->reported_mode);
bq->automode = 1;
......@@ -1727,9 +1746,28 @@ static const struct i2c_device_id bq2415x_i2c_id_table[] = {
};
MODULE_DEVICE_TABLE(i2c, bq2415x_i2c_id_table);
static const struct acpi_device_id bq2415x_i2c_acpi_match[] = {
{ "BQ2415X", BQUNKNOWN },
{ "BQ241500", BQ24150 },
{ "BQA24150", BQ24150A },
{ "BQ241510", BQ24151 },
{ "BQA24151", BQ24151A },
{ "BQ241520", BQ24152 },
{ "BQ241530", BQ24153 },
{ "BQA24153", BQ24153A },
{ "BQ241550", BQ24155 },
{ "BQ241560", BQ24156 },
{ "BQA24156", BQ24156A },
{ "BQS24157", BQ24157S },
{ "BQ241580", BQ24158 },
{},
};
MODULE_DEVICE_TABLE(acpi, bq2415x_i2c_acpi_match);
static struct i2c_driver bq2415x_driver = {
.driver = {
.name = "bq2415x-charger",
.acpi_match_table = ACPI_PTR(bq2415x_i2c_acpi_match),
},
.probe = bq2415x_probe,
.remove = bq2415x_remove,
......
......@@ -1258,10 +1258,13 @@ static irqreturn_t bq24190_irq_handler_thread(int irq, void *data)
* register reset so we should ignore that one (the very first
* interrupt received).
*/
if (alert_userspace && !bdi->first_time) {
power_supply_changed(bdi->charger);
power_supply_changed(bdi->battery);
bdi->first_time = false;
if (alert_userspace) {
if (!bdi->first_time) {
power_supply_changed(bdi->charger);
power_supply_changed(bdi->battery);
} else {
bdi->first_time = false;
}
}
out:
......
此差异已折叠。
此差异已折叠。
......@@ -1768,7 +1768,8 @@ static int charger_manager_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&cm->fullbatt_vchk_work, fullbatt_vchk);
cm->charger_psy = power_supply_register(NULL, &cm->charger_psy_desc,
cm->charger_psy = power_supply_register(&pdev->dev,
&cm->charger_psy_desc,
&psy_cfg);
if (IS_ERR(cm->charger_psy)) {
dev_err(&pdev->dev, "Cannot register charger-manager with name \"%s\"\n",
......
......@@ -63,6 +63,8 @@
#define dP_ACC_100 0x1900
#define dP_ACC_200 0x3200
#define MAX17042_VMAX_TOLERANCE 50 /* 50 mV */
struct max17042_chip {
struct i2c_client *client;
struct regmap *regmap;
......@@ -85,10 +87,94 @@ static enum power_supply_property max17042_battery_props[] = {
POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_COUNTER,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_TEMP_ALERT_MIN,
POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
POWER_SUPPLY_PROP_TEMP_MIN,
POWER_SUPPLY_PROP_TEMP_MAX,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CURRENT_AVG,
};
static int max17042_get_temperature(struct max17042_chip *chip, int *temp)
{
int ret;
u32 data;
struct regmap *map = chip->regmap;
ret = regmap_read(map, MAX17042_TEMP, &data);
if (ret < 0)
return ret;
*temp = data;
/* The value is signed. */
if (*temp & 0x8000) {
*temp = (0x7fff & ~*temp) + 1;
*temp *= -1;
}
/* The value is converted into deci-centigrade scale */
/* Units of LSB = 1 / 256 degree Celsius */
*temp = *temp * 10 / 256;
return 0;
}
static int max17042_get_battery_health(struct max17042_chip *chip, int *health)
{
int temp, vavg, vbatt, ret;
u32 val;
ret = regmap_read(chip->regmap, MAX17042_AvgVCELL, &val);
if (ret < 0)
goto health_error;
/* bits [0-3] unused */
vavg = val * 625 / 8;
/* Convert to millivolts */
vavg /= 1000;
ret = regmap_read(chip->regmap, MAX17042_VCELL, &val);
if (ret < 0)
goto health_error;
/* bits [0-3] unused */
vbatt = val * 625 / 8;
/* Convert to millivolts */
vbatt /= 1000;
if (vavg < chip->pdata->vmin) {
*health = POWER_SUPPLY_HEALTH_DEAD;
goto out;
}
if (vbatt > chip->pdata->vmax + MAX17042_VMAX_TOLERANCE) {
*health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
goto out;
}
ret = max17042_get_temperature(chip, &temp);
if (ret < 0)
goto health_error;
if (temp <= chip->pdata->temp_min) {
*health = POWER_SUPPLY_HEALTH_COLD;
goto out;
}
if (temp >= chip->pdata->temp_max) {
*health = POWER_SUPPLY_HEALTH_OVERHEAT;
goto out;
}
*health = POWER_SUPPLY_HEALTH_GOOD;
out:
return 0;
health_error:
return ret;
}
static int max17042_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
......@@ -181,19 +267,34 @@ static int max17042_get_property(struct power_supply *psy,
val->intval = data * 1000 / 2;
break;
case POWER_SUPPLY_PROP_TEMP:
ret = regmap_read(map, MAX17042_TEMP, &data);
ret = max17042_get_temperature(chip, &val->intval);
if (ret < 0)
return ret;
break;
case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
ret = regmap_read(map, MAX17042_TALRT_Th, &data);
if (ret < 0)
return ret;
/* LSB is Alert Minimum. In deci-centigrade */
val->intval = (data & 0xff) * 10;
break;
case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
ret = regmap_read(map, MAX17042_TALRT_Th, &data);
if (ret < 0)
return ret;
/* MSB is Alert Maximum. In deci-centigrade */
val->intval = (data >> 8) * 10;
break;
case POWER_SUPPLY_PROP_TEMP_MIN:
val->intval = chip->pdata->temp_min;
break;
case POWER_SUPPLY_PROP_TEMP_MAX:
val->intval = chip->pdata->temp_max;
break;
case POWER_SUPPLY_PROP_HEALTH:
ret = max17042_get_battery_health(chip, &val->intval);
if (ret < 0)
return ret;
val->intval = data;
/* The value is signed. */
if (val->intval & 0x8000) {
val->intval = (0x7fff & ~val->intval) + 1;
val->intval *= -1;
}
/* The value is converted into deci-centigrade scale */
/* Units of LSB = 1 / 256 degree Celsius */
val->intval = val->intval * 10 / 256;
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
if (chip->pdata->enable_current_sense) {
......@@ -237,6 +338,69 @@ static int max17042_get_property(struct power_supply *psy,
return 0;
}
static int max17042_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
struct max17042_chip *chip = power_supply_get_drvdata(psy);
struct regmap *map = chip->regmap;
int ret = 0;
u32 data;
int8_t temp;
switch (psp) {
case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
ret = regmap_read(map, MAX17042_TALRT_Th, &data);
if (ret < 0)
return ret;
/* Input in deci-centigrade, convert to centigrade */
temp = val->intval / 10;
/* force min < max */
if (temp >= (int8_t)(data >> 8))
temp = (int8_t)(data >> 8) - 1;
/* Write both MAX and MIN ALERT */
data = (data & 0xff00) + temp;
ret = regmap_write(map, MAX17042_TALRT_Th, data);
break;
case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
ret = regmap_read(map, MAX17042_TALRT_Th, &data);
if (ret < 0)
return ret;
/* Input in Deci-Centigrade, convert to centigrade */
temp = val->intval / 10;
/* force max > min */
if (temp <= (int8_t)(data & 0xff))
temp = (int8_t)(data & 0xff) + 1;
/* Write both MAX and MIN ALERT */
data = (data & 0xff) + (temp << 8);
ret = regmap_write(map, MAX17042_TALRT_Th, data);
break;
default:
ret = -EINVAL;
}
return ret;
}
static int max17042_property_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
int ret;
switch (psp) {
case POWER_SUPPLY_PROP_TEMP_ALERT_MIN:
case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
ret = 1;
break;
default:
ret = 0;
}
return ret;
}
static int max17042_write_verify_reg(struct regmap *map, u8 reg, u32 value)
{
int retries = 8;
......@@ -645,6 +809,15 @@ max17042_get_pdata(struct device *dev)
pdata->enable_current_sense = true;
}
if (of_property_read_s32(np, "maxim,cold-temp", &pdata->temp_min))
pdata->temp_min = INT_MIN;
if (of_property_read_s32(np, "maxim,over-heat-temp", &pdata->temp_max))
pdata->temp_max = INT_MAX;
if (of_property_read_s32(np, "maxim,dead-volt", &pdata->vmin))
pdata->vmin = INT_MIN;
if (of_property_read_s32(np, "maxim,over-volt", &pdata->vmax))
pdata->vmax = INT_MAX;
return pdata;
}
#else
......@@ -665,6 +838,8 @@ static const struct power_supply_desc max17042_psy_desc = {
.name = "max170xx_battery",
.type = POWER_SUPPLY_TYPE_BATTERY,
.get_property = max17042_get_property,
.set_property = max17042_set_property,
.property_is_writeable = max17042_property_is_writeable,
.properties = max17042_battery_props,
.num_properties = ARRAY_SIZE(max17042_battery_props),
};
......@@ -673,6 +848,8 @@ static const struct power_supply_desc max17042_no_current_sense_psy_desc = {
.name = "max170xx_battery",
.type = POWER_SUPPLY_TYPE_BATTERY,
.get_property = max17042_get_property,
.set_property = max17042_set_property,
.property_is_writeable = max17042_property_is_writeable,
.properties = max17042_battery_props,
.num_properties = ARRAY_SIZE(max17042_battery_props) - 2,
};
......
......@@ -30,6 +30,8 @@ EXPORT_SYMBOL_GPL(power_supply_notifier);
static struct device_type power_supply_dev_type;
#define POWER_SUPPLY_DEFERRED_REGISTER_TIME msecs_to_jiffies(10)
static bool __power_supply_is_supplied_by(struct power_supply *supplier,
struct power_supply *supply)
{
......@@ -121,6 +123,30 @@ void power_supply_changed(struct power_supply *psy)
}
EXPORT_SYMBOL_GPL(power_supply_changed);
/*
* Notify that power supply was registered after parent finished the probing.
*
* Often power supply is registered from driver's probe function. However
* calling power_supply_changed() directly from power_supply_register()
* would lead to execution of get_property() function provided by the driver
* too early - before the probe ends.
*
* Avoid that by waiting on parent's mutex.
*/
static void power_supply_deferred_register_work(struct work_struct *work)
{
struct power_supply *psy = container_of(work, struct power_supply,
deferred_register_work.work);
if (psy->dev.parent)
mutex_lock(&psy->dev.parent->mutex);
power_supply_changed(psy);
if (psy->dev.parent)
mutex_unlock(&psy->dev.parent->mutex);
}
#ifdef CONFIG_OF
#include <linux/of.h>
......@@ -420,6 +446,45 @@ struct power_supply *power_supply_get_by_phandle(struct device_node *np,
return psy;
}
EXPORT_SYMBOL_GPL(power_supply_get_by_phandle);
static void devm_power_supply_put(struct device *dev, void *res)
{
struct power_supply **psy = res;
power_supply_put(*psy);
}
/**
* devm_power_supply_get_by_phandle() - Resource managed version of
* power_supply_get_by_phandle()
* @dev: Pointer to device holding phandle property
* @phandle_name: Name of property holding a power supply phandle
*
* Return: On success returns a reference to a power supply with
* matching name equals to value under @property, NULL or ERR_PTR otherwise.
*/
struct power_supply *devm_power_supply_get_by_phandle(struct device *dev,
const char *property)
{
struct power_supply **ptr, *psy;
if (!dev->of_node)
return ERR_PTR(-ENODEV);
ptr = devres_alloc(devm_power_supply_put, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return ERR_PTR(-ENOMEM);
psy = power_supply_get_by_phandle(dev->of_node, property);
if (IS_ERR_OR_NULL(psy)) {
devres_free(ptr);
} else {
*ptr = psy;
devres_add(dev, ptr);
}
return psy;
}
EXPORT_SYMBOL_GPL(devm_power_supply_get_by_phandle);
#endif /* CONFIG_OF */
int power_supply_get_property(struct power_supply *psy,
......@@ -645,6 +710,10 @@ __power_supply_register(struct device *parent,
struct power_supply *psy;
int rc;
if (!parent)
pr_warn("%s: Expected proper parent device for '%s'\n",
__func__, desc->name);
psy = kzalloc(sizeof(*psy), GFP_KERNEL);
if (!psy)
return ERR_PTR(-ENOMEM);
......@@ -659,7 +728,6 @@ __power_supply_register(struct device *parent,
dev->release = power_supply_dev_release;
dev_set_drvdata(dev, psy);
psy->desc = desc;
atomic_inc(&psy->use_cnt);
if (cfg) {
psy->drv_data = cfg->drv_data;
psy->of_node = cfg->of_node;
......@@ -672,6 +740,8 @@ __power_supply_register(struct device *parent,
goto dev_set_name_failed;
INIT_WORK(&psy->changed_work, power_supply_changed_work);
INIT_DELAYED_WORK(&psy->deferred_register_work,
power_supply_deferred_register_work);
rc = power_supply_check_supplies(psy);
if (rc) {
......@@ -700,7 +770,20 @@ __power_supply_register(struct device *parent,
if (rc)
goto create_triggers_failed;
power_supply_changed(psy);
/*
* Update use_cnt after any uevents (most notably from device_add()).
* We are here still during driver's probe but
* the power_supply_uevent() calls back driver's get_property
* method so:
* 1. Driver did not assigned the returned struct power_supply,
* 2. Driver could not finish initialization (anything in its probe
* after calling power_supply_register()).
*/
atomic_inc(&psy->use_cnt);
queue_delayed_work(system_power_efficient_wq,
&psy->deferred_register_work,
POWER_SUPPLY_DEFERRED_REGISTER_TIME);
return psy;
......@@ -720,7 +803,8 @@ __power_supply_register(struct device *parent,
/**
* power_supply_register() - Register new power supply
* @parent: Device to be a parent of power supply's device
* @parent: Device to be a parent of power supply's device, usually
* the device which probe function calls this
* @desc: Description of power supply, must be valid through whole
* lifetime of this power supply
* @cfg: Run-time specific configuration accessed during registering,
......@@ -740,8 +824,9 @@ struct power_supply *__must_check power_supply_register(struct device *parent,
EXPORT_SYMBOL_GPL(power_supply_register);
/**
* power_supply_register() - Register new non-waking-source power supply
* @parent: Device to be a parent of power supply's device
* power_supply_register_no_ws() - Register new non-waking-source power supply
* @parent: Device to be a parent of power supply's device, usually
* the device which probe function calls this
* @desc: Description of power supply, must be valid through whole
* lifetime of this power supply
* @cfg: Run-time specific configuration accessed during registering,
......@@ -769,8 +854,9 @@ static void devm_power_supply_release(struct device *dev, void *res)
}
/**
* power_supply_register() - Register managed power supply
* @parent: Device to be a parent of power supply's device
* devm_power_supply_register() - Register managed power supply
* @parent: Device to be a parent of power supply's device, usually
* the device which probe function calls this
* @desc: Description of power supply, must be valid through whole
* lifetime of this power supply
* @cfg: Run-time specific configuration accessed during registering,
......@@ -804,8 +890,9 @@ devm_power_supply_register(struct device *parent,
EXPORT_SYMBOL_GPL(devm_power_supply_register);
/**
* power_supply_register() - Register managed non-waking-source power supply
* @parent: Device to be a parent of power supply's device
* devm_power_supply_register_no_ws() - Register managed non-waking-source power supply
* @parent: Device to be a parent of power supply's device, usually
* the device which probe function calls this
* @desc: Description of power supply, must be valid through whole
* lifetime of this power supply
* @cfg: Run-time specific configuration accessed during registering,
......@@ -849,6 +936,7 @@ void power_supply_unregister(struct power_supply *psy)
{
WARN_ON(atomic_dec_return(&psy->use_cnt));
cancel_work_sync(&psy->changed_work);
cancel_delayed_work_sync(&psy->deferred_register_work);
sysfs_remove_link(&psy->dev.kobj, "powers");
power_supply_remove_triggers(psy);
psy_unregister_cooler(psy);
......
......@@ -25,7 +25,7 @@ static void power_supply_update_bat_leds(struct power_supply *psy)
unsigned long delay_on = 0;
unsigned long delay_off = 0;
if (psy->desc->get_property(psy, POWER_SUPPLY_PROP_STATUS, &status))
if (power_supply_get_property(psy, POWER_SUPPLY_PROP_STATUS, &status))
return;
dev_dbg(&psy->dev, "%s %d\n", __func__, status.intval);
......@@ -115,7 +115,7 @@ static void power_supply_update_gen_leds(struct power_supply *psy)
{
union power_supply_propval online;
if (psy->desc->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online))
if (power_supply_get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online))
return;
dev_dbg(&psy->dev, "%s %d\n", __func__, online.intval);
......
......@@ -125,7 +125,7 @@ static ssize_t power_supply_store_property(struct device *dev,
value.intval = long_val;
ret = psy->desc->set_property(psy, off, &value);
ret = power_supply_set_property(psy, off, &value);
if (ret < 0)
return ret;
......@@ -223,7 +223,7 @@ static umode_t power_supply_attr_is_visible(struct kobject *kobj,
if (property == attrno) {
if (psy->desc->property_is_writeable &&
power_supply_property_is_writeable(psy, property) > 0)
psy->desc->property_is_writeable(psy, property) > 0)
mode |= S_IWUSR;
return mode;
......
......@@ -243,7 +243,7 @@ static int at91_reset_probe(struct platform_device *pdev)
return 0;
}
static struct platform_device_id at91_reset_plat_match[] = {
static const struct platform_device_id at91_reset_plat_match[] = {
{ "at91-sam9260-reset", (unsigned long)at91sam9260_restart },
{ "at91-sam9g45-reset", (unsigned long)at91sam9g45_restart },
{ /* sentinel */ }
......
......@@ -48,6 +48,7 @@ static void gpio_poweroff_do_poweroff(void)
static int gpio_poweroff_probe(struct platform_device *pdev)
{
bool input = false;
enum gpiod_flags flags;
/* If a pm_power_off function has already been added, leave it alone */
if (pm_power_off != NULL) {
......@@ -57,25 +58,15 @@ static int gpio_poweroff_probe(struct platform_device *pdev)
return -EBUSY;
}
reset_gpio = devm_gpiod_get(&pdev->dev, NULL);
if (IS_ERR(reset_gpio))
return PTR_ERR(reset_gpio);
input = of_property_read_bool(pdev->dev.of_node, "input");
if (input)
flags = GPIOD_IN;
else
flags = GPIOD_OUT_LOW;
if (input) {
if (gpiod_direction_input(reset_gpio)) {
dev_err(&pdev->dev,
"Could not set direction of reset GPIO to input\n");
return -ENODEV;
}
} else {
if (gpiod_direction_output(reset_gpio, 0)) {
dev_err(&pdev->dev,
"Could not set direction of reset GPIO\n");
return -ENODEV;
}
}
reset_gpio = devm_gpiod_get(&pdev->dev, NULL, flags);
if (IS_ERR(reset_gpio))
return PTR_ERR(reset_gpio);
pm_power_off = &gpio_poweroff_do_poweroff;
return 0;
......
......@@ -78,7 +78,7 @@ static int gpio_restart_probe(struct platform_device *pdev)
}
gpio_restart->restart_handler.notifier_call = gpio_restart_notify;
gpio_restart->restart_handler.priority = 128;
gpio_restart->restart_handler.priority = 129;
gpio_restart->active_delay_ms = 100;
gpio_restart->inactive_delay_ms = 100;
gpio_restart->wait_delay_ms = 3000;
......
......@@ -201,16 +201,15 @@ static int ltc2952_poweroff_init(struct platform_device *pdev)
return ret;
}
data->gpio_trigger = devm_gpiod_get(&pdev->dev, "trigger", GPIOD_IN);
data->gpio_trigger = devm_gpiod_get_optional(&pdev->dev, "trigger",
GPIOD_IN);
if (IS_ERR(data->gpio_trigger)) {
/*
* It's not a problem if the trigger gpio isn't available, but
* it is worth a warning if its use was defined in the device
* tree.
*/
if (PTR_ERR(data->gpio_trigger) != -ENOENT)
dev_err(&pdev->dev,
"unable to claim gpio \"trigger\"\n");
dev_err(&pdev->dev, "unable to claim gpio \"trigger\"\n");
data->gpio_trigger = NULL;
}
......
此差异已折叠。
......@@ -28,6 +28,7 @@
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/stat.h>
#include <linux/power/sbs-battery.h>
......@@ -170,6 +171,7 @@ struct sbs_info {
static char model_name[I2C_SMBUS_BLOCK_MAX + 1];
static char manufacturer[I2C_SMBUS_BLOCK_MAX + 1];
static bool force_load;
static int sbs_read_word_data(struct i2c_client *client, u8 address)
{
......@@ -885,14 +887,17 @@ static int sbs_probe(struct i2c_client *client,
skip_gpio:
/*
* Before we register, we need to make sure we can actually talk
* Before we register, we might need to make sure we can actually talk
* to the battery.
*/
rc = sbs_read_word_data(client, sbs_data[REG_STATUS].addr);
if (rc < 0) {
dev_err(&client->dev, "%s: Failed to get device status\n",
__func__);
goto exit_psupply;
if (!force_load) {
rc = sbs_read_word_data(client, sbs_data[REG_STATUS].addr);
if (rc < 0) {
dev_err(&client->dev, "%s: Failed to get device status\n",
__func__);
goto exit_psupply;
}
}
chip->power_supply = power_supply_register(&client->dev, sbs_desc,
......@@ -991,3 +996,7 @@ module_i2c_driver(sbs_battery_driver);
MODULE_DESCRIPTION("SBS battery monitor driver");
MODULE_LICENSE("GPL");
module_param(force_load, bool, S_IRUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(force_load,
"Attempt to load the driver even if no battery is connected");
......@@ -609,6 +609,7 @@ static int wm831x_power_probe(struct platform_device *pdev)
return ret;
err_bat_irq:
--i;
for (; i >= 0; i--) {
irq = platform_get_irq_byname(pdev, wm831x_bat_irqs[i]);
free_irq(irq, power);
......
......@@ -275,4 +275,11 @@ struct axp20x_fg_pdata {
int thermistor_curve[MAX_THERM_CURVE_SIZE][2];
};
struct axp20x_chrg_pdata {
int max_cc;
int max_cv;
int def_cc;
int def_cv;
};
#endif /* __LINUX_MFD_AXP20X_H */
......@@ -215,6 +215,10 @@ struct max17042_platform_data {
* the datasheet although it can be changed by board designers.
*/
unsigned int r_sns;
int vmin; /* in millivolts */
int vmax; /* in millivolts */
int temp_min; /* in tenths of degree Celsius */
int temp_max; /* in tenths of degree Celsius */
};
#endif /* __MAX17042_BATTERY_H_ */
......@@ -206,6 +206,11 @@ struct power_supply_desc {
int (*set_property)(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val);
/*
* property_is_writeable() will be called during registration
* of power supply. If this happens during device probe then it must
* not access internal data of device (because probe did not end).
*/
int (*property_is_writeable)(struct power_supply *psy,
enum power_supply_property psp);
void (*external_power_changed)(struct power_supply *psy);
......@@ -237,6 +242,7 @@ struct power_supply {
/* private */
struct device dev;
struct work_struct changed_work;
struct delayed_work deferred_register_work;
spinlock_t changed_lock;
bool changed;
atomic_t use_cnt;
......@@ -286,10 +292,15 @@ extern void power_supply_put(struct power_supply *psy);
#ifdef CONFIG_OF
extern struct power_supply *power_supply_get_by_phandle(struct device_node *np,
const char *property);
extern struct power_supply *devm_power_supply_get_by_phandle(
struct device *dev, const char *property);
#else /* !CONFIG_OF */
static inline struct power_supply *
power_supply_get_by_phandle(struct device_node *np, const char *property)
{ return NULL; }
static inline struct power_supply *
devm_power_supply_get_by_phandle(struct device *dev, const char *property)
{ return NULL; }
#endif /* CONFIG_OF */
extern void power_supply_changed(struct power_supply *psy);
extern int power_supply_am_i_supplied(struct power_supply *psy);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册