mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
power supply and reset changes for the 6.11 series
* power-supply core - new charging_orange_full_green RGB LED trigger - simplify and cleanup power-supply LED trigger code - expose power information via hwmon compatibility layer * new hardware support - enable battery support for Qualcomm Snapdragon X Elite - new battery driver for Maxim MAX17201/MAX17205 - new battery driver for Lenovo Yoga C630 laptop (custom EC) * cleanup 'struct i2c_device_id' initializations * misc. small battery driver cleanups and fixes -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE72YNB0Y/i3JqeVQT2O7X88g7+poFAmadpdQACgkQ2O7X88g7 +poOIBAAm8B28rdJc35M0qj4akFp67z84wxGs0yR3KmwwUyIv5bHMZKXuSgOdMJ7 bVA/W5Lvzi/Mp6bF5lt4EbFt3QGIEG2odWMWcoc/PTdKaPYC7CcDBVGCZr7hQFJS 2THzaUuLVDQzVwBc62YcFh7AB+xQmJ/SaX+Ci2k//vFyQJ1EfBiOkoq6MjJXCPcT hz21hXCQjGirNSsV4gxK1EwefrRomj4MVCHCf/E5i2tM2lNtO+HPu28UznJYEh9S NB+M4Z0EADnfPWoBmB3emonYYlGlYC34kYb6nqcn6sUm9usU9JUMeZBT1yOstUMd 3p5V+uvUFQ9MGqXUgN8Qd5/ZfszCZzX2TaHDnWWRF4g7KTdSpcXOXrLW4gEO3TFf BtUU0WvZLiwXjMPrtvdTIPJCFTStfLcIAtWEyUhdCLouR2nJsAIYyfMm5OOyktqK KGeRaJhBp8c2bJTU1Xxj4FkO07z0iSY2EGDFCuEe4sBCN5EMA/ClwN/35P7Fwv30 0sRjzwS/gRkT1IiLRjqu8We3dVUxclkgsXhZ/5UuOzRqTzV7VH0xYdgn6iCOs0nz RSLFo37DqjIYbAJGcv9E6/7TSy+lB1RVHQL1DsQVKOMTf4NW5REfSoMzbjPClj8u qYTVoONCXLQEzo8oxuIly9m6eeExA3+2ulvDq00FuDb+pCVZ1ig= =+h6p -----END PGP SIGNATURE----- Merge tag 'for-v6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply Pull power supply and reset updates from Sebastian Reichel: "Power-supply core: - new charging_orange_full_green RGB LED trigger - simplify and cleanup power-supply LED trigger code - expose power information via hwmon compatibility layer New hardware support: - enable battery support for Qualcomm Snapdragon X Elite - new battery driver for Maxim MAX17201/MAX17205 - new battery driver for Lenovo Yoga C630 laptop (custom EC) Cleanups: - cleanup 'struct i2c_device_id' initializations - misc small battery driver cleanups and fixes" * tag 'for-v6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: power: supply: sysfs: use power_supply_property_is_writeable() power: supply: qcom_battmgr: Enable battery support on x1e80100 power: supply: add support for MAX1720x standalone fuel gauge dt-bindings: power: supply: add support for MAX17201/MAX17205 fuel gauge power: reset: piix4: add missing MODULE_DESCRIPTION() macro power: supply: samsung-sdi-battery: Constify struct power_supply_maintenance_charge_table power: supply: samsung-sdi-battery: Constify struct power_supply_vbat_ri_table power: supply: lenovo_yoga_c630_battery: add Lenovo C630 driver power: supply: ingenic: Fix some error handling paths in ingenic_battery_get_property() power: supply: ab8500: Clean some error messages power: supply: ab8500: Use iio_read_channel_processed_scale() power: supply: ab8500: Fix error handling when calling iio_read_channel_processed() power: supply: hwmon: Add support for power sensors power: supply: ab8500: remove unused struct 'inst_curr_result_list' power: supply: bd99954: remove unused struct 'battery_data' power: supply: leds: Add activate() callback to triggers power: supply: leds: Share trig pointer for online and charging_full power: supply: leds: Add power_supply_[un]register_led_trigger() power: supply: Drop explicit initialization of struct i2c_device_id::driver_data to 0
This commit is contained in:
commit
fd71b9a07b
@ -0,0 +1,58 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/power/supply/maxim,max17201.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Maxim MAX17201 fuel gauge
|
||||
|
||||
maintainers:
|
||||
- Dimitri Fedrau <dima.fedrau@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: power-supply.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: maxim,max17201
|
||||
- items:
|
||||
- enum:
|
||||
- maxim,max17205
|
||||
- const: maxim,max17201
|
||||
|
||||
reg:
|
||||
items:
|
||||
- description: ModelGauge m5 registers
|
||||
- description: Nonvolatile registers
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: m5
|
||||
- const: nvmem
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- reg-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
fuel-gauge@36 {
|
||||
compatible = "maxim,max17201";
|
||||
reg = <0x36>, <0xb>;
|
||||
reg-names = "m5", "nvmem";
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <31 IRQ_TYPE_LEVEL_LOW>;
|
||||
};
|
||||
};
|
@ -106,4 +106,5 @@ static struct pci_driver piix4_poweroff_driver = {
|
||||
|
||||
module_pci_driver(piix4_poweroff_driver);
|
||||
MODULE_AUTHOR("Paul Burton <paul.burton@mips.com>");
|
||||
MODULE_DESCRIPTION("Intel PIIX4 power-off driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -167,6 +167,15 @@ config BATTERY_LEGO_EV3
|
||||
help
|
||||
Say Y here to enable support for the LEGO MINDSTORMS EV3 battery.
|
||||
|
||||
config BATTERY_LENOVO_YOGA_C630
|
||||
tristate "Lenovo Yoga C630 battery"
|
||||
depends on EC_LENOVO_YOGA_C630
|
||||
help
|
||||
This driver enables battery support on the Lenovo Yoga C630 laptop.
|
||||
|
||||
To compile the driver as a module, choose M here: the module will be
|
||||
called lenovo_yoga_c630_battery.
|
||||
|
||||
config BATTERY_PMU
|
||||
tristate "Apple PMU battery"
|
||||
depends on PPC32 && ADB_PMU
|
||||
@ -402,6 +411,18 @@ config BATTERY_MAX17042
|
||||
|
||||
Driver can be build as a module (max17042_battery).
|
||||
|
||||
config BATTERY_MAX1720X
|
||||
tristate "Maxim MAX17201/MAX17205 Fuel Gauge"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
MAX1720x is a family of fuel-gauge systems for lithium-ion (Li+)
|
||||
batteries in handheld and portable equipment. MAX17201 are
|
||||
configured to operate with a single lithium cell, the MAX17205
|
||||
can operate with multiple cells.
|
||||
|
||||
Say Y to include support for the MAX17201/MAX17205 Fuel Gauges.
|
||||
|
||||
config BATTERY_MAX1721X
|
||||
tristate "MAX17211/MAX17215 standalone gas-gauge"
|
||||
depends on W1
|
||||
|
@ -32,6 +32,7 @@ obj-$(CONFIG_BATTERY_DS2782) += ds2782_battery.o
|
||||
obj-$(CONFIG_BATTERY_GAUGE_LTC2941) += ltc2941-battery-gauge.o
|
||||
obj-$(CONFIG_BATTERY_GOLDFISH) += goldfish_battery.o
|
||||
obj-$(CONFIG_BATTERY_LEGO_EV3) += lego_ev3_battery.o
|
||||
obj-$(CONFIG_BATTERY_LENOVO_YOGA_C630) += lenovo_yoga_c630_battery.o
|
||||
obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
|
||||
obj-$(CONFIG_BATTERY_QCOM_BATTMGR) += qcom_battmgr.o
|
||||
obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
|
||||
@ -52,6 +53,7 @@ obj-$(CONFIG_CHARGER_DA9150) += da9150-charger.o
|
||||
obj-$(CONFIG_BATTERY_DA9150) += da9150-fg.o
|
||||
obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
|
||||
obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
|
||||
obj-$(CONFIG_BATTERY_MAX1720X) += max1720x_battery.o
|
||||
obj-$(CONFIG_BATTERY_MAX1721X) += max1721x_battery.o
|
||||
obj-$(CONFIG_BATTERY_RT5033) += rt5033_battery.o
|
||||
obj-$(CONFIG_CHARGER_RT5033) += rt5033_charger.o
|
||||
|
@ -1225,8 +1225,8 @@ static bool ab8500_chargalg_time_to_restart(struct ab8500_chargalg *di)
|
||||
*/
|
||||
static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di)
|
||||
{
|
||||
const struct power_supply_maintenance_charge_table *mt;
|
||||
struct power_supply_battery_info *bi = di->bm->bi;
|
||||
struct power_supply_maintenance_charge_table *mt;
|
||||
int charger_status;
|
||||
int ret;
|
||||
|
||||
|
@ -487,14 +487,17 @@ static int ab8500_charger_get_ac_voltage(struct ab8500_charger *di)
|
||||
|
||||
/* Only measure voltage if the charger is connected */
|
||||
if (di->ac.charger_connected) {
|
||||
ret = iio_read_channel_processed(di->adc_main_charger_v, &vch);
|
||||
if (ret < 0)
|
||||
dev_err(di->dev, "%s ADC conv failed,\n", __func__);
|
||||
/* Convert to microvolt, IIO returns millivolt */
|
||||
ret = iio_read_channel_processed_scale(di->adc_main_charger_v,
|
||||
&vch, 1000);
|
||||
if (ret < 0) {
|
||||
dev_err(di->dev, "%s ADC conv failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
vch = 0;
|
||||
}
|
||||
/* Convert to microvolt, IIO returns millivolt */
|
||||
return vch * 1000;
|
||||
return vch;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -539,14 +542,17 @@ static int ab8500_charger_get_vbus_voltage(struct ab8500_charger *di)
|
||||
|
||||
/* Only measure voltage if the charger is connected */
|
||||
if (di->usb.charger_connected) {
|
||||
ret = iio_read_channel_processed(di->adc_vbus_v, &vch);
|
||||
if (ret < 0)
|
||||
dev_err(di->dev, "%s ADC conv failed,\n", __func__);
|
||||
/* Convert to microvolt, IIO returns millivolt */
|
||||
ret = iio_read_channel_processed_scale(di->adc_vbus_v,
|
||||
&vch, 1000);
|
||||
if (ret < 0) {
|
||||
dev_err(di->dev, "%s ADC conv failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
vch = 0;
|
||||
}
|
||||
/* Convert to microvolt, IIO returns millivolt */
|
||||
return vch * 1000;
|
||||
return vch;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -562,14 +568,17 @@ static int ab8500_charger_get_usb_current(struct ab8500_charger *di)
|
||||
|
||||
/* Only measure current if the charger is online */
|
||||
if (di->usb.charger_online) {
|
||||
ret = iio_read_channel_processed(di->adc_usb_charger_c, &ich);
|
||||
if (ret < 0)
|
||||
dev_err(di->dev, "%s ADC conv failed,\n", __func__);
|
||||
/* Return microamperes */
|
||||
ret = iio_read_channel_processed_scale(di->adc_usb_charger_c,
|
||||
&ich, 1000);
|
||||
if (ret < 0) {
|
||||
dev_err(di->dev, "%s ADC conv failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
ich = 0;
|
||||
}
|
||||
/* Return microamperes */
|
||||
return ich * 1000;
|
||||
return ich;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -585,14 +594,17 @@ static int ab8500_charger_get_ac_current(struct ab8500_charger *di)
|
||||
|
||||
/* Only measure current if the charger is online */
|
||||
if (di->ac.charger_online) {
|
||||
ret = iio_read_channel_processed(di->adc_main_charger_c, &ich);
|
||||
if (ret < 0)
|
||||
dev_err(di->dev, "%s ADC conv failed,\n", __func__);
|
||||
/* Return microamperes */
|
||||
ret = iio_read_channel_processed_scale(di->adc_main_charger_c,
|
||||
&ich, 1000);
|
||||
if (ret < 0) {
|
||||
dev_err(di->dev, "%s ADC conv failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
ich = 0;
|
||||
}
|
||||
/* Return microamperes */
|
||||
return ich * 1000;
|
||||
return ich;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -149,11 +149,6 @@ struct ab8500_fg_flags {
|
||||
bool batt_id_received;
|
||||
};
|
||||
|
||||
struct inst_curr_result_list {
|
||||
struct list_head list;
|
||||
int *result;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ab8500_fg - ab8500 FG device information
|
||||
* @dev: Pointer to the structure device
|
||||
|
@ -727,7 +727,7 @@ static int adp5061_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adp5061_id[] = {
|
||||
{ "adp5061", 0},
|
||||
{ "adp5061" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adp5061_id);
|
||||
|
@ -70,13 +70,6 @@
|
||||
|
||||
#include "bd99954-charger.h"
|
||||
|
||||
struct battery_data {
|
||||
u16 precharge_current; /* Trickle-charge Current */
|
||||
u16 fc_reg_voltage; /* Fast Charging Regulation Voltage */
|
||||
u16 voltage_min;
|
||||
u16 voltage_max;
|
||||
};
|
||||
|
||||
/* Initial field values, converted to initial register values */
|
||||
struct bd9995x_init_data {
|
||||
u16 vsysreg_set; /* VSYS Regulation Setting */
|
||||
|
@ -489,7 +489,7 @@ static int bq24735_charger_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id bq24735_charger_id[] = {
|
||||
{ "bq24735-charger", 0 },
|
||||
{ "bq24735-charger" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, bq24735_charger_id);
|
||||
|
@ -1617,11 +1617,11 @@ static const struct dev_pm_ops bq25890_pm = {
|
||||
};
|
||||
|
||||
static const struct i2c_device_id bq25890_i2c_ids[] = {
|
||||
{ "bq25890", 0 },
|
||||
{ "bq25892", 0 },
|
||||
{ "bq25895", 0 },
|
||||
{ "bq25896", 0 },
|
||||
{},
|
||||
{ "bq25890" },
|
||||
{ "bq25892" },
|
||||
{ "bq25895" },
|
||||
{ "bq25896" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, bq25890_i2c_ids);
|
||||
|
||||
|
@ -731,7 +731,7 @@ static int __maybe_unused cw_bat_resume(struct device *dev)
|
||||
static SIMPLE_DEV_PM_OPS(cw_bat_pm_ops, cw_bat_suspend, cw_bat_resume);
|
||||
|
||||
static const struct i2c_device_id cw_bat_id_table[] = {
|
||||
{ "cw2015", 0 },
|
||||
{ "cw2015" },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -31,8 +31,9 @@ static int ingenic_battery_get_property(struct power_supply *psy,
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_HEALTH:
|
||||
ret = iio_read_channel_processed(bat->channel, &val->intval);
|
||||
val->intval *= 1000;
|
||||
ret = iio_read_channel_processed_scale(bat->channel,
|
||||
&val->intval,
|
||||
1000);
|
||||
if (val->intval < info->voltage_min_design_uv)
|
||||
val->intval = POWER_SUPPLY_HEALTH_DEAD;
|
||||
else if (val->intval > info->voltage_max_design_uv)
|
||||
@ -41,8 +42,9 @@ static int ingenic_battery_get_property(struct power_supply *psy,
|
||||
val->intval = POWER_SUPPLY_HEALTH_GOOD;
|
||||
return ret;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
ret = iio_read_channel_processed(bat->channel, &val->intval);
|
||||
val->intval *= 1000;
|
||||
ret = iio_read_channel_processed_scale(bat->channel,
|
||||
&val->intval,
|
||||
1000);
|
||||
return ret;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
|
||||
val->intval = info->voltage_min_design_uv;
|
||||
|
501
drivers/power/supply/lenovo_yoga_c630_battery.c
Normal file
501
drivers/power/supply/lenovo_yoga_c630_battery.c
Normal file
@ -0,0 +1,501 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2022-2024, Linaro Ltd
|
||||
* Authors:
|
||||
* Bjorn Andersson
|
||||
* Dmitry Baryshkov
|
||||
*/
|
||||
#include <linux/auxiliary_bus.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/cleanup.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/platform_data/lenovo-yoga-c630.h>
|
||||
|
||||
struct yoga_c630_psy {
|
||||
struct yoga_c630_ec *ec;
|
||||
struct device *dev;
|
||||
struct fwnode_handle *fwnode;
|
||||
struct notifier_block nb;
|
||||
|
||||
/* guards all battery properties and registration of power supplies */
|
||||
struct mutex lock;
|
||||
|
||||
struct power_supply *adp_psy;
|
||||
struct power_supply *bat_psy;
|
||||
|
||||
unsigned long last_status_update;
|
||||
|
||||
bool adapter_online;
|
||||
|
||||
bool unit_mA;
|
||||
|
||||
bool bat_present;
|
||||
unsigned int bat_status;
|
||||
unsigned int design_capacity;
|
||||
unsigned int design_voltage;
|
||||
unsigned int full_charge_capacity;
|
||||
|
||||
unsigned int capacity_now;
|
||||
unsigned int voltage_now;
|
||||
|
||||
int current_now;
|
||||
int rate_now;
|
||||
};
|
||||
|
||||
#define LENOVO_EC_CACHE_TIME (10 * HZ)
|
||||
|
||||
#define LENOVO_EC_ADPT_STATUS 0xa3
|
||||
#define LENOVO_EC_ADPT_STATUS_PRESENT BIT(7)
|
||||
#define LENOVO_EC_BAT_ATTRIBUTES 0xc0
|
||||
#define LENOVO_EC_BAT_ATTRIBUTES_UNIT_IS_MA BIT(1)
|
||||
#define LENOVO_EC_BAT_STATUS 0xc1
|
||||
#define LENOVO_EC_BAT_STATUS_DISCHARGING BIT(0)
|
||||
#define LENOVO_EC_BAT_STATUS_CHARGING BIT(1)
|
||||
#define LENOVO_EC_BAT_REMAIN_CAPACITY 0xc2
|
||||
#define LENOVO_EC_BAT_VOLTAGE 0xc6
|
||||
#define LENOVO_EC_BAT_DESIGN_VOLTAGE 0xc8
|
||||
#define LENOVO_EC_BAT_DESIGN_CAPACITY 0xca
|
||||
#define LENOVO_EC_BAT_FULL_CAPACITY 0xcc
|
||||
#define LENOVO_EC_BAT_CURRENT 0xd2
|
||||
#define LENOVO_EC_BAT_FULL_FACTORY 0xd6
|
||||
#define LENOVO_EC_BAT_PRESENT 0xda
|
||||
#define LENOVO_EC_BAT_PRESENT_IS_PRESENT BIT(0)
|
||||
#define LENOVO_EC_BAT_FULL_REGISTER 0xdb
|
||||
#define LENOVO_EC_BAT_FULL_REGISTER_IS_FACTORY BIT(0)
|
||||
|
||||
static int yoga_c630_psy_update_bat_info(struct yoga_c630_psy *ecbat)
|
||||
{
|
||||
struct yoga_c630_ec *ec = ecbat->ec;
|
||||
int val;
|
||||
|
||||
lockdep_assert_held(&ecbat->lock);
|
||||
|
||||
val = yoga_c630_ec_read8(ec, LENOVO_EC_BAT_PRESENT);
|
||||
if (val < 0)
|
||||
return val;
|
||||
ecbat->bat_present = !!(val & LENOVO_EC_BAT_PRESENT_IS_PRESENT);
|
||||
if (!ecbat->bat_present)
|
||||
return val;
|
||||
|
||||
val = yoga_c630_ec_read8(ec, LENOVO_EC_BAT_ATTRIBUTES);
|
||||
if (val < 0)
|
||||
return val;
|
||||
ecbat->unit_mA = val & LENOVO_EC_BAT_ATTRIBUTES_UNIT_IS_MA;
|
||||
|
||||
val = yoga_c630_ec_read16(ec, LENOVO_EC_BAT_DESIGN_CAPACITY);
|
||||
if (val < 0)
|
||||
return val;
|
||||
ecbat->design_capacity = val * 1000;
|
||||
|
||||
/*
|
||||
* DSDT has delays after most of EC reads in these methods.
|
||||
* Having no documentation for the EC we have to follow and sleep here.
|
||||
*/
|
||||
msleep(50);
|
||||
|
||||
val = yoga_c630_ec_read16(ec, LENOVO_EC_BAT_DESIGN_VOLTAGE);
|
||||
if (val < 0)
|
||||
return val;
|
||||
ecbat->design_voltage = val;
|
||||
|
||||
msleep(50);
|
||||
|
||||
val = yoga_c630_ec_read8(ec, LENOVO_EC_BAT_FULL_REGISTER);
|
||||
if (val < 0)
|
||||
return val;
|
||||
val = yoga_c630_ec_read16(ec,
|
||||
val & LENOVO_EC_BAT_FULL_REGISTER_IS_FACTORY ?
|
||||
LENOVO_EC_BAT_FULL_FACTORY :
|
||||
LENOVO_EC_BAT_FULL_CAPACITY);
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
ecbat->full_charge_capacity = val * 1000;
|
||||
|
||||
if (!ecbat->unit_mA) {
|
||||
ecbat->design_capacity *= 10;
|
||||
ecbat->full_charge_capacity *= 10;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int yoga_c630_psy_maybe_update_bat_status(struct yoga_c630_psy *ecbat)
|
||||
{
|
||||
struct yoga_c630_ec *ec = ecbat->ec;
|
||||
int current_mA;
|
||||
int val;
|
||||
|
||||
guard(mutex)(&ecbat->lock);
|
||||
if (time_before(jiffies, ecbat->last_status_update + LENOVO_EC_CACHE_TIME))
|
||||
return 0;
|
||||
|
||||
val = yoga_c630_ec_read8(ec, LENOVO_EC_BAT_STATUS);
|
||||
if (val < 0)
|
||||
return val;
|
||||
ecbat->bat_status = val;
|
||||
|
||||
msleep(50);
|
||||
|
||||
val = yoga_c630_ec_read16(ec, LENOVO_EC_BAT_REMAIN_CAPACITY);
|
||||
if (val < 0)
|
||||
return val;
|
||||
ecbat->capacity_now = val * 1000;
|
||||
|
||||
msleep(50);
|
||||
|
||||
val = yoga_c630_ec_read16(ec, LENOVO_EC_BAT_VOLTAGE);
|
||||
if (val < 0)
|
||||
return val;
|
||||
ecbat->voltage_now = val * 1000;
|
||||
|
||||
msleep(50);
|
||||
|
||||
val = yoga_c630_ec_read16(ec, LENOVO_EC_BAT_CURRENT);
|
||||
if (val < 0)
|
||||
return val;
|
||||
current_mA = sign_extend32(val, 15);
|
||||
ecbat->current_now = current_mA * 1000;
|
||||
ecbat->rate_now = current_mA * (ecbat->voltage_now / 1000);
|
||||
|
||||
msleep(50);
|
||||
|
||||
if (!ecbat->unit_mA)
|
||||
ecbat->capacity_now *= 10;
|
||||
|
||||
ecbat->last_status_update = jiffies;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int yoga_c630_psy_update_adapter_status(struct yoga_c630_psy *ecbat)
|
||||
{
|
||||
struct yoga_c630_ec *ec = ecbat->ec;
|
||||
int val;
|
||||
|
||||
guard(mutex)(&ecbat->lock);
|
||||
|
||||
val = yoga_c630_ec_read8(ec, LENOVO_EC_ADPT_STATUS);
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
ecbat->adapter_online = !!(val & LENOVO_EC_ADPT_STATUS_PRESENT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool yoga_c630_psy_is_charged(struct yoga_c630_psy *ecbat)
|
||||
{
|
||||
if (ecbat->bat_status != 0)
|
||||
return false;
|
||||
|
||||
if (ecbat->full_charge_capacity <= ecbat->capacity_now)
|
||||
return true;
|
||||
|
||||
if (ecbat->design_capacity <= ecbat->capacity_now)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int yoga_c630_psy_bat_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct yoga_c630_psy *ecbat = power_supply_get_drvdata(psy);
|
||||
int rc = 0;
|
||||
|
||||
if (!ecbat->bat_present && psp != POWER_SUPPLY_PROP_PRESENT)
|
||||
return -ENODEV;
|
||||
|
||||
rc = yoga_c630_psy_maybe_update_bat_status(ecbat);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
if (ecbat->bat_status & LENOVO_EC_BAT_STATUS_DISCHARGING)
|
||||
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
else if (ecbat->bat_status & LENOVO_EC_BAT_STATUS_CHARGING)
|
||||
val->intval = POWER_SUPPLY_STATUS_CHARGING;
|
||||
else if (yoga_c630_psy_is_charged(ecbat))
|
||||
val->intval = POWER_SUPPLY_STATUS_FULL;
|
||||
else
|
||||
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_PRESENT:
|
||||
val->intval = ecbat->bat_present;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
|
||||
val->intval = ecbat->design_voltage;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
|
||||
case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
|
||||
val->intval = ecbat->design_capacity;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_FULL:
|
||||
case POWER_SUPPLY_PROP_ENERGY_FULL:
|
||||
val->intval = ecbat->full_charge_capacity;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_NOW:
|
||||
case POWER_SUPPLY_PROP_ENERGY_NOW:
|
||||
val->intval = ecbat->capacity_now;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
||||
val->intval = ecbat->current_now;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_POWER_NOW:
|
||||
val->intval = ecbat->rate_now;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
val->intval = ecbat->voltage_now;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TECHNOLOGY:
|
||||
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_MODEL_NAME:
|
||||
val->strval = "PABAS0241231";
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_MANUFACTURER:
|
||||
val->strval = "Compal";
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_SCOPE:
|
||||
val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
|
||||
break;
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static enum power_supply_property yoga_c630_psy_bat_mA_properties[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL,
|
||||
POWER_SUPPLY_PROP_CHARGE_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
POWER_SUPPLY_PROP_POWER_NOW,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_TECHNOLOGY,
|
||||
POWER_SUPPLY_PROP_MODEL_NAME,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
POWER_SUPPLY_PROP_SCOPE,
|
||||
};
|
||||
|
||||
static enum power_supply_property yoga_c630_psy_bat_mWh_properties[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
|
||||
POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
|
||||
POWER_SUPPLY_PROP_ENERGY_FULL,
|
||||
POWER_SUPPLY_PROP_ENERGY_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
POWER_SUPPLY_PROP_POWER_NOW,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_TECHNOLOGY,
|
||||
POWER_SUPPLY_PROP_MODEL_NAME,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
POWER_SUPPLY_PROP_SCOPE,
|
||||
};
|
||||
|
||||
static const struct power_supply_desc yoga_c630_psy_bat_psy_desc_mA = {
|
||||
.name = "yoga-c630-battery",
|
||||
.type = POWER_SUPPLY_TYPE_BATTERY,
|
||||
.properties = yoga_c630_psy_bat_mA_properties,
|
||||
.num_properties = ARRAY_SIZE(yoga_c630_psy_bat_mA_properties),
|
||||
.get_property = yoga_c630_psy_bat_get_property,
|
||||
};
|
||||
|
||||
static const struct power_supply_desc yoga_c630_psy_bat_psy_desc_mWh = {
|
||||
.name = "yoga-c630-battery",
|
||||
.type = POWER_SUPPLY_TYPE_BATTERY,
|
||||
.properties = yoga_c630_psy_bat_mWh_properties,
|
||||
.num_properties = ARRAY_SIZE(yoga_c630_psy_bat_mWh_properties),
|
||||
.get_property = yoga_c630_psy_bat_get_property,
|
||||
};
|
||||
|
||||
static int yoga_c630_psy_adpt_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct yoga_c630_psy *ecbat = power_supply_get_drvdata(psy);
|
||||
int ret = 0;
|
||||
|
||||
ret = yoga_c630_psy_update_adapter_status(ecbat);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
val->intval = ecbat->adapter_online;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_USB_TYPE:
|
||||
val->intval = POWER_SUPPLY_USB_TYPE_C;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum power_supply_property yoga_c630_psy_adpt_properties[] = {
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
POWER_SUPPLY_PROP_USB_TYPE,
|
||||
};
|
||||
|
||||
static const enum power_supply_usb_type yoga_c630_psy_adpt_usb_type[] = {
|
||||
POWER_SUPPLY_USB_TYPE_C,
|
||||
};
|
||||
|
||||
static const struct power_supply_desc yoga_c630_psy_adpt_psy_desc = {
|
||||
.name = "yoga-c630-adapter",
|
||||
.type = POWER_SUPPLY_TYPE_USB,
|
||||
.usb_types = yoga_c630_psy_adpt_usb_type,
|
||||
.num_usb_types = ARRAY_SIZE(yoga_c630_psy_adpt_usb_type),
|
||||
.properties = yoga_c630_psy_adpt_properties,
|
||||
.num_properties = ARRAY_SIZE(yoga_c630_psy_adpt_properties),
|
||||
.get_property = yoga_c630_psy_adpt_get_property,
|
||||
};
|
||||
|
||||
static int yoga_c630_psy_register_bat_psy(struct yoga_c630_psy *ecbat)
|
||||
{
|
||||
struct power_supply_config bat_cfg = {};
|
||||
|
||||
bat_cfg.drv_data = ecbat;
|
||||
bat_cfg.fwnode = ecbat->fwnode;
|
||||
ecbat->bat_psy = power_supply_register_no_ws(ecbat->dev,
|
||||
ecbat->unit_mA ?
|
||||
&yoga_c630_psy_bat_psy_desc_mA :
|
||||
&yoga_c630_psy_bat_psy_desc_mWh,
|
||||
&bat_cfg);
|
||||
if (IS_ERR(ecbat->bat_psy)) {
|
||||
dev_err(ecbat->dev, "failed to register battery supply\n");
|
||||
return PTR_ERR(ecbat->bat_psy);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void yoga_c630_ec_refresh_bat_info(struct yoga_c630_psy *ecbat)
|
||||
{
|
||||
bool current_unit;
|
||||
|
||||
guard(mutex)(&ecbat->lock);
|
||||
|
||||
current_unit = ecbat->unit_mA;
|
||||
|
||||
yoga_c630_psy_update_bat_info(ecbat);
|
||||
|
||||
if (current_unit != ecbat->unit_mA) {
|
||||
power_supply_unregister(ecbat->bat_psy);
|
||||
yoga_c630_psy_register_bat_psy(ecbat);
|
||||
}
|
||||
}
|
||||
|
||||
static int yoga_c630_psy_notify(struct notifier_block *nb,
|
||||
unsigned long action, void *data)
|
||||
{
|
||||
struct yoga_c630_psy *ecbat = container_of(nb, struct yoga_c630_psy, nb);
|
||||
|
||||
switch (action) {
|
||||
case LENOVO_EC_EVENT_BAT_INFO:
|
||||
yoga_c630_ec_refresh_bat_info(ecbat);
|
||||
break;
|
||||
case LENOVO_EC_EVENT_BAT_ADPT_STATUS:
|
||||
power_supply_changed(ecbat->adp_psy);
|
||||
fallthrough;
|
||||
case LENOVO_EC_EVENT_BAT_STATUS:
|
||||
power_supply_changed(ecbat->bat_psy);
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static int yoga_c630_psy_probe(struct auxiliary_device *adev,
|
||||
const struct auxiliary_device_id *id)
|
||||
{
|
||||
struct yoga_c630_ec *ec = adev->dev.platform_data;
|
||||
struct power_supply_config adp_cfg = {};
|
||||
struct device *dev = &adev->dev;
|
||||
struct yoga_c630_psy *ecbat;
|
||||
int ret;
|
||||
|
||||
ecbat = devm_kzalloc(&adev->dev, sizeof(*ecbat), GFP_KERNEL);
|
||||
if (!ecbat)
|
||||
return -ENOMEM;
|
||||
|
||||
ecbat->ec = ec;
|
||||
ecbat->dev = dev;
|
||||
mutex_init(&ecbat->lock);
|
||||
ecbat->fwnode = adev->dev.parent->fwnode;
|
||||
ecbat->nb.notifier_call = yoga_c630_psy_notify;
|
||||
|
||||
auxiliary_set_drvdata(adev, ecbat);
|
||||
|
||||
adp_cfg.drv_data = ecbat;
|
||||
adp_cfg.fwnode = ecbat->fwnode;
|
||||
adp_cfg.supplied_to = (char **)&yoga_c630_psy_bat_psy_desc_mA.name;
|
||||
adp_cfg.num_supplicants = 1;
|
||||
ecbat->adp_psy = devm_power_supply_register_no_ws(dev, &yoga_c630_psy_adpt_psy_desc, &adp_cfg);
|
||||
if (IS_ERR(ecbat->adp_psy)) {
|
||||
dev_err(dev, "failed to register AC adapter supply\n");
|
||||
return PTR_ERR(ecbat->adp_psy);
|
||||
}
|
||||
|
||||
scoped_guard(mutex, &ecbat->lock) {
|
||||
ret = yoga_c630_psy_update_bat_info(ecbat);
|
||||
if (ret)
|
||||
goto err_unreg_bat;
|
||||
|
||||
ret = yoga_c630_psy_register_bat_psy(ecbat);
|
||||
if (ret)
|
||||
goto err_unreg_bat;
|
||||
}
|
||||
|
||||
ret = yoga_c630_ec_register_notify(ecbat->ec, &ecbat->nb);
|
||||
if (ret)
|
||||
goto err_unreg_bat;
|
||||
|
||||
return 0;
|
||||
|
||||
err_unreg_bat:
|
||||
power_supply_unregister(ecbat->bat_psy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void yoga_c630_psy_remove(struct auxiliary_device *adev)
|
||||
{
|
||||
struct yoga_c630_psy *ecbat = auxiliary_get_drvdata(adev);
|
||||
|
||||
yoga_c630_ec_unregister_notify(ecbat->ec, &ecbat->nb);
|
||||
power_supply_unregister(ecbat->bat_psy);
|
||||
}
|
||||
|
||||
static const struct auxiliary_device_id yoga_c630_psy_id_table[] = {
|
||||
{ .name = YOGA_C630_MOD_NAME "." YOGA_C630_DEV_PSY, },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(auxiliary, yoga_c630_psy_id_table);
|
||||
|
||||
static struct auxiliary_driver yoga_c630_psy_driver = {
|
||||
.name = YOGA_C630_DEV_PSY,
|
||||
.id_table = yoga_c630_psy_id_table,
|
||||
.probe = yoga_c630_psy_probe,
|
||||
.remove = yoga_c630_psy_remove,
|
||||
};
|
||||
|
||||
module_auxiliary_driver(yoga_c630_psy_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Lenovo Yoga C630 psy");
|
||||
MODULE_LICENSE("GPL");
|
@ -584,7 +584,7 @@ static const struct of_device_id lp8727_dt_ids[] __maybe_unused = {
|
||||
MODULE_DEVICE_TABLE(of, lp8727_dt_ids);
|
||||
|
||||
static const struct i2c_device_id lp8727_ids[] = {
|
||||
{"lp8727", 0},
|
||||
{ "lp8727" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, lp8727_ids);
|
||||
|
@ -903,8 +903,8 @@ static void ltc4162l_alert(struct i2c_client *client,
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ltc4162l_i2c_id_table[] = {
|
||||
{ "ltc4162-l", 0 },
|
||||
{ },
|
||||
{ "ltc4162-l" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ltc4162l_i2c_id_table);
|
||||
|
||||
|
@ -300,7 +300,7 @@ static int max14656_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id max14656_id[] = {
|
||||
{ "max14656", 0 },
|
||||
{ "max14656" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max14656_id);
|
||||
|
337
drivers/power/supply/max1720x_battery.c
Normal file
337
drivers/power/supply/max1720x_battery.c
Normal file
@ -0,0 +1,337 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Fuel gauge driver for Maxim 17201/17205
|
||||
*
|
||||
* based on max1721x_battery.c
|
||||
*
|
||||
* Copyright (C) 2024 Liebherr-Electronics and Drives GmbH
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
/* Nonvolatile registers */
|
||||
#define MAX1720X_NRSENSE 0xCF /* RSense in 10^-5 Ohm */
|
||||
|
||||
/* ModelGauge m5 */
|
||||
#define MAX172XX_STATUS 0x00 /* Status */
|
||||
#define MAX172XX_STATUS_BAT_ABSENT BIT(3) /* Battery absent */
|
||||
#define MAX172XX_REPCAP 0x05 /* Average capacity */
|
||||
#define MAX172XX_REPSOC 0x06 /* Percentage of charge */
|
||||
#define MAX172XX_TEMP 0x08 /* Temperature */
|
||||
#define MAX172XX_CURRENT 0x0A /* Actual current */
|
||||
#define MAX172XX_AVG_CURRENT 0x0B /* Average current */
|
||||
#define MAX172XX_TTE 0x11 /* Time to empty */
|
||||
#define MAX172XX_AVG_TA 0x16 /* Average temperature */
|
||||
#define MAX172XX_CYCLES 0x17
|
||||
#define MAX172XX_DESIGN_CAP 0x18 /* Design capacity */
|
||||
#define MAX172XX_AVG_VCELL 0x19
|
||||
#define MAX172XX_TTF 0x20 /* Time to full */
|
||||
#define MAX172XX_DEV_NAME 0x21 /* Device name */
|
||||
#define MAX172XX_DEV_NAME_TYPE_MASK GENMASK(3, 0)
|
||||
#define MAX172XX_DEV_NAME_TYPE_MAX17201 BIT(0)
|
||||
#define MAX172XX_DEV_NAME_TYPE_MAX17205 (BIT(0) | BIT(2))
|
||||
#define MAX172XX_QR_TABLE10 0x22
|
||||
#define MAX172XX_BATT 0xDA /* Battery voltage */
|
||||
#define MAX172XX_ATAVCAP 0xDF
|
||||
|
||||
static const char *const max1720x_manufacturer = "Maxim Integrated";
|
||||
static const char *const max17201_model = "MAX17201";
|
||||
static const char *const max17205_model = "MAX17205";
|
||||
|
||||
struct max1720x_device_info {
|
||||
struct regmap *regmap;
|
||||
int rsense;
|
||||
};
|
||||
|
||||
/*
|
||||
* Model Gauge M5 Algorithm output register
|
||||
* Volatile data (must not be cached)
|
||||
*/
|
||||
static const struct regmap_range max1720x_volatile_allow[] = {
|
||||
regmap_reg_range(MAX172XX_STATUS, MAX172XX_CYCLES),
|
||||
regmap_reg_range(MAX172XX_AVG_VCELL, MAX172XX_TTF),
|
||||
regmap_reg_range(MAX172XX_QR_TABLE10, MAX172XX_ATAVCAP),
|
||||
};
|
||||
|
||||
static const struct regmap_range max1720x_readable_allow[] = {
|
||||
regmap_reg_range(MAX172XX_STATUS, MAX172XX_ATAVCAP),
|
||||
};
|
||||
|
||||
static const struct regmap_range max1720x_readable_deny[] = {
|
||||
/* unused registers */
|
||||
regmap_reg_range(0x24, 0x26),
|
||||
regmap_reg_range(0x30, 0x31),
|
||||
regmap_reg_range(0x33, 0x34),
|
||||
regmap_reg_range(0x37, 0x37),
|
||||
regmap_reg_range(0x3B, 0x3C),
|
||||
regmap_reg_range(0x40, 0x41),
|
||||
regmap_reg_range(0x43, 0x44),
|
||||
regmap_reg_range(0x47, 0x49),
|
||||
regmap_reg_range(0x4B, 0x4C),
|
||||
regmap_reg_range(0x4E, 0xAF),
|
||||
regmap_reg_range(0xB1, 0xB3),
|
||||
regmap_reg_range(0xB5, 0xB7),
|
||||
regmap_reg_range(0xBF, 0xD0),
|
||||
regmap_reg_range(0xDB, 0xDB),
|
||||
regmap_reg_range(0xE0, 0xFF),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table max1720x_readable_regs = {
|
||||
.yes_ranges = max1720x_readable_allow,
|
||||
.n_yes_ranges = ARRAY_SIZE(max1720x_readable_allow),
|
||||
.no_ranges = max1720x_readable_deny,
|
||||
.n_no_ranges = ARRAY_SIZE(max1720x_readable_deny),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table max1720x_volatile_regs = {
|
||||
.yes_ranges = max1720x_volatile_allow,
|
||||
.n_yes_ranges = ARRAY_SIZE(max1720x_volatile_allow),
|
||||
.no_ranges = max1720x_readable_deny,
|
||||
.n_no_ranges = ARRAY_SIZE(max1720x_readable_deny),
|
||||
};
|
||||
|
||||
static const struct regmap_config max1720x_regmap_cfg = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 16,
|
||||
.max_register = MAX172XX_ATAVCAP,
|
||||
.val_format_endian = REGMAP_ENDIAN_LITTLE,
|
||||
.rd_table = &max1720x_readable_regs,
|
||||
.volatile_table = &max1720x_volatile_regs,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static const enum power_supply_property max1720x_battery_props[] = {
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_CAPACITY,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
|
||||
POWER_SUPPLY_PROP_CHARGE_AVG,
|
||||
POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
|
||||
POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
|
||||
POWER_SUPPLY_PROP_TEMP,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
POWER_SUPPLY_PROP_CURRENT_AVG,
|
||||
POWER_SUPPLY_PROP_MODEL_NAME,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
};
|
||||
|
||||
/* Convert regs value to power_supply units */
|
||||
|
||||
static int max172xx_time_to_ps(unsigned int reg)
|
||||
{
|
||||
return reg * 5625 / 1000; /* in sec. */
|
||||
}
|
||||
|
||||
static int max172xx_percent_to_ps(unsigned int reg)
|
||||
{
|
||||
return reg / 256; /* in percent from 0 to 100 */
|
||||
}
|
||||
|
||||
static int max172xx_voltage_to_ps(unsigned int reg)
|
||||
{
|
||||
return reg * 1250; /* in uV */
|
||||
}
|
||||
|
||||
static int max172xx_capacity_to_ps(unsigned int reg)
|
||||
{
|
||||
return reg * 500; /* in uAh */
|
||||
}
|
||||
|
||||
/*
|
||||
* Current and temperature is signed values, so unsigned regs
|
||||
* value must be converted to signed type
|
||||
*/
|
||||
|
||||
static int max172xx_temperature_to_ps(unsigned int reg)
|
||||
{
|
||||
int val = (int16_t)reg;
|
||||
|
||||
return val * 10 / 256; /* in tenths of deg. C */
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculating current registers resolution:
|
||||
*
|
||||
* RSense stored in 10^-5 Ohm, so mesaurment voltage must be
|
||||
* in 10^-11 Volts for get current in uA.
|
||||
* 16 bit current reg fullscale +/-51.2mV is 102400 uV.
|
||||
* So: 102400 / 65535 * 10^5 = 156252
|
||||
*/
|
||||
static int max172xx_current_to_voltage(unsigned int reg)
|
||||
{
|
||||
int val = (int16_t)reg;
|
||||
|
||||
return val * 156252;
|
||||
}
|
||||
|
||||
static int max1720x_battery_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct max1720x_device_info *info = power_supply_get_drvdata(psy);
|
||||
unsigned int reg_val;
|
||||
int ret = 0;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_PRESENT:
|
||||
/*
|
||||
* POWER_SUPPLY_PROP_PRESENT will always readable via
|
||||
* sysfs interface. Value return 0 if battery not
|
||||
* present or unaccesable via I2c.
|
||||
*/
|
||||
ret = regmap_read(info->regmap, MAX172XX_STATUS, ®_val);
|
||||
if (ret < 0) {
|
||||
val->intval = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
val->intval = !FIELD_GET(MAX172XX_STATUS_BAT_ABSENT, reg_val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CAPACITY:
|
||||
ret = regmap_read(info->regmap, MAX172XX_REPSOC, ®_val);
|
||||
val->intval = max172xx_percent_to_ps(reg_val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
ret = regmap_read(info->regmap, MAX172XX_BATT, ®_val);
|
||||
val->intval = max172xx_voltage_to_ps(reg_val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
|
||||
ret = regmap_read(info->regmap, MAX172XX_DESIGN_CAP, ®_val);
|
||||
val->intval = max172xx_capacity_to_ps(reg_val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_AVG:
|
||||
ret = regmap_read(info->regmap, MAX172XX_REPCAP, ®_val);
|
||||
val->intval = max172xx_capacity_to_ps(reg_val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
|
||||
ret = regmap_read(info->regmap, MAX172XX_TTE, ®_val);
|
||||
val->intval = max172xx_time_to_ps(reg_val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG:
|
||||
ret = regmap_read(info->regmap, MAX172XX_TTF, ®_val);
|
||||
val->intval = max172xx_time_to_ps(reg_val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TEMP:
|
||||
ret = regmap_read(info->regmap, MAX172XX_TEMP, ®_val);
|
||||
val->intval = max172xx_temperature_to_ps(reg_val);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
||||
ret = regmap_read(info->regmap, MAX172XX_CURRENT, ®_val);
|
||||
val->intval = max172xx_current_to_voltage(reg_val) / info->rsense;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CURRENT_AVG:
|
||||
ret = regmap_read(info->regmap, MAX172XX_AVG_CURRENT, ®_val);
|
||||
val->intval = max172xx_current_to_voltage(reg_val) / info->rsense;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_MODEL_NAME:
|
||||
ret = regmap_read(info->regmap, MAX172XX_DEV_NAME, ®_val);
|
||||
reg_val = FIELD_GET(MAX172XX_DEV_NAME_TYPE_MASK, reg_val);
|
||||
if (reg_val == MAX172XX_DEV_NAME_TYPE_MAX17201)
|
||||
val->strval = max17201_model;
|
||||
else if (reg_val == MAX172XX_DEV_NAME_TYPE_MAX17205)
|
||||
val->strval = max17205_model;
|
||||
else
|
||||
return -ENODEV;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_MANUFACTURER:
|
||||
val->strval = max1720x_manufacturer;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max1720x_probe_sense_resistor(struct i2c_client *client,
|
||||
struct max1720x_device_info *info)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct i2c_client *ancillary;
|
||||
int ret;
|
||||
|
||||
ancillary = i2c_new_ancillary_device(client, "nvmem", 0xb);
|
||||
if (IS_ERR(ancillary)) {
|
||||
dev_err(dev, "Failed to initialize ancillary i2c device\n");
|
||||
return PTR_ERR(ancillary);
|
||||
}
|
||||
|
||||
ret = i2c_smbus_read_word_data(ancillary, MAX1720X_NRSENSE);
|
||||
i2c_unregister_device(ancillary);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
info->rsense = ret;
|
||||
if (!info->rsense) {
|
||||
dev_warn(dev, "RSense not calibrated, set 10 mOhms!\n");
|
||||
info->rsense = 1000; /* in regs in 10^-5 */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct power_supply_desc max1720x_bat_desc = {
|
||||
.name = "max1720x",
|
||||
.no_thermal = true,
|
||||
.type = POWER_SUPPLY_TYPE_BATTERY,
|
||||
.properties = max1720x_battery_props,
|
||||
.num_properties = ARRAY_SIZE(max1720x_battery_props),
|
||||
.get_property = max1720x_battery_get_property,
|
||||
};
|
||||
|
||||
static int max1720x_probe(struct i2c_client *client)
|
||||
{
|
||||
struct power_supply_config psy_cfg = {};
|
||||
struct device *dev = &client->dev;
|
||||
struct max1720x_device_info *info;
|
||||
struct power_supply *bat;
|
||||
int ret;
|
||||
|
||||
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
psy_cfg.drv_data = info;
|
||||
psy_cfg.fwnode = dev_fwnode(dev);
|
||||
info->regmap = devm_regmap_init_i2c(client, &max1720x_regmap_cfg);
|
||||
if (IS_ERR(info->regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(info->regmap),
|
||||
"regmap initialization failed\n");
|
||||
|
||||
ret = max1720x_probe_sense_resistor(client, info);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"Failed to read sense resistor value\n");
|
||||
|
||||
bat = devm_power_supply_register(dev, &max1720x_bat_desc, &psy_cfg);
|
||||
if (IS_ERR(bat))
|
||||
return dev_err_probe(dev, PTR_ERR(bat),
|
||||
"Failed to register power supply\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id max1720x_of_match[] = {
|
||||
{ .compatible = "maxim,max17201" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max1720x_of_match);
|
||||
|
||||
static struct i2c_driver max1720x_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "max1720x",
|
||||
.of_match_table = max1720x_of_match,
|
||||
},
|
||||
.probe = max1720x_probe,
|
||||
};
|
||||
module_i2c_driver(max1720x_i2c_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Dimitri Fedrau <dima.fedrau@gmail.com>");
|
||||
MODULE_DESCRIPTION("Maxim MAX17201/MAX17205 Fuel Gauge IC driver");
|
@ -483,8 +483,8 @@ static int max77976_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id max77976_i2c_id[] = {
|
||||
{ MAX77976_DRIVER_NAME, 0 },
|
||||
{ },
|
||||
{ MAX77976_DRIVER_NAME },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max77976_i2c_id);
|
||||
|
||||
|
@ -284,7 +284,7 @@ static int mm8013_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id mm8013_id_table[] = {
|
||||
{ "mm8013", 0 },
|
||||
{ "mm8013" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mm8013_id_table);
|
||||
|
@ -1024,7 +1024,7 @@ EXPORT_SYMBOL_GPL(power_supply_temp2resist_simple);
|
||||
int power_supply_vbat2ri(struct power_supply_battery_info *info,
|
||||
int vbat_uv, bool charging)
|
||||
{
|
||||
struct power_supply_vbat_ri_table *vbat2ri;
|
||||
const struct power_supply_vbat_ri_table *vbat2ri;
|
||||
int table_len;
|
||||
int i, high, low;
|
||||
|
||||
@ -1072,7 +1072,7 @@ int power_supply_vbat2ri(struct power_supply_battery_info *info,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(power_supply_vbat2ri);
|
||||
|
||||
struct power_supply_maintenance_charge_table *
|
||||
const struct power_supply_maintenance_charge_table *
|
||||
power_supply_get_maintenance_charging_setting(struct power_supply_battery_info *info,
|
||||
int index)
|
||||
{
|
||||
|
@ -48,6 +48,18 @@ static int power_supply_hwmon_curr_to_property(u32 attr)
|
||||
}
|
||||
}
|
||||
|
||||
static int power_supply_hwmon_power_to_property(u32 attr)
|
||||
{
|
||||
switch (attr) {
|
||||
case hwmon_power_input:
|
||||
return POWER_SUPPLY_PROP_POWER_NOW;
|
||||
case hwmon_power_average:
|
||||
return POWER_SUPPLY_PROP_POWER_AVG;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int power_supply_hwmon_temp_to_property(u32 attr, int channel)
|
||||
{
|
||||
if (channel) {
|
||||
@ -90,6 +102,8 @@ power_supply_hwmon_to_property(enum hwmon_sensor_types type,
|
||||
return power_supply_hwmon_in_to_property(attr);
|
||||
case hwmon_curr:
|
||||
return power_supply_hwmon_curr_to_property(attr);
|
||||
case hwmon_power:
|
||||
return power_supply_hwmon_power_to_property(attr);
|
||||
case hwmon_temp:
|
||||
return power_supply_hwmon_temp_to_property(attr, channel);
|
||||
default:
|
||||
@ -229,6 +243,11 @@ power_supply_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
case hwmon_in:
|
||||
pspval.intval = DIV_ROUND_CLOSEST(pspval.intval, 1000);
|
||||
break;
|
||||
case hwmon_power:
|
||||
/*
|
||||
* Power properties are already in microwatts.
|
||||
*/
|
||||
break;
|
||||
/*
|
||||
* Temp needs to be converted from 1/10 C to milli-C
|
||||
*/
|
||||
@ -311,6 +330,10 @@ static const struct hwmon_channel_info * const power_supply_hwmon_info[] = {
|
||||
HWMON_C_MAX |
|
||||
HWMON_C_INPUT),
|
||||
|
||||
HWMON_CHANNEL_INFO(power,
|
||||
HWMON_P_INPUT |
|
||||
HWMON_P_AVERAGE),
|
||||
|
||||
HWMON_CHANNEL_INFO(in,
|
||||
HWMON_I_AVERAGE |
|
||||
HWMON_I_MIN |
|
||||
@ -359,6 +382,8 @@ int power_supply_add_hwmon_sysfs(struct power_supply *psy)
|
||||
case POWER_SUPPLY_PROP_CURRENT_AVG:
|
||||
case POWER_SUPPLY_PROP_CURRENT_MAX:
|
||||
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
||||
case POWER_SUPPLY_PROP_POWER_AVG:
|
||||
case POWER_SUPPLY_PROP_POWER_NOW:
|
||||
case POWER_SUPPLY_PROP_TEMP:
|
||||
case POWER_SUPPLY_PROP_TEMP_MAX:
|
||||
case POWER_SUPPLY_PROP_TEMP_MIN:
|
||||
|
@ -19,6 +19,76 @@
|
||||
|
||||
/* Battery specific LEDs triggers. */
|
||||
|
||||
struct power_supply_led_trigger {
|
||||
struct led_trigger trig;
|
||||
struct power_supply *psy;
|
||||
};
|
||||
|
||||
#define trigger_to_psy_trigger(trigger) \
|
||||
container_of(trigger, struct power_supply_led_trigger, trig)
|
||||
|
||||
static int power_supply_led_trigger_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct power_supply_led_trigger *psy_trig =
|
||||
trigger_to_psy_trigger(led_cdev->trigger);
|
||||
|
||||
/* Sync current power-supply state to LED being activated */
|
||||
power_supply_update_leds(psy_trig->psy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int power_supply_register_led_trigger(struct power_supply *psy,
|
||||
const char *name_template,
|
||||
struct led_trigger **tp, int *err)
|
||||
{
|
||||
struct power_supply_led_trigger *psy_trig;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
/* Bail on previous errors */
|
||||
if (err && *err)
|
||||
return *err;
|
||||
|
||||
psy_trig = kzalloc(sizeof(*psy_trig), GFP_KERNEL);
|
||||
if (!psy_trig)
|
||||
goto err_free_trigger;
|
||||
|
||||
psy_trig->trig.name = kasprintf(GFP_KERNEL, name_template, psy->desc->name);
|
||||
if (!psy_trig->trig.name)
|
||||
goto err_free_trigger;
|
||||
|
||||
psy_trig->trig.activate = power_supply_led_trigger_activate;
|
||||
psy_trig->psy = psy;
|
||||
|
||||
ret = led_trigger_register(&psy_trig->trig);
|
||||
if (ret)
|
||||
goto err_free_name;
|
||||
|
||||
*tp = &psy_trig->trig;
|
||||
return 0;
|
||||
|
||||
err_free_name:
|
||||
kfree(psy_trig->trig.name);
|
||||
err_free_trigger:
|
||||
kfree(psy_trig);
|
||||
if (err)
|
||||
*err = ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void power_supply_unregister_led_trigger(struct led_trigger *trig)
|
||||
{
|
||||
struct power_supply_led_trigger *psy_trig;
|
||||
|
||||
if (!trig)
|
||||
return;
|
||||
|
||||
psy_trig = trigger_to_psy_trigger(trig);
|
||||
led_trigger_unregister(&psy_trig->trig);
|
||||
kfree(psy_trig->trig.name);
|
||||
kfree(psy_trig);
|
||||
}
|
||||
|
||||
static void power_supply_update_bat_leds(struct power_supply *psy)
|
||||
{
|
||||
union power_supply_propval status;
|
||||
@ -32,7 +102,7 @@ static void power_supply_update_bat_leds(struct power_supply *psy)
|
||||
|
||||
switch (status.intval) {
|
||||
case POWER_SUPPLY_STATUS_FULL:
|
||||
led_trigger_event(psy->charging_full_trig, LED_FULL);
|
||||
led_trigger_event(psy->trig, LED_FULL);
|
||||
led_trigger_event(psy->charging_trig, LED_OFF);
|
||||
led_trigger_event(psy->full_trig, LED_FULL);
|
||||
/* Going from blink to LED on requires a LED_OFF event to stop blink */
|
||||
@ -44,7 +114,7 @@ static void power_supply_update_bat_leds(struct power_supply *psy)
|
||||
LED_FULL);
|
||||
break;
|
||||
case POWER_SUPPLY_STATUS_CHARGING:
|
||||
led_trigger_event(psy->charging_full_trig, LED_FULL);
|
||||
led_trigger_event(psy->trig, LED_FULL);
|
||||
led_trigger_event(psy->charging_trig, LED_FULL);
|
||||
led_trigger_event(psy->full_trig, LED_OFF);
|
||||
led_trigger_blink(psy->charging_blink_full_solid_trig, 0, 0);
|
||||
@ -54,7 +124,7 @@ static void power_supply_update_bat_leds(struct power_supply *psy)
|
||||
LED_FULL);
|
||||
break;
|
||||
default:
|
||||
led_trigger_event(psy->charging_full_trig, LED_OFF);
|
||||
led_trigger_event(psy->trig, LED_OFF);
|
||||
led_trigger_event(psy->charging_trig, LED_OFF);
|
||||
led_trigger_event(psy->full_trig, LED_OFF);
|
||||
led_trigger_event(psy->charging_blink_full_solid_trig,
|
||||
@ -65,69 +135,33 @@ static void power_supply_update_bat_leds(struct power_supply *psy)
|
||||
}
|
||||
}
|
||||
|
||||
static int power_supply_create_bat_triggers(struct power_supply *psy)
|
||||
{
|
||||
psy->charging_full_trig_name = kasprintf(GFP_KERNEL,
|
||||
"%s-charging-or-full", psy->desc->name);
|
||||
if (!psy->charging_full_trig_name)
|
||||
goto charging_full_failed;
|
||||
|
||||
psy->charging_trig_name = kasprintf(GFP_KERNEL,
|
||||
"%s-charging", psy->desc->name);
|
||||
if (!psy->charging_trig_name)
|
||||
goto charging_failed;
|
||||
|
||||
psy->full_trig_name = kasprintf(GFP_KERNEL, "%s-full", psy->desc->name);
|
||||
if (!psy->full_trig_name)
|
||||
goto full_failed;
|
||||
|
||||
psy->charging_blink_full_solid_trig_name = kasprintf(GFP_KERNEL,
|
||||
"%s-charging-blink-full-solid", psy->desc->name);
|
||||
if (!psy->charging_blink_full_solid_trig_name)
|
||||
goto charging_blink_full_solid_failed;
|
||||
|
||||
psy->charging_orange_full_green_trig_name = kasprintf(GFP_KERNEL,
|
||||
"%s-charging-orange-full-green", psy->desc->name);
|
||||
if (!psy->charging_orange_full_green_trig_name)
|
||||
goto charging_red_full_green_failed;
|
||||
|
||||
led_trigger_register_simple(psy->charging_full_trig_name,
|
||||
&psy->charging_full_trig);
|
||||
led_trigger_register_simple(psy->charging_trig_name,
|
||||
&psy->charging_trig);
|
||||
led_trigger_register_simple(psy->full_trig_name,
|
||||
&psy->full_trig);
|
||||
led_trigger_register_simple(psy->charging_blink_full_solid_trig_name,
|
||||
&psy->charging_blink_full_solid_trig);
|
||||
led_trigger_register_simple(psy->charging_orange_full_green_trig_name,
|
||||
&psy->charging_orange_full_green_trig);
|
||||
|
||||
return 0;
|
||||
|
||||
charging_red_full_green_failed:
|
||||
kfree(psy->charging_blink_full_solid_trig_name);
|
||||
charging_blink_full_solid_failed:
|
||||
kfree(psy->full_trig_name);
|
||||
full_failed:
|
||||
kfree(psy->charging_trig_name);
|
||||
charging_failed:
|
||||
kfree(psy->charging_full_trig_name);
|
||||
charging_full_failed:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void power_supply_remove_bat_triggers(struct power_supply *psy)
|
||||
{
|
||||
led_trigger_unregister_simple(psy->charging_full_trig);
|
||||
led_trigger_unregister_simple(psy->charging_trig);
|
||||
led_trigger_unregister_simple(psy->full_trig);
|
||||
led_trigger_unregister_simple(psy->charging_blink_full_solid_trig);
|
||||
led_trigger_unregister_simple(psy->charging_orange_full_green_trig);
|
||||
kfree(psy->charging_blink_full_solid_trig_name);
|
||||
kfree(psy->full_trig_name);
|
||||
kfree(psy->charging_trig_name);
|
||||
kfree(psy->charging_full_trig_name);
|
||||
kfree(psy->charging_orange_full_green_trig_name);
|
||||
power_supply_unregister_led_trigger(psy->trig);
|
||||
power_supply_unregister_led_trigger(psy->charging_trig);
|
||||
power_supply_unregister_led_trigger(psy->full_trig);
|
||||
power_supply_unregister_led_trigger(psy->charging_blink_full_solid_trig);
|
||||
power_supply_unregister_led_trigger(psy->charging_orange_full_green_trig);
|
||||
}
|
||||
|
||||
static int power_supply_create_bat_triggers(struct power_supply *psy)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
power_supply_register_led_trigger(psy, "%s-charging-or-full",
|
||||
&psy->trig, &err);
|
||||
power_supply_register_led_trigger(psy, "%s-charging",
|
||||
&psy->charging_trig, &err);
|
||||
power_supply_register_led_trigger(psy, "%s-full",
|
||||
&psy->full_trig, &err);
|
||||
power_supply_register_led_trigger(psy, "%s-charging-blink-full-solid",
|
||||
&psy->charging_blink_full_solid_trig, &err);
|
||||
power_supply_register_led_trigger(psy, "%s-charging-orange-full-green",
|
||||
&psy->charging_orange_full_green_trig, &err);
|
||||
if (err)
|
||||
power_supply_remove_bat_triggers(psy);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Generated power specific LEDs triggers. */
|
||||
@ -142,27 +176,19 @@ static void power_supply_update_gen_leds(struct power_supply *psy)
|
||||
dev_dbg(&psy->dev, "%s %d\n", __func__, online.intval);
|
||||
|
||||
if (online.intval)
|
||||
led_trigger_event(psy->online_trig, LED_FULL);
|
||||
led_trigger_event(psy->trig, LED_FULL);
|
||||
else
|
||||
led_trigger_event(psy->online_trig, LED_OFF);
|
||||
led_trigger_event(psy->trig, LED_OFF);
|
||||
}
|
||||
|
||||
static int power_supply_create_gen_triggers(struct power_supply *psy)
|
||||
{
|
||||
psy->online_trig_name = kasprintf(GFP_KERNEL, "%s-online",
|
||||
psy->desc->name);
|
||||
if (!psy->online_trig_name)
|
||||
return -ENOMEM;
|
||||
|
||||
led_trigger_register_simple(psy->online_trig_name, &psy->online_trig);
|
||||
|
||||
return 0;
|
||||
return power_supply_register_led_trigger(psy, "%s-online", &psy->trig, NULL);
|
||||
}
|
||||
|
||||
static void power_supply_remove_gen_triggers(struct power_supply *psy)
|
||||
{
|
||||
led_trigger_unregister_simple(psy->online_trig);
|
||||
kfree(psy->online_trig_name);
|
||||
power_supply_unregister_led_trigger(psy->trig);
|
||||
}
|
||||
|
||||
/* Choice what triggers to create&update. */
|
||||
|
@ -379,8 +379,7 @@ static umode_t power_supply_attr_is_visible(struct kobject *kobj,
|
||||
int property = psy->desc->properties[i];
|
||||
|
||||
if (property == attrno) {
|
||||
if (psy->desc->property_is_writeable &&
|
||||
psy->desc->property_is_writeable(psy, property) > 0)
|
||||
if (power_supply_property_is_writeable(psy, property) > 0)
|
||||
mode |= S_IWUSR;
|
||||
|
||||
return mode;
|
||||
|
@ -1308,6 +1308,7 @@ static void qcom_battmgr_pdr_notify(void *priv, int state)
|
||||
static const struct of_device_id qcom_battmgr_of_variants[] = {
|
||||
{ .compatible = "qcom,sc8180x-pmic-glink", .data = (void *)QCOM_BATTMGR_SC8280XP },
|
||||
{ .compatible = "qcom,sc8280xp-pmic-glink", .data = (void *)QCOM_BATTMGR_SC8280XP },
|
||||
{ .compatible = "qcom,x1e80100-pmic-glink", .data = (void *)QCOM_BATTMGR_SC8280XP },
|
||||
/* Unmatched devices falls back to QCOM_BATTMGR_SM8350 */
|
||||
{}
|
||||
};
|
||||
|
@ -1718,8 +1718,8 @@ static void rt9455_remove(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id rt9455_i2c_id_table[] = {
|
||||
{ RT9455_DRIVER_NAME, 0 },
|
||||
{ },
|
||||
{ RT9455_DRIVER_NAME },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, rt9455_i2c_id_table);
|
||||
|
||||
|
@ -25,7 +25,7 @@ struct samsung_sdi_battery {
|
||||
* tables apply depending on whether we are charging or not.
|
||||
*/
|
||||
|
||||
static struct power_supply_vbat_ri_table samsung_vbat2res_discharging_eb_l1m7flu[] = {
|
||||
static const struct power_supply_vbat_ri_table samsung_vbat2res_discharging_eb_l1m7flu[] = {
|
||||
{ .vbat_uv = 4240000, .ri_uohm = 160000 },
|
||||
{ .vbat_uv = 4210000, .ri_uohm = 179000 },
|
||||
{ .vbat_uv = 4180000, .ri_uohm = 183000 },
|
||||
@ -53,7 +53,7 @@ static struct power_supply_vbat_ri_table samsung_vbat2res_discharging_eb_l1m7flu
|
||||
{ .vbat_uv = 3300000, .ri_uohm = 339000 },
|
||||
};
|
||||
|
||||
static struct power_supply_vbat_ri_table samsung_vbat2res_charging_eb_l1m7flu[] = {
|
||||
static const struct power_supply_vbat_ri_table samsung_vbat2res_charging_eb_l1m7flu[] = {
|
||||
{ .vbat_uv = 4302000, .ri_uohm = 230000 },
|
||||
{ .vbat_uv = 4276000, .ri_uohm = 345000 },
|
||||
{ .vbat_uv = 4227000, .ri_uohm = 345000 },
|
||||
@ -73,7 +73,7 @@ static struct power_supply_vbat_ri_table samsung_vbat2res_charging_eb_l1m7flu[]
|
||||
{ .vbat_uv = 3590000, .ri_uohm = 164000 },
|
||||
};
|
||||
|
||||
static struct power_supply_vbat_ri_table samsung_vbat2res_discharging_eb425161la[] = {
|
||||
static const struct power_supply_vbat_ri_table samsung_vbat2res_discharging_eb425161la[] = {
|
||||
{ .vbat_uv = 4240000, .ri_uohm = 160000 },
|
||||
{ .vbat_uv = 4210000, .ri_uohm = 179000 },
|
||||
{ .vbat_uv = 4180000, .ri_uohm = 183000 },
|
||||
@ -105,7 +105,7 @@ static struct power_supply_vbat_ri_table samsung_vbat2res_discharging_eb425161la
|
||||
{ .vbat_uv = 3300000, .ri_uohm = 339000 },
|
||||
};
|
||||
|
||||
static struct power_supply_vbat_ri_table samsung_vbat2res_charging_eb425161la[] = {
|
||||
static const struct power_supply_vbat_ri_table samsung_vbat2res_charging_eb425161la[] = {
|
||||
{ .vbat_uv = 4345000, .ri_uohm = 230000 },
|
||||
{ .vbat_uv = 4329000, .ri_uohm = 238000 },
|
||||
{ .vbat_uv = 4314000, .ri_uohm = 225000 },
|
||||
@ -182,7 +182,7 @@ static struct power_supply_vbat_ri_table samsung_vbat2res_charging_eb425161la[]
|
||||
{ .vbat_uv = 3590000, .ri_uohm = 164000 },
|
||||
};
|
||||
|
||||
static struct power_supply_vbat_ri_table samsung_vbat2res_discharging_eb425161lu[] = {
|
||||
static const struct power_supply_vbat_ri_table samsung_vbat2res_discharging_eb425161lu[] = {
|
||||
{ .vbat_uv = 4240000, .ri_uohm = 160000 },
|
||||
{ .vbat_uv = 4210000, .ri_uohm = 179000 },
|
||||
{ .vbat_uv = 4180000, .ri_uohm = 183000 },
|
||||
@ -214,7 +214,7 @@ static struct power_supply_vbat_ri_table samsung_vbat2res_discharging_eb425161lu
|
||||
{ .vbat_uv = 3300000, .ri_uohm = 339000 },
|
||||
};
|
||||
|
||||
static struct power_supply_vbat_ri_table samsung_vbat2res_charging_eb425161lu[] = {
|
||||
static const struct power_supply_vbat_ri_table samsung_vbat2res_charging_eb425161lu[] = {
|
||||
{ .vbat_uv = 4346000, .ri_uohm = 293000 },
|
||||
{ .vbat_uv = 4336000, .ri_uohm = 290000 },
|
||||
{ .vbat_uv = 4315000, .ri_uohm = 274000 },
|
||||
@ -244,7 +244,7 @@ static struct power_supply_vbat_ri_table samsung_vbat2res_charging_eb425161lu[]
|
||||
{ .vbat_uv = 3590000, .ri_uohm = 164000 },
|
||||
};
|
||||
|
||||
static struct power_supply_vbat_ri_table samsung_vbat2res_discharging_eb485159lu[] = {
|
||||
static const struct power_supply_vbat_ri_table samsung_vbat2res_discharging_eb485159lu[] = {
|
||||
{ .vbat_uv = 4240000, .ri_uohm = 160000 },
|
||||
{ .vbat_uv = 4210000, .ri_uohm = 179000 },
|
||||
{ .vbat_uv = 4180000, .ri_uohm = 183000 },
|
||||
@ -271,7 +271,7 @@ static struct power_supply_vbat_ri_table samsung_vbat2res_discharging_eb485159lu
|
||||
{ .vbat_uv = 3300000, .ri_uohm = 339000 },
|
||||
};
|
||||
|
||||
static struct power_supply_vbat_ri_table samsung_vbat2res_charging_eb485159lu[] = {
|
||||
static const struct power_supply_vbat_ri_table samsung_vbat2res_charging_eb485159lu[] = {
|
||||
{ .vbat_uv = 4302000, .ri_uohm = 200000 },
|
||||
{ .vbat_uv = 4258000, .ri_uohm = 206000 },
|
||||
{ .vbat_uv = 4200000, .ri_uohm = 231000 },
|
||||
@ -291,7 +291,7 @@ static struct power_supply_vbat_ri_table samsung_vbat2res_charging_eb485159lu[]
|
||||
{ .vbat_uv = 3590000, .ri_uohm = 164000 },
|
||||
};
|
||||
|
||||
static struct power_supply_vbat_ri_table samsung_vbat2res_discharging_eb535151vu[] = {
|
||||
static const struct power_supply_vbat_ri_table samsung_vbat2res_discharging_eb535151vu[] = {
|
||||
{ .vbat_uv = 4071000, .ri_uohm = 158000 },
|
||||
{ .vbat_uv = 4019000, .ri_uohm = 187000 },
|
||||
{ .vbat_uv = 3951000, .ri_uohm = 191000 },
|
||||
@ -311,7 +311,7 @@ static struct power_supply_vbat_ri_table samsung_vbat2res_discharging_eb535151vu
|
||||
{ .vbat_uv = 3280000, .ri_uohm = 250000 },
|
||||
};
|
||||
|
||||
static struct power_supply_vbat_ri_table samsung_vbat2res_charging_eb535151vu[] = {
|
||||
static const struct power_supply_vbat_ri_table samsung_vbat2res_charging_eb535151vu[] = {
|
||||
{ .vbat_uv = 4190000, .ri_uohm = 214000 },
|
||||
{ .vbat_uv = 4159000, .ri_uohm = 252000 },
|
||||
{ .vbat_uv = 4121000, .ri_uohm = 245000 },
|
||||
@ -331,7 +331,7 @@ static struct power_supply_vbat_ri_table samsung_vbat2res_charging_eb535151vu[]
|
||||
{ .vbat_uv = 3510000, .ri_uohm = 228000 },
|
||||
};
|
||||
|
||||
static struct power_supply_vbat_ri_table samsung_vbat2res_discharging_eb585157lu[] = {
|
||||
static const struct power_supply_vbat_ri_table samsung_vbat2res_discharging_eb585157lu[] = {
|
||||
{ .vbat_uv = 4194000, .ri_uohm = 121000 },
|
||||
{ .vbat_uv = 4169000, .ri_uohm = 188000 },
|
||||
{ .vbat_uv = 4136000, .ri_uohm = 173000 },
|
||||
@ -401,7 +401,7 @@ static struct power_supply_vbat_ri_table samsung_vbat2res_discharging_eb585157lu
|
||||
{ .vbat_uv = 3161000, .ri_uohm = 452000 },
|
||||
};
|
||||
|
||||
static struct power_supply_vbat_ri_table samsung_vbat2res_charging_eb585157lu[] = {
|
||||
static const struct power_supply_vbat_ri_table samsung_vbat2res_charging_eb585157lu[] = {
|
||||
{ .vbat_uv = 4360000, .ri_uohm = 128000 },
|
||||
{ .vbat_uv = 4325000, .ri_uohm = 130000 },
|
||||
{ .vbat_uv = 4316000, .ri_uohm = 148000 },
|
||||
@ -613,7 +613,7 @@ static struct power_supply_battery_ocv_table samsung_ocv_cap_eb585157lu[] = {
|
||||
{ .ocv = 3300000, .capacity = 0},
|
||||
};
|
||||
|
||||
static struct power_supply_maintenance_charge_table samsung_maint_charge_table[] = {
|
||||
static const struct power_supply_maintenance_charge_table samsung_maint_charge_table[] = {
|
||||
{
|
||||
/* Maintenance charging phase A, 60 hours */
|
||||
.charge_current_max_ua = 600000,
|
||||
|
@ -234,7 +234,7 @@ MODULE_DEVICE_TABLE(of, sbs_dt_ids);
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id sbs_id[] = {
|
||||
{ "sbs-charger", 0 },
|
||||
{ "sbs-charger" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, sbs_id);
|
||||
|
@ -389,8 +389,8 @@ static int sbsm_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id sbsm_ids[] = {
|
||||
{ "sbs-manager", 0 },
|
||||
{ "ltc1760", 0 },
|
||||
{ "sbs-manager" },
|
||||
{ "ltc1760" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, sbsm_ids);
|
||||
|
@ -309,18 +309,11 @@ struct power_supply {
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LEDS_TRIGGERS
|
||||
struct led_trigger *charging_full_trig;
|
||||
char *charging_full_trig_name;
|
||||
struct led_trigger *trig;
|
||||
struct led_trigger *charging_trig;
|
||||
char *charging_trig_name;
|
||||
struct led_trigger *full_trig;
|
||||
char *full_trig_name;
|
||||
struct led_trigger *online_trig;
|
||||
char *online_trig_name;
|
||||
struct led_trigger *charging_blink_full_solid_trig;
|
||||
char *charging_blink_full_solid_trig_name;
|
||||
struct led_trigger *charging_orange_full_green_trig;
|
||||
char *charging_orange_full_green_trig_name;
|
||||
#endif
|
||||
};
|
||||
|
||||
@ -743,7 +736,7 @@ struct power_supply_battery_info {
|
||||
int overvoltage_limit_uv;
|
||||
int constant_charge_current_max_ua;
|
||||
int constant_charge_voltage_max_uv;
|
||||
struct power_supply_maintenance_charge_table *maintenance_charge;
|
||||
const struct power_supply_maintenance_charge_table *maintenance_charge;
|
||||
int maintenance_charge_size;
|
||||
int alert_low_temp_charge_current_ua;
|
||||
int alert_low_temp_charge_voltage_uv;
|
||||
@ -762,9 +755,9 @@ struct power_supply_battery_info {
|
||||
int ocv_table_size[POWER_SUPPLY_OCV_TEMP_MAX];
|
||||
struct power_supply_resistance_temp_table *resist_table;
|
||||
int resist_table_size;
|
||||
struct power_supply_vbat_ri_table *vbat2ri_discharging;
|
||||
const struct power_supply_vbat_ri_table *vbat2ri_discharging;
|
||||
int vbat2ri_discharging_size;
|
||||
struct power_supply_vbat_ri_table *vbat2ri_charging;
|
||||
const struct power_supply_vbat_ri_table *vbat2ri_charging;
|
||||
int vbat2ri_charging_size;
|
||||
int bti_resistance_ohm;
|
||||
int bti_resistance_tolerance;
|
||||
@ -817,7 +810,7 @@ power_supply_temp2resist_simple(struct power_supply_resistance_temp_table *table
|
||||
int table_len, int temp);
|
||||
extern int power_supply_vbat2ri(struct power_supply_battery_info *info,
|
||||
int vbat_uv, bool charging);
|
||||
extern struct power_supply_maintenance_charge_table *
|
||||
extern const struct power_supply_maintenance_charge_table *
|
||||
power_supply_get_maintenance_charging_setting(struct power_supply_battery_info *info, int index);
|
||||
extern bool power_supply_battery_bti_in_range(struct power_supply_battery_info *info,
|
||||
int resistance);
|
||||
@ -831,7 +824,7 @@ extern int power_supply_set_battery_charged(struct power_supply *psy);
|
||||
static inline bool
|
||||
power_supply_supports_maintenance_charging(struct power_supply_battery_info *info)
|
||||
{
|
||||
struct power_supply_maintenance_charge_table *mt;
|
||||
const struct power_supply_maintenance_charge_table *mt;
|
||||
|
||||
mt = power_supply_get_maintenance_charging_setting(info, 0);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user