1
0
Fork 0

power supply and reset changes for the v4.6 series

* add types for USB Type C and PD chargers
  * add act8945a charger driver
  * add ACPI/DT bindings for goldfish-battery
  * add support for versatile reset controller
  * misc. fixes
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCgAGBQJW6XstAAoJENju1/PIO/qaSmMP+gJY9U4yPscEoW2UkvKJ2y81
 /Bxvy8GWSnnaFFPLMHYk/n53EPJbPnewETBftv1xRHzgJ6wQlgM/5EAEU2Qwud+A
 V8K3V8VStIZLIrQ1tU8r10UE5OW95lsupCAlFp9AHYrBgIiRDUHlqWtxuhwH12F2
 uLZt7moLHJFZtvg3EWl4agsvoEWfqPOKwmOpda+PyIUOlZrAIu3nItvKwBKWdvr3
 WuomqfknkekkvX2lSB8R4OfE+w4fkYTFak2+4ymNiaQWrLeEqLuJbICUNGMD+APb
 nX8TmQ8wmYYHLZTu455ctGJIdpYfrRI/IPAsdW/vMYnQ/8GiO0dgke5dfzZU08Du
 PAWb/NM2pjFfG76fqG46hQPq/Jsns9k/SM1e3Q6fCkwewqtx8P56vUML6FtomYe7
 HP3oPqlNeEpcF/jMmxKfSNiF78pmRLpCkWuhhYaT4Suv8bJhoQRE7Ur00Y47hp9i
 taAIDE3HNFucqTEXMudBktEKsDPRpEx2K1fZEvZbCF8sOUK4xWPQr1yuPTXrM7jm
 sWl/T4s1tn9/P6esdZUTXGghBiehj71mCHsOfXBQZPifaB2s8uINEf+GHQyQcLL4
 X2HiMWrv9Pyn+PLVVwWRmTpSVIFWrCHNQPQ1ofgsgWkrEqsAbdZ4O2srlCqg/4WL
 irCHBm6fbGpoVRQHg3xS
 =L4ho
 -----END PGP SIGNATURE-----

Merge tag 'for-v4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply

Pull power supply and reset changes from Sebastian Reichel:
 - add types for USB Type C and PD chargers
 - add act8945a charger driver
 - add ACPI/DT bindings for goldfish-battery
 - add support for versatile reset controller
 - misc fixes

* tag 'for-v4.6' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (24 commits)
  power: pm2301-charger: use __maybe_unused to hide pm functions
  power: ipaq-micro-battery: use __maybe_unused to hide pm functions
  power_supply: 88pm860x_charger: do not pass NULL to power_supply_put
  jz4740-battery: Correct voltage change check
  power_supply: lp8788-charger: initialize boolean 'found'
  goldfish: Enable ACPI-based enumeration for goldfish battery
  power: goldfish_battery: add devicetree bindings
  power: act8945a: add charger driver for ACT8945A
  power: add documentation for ACT8945A's charger DT bindings
  ARM: dts: n900: Rename isp1704 to isp1707 to match correct name
  power_supply: bq27xxx_battery: Add of modalias and match table when CONFIG_OF is enabled
  power_supply: bq2415x_charger: Add of modalias and match table when CONFIG_OF is enabled
  power_supply: bq2415x_charger: Do not add acpi modalias when CONFIG_ACPI is not enabled
  power_supply: isp1704_charger: Add compatible of match for nxp,isp1707
  power_supply: isp1704_charger: Error messages when probe fail
  power_supply: Add types for USB Type C and PD chargers
  power: bq24735-charger: add 'ti,external-control' option
  power: bq24735-charger: document 'ti,external-control' option
  power: bq24735-charger: fix failed i2c with ac-detect
  power: reset: Fix dependencies for !HAS_IOMEM archs
  ...
hifive-unleashed-5.1
Linus Torvalds 2016-03-17 12:50:55 -07:00
commit 9cc984e4bc
24 changed files with 687 additions and 65 deletions

View File

@ -0,0 +1,17 @@
Android Goldfish Battery
Android goldfish battery device generated by android emulator.
Required properties:
- compatible : should contain "google,goldfish-battery" to match emulator
- reg : <registers mapping>
- interrupts : <interrupt mapping>
Example:
goldfish_battery@9020000 {
compatible = "google,goldfish-battery";
reg = <0x9020000 0x1000>;
interrupts = <0x3>;
};

View File

@ -0,0 +1,35 @@
Device-Tree bindings for charger of Active-semi ACT8945A Multi-Function Device
Required properties:
- compatible: "active-semi,act8945a", please refer to ../mfd/act8945a.txt.
- active-semi,chglev-gpios: charge current level phandle with args
as described in ../gpio/gpio.txt.
Optional properties:
- active-semi,check-battery-temperature: boolean to check the battery
temperature or not.
- active-semi,input-voltage-threshold-microvolt: unit: mV;
Specifies the charger's input over-voltage threshold value;
The value can be: 6600, 7000, 7500, 8000; default: 6600
- active-semi,precondition-timeout: unit: minutes;
Specifies the charger's PRECONDITION safety timer setting value;
The value can be: 40, 60, 80, 0; If 0, it means to disable this timer;
default: 40.
- active-semi,total-timeout: unit: hours;
Specifies the charger's total safety timer setting value;
The value can be: 3, 4, 5, 0; If 0, it means to disable this timer;
default: 3.
Example:
pmic@5b {
compatible = "active-semi,act8945a";
reg = <0x5b>;
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_charger_chglev>;
active-semi,chglev-gpios = <&pioA 12 GPIO_ACTIVE_HIGH>;
active-semi,input-voltage-threshold-microvolt = <6600>;
active-semi,precondition-timeout = <40>;
active-semi,total-timeout = <3>;
};

View File

@ -22,6 +22,9 @@ Optional properties :
value must be between 128mA and 8.064A with a 128mA step resolution. The
POR value is 0x1000h. This number is in mA (e.g. 8064), see the spec for
more information about the InputCurrent (0x3fh) register.
- ti,external-control : Indicates that the charger is configured externally
and that the host should not attempt to enable/disable charging or set the
charge voltage/current.
Example:

View File

@ -107,8 +107,8 @@
};
};
isp1704: isp1704 {
compatible = "nxp,isp1704";
isp1707: isp1707 {
compatible = "nxp,isp1707";
nxp,enable-gpio = <&gpio3 3 GPIO_ACTIVE_HIGH>;
usb-phy = <&usb2_phy>;
};
@ -618,7 +618,7 @@
ti,termination-current = <100>;
ti,resistor-sense = <68>;
ti,usb-charger-detection = <&isp1704>;
ti,usb-charger-detection = <&isp1707>;
};
};

View File

@ -435,7 +435,7 @@ static irqreturn_t pm860x_temp_handler(int irq, void *data)
psy = power_supply_get_by_name(pm860x_supplied_to[0]);
if (!psy)
goto out;
return IRQ_HANDLED;
ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_TEMP, &temp);
if (ret)
goto out;

View File

@ -75,6 +75,13 @@ config BATTERY_88PM860X
help
Say Y here to enable battery monitor for Marvell 88PM860x chip.
config BATTERY_ACT8945A
tristate "Active-semi ACT8945A charger driver"
depends on MFD_ACT8945A || COMPILE_TEST
help
Say Y here to enable support for power supply provided by
Active-semi ActivePath ACT8945A charger.
config BATTERY_DS2760
tristate "DS2760 battery driver (HP iPAQ & others)"
depends on W1 && W1_SLAVE_DS2760

View File

@ -17,6 +17,7 @@ obj-$(CONFIG_WM8350_POWER) += wm8350_power.o
obj-$(CONFIG_TEST_POWER) += test_power.o
obj-$(CONFIG_BATTERY_88PM860X) += 88pm860x_battery.o
obj-$(CONFIG_BATTERY_ACT8945A) += act8945a_charger.o
obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
obj-$(CONFIG_BATTERY_DS2780) += ds2780_battery.o
obj-$(CONFIG_BATTERY_DS2781) += ds2781_battery.o

View File

@ -0,0 +1,359 @@
/*
* Power supply driver for the Active-semi ACT8945A PMIC
*
* Copyright (C) 2015 Atmel Corporation
*
* Author: Wenyou Yang <wenyou.yang@atmel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/regmap.h>
static const char *act8945a_charger_model = "ACT8945A";
static const char *act8945a_charger_manufacturer = "Active-semi";
/**
* ACT8945A Charger Register Map
*/
/* 0x70: Reserved */
#define ACT8945A_APCH_CFG 0x71
#define ACT8945A_APCH_STATUS 0x78
#define ACT8945A_APCH_CTRL 0x79
#define ACT8945A_APCH_STATE 0x7A
/* ACT8945A_APCH_CFG */
#define APCH_CFG_OVPSET (0x3 << 0)
#define APCH_CFG_OVPSET_6V6 (0x0 << 0)
#define APCH_CFG_OVPSET_7V (0x1 << 0)
#define APCH_CFG_OVPSET_7V5 (0x2 << 0)
#define APCH_CFG_OVPSET_8V (0x3 << 0)
#define APCH_CFG_PRETIMO (0x3 << 2)
#define APCH_CFG_PRETIMO_40_MIN (0x0 << 2)
#define APCH_CFG_PRETIMO_60_MIN (0x1 << 2)
#define APCH_CFG_PRETIMO_80_MIN (0x2 << 2)
#define APCH_CFG_PRETIMO_DISABLED (0x3 << 2)
#define APCH_CFG_TOTTIMO (0x3 << 4)
#define APCH_CFG_TOTTIMO_3_HOUR (0x0 << 4)
#define APCH_CFG_TOTTIMO_4_HOUR (0x1 << 4)
#define APCH_CFG_TOTTIMO_5_HOUR (0x2 << 4)
#define APCH_CFG_TOTTIMO_DISABLED (0x3 << 4)
#define APCH_CFG_SUSCHG (0x1 << 7)
#define APCH_STATUS_CHGDAT BIT(0)
#define APCH_STATUS_INDAT BIT(1)
#define APCH_STATUS_TEMPDAT BIT(2)
#define APCH_STATUS_TIMRDAT BIT(3)
#define APCH_STATUS_CHGSTAT BIT(4)
#define APCH_STATUS_INSTAT BIT(5)
#define APCH_STATUS_TEMPSTAT BIT(6)
#define APCH_STATUS_TIMRSTAT BIT(7)
#define APCH_CTRL_CHGEOCOUT BIT(0)
#define APCH_CTRL_INDIS BIT(1)
#define APCH_CTRL_TEMPOUT BIT(2)
#define APCH_CTRL_TIMRPRE BIT(3)
#define APCH_CTRL_CHGEOCIN BIT(4)
#define APCH_CTRL_INCON BIT(5)
#define APCH_CTRL_TEMPIN BIT(6)
#define APCH_CTRL_TIMRTOT BIT(7)
#define APCH_STATE_ACINSTAT (0x1 << 1)
#define APCH_STATE_CSTATE (0x3 << 4)
#define APCH_STATE_CSTATE_SHIFT 4
#define APCH_STATE_CSTATE_DISABLED 0x00
#define APCH_STATE_CSTATE_EOC 0x01
#define APCH_STATE_CSTATE_FAST 0x02
#define APCH_STATE_CSTATE_PRE 0x03
struct act8945a_charger {
struct regmap *regmap;
bool battery_temperature;
};
static int act8945a_get_charger_state(struct regmap *regmap, int *val)
{
int ret;
unsigned int status, state;
ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
if (ret < 0)
return ret;
ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
if (ret < 0)
return ret;
state &= APCH_STATE_CSTATE;
state >>= APCH_STATE_CSTATE_SHIFT;
if (state == APCH_STATE_CSTATE_EOC) {
if (status & APCH_STATUS_CHGDAT)
*val = POWER_SUPPLY_STATUS_FULL;
else
*val = POWER_SUPPLY_STATUS_NOT_CHARGING;
} else if ((state == APCH_STATE_CSTATE_FAST) ||
(state == APCH_STATE_CSTATE_PRE)) {
*val = POWER_SUPPLY_STATUS_CHARGING;
} else {
*val = POWER_SUPPLY_STATUS_NOT_CHARGING;
}
return 0;
}
static int act8945a_get_charge_type(struct regmap *regmap, int *val)
{
int ret;
unsigned int state;
ret = regmap_read(regmap, ACT8945A_APCH_STATE, &state);
if (ret < 0)
return ret;
state &= APCH_STATE_CSTATE;
state >>= APCH_STATE_CSTATE_SHIFT;
switch (state) {
case APCH_STATE_CSTATE_PRE:
*val = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
break;
case APCH_STATE_CSTATE_FAST:
*val = POWER_SUPPLY_CHARGE_TYPE_FAST;
break;
case APCH_STATE_CSTATE_EOC:
case APCH_STATE_CSTATE_DISABLED:
default:
*val = POWER_SUPPLY_CHARGE_TYPE_NONE;
}
return 0;
}
static int act8945a_get_battery_health(struct act8945a_charger *charger,
struct regmap *regmap, int *val)
{
int ret;
unsigned int status;
ret = regmap_read(regmap, ACT8945A_APCH_STATUS, &status);
if (ret < 0)
return ret;
if (charger->battery_temperature && !(status & APCH_STATUS_TEMPDAT))
*val = POWER_SUPPLY_HEALTH_OVERHEAT;
else if (!(status & APCH_STATUS_INDAT))
*val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
else if (status & APCH_STATUS_TIMRDAT)
*val = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
else
*val = POWER_SUPPLY_HEALTH_GOOD;
return 0;
}
static enum power_supply_property act8945a_charger_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_CHARGE_TYPE,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER
};
static int act8945a_charger_get_property(struct power_supply *psy,
enum power_supply_property prop,
union power_supply_propval *val)
{
struct act8945a_charger *charger = power_supply_get_drvdata(psy);
struct regmap *regmap = charger->regmap;
int ret = 0;
switch (prop) {
case POWER_SUPPLY_PROP_STATUS:
ret = act8945a_get_charger_state(regmap, &val->intval);
break;
case POWER_SUPPLY_PROP_CHARGE_TYPE:
ret = act8945a_get_charge_type(regmap, &val->intval);
break;
case POWER_SUPPLY_PROP_TECHNOLOGY:
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
break;
case POWER_SUPPLY_PROP_HEALTH:
ret = act8945a_get_battery_health(charger,
regmap, &val->intval);
break;
case POWER_SUPPLY_PROP_MODEL_NAME:
val->strval = act8945a_charger_model;
break;
case POWER_SUPPLY_PROP_MANUFACTURER:
val->strval = act8945a_charger_manufacturer;
break;
default:
return -EINVAL;
}
return ret;
}
static const struct power_supply_desc act8945a_charger_desc = {
.name = "act8945a-charger",
.type = POWER_SUPPLY_TYPE_BATTERY,
.get_property = act8945a_charger_get_property,
.properties = act8945a_charger_props,
.num_properties = ARRAY_SIZE(act8945a_charger_props),
};
#define DEFAULT_TOTAL_TIME_OUT 3
#define DEFAULT_PRE_TIME_OUT 40
#define DEFAULT_INPUT_OVP_THRESHOLD 6600
static int act8945a_charger_config(struct device *dev,
struct act8945a_charger *charger)
{
struct device_node *np = dev->of_node;
enum of_gpio_flags flags;
struct regmap *regmap = charger->regmap;
u32 total_time_out;
u32 pre_time_out;
u32 input_voltage_threshold;
int chglev_pin;
unsigned int value = 0;
if (!np) {
dev_err(dev, "no charger of node\n");
return -EINVAL;
}
charger->battery_temperature = of_property_read_bool(np,
"active-semi,check-battery-temperature");
chglev_pin = of_get_named_gpio_flags(np,
"active-semi,chglev-gpios", 0, &flags);
if (gpio_is_valid(chglev_pin)) {
gpio_set_value(chglev_pin,
((flags == OF_GPIO_ACTIVE_LOW) ? 0 : 1));
}
if (of_property_read_u32(np,
"active-semi,input-voltage-threshold-microvolt",
&input_voltage_threshold))
input_voltage_threshold = DEFAULT_INPUT_OVP_THRESHOLD;
if (of_property_read_u32(np,
"active-semi,precondition-timeout",
&pre_time_out))
pre_time_out = DEFAULT_PRE_TIME_OUT;
if (of_property_read_u32(np, "active-semi,total-timeout",
&total_time_out))
total_time_out = DEFAULT_TOTAL_TIME_OUT;
switch (input_voltage_threshold) {
case 8000:
value |= APCH_CFG_OVPSET_8V;
break;
case 7500:
value |= APCH_CFG_OVPSET_7V5;
break;
case 7000:
value |= APCH_CFG_OVPSET_7V;
break;
case 6600:
default:
value |= APCH_CFG_OVPSET_6V6;
break;
}
switch (pre_time_out) {
case 60:
value |= APCH_CFG_PRETIMO_60_MIN;
break;
case 80:
value |= APCH_CFG_PRETIMO_80_MIN;
break;
case 0:
value |= APCH_CFG_PRETIMO_DISABLED;
break;
case 40:
default:
value |= APCH_CFG_PRETIMO_40_MIN;
break;
}
switch (total_time_out) {
case 4:
value |= APCH_CFG_TOTTIMO_4_HOUR;
break;
case 5:
value |= APCH_CFG_TOTTIMO_5_HOUR;
break;
case 0:
value |= APCH_CFG_TOTTIMO_DISABLED;
break;
case 3:
default:
value |= APCH_CFG_TOTTIMO_3_HOUR;
break;
}
return regmap_write(regmap, ACT8945A_APCH_CFG, value);
}
static int act8945a_charger_probe(struct platform_device *pdev)
{
struct act8945a_charger *charger;
struct power_supply *psy;
struct power_supply_config psy_cfg = {};
int ret;
charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
if (!charger)
return -ENOMEM;
charger->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!charger->regmap) {
dev_err(&pdev->dev, "Parent did not provide regmap\n");
return -EINVAL;
}
ret = act8945a_charger_config(pdev->dev.parent, charger);
if (ret)
return ret;
psy_cfg.of_node = pdev->dev.parent->of_node;
psy_cfg.drv_data = charger;
psy = devm_power_supply_register(&pdev->dev,
&act8945a_charger_desc,
&psy_cfg);
if (IS_ERR(psy)) {
dev_err(&pdev->dev, "failed to register power supply\n");
return PTR_ERR(psy);
}
return 0;
}
static struct platform_driver act8945a_charger_driver = {
.driver = {
.name = "act8945a-charger",
},
.probe = act8945a_charger_probe,
};
module_platform_driver(act8945a_charger_driver);
MODULE_DESCRIPTION("Active-semi ACT8945A ActivePath charger driver");
MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>");
MODULE_LICENSE("GPL");

View File

@ -1759,6 +1759,7 @@ static const struct i2c_device_id bq2415x_i2c_id_table[] = {
};
MODULE_DEVICE_TABLE(i2c, bq2415x_i2c_id_table);
#ifdef CONFIG_ACPI
static const struct acpi_device_id bq2415x_i2c_acpi_match[] = {
{ "BQ2415X", BQUNKNOWN },
{ "BQ241500", BQ24150 },
@ -1776,10 +1777,31 @@ static const struct acpi_device_id bq2415x_i2c_acpi_match[] = {
{},
};
MODULE_DEVICE_TABLE(acpi, bq2415x_i2c_acpi_match);
#endif
#ifdef CONFIG_OF
static const struct of_device_id bq2415x_of_match_table[] = {
{ .compatible = "ti,bq24150" },
{ .compatible = "ti,bq24150a" },
{ .compatible = "ti,bq24151" },
{ .compatible = "ti,bq24151a" },
{ .compatible = "ti,bq24152" },
{ .compatible = "ti,bq24153" },
{ .compatible = "ti,bq24153a" },
{ .compatible = "ti,bq24155" },
{ .compatible = "ti,bq24156" },
{ .compatible = "ti,bq24156a" },
{ .compatible = "ti,bq24157s" },
{ .compatible = "ti,bq24158" },
{},
};
MODULE_DEVICE_TABLE(of, bq2415x_of_match_table);
#endif
static struct i2c_driver bq2415x_driver = {
.driver = {
.name = "bq2415x-charger",
.of_match_table = of_match_ptr(bq2415x_of_match_table),
.acpi_match_table = ACPI_PTR(bq2415x_i2c_acpi_match),
},
.probe = bq2415x_probe,

View File

@ -48,6 +48,8 @@ struct bq24735 {
struct power_supply_desc charger_desc;
struct i2c_client *client;
struct bq24735_platform *pdata;
struct mutex lock;
bool charging;
};
static inline struct bq24735 *to_bq24735(struct power_supply *psy)
@ -56,9 +58,23 @@ static inline struct bq24735 *to_bq24735(struct power_supply *psy)
}
static enum power_supply_property bq24735_charger_properties[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_ONLINE,
};
static int bq24735_charger_property_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
return 1;
default:
break;
}
return 0;
}
static inline int bq24735_write_word(struct i2c_client *client, u8 reg,
u16 value)
{
@ -90,6 +106,9 @@ static int bq24735_update_word(struct i2c_client *client, u8 reg,
static inline int bq24735_enable_charging(struct bq24735 *charger)
{
if (charger->pdata->ext_control)
return 0;
return bq24735_update_word(charger->client, BQ24735_CHG_OPT,
BQ24735_CHG_OPT_CHARGE_DISABLE,
~BQ24735_CHG_OPT_CHARGE_DISABLE);
@ -97,6 +116,9 @@ static inline int bq24735_enable_charging(struct bq24735 *charger)
static inline int bq24735_disable_charging(struct bq24735 *charger)
{
if (charger->pdata->ext_control)
return 0;
return bq24735_update_word(charger->client, BQ24735_CHG_OPT,
BQ24735_CHG_OPT_CHARGE_DISABLE,
BQ24735_CHG_OPT_CHARGE_DISABLE);
@ -108,6 +130,9 @@ static int bq24735_config_charger(struct bq24735 *charger)
int ret;
u16 value;
if (pdata->ext_control)
return 0;
if (pdata->charge_current) {
value = pdata->charge_current & BQ24735_CHARGE_CURRENT_MASK;
@ -174,16 +199,30 @@ static bool bq24735_charger_is_present(struct bq24735 *charger)
return false;
}
static int bq24735_charger_is_charging(struct bq24735 *charger)
{
int ret = bq24735_read_word(charger->client, BQ24735_CHG_OPT);
if (ret < 0)
return ret;
return !(ret & BQ24735_CHG_OPT_CHARGE_DISABLE);
}
static irqreturn_t bq24735_charger_isr(int irq, void *devid)
{
struct power_supply *psy = devid;
struct bq24735 *charger = to_bq24735(psy);
if (bq24735_charger_is_present(charger))
mutex_lock(&charger->lock);
if (charger->charging && bq24735_charger_is_present(charger))
bq24735_enable_charging(charger);
else
bq24735_disable_charging(charger);
mutex_unlock(&charger->lock);
power_supply_changed(psy);
return IRQ_HANDLED;
@ -199,6 +238,19 @@ static int bq24735_charger_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_ONLINE:
val->intval = bq24735_charger_is_present(charger) ? 1 : 0;
break;
case POWER_SUPPLY_PROP_STATUS:
switch (bq24735_charger_is_charging(charger)) {
case 1:
val->intval = POWER_SUPPLY_STATUS_CHARGING;
break;
case 0:
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
break;
default:
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
break;
}
break;
default:
return -EINVAL;
}
@ -206,6 +258,46 @@ static int bq24735_charger_get_property(struct power_supply *psy,
return 0;
}
static int bq24735_charger_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
struct bq24735 *charger = to_bq24735(psy);
int ret;
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
switch (val->intval) {
case POWER_SUPPLY_STATUS_CHARGING:
mutex_lock(&charger->lock);
charger->charging = true;
ret = bq24735_enable_charging(charger);
mutex_unlock(&charger->lock);
if (ret)
return ret;
bq24735_config_charger(charger);
break;
case POWER_SUPPLY_STATUS_DISCHARGING:
case POWER_SUPPLY_STATUS_NOT_CHARGING:
mutex_lock(&charger->lock);
charger->charging = false;
ret = bq24735_disable_charging(charger);
mutex_unlock(&charger->lock);
if (ret)
return ret;
break;
default:
return -EINVAL;
}
power_supply_changed(psy);
break;
default:
return -EPERM;
}
return 0;
}
static struct bq24735_platform *bq24735_parse_dt_data(struct i2c_client *client)
{
struct bq24735_platform *pdata;
@ -239,6 +331,8 @@ static struct bq24735_platform *bq24735_parse_dt_data(struct i2c_client *client)
if (!ret)
pdata->input_current = val;
pdata->ext_control = of_property_read_bool(np, "ti,external-control");
return pdata;
}
@ -255,6 +349,8 @@ static int bq24735_charger_probe(struct i2c_client *client,
if (!charger)
return -ENOMEM;
mutex_init(&charger->lock);
charger->charging = true;
charger->pdata = client->dev.platform_data;
if (IS_ENABLED(CONFIG_OF) && !charger->pdata && client->dev.of_node)
@ -285,6 +381,9 @@ static int bq24735_charger_probe(struct i2c_client *client,
supply_desc->properties = bq24735_charger_properties;
supply_desc->num_properties = ARRAY_SIZE(bq24735_charger_properties);
supply_desc->get_property = bq24735_charger_get_property;
supply_desc->set_property = bq24735_charger_set_property;
supply_desc->property_is_writeable =
bq24735_charger_property_is_writeable;
psy_cfg.supplied_to = charger->pdata->supplied_to;
psy_cfg.num_supplicants = charger->pdata->num_supplicants;
@ -293,27 +392,6 @@ static int bq24735_charger_probe(struct i2c_client *client,
i2c_set_clientdata(client, charger);
ret = bq24735_read_word(client, BQ24735_MANUFACTURER_ID);
if (ret < 0) {
dev_err(&client->dev, "Failed to read manufacturer id : %d\n",
ret);
return ret;
} else if (ret != 0x0040) {
dev_err(&client->dev,
"manufacturer id mismatch. 0x0040 != 0x%04x\n", ret);
return -ENODEV;
}
ret = bq24735_read_word(client, BQ24735_DEVICE_ID);
if (ret < 0) {
dev_err(&client->dev, "Failed to read device id : %d\n", ret);
return ret;
} else if (ret != 0x000B) {
dev_err(&client->dev,
"device id mismatch. 0x000b != 0x%04x\n", ret);
return -ENODEV;
}
if (gpio_is_valid(charger->pdata->status_gpio)) {
ret = devm_gpio_request(&client->dev,
charger->pdata->status_gpio,
@ -327,6 +405,30 @@ static int bq24735_charger_probe(struct i2c_client *client,
charger->pdata->status_gpio_valid = !ret;
}
if (!charger->pdata->status_gpio_valid
|| bq24735_charger_is_present(charger)) {
ret = bq24735_read_word(client, BQ24735_MANUFACTURER_ID);
if (ret < 0) {
dev_err(&client->dev, "Failed to read manufacturer id : %d\n",
ret);
return ret;
} else if (ret != 0x0040) {
dev_err(&client->dev,
"manufacturer id mismatch. 0x0040 != 0x%04x\n", ret);
return -ENODEV;
}
ret = bq24735_read_word(client, BQ24735_DEVICE_ID);
if (ret < 0) {
dev_err(&client->dev, "Failed to read device id : %d\n", ret);
return ret;
} else if (ret != 0x000B) {
dev_err(&client->dev,
"device id mismatch. 0x000b != 0x%04x\n", ret);
return -ENODEV;
}
}
ret = bq24735_config_charger(charger);
if (ret < 0) {
dev_err(&client->dev, "failed in configuring charger");

View File

@ -46,6 +46,7 @@
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/power/bq27xxx_battery.h>
@ -1090,16 +1091,27 @@ static const struct platform_device_id bq27xxx_battery_platform_id_table[] = {
};
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");

View File

@ -166,9 +166,33 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
};
MODULE_DEVICE_TABLE(i2c, bq27xxx_i2c_id_table);
#ifdef CONFIG_OF
static const struct of_device_id bq27xxx_battery_i2c_of_match_table[] = {
{ .compatible = "ti,bq27200" },
{ .compatible = "ti,bq27210" },
{ .compatible = "ti,bq27500" },
{ .compatible = "ti,bq27510" },
{ .compatible = "ti,bq27520" },
{ .compatible = "ti,bq27530" },
{ .compatible = "ti,bq27531" },
{ .compatible = "ti,bq27541" },
{ .compatible = "ti,bq27542" },
{ .compatible = "ti,bq27546" },
{ .compatible = "ti,bq27742" },
{ .compatible = "ti,bq27545" },
{ .compatible = "ti,bq27421" },
{ .compatible = "ti,bq27425" },
{ .compatible = "ti,bq27441" },
{ .compatible = "ti,bq27621" },
{},
};
MODULE_DEVICE_TABLE(of, bq27xxx_battery_i2c_of_match_table);
#endif
static struct i2c_driver bq27xxx_battery_i2c_driver = {
.driver = {
.name = "bq27xxx-battery",
.of_match_table = of_match_ptr(bq27xxx_battery_i2c_of_match_table),
},
.probe = bq27xxx_battery_i2c_probe,
.remove = bq27xxx_battery_i2c_remove,

View File

@ -26,7 +26,6 @@
static DEFINE_MUTEX(bat_lock); /* protects gpio pins */
static struct work_struct bat_work;
static struct ucb1x00 *ucb;
static int wakeup_enabled;
struct collie_bat {
int status;
@ -291,6 +290,8 @@ static struct gpio collie_batt_gpios[] = {
};
#ifdef CONFIG_PM
static int wakeup_enabled;
static int collie_bat_suspend(struct ucb1x00_dev *dev)
{
/* flush all pending status updates */

View File

@ -24,6 +24,7 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/acpi.h>
struct goldfish_battery_data {
void __iomem *reg_base;
@ -227,11 +228,25 @@ static int goldfish_battery_remove(struct platform_device *pdev)
return 0;
}
static const struct of_device_id goldfish_battery_of_match[] = {
{ .compatible = "google,goldfish-battery", },
{},
};
MODULE_DEVICE_TABLE(of, goldfish_battery_of_match);
static const struct acpi_device_id goldfish_battery_acpi_match[] = {
{ "GFSH0001", 0 },
{ },
};
MODULE_DEVICE_TABLE(acpi, goldfish_battery_acpi_match);
static struct platform_driver goldfish_battery_device = {
.probe = goldfish_battery_probe,
.remove = goldfish_battery_remove,
.driver = {
.name = "goldfish-battery"
.name = "goldfish-battery",
.of_match_table = goldfish_battery_of_match,
.acpi_match_table = ACPI_PTR(goldfish_battery_acpi_match),
}
};
module_platform_driver(goldfish_battery_device);

View File

@ -281,7 +281,7 @@ static int micro_batt_remove(struct platform_device *pdev)
return 0;
}
static int micro_batt_suspend(struct device *dev)
static int __maybe_unused micro_batt_suspend(struct device *dev)
{
struct micro_battery *mb = dev_get_drvdata(dev);
@ -289,7 +289,7 @@ static int micro_batt_suspend(struct device *dev)
return 0;
}
static int micro_batt_resume(struct device *dev)
static int __maybe_unused micro_batt_resume(struct device *dev)
{
struct micro_battery *mb = dev_get_drvdata(dev);

View File

@ -411,8 +411,10 @@ static int isp1704_charger_probe(struct platform_device *pdev)
if (np) {
int gpio = of_get_named_gpio(np, "nxp,enable-gpio", 0);
if (gpio < 0)
if (gpio < 0) {
dev_err(&pdev->dev, "missing DT GPIO nxp,enable-gpio\n");
return gpio;
}
pdata = devm_kzalloc(&pdev->dev,
sizeof(struct isp1704_charger_data), GFP_KERNEL);
@ -422,8 +424,10 @@ static int isp1704_charger_probe(struct platform_device *pdev)
ret = devm_gpio_request_one(&pdev->dev, pdata->enable_gpio,
GPIOF_OUT_INIT_HIGH, "isp1704_reset");
if (ret)
if (ret) {
dev_err(&pdev->dev, "gpio request failed\n");
goto fail0;
}
}
if (!pdata) {
@ -443,6 +447,7 @@ static int isp1704_charger_probe(struct platform_device *pdev)
if (IS_ERR(isp->phy)) {
ret = PTR_ERR(isp->phy);
dev_err(&pdev->dev, "usb_get_phy failed\n");
goto fail0;
}
@ -452,8 +457,10 @@ static int isp1704_charger_probe(struct platform_device *pdev)
isp1704_charger_set_power(isp, 1);
ret = isp1704_test_ulpi(isp);
if (ret < 0)
if (ret < 0) {
dev_err(&pdev->dev, "isp1704_test_ulpi failed\n");
goto fail1;
}
isp->psy_desc.name = "isp1704";
isp->psy_desc.type = POWER_SUPPLY_TYPE_USB;
@ -466,6 +473,7 @@ static int isp1704_charger_probe(struct platform_device *pdev)
isp->psy = power_supply_register(isp->dev, &isp->psy_desc, &psy_cfg);
if (IS_ERR(isp->psy)) {
ret = PTR_ERR(isp->psy);
dev_err(&pdev->dev, "power_supply_register failed\n");
goto fail1;
}
@ -478,8 +486,10 @@ static int isp1704_charger_probe(struct platform_device *pdev)
isp->nb.notifier_call = isp1704_notifier_call;
ret = usb_register_notifier(isp->phy, &isp->nb);
if (ret)
if (ret) {
dev_err(&pdev->dev, "usb_register_notifier failed\n");
goto fail2;
}
dev_info(isp->dev, "registered with product id %s\n", isp->model);
@ -526,6 +536,7 @@ static int isp1704_charger_remove(struct platform_device *pdev)
#ifdef CONFIG_OF
static const struct of_device_id omap_isp1704_of_match[] = {
{ .compatible = "nxp,isp1704", },
{ .compatible = "nxp,isp1707", },
{},
};
MODULE_DEVICE_TABLE(of, omap_isp1704_of_match);

View File

@ -208,7 +208,7 @@ static void jz_battery_update(struct jz_battery *jz_battery)
}
voltage = jz_battery_read_voltage(jz_battery);
if (abs(voltage - jz_battery->voltage) < 50000) {
if (voltage >= 0 && abs(voltage - jz_battery->voltage) > 50000) {
jz_battery->voltage = voltage;
has_changed = true;
}

View File

@ -455,7 +455,7 @@ static void lp8788_charger_event(struct work_struct *work)
static bool lp8788_find_irq_id(struct lp8788_charger *pchg, int virq, int *id)
{
bool found;
bool found = false;
int i;
for (i = 0; i < pchg->num_irqs; i++) {

View File

@ -911,11 +911,7 @@ static struct pm2xxx_irq pm2xxx_charger_irq[] = {
{"PM2XXX_IRQ_INT", pm2xxx_irq_int},
};
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int pm2xxx_wall_charger_resume(struct device *dev)
static int __maybe_unused pm2xxx_wall_charger_resume(struct device *dev)
{
struct i2c_client *i2c_client = to_i2c_client(dev);
struct pm2xxx_charger *pm2;
@ -931,7 +927,7 @@ static int pm2xxx_wall_charger_resume(struct device *dev)
return 0;
}
static int pm2xxx_wall_charger_suspend(struct device *dev)
static int __maybe_unused pm2xxx_wall_charger_suspend(struct device *dev)
{
struct i2c_client *i2c_client = to_i2c_client(dev);
struct pm2xxx_charger *pm2;
@ -949,9 +945,7 @@ static int pm2xxx_wall_charger_suspend(struct device *dev)
return 0;
}
#endif
static int pm2xxx_runtime_suspend(struct device *dev)
static int __maybe_unused pm2xxx_runtime_suspend(struct device *dev)
{
struct i2c_client *pm2xxx_i2c_client = to_i2c_client(dev);
struct pm2xxx_charger *pm2;
@ -962,7 +956,7 @@ static int pm2xxx_runtime_suspend(struct device *dev)
return 0;
}
static int pm2xxx_runtime_resume(struct device *dev)
static int __maybe_unused pm2xxx_runtime_resume(struct device *dev)
{
struct i2c_client *pm2xxx_i2c_client = to_i2c_client(dev);
struct pm2xxx_charger *pm2;
@ -975,15 +969,11 @@ static int pm2xxx_runtime_resume(struct device *dev)
return 0;
}
static const struct dev_pm_ops pm2xxx_pm_ops = {
static const struct dev_pm_ops pm2xxx_pm_ops __maybe_unused = {
SET_SYSTEM_SLEEP_PM_OPS(pm2xxx_wall_charger_suspend,
pm2xxx_wall_charger_resume)
SET_RUNTIME_PM_OPS(pm2xxx_runtime_suspend, pm2xxx_runtime_resume, NULL)
};
#define PM2XXX_PM_OPS (&pm2xxx_pm_ops)
#else
#define PM2XXX_PM_OPS NULL
#endif
static int pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
const struct i2c_device_id *id)
@ -1244,7 +1234,7 @@ static struct i2c_driver pm2xxx_charger_driver = {
.remove = pm2xxx_wall_charger_remove,
.driver = {
.name = "pm2xxx-wall_charger",
.pm = PM2XXX_PM_OPS,
.pm = IS_ENABLED(CONFIG_PM) ? &pm2xxx_pm_ops : NULL,
},
.id_table = pm2xxx_id,
};

View File

@ -45,7 +45,8 @@ static ssize_t power_supply_show_property(struct device *dev,
char *buf) {
static char *type_text[] = {
"Unknown", "Battery", "UPS", "Mains", "USB",
"USB_DCP", "USB_CDP", "USB_ACA"
"USB_DCP", "USB_CDP", "USB_ACA", "USB_C",
"USB_PD", "USB_PD_DRP"
};
static char *status_text[] = {
"Unknown", "Charging", "Discharging", "Not charging", "Full"

View File

@ -148,6 +148,7 @@ config POWER_RESET_KEYSTONE
config POWER_RESET_SYSCON
bool "Generic SYSCON regmap reset driver"
depends on OF
depends on HAS_IOMEM
select MFD_SYSCON
help
Reboot support for generic SYSCON mapped register reset.
@ -155,6 +156,7 @@ config POWER_RESET_SYSCON
config POWER_RESET_SYSCON_POWEROFF
bool "Generic SYSCON regmap poweroff driver"
depends on OF
depends on HAS_IOMEM
select MFD_SYSCON
help
Poweroff support for generic SYSCON mapped register poweroff.

View File

@ -18,8 +18,8 @@
#define INTEGRATOR_HDR_LOCK_OFFSET 0x14
#define INTEGRATOR_CM_CTRL_RESET (1 << 3)
#define REALVIEW_SYS_LOCK_OFFSET 0x20
#define REALVIEW_SYS_RESETCTL_OFFSET 0x40
#define VERSATILE_SYS_LOCK_OFFSET 0x20
#define VERSATILE_SYS_RESETCTL_OFFSET 0x40
/* Magic unlocking token used on all Versatile boards */
#define VERSATILE_LOCK_VAL 0xA05F
@ -29,6 +29,7 @@
*/
enum versatile_reboot {
INTEGRATOR_REBOOT_CM,
VERSATILE_REBOOT_CM,
REALVIEW_REBOOT_EB,
REALVIEW_REBOOT_PB1176,
REALVIEW_REBOOT_PB11MP,
@ -45,6 +46,10 @@ static const struct of_device_id versatile_reboot_of_match[] = {
.compatible = "arm,core-module-integrator",
.data = (void *)INTEGRATOR_REBOOT_CM
},
{
.compatible = "arm,core-module-versatile",
.data = (void *)VERSATILE_REBOOT_CM,
},
{
.compatible = "arm,realview-eb-syscon",
.data = (void *)REALVIEW_REBOOT_EB,
@ -82,33 +87,43 @@ static int versatile_reboot(struct notifier_block *this, unsigned long mode,
INTEGRATOR_CM_CTRL_RESET,
INTEGRATOR_CM_CTRL_RESET);
break;
case VERSATILE_REBOOT_CM:
regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,
VERSATILE_LOCK_VAL);
regmap_update_bits(syscon_regmap,
VERSATILE_SYS_RESETCTL_OFFSET,
0x0107,
0x0105);
regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,
0);
break;
case REALVIEW_REBOOT_EB:
regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET,
regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,
VERSATILE_LOCK_VAL);
regmap_write(syscon_regmap,
REALVIEW_SYS_RESETCTL_OFFSET, 0x0008);
VERSATILE_SYS_RESETCTL_OFFSET, 0x0008);
break;
case REALVIEW_REBOOT_PB1176:
regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET,
regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,
VERSATILE_LOCK_VAL);
regmap_write(syscon_regmap,
REALVIEW_SYS_RESETCTL_OFFSET, 0x0100);
VERSATILE_SYS_RESETCTL_OFFSET, 0x0100);
break;
case REALVIEW_REBOOT_PB11MP:
case REALVIEW_REBOOT_PBA8:
regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET,
regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,
VERSATILE_LOCK_VAL);
regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
regmap_write(syscon_regmap, VERSATILE_SYS_RESETCTL_OFFSET,
0x0000);
regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
regmap_write(syscon_regmap, VERSATILE_SYS_RESETCTL_OFFSET,
0x0004);
break;
case REALVIEW_REBOOT_PBX:
regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET,
regmap_write(syscon_regmap, VERSATILE_SYS_LOCK_OFFSET,
VERSATILE_LOCK_VAL);
regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
regmap_write(syscon_regmap, VERSATILE_SYS_RESETCTL_OFFSET,
0x00f0);
regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
regmap_write(syscon_regmap, VERSATILE_SYS_RESETCTL_OFFSET,
0x00f4);
break;
}

View File

@ -32,6 +32,8 @@ struct bq24735_platform {
int status_gpio_active_low;
bool status_gpio_valid;
bool ext_control;
char **supplied_to;
size_t num_supplicants;
};

View File

@ -163,6 +163,9 @@ enum power_supply_type {
POWER_SUPPLY_TYPE_USB_DCP, /* Dedicated Charging Port */
POWER_SUPPLY_TYPE_USB_CDP, /* Charging Downstream Port */
POWER_SUPPLY_TYPE_USB_ACA, /* Accessory Charger Adapters */
POWER_SUPPLY_TYPE_USB_TYPE_C, /* Type C Port */
POWER_SUPPLY_TYPE_USB_PD, /* Power Delivery Port */
POWER_SUPPLY_TYPE_USB_PD_DRP, /* PD Dual Role Port */
};
enum power_supply_notifier_events {