linux/drivers/power/supply/cpcap-battery.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Battery driver for CPCAP PMIC
 *
 * Copyright (C) 2017 Tony Lindgren <[email protected]>
 *
 * Some parts of the code based on earlier Motorola mapphone Linux kernel
 * drivers:
 *
 * Copyright (C) 2009-2010 Motorola, Inc.
 */

#include <linux/delay.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/nvmem-consumer.h>
#include <linux/moduleparam.h>

#include <linux/iio/consumer.h>
#include <linux/iio/types.h>
#include <linux/mfd/motorola-cpcap.h>

/*
 * Register bit defines for CPCAP_REG_BPEOL. Some of these seem to
 * map to MC13783UG.pdf "Table 5-19. Register 13, Power Control 0"
 * to enable BATTDETEN, LOBAT and EOL features. We currently use
 * LOBAT interrupts instead of EOL.
 */
#define CPCAP_REG_BPEOL_BIT_EOL9
#define CPCAP_REG_BPEOL_BIT_EOL8
#define CPCAP_REG_BPEOL_BIT_UNKNOWN7
#define CPCAP_REG_BPEOL_BIT_UNKNOWN6
#define CPCAP_REG_BPEOL_BIT_UNKNOWN5
#define CPCAP_REG_BPEOL_BIT_EOL_MULTI
#define CPCAP_REG_BPEOL_BIT_UNKNOWN3
#define CPCAP_REG_BPEOL_BIT_UNKNOWN2
#define CPCAP_REG_BPEOL_BIT_BATTDETEN
#define CPCAP_REG_BPEOL_BIT_EOLSEL

/*
 * Register bit defines for CPCAP_REG_CCC1. These seem similar to the twl6030
 * coulomb counter registers rather than the mc13892 registers. Both twl6030
 * and mc13892 set bits 2 and 1 to reset and clear registers. But mc13892
 * sets bit 0 to start the coulomb counter while twl6030 sets bit 0 to stop
 * the coulomb counter like cpcap does. So for now, we use the twl6030 style
 * naming for the registers.
 */
#define CPCAP_REG_CCC1_ACTIVE_MODE1
#define CPCAP_REG_CCC1_ACTIVE_MODE0
#define CPCAP_REG_CCC1_AUTOCLEAR
#define CPCAP_REG_CCC1_CAL_EN
#define CPCAP_REG_CCC1_PAUSE
#define CPCAP_REG_CCC1_RESET_MASK

#define CPCAP_REG_CCCC2_RATE1
#define CPCAP_REG_CCCC2_RATE0
#define CPCAP_REG_CCCC2_ENABLE

#define CPCAP_BATTERY_CC_SAMPLE_PERIOD_MS

#define CPCAP_BATTERY_EB41_HW4X_ID
#define CPCAP_BATTERY_BW8X_ID

enum {};

enum cpcap_battery_irq_action {};

struct cpcap_interrupt_desc {};

struct cpcap_battery_config {};

struct cpcap_coulomb_counter_data {};

enum cpcap_battery_state {};

struct cpcap_battery_state_data {};

struct cpcap_battery_ddata {};

#define CPCAP_NO_BATTERY

static bool ignore_temperature_probe;
module_param(ignore_temperature_probe, bool, 0660);

static struct cpcap_battery_state_data *
cpcap_battery_get_state(struct cpcap_battery_ddata *ddata,
			enum cpcap_battery_state state)
{}

static struct cpcap_battery_state_data *
cpcap_battery_latest(struct cpcap_battery_ddata *ddata)
{}

static struct cpcap_battery_state_data *
cpcap_battery_previous(struct cpcap_battery_ddata *ddata)
{}

static struct cpcap_battery_state_data *
cpcap_battery_get_empty(struct cpcap_battery_ddata *ddata)
{}

static struct cpcap_battery_state_data *
cpcap_battery_get_full(struct cpcap_battery_ddata *ddata)
{}

static int cpcap_charger_battery_temperature(struct cpcap_battery_ddata *ddata,
					     int *value)
{}

static int cpcap_battery_get_voltage(struct cpcap_battery_ddata *ddata)
{}

static int cpcap_battery_get_current(struct cpcap_battery_ddata *ddata)
{}

/**
 * cpcap_battery_cc_raw_div - calculate and divide coulomb counter μAms values
 * @ddata: device driver data
 * @sample: coulomb counter sample value
 * @accumulator: coulomb counter integrator value
 * @offset: coulomb counter offset value
 * @divider: conversion divider
 *
 * Note that cc_lsb and cc_dur values are from Motorola Linux kernel
 * function data_get_avg_curr_ua() and seem to be based on measured test
 * results. It also has the following comment:
 *
 * Adjustment factors are applied here as a temp solution per the test
 * results. Need to work out a formal solution for this adjustment.
 *
 * A coulomb counter for similar hardware seems to be documented in
 * "TWL6030 Gas Gauging Basics (Rev. A)" swca095a.pdf in chapter
 * "10 Calculating Accumulated Current". We however follow what the
 * Motorola mapphone Linux kernel is doing as there may be either a
 * TI or ST coulomb counter in the PMIC.
 */
static int cpcap_battery_cc_raw_div(struct cpcap_battery_ddata *ddata,
				    s32 sample, s32 accumulator,
				    s16 offset, u32 divider)
{}

/* 3600000μAms = 1μAh */
static int cpcap_battery_cc_to_uah(struct cpcap_battery_ddata *ddata,
				   s32 sample, s32 accumulator,
				   s16 offset)
{}

static int cpcap_battery_cc_to_ua(struct cpcap_battery_ddata *ddata,
				  s32 sample, s32 accumulator,
				  s16 offset)
{}

/**
 * cpcap_battery_read_accumulated - reads cpcap coulomb counter
 * @ddata: device driver data
 * @ccd: coulomb counter values
 *
 * Based on Motorola mapphone kernel function data_read_regs().
 * Looking at the registers, the coulomb counter seems similar to
 * the coulomb counter in TWL6030. See "TWL6030 Gas Gauging Basics
 * (Rev. A) swca095a.pdf for "10 Calculating Accumulated Current".
 *
 * Note that swca095a.pdf instructs to stop the coulomb counter
 * before reading to avoid values changing. Motorola mapphone
 * Linux kernel does not do it, so let's assume they've verified
 * the data produced is correct.
 */
static int
cpcap_battery_read_accumulated(struct cpcap_battery_ddata *ddata,
			       struct cpcap_coulomb_counter_data *ccd)
{}


/*
 * Based on the values from Motorola mapphone Linux kernel for the
 * stock Droid 4 battery eb41. In the Motorola mapphone Linux
 * kernel tree the value for pm_cd_factor is passed to the kernel
 * via device tree. If it turns out to be something device specific
 * we can consider that too later. These values are also fine for
 * Bionic's hw4x.
 *
 * And looking at the battery full and shutdown values for the stock
 * kernel on droid 4, full is 4351000 and software initiates shutdown
 * at 3078000. The device will die around 2743000.
 */
static const struct cpcap_battery_config cpcap_battery_eb41_data =;

/* Values for the extended Droid Bionic battery bw8x. */
static const struct cpcap_battery_config cpcap_battery_bw8x_data =;

/*
 * Safe values for any lipo battery likely to fit into a mapphone
 * battery bay.
 */
static const struct cpcap_battery_config cpcap_battery_unkown_data =;

static int cpcap_battery_match_nvmem(struct device *dev, const void *data)
{}

static void cpcap_battery_detect_battery_type(struct cpcap_battery_ddata *ddata)
{}

/**
 * cpcap_battery_cc_get_avg_current - read cpcap coulumb counter
 * @ddata: cpcap battery driver device data
 */
static int cpcap_battery_cc_get_avg_current(struct cpcap_battery_ddata *ddata)
{}

static int cpcap_battery_get_charger_status(struct cpcap_battery_ddata *ddata,
					    int *val)
{}

static bool cpcap_battery_full(struct cpcap_battery_ddata *ddata)
{}

static bool cpcap_battery_low(struct cpcap_battery_ddata *ddata)
{}

static int cpcap_battery_update_status(struct cpcap_battery_ddata *ddata)
{}

/*
 * Update battery status when cpcap-charger calls power_supply_changed().
 * This allows us to detect battery full condition before the charger
 * disconnects.
 */
static void cpcap_battery_external_power_changed(struct power_supply *psy)
{}

static enum power_supply_property cpcap_battery_props[] =;

static int cpcap_battery_get_property(struct power_supply *psy,
				      enum power_supply_property psp,
				      union power_supply_propval *val)
{}

static int cpcap_battery_update_charger(struct cpcap_battery_ddata *ddata,
					int const_charge_voltage)
{}

static int cpcap_battery_set_property(struct power_supply *psy,
				      enum power_supply_property psp,
				      const union power_supply_propval *val)
{}

static int cpcap_battery_property_is_writeable(struct power_supply *psy,
					       enum power_supply_property psp)
{}

static irqreturn_t cpcap_battery_irq_thread(int irq, void *data)
{}

static int cpcap_battery_init_irq(struct platform_device *pdev,
				  struct cpcap_battery_ddata *ddata,
				  const char *name)
{}

static int cpcap_battery_init_interrupts(struct platform_device *pdev,
					 struct cpcap_battery_ddata *ddata)
{}

static int cpcap_battery_init_iio(struct cpcap_battery_ddata *ddata)
{}

/* Calibrate coulomb counter */
static int cpcap_battery_calibrate(struct cpcap_battery_ddata *ddata)
{}

#ifdef CONFIG_OF
static const struct of_device_id cpcap_battery_id_table[] =;
MODULE_DEVICE_TABLE(of, cpcap_battery_id_table);
#endif

static const struct power_supply_desc cpcap_charger_battery_desc =;

static int cpcap_battery_probe(struct platform_device *pdev)
{}

static void cpcap_battery_remove(struct platform_device *pdev)
{}

static struct platform_driver cpcap_battery_driver =;
module_platform_driver();

MODULE_LICENSE();
MODULE_AUTHOR();
MODULE_DESCRIPTION();