Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/power/supply/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 8 kB image not shown  

Quelle  chagall-battery.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later

#include <linux/array_size.h>
#include <linux/delay.h>
#include <linux/devm-helpers.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/leds.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/power_supply.h>
#include <linux/regmap.h>

#define CHAGALL_REG_LED_AMBER    0x60
#define CHAGALL_REG_LED_WHITE    0x70
#define CHAGALL_REG_BATTERY_TEMPERATURE   0xa2
#define CHAGALL_REG_BATTERY_VOLTAGE   0xa4
#define CHAGALL_REG_BATTERY_CURRENT   0xa6
#define CHAGALL_REG_BATTERY_CAPACITY   0xa8
#define CHAGALL_REG_BATTERY_CHARGING_CURRENT  0xaa
#define CHAGALL_REG_BATTERY_CHARGING_VOLTAGE  0xac
#define CHAGALL_REG_BATTERY_STATUS   0xae
#define   BATTERY_DISCHARGING    BIT(6)
#define   BATTERY_FULL_CHARGED    BIT(5)
#define   BATTERY_FULL_DISCHARGED   BIT(4)
#define CHAGALL_REG_BATTERY_REMAIN_CAPACITY  0xb0
#define CHAGALL_REG_BATTERY_FULL_CAPACITY  0xb2
#define CHAGALL_REG_MAX_COUNT    0xb4

#define CHAGALL_BATTERY_DATA_REFRESH   5000
#define TEMP_CELSIUS_OFFSET    2731

static const struct regmap_config chagall_battery_regmap_config = {
 .reg_bits = 8,
 .val_bits = 8,
 .max_register = CHAGALL_REG_MAX_COUNT,
 .reg_format_endian = REGMAP_ENDIAN_LITTLE,
 .val_format_endian = REGMAP_ENDIAN_LITTLE,
};

struct chagall_battery_data {
 struct regmap *regmap;
 struct led_classdev amber_led;
 struct led_classdev white_led;
 struct power_supply *battery;
 struct delayed_work poll_work;
 u16 last_state;
};

static void chagall_led_set_brightness_amber(struct led_classdev *led,
          enum led_brightness brightness)
{
 struct chagall_battery_data *cg =
  container_of(led, struct chagall_battery_data, amber_led);

 regmap_write(cg->regmap, CHAGALL_REG_LED_AMBER, brightness);
}

static void chagall_led_set_brightness_white(struct led_classdev *led,
          enum led_brightness brightness)
{
 struct chagall_battery_data *cg =
  container_of(led, struct chagall_battery_data, white_led);

 regmap_write(cg->regmap, CHAGALL_REG_LED_WHITE, brightness);
}

static const enum power_supply_property chagall_battery_properties[] = {
 POWER_SUPPLY_PROP_STATUS,
 POWER_SUPPLY_PROP_PRESENT,
 POWER_SUPPLY_PROP_VOLTAGE_NOW,
 POWER_SUPPLY_PROP_VOLTAGE_MAX,
 POWER_SUPPLY_PROP_CURRENT_NOW,
 POWER_SUPPLY_PROP_CURRENT_MAX,
 POWER_SUPPLY_PROP_CAPACITY,
 POWER_SUPPLY_PROP_TEMP,
 POWER_SUPPLY_PROP_CHARGE_FULL,
 POWER_SUPPLY_PROP_CHARGE_NOW,
};

static const unsigned int chagall_battery_prop_offs[] = {
 [POWER_SUPPLY_PROP_STATUS] = CHAGALL_REG_BATTERY_STATUS,
 [POWER_SUPPLY_PROP_VOLTAGE_NOW] = CHAGALL_REG_BATTERY_VOLTAGE,
 [POWER_SUPPLY_PROP_VOLTAGE_MAX] = CHAGALL_REG_BATTERY_CHARGING_VOLTAGE,
 [POWER_SUPPLY_PROP_CURRENT_NOW] = CHAGALL_REG_BATTERY_CURRENT,
 [POWER_SUPPLY_PROP_CURRENT_MAX] = CHAGALL_REG_BATTERY_CHARGING_CURRENT,
 [POWER_SUPPLY_PROP_CAPACITY] = CHAGALL_REG_BATTERY_CAPACITY,
 [POWER_SUPPLY_PROP_TEMP] = CHAGALL_REG_BATTERY_TEMPERATURE,
 [POWER_SUPPLY_PROP_CHARGE_FULL] = CHAGALL_REG_BATTERY_FULL_CAPACITY,
 [POWER_SUPPLY_PROP_CHARGE_NOW] = CHAGALL_REG_BATTERY_REMAIN_CAPACITY,
};

static int chagall_battery_get_value(struct chagall_battery_data *cg,
         enum power_supply_property psp, u32 *val)
{
 if (psp >= ARRAY_SIZE(chagall_battery_prop_offs))
  return -EINVAL;
 if (!chagall_battery_prop_offs[psp])
  return -EINVAL;

 /* Battery data is stored in 2 consecutive registers with little-endian */
 return regmap_bulk_read(cg->regmap, chagall_battery_prop_offs[psp], val, 2);
}

static int chagall_battery_get_status(u32 status_reg)
{
 if (status_reg & BATTERY_FULL_CHARGED)
  return POWER_SUPPLY_STATUS_FULL;
 else if (status_reg & BATTERY_DISCHARGING)
  return POWER_SUPPLY_STATUS_DISCHARGING;
 else
  return POWER_SUPPLY_STATUS_CHARGING;
}

static int chagall_battery_get_property(struct power_supply *psy,
     enum power_supply_property psp,
     union power_supply_propval *val)
{
 struct chagall_battery_data *cg = power_supply_get_drvdata(psy);
 int ret;

 switch (psp) {
 case POWER_SUPPLY_PROP_PRESENT:
  val->intval = 1;
  break;

 default:
  ret = chagall_battery_get_value(cg, psp, &val->intval);
  if (ret)
   return ret;

  switch (psp) {
  case POWER_SUPPLY_PROP_TEMP:
   val->intval -= TEMP_CELSIUS_OFFSET;
   break;

  case POWER_SUPPLY_PROP_VOLTAGE_MAX:
  case POWER_SUPPLY_PROP_VOLTAGE_NOW:
  case POWER_SUPPLY_PROP_CURRENT_MAX:
  case POWER_SUPPLY_PROP_CURRENT_NOW:
  case POWER_SUPPLY_PROP_CHARGE_FULL:
  case POWER_SUPPLY_PROP_CHARGE_NOW:
   val->intval *= 1000;
   break;

  case POWER_SUPPLY_PROP_STATUS:
   val->intval = chagall_battery_get_status(val->intval);
   break;

  default:
   break;
  }

  break;
 }

 return 0;
}

static void chagall_battery_poll_work(struct work_struct *work)
{
 struct chagall_battery_data *cg =
  container_of(work, struct chagall_battery_data, poll_work.work);
 u32 state;
 int ret;

 ret = chagall_battery_get_value(cg, POWER_SUPPLY_PROP_STATUS, &state);
 if (ret)
  return;

 state = chagall_battery_get_status(state);

 if (cg->last_state != state) {
  cg->last_state = state;
  power_supply_changed(cg->battery);
 }

 /* continuously send uevent notification */
 schedule_delayed_work(&cg->poll_work,
         msecs_to_jiffies(CHAGALL_BATTERY_DATA_REFRESH));
}

static const struct power_supply_desc chagall_battery_desc = {
 .name = "chagall-battery",
 .type = POWER_SUPPLY_TYPE_BATTERY,
 .properties = chagall_battery_properties,
 .num_properties = ARRAY_SIZE(chagall_battery_properties),
 .get_property = chagall_battery_get_property,
 .external_power_changed = power_supply_changed,
};

static int chagall_battery_probe(struct i2c_client *client)
{
 struct chagall_battery_data *cg;
 struct device *dev = &client->dev;
 struct power_supply_config cfg = { };
 int ret;

 cg = devm_kzalloc(dev, sizeof(*cg), GFP_KERNEL);
 if (!cg)
  return -ENOMEM;

 cfg.drv_data = cg;
 cfg.fwnode = dev_fwnode(dev);

 i2c_set_clientdata(client, cg);

 cg->regmap = devm_regmap_init_i2c(client, &chagall_battery_regmap_config);
 if (IS_ERR(cg->regmap))
  return dev_err_probe(dev, PTR_ERR(cg->regmap), "cannot allocate regmap\n");

 cg->last_state = POWER_SUPPLY_STATUS_UNKNOWN;
 cg->battery = devm_power_supply_register(dev, &chagall_battery_desc, &cfg);
 if (IS_ERR(cg->battery))
  return dev_err_probe(dev, PTR_ERR(cg->battery),
         "failed to register power supply\n");

 cg->amber_led.name = "power::amber";
 cg->amber_led.max_brightness = 1;
 cg->amber_led.flags = LED_CORE_SUSPENDRESUME;
 cg->amber_led.brightness_set = chagall_led_set_brightness_amber;
 cg->amber_led.default_trigger = "chagall-battery-charging";

 ret = devm_led_classdev_register(dev, &cg->amber_led);
 if (ret)
  return dev_err_probe(dev, ret, "failed to register amber LED\n");

 cg->white_led.name = "power::white";
 cg->white_led.max_brightness = 1;
 cg->white_led.flags = LED_CORE_SUSPENDRESUME;
 cg->white_led.brightness_set = chagall_led_set_brightness_white;
 cg->white_led.default_trigger = "chagall-battery-full";

 ret = devm_led_classdev_register(dev, &cg->white_led);
 if (ret)
  return dev_err_probe(dev, ret, "failed to register white LED\n");

 led_set_brightness(&cg->amber_led, LED_OFF);
 led_set_brightness(&cg->white_led, LED_OFF);

 ret = devm_delayed_work_autocancel(dev, &cg->poll_work, chagall_battery_poll_work);
 if (ret)
  return ret;

 schedule_delayed_work(&cg->poll_work, msecs_to_jiffies(CHAGALL_BATTERY_DATA_REFRESH));

 return 0;
}

static int __maybe_unused chagall_battery_suspend(struct device *dev)
{
 struct i2c_client *client = to_i2c_client(dev);
 struct chagall_battery_data *cg = i2c_get_clientdata(client);

 cancel_delayed_work_sync(&cg->poll_work);

 return 0;
}

static int __maybe_unused chagall_battery_resume(struct device *dev)
{
 struct i2c_client *client = to_i2c_client(dev);
 struct chagall_battery_data *cg = i2c_get_clientdata(client);

 schedule_delayed_work(&cg->poll_work, msecs_to_jiffies(CHAGALL_BATTERY_DATA_REFRESH));

 return 0;
}

static SIMPLE_DEV_PM_OPS(chagall_battery_pm_ops,
    chagall_battery_suspend, chagall_battery_resume);

static const struct of_device_id chagall_of_match[] = {
 { .compatible = "pegatron,chagall-ec" },
 { }
};
MODULE_DEVICE_TABLE(of, chagall_of_match);

static struct i2c_driver chagall_battery_driver = {
 .driver = {
  .name = "chagall-battery",
  .pm = &chagall_battery_pm_ops,
  .of_match_table = chagall_of_match,
 },
 .probe = chagall_battery_probe,
};
module_i2c_driver(chagall_battery_driver);

MODULE_AUTHOR("Svyatoslav Ryhel ");
MODULE_DESCRIPTION("Pegatron Chagall fuel gauge driver");
MODULE_LICENSE("GPL");

Messung V0.5
C=95 H=96 G=95

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.