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:
Linus Torvalds 2024-07-23 09:38:27 -07:00
commit fd71b9a07b
30 changed files with 1129 additions and 163 deletions

View File

@ -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>;
};
};

View File

@ -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");

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;
}
/**

View File

@ -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

View File

@ -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);

View File

@ -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 */

View File

@ -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);

View File

@ -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);

View File

@ -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" },
{ }
};

View File

@ -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;

View 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");

View File

@ -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);

View File

@ -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);

View File

@ -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);

View 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, &reg_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, &reg_val);
val->intval = max172xx_percent_to_ps(reg_val);
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
ret = regmap_read(info->regmap, MAX172XX_BATT, &reg_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, &reg_val);
val->intval = max172xx_capacity_to_ps(reg_val);
break;
case POWER_SUPPLY_PROP_CHARGE_AVG:
ret = regmap_read(info->regmap, MAX172XX_REPCAP, &reg_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, &reg_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, &reg_val);
val->intval = max172xx_time_to_ps(reg_val);
break;
case POWER_SUPPLY_PROP_TEMP:
ret = regmap_read(info->regmap, MAX172XX_TEMP, &reg_val);
val->intval = max172xx_temperature_to_ps(reg_val);
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
ret = regmap_read(info->regmap, MAX172XX_CURRENT, &reg_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, &reg_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, &reg_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");

View File

@ -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);

View File

@ -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);

View File

@ -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)
{

View File

@ -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:

View File

@ -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. */

View File

@ -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;

View File

@ -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 */
{}
};

View File

@ -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);

View File

@ -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,

View File

@ -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);

View File

@ -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);

View File

@ -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);