You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'for-v4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply
Pull power supply and reset updates from Sebastian Reichel: "New drivers: - sbs-charger driver - max14656_charger_detector - axp20x_ac_power New chip/feature support" - axp20x_usb_power: add AXP223 support - tps65217: add usb charger support - qcom_smbb: support otg regulator - at91-reset: add samx7 support Dropped drivers: - intel_mid_battery (platform was dropped) Fixes: - at91-poweroff: avoid wearing off LPDDR memory - replace deprecated extcon API - lots of cleanup and style fixes - misc minor functionality fixes" * tag 'for-v4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (84 commits) power: supply: add AC power supply driver for AXP20X and AXP22X PMICs dt-bindings: power: supply: add AXP20X/AXP22X AC power supply power: supply: axp20x_usb_power: use IIO channels when available power: supply: max14656: Export I2C and OF device ID as module aliases power: supply: bq2415x: check for NULL acpi_id to avoid null pointer dereference power: supply: bq24190_charger: Adjust formatting power: supply: bq24190_charger: Handle fault before status on interrupt power: supply: bq24190_charger: Don't read fault register outside irq_handle_thread() power: supply: bq24190_charger: Call power_supply_changed() for relevant component power: supply: bq24190_charger: Install irq_handler_thread() at end of probe() power: supply: bq24190_charger: Call set_mode_host() on pm_resume() power: supply: bq24190_charger: Fix irq trigger to IRQF_TRIGGER_FALLING power: supply: qcom_smbb: add regulator dependency power: reset: at91-reset: remove leftover platform_device_id power: reset: at91-reset: add samx7 support power: supply: max14656: fix platform_no_drv_owner.cocci warnings power: supply: pcf50633-charger: Compress return logic into one line. power: supply: ab8500_btemp: Compress return logic into one line. power: reset: at91-poweroff: timely shutdown LPDDR memories ARM: at91: define LPDDR types ...
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
AXP20X and AXP22X PMICs' AC power supply
|
||||
|
||||
Required Properties:
|
||||
- compatible: One of:
|
||||
"x-powers,axp202-ac-power-supply"
|
||||
"x-powers,axp221-ac-power-supply"
|
||||
|
||||
This node is a subnode of the axp20x PMIC.
|
||||
|
||||
The AXP20X can read the current current and voltage supplied by AC by
|
||||
reading ADC channels from the AXP20X ADC.
|
||||
|
||||
The AXP22X is only able to tell if an AC power supply is present and
|
||||
usable.
|
||||
|
||||
Example:
|
||||
|
||||
&axp209 {
|
||||
ac_power_supply: ac-power-supply {
|
||||
compatible = "x-powers,axp202-ac-power-supply";
|
||||
};
|
||||
};
|
||||
@@ -3,6 +3,11 @@ AXP20x USB power supply
|
||||
Required Properties:
|
||||
-compatible: One of: "x-powers,axp202-usb-power-supply"
|
||||
"x-powers,axp221-usb-power-supply"
|
||||
"x-powers,axp223-usb-power-supply"
|
||||
|
||||
The AXP223 PMIC shares most of its behaviour with the AXP221 but has slight
|
||||
variations such as the former being able to set the VBUS power supply max
|
||||
current to 100mA, unlike the latter.
|
||||
|
||||
This node is a subnode of the axp20x PMIC.
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
Binding for TI BQ27XXX fuel gauge family
|
||||
|
||||
Required properties:
|
||||
- compatible: Should contain one of the following:
|
||||
* "ti,bq27200" - BQ27200
|
||||
* "ti,bq27210" - BQ27210
|
||||
* "ti,bq27500" - deprecated, use revision specific property below
|
||||
* "ti,bq27510" - deprecated, use revision specific property below
|
||||
* "ti,bq27520" - deprecated, use revision specific property below
|
||||
* "ti,bq27500-1" - BQ27500/1
|
||||
* "ti,bq27510g1" - BQ27510-g1
|
||||
* "ti,bq27510g2" - BQ27510-g2
|
||||
* "ti,bq27510g3" - BQ27510-g3
|
||||
* "ti,bq27520g1" - BQ27520-g1
|
||||
* "ti,bq27520g2" - BQ27520-g2
|
||||
* "ti,bq27520g3" - BQ27520-g3
|
||||
* "ti,bq27520g4" - BQ27520-g4
|
||||
* "ti,bq27530" - BQ27530
|
||||
* "ti,bq27531" - BQ27531
|
||||
* "ti,bq27541" - BQ27541
|
||||
* "ti,bq27542" - BQ27542
|
||||
* "ti,bq27546" - BQ27546
|
||||
* "ti,bq27742" - BQ27742
|
||||
* "ti,bq27545" - BQ27545
|
||||
* "ti,bq27421" - BQ27421
|
||||
* "ti,bq27425" - BQ27425
|
||||
* "ti,bq27441" - BQ27441
|
||||
* "ti,bq27621" - BQ27621
|
||||
- reg: integer, i2c address of the device.
|
||||
|
||||
Example:
|
||||
|
||||
bq27510g3 {
|
||||
compatible = "ti,bq27510g3";
|
||||
reg = <0x55>;
|
||||
};
|
||||
@@ -105,6 +105,22 @@ PROPERTIES
|
||||
regulation must be done externally to fully comply with
|
||||
the JEITA safety guidelines if this flag is set.
|
||||
|
||||
- usb_otg_in-supply:
|
||||
Usage: optional
|
||||
Value type: <phandle>
|
||||
Description: Reference to the regulator supplying power to the USB_OTG_IN
|
||||
pin.
|
||||
|
||||
child nodes:
|
||||
- otg-vbus:
|
||||
Usage: optional
|
||||
Description: This node defines a regulator used to control the direction
|
||||
of VBUS voltage - specifically: whether to supply voltage
|
||||
to VBUS for host mode operation of the OTG port, or allow
|
||||
input voltage from external VBUS for charging. In the
|
||||
hardware, the supply for this regulator comes from
|
||||
usb_otg_in-supply.
|
||||
|
||||
EXAMPLE
|
||||
charger@1000 {
|
||||
compatible = "qcom,pm8941-charger";
|
||||
@@ -128,4 +144,7 @@ charger@1000 {
|
||||
|
||||
qcom,fast-charge-current-limit = <1000000>;
|
||||
qcom,dc-charge-current-limit = <1000000>;
|
||||
usb_otg_in-supply = <&pm8941_5vs1>;
|
||||
|
||||
otg-vbus {};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
SBS sbs-charger
|
||||
~~~~~~~~~~
|
||||
|
||||
Required properties:
|
||||
- compatible: "<vendor>,<part-number>", "sbs,sbs-charger" as fallback. The part
|
||||
number compatible string might be used in order to take care of vendor
|
||||
specific registers.
|
||||
|
||||
Optional properties:
|
||||
- interrupt-parent: Should be the phandle for the interrupt controller. Use in
|
||||
conjunction with "interrupts".
|
||||
- interrupts: Interrupt mapping for GPIO IRQ. Use in conjunction with
|
||||
"interrupt-parent". If an interrupt is not provided the driver will switch
|
||||
automatically to polling.
|
||||
|
||||
Example:
|
||||
|
||||
ltc4100@9 {
|
||||
compatible = "lltc,ltc4100", "sbs,sbs-charger";
|
||||
reg = <0x9>;
|
||||
interrupt-parent = <&gpio6>;
|
||||
interrupts = <7 IRQ_TYPE_LEVEL_LOW>;
|
||||
};
|
||||
@@ -8,8 +8,10 @@ Optional properties :
|
||||
- interrupts : Specify the interrupt to be used to trigger when the AC
|
||||
adapter is either plugged in or removed.
|
||||
- ti,ac-detect-gpios : This GPIO is optionally used to read the AC adapter
|
||||
presence. This is a Host GPIO that is configured as an input and
|
||||
connected to the bq24735.
|
||||
status. This is a Host GPIO that is configured as an input and connected
|
||||
to the ACOK pin on the bq24735. Note: for backwards compatibility reasons,
|
||||
the GPIO must be active on AC adapter absence despite ACOK being active
|
||||
(high) on AC adapter presence.
|
||||
- ti,charge-current : Used to control and set the charging current. This value
|
||||
must be between 128mA and 8.128A with a 64mA step resolution. The POR value
|
||||
is 0x0000h. This number is in mA (e.g. 8192), see spec for more information
|
||||
@@ -25,6 +27,8 @@ Optional properties :
|
||||
- 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.
|
||||
- poll-interval : In case 'interrupts' is not specified, poll AC adapter
|
||||
presence with this interval (milliseconds).
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
Maxim MAX14656 / AL32 USB Charger Detector
|
||||
|
||||
Required properties :
|
||||
- compatible : "maxim,max14656";
|
||||
- reg: i2c slave address
|
||||
- interrupt-parent: the phandle for the interrupt controller
|
||||
- interrupts: interrupt line
|
||||
|
||||
Example:
|
||||
|
||||
&i2c2 {
|
||||
clock-frequency = <50000>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_i2c2>;
|
||||
status = "okay";
|
||||
|
||||
max14656@35 {
|
||||
compatible = "maxim,max14656";
|
||||
reg = <0x35>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_charger_detect>;
|
||||
interrupt-parent = <&gpio6>;
|
||||
interrupts = <26 IRQ_TYPE_LEVEL_HIGH>;
|
||||
};
|
||||
};
|
||||
@@ -32,7 +32,7 @@ config POWER_RESET_AT91_RESET
|
||||
|
||||
config POWER_RESET_AT91_SAMA5D2_SHDWC
|
||||
tristate "Atmel AT91 SAMA5D2-Compatible shutdown controller driver"
|
||||
depends on ARCH_AT91 || COMPILE_TEST
|
||||
depends on ARCH_AT91
|
||||
default SOC_SAMA5
|
||||
help
|
||||
This driver supports the alternate shutdown controller for some Atmel
|
||||
|
||||
@@ -14,9 +14,12 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/printk.h>
|
||||
|
||||
#include <soc/at91/at91sam9_ddrsdr.h>
|
||||
|
||||
#define AT91_SHDW_CR 0x00 /* Shut Down Control Register */
|
||||
#define AT91_SHDW_SHDW BIT(0) /* Shut Down command */
|
||||
#define AT91_SHDW_KEY (0xa5 << 24) /* KEY Password */
|
||||
@@ -50,6 +53,7 @@ static const char *shdwc_wakeup_modes[] = {
|
||||
|
||||
static void __iomem *at91_shdwc_base;
|
||||
static struct clk *sclk;
|
||||
static void __iomem *mpddrc_base;
|
||||
|
||||
static void __init at91_wakeup_status(void)
|
||||
{
|
||||
@@ -73,6 +77,29 @@ static void at91_poweroff(void)
|
||||
writel(AT91_SHDW_KEY | AT91_SHDW_SHDW, at91_shdwc_base + AT91_SHDW_CR);
|
||||
}
|
||||
|
||||
static void at91_lpddr_poweroff(void)
|
||||
{
|
||||
asm volatile(
|
||||
/* Align to cache lines */
|
||||
".balign 32\n\t"
|
||||
|
||||
/* Ensure AT91_SHDW_CR is in the TLB by reading it */
|
||||
" ldr r6, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t"
|
||||
|
||||
/* Power down SDRAM0 */
|
||||
" str %1, [%0, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t"
|
||||
/* Shutdown CPU */
|
||||
" str %3, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t"
|
||||
|
||||
" b .\n\t"
|
||||
:
|
||||
: "r" (mpddrc_base),
|
||||
"r" cpu_to_le32(AT91_DDRSDRC_LPDDR2_PWOFF),
|
||||
"r" (at91_shdwc_base),
|
||||
"r" cpu_to_le32(AT91_SHDW_KEY | AT91_SHDW_SHDW)
|
||||
: "r0");
|
||||
}
|
||||
|
||||
static int at91_poweroff_get_wakeup_mode(struct device_node *np)
|
||||
{
|
||||
const char *pm;
|
||||
@@ -124,6 +151,8 @@ static void at91_poweroff_dt_set_wakeup_mode(struct platform_device *pdev)
|
||||
static int __init at91_poweroff_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct device_node *np;
|
||||
u32 ddr_type;
|
||||
int ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
@@ -150,12 +179,30 @@ static int __init at91_poweroff_probe(struct platform_device *pdev)
|
||||
|
||||
pm_power_off = at91_poweroff;
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "atmel,sama5d3-ddramc");
|
||||
if (!np)
|
||||
return 0;
|
||||
|
||||
mpddrc_base = of_iomap(np, 0);
|
||||
of_node_put(np);
|
||||
|
||||
if (!mpddrc_base)
|
||||
return 0;
|
||||
|
||||
ddr_type = readl(mpddrc_base + AT91_DDRSDRC_MDR) & AT91_DDRSDRC_MD;
|
||||
if ((ddr_type == AT91_DDRSDRC_MD_LPDDR2) ||
|
||||
(ddr_type == AT91_DDRSDRC_MD_LPDDR3))
|
||||
pm_power_off = at91_lpddr_poweroff;
|
||||
else
|
||||
iounmap(mpddrc_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __exit at91_poweroff_remove(struct platform_device *pdev)
|
||||
{
|
||||
if (pm_power_off == at91_poweroff)
|
||||
if (pm_power_off == at91_poweroff ||
|
||||
pm_power_off == at91_lpddr_poweroff)
|
||||
pm_power_off = NULL;
|
||||
|
||||
clk_disable_unprepare(sclk);
|
||||
@@ -163,6 +210,11 @@ static int __exit at91_poweroff_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id at91_ramc_of_match[] = {
|
||||
{ .compatible = "atmel,sama5d3-ddramc", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
static const struct of_device_id at91_poweroff_of_match[] = {
|
||||
{ .compatible = "atmel,at91sam9260-shdwc", },
|
||||
{ .compatible = "atmel,at91sam9rl-shdwc", },
|
||||
|
||||
@@ -134,6 +134,15 @@ static int sama5d3_restart(struct notifier_block *this, unsigned long mode,
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int samx7_restart(struct notifier_block *this, unsigned long mode,
|
||||
void *cmd)
|
||||
{
|
||||
writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PROCRST),
|
||||
at91_rstc_base);
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static void __init at91_reset_status(struct platform_device *pdev)
|
||||
{
|
||||
u32 reg = readl(at91_rstc_base + AT91_RSTC_SR);
|
||||
@@ -173,6 +182,7 @@ static const struct of_device_id at91_reset_of_match[] = {
|
||||
{ .compatible = "atmel,at91sam9260-rstc", .data = at91sam9260_restart },
|
||||
{ .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart },
|
||||
{ .compatible = "atmel,sama5d3-rstc", .data = sama5d3_restart },
|
||||
{ .compatible = "atmel,samx7-rstc", .data = samx7_restart },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, at91_reset_of_match);
|
||||
@@ -238,20 +248,12 @@ static int __exit at91_reset_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, at91_reset_plat_match);
|
||||
|
||||
static struct platform_driver at91_reset_driver = {
|
||||
.remove = __exit_p(at91_reset_remove),
|
||||
.driver = {
|
||||
.name = "at91-reset",
|
||||
.of_match_table = at91_reset_of_match,
|
||||
},
|
||||
.id_table = at91_reset_plat_match,
|
||||
};
|
||||
module_platform_driver_probe(at91_reset_driver, at91_reset_probe);
|
||||
|
||||
|
||||
@@ -22,9 +22,12 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/printk.h>
|
||||
|
||||
#include <soc/at91/at91sam9_ddrsdr.h>
|
||||
|
||||
#define SLOW_CLOCK_FREQ 32768
|
||||
|
||||
#define AT91_SHDW_CR 0x00 /* Shut Down Control Register */
|
||||
@@ -75,6 +78,7 @@ struct shdwc {
|
||||
*/
|
||||
static struct shdwc *at91_shdwc;
|
||||
static struct clk *sclk;
|
||||
static void __iomem *mpddrc_base;
|
||||
|
||||
static const unsigned long long sdwc_dbc_period[] = {
|
||||
0, 3, 32, 512, 4096, 32768,
|
||||
@@ -108,6 +112,29 @@ static void at91_poweroff(void)
|
||||
at91_shdwc->at91_shdwc_base + AT91_SHDW_CR);
|
||||
}
|
||||
|
||||
static void at91_lpddr_poweroff(void)
|
||||
{
|
||||
asm volatile(
|
||||
/* Align to cache lines */
|
||||
".balign 32\n\t"
|
||||
|
||||
/* Ensure AT91_SHDW_CR is in the TLB by reading it */
|
||||
" ldr r6, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t"
|
||||
|
||||
/* Power down SDRAM0 */
|
||||
" str %1, [%0, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t"
|
||||
/* Shutdown CPU */
|
||||
" str %3, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t"
|
||||
|
||||
" b .\n\t"
|
||||
:
|
||||
: "r" (mpddrc_base),
|
||||
"r" cpu_to_le32(AT91_DDRSDRC_LPDDR2_PWOFF),
|
||||
"r" (at91_shdwc->at91_shdwc_base),
|
||||
"r" cpu_to_le32(AT91_SHDW_KEY | AT91_SHDW_SHDW)
|
||||
: "r0");
|
||||
}
|
||||
|
||||
static u32 at91_shdwc_debouncer_value(struct platform_device *pdev,
|
||||
u32 in_period_us)
|
||||
{
|
||||
@@ -212,6 +239,8 @@ static int __init at91_shdwc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
const struct of_device_id *match;
|
||||
struct device_node *np;
|
||||
u32 ddr_type;
|
||||
int ret;
|
||||
|
||||
if (!pdev->dev.of_node)
|
||||
@@ -249,6 +278,23 @@ static int __init at91_shdwc_probe(struct platform_device *pdev)
|
||||
|
||||
pm_power_off = at91_poweroff;
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "atmel,sama5d3-ddramc");
|
||||
if (!np)
|
||||
return 0;
|
||||
|
||||
mpddrc_base = of_iomap(np, 0);
|
||||
of_node_put(np);
|
||||
|
||||
if (!mpddrc_base)
|
||||
return 0;
|
||||
|
||||
ddr_type = readl(mpddrc_base + AT91_DDRSDRC_MDR) & AT91_DDRSDRC_MD;
|
||||
if ((ddr_type == AT91_DDRSDRC_MD_LPDDR2) ||
|
||||
(ddr_type == AT91_DDRSDRC_MD_LPDDR3))
|
||||
pm_power_off = at91_lpddr_poweroff;
|
||||
else
|
||||
iounmap(mpddrc_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -256,7 +302,8 @@ static int __exit at91_shdwc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct shdwc *shdw = platform_get_drvdata(pdev);
|
||||
|
||||
if (pm_power_off == at91_poweroff)
|
||||
if (pm_power_off == at91_poweroff ||
|
||||
pm_power_off == at91_lpddr_poweroff)
|
||||
pm_power_off = NULL;
|
||||
|
||||
/* Reset values to disable wake-up features */
|
||||
|
||||
@@ -164,6 +164,12 @@ config BATTERY_SBS
|
||||
Say Y to include support for SBS battery driver for SBS-compliant
|
||||
gas gauges.
|
||||
|
||||
config CHARGER_SBS
|
||||
tristate "SBS Compliant charger"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y to include support for SBS compilant battery chargers.
|
||||
|
||||
config BATTERY_BQ27XXX
|
||||
tristate "BQ27xxx battery driver"
|
||||
help
|
||||
@@ -214,6 +220,18 @@ config BATTERY_DA9150
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called da9150-fg.
|
||||
|
||||
config CHARGER_AXP20X
|
||||
tristate "X-Powers AXP20X and AXP22X AC power supply driver"
|
||||
depends on MFD_AXP20X
|
||||
depends on AXP20X_ADC
|
||||
depends on IIO
|
||||
help
|
||||
Say Y here to enable support for X-Powers AXP20X and AXP22X PMICs' AC
|
||||
power supply.
|
||||
|
||||
This driver can also be built as a module. If so, the module will be
|
||||
called axp20x_ac_power.
|
||||
|
||||
config AXP288_CHARGER
|
||||
tristate "X-Powers AXP288 Charger"
|
||||
depends on MFD_AXP20X && EXTCON_AXP288
|
||||
@@ -292,13 +310,6 @@ config BATTERY_JZ4740
|
||||
This driver can be build as a module. If so, the module will be
|
||||
called jz4740-battery.
|
||||
|
||||
config BATTERY_INTEL_MID
|
||||
tristate "Battery driver for Intel MID platforms"
|
||||
depends on INTEL_SCU_IPC && SPI
|
||||
help
|
||||
Say Y here to enable the battery driver on Intel MID
|
||||
platforms.
|
||||
|
||||
config BATTERY_RX51
|
||||
tristate "Nokia RX-51 (N900) battery driver"
|
||||
depends on TWL4030_MADC
|
||||
@@ -370,6 +381,16 @@ config CHARGER_MAX14577
|
||||
Say Y to enable support for the battery charger control sysfs and
|
||||
platform data of MAX14577/77836 MUICs.
|
||||
|
||||
config CHARGER_DETECTOR_MAX14656
|
||||
tristate "Maxim MAX14656 USB charger detector"
|
||||
depends on I2C
|
||||
depends on OF
|
||||
help
|
||||
Say Y to enable support for the Maxim MAX14656 USB charger detector.
|
||||
The device is compliant with the USB Battery Charging Specification
|
||||
Revision 1.2 and can be found e.g. in Kindle 4/5th generation
|
||||
readers and certain LG devices.
|
||||
|
||||
config CHARGER_MAX77693
|
||||
tristate "Maxim MAX77693 battery charger driver"
|
||||
depends on MFD_MAX77693
|
||||
@@ -395,6 +416,7 @@ config CHARGER_QCOM_SMBB
|
||||
depends on MFD_SPMI_PMIC || COMPILE_TEST
|
||||
depends on OF
|
||||
depends on EXTCON
|
||||
depends on REGULATOR
|
||||
help
|
||||
Say Y to include support for the Switch-Mode Battery Charger and
|
||||
Boost (SMBB) hardware found in Qualcomm PM8941 PMICs. The charger
|
||||
|
||||
@@ -18,6 +18,7 @@ obj-$(CONFIG_TEST_POWER) += test_power.o
|
||||
|
||||
obj-$(CONFIG_BATTERY_88PM860X) += 88pm860x_battery.o
|
||||
obj-$(CONFIG_BATTERY_ACT8945A) += act8945a_charger.o
|
||||
obj-$(CONFIG_CHARGER_AXP20X) += axp20x_ac_power.o
|
||||
obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
|
||||
obj-$(CONFIG_BATTERY_DS2780) += ds2780_battery.o
|
||||
obj-$(CONFIG_BATTERY_DS2781) += ds2781_battery.o
|
||||
@@ -31,6 +32,7 @@ obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o
|
||||
obj-$(CONFIG_BATTERY_IPAQ_MICRO) += ipaq_micro_battery.o
|
||||
obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o
|
||||
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_DA9030) += da9030_battery.o
|
||||
@@ -47,7 +49,6 @@ obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o
|
||||
obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o
|
||||
obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
|
||||
obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o
|
||||
obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o
|
||||
obj-$(CONFIG_BATTERY_RX51) += rx51_battery.o
|
||||
obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o pm2301_charger.o
|
||||
obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
|
||||
@@ -58,6 +59,7 @@ obj-$(CONFIG_CHARGER_LP8788) += lp8788-charger.o
|
||||
obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
|
||||
obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o
|
||||
obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o
|
||||
obj-$(CONFIG_CHARGER_DETECTOR_MAX14656) += max14656_charger_detector.o
|
||||
obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o
|
||||
obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
|
||||
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
|
||||
|
||||
@@ -76,8 +76,8 @@ struct ab8500_btemp_ranges {
|
||||
* @dev: Pointer to the structure device
|
||||
* @node: List of AB8500 BTEMPs, hence prepared for reentrance
|
||||
* @curr_source: What current source we use, in uA
|
||||
* @bat_temp: Dispatched battery temperature in degree Celcius
|
||||
* @prev_bat_temp Last measured battery temperature in degree Celcius
|
||||
* @bat_temp: Dispatched battery temperature in degree Celsius
|
||||
* @prev_bat_temp Last measured battery temperature in degree Celsius
|
||||
* @parent: Pointer to the struct ab8500
|
||||
* @gpadc: Pointer to the struct gpadc
|
||||
* @fg: Pointer to the struct fg
|
||||
@@ -123,10 +123,7 @@ static LIST_HEAD(ab8500_btemp_list);
|
||||
*/
|
||||
struct ab8500_btemp *ab8500_btemp_get(void)
|
||||
{
|
||||
struct ab8500_btemp *btemp;
|
||||
btemp = list_first_entry(&ab8500_btemp_list, struct ab8500_btemp, node);
|
||||
|
||||
return btemp;
|
||||
return list_first_entry(&ab8500_btemp_list, struct ab8500_btemp, node);
|
||||
}
|
||||
EXPORT_SYMBOL(ab8500_btemp_get);
|
||||
|
||||
@@ -464,13 +461,13 @@ static int ab8500_btemp_get_batctrl_res(struct ab8500_btemp *di)
|
||||
* @tbl_size: size of the resistance to temperature table
|
||||
* @res: resistance to calculate the temperature from
|
||||
*
|
||||
* This function returns the battery temperature in degrees Celcius
|
||||
* This function returns the battery temperature in degrees Celsius
|
||||
* based on the NTC resistance.
|
||||
*/
|
||||
static int ab8500_btemp_res_to_temp(struct ab8500_btemp *di,
|
||||
const struct abx500_res_to_temp *tbl, int tbl_size, int res)
|
||||
{
|
||||
int i, temp;
|
||||
int i;
|
||||
/*
|
||||
* Calculate the formula for the straight line
|
||||
* Simple interpolation if we are within
|
||||
@@ -488,9 +485,8 @@ static int ab8500_btemp_res_to_temp(struct ab8500_btemp *di,
|
||||
i++;
|
||||
}
|
||||
|
||||
temp = tbl[i].temp + ((tbl[i + 1].temp - tbl[i].temp) *
|
||||
return tbl[i].temp + ((tbl[i + 1].temp - tbl[i].temp) *
|
||||
(res - tbl[i].resist)) / (tbl[i + 1].resist - tbl[i].resist);
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* AXP20X and AXP22X PMICs' ACIN power supply driver
|
||||
*
|
||||
* Copyright (C) 2016 Free Electrons
|
||||
* Quentin Schulz <quentin.schulz@free-electrons.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/axp20x.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/iio/consumer.h>
|
||||
|
||||
#define AXP20X_PWR_STATUS_ACIN_PRESENT BIT(7)
|
||||
#define AXP20X_PWR_STATUS_ACIN_AVAIL BIT(6)
|
||||
|
||||
#define DRVNAME "axp20x-ac-power-supply"
|
||||
|
||||
struct axp20x_ac_power {
|
||||
struct regmap *regmap;
|
||||
struct power_supply *supply;
|
||||
struct iio_channel *acin_v;
|
||||
struct iio_channel *acin_i;
|
||||
};
|
||||
|
||||
static irqreturn_t axp20x_ac_power_irq(int irq, void *devid)
|
||||
{
|
||||
struct axp20x_ac_power *power = devid;
|
||||
|
||||
power_supply_changed(power->supply);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int axp20x_ac_power_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct axp20x_ac_power *power = power_supply_get_drvdata(psy);
|
||||
int ret, reg;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_HEALTH:
|
||||
ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (reg & AXP20X_PWR_STATUS_ACIN_PRESENT) {
|
||||
val->intval = POWER_SUPPLY_HEALTH_GOOD;
|
||||
return 0;
|
||||
}
|
||||
|
||||
val->intval = POWER_SUPPLY_HEALTH_UNKNOWN;
|
||||
return 0;
|
||||
|
||||
case POWER_SUPPLY_PROP_PRESENT:
|
||||
ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val->intval = !!(reg & AXP20X_PWR_STATUS_ACIN_PRESENT);
|
||||
return 0;
|
||||
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val->intval = !!(reg & AXP20X_PWR_STATUS_ACIN_AVAIL);
|
||||
return 0;
|
||||
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
ret = iio_read_channel_processed(power->acin_v, &val->intval);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* IIO framework gives mV but Power Supply framework gives uV */
|
||||
val->intval *= 1000;
|
||||
|
||||
return 0;
|
||||
|
||||
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
||||
ret = iio_read_channel_processed(power->acin_i, &val->intval);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* IIO framework gives mA but Power Supply framework gives uA */
|
||||
val->intval *= 1000;
|
||||
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static enum power_supply_property axp20x_ac_power_properties[] = {
|
||||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
};
|
||||
|
||||
static enum power_supply_property axp22x_ac_power_properties[] = {
|
||||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
};
|
||||
|
||||
static const struct power_supply_desc axp20x_ac_power_desc = {
|
||||
.name = "axp20x-ac",
|
||||
.type = POWER_SUPPLY_TYPE_MAINS,
|
||||
.properties = axp20x_ac_power_properties,
|
||||
.num_properties = ARRAY_SIZE(axp20x_ac_power_properties),
|
||||
.get_property = axp20x_ac_power_get_property,
|
||||
};
|
||||
|
||||
static const struct power_supply_desc axp22x_ac_power_desc = {
|
||||
.name = "axp22x-ac",
|
||||
.type = POWER_SUPPLY_TYPE_MAINS,
|
||||
.properties = axp22x_ac_power_properties,
|
||||
.num_properties = ARRAY_SIZE(axp22x_ac_power_properties),
|
||||
.get_property = axp20x_ac_power_get_property,
|
||||
};
|
||||
|
||||
struct axp_data {
|
||||
const struct power_supply_desc *power_desc;
|
||||
bool acin_adc;
|
||||
};
|
||||
|
||||
static const struct axp_data axp20x_data = {
|
||||
.power_desc = &axp20x_ac_power_desc,
|
||||
.acin_adc = true,
|
||||
};
|
||||
|
||||
static const struct axp_data axp22x_data = {
|
||||
.power_desc = &axp22x_ac_power_desc,
|
||||
.acin_adc = false,
|
||||
};
|
||||
|
||||
static int axp20x_ac_power_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
|
||||
struct power_supply_config psy_cfg = {};
|
||||
struct axp20x_ac_power *power;
|
||||
struct axp_data *axp_data;
|
||||
static const char * const irq_names[] = { "ACIN_PLUGIN", "ACIN_REMOVAL",
|
||||
NULL };
|
||||
int i, irq, ret;
|
||||
|
||||
if (!of_device_is_available(pdev->dev.of_node))
|
||||
return -ENODEV;
|
||||
|
||||
if (!axp20x) {
|
||||
dev_err(&pdev->dev, "Parent drvdata not set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
power = devm_kzalloc(&pdev->dev, sizeof(*power), GFP_KERNEL);
|
||||
if (!power)
|
||||
return -ENOMEM;
|
||||
|
||||
axp_data = (struct axp_data *)of_device_get_match_data(&pdev->dev);
|
||||
|
||||
if (axp_data->acin_adc) {
|
||||
power->acin_v = devm_iio_channel_get(&pdev->dev, "acin_v");
|
||||
if (IS_ERR(power->acin_v)) {
|
||||
if (PTR_ERR(power->acin_v) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
return PTR_ERR(power->acin_v);
|
||||
}
|
||||
|
||||
power->acin_i = devm_iio_channel_get(&pdev->dev, "acin_i");
|
||||
if (IS_ERR(power->acin_i)) {
|
||||
if (PTR_ERR(power->acin_i) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
return PTR_ERR(power->acin_i);
|
||||
}
|
||||
}
|
||||
|
||||
power->regmap = dev_get_regmap(pdev->dev.parent, NULL);
|
||||
|
||||
platform_set_drvdata(pdev, power);
|
||||
|
||||
psy_cfg.of_node = pdev->dev.of_node;
|
||||
psy_cfg.drv_data = power;
|
||||
|
||||
power->supply = devm_power_supply_register(&pdev->dev,
|
||||
axp_data->power_desc,
|
||||
&psy_cfg);
|
||||
if (IS_ERR(power->supply))
|
||||
return PTR_ERR(power->supply);
|
||||
|
||||
/* Request irqs after registering, as irqs may trigger immediately */
|
||||
for (i = 0; irq_names[i]; i++) {
|
||||
irq = platform_get_irq_byname(pdev, irq_names[i]);
|
||||
if (irq < 0) {
|
||||
dev_warn(&pdev->dev, "No IRQ for %s: %d\n",
|
||||
irq_names[i], irq);
|
||||
continue;
|
||||
}
|
||||
irq = regmap_irq_get_virq(axp20x->regmap_irqc, irq);
|
||||
ret = devm_request_any_context_irq(&pdev->dev, irq,
|
||||
axp20x_ac_power_irq, 0,
|
||||
DRVNAME, power);
|
||||
if (ret < 0)
|
||||
dev_warn(&pdev->dev, "Error requesting %s IRQ: %d\n",
|
||||
irq_names[i], ret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id axp20x_ac_power_match[] = {
|
||||
{
|
||||
.compatible = "x-powers,axp202-ac-power-supply",
|
||||
.data = (void *)&axp20x_data,
|
||||
}, {
|
||||
.compatible = "x-powers,axp221-ac-power-supply",
|
||||
.data = (void *)&axp22x_data,
|
||||
}, { /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, axp20x_ac_power_match);
|
||||
|
||||
static struct platform_driver axp20x_ac_power_driver = {
|
||||
.probe = axp20x_ac_power_probe,
|
||||
.driver = {
|
||||
.name = DRVNAME,
|
||||
.of_match_table = axp20x_ac_power_match,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(axp20x_ac_power_driver);
|
||||
|
||||
MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
|
||||
MODULE_DESCRIPTION("AXP20X and AXP22X PMICs' AC power supply driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -17,10 +17,12 @@
|
||||
#include <linux/mfd/axp20x.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/iio/consumer.h>
|
||||
|
||||
#define DRVNAME "axp20x-usb-power-supply"
|
||||
|
||||
@@ -30,6 +32,8 @@
|
||||
#define AXP20X_USB_STATUS_VBUS_VALID BIT(2)
|
||||
|
||||
#define AXP20X_VBUS_VHOLD_uV(b) (4000000 + (((b) >> 3) & 7) * 100000)
|
||||
#define AXP20X_VBUS_VHOLD_MASK GENMASK(5, 3)
|
||||
#define AXP20X_VBUS_VHOLD_OFFSET 3
|
||||
#define AXP20X_VBUS_CLIMIT_MASK 3
|
||||
#define AXP20X_VBUC_CLIMIT_900mA 0
|
||||
#define AXP20X_VBUC_CLIMIT_500mA 1
|
||||
@@ -45,6 +49,9 @@ struct axp20x_usb_power {
|
||||
struct device_node *np;
|
||||
struct regmap *regmap;
|
||||
struct power_supply *supply;
|
||||
enum axp20x_variants axp20x_id;
|
||||
struct iio_channel *vbus_v;
|
||||
struct iio_channel *vbus_i;
|
||||
};
|
||||
|
||||
static irqreturn_t axp20x_usb_power_irq(int irq, void *devid)
|
||||
@@ -72,6 +79,20 @@ static int axp20x_usb_power_get_property(struct power_supply *psy,
|
||||
val->intval = AXP20X_VBUS_VHOLD_uV(v);
|
||||
return 0;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
if (IS_ENABLED(CONFIG_AXP20X_ADC)) {
|
||||
ret = iio_read_channel_processed(power->vbus_v,
|
||||
&val->intval);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* IIO framework gives mV but Power Supply framework
|
||||
* gives uV.
|
||||
*/
|
||||
val->intval *= 1000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = axp20x_read_variable_width(power->regmap,
|
||||
AXP20X_VBUS_V_ADC_H, 12);
|
||||
if (ret < 0)
|
||||
@@ -86,12 +107,10 @@ static int axp20x_usb_power_get_property(struct power_supply *psy,
|
||||
|
||||
switch (v & AXP20X_VBUS_CLIMIT_MASK) {
|
||||
case AXP20X_VBUC_CLIMIT_100mA:
|
||||
if (of_device_is_compatible(power->np,
|
||||
"x-powers,axp202-usb-power-supply")) {
|
||||
val->intval = 100000;
|
||||
} else {
|
||||
if (power->axp20x_id == AXP221_ID)
|
||||
val->intval = -1; /* No 100mA limit */
|
||||
}
|
||||
else
|
||||
val->intval = 100000;
|
||||
break;
|
||||
case AXP20X_VBUC_CLIMIT_500mA:
|
||||
val->intval = 500000;
|
||||
@@ -105,6 +124,20 @@ static int axp20x_usb_power_get_property(struct power_supply *psy,
|
||||
}
|
||||
return 0;
|
||||
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
||||
if (IS_ENABLED(CONFIG_AXP20X_ADC)) {
|
||||
ret = iio_read_channel_processed(power->vbus_i,
|
||||
&val->intval);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* IIO framework gives mA but Power Supply framework
|
||||
* gives uA.
|
||||
*/
|
||||
val->intval *= 1000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = axp20x_read_variable_width(power->regmap,
|
||||
AXP20X_VBUS_I_ADC_H, 12);
|
||||
if (ret < 0)
|
||||
@@ -130,8 +163,7 @@ static int axp20x_usb_power_get_property(struct power_supply *psy,
|
||||
|
||||
val->intval = POWER_SUPPLY_HEALTH_GOOD;
|
||||
|
||||
if (of_device_is_compatible(power->np,
|
||||
"x-powers,axp202-usb-power-supply")) {
|
||||
if (power->axp20x_id == AXP202_ID) {
|
||||
ret = regmap_read(power->regmap,
|
||||
AXP20X_USB_OTG_STATUS, &v);
|
||||
if (ret)
|
||||
@@ -155,6 +187,81 @@ static int axp20x_usb_power_get_property(struct power_supply *psy,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int axp20x_usb_power_set_voltage_min(struct axp20x_usb_power *power,
|
||||
int intval)
|
||||
{
|
||||
int val;
|
||||
|
||||
switch (intval) {
|
||||
case 4000000:
|
||||
case 4100000:
|
||||
case 4200000:
|
||||
case 4300000:
|
||||
case 4400000:
|
||||
case 4500000:
|
||||
case 4600000:
|
||||
case 4700000:
|
||||
val = (intval - 4000000) / 100000;
|
||||
return regmap_update_bits(power->regmap,
|
||||
AXP20X_VBUS_IPSOUT_MGMT,
|
||||
AXP20X_VBUS_VHOLD_MASK,
|
||||
val << AXP20X_VBUS_VHOLD_OFFSET);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int axp20x_usb_power_set_current_max(struct axp20x_usb_power *power,
|
||||
int intval)
|
||||
{
|
||||
int val;
|
||||
|
||||
switch (intval) {
|
||||
case 100000:
|
||||
if (power->axp20x_id == AXP221_ID)
|
||||
return -EINVAL;
|
||||
case 500000:
|
||||
case 900000:
|
||||
val = (900000 - intval) / 400000;
|
||||
return regmap_update_bits(power->regmap,
|
||||
AXP20X_VBUS_IPSOUT_MGMT,
|
||||
AXP20X_VBUS_CLIMIT_MASK, val);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int axp20x_usb_power_set_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
const union power_supply_propval *val)
|
||||
{
|
||||
struct axp20x_usb_power *power = power_supply_get_drvdata(psy);
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_MIN:
|
||||
return axp20x_usb_power_set_voltage_min(power, val->intval);
|
||||
|
||||
case POWER_SUPPLY_PROP_CURRENT_MAX:
|
||||
return axp20x_usb_power_set_current_max(power, val->intval);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int axp20x_usb_power_prop_writeable(struct power_supply *psy,
|
||||
enum power_supply_property psp)
|
||||
{
|
||||
return psp == POWER_SUPPLY_PROP_VOLTAGE_MIN ||
|
||||
psp == POWER_SUPPLY_PROP_CURRENT_MAX;
|
||||
}
|
||||
|
||||
static enum power_supply_property axp20x_usb_power_properties[] = {
|
||||
POWER_SUPPLY_PROP_HEALTH,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
@@ -178,7 +285,9 @@ static const struct power_supply_desc axp20x_usb_power_desc = {
|
||||
.type = POWER_SUPPLY_TYPE_USB,
|
||||
.properties = axp20x_usb_power_properties,
|
||||
.num_properties = ARRAY_SIZE(axp20x_usb_power_properties),
|
||||
.property_is_writeable = axp20x_usb_power_prop_writeable,
|
||||
.get_property = axp20x_usb_power_get_property,
|
||||
.set_property = axp20x_usb_power_set_property,
|
||||
};
|
||||
|
||||
static const struct power_supply_desc axp22x_usb_power_desc = {
|
||||
@@ -186,9 +295,41 @@ static const struct power_supply_desc axp22x_usb_power_desc = {
|
||||
.type = POWER_SUPPLY_TYPE_USB,
|
||||
.properties = axp22x_usb_power_properties,
|
||||
.num_properties = ARRAY_SIZE(axp22x_usb_power_properties),
|
||||
.property_is_writeable = axp20x_usb_power_prop_writeable,
|
||||
.get_property = axp20x_usb_power_get_property,
|
||||
.set_property = axp20x_usb_power_set_property,
|
||||
};
|
||||
|
||||
static int configure_iio_channels(struct platform_device *pdev,
|
||||
struct axp20x_usb_power *power)
|
||||
{
|
||||
power->vbus_v = devm_iio_channel_get(&pdev->dev, "vbus_v");
|
||||
if (IS_ERR(power->vbus_v)) {
|
||||
if (PTR_ERR(power->vbus_v) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
return PTR_ERR(power->vbus_v);
|
||||
}
|
||||
|
||||
power->vbus_i = devm_iio_channel_get(&pdev->dev, "vbus_i");
|
||||
if (IS_ERR(power->vbus_i)) {
|
||||
if (PTR_ERR(power->vbus_i) == -ENODEV)
|
||||
return -EPROBE_DEFER;
|
||||
return PTR_ERR(power->vbus_i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int configure_adc_registers(struct axp20x_usb_power *power)
|
||||
{
|
||||
/* Enable vbus voltage and current measurement */
|
||||
return regmap_update_bits(power->regmap, AXP20X_ADC_EN1,
|
||||
AXP20X_ADC_EN1_VBUS_CURR |
|
||||
AXP20X_ADC_EN1_VBUS_VOLT,
|
||||
AXP20X_ADC_EN1_VBUS_CURR |
|
||||
AXP20X_ADC_EN1_VBUS_VOLT);
|
||||
}
|
||||
|
||||
static int axp20x_usb_power_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
|
||||
@@ -214,11 +355,13 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
|
||||
if (!power)
|
||||
return -ENOMEM;
|
||||
|
||||
power->axp20x_id = (enum axp20x_variants)of_device_get_match_data(
|
||||
&pdev->dev);
|
||||
|
||||
power->np = pdev->dev.of_node;
|
||||
power->regmap = axp20x->regmap;
|
||||
|
||||
if (of_device_is_compatible(power->np,
|
||||
"x-powers,axp202-usb-power-supply")) {
|
||||
if (power->axp20x_id == AXP202_ID) {
|
||||
/* Enable vbus valid checking */
|
||||
ret = regmap_update_bits(power->regmap, AXP20X_VBUS_MON,
|
||||
AXP20X_VBUS_MON_VBUS_VALID,
|
||||
@@ -226,17 +369,18 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Enable vbus voltage and current measurement */
|
||||
ret = regmap_update_bits(power->regmap, AXP20X_ADC_EN1,
|
||||
AXP20X_ADC_EN1_VBUS_CURR | AXP20X_ADC_EN1_VBUS_VOLT,
|
||||
AXP20X_ADC_EN1_VBUS_CURR | AXP20X_ADC_EN1_VBUS_VOLT);
|
||||
if (IS_ENABLED(CONFIG_AXP20X_ADC))
|
||||
ret = configure_iio_channels(pdev, power);
|
||||
else
|
||||
ret = configure_adc_registers(power);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
usb_power_desc = &axp20x_usb_power_desc;
|
||||
irq_names = axp20x_irq_names;
|
||||
} else if (of_device_is_compatible(power->np,
|
||||
"x-powers,axp221-usb-power-supply")) {
|
||||
} else if (power->axp20x_id == AXP221_ID ||
|
||||
power->axp20x_id == AXP223_ID) {
|
||||
usb_power_desc = &axp22x_usb_power_desc;
|
||||
irq_names = axp22x_irq_names;
|
||||
} else {
|
||||
@@ -273,9 +417,16 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct of_device_id axp20x_usb_power_match[] = {
|
||||
{ .compatible = "x-powers,axp202-usb-power-supply" },
|
||||
{ .compatible = "x-powers,axp221-usb-power-supply" },
|
||||
{ }
|
||||
{
|
||||
.compatible = "x-powers,axp202-usb-power-supply",
|
||||
.data = (void *)AXP202_ID,
|
||||
}, {
|
||||
.compatible = "x-powers,axp221-usb-power-supply",
|
||||
.data = (void *)AXP221_ID,
|
||||
}, {
|
||||
.compatible = "x-powers,axp223-usb-power-supply",
|
||||
.data = (void *)AXP223_ID,
|
||||
}, { /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, axp20x_usb_power_match);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1569,6 +1569,11 @@ static int bq2415x_probe(struct i2c_client *client,
|
||||
acpi_id =
|
||||
acpi_match_device(client->dev.driver->acpi_match_table,
|
||||
&client->dev);
|
||||
if (!acpi_id) {
|
||||
dev_err(&client->dev, "failed to match device name\n");
|
||||
ret = -ENODEV;
|
||||
goto error_1;
|
||||
}
|
||||
name = kasprintf(GFP_KERNEL, "%s-%d", acpi_id->id, num);
|
||||
}
|
||||
if (!name) {
|
||||
|
||||
@@ -144,10 +144,7 @@
|
||||
* so the first read after a fault returns the latched value and subsequent
|
||||
* reads return the current value. In order to return the fault status
|
||||
* to the user, have the interrupt handler save the reg's value and retrieve
|
||||
* it in the appropriate health/status routine. Each routine has its own
|
||||
* flag indicating whether it should use the value stored by the last run
|
||||
* of the interrupt handler or do an actual reg read. That way each routine
|
||||
* can report back whatever fault may have occured.
|
||||
* it in the appropriate health/status routine.
|
||||
*/
|
||||
struct bq24190_dev_info {
|
||||
struct i2c_client *client;
|
||||
@@ -159,10 +156,6 @@ struct bq24190_dev_info {
|
||||
unsigned int gpio_int;
|
||||
unsigned int irq;
|
||||
struct mutex f_reg_lock;
|
||||
bool first_time;
|
||||
bool charger_health_valid;
|
||||
bool battery_health_valid;
|
||||
bool battery_status_valid;
|
||||
u8 f_reg;
|
||||
u8 ss_reg;
|
||||
u8 watchdog;
|
||||
@@ -199,7 +192,7 @@ static const int bq24190_cvc_vreg_values[] = {
|
||||
4400000
|
||||
};
|
||||
|
||||
/* REG06[1:0] (TREG) in tenths of degrees Celcius */
|
||||
/* REG06[1:0] (TREG) in tenths of degrees Celsius */
|
||||
static const int bq24190_ictrc_treg_values[] = {
|
||||
600, 800, 1000, 1200
|
||||
};
|
||||
@@ -636,21 +629,11 @@ static int bq24190_charger_get_health(struct bq24190_dev_info *bdi,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
u8 v;
|
||||
int health, ret;
|
||||
int health;
|
||||
|
||||
mutex_lock(&bdi->f_reg_lock);
|
||||
|
||||
if (bdi->charger_health_valid) {
|
||||
v = bdi->f_reg;
|
||||
bdi->charger_health_valid = false;
|
||||
mutex_unlock(&bdi->f_reg_lock);
|
||||
} else {
|
||||
mutex_unlock(&bdi->f_reg_lock);
|
||||
|
||||
ret = bq24190_read(bdi, BQ24190_REG_F, &v);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
v = bdi->f_reg;
|
||||
mutex_unlock(&bdi->f_reg_lock);
|
||||
|
||||
if (v & BQ24190_REG_F_BOOST_FAULT_MASK) {
|
||||
/*
|
||||
@@ -937,18 +920,8 @@ static int bq24190_battery_get_status(struct bq24190_dev_info *bdi,
|
||||
int status, ret;
|
||||
|
||||
mutex_lock(&bdi->f_reg_lock);
|
||||
|
||||
if (bdi->battery_status_valid) {
|
||||
chrg_fault = bdi->f_reg;
|
||||
bdi->battery_status_valid = false;
|
||||
mutex_unlock(&bdi->f_reg_lock);
|
||||
} else {
|
||||
mutex_unlock(&bdi->f_reg_lock);
|
||||
|
||||
ret = bq24190_read(bdi, BQ24190_REG_F, &chrg_fault);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
chrg_fault = bdi->f_reg;
|
||||
mutex_unlock(&bdi->f_reg_lock);
|
||||
|
||||
chrg_fault &= BQ24190_REG_F_CHRG_FAULT_MASK;
|
||||
chrg_fault >>= BQ24190_REG_F_CHRG_FAULT_SHIFT;
|
||||
@@ -996,21 +969,11 @@ static int bq24190_battery_get_health(struct bq24190_dev_info *bdi,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
u8 v;
|
||||
int health, ret;
|
||||
int health;
|
||||
|
||||
mutex_lock(&bdi->f_reg_lock);
|
||||
|
||||
if (bdi->battery_health_valid) {
|
||||
v = bdi->f_reg;
|
||||
bdi->battery_health_valid = false;
|
||||
mutex_unlock(&bdi->f_reg_lock);
|
||||
} else {
|
||||
mutex_unlock(&bdi->f_reg_lock);
|
||||
|
||||
ret = bq24190_read(bdi, BQ24190_REG_F, &v);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
v = bdi->f_reg;
|
||||
mutex_unlock(&bdi->f_reg_lock);
|
||||
|
||||
if (v & BQ24190_REG_F_BAT_FAULT_MASK) {
|
||||
health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
|
||||
@@ -1197,9 +1160,12 @@ static const struct power_supply_desc bq24190_battery_desc = {
|
||||
static irqreturn_t bq24190_irq_handler_thread(int irq, void *data)
|
||||
{
|
||||
struct bq24190_dev_info *bdi = data;
|
||||
bool alert_userspace = false;
|
||||
const u8 battery_mask_ss = BQ24190_REG_SS_CHRG_STAT_MASK;
|
||||
const u8 battery_mask_f = BQ24190_REG_F_BAT_FAULT_MASK
|
||||
| BQ24190_REG_F_NTC_FAULT_MASK;
|
||||
bool alert_charger = false, alert_battery = false;
|
||||
u8 ss_reg = 0, f_reg = 0;
|
||||
int ret;
|
||||
int i, ret;
|
||||
|
||||
pm_runtime_get_sync(bdi->dev);
|
||||
|
||||
@@ -1209,6 +1175,32 @@ static irqreturn_t bq24190_irq_handler_thread(int irq, void *data)
|
||||
goto out;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
do {
|
||||
ret = bq24190_read(bdi, BQ24190_REG_F, &f_reg);
|
||||
if (ret < 0) {
|
||||
dev_err(bdi->dev, "Can't read F reg: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
} while (f_reg && ++i < 2);
|
||||
|
||||
if (f_reg != bdi->f_reg) {
|
||||
dev_info(bdi->dev,
|
||||
"Fault: boost %d, charge %d, battery %d, ntc %d\n",
|
||||
!!(f_reg & BQ24190_REG_F_BOOST_FAULT_MASK),
|
||||
!!(f_reg & BQ24190_REG_F_CHRG_FAULT_MASK),
|
||||
!!(f_reg & BQ24190_REG_F_BAT_FAULT_MASK),
|
||||
!!(f_reg & BQ24190_REG_F_NTC_FAULT_MASK));
|
||||
|
||||
mutex_lock(&bdi->f_reg_lock);
|
||||
if ((bdi->f_reg & battery_mask_f) != (f_reg & battery_mask_f))
|
||||
alert_battery = true;
|
||||
if ((bdi->f_reg & ~battery_mask_f) != (f_reg & ~battery_mask_f))
|
||||
alert_charger = true;
|
||||
bdi->f_reg = f_reg;
|
||||
mutex_unlock(&bdi->f_reg_lock);
|
||||
}
|
||||
|
||||
if (ss_reg != bdi->ss_reg) {
|
||||
/*
|
||||
* The device is in host mode so when PG_STAT goes from 1->0
|
||||
@@ -1225,47 +1217,17 @@ static irqreturn_t bq24190_irq_handler_thread(int irq, void *data)
|
||||
ret);
|
||||
}
|
||||
|
||||
if ((bdi->ss_reg & battery_mask_ss) != (ss_reg & battery_mask_ss))
|
||||
alert_battery = true;
|
||||
if ((bdi->ss_reg & ~battery_mask_ss) != (ss_reg & ~battery_mask_ss))
|
||||
alert_charger = true;
|
||||
bdi->ss_reg = ss_reg;
|
||||
alert_userspace = true;
|
||||
}
|
||||
|
||||
mutex_lock(&bdi->f_reg_lock);
|
||||
|
||||
ret = bq24190_read(bdi, BQ24190_REG_F, &f_reg);
|
||||
if (ret < 0) {
|
||||
mutex_unlock(&bdi->f_reg_lock);
|
||||
dev_err(bdi->dev, "Can't read F reg: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (f_reg != bdi->f_reg) {
|
||||
bdi->f_reg = f_reg;
|
||||
bdi->charger_health_valid = true;
|
||||
bdi->battery_health_valid = true;
|
||||
bdi->battery_status_valid = true;
|
||||
|
||||
alert_userspace = true;
|
||||
}
|
||||
|
||||
mutex_unlock(&bdi->f_reg_lock);
|
||||
|
||||
/*
|
||||
* Sometimes bq24190 gives a steady trickle of interrupts even
|
||||
* though the watchdog timer is turned off and neither the STATUS
|
||||
* nor FAULT registers have changed. Weed out these sprurious
|
||||
* interrupts so userspace isn't alerted for no reason.
|
||||
* In addition, the chip always generates an interrupt after
|
||||
* register reset so we should ignore that one (the very first
|
||||
* interrupt received).
|
||||
*/
|
||||
if (alert_userspace) {
|
||||
if (!bdi->first_time) {
|
||||
power_supply_changed(bdi->charger);
|
||||
power_supply_changed(bdi->battery);
|
||||
} else {
|
||||
bdi->first_time = false;
|
||||
}
|
||||
}
|
||||
if (alert_charger)
|
||||
power_supply_changed(bdi->charger);
|
||||
if (alert_battery)
|
||||
power_supply_changed(bdi->battery);
|
||||
|
||||
out:
|
||||
pm_runtime_put_sync(bdi->dev);
|
||||
@@ -1300,6 +1262,10 @@ static int bq24190_hw_init(struct bq24190_dev_info *bdi)
|
||||
goto out;
|
||||
|
||||
ret = bq24190_set_mode_host(bdi);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = bq24190_read(bdi, BQ24190_REG_SS, &bdi->ss_reg);
|
||||
out:
|
||||
pm_runtime_put_sync(bdi->dev);
|
||||
return ret;
|
||||
@@ -1375,10 +1341,8 @@ static int bq24190_probe(struct i2c_client *client,
|
||||
bdi->model = id->driver_data;
|
||||
strncpy(bdi->model_name, id->name, I2C_NAME_SIZE);
|
||||
mutex_init(&bdi->f_reg_lock);
|
||||
bdi->first_time = true;
|
||||
bdi->charger_health_valid = false;
|
||||
bdi->battery_health_valid = false;
|
||||
bdi->battery_status_valid = false;
|
||||
bdi->f_reg = 0;
|
||||
bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */
|
||||
|
||||
i2c_set_clientdata(client, bdi);
|
||||
|
||||
@@ -1392,22 +1356,13 @@ static int bq24190_probe(struct i2c_client *client,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(dev, bdi->irq, NULL,
|
||||
bq24190_irq_handler_thread,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
"bq24190-charger", bdi);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Can't set up irq handler\n");
|
||||
goto out1;
|
||||
}
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_resume(dev);
|
||||
|
||||
ret = bq24190_hw_init(bdi);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Hardware init failed\n");
|
||||
goto out2;
|
||||
goto out1;
|
||||
}
|
||||
|
||||
charger_cfg.drv_data = bdi;
|
||||
@@ -1418,7 +1373,7 @@ static int bq24190_probe(struct i2c_client *client,
|
||||
if (IS_ERR(bdi->charger)) {
|
||||
dev_err(dev, "Can't register charger\n");
|
||||
ret = PTR_ERR(bdi->charger);
|
||||
goto out2;
|
||||
goto out1;
|
||||
}
|
||||
|
||||
battery_cfg.drv_data = bdi;
|
||||
@@ -1427,27 +1382,39 @@ static int bq24190_probe(struct i2c_client *client,
|
||||
if (IS_ERR(bdi->battery)) {
|
||||
dev_err(dev, "Can't register battery\n");
|
||||
ret = PTR_ERR(bdi->battery);
|
||||
goto out3;
|
||||
goto out2;
|
||||
}
|
||||
|
||||
ret = bq24190_sysfs_create_group(bdi);
|
||||
if (ret) {
|
||||
dev_err(dev, "Can't create sysfs entries\n");
|
||||
goto out3;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(dev, bdi->irq, NULL,
|
||||
bq24190_irq_handler_thread,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
"bq24190-charger", bdi);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Can't set up irq handler\n");
|
||||
goto out4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out4:
|
||||
power_supply_unregister(bdi->battery);
|
||||
bq24190_sysfs_remove_group(bdi);
|
||||
|
||||
out3:
|
||||
power_supply_unregister(bdi->charger);
|
||||
power_supply_unregister(bdi->battery);
|
||||
|
||||
out2:
|
||||
pm_runtime_disable(dev);
|
||||
power_supply_unregister(bdi->charger);
|
||||
|
||||
out1:
|
||||
pm_runtime_disable(dev);
|
||||
if (bdi->gpio_int)
|
||||
gpio_free(bdi->gpio_int);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1488,12 +1455,13 @@ static int bq24190_pm_resume(struct device *dev)
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
|
||||
|
||||
bdi->charger_health_valid = false;
|
||||
bdi->battery_health_valid = false;
|
||||
bdi->battery_status_valid = false;
|
||||
bdi->f_reg = 0;
|
||||
bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */
|
||||
|
||||
pm_runtime_get_sync(bdi->dev);
|
||||
bq24190_register_reset(bdi);
|
||||
bq24190_set_mode_host(bdi);
|
||||
bq24190_read(bdi, BQ24190_REG_SS, &bdi->ss_reg);
|
||||
pm_runtime_put_sync(bdi->dev);
|
||||
|
||||
/* Things may have changed while suspended so alert upper layer */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user