Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e3e00bfb authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "power: qcom: Add QTI QBG(Qualcomm Battery Gauging) driver"

parents 7b79fdc0 2ca18754
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -101,4 +101,16 @@ config SMB358_CHARGER
	  The driver supports charger enable/disable.
	  The driver reports the charger status via the power supply framework.
	  A charger status change triggers an IRQ via the device STAT pin.

config QTI_QBG
	tristate "QTI Battery Gauge"
	depends on MFD_SPMI_PMIC && IIO
	help
	  Say Y here to enable the Qualcomm Technologies, Inc. Battery Gauge
	  driver which uses the periodic samples of the battery voltage and
	  current to determine the battery state-of-charge (SOC) and supports
	  other battery management features.

	  To compile this driver as a module, choose M here: the
	  module will be called qti-qbg-main.
endif
+2 −0
Original line number Diff line number Diff line
@@ -13,3 +13,5 @@ qcom-smb1355-charger-y += smb1355-charger.o pmic-voter.o
obj-$(CONFIG_SMB1351_USB_CHARGER)	+= smb1351-charger.o pmic-voter.o
obj-$(CONFIG_SMB1390_CHARGE_PUMP_PSY)   += qcom-smb1390-charger.o
qcom-smb1390-charger-y += smb1390-charger-psy.o pmic-voter.o
obj-$(CONFIG_QTI_QBG)	+= qti-qbg-main.o
qti-qbg-main-y	+= qti-qbg.o qbg-sdam.o qbg-battery-profile.o battery-profile-loader.o
+589 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2021 The Linux Foundation. All rights reserved.
 */

#define pr_fmt(fmt)	"QBG-K: %s: " fmt, __func__

#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fcntl.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/uaccess.h>

#include <uapi/linux/qbg-profile.h>

#include "qbg-battery-profile.h"

static int table_temperatures[] = { -20, -10, 0, 10, 25, 40, 50 };

static int qbg_battery_data_open(struct inode *inode, struct file *file)
{
	struct qbg_battery_data *battery = container_of(inode->i_cdev,
				struct qbg_battery_data, battery_cdev);

	pr_debug("battery_data device opened\n");
	file->private_data = battery;

	return 0;
}

static long qbg_battery_data_ioctl(struct file *file, unsigned int cmd,
						unsigned long arg)
{
	struct qbg_battery_data *battery = file->private_data;
	struct battery_config __user *profile_user;
	struct battery_profile_table bp_table;
	struct battery_profile_table __user *bp_table_user;
	struct battery_data_table *table;
	int rc = 0, table_index, table_type;

	if (!battery->profile_node) {
		pr_err("Invalid battery profile node\n");
		return -EINVAL;
	}

	if (!arg) {
		pr_err("Invalid user pointer\n");
		return -EINVAL;
	}

	switch (cmd) {
	case BPIOCXBP:
		profile_user = (struct battery_config __user *)arg;

		if (copy_to_user(profile_user, &battery->bp, sizeof(battery->bp))) {
			pr_err("Failed to copy battery profile to user\n");
			return -EFAULT;
		}

		break;
	case BPIOCXBPTABLE:
		bp_table_user = (struct battery_profile_table __user *)arg;

		if (copy_from_user(&bp_table, bp_table_user, sizeof(bp_table))) {
			pr_err("Failed to copy battery_profile_table from user\n");
			return -EFAULT;
		}

		table_index = bp_table.table_index;
		table_type = bp_table.table_type;

		if ((table_type != CHARGE_TABLE) &&
		    (table_type != DISCHARGE_TABLE))
			return -EFAULT;

		if (((table_type == CHARGE_TABLE) &&
		     (table_index >= battery->num_ctables)) ||
		     ((table_type == DISCHARGE_TABLE) &&
		     (table_index >= battery->num_dtables)))
			return -EFAULT;

		table = (table_type == CHARGE_TABLE) ?
				battery->bp_charge_tables[table_index] :
				battery->bp_discharge_tables[table_index];

		if (copy_to_user(bp_table.table, table, sizeof(*table))) {
			pr_err("Failed to copy battery profile table to user\n");
			return -EFAULT;
		}

		pr_debug("Copied %s table %d to user\n",
			table_type == CHARGE_TABLE ? "Charge" : "Discharge", table_index);
		break;
	default:
		pr_err_ratelimited("IOCTL %u not supported\n", cmd);
		rc = -EINVAL;
		break;
	}

	return rc;
}

static int qbg_battery_data_release(struct inode *inode, struct file *file)
{
	pr_debug("battery_data device closed\n");

	return 0;
}

static const struct file_operations qbg_battery_data_fops = {
	.owner = THIS_MODULE,
	.open = qbg_battery_data_open,
	.unlocked_ioctl = qbg_battery_data_ioctl,
	.compat_ioctl = qbg_battery_data_ioctl,
	.release = qbg_battery_data_release,
};

#define QBG_PON_TEMPERATURE	25
static int qbg_parse_table0(struct device_node *profile_node,
		char *table_name, struct battery_data_table0 *table)
{
	struct device_node *node;
	int rc = 0, temperature;

	node = of_find_node_by_name(profile_node, table_name);
	if (!node) {
		pr_err("%s not found\n", table_name);
		return -ENODEV;
	}

	rc = of_property_read_s32(node, "qcom,temperature", &temperature);
	if (rc < 0) {
		pr_err("Failed to read %s temperature\n", table_name);
		goto out;
	}

	if (temperature != QBG_PON_TEMPERATURE) {
		pr_err("Invalid table0 found, temperature:%d\n",
			temperature);
		rc = -EINVAL;
		goto out;
	}

	rc = of_property_count_elems_of_size(node, "qcom,soc", sizeof(int));
	if (rc < 0) {
		pr_err("Failed to get soc-length for %s, rc=%d\n",
			table_name, rc);
		goto out;
	}
	table->soc_length = rc;

	table->soc = kcalloc(table->soc_length, sizeof(*table->soc), GFP_KERNEL);
	if (!table->soc) {
		rc = -ENOMEM;
		goto out;
	}

	rc = of_property_read_u32_array(node, "qcom,soc", table->soc,
						table->soc_length);
	if (rc < 0) {
		pr_err("Failed to read qcom,soc\n");
		rc = -EINVAL;
		goto cleanup_soc;
	}

	rc = of_property_count_elems_of_size(node, "qcom,ocv", sizeof(int));
	if (rc < 0) {
		pr_err("Failed to get ocv-length for %s, rc=%d\n",
			table_name, rc);
		goto cleanup_soc;
	}
	table->ocv_length = rc;

	table->ocv = kcalloc(table->ocv_length, sizeof(*table->ocv), GFP_KERNEL);
	if (!table->ocv) {
		rc = -ENOMEM;
		goto cleanup_soc;
	}

	rc = of_property_read_u32_array(node, "qcom,ocv", table->ocv,
						table->ocv_length);
	if (rc < 0) {
		pr_err("Failed to read qcom,ocv\n");
		rc = -EINVAL;
		goto cleanup_ocv;
	}

	return 0;

cleanup_ocv:
	kfree(table->ocv);
cleanup_soc:
	kfree(table->soc);
out:
	of_node_put(node);

	return rc;
}

static int qbg_parse_table(struct device_node *profile_node,
		int index, char *table_name, struct battery_data_table *bp_table)
{
	struct device_node *node;
	struct property *prop;
	const __be32 *data;
	int rc = 0, j, k, temperature;
	u32 rows, cols;

	node = of_find_node_by_name(profile_node, table_name);
	if (!node) {
		pr_err("%s not found\n", table_name);
		return -ENODEV;
	}

	rc = of_property_read_s32(node, "qcom,temperature", &temperature);
	if (rc < 0) {
		pr_err("Failed to read %s temperature\n", table_name);
		goto out;
	}

	if (temperature != table_temperatures[index]) {
		pr_err("Invalid table at wrong index %d temperature:%d\n",
			index, temperature);
		rc = -EINVAL;
		goto out;
	}

	rc = of_property_read_u32(node, "qcom,nrows", &rows);
	if (rc < 0) {
		pr_err("Failed to read %s\n", table_name);
		goto out;
	}
	bp_table->nrows = rows;

	rc = of_property_read_u32(node, "qcom,ncols", &cols);
	if (rc < 0) {
		pr_err("Failed to read %s\n", table_name);
		goto out;
	}
	bp_table->ncols = cols;

	rc = of_property_read_u32_array(node, "qcom,conv-factor",
					bp_table->unit_conv_factor,
					MAX_BP_LUT_COLS);
	if (rc < 0) {
		pr_err("Failed to read conv-factor\n");
		rc = -EINVAL;
		goto out;
	}

	prop = of_find_property(node, "qcom,data", NULL);
	if (!prop) {
		pr_err("Failed to find lut-data\n");
		rc = -EINVAL;
		goto out;
	}

	data = prop->value;

	for (j = 0; j < bp_table->nrows; j++) {
		for (k = 0; k < bp_table->ncols; k++)
			bp_table->table[j][k] = be32_to_cpup(data++);
	}

	pr_debug("Profile %s parsed rows=%d cols=%d\n", table_name,
		bp_table->nrows, bp_table->ncols);
out:
	of_node_put(node);

	return rc;
}

static int qbg_parse_u32_dt_array(struct device_node *node,
				const char *prop_name, int *buf, int len)
{
	int rc;

	rc = of_property_count_elems_of_size(node, prop_name, sizeof(u32));
	if (rc < 0) {
		pr_err("Property %s not found, rc=%d\n", prop_name, rc);
		return rc;
	} else if (rc != len) {
		pr_err("Incorrect length %d for %s, rc=%d\n", len, prop_name,
			rc);
		return -EINVAL;
	}

	rc = of_property_read_u32_array(node, prop_name, buf, len);
	if (rc < 0) {
		pr_err("Error in reading %s, rc=%d\n", prop_name, rc);
		return rc;
	}

	return 0;
}

static int qbg_parse_battery_profile(struct qbg_battery_data *battery)
{
	struct device_node *node = battery->profile_node;
	struct device_node *child;
	struct battery_config *bp = &battery->bp;
	char buf[32];
	const char *battery_name = NULL;
	int rc, i = 0;
	u32 temp[2];

	rc = of_property_read_string(node, "qcom,battery-type", &battery_name);
	if (rc < 0) {
		pr_err("Failed to get battery type, rc=%d\n", rc);
		return rc;
	}
	strlcpy(bp->bp_profile_name, battery_name, MAX_PROFILE_NAME_LENGTH);

	rc = of_property_read_u32(node, "qcom,batt-id-kohm", &bp->bp_batt_id);
	if (rc < 0) {
		pr_err("Failed to get battery id, rc=%d\n", rc);
		return rc;
	}

	rc = of_property_read_u32(node, "qcom,capacity", &bp->capacity);
	if (rc < 0) {
		pr_err("Failed to get battery capacity, rc=%d\n", rc);
		return rc;
	}

	rc = of_property_read_u32(node, "qcom,checksum", &bp->bp_checksum);
	if (rc < 0) {
		pr_err("Failed to get checksum, rc=%d\n", rc);
		return rc;
	}

	rc = qbg_parse_u32_dt_array(node, "qcom,soh-range", temp, 2);
	if (rc < 0)
		return rc;

	if (temp[0] > 100 || temp[1] > 100 || (temp[0] > temp[1])) {
		pr_err("Incorrect SOH range [%d %d]\n", temp[0],
			temp[1]);
		return -ERANGE;
	}
	bp->soh_range_low = temp[0];
	bp->soh_range_high = temp[1];

	rc = qbg_parse_u32_dt_array(node, "qcom,battery-impedance", temp, 2);
	if (rc < 0)
		return rc;

	bp->normal_impedance = temp[0];
	bp->aged_impedance = temp[1];

	rc = qbg_parse_u32_dt_array(node, "qcom,battery-capacity", temp, 2);
	if (rc < 0)
		return rc;

	bp->normal_capacity = temp[0];
	bp->aged_capacity = temp[1];

	rc = of_property_read_u32(node, "qcom,recharge-soc-delta",
					&bp->recharge_soc_delta);
	if (rc < 0) {
		pr_err("Failed to get recharege soc delta, rc=%d\n",
			rc);
		return rc;
	}

	rc = of_property_read_u32(node, "qcom,recharge-vflt-delta",
					&bp->recharge_vflt_delta);
	if (rc < 0) {
		pr_err("Failed to get recharge vflt delta, rc=%d\n",
			rc);
		return rc;
	}

	rc = of_property_read_u32(node, "qcom,recharge-iterm-ma",
					&bp->recharge_iterm);
	if (rc < 0) {
		pr_err("Failed to get recharge iterm, rc=%d\n", rc);
		return rc;
	}

	for_each_available_child_of_node(battery->profile_node, child) {
		if (of_node_name_prefix(child, "qcom,bp-c-table"))
			battery->num_ctables++;
		else if (of_node_name_prefix(child, "qcom,bp-d-table"))
			battery->num_dtables++;
	}

	if (!battery->num_ctables || !battery->num_dtables) {
		pr_err("ctable or dtable missing\n");
		return -EINVAL;
	}

	/* Battery profile contains additional table (table0) */
	if (battery->num_ctables)
		battery->num_ctables--;
	if (battery->num_dtables)
		battery->num_dtables--;

	battery->bp_discharge_tables = kcalloc(battery->num_dtables,
				sizeof(*battery->bp_discharge_tables), GFP_KERNEL);
	if (!battery->bp_discharge_tables)
		return -ENOMEM;

	battery->bp_charge_tables = kcalloc(battery->num_ctables,
				sizeof(*battery->bp_charge_tables), GFP_KERNEL);
	if (!battery->bp_charge_tables)
		return -ENOMEM;

	/* Parse c-table-0 */
	scnprintf(buf, sizeof(buf), "qcom,bp-c-table-0");
	rc = qbg_parse_table0(battery->profile_node, buf, &battery->table0[0]);
	if (rc < 0) {
		pr_err("Failed to parse %s, rc=%d\n", buf, rc);
		return rc;
	}

	/* Parse d-table-0 */
	scnprintf(buf, sizeof(buf), "qcom,bp-d-table-0");
	rc = qbg_parse_table0(battery->profile_node, buf, &battery->table0[1]);
	if (rc < 0) {
		pr_err("Failed to parse %s, rc=%d\n", buf, rc);
		goto cleanup_ctable;
	}

	for (i = 0; i < battery->num_dtables; i++) {
		battery->bp_discharge_tables[i] = kzalloc(
			sizeof(*battery->bp_discharge_tables[i]), GFP_KERNEL);
		if (!battery->bp_discharge_tables[i]) {
			rc = -ENOMEM;
			goto cleanup_ctable;
		}

		scnprintf(buf, sizeof(buf), "qcom,bp-d-table-%d", i + 1);

		rc = qbg_parse_table(battery->profile_node, i, buf,
					battery->bp_discharge_tables[i]);
		if (rc < 0) {
			pr_err("Failed to parse %s, rc=%d\n", buf, rc);
			goto cleanup_dtable;
		}
	}

	for (i = 0; i < battery->num_ctables; i++) {
		battery->bp_charge_tables[i] = kzalloc(
				sizeof(*battery->bp_charge_tables[i]), GFP_KERNEL);
		if (!battery->bp_charge_tables[i]) {
			rc = -ENOMEM;
			goto cleanup_ctable;
		}

		scnprintf(buf, sizeof(buf), "qcom,bp-c-table-%d", i + 1);

		rc = qbg_parse_table(battery->profile_node, i, buf,
					battery->bp_charge_tables[i]);
		if (rc < 0) {
			pr_err("Failed to parse %s, rc=%d\n", buf, rc);
			goto cleanup_ctable;
		}
	}

	return 0;

cleanup_ctable:
	for (; i > 0; i--)
		kfree(battery->bp_charge_tables[i]);
	i = battery->num_dtables;
cleanup_dtable:
	for (; i > 0; i--)
		kfree(battery->bp_discharge_tables[i]);

	return rc;
}

int qbg_batterydata_init(struct device_node *profile_node,
	struct qbg_battery_data *battery)
{
	int rc = 0;

	/* char device to access battery-profile data */
	rc = alloc_chrdev_region(&battery->dev_no, 0, 1, "qbg_battery");
	if (rc < 0) {
		pr_err("Failed to allocate chrdev, rc=%d\n", rc);
		goto free_battery;
	}

	cdev_init(&battery->battery_cdev, &qbg_battery_data_fops);
	rc = cdev_add(&battery->battery_cdev, battery->dev_no, 1);
	if (rc) {
		pr_err("Failed to add battery_cdev, rc=%d\n", rc);
		goto unregister_chrdev;
	}

	battery->battery_class = class_create(THIS_MODULE, "qbg_battery");
	if (IS_ERR_OR_NULL(battery->battery_class)) {
		pr_err("Failed to create qbg-battery class (%d)\n",
			PTR_ERR(battery->battery_class));
		rc = -ENODEV;
		goto delete_cdev;
	}

	battery->battery_device = device_create(battery->battery_class, NULL,
						battery->dev_no, NULL,
						"qbg_battery");
	if (IS_ERR_OR_NULL(battery->battery_device)) {
		pr_err("Failed to create battery_device device (%d)\n",
			PTR_ERR(battery->battery_device));
		rc = -ENODEV;
		goto destroy_class;
	}

	battery->profile_node = profile_node;

	/* parse the battery profile */
	rc = qbg_parse_battery_profile(battery);
	if (rc < 0) {
		pr_err("Failed to parse battery profile, rc=%d\n", rc);
		goto destroy_device;
	}

	pr_info("QBG Battery-profile loaded, id:%d name:%s\n",
		battery->bp.bp_batt_id, battery->bp.bp_profile_name);

	return 0;

destroy_device:
	device_destroy(battery->battery_class, battery->dev_no);
destroy_class:
	class_destroy(battery->battery_class);
delete_cdev:
	cdev_del(&battery->battery_cdev);
unregister_chrdev:
	unregister_chrdev_region(battery->dev_no, 1);
free_battery:
	kfree(battery);
	return rc;
}

void qbg_batterydata_exit(struct qbg_battery_data *battery)
{
	int i;

	if (!battery) {
		pr_err("Battery cannot be null\n");
		return;
	}

	/* unregister the device node */
	device_destroy(battery->battery_class, battery->dev_no);
	class_destroy(battery->battery_class);
	cdev_del(&battery->battery_cdev);
	unregister_chrdev_region(battery->dev_no, 1);

	/* delete all the battery profile memory */
	for (i = 0; i < battery->num_ctables; i++)
		kfree(battery->bp_charge_tables[i]);

	for (i = 0; i < battery->num_dtables; i++)
		kfree(battery->bp_discharge_tables[i]);
}

int qbg_lookup_soc_ocv(struct qbg_battery_data *battery, int *pon_soc, int ocv, bool charging)
{
	struct battery_data_table0 *lut;
	int i;

	*pon_soc = -EINVAL;

	lut = charging ? &battery->table0[0] : &battery->table0[1];
	for (i = 0; i < lut->ocv_length; i++) {
		if (ocv == lut->ocv[i]) {
			*pon_soc = lut->soc[i];
			break;
		} else if (is_between(lut->ocv[i], lut->ocv[i+1], ocv)) {
			*pon_soc = (lut->soc[i] + lut->soc[i+1]) / 2;
			break;
		}
	}

	if (*pon_soc == -EINVAL) {
		pr_debug("%d ocv wasn't found in the LUT returning 100%\n", ocv);
		*pon_soc = 10000;
	}

	return 0;
}
+55 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2021 The Linux Foundation. All rights reserved.
 */

#ifndef __QBG_BATTERY_PROFILE_H__
#define __QBG_BATTERY_PROFILE_H__

#define is_between(left, right, value) \
		(((left) >= (right) && (left) >= (value) \
			&& (value) >= (right)) \
		|| ((left) <= (right) && (left) <= (value) \
			&& (value) <= (right)))

struct battery_data_table0 {
	int	soc_length;
	int	ocv_length;
	int	*soc;
	int	*ocv;
};

/**
 * struct qbg_battery_data - Structure for QBG battery data
 * @dev_no:		Device number for QBG battery char device
 * @profile_node:	Pointer to devicetree node handle of profile
 * @battery_class:	Pointer to battery class
 * @battery_device:	Pointer to battery class device
 * @battery_cdev:	QBG battery char device
 * @bp:			QBG battery configuration
 * @bp_charge_tables:	Charge tables in QBG battery profile
 * @bp_discharge_tables:	Discharge tables in QBG battery profile
 * @table0:		Two tables for PON OCV to SOC mapping
 * @num_ctables:	Number of charge tables
 * @num_dtables:	Number of discharge tables
 */

struct qbg_battery_data {
	dev_t				dev_no;
	struct device_node		*profile_node;
	struct class			*battery_class;
	struct device			*battery_device;
	struct cdev			battery_cdev;
	struct battery_config		bp;
	struct battery_data_table	**bp_charge_tables;
	struct battery_data_table	**bp_discharge_tables;
	struct battery_data_table0	table0[2];
	int				num_ctables;
	int				num_dtables;
};

int qbg_batterydata_init(struct device_node *node,
	struct qbg_battery_data *battery);
void qbg_batterydata_exit(struct qbg_battery_data *battery);
int qbg_lookup_soc_ocv(struct qbg_battery_data *battery, int *pon_soc, int ocv, bool charging);
#endif /* __QBG_BATTERY_PROFILE_H__ */
+178 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2021 The Linux Foundation. All rights reserved.
 */

#ifndef __QBG_CORE_H__
#define __QBG_CORE_H__

#define qbg_dbg(chip, reason, fmt, ...)			\
	do {							\
		if (*chip->debug_mask & (reason))		\
			pr_err(fmt, ##__VA_ARGS__);	\
		else						\
			pr_debug(fmt, ##__VA_ARGS__);	\
	} while (0)

enum debug_mask {
	QBG_DEBUG_BUS_READ	= BIT(0),
	QBG_DEBUG_BUS_WRITE	= BIT(1),
	QBG_DEBUG_FIFO		= BIT(2),
	QBG_DEBUG_IRQ		= BIT(3),
	QBG_DEBUG_DEVICE	= BIT(4),
	QBG_DEBUG_PROFILE	= BIT(5),
	QBG_DEBUG_SOC		= BIT(6),
	QBG_DEBUG_SDAM		= BIT(7),
	QBG_DEBUG_STATUS	= BIT(8),
	QBG_DEBUG_PON		= BIT(9),
};

enum qbg_sdam {
	SDAM_CTRL0 = 0,
	SDAM_CTRL1,
	SDAM_DATA0,
	SDAM_DATA1,
	SDAM_DATA2,
	SDAM_DATA3,
	SDAM_DATA4,
};

/**
 * struct qti_qbg - Structure for QTI QBG device
 * @dev:		Pointer to QBG device structure
 * @regmap:		Pointer to regmap structure
 * @qbg_psy:		Pointer to QBG power supply
 * @batt_psy:		Pointer to Battery power supply
 * @qbg_class:		Pointer to QBG class
 * @qbg_device:		Pointer to QBG device
 * @qbg_cdev:		Member for QBG char device
 * @dev_no:		Device number for QBG char device
 * @batt_node:		Pointer to battery device node
 * @indio_dev:		Pointer to QBG IIO device
 * @iio_chan:		Pointer to QBG IIO channels
 * @sdam:		Pointer to multiple QBG SDAMs
 * @fifo:		QBG FIFO data
 * @essential_params:	QBG essential params
 * @status_change_work:	Power supply status change work
 * @udata_work:		User space data change work
 * @nb:			Power supply notifier block
 * @kdata:		QBG Kernel space data structure
 * @udata:		QBG user space data structure
 * @battery:		Pointer to QBG battery data structure
 * @fifo_lock:		Lock for reading FIFO data
 * @data_lock:		Lock for reading kdata from QBG char device
 * @batt_id_chan:	IIO channel to read battery ID
 * @batt_temp_chan:	IIO channel to read battery temperature
 * @rtc:		RTC device to read real time
 * @last_fast_char_time: Timestamp of last time QBG in fast char mode
 * @qbg_wait_q:		Wait queue for reads to QBG char device
 * @irq_name:		QBG interrupt name
 * @batt_type_str:	String array denoting battery type
 * @irq:		QBG irq number
 * @base:		Base address of QBG HW
 * @num_sdams:		Number of sdams used for QBG
 * @batt_id_ohm:	Battery resistance in ohms
 * @debug_mask:		Debug mask to enable/disable debug prints
 * @pon_ocv:		Power-on OCV of QBG device
 * @pon_ibat:		Power-on current of QBG device
 * @pon_soc:		Power-on SOC of QBG device
 * @soc:		Monotonic SOC of QBG device
 * @batt_soc:		Battery SOC
 * @sys_soc:		Battery system SOC
 * @esr:		Battery equivalent series resistance
 * @ocv_uv:		Battery open circuit voltage
 * @voltage_now:	Battery voltage
 * @current_now:	Battery current
 * @tbat:		Battery temperature
 * @charge_cycle_count:	Battery charge cycle count
 * @nominal_capacity:	Battery nominal capacity
 * @learned_capacity:	Battery learned capacity
 * @ttf:		Time to full
 * @tte:		Time to empty
 * @soh:		Battery state of health
 * @charge_type:	Charging type
 * @float_volt_uv:	Battery maximum voltage
 * @fastchg_curr_ma:	Battery fast charge current
 * @vbat_cutoff_mv:	Battery cutoff voltage
 * @ibat_cutoff_ma:	Battery cutoff current
 * @vph_min_mv:	Battery minimum power
 * @iterm_ma:	Charge Termination current
 * @rconn_mohm:	Battery connector resistance
 * @previous_ep_time:	Previous timestamp when essential params stored
 * @current_time:	Current time stamp
 * @profile_loaded:	Flag to indicated battery profile is loaded
 * @battery_missing:	Flag to indicate battery is missing
 * @data_ready:		Flag to indicate QBG data is ready
 * @in_fast_char:	Flag to indicate QBG is in fast char mode
 */
struct qti_qbg {
	struct device		*dev;
	struct regmap		*regmap;
	struct power_supply	*qbg_psy;
	struct power_supply	*batt_psy;
	struct class		*qbg_class;
	struct device		*qbg_device;
	struct cdev		qbg_cdev;
	dev_t			dev_no;
	struct device_node      *batt_node;
	struct iio_dev		*indio_dev;
	struct iio_chan_spec	*iio_chan;
	struct nvmem_device	**sdam;
	struct fifo_data	fifo[MAX_FIFO_COUNT];
	struct qbg_essential_params	essential_params;
	struct work_struct	status_change_work;
	struct work_struct	udata_work;
	struct notifier_block	nb;
	struct qbg_kernel_data	kdata;
	struct qbg_user_data	udata;
	struct qbg_battery_data	*battery;
	struct mutex		fifo_lock;
	struct mutex		data_lock;
	struct iio_channel	*batt_id_chan;
	struct iio_channel	*batt_temp_chan;
	struct rtc_device	*rtc;
	ktime_t			last_fast_char_time;
	wait_queue_head_t	qbg_wait_q;
	const char		*irq_name;
	const char		*batt_type_str;
	int			irq;
	u32			base;
	u32			sdam_base;
	u32			num_sdams;
	u32			num_data_sdams;
	u32			batt_id_ohm;
	u32			*debug_mask;
	int			pon_ocv;
	int			pon_ibat;
	int			pon_tbat;
	int			pon_soc;
	int			soc;
	int			batt_soc;
	int			sys_soc;
	int			esr;
	int			ocv_uv;
	int			voltage_now;
	int			current_now;
	int			tbat;
	int			charge_cycle_count;
	int			nominal_capacity;
	int			learned_capacity;
	int			ttf;
	int			tte;
	int			soh;
	int			charge_type;
	int			float_volt_uv;
	int			fastchg_curr_ma;
	int			vbat_cutoff_mv;
	int			ibat_cutoff_ma;
	int			vph_min_mv;
	int			iterm_ma;
	int			rconn_mohm;
	unsigned long		previous_ep_time;
	unsigned long		current_time;
	bool			profile_loaded;
	bool			battery_missing;
	bool			data_ready;
	bool			in_fast_char;
};
#endif /* __QBG_CORE_H__ */
Loading