Commit 4520dcbe authored by Linus Torvalds's avatar Linus Torvalds

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

Pull power supply and reset updates from Sebastian Reichel:
 "Battery/charger related:
   - cros-peripheral-charger: new driver
   - mt6360-charger: new driver
   - simple-battery: support reading chemistry info
   - max17042-battery: add max77849 support
   - sbs-battery: add time_to_empty_now support
   - smb347-charger: prepare USB OTG support
   - rn5t618: add voltage_now support
   - axp288: cleanup & optimizations
   - max17042_battery: cleanups
   - ab8500: cleanups
   - misc minor cleanups and DT binding fixes

  reset related:
   - tps65086-restart: new driver
   - linkstation-poweroff: support NETGEAR ReadyNAS Duo v2"

* tag 'for-v5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (51 commits)
  power: supply: core: Fix parsing of battery chemistry/technology
  power: supply: max17042_battery: log SOC threshold using debug log level
  power: supply: max17042_battery: more robust chip type checks
  power: supply: max17042_battery: fix typo in MAx17042_TOFF
  power: supply: max17042_battery: clean up MAX17055_V_empty
  power: supply: smb347-charger: Implement USB VBUS regulator
  power: supply: smb347-charger: Add missing pin control activation
  power: supply: smb347-charger: Utilize generic regmap caching
  power: supply: smb347-charger: Make smb347_set_writable() IRQ-safe
  dt-bindings: power: supply: smb347-charger: Document USB VBUS regulator
  power: reset: Add TPS65086 restart driver
  dt-bindings: power: supply: max17042: describe interrupt
  power: supply: max17042: remove duplicated STATUS bit defines
  power: supply: max17042: handle fails of reading status register
  power: supply: core: Parse battery chemistry/technology
  dt-bindings: power: Extend battery bindings with chemistry
  power: reset: linkstation-poweroff: add new device
  power: reset: linkstation-poweroff: prepare for new devices
  power: supply: bq24735: reorganize ChargeOption command macros
  power: supply: rn5t618: Add voltage_now property
  ...
parents 0da9bc6d c9398455
......@@ -31,6 +31,20 @@ properties:
compatible:
const: simple-battery
device-chemistry:
description: This describes the chemical technology of the battery.
oneOf:
- const: nickel-cadmium
- const: nickel-metal-hydride
- const: lithium-ion
description: This is a blanket type for all lithium-ion batteries,
including those below. If possible, a precise compatible string
from below should be used, but sometimes it is unknown which specific
lithium ion battery is employed and this wide compatible can be used.
- const: lithium-ion-polymer
- const: lithium-ion-iron-phosphate
- const: lithium-ion-manganese-oxide
over-voltage-threshold-microvolt:
description: battery over-voltage limit
......
......@@ -19,12 +19,15 @@ properties:
- maxim,max17047
- maxim,max17050
- maxim,max17055
- maxim,max77849-battery
reg:
maxItems: 1
interrupts:
maxItems: 1
description: |
The ALRT pin, an open-drain interrupt.
maxim,rsns-microohm:
$ref: /schemas/types.yaml#/definitions/uint32
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/power/supply/mt6360_charger.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Battery charger driver for MT6360 PMIC from MediaTek Integrated.
maintainers:
- Gene Chen <gene_chen@richtek.com>
description: |
This module is part of the MT6360 MFD device.
Provides Battery Charger, Boost for OTG devices and BC1.2 detection.
properties:
compatible:
const: mediatek,mt6360-chg
richtek,vinovp-microvolt:
description: Maximum CHGIN regulation voltage in uV.
enum: [ 5500000, 6500000, 11000000, 14500000 ]
usb-otg-vbus-regulator:
type: object
description: OTG boost regulator.
$ref: /schemas/regulator/regulator.yaml#
required:
- compatible
additionalProperties: false
examples:
- |
mt6360_charger: charger {
compatible = "mediatek,mt6360-chg";
richtek,vinovp-microvolt = <14500000>;
otg_vbus_regulator: usb-otg-vbus-regulator {
regulator-compatible = "usb-otg-vbus";
regulator-name = "usb-otg-vbus";
regulator-min-microvolt = <4425000>;
regulator-max-microvolt = <5825000>;
};
};
...
......@@ -73,6 +73,26 @@ properties:
- 1 # SMB3XX_SOFT_TEMP_COMPENSATE_CURRENT Current compensation
- 2 # SMB3XX_SOFT_TEMP_COMPENSATE_VOLTAGE Voltage compensation
summit,inok-polarity:
description: |
Polarity of INOK signal indicating presence of external power supply.
$ref: /schemas/types.yaml#/definitions/uint32
enum:
- 0 # SMB3XX_SYSOK_INOK_ACTIVE_LOW
- 1 # SMB3XX_SYSOK_INOK_ACTIVE_HIGH
usb-vbus:
$ref: "../../regulator/regulator.yaml#"
type: object
properties:
summit,needs-inok-toggle:
type: boolean
description: INOK signal is fixed and polarity needs to be toggled
in order to enable/disable output mode.
unevaluatedProperties: false
allOf:
- if:
properties:
......@@ -134,6 +154,7 @@ examples:
reg = <0x7f>;
summit,enable-charge-control = <SMB3XX_CHG_ENABLE_PIN_ACTIVE_HIGH>;
summit,inok-polarity = <SMB3XX_SYSOK_INOK_ACTIVE_LOW>;
summit,chip-temperature-threshold-celsius = <110>;
summit,mains-current-limit-microamp = <2000000>;
summit,usb-current-limit-microamp = <500000>;
......@@ -141,6 +162,15 @@ examples:
summit,enable-mains-charging;
monitored-battery = <&battery>;
usb-vbus {
regulator-name = "usb_vbus";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
regulator-min-microamp = <750000>;
regulator-max-microamp = <750000>;
summit,needs-inok-toggle;
};
};
};
......
......@@ -21,10 +21,13 @@ allOf:
properties:
compatible:
enum:
- x-powers,axp202-ac-power-supply
- x-powers,axp221-ac-power-supply
- x-powers,axp813-ac-power-supply
oneOf:
- const: x-powers,axp202-ac-power-supply
- const: x-powers,axp221-ac-power-supply
- items:
- const: x-powers,axp803-ac-power-supply
- const: x-powers,axp813-ac-power-supply
- const: x-powers,axp813-ac-power-supply
required:
- compatible
......
......@@ -19,10 +19,14 @@ allOf:
properties:
compatible:
enum:
- x-powers,axp209-battery-power-supply
- x-powers,axp221-battery-power-supply
- x-powers,axp813-battery-power-supply
oneOf:
- const: x-powers,axp202-battery-power-supply
- const: x-powers,axp209-battery-power-supply
- const: x-powers,axp221-battery-power-supply
- items:
- const: x-powers,axp803-battery-power-supply
- const: x-powers,axp813-battery-power-supply
- const: x-powers,axp813-battery-power-supply
required:
- compatible
......
......@@ -20,11 +20,15 @@ allOf:
properties:
compatible:
enum:
- x-powers,axp202-usb-power-supply
- x-powers,axp221-usb-power-supply
- x-powers,axp223-usb-power-supply
- x-powers,axp813-usb-power-supply
oneOf:
- enum:
- x-powers,axp202-usb-power-supply
- x-powers,axp221-usb-power-supply
- x-powers,axp223-usb-power-supply
- x-powers,axp813-usb-power-supply
- items:
- const: x-powers,axp803-usb-power-supply
- const: x-powers,axp813-usb-power-supply
required:
......
......@@ -16,6 +16,8 @@
#include <linux/completion.h>
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
#include <linux/iio/machine.h>
#include <linux/slab.h>
#define RN5T618_ADC_CONVERSION_TIMEOUT (msecs_to_jiffies(500))
......@@ -189,6 +191,19 @@ static const struct iio_chan_spec rn5t618_adc_iio_channels[] = {
RN5T618_ADC_CHANNEL(AIN0, IIO_VOLTAGE, "AIN0")
};
static struct iio_map rn5t618_maps[] = {
IIO_MAP("VADP", "rn5t618-power", "vadp"),
IIO_MAP("VUSB", "rn5t618-power", "vusb"),
{ /* sentinel */ }
};
static void unregister_map(void *data)
{
struct iio_dev *iio_dev = (struct iio_dev *) data;
iio_map_array_unregister(iio_dev);
}
static int rn5t618_adc_probe(struct platform_device *pdev)
{
int ret;
......@@ -239,6 +254,14 @@ static int rn5t618_adc_probe(struct platform_device *pdev)
return ret;
}
ret = iio_map_array_register(iio_dev, rn5t618_maps);
if (ret < 0)
return ret;
ret = devm_add_action_or_reset(adc->dev, unregister_map, iio_dev);
if (ret < 0)
return ret;
return devm_iio_device_register(adc->dev, iio_dev);
}
......
......@@ -204,6 +204,12 @@ config POWER_RESET_ST
help
Reset support for STMicroelectronics boards.
config POWER_RESET_TPS65086
bool "TPS65086 restart driver"
depends on MFD_TPS65086
help
This driver adds support for resetting the TPS65086 PMIC on restart.
config POWER_RESET_VERSATILE
bool "ARM Versatile family reboot driver"
depends on ARM
......
......@@ -23,6 +23,7 @@ obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
obj-$(CONFIG_POWER_RESET_REGULATOR) += regulator-poweroff.o
obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
obj-$(CONFIG_POWER_RESET_ST) += st-poweroff.o
obj-$(CONFIG_POWER_RESET_TPS65086) += tps65086-restart.o
obj-$(CONFIG_POWER_RESET_VERSATILE) += arm-versatile-reboot.o
obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o
obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o
......
......@@ -19,6 +19,7 @@
#define MII_MARVELL_PHY_PAGE 22
#define MII_PHY_LED_CTRL 16
#define MII_PHY_LED_POL_CTRL 17
#define MII_88E1318S_PHY_LED_TCR 18
#define MII_88E1318S_PHY_WOL_CTRL 16
#define MII_M1011_IEVENT 19
......@@ -29,11 +30,23 @@
#define LED2_FORCE_ON (0x8 << 8)
#define LEDMASK GENMASK(11,8)
#define MII_88E1318S_PHY_LED_POL_LED2 BIT(4)
struct power_off_cfg {
char *mdio_node_name;
void (*phy_set_reg)(bool restart);
};
static struct phy_device *phydev;
static const struct power_off_cfg *cfg;
static void mvphy_reg_intn(u16 data)
static void linkstation_mvphy_reg_intn(bool restart)
{
int rc = 0, saved_page;
u16 data = 0;
if (restart)
data = MII_88E1318S_PHY_LED_TCR_FORCE_INT;
saved_page = phy_select_page(phydev, MII_MARVELL_LED_PAGE);
if (saved_page < 0)
......@@ -66,11 +79,52 @@ static void mvphy_reg_intn(u16 data)
dev_err(&phydev->mdio.dev, "Write register failed, %d\n", rc);
}
static void readynas_mvphy_set_reg(bool restart)
{
int rc = 0, saved_page;
u16 data = 0;
if (restart)
data = MII_88E1318S_PHY_LED_POL_LED2;
saved_page = phy_select_page(phydev, MII_MARVELL_LED_PAGE);
if (saved_page < 0)
goto err;
/* Set the LED[2].0 Polarity bit to the required state */
__phy_modify(phydev, MII_PHY_LED_POL_CTRL,
MII_88E1318S_PHY_LED_POL_LED2, data);
if (!data) {
/* If WOL was enabled and a magic packet was received before powering
* off, we won't be able to wake up by sending another magic packet.
* Clear WOL status.
*/
__phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_MARVELL_WOL_PAGE);
__phy_set_bits(phydev, MII_88E1318S_PHY_WOL_CTRL,
MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS);
}
err:
rc = phy_restore_page(phydev, saved_page, rc);
if (rc < 0)
dev_err(&phydev->mdio.dev, "Write register failed, %d\n", rc);
}
static const struct power_off_cfg linkstation_power_off_cfg = {
.mdio_node_name = "mdio",
.phy_set_reg = linkstation_mvphy_reg_intn,
};
static const struct power_off_cfg readynas_power_off_cfg = {
.mdio_node_name = "mdio-bus",
.phy_set_reg = readynas_mvphy_set_reg,
};
static int linkstation_reboot_notifier(struct notifier_block *nb,
unsigned long action, void *unused)
{
if (action == SYS_RESTART)
mvphy_reg_intn(MII_88E1318S_PHY_LED_TCR_FORCE_INT);
cfg->phy_set_reg(true);
return NOTIFY_DONE;
}
......@@ -82,14 +136,21 @@ static struct notifier_block linkstation_reboot_nb = {
static void linkstation_poweroff(void)
{
unregister_reboot_notifier(&linkstation_reboot_nb);
mvphy_reg_intn(0);
cfg->phy_set_reg(false);
kernel_restart("Power off");
}
static const struct of_device_id ls_poweroff_of_match[] = {
{ .compatible = "buffalo,ls421d" },
{ .compatible = "buffalo,ls421de" },
{ .compatible = "buffalo,ls421d",
.data = &linkstation_power_off_cfg,
},
{ .compatible = "buffalo,ls421de",
.data = &linkstation_power_off_cfg,
},
{ .compatible = "netgear,readynas-duo-v2",
.data = &readynas_power_off_cfg,
},
{ },
};
......@@ -97,13 +158,17 @@ static int __init linkstation_poweroff_init(void)
{
struct mii_bus *bus;
struct device_node *dn;
const struct of_device_id *match;
dn = of_find_matching_node(NULL, ls_poweroff_of_match);
if (!dn)
return -ENODEV;
of_node_put(dn);
dn = of_find_node_by_name(NULL, "mdio");
match = of_match_node(ls_poweroff_of_match, dn);
cfg = match->data;
dn = of_find_node_by_name(NULL, cfg->mdio_node_name);
if (!dn)
return -ENODEV;
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2021 Emil Renner Berthing
*/
#include <linux/mfd/tps65086.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
struct tps65086_restart {
struct notifier_block handler;
struct device *dev;
};
static int tps65086_restart_notify(struct notifier_block *this,
unsigned long mode, void *cmd)
{
struct tps65086_restart *tps65086_restart =
container_of(this, struct tps65086_restart, handler);
struct tps65086 *tps65086 = dev_get_drvdata(tps65086_restart->dev->parent);
int ret;
ret = regmap_write(tps65086->regmap, TPS65086_FORCESHUTDN, 1);
if (ret) {
dev_err(tps65086_restart->dev, "%s: error writing to tps65086 pmic: %d\n",
__func__, ret);
return NOTIFY_DONE;
}
/* give it a little time */
mdelay(200);
WARN_ON(1);
return NOTIFY_DONE;
}
static int tps65086_restart_probe(struct platform_device *pdev)
{
struct tps65086_restart *tps65086_restart;
int ret;
tps65086_restart = devm_kzalloc(&pdev->dev, sizeof(*tps65086_restart), GFP_KERNEL);
if (!tps65086_restart)
return -ENOMEM;
platform_set_drvdata(pdev, tps65086_restart);
tps65086_restart->handler.notifier_call = tps65086_restart_notify;
tps65086_restart->handler.priority = 192;
tps65086_restart->dev = &pdev->dev;
ret = register_restart_handler(&tps65086_restart->handler);
if (ret) {
dev_err(&pdev->dev, "%s: cannot register restart handler: %d\n",
__func__, ret);
return -ENODEV;
}
return 0;
}
static int tps65086_restart_remove(struct platform_device *pdev)
{
struct tps65086_restart *tps65086_restart = platform_get_drvdata(pdev);
int ret;
ret = unregister_restart_handler(&tps65086_restart->handler);
if (ret) {
dev_err(&pdev->dev, "%s: cannot unregister restart handler: %d\n",
__func__, ret);
return -ENODEV;
}
return 0;
}
static const struct platform_device_id tps65086_restart_id_table[] = {
{ "tps65086-reset", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, tps65086_restart_id_table);
static struct platform_driver tps65086_restart_driver = {
.driver = {
.name = "tps65086-restart",
},
.probe = tps65086_restart_probe,
.remove = tps65086_restart_remove,
.id_table = tps65086_restart_id_table,
};
module_platform_driver(tps65086_restart_driver);
MODULE_AUTHOR("Emil Renner Berthing <kernel@esmil.dk>");
MODULE_DESCRIPTION("TPS65086 restart driver");
MODULE_LICENSE("GPL v2");
......@@ -358,7 +358,7 @@ config AXP288_CHARGER
config AXP288_FUEL_GAUGE
tristate "X-Powers AXP288 Fuel Gauge"
depends on MFD_AXP20X && IIO
depends on MFD_AXP20X && IIO && IOSF_MBI
help
Say yes here to have support for X-Power power management IC (PMIC)
Fuel Gauge. The device provides battery statistics and status
......@@ -577,6 +577,17 @@ config CHARGER_MP2629
Battery charger. This driver provides Battery charger power management
functions on the systems.
config CHARGER_MT6360
tristate "Mediatek MT6360 Charger Driver"
depends on MFD_MT6360
depends on REGULATOR
select LINEAR_RANGES
help
Say Y here to enable MT6360 Charger Part.
The device supports High-Accuracy Voltage/Current Regulation,
Average Input Current Regulation, Battery Temperature Sensing,
Over-Temperature Protection, DPDM Detection for BC1.2.
config CHARGER_QCOM_SMBB
tristate "Qualcomm Switch-Mode Battery Charger and Boost"
depends on MFD_SPMI_PMIC || COMPILE_TEST
......@@ -669,6 +680,7 @@ config CHARGER_BQ256XX
config CHARGER_SMB347
tristate "Summit Microelectronics SMB3XX Battery Charger"
depends on I2C
depends on REGULATOR
select REGMAP_I2C
help
Say Y to include support for Summit Microelectronics SMB345,
......@@ -736,6 +748,16 @@ config CHARGER_CROS_USBPD
what is connected to USB PD ports from the EC and converts
that into power_supply properties.
config CHARGER_CROS_PCHG
tristate "ChromeOS EC based peripheral charger"
depends on MFD_CROS_EC_DEV
default MFD_CROS_EC_DEV
help
Say Y here to enable ChromeOS EC based peripheral charge driver.
This driver gets various information about the devices connected to
the peripheral charge ports from the EC and converts that into
power_supply properties.
config CHARGER_SC2731
tristate "Spreadtrum SC2731 charger driver"
depends on MFD_SC27XX_PMIC || COMPILE_TEST
......@@ -782,6 +804,8 @@ config CHARGER_WILCO
config RN5T618_POWER
tristate "RN5T618 charger/fuel gauge support"
depends on MFD_RN5T618
depends on RN5T618_ADC
depends on IIO
help
Say Y here to have support for RN5T618 PMIC family fuel gauge and charger.
This driver can also be built as a module. If so, the module will be
......
......@@ -60,7 +60,7 @@ 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_RX51) += rx51_battery.o
obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o
obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o ab8500_chargalg.o
obj-$(CONFIG_CHARGER_CPCAP) += cpcap-charger.o
obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o
......@@ -78,6 +78,7 @@ obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o
obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
obj-$(CONFIG_CHARGER_MP2629) += mp2629_charger.o
obj-$(CONFIG_CHARGER_MT6360) += mt6360_charger.o
obj-$(CONFIG_CHARGER_QCOM_SMBB) += qcom_smbb.o
obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o
obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o
......@@ -93,6 +94,7 @@ obj-$(CONFIG_CHARGER_TPS65217) += tps65217_charger.o
obj-$(CONFIG_AXP288_FUEL_GAUGE) += axp288_fuel_gauge.o
obj-$(CONFIG_AXP288_CHARGER) += axp288_charger.o
obj-$(CONFIG_CHARGER_CROS_USBPD) += cros_usbpd-charger.o
obj-$(CONFIG_CHARGER_CROS_PCHG) += cros_peripheral_charger.o
obj-$(CONFIG_CHARGER_SC2731) += sc2731_charger.o
obj-$(CONFIG_FUEL_GAUGE_SC27XX) += sc27xx_fuel_gauge.o
obj-$(CONFIG_CHARGER_UCS1002) += ucs1002_power.o
......
This diff is collapsed.
......@@ -2,8 +2,6 @@
#include <linux/export.h>
#include <linux/power_supply.h>
#include <linux/of.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
#include "ab8500-bm.h"
......@@ -13,7 +11,7 @@
* Note that the res_to_temp table must be strictly sorted by falling resistance
* values to work.
*/
const struct abx500_res_to_temp ab8500_temp_tbl_a_thermistor[] = {
const struct ab8500_res_to_temp ab8500_temp_tbl_a_thermistor[] = {
{-5, 53407},
{ 0, 48594},
{ 5, 43804},
......@@ -35,7 +33,7 @@ EXPORT_SYMBOL(ab8500_temp_tbl_a_thermistor);
const int ab8500_temp_tbl_a_size = ARRAY_SIZE(ab8500_temp_tbl_a_thermistor);
EXPORT_SYMBOL(ab8500_temp_tbl_a_size);
const struct abx500_res_to_temp ab8500_temp_tbl_b_thermistor[] = {
const struct ab8500_res_to_temp ab8500_temp_tbl_b_thermistor[] = {
{-5, 200000},
{ 0, 159024},
{ 5, 151921},
......@@ -57,7 +55,7 @@ EXPORT_SYMBOL(ab8500_temp_tbl_b_thermistor);
const int ab8500_temp_tbl_b_size = ARRAY_SIZE(ab8500_temp_tbl_b_thermistor);
EXPORT_SYMBOL(ab8500_temp_tbl_b_size);
static const struct abx500_v_to_cap cap_tbl_a_thermistor[] = {
static const struct ab8500_v_to_cap cap_tbl_a_thermistor[] = {
{4171, 100},
{4114, 95},
{4009, 83},
......@@ -80,7 +78,7 @@ static const struct abx500_v_to_cap cap_tbl_a_thermistor[] = {
{3247, 0},
};
static const struct abx500_v_to_cap cap_tbl_b_thermistor[] = {
static const struct ab8500_v_to_cap cap_tbl_b_thermistor[] = {
{4161, 100},
{4124, 98},
{4044, 90},
......@@ -103,7 +101,7 @@ static const struct abx500_v_to_cap cap_tbl_b_thermistor[] = {
{3250, 0},
};
static const struct abx500_v_to_cap cap_tbl[] = {
static const struct ab8500_v_to_cap cap_tbl[] = {
{4186, 100},
{4163, 99},
{4114, 95},
......@@ -134,7 +132,7 @@ static const struct abx500_v_to_cap cap_tbl[] = {
* Note that the res_to_temp table must be strictly sorted by falling
* resistance values to work.
*/
static const struct abx500_res_to_temp temp_tbl[] = {
static const struct ab8500_res_to_temp temp_tbl[] = {
{-5, 214834},
{ 0, 162943},
{ 5, 124820},
......@@ -191,7 +189,7 @@ static const struct batres_vs_temp temp_to_batres_tbl_9100[] = {
{-20, 180},
};
static struct abx500_battery_type bat_type_thermistor[] = {
static struct ab8500_battery_type bat_type_thermistor[] = {
[BATTERY_UNKNOWN] = {
/* First element always represent the UNKNOWN battery */
.name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
......@@ -277,7 +275,7 @@ static struct abx500_battery_type bat_type_thermistor[] = {
},
};
static struct abx500_battery_type bat_type_ext_thermistor[] = {
static struct ab8500_battery_type bat_type_ext_thermistor[] = {
[BATTERY_UNKNOWN] = {
/* First element always represent the UNKNOWN battery */
.name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN,
......@@ -394,7 +392,7 @@ static struct abx500_battery_type bat_type_ext_thermistor[] = {
},
};
static const struct abx500_bm_capacity_levels cap_levels = {
static const struct ab8500_bm_capacity_levels cap_levels = {
.critical = 2,
.low = 10,
.normal = 70,
......@@ -402,7 +400,7 @@ static const struct abx500_bm_capacity_levels cap_levels = {
.full = 100,
};
static const struct abx500_fg_parameters fg = {
static const struct ab8500_fg_parameters fg = {
.recovery_sleep_timer = 10,
.recovery_total_time = 100,
.init_timer = 1,
......@@ -424,14 +422,14 @@ static const struct abx500_fg_parameters fg = {
.pcut_debounce_time = 2,
};
static const struct abx500_maxim_parameters ab8500_maxi_params = {
static const struct ab8500_maxim_parameters ab8500_maxi_params = {
.ena_maxi = true,
.chg_curr = 910,
.wait_cycles = 10,
.charger_curr_step = 100,
};
static const struct abx500_bm_charger_parameters chg = {
static const struct ab8500_bm_charger_parameters chg = {
.usb_volt_max = 5500,
.usb_curr_max = 1500,
.ac_volt_max = 7500,
......@@ -456,7 +454,7 @@ static int ab8500_charge_input_curr_map[] = {
700, 800, 900, 1000, 1100, 1300, 1400, 1500,
};
struct abx500_bm_data ab8500_bm_data = {
struct ab8500_bm_data ab8500_bm_data = {
.temp_under = 3,
.temp_low = 8,
.temp_high = 43,
......@@ -469,7 +467,7 @@ struct abx500_bm_data ab8500_bm_data = {
.bkup_bat_i = BUP_ICH_SEL_150UA,
.no_maintenance = false,
.capacity_scaling = false,
.adc_therm = ABx500_ADC_THERM_BATCTRL,
.adc_therm = AB8500_ADC_THERM_BATCTRL,
.chg_unknown_bat = false,
.enable_overshoot = false,
.fg_res = 100,
......@@ -492,7 +490,7 @@ struct abx500_bm_data ab8500_bm_data = {
int ab8500_bm_of_probe(struct device *dev,
struct device_node *np,
struct abx500_bm_data *bm)
struct ab8500_bm_data *bm)
{
const struct batres_vs_temp *tmp_batres_tbl;
struct device_node *battery_node;
......@@ -531,7 +529,7 @@ int ab8500_bm_of_probe(struct device *dev,
} else {
bm->n_btypes = 4;
bm->bat_type = bat_type_ext_thermistor;
bm->adc_therm = ABx500_ADC_THERM_BATTEMP;
bm->adc_therm = AB8500_ADC_THERM_BATTEMP;
tmp_batres_tbl = temp_to_batres_tbl_ext_thermistor;
}
......
......@@ -27,6 +27,7 @@
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/iio/consumer.h>
#include <linux/fixp-arith.h>
#include "ab8500-bm.h"
......@@ -102,7 +103,7 @@ struct ab8500_btemp {
struct iio_channel *btemp_ball;
struct iio_channel *bat_ctrl;
struct ab8500_fg *fg;
struct abx500_bm_data *bm;
struct ab8500_bm_data *bm;
struct power_supply *btemp_psy;
struct ab8500_btemp_events events;
struct ab8500_btemp_ranges btemp_ranges;
......@@ -144,7 +145,7 @@ static int ab8500_btemp_batctrl_volt_to_res(struct ab8500_btemp *di,
return (450000 * (v_batctrl)) / (1800 - v_batctrl);
}
if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL) {
if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL) {
/*
* If the battery has internal NTC, we use the current
* source to calculate the resistance.
......@@ -206,7 +207,7 @@ static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di,
return 0;
/* Only do this for batteries with internal NTC */
if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && enable) {
if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL && enable) {
if (di->curr_source == BTEMP_BATCTRL_CURR_SRC_7UA)
curr = BAT_CTRL_7U_ENA;
......@@ -239,7 +240,7 @@ static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di,
__func__);
goto disable_curr_source;
}
} else if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && !enable) {
} else if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL && !enable) {
dev_dbg(di->dev, "Disable BATCTRL curr source\n");
/* Write 0 to the curr bits */
......@@ -417,7 +418,7 @@ static int ab8500_btemp_get_batctrl_res(struct ab8500_btemp *di)
* 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)
const struct ab8500_res_to_temp *tbl, int tbl_size, int res)
{
int i;
/*
......@@ -437,8 +438,9 @@ static int ab8500_btemp_res_to_temp(struct ab8500_btemp *di,
i++;
}
return tbl[i].temp + ((tbl[i + 1].temp - tbl[i].temp) *
(res - tbl[i].resist)) / (tbl[i + 1].resist - tbl[i].resist);
return fixp_linear_interpolate(tbl[i].resist, tbl[i].temp,
tbl[i + 1].resist, tbl[i + 1].temp,
res);
}
/**
......@@ -456,7 +458,7 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di)
id = di->bm->batt_id;
if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL &&
if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL &&
id != BATTERY_UNKNOWN) {
rbat = ab8500_btemp_get_batctrl_res(di);
......@@ -525,7 +527,7 @@ static int ab8500_btemp_id(struct ab8500_btemp *di)
dev_dbg(di->dev, "Battery detected on %s"
" low %d < res %d < high: %d"
" index: %d\n",
di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL ?
di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL ?
"BATCTRL" : "BATTEMP",
di->bm->bat_type[i].resis_low, res,
di->bm->bat_type[i].resis_high, i);
......@@ -545,7 +547,7 @@ static int ab8500_btemp_id(struct ab8500_btemp *di)
* We only have to change current source if the
* detected type is Type 1.
*/
if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL &&
if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL &&
di->bm->batt_id == 1) {
dev_dbg(di->dev, "Set BATCTRL current source to 20uA\n");
di->curr_source = BTEMP_BATCTRL_CURR_SRC_20UA;
......
......@@ -292,7 +292,7 @@ struct ab8500_charger {
struct iio_channel *adc_main_charger_c;
struct iio_channel *adc_vbus_v;
struct iio_channel *adc_usb_charger_c;
struct abx500_bm_data *bm;
struct ab8500_bm_data *bm;
struct ab8500_charger_event_flags flags;
struct ab8500_charger_usb_state usb_state;
struct ab8500_charger_max_usb_in_curr max_usb_in_curr;
......@@ -3388,7 +3388,7 @@ static const struct component_master_ops ab8500_charger_comp_ops = {
static struct platform_driver *const ab8500_charger_component_drivers[] = {
&ab8500_fg_driver,
&ab8500_btemp_driver,
&abx500_chargalg_driver,
&ab8500_chargalg_driver,
};
static int ab8500_charger_compare_dev(struct device *dev, void *data)
......
......@@ -34,6 +34,7 @@
#include <linux/mfd/abx500/ab8500.h>
#include <linux/iio/consumer.h>
#include <linux/kernel.h>
#include <linux/fixp-arith.h>
#include "ab8500-bm.h"
......@@ -56,9 +57,6 @@
/* FG constants */
#define BATT_OVV 0x01
#define interpolate(x, x1, y1, x2, y2) \
((y1) + ((((y2) - (y1)) * ((x) - (x1))) / ((x2) - (x1))));
/**
* struct ab8500_fg_interrupts - ab8500 fg interrupts
* @name: name of the interrupt
......@@ -227,7 +225,7 @@ struct ab8500_fg {
struct ab8500_fg_avg_cap avg_cap;
struct ab8500 *parent;
struct iio_channel *main_bat_v;
struct abx500_bm_data *bm;
struct ab8500_bm_data *bm;
struct power_supply *fg_psy;
struct workqueue_struct *fg_wq;
struct delayed_work fg_periodic_work;
......@@ -856,7 +854,7 @@ static int ab8500_fg_bat_voltage(struct ab8500_fg *di)
static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage)
{
int i, tbl_size;
const struct abx500_v_to_cap *tbl;
const struct ab8500_v_to_cap *tbl;
int cap = 0;
tbl = di->bm->bat_type[di->bm->batt_id].v_to_cap_tbl;
......@@ -868,11 +866,12 @@ static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage)
}
if ((i > 0) && (i < tbl_size)) {
cap = interpolate(voltage,
cap = fixp_linear_interpolate(
tbl[i].voltage,
tbl[i].capacity * 10,
tbl[i-1].voltage,
tbl[i-1].capacity * 10);
tbl[i-1].capacity * 10,
voltage);
} else if (i == 0) {
cap = 1000;
} else {
......@@ -920,11 +919,12 @@ static int ab8500_fg_battery_resistance(struct ab8500_fg *di)
}
if ((i > 0) && (i < tbl_size)) {
resist = interpolate(di->bat_temp / 10,
resist = fixp_linear_interpolate(
tbl[i].temp,
tbl[i].resist,
tbl[i-1].temp,
tbl[i-1].resist);
tbl[i-1].resist,
di->bat_temp / 10);
} else if (i == 0) {
resist = tbl[0].resist;
} else {
......@@ -2235,7 +2235,7 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data)
case POWER_SUPPLY_TYPE_BATTERY:
if (!di->flags.batt_id_received &&
di->bm->batt_id != BATTERY_UNKNOWN) {
const struct abx500_battery_type *b;
const struct ab8500_battery_type *b;
b = &(di->bm->bat_type[di->bm->batt_id]);
......
......@@ -813,7 +813,7 @@ static int axp288_charger_probe(struct platform_device *pdev)
if (val == 0)
return -ENODEV;
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
......@@ -823,7 +823,7 @@ static int axp288_charger_probe(struct platform_device *pdev)
info->cable.edev = extcon_get_extcon_dev(AXP288_EXTCON_DEV_NAME);
if (info->cable.edev == NULL) {
dev_dbg(&pdev->dev, "%s is not ready, probe deferred\n",
dev_dbg(dev, "%s is not ready, probe deferred\n",
AXP288_EXTCON_DEV_NAME);
return -EPROBE_DEFER;
}
......@@ -834,8 +834,7 @@ static int axp288_charger_probe(struct platform_device *pdev)
dev_dbg(dev, "EXTCON_USB_HOST is not ready, probe deferred\n");
return -EPROBE_DEFER;
}
dev_info(&pdev->dev,
"Using " USB_HOST_EXTCON_HID " extcon for usb-id\n");
dev_info(dev, "Using " USB_HOST_EXTCON_HID " extcon for usb-id\n");
}
platform_set_drvdata(pdev, info);
......@@ -874,7 +873,7 @@ static int axp288_charger_probe(struct platform_device *pdev)
INIT_WORK(&info->otg.work, axp288_charger_otg_evt_worker);
info->otg.id_nb.notifier_call = axp288_charger_handle_otg_evt;
if (info->otg.cable) {
ret = devm_extcon_register_notifier(&pdev->dev, info->otg.cable,
ret = devm_extcon_register_notifier(dev, info->otg.cable,
EXTCON_USB_HOST, &info->otg.id_nb);
if (ret) {
dev_err(dev, "failed to register EXTCON_USB_HOST notifier\n");
......@@ -899,7 +898,7 @@ static int axp288_charger_probe(struct platform_device *pdev)
NULL, axp288_charger_irq_thread_handler,
IRQF_ONESHOT, info->pdev->name, info);
if (ret) {
dev_err(&pdev->dev, "failed to request interrupt=%d\n",
dev_err(dev, "failed to request interrupt=%d\n",
info->irq[i]);
return ret;
}
......
This diff is collapsed.
......@@ -31,9 +31,8 @@
#include <linux/power/bq24735-charger.h>
#define BQ24735_CHG_OPT 0x12
#define BQ24735_CHG_OPT_CHARGE_DISABLE (1 << 0)
#define BQ24735_CHG_OPT_AC_PRESENT (1 << 4)
/* BQ24735 available commands and their respective masks */
#define BQ24735_CHARGE_OPT 0x12
#define BQ24735_CHARGE_CURRENT 0x14
#define BQ24735_CHARGE_CURRENT_MASK 0x1fc0
#define BQ24735_CHARGE_VOLTAGE 0x15
......@@ -43,6 +42,10 @@
#define BQ24735_MANUFACTURER_ID 0xfe
#define BQ24735_DEVICE_ID 0xff
/* ChargeOptions bits of interest */
#define BQ24735_CHARGE_OPT_CHG_DISABLE (1 << 0)
#define BQ24735_CHARGE_OPT_AC_PRESENT (1 << 4)
struct bq24735 {
struct power_supply *charger;
struct power_supply_desc charger_desc;
......@@ -167,8 +170,8 @@ static inline int bq24735_enable_charging(struct bq24735 *charger)
if (ret)
return ret;
return bq24735_update_word(charger->client, BQ24735_CHG_OPT,
BQ24735_CHG_OPT_CHARGE_DISABLE, 0);
return bq24735_update_word(charger->client, BQ24735_CHARGE_OPT,
BQ24735_CHARGE_OPT_CHG_DISABLE, 0);
}
static inline int bq24735_disable_charging(struct bq24735 *charger)
......@@ -176,9 +179,9 @@ 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);
return bq24735_update_word(charger->client, BQ24735_CHARGE_OPT,
BQ24735_CHARGE_OPT_CHG_DISABLE,
BQ24735_CHARGE_OPT_CHG_DISABLE);
}
static bool bq24735_charger_is_present(struct bq24735 *charger)
......@@ -188,14 +191,14 @@ static bool bq24735_charger_is_present(struct bq24735 *charger)
} else {
int ac = 0;
ac = bq24735_read_word(charger->client, BQ24735_CHG_OPT);
ac = bq24735_read_word(charger->client, BQ24735_CHARGE_OPT);
if (ac < 0) {
dev_dbg(&charger->client->dev,
"Failed to read charger options : %d\n",
ac);
return false;
}
return (ac & BQ24735_CHG_OPT_AC_PRESENT) ? true : false;
return (ac & BQ24735_CHARGE_OPT_AC_PRESENT) ? true : false;
}
return false;
......@@ -208,11 +211,11 @@ static int bq24735_charger_is_charging(struct bq24735 *charger)
if (!bq24735_charger_is_present(charger))
return 0;
ret = bq24735_read_word(charger->client, BQ24735_CHG_OPT);
ret = bq24735_read_word(charger->client, BQ24735_CHARGE_OPT);
if (ret < 0)
return ret;
return !(ret & BQ24735_CHG_OPT_CHARGE_DISABLE);
return !(ret & BQ24735_CHARGE_OPT_CHG_DISABLE);
}
static void bq24735_update(struct bq24735 *charger)
......
// SPDX-License-Identifier: GPL-2.0
/*
* Power supply driver for ChromeOS EC based Peripheral Device Charger.
*
* Copyright 2020 Google LLC.
*/
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_data/cros_ec_proto.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/slab.h>
#include <linux/stringify.h>
#include <linux/types.h>
#define DRV_NAME "cros-ec-pchg"
#define PCHG_DIR_PREFIX "peripheral"
#define PCHG_DIR_NAME PCHG_DIR_PREFIX "%d"
#define PCHG_DIR_NAME_LENGTH \
sizeof(PCHG_DIR_PREFIX __stringify(EC_PCHG_MAX_PORTS))
#define PCHG_CACHE_UPDATE_DELAY msecs_to_jiffies(500)
struct port_data {
int port_number;
char name[PCHG_DIR_NAME_LENGTH];
struct power_supply *psy;
struct power_supply_desc psy_desc;
int psy_status;
int battery_percentage;
int charge_type;
struct charger_data *charger;
unsigned long last_update;
};
struct charger_data {
struct device *dev;
struct cros_ec_dev *ec_dev;
struct cros_ec_device *ec_device;
int num_registered_psy;
struct port_data *ports[EC_PCHG_MAX_PORTS];
struct notifier_block notifier;
};
static enum power_supply_property cros_pchg_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_CHARGE_TYPE,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_SCOPE,
};
static int cros_pchg_ec_command(const struct charger_data *charger,
unsigned int version,
unsigned int command,
const void *outdata,
unsigned int outsize,
void *indata,
unsigned int insize)
{
struct cros_ec_dev *ec_dev = charger->ec_dev;
struct cros_ec_command *msg;
int ret;
msg = kzalloc(sizeof(*msg) + max(outsize, insize), GFP_KERNEL);
if (!msg)
return -ENOMEM;
msg->version = version;
msg->command = ec_dev->cmd_offset + command;
msg->outsize = outsize;
msg->insize = insize;
if (outsize)
memcpy(msg->data, outdata, outsize);
ret = cros_ec_cmd_xfer_status(charger->ec_device, msg);
if (ret >= 0 && insize)
memcpy(indata, msg->data, insize);
kfree(msg);
return ret;
}
static const unsigned int pchg_cmd_version = 1;
static bool cros_pchg_cmd_ver_check(const struct charger_data *charger)
{
struct ec_params_get_cmd_versions_v1 req;
struct ec_response_get_cmd_versions rsp;
int ret;
req.cmd = EC_CMD_PCHG;
ret = cros_pchg_ec_command(charger, 1, EC_CMD_GET_CMD_VERSIONS,
&req, sizeof(req), &rsp, sizeof(rsp));
if (ret < 0) {
dev_warn(charger->dev,
"Unable to get versions of EC_CMD_PCHG (err:%d)\n",
ret);
return false;
}
return !!(rsp.version_mask & BIT(pchg_cmd_version));
}
static int cros_pchg_port_count(const struct charger_data *charger)
{
struct ec_response_pchg_count rsp;
int ret;
ret = cros_pchg_ec_command(charger, 0, EC_CMD_PCHG_COUNT,
NULL, 0, &rsp, sizeof(rsp));
if (ret < 0) {
dev_warn(charger->dev,
"Unable to get number or ports (err:%d)\n", ret);
return ret;
}
return rsp.port_count;
}
static int cros_pchg_get_status(struct port_data *port)
{
struct charger_data *charger = port->charger;
struct ec_params_pchg req;
struct ec_response_pchg rsp;
struct device *dev = charger->dev;
int old_status = port->psy_status;
int old_percentage = port->battery_percentage;
int ret;
req.port = port->port_number;
ret = cros_pchg_ec_command(charger, pchg_cmd_version, EC_CMD_PCHG,
&req, sizeof(req), &rsp, sizeof(rsp));
if (ret < 0) {
dev_err(dev, "Unable to get port.%d status (err:%d)\n",
port->port_number, ret);
return ret;
}
switch (rsp.state) {
case PCHG_STATE_RESET:
case PCHG_STATE_INITIALIZED:
case PCHG_STATE_ENABLED:
default:
port->psy_status = POWER_SUPPLY_STATUS_UNKNOWN;
port->charge_type = POWER_SUPPLY_CHARGE_TYPE_NONE;
break;
case PCHG_STATE_DETECTED:
port->psy_status = POWER_SUPPLY_STATUS_CHARGING;
port->charge_type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
break;
case PCHG_STATE_CHARGING:
port->psy_status = POWER_SUPPLY_STATUS_CHARGING;
port->charge_type = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
break;
case PCHG_STATE_FULL:
port->psy_status = POWER_SUPPLY_STATUS_FULL;
port->charge_type = POWER_SUPPLY_CHARGE_TYPE_NONE;
break;
}
port->battery_percentage = rsp.battery_percentage;
if (port->psy_status != old_status ||
port->battery_percentage != old_percentage)
power_supply_changed(port->psy);
dev_dbg(dev,
"Port %d: state=%d battery=%d%%\n",
port->port_number, rsp.state, rsp.battery_percentage);
return 0;
}
static int cros_pchg_get_port_status(struct port_data *port, bool ratelimit)
{
int ret;
if (ratelimit &&
time_is_after_jiffies(port->last_update + PCHG_CACHE_UPDATE_DELAY))
return 0;
ret = cros_pchg_get_status(port);
if (ret < 0)
return ret;
port->last_update = jiffies;
return ret;
}
static int cros_pchg_get_prop(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct port_data *port = power_supply_get_drvdata(psy);
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
case POWER_SUPPLY_PROP_CAPACITY:
case POWER_SUPPLY_PROP_CHARGE_TYPE:
cros_pchg_get_port_status(port, true);
break;
default:
break;
}
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
val->intval = port->psy_status;
break;
case POWER_SUPPLY_PROP_CAPACITY:
val->intval = port->battery_percentage;
break;
case POWER_SUPPLY_PROP_CHARGE_TYPE:
val->intval = port->charge_type;
break;
case POWER_SUPPLY_PROP_SCOPE:
val->intval = POWER_SUPPLY_SCOPE_DEVICE;
break;
default:
return -EINVAL;
}
return 0;
}
static int cros_pchg_event(const struct charger_data *charger,
unsigned long host_event)
{
int i;
for (i = 0; i < charger->num_registered_psy; i++)
cros_pchg_get_port_status(charger->ports[i], false);
return NOTIFY_OK;
}
static u32 cros_get_device_event(const struct charger_data *charger)
{
struct ec_params_device_event req;
struct ec_response_device_event rsp;
struct device *dev = charger->dev;
int ret;
req.param = EC_DEVICE_EVENT_PARAM_GET_CURRENT_EVENTS;
ret = cros_pchg_ec_command(charger, 0, EC_CMD_DEVICE_EVENT,
&req, sizeof(req), &rsp, sizeof(rsp));
if (ret < 0) {
dev_warn(dev, "Unable to get device events (err:%d)\n", ret);
return 0;
}
return rsp.event_mask;
}
static int cros_ec_notify(struct notifier_block *nb,
unsigned long queued_during_suspend,
void *data)
{
struct cros_ec_device *ec_dev = (struct cros_ec_device *)data;
u32 host_event = cros_ec_get_host_event(ec_dev);
struct charger_data *charger =
container_of(nb, struct charger_data, notifier);
u32 device_event_mask;
if (!host_event)
return NOTIFY_DONE;
if (!(host_event & EC_HOST_EVENT_MASK(EC_HOST_EVENT_DEVICE)))
return NOTIFY_DONE;
/*
* todo: Retrieve device event mask in common place
* (e.g. cros_ec_proto.c).
*/
device_event_mask = cros_get_device_event(charger);
if (!(device_event_mask & EC_DEVICE_EVENT_MASK(EC_DEVICE_EVENT_WLC)))
return NOTIFY_DONE;
return cros_pchg_event(charger, host_event);
}
static int cros_pchg_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
struct cros_ec_device *ec_device = ec_dev->ec_dev;
struct power_supply_desc *psy_desc;
struct charger_data *charger;
struct power_supply *psy;
struct port_data *port;
struct notifier_block *nb;
int num_ports;
int ret;
int i;
charger = devm_kzalloc(dev, sizeof(*charger), GFP_KERNEL);
if (!charger)
return -ENOMEM;
charger->dev = dev;
charger->ec_dev = ec_dev;
charger->ec_device = ec_device;
ret = cros_pchg_port_count(charger);
if (ret <= 0) {
/*
* This feature is enabled by the EC and the kernel driver is
* included by default for CrOS devices. Don't need to be loud
* since this error can be normal.
*/
dev_info(dev, "No peripheral charge ports (err:%d)\n", ret);
return -ENODEV;
}
if (!cros_pchg_cmd_ver_check(charger)) {
dev_err(dev, "EC_CMD_PCHG version %d isn't available.\n",
pchg_cmd_version);
return -EOPNOTSUPP;
}
num_ports = ret;
if (num_ports > EC_PCHG_MAX_PORTS) {
dev_err(dev, "Too many peripheral charge ports (%d)\n",
num_ports);
return -ENOBUFS;
}
dev_info(dev, "%d peripheral charge ports found\n", num_ports);
for (i = 0; i < num_ports; i++) {
struct power_supply_config psy_cfg = {};
port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
if (!port)
return -ENOMEM;
port->charger = charger;
port->port_number = i;
snprintf(port->name, sizeof(port->name), PCHG_DIR_NAME, i);
psy_desc = &port->psy_desc;
psy_desc->name = port->name;
psy_desc->type = POWER_SUPPLY_TYPE_BATTERY;
psy_desc->get_property = cros_pchg_get_prop;
psy_desc->external_power_changed = NULL;
psy_desc->properties = cros_pchg_props;
psy_desc->num_properties = ARRAY_SIZE(cros_pchg_props);
psy_cfg.drv_data = port;
psy = devm_power_supply_register(dev, psy_desc, &psy_cfg);
if (IS_ERR(psy))
return dev_err_probe(dev, PTR_ERR(psy),
"Failed to register power supply\n");
port->psy = psy;
charger->ports[charger->num_registered_psy++] = port;
}
if (!charger->num_registered_psy)
return -ENODEV;
nb = &charger->notifier;
nb->notifier_call = cros_ec_notify;
ret = blocking_notifier_chain_register(&ec_dev->ec_dev->event_notifier,
nb);
if (ret < 0)
dev_err(dev, "Failed to register notifier (err:%d)\n", ret);
return 0;
}
static struct platform_driver cros_pchg_driver = {
.driver = {
.name = DRV_NAME,
},
.probe = cros_pchg_probe
};
module_platform_driver(cros_pchg_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("ChromeOS EC peripheral device charger");
MODULE_ALIAS("platform:" DRV_NAME);
......@@ -679,7 +679,9 @@ static int cw_bat_probe(struct i2c_client *client)
&cw2015_bat_desc,
&psy_cfg);
if (IS_ERR(cw_bat->rk_bat)) {
dev_err(cw_bat->dev, "Failed to register power supply\n");
/* try again if this happens */
dev_err_probe(&client->dev, PTR_ERR(cw_bat->rk_bat),
"Failed to register power supply\n");
return PTR_ERR(cw_bat->rk_bat);
}
......
......@@ -36,8 +36,6 @@
/* Interrupt mask bits */
#define CONFIG_ALRT_BIT_ENBL (1 << 2)
#define STATUS_INTR_SOCMIN_BIT (1 << 10)
#define STATUS_INTR_SOCMAX_BIT (1 << 14)
#define VFSOC0_LOCK 0x0000
#define VFSOC0_UNLOCK 0x0080
......@@ -285,8 +283,6 @@ static int max17042_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042)
ret = regmap_read(map, MAX17042_V_empty, &data);
else if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055)
ret = regmap_read(map, MAX17055_V_empty, &data);
else
ret = regmap_read(map, MAX17047_V_empty, &data);
if (ret < 0)
......@@ -748,7 +744,7 @@ static inline void max17042_override_por_values(struct max17042_chip *chip)
struct max17042_config_data *config = chip->pdata->config_data;
max17042_override_por(map, MAX17042_TGAIN, config->tgain);
max17042_override_por(map, MAx17042_TOFF, config->toff);
max17042_override_por(map, MAX17042_TOFF, config->toff);
max17042_override_por(map, MAX17042_CGAIN, config->cgain);
max17042_override_por(map, MAX17042_COFF, config->coff);
......@@ -767,36 +763,36 @@ static inline void max17042_override_por_values(struct max17042_chip *chip)
max17042_override_por(map, MAX17042_FilterCFG, config->filter_cfg);
max17042_override_por(map, MAX17042_RelaxCFG, config->relax_cfg);
max17042_override_por(map, MAX17042_MiscCFG, config->misc_cfg);
max17042_override_por(map, MAX17042_MaskSOC, config->masksoc);
max17042_override_por(map, MAX17042_FullCAP, config->fullcap);
max17042_override_por(map, MAX17042_FullCAPNom, config->fullcapnom);
if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042)
max17042_override_por(map, MAX17042_SOC_empty,
config->socempty);
max17042_override_por(map, MAX17042_LAvg_empty, config->lavg_empty);
max17042_override_por(map, MAX17042_dQacc, config->dqacc);
max17042_override_por(map, MAX17042_dPacc, config->dpacc);
if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042)
max17042_override_por(map, MAX17042_V_empty, config->vempty);
if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055)
max17042_override_por(map, MAX17055_V_empty, config->vempty);
else
max17042_override_por(map, MAX17047_V_empty, config->vempty);
max17042_override_por(map, MAX17042_TempNom, config->temp_nom);
max17042_override_por(map, MAX17042_TempLim, config->temp_lim);
max17042_override_por(map, MAX17042_FCTC, config->fctc);
max17042_override_por(map, MAX17042_RCOMP0, config->rcomp0);
max17042_override_por(map, MAX17042_TempCo, config->tcompc0);
if (chip->chip_type &&
((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) ||
if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) {
max17042_override_por(map, MAX17042_MaskSOC, config->masksoc);
max17042_override_por(map, MAX17042_SOC_empty, config->socempty);
max17042_override_por(map, MAX17042_V_empty, config->vempty);
max17042_override_por(map, MAX17042_EmptyTempCo, config->empty_tempco);
max17042_override_por(map, MAX17042_K_empty0, config->kempty0);
}
if ((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) ||
(chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047) ||
(chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050))) {
max17042_override_por(map, MAX17042_EmptyTempCo,
config->empty_tempco);
max17042_override_por(map, MAX17042_K_empty0,
config->kempty0);
(chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050)) {
max17042_override_por(map, MAX17042_LAvg_empty, config->lavg_empty);
max17042_override_por(map, MAX17042_TempNom, config->temp_nom);
max17042_override_por(map, MAX17042_TempLim, config->temp_lim);
max17042_override_por(map, MAX17042_FCTC, config->fctc);
}
if ((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047) ||
(chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050) ||
(chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055)) {
max17042_override_por(map, MAX17047_V_empty, config->vempty);
}
}
......@@ -869,11 +865,14 @@ static irqreturn_t max17042_thread_handler(int id, void *dev)
{
struct max17042_chip *chip = dev;
u32 val;
int ret;
regmap_read(chip->regmap, MAX17042_STATUS, &val);
if ((val & STATUS_INTR_SOCMIN_BIT) ||
(val & STATUS_INTR_SOCMAX_BIT)) {
dev_info(&chip->client->dev, "SOC threshold INTR\n");
ret = regmap_read(chip->regmap, MAX17042_STATUS, &val);
if (ret)
return IRQ_HANDLED;
if ((val & STATUS_SMN_BIT) || (val & STATUS_SMX_BIT)) {
dev_dbg(&chip->client->dev, "SOC threshold INTR\n");
max17042_set_soc_threshold(chip, 1);
}
......@@ -1196,6 +1195,7 @@ static const struct of_device_id max17042_dt_match[] = {
{ .compatible = "maxim,max17047" },
{ .compatible = "maxim,max17050" },
{ .compatible = "maxim,max17055" },
{ .compatible = "maxim,max77849-battery" },
{ },
};
MODULE_DEVICE_TABLE(of, max17042_dt_match);
......@@ -1206,6 +1206,7 @@ static const struct i2c_device_id max17042_id[] = {
{ "max17047", MAXIM_DEVICE_TYPE_MAX17047 },
{ "max17050", MAXIM_DEVICE_TYPE_MAX17050 },
{ "max17055", MAXIM_DEVICE_TYPE_MAX17055 },
{ "max77849-battery", MAXIM_DEVICE_TYPE_MAX17047 },
{ }
};
MODULE_DEVICE_TABLE(i2c, max17042_id);
......
This diff is collapsed.
......@@ -571,6 +571,7 @@ int power_supply_get_battery_info(struct power_supply *psy,
int err, len, index;
const __be32 *list;
info->technology = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
info->energy_full_design_uwh = -EINVAL;
info->charge_full_design_uah = -EINVAL;
info->voltage_min_design_uv = -EINVAL;
......@@ -618,6 +619,24 @@ int power_supply_get_battery_info(struct power_supply *psy,
* Documentation/power/power_supply_class.rst.
*/
if (!of_property_read_string(battery_np, "device-chemistry", &value)) {
if (!strcmp("nickel-cadmium", value))
info->technology = POWER_SUPPLY_TECHNOLOGY_NiCd;
else if (!strcmp("nickel-metal-hydride", value))
info->technology = POWER_SUPPLY_TECHNOLOGY_NiMH;
else if (!strcmp("lithium-ion", value))
/* Imprecise lithium-ion type */
info->technology = POWER_SUPPLY_TECHNOLOGY_LION;
else if (!strcmp("lithium-ion-polymer", value))
info->technology = POWER_SUPPLY_TECHNOLOGY_LIPO;
else if (!strcmp("lithium-ion-iron-phosphate", value))
info->technology = POWER_SUPPLY_TECHNOLOGY_LiFe;
else if (!strcmp("lithium-ion-manganese-oxide", value))
info->technology = POWER_SUPPLY_TECHNOLOGY_LiMn;
else
dev_warn(&psy->dev, "%s unknown battery type\n", value);
}
of_property_read_u32(battery_np, "energy-full-design-microwatt-hours",
&info->energy_full_design_uwh);
of_property_read_u32(battery_np, "charge-full-design-microamp-hours",
......
......@@ -929,11 +929,8 @@ static int smbb_charger_probe(struct platform_device *pdev)
int irq;
irq = platform_get_irq_byname(pdev, smbb_charger_irqs[i].name);
if (irq < 0) {
dev_err(&pdev->dev, "failed to get irq '%s'\n",
smbb_charger_irqs[i].name);
if (irq < 0)
return irq;
}
smbb_charger_irqs[i].handler(irq, chg);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment