Commit 00074a70 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-v5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply

Pull power supply and reset updates from Sebastian Reichel:

 - test_power: add support for current and charge_counter

 - cpcap-charger: improve charge calculation and limit default charge
   voltage

 - ab8500: convert to IIO

 - misc small fixes all over drivers

* tag 'for-v5.5' of git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply: (29 commits)
  power: supply: bd70528: Add MODULE_ALIAS to allow module auto loading
  power: supply: ab8500_charger: Fix inconsistent IS_ERR and PTR_ERR
  power: supply: cpcap-charger: cpcap_charger_voltage_to_regval() can be static
  power: supply: cpcap-battery: Add basic coulomb counter calibrate support
  power: supply: cpcap-battery: Read and save integrator register CCI
  power: supply: cpcap-battery: Simplify short term power average calculation
  power: supply: cpcap-battery: Simplify coulomb counter calculation with div_s64
  power: supply: cpcap-battery: Move coulomb counter units per lsb to ddata
  power: supply: cpcap-charger: Allow changing constant charge voltage
  power: supply: cpcap-battery: Fix handling of lowered charger voltage
  power: supply: cpcap-charger: Improve battery detection
  power: supply: cpcap-battery: Check voltage before orderly_poweroff
  power: supply: cpcap-charger: Limit voltage to 4.2V for battery
  power: supply: ab8500: Handle invalid IRQ from platform_get_irq_byname()
  power: supply: ab8500_fg: Do not free non-requested IRQs in probe's error path
  power: supply: ab8500: Cleanup probe in reverse order
  power: reset: at91: fix __le32 cast in reset code
  power: supply: abx500_chargalg: Fix code indentation
  mfd: Switch the AB8500 GPADC to IIO
  iio: adc: New driver for the AB8500 GPADC
  ...
parents 89d57ddd 9480029f
......@@ -69,6 +69,18 @@ Required child device properties:
- compatible : "stericsson,ab8500-[bm|btemp|charger|fg|gpadc|gpio|ponkey|
pwm|regulator|rtc|sysctrl|usb]";
A few child devices require ADC channels from the GPADC node. Those follow the
standard bindings from iio/iio-bindings.txt and iio/adc/adc.txt
abx500-temp : io-channels "aux1" and "aux2" for measuring external
temperatures.
ab8500-fg : io-channel "main_bat_v" for measuring main battery voltage,
ab8500-btemp : io-channels "btemp_ball" and "bat_ctrl" for measuring the
battery voltage.
ab8500-charger : io-channels "main_charger_v", "main_charger_c", "vbus_v",
"usb_charger_c" for measuring voltage and current of the
different charging supplies.
Optional child device properties:
- interrupts : contains the device IRQ(s) using the 2-cell format (see above)
- interrupt-names : contains names of IRQ resource in the order in which they were
......@@ -102,6 +114,113 @@ ab8500 {
39 0x4>;
interrupt-names = "HW_CONV_END", "SW_CONV_END";
vddadc-supply = <&ab8500_ldo_tvout_reg>;
#address-cells = <1>;
#size-cells = <0>;
#io-channel-cells = <1>;
/* GPADC channels */
bat_ctrl: channel@1 {
reg = <0x01>;
};
btemp_ball: channel@2 {
reg = <0x02>;
};
main_charger_v: channel@3 {
reg = <0x03>;
};
acc_detect1: channel@4 {
reg = <0x04>;
};
acc_detect2: channel@5 {
reg = <0x05>;
};
adc_aux1: channel@6 {
reg = <0x06>;
};
adc_aux2: channel@7 {
reg = <0x07>;
};
main_batt_v: channel@8 {
reg = <0x08>;
};
vbus_v: channel@9 {
reg = <0x09>;
};
main_charger_c: channel@a {
reg = <0x0a>;
};
usb_charger_c: channel@b {
reg = <0x0b>;
};
bk_bat_v: channel@c {
reg = <0x0c>;
};
die_temp: channel@d {
reg = <0x0d>;
};
usb_id: channel@e {
reg = <0x0e>;
};
xtal_temp: channel@12 {
reg = <0x12>;
};
vbat_true_meas: channel@13 {
reg = <0x13>;
};
bat_ctrl_and_ibat: channel@1c {
reg = <0x1c>;
};
vbat_meas_and_ibat: channel@1d {
reg = <0x1d>;
};
vbat_true_meas_and_ibat: channel@1e {
reg = <0x1e>;
};
bat_temp_and_ibat: channel@1f {
reg = <0x1f>;
};
};
ab8500_temp {
compatible = "stericsson,abx500-temp";
io-channels = <&gpadc 0x06>,
<&gpadc 0x07>;
io-channel-name = "aux1", "aux2";
};
ab8500_battery: ab8500_battery {
stericsson,battery-type = "LIPO";
thermistor-on-batctrl;
};
ab8500_fg {
compatible = "stericsson,ab8500-fg";
battery = <&ab8500_battery>;
io-channels = <&gpadc 0x08>;
io-channel-name = "main_bat_v";
};
ab8500_btemp {
compatible = "stericsson,ab8500-btemp";
battery = <&ab8500_battery>;
io-channels = <&gpadc 0x02>,
<&gpadc 0x01>;
io-channel-name = "btemp_ball",
"bat_ctrl";
};
ab8500_charger {
compatible = "stericsson,ab8500-charger";
battery = <&ab8500_battery>;
vddadc-supply = <&ab8500_ldo_tvout_reg>;
io-channels = <&gpadc 0x03>,
<&gpadc 0x0a>,
<&gpadc 0x09>,
<&gpadc 0x0b>;
io-channel-name = "main_charger_v",
"main_charger_c",
"vbus_v",
"usb_charger_c";
};
ab8500-usb {
......
......@@ -5,7 +5,8 @@ Required properties:
- interrupts: Interrupt specifier for each name in interrupt-names
- interrupt-names: Should contain the following entries:
"chrg_det", "rvrs_chrg", "chrg_se1b", "se0conn",
"rvrs_mode", "chrgcurr1", "vbusvld", "battdetb"
"rvrs_mode", "chrgcurr2", "chrgcurr1", "vbusvld",
"battdetb"
- io-channels: IIO ADC channel specifier for each name in io-channel-names
- io-channel-names: Should contain the following entries:
"battdetb", "battp", "vbus", "chg_isense", "batti"
......@@ -21,11 +22,13 @@ cpcap_charger: charger {
compatible = "motorola,mapphone-cpcap-charger";
interrupts-extended = <
&cpcap 13 0 &cpcap 12 0 &cpcap 29 0 &cpcap 28 0
&cpcap 22 0 &cpcap 20 0 &cpcap 19 0 &cpcap 54 0
&cpcap 22 0 &cpcap 21 0 &cpcap 20 0 &cpcap 19 0
&cpcap 54 0
>;
interrupt-names =
"chrg_det", "rvrs_chrg", "chrg_se1b", "se0conn",
"rvrs_mode", "chrgcurr1", "vbusvld", "battdetb";
"rvrs_mode", "chrgcurr2", "chrgcurr1", "vbusvld",
"battdetb";
mode-gpios = <&gpio3 29 GPIO_ACTIVE_LOW
&gpio3 23 GPIO_ACTIVE_LOW>;
io-channels = <&cpcap_adc 0 &cpcap_adc 1
......
......@@ -2021,6 +2021,7 @@ F: drivers/dma/ste_dma40*
F: drivers/hwspinlock/u8500_hsem.c
F: drivers/i2c/busses/i2c-nomadik.c
F: drivers/i2c/busses/i2c-stu300.c
F: drivers/iio/adc/ab8500-gpadc.c
F: drivers/mfd/ab3100*
F: drivers/mfd/ab8500*
F: drivers/mfd/abx500*
......
......@@ -43,11 +43,13 @@ cpcap_charger: charger {
compatible = "motorola,mapphone-cpcap-charger";
interrupts-extended = <
&cpcap 13 0 &cpcap 12 0 &cpcap 29 0 &cpcap 28 0
&cpcap 22 0 &cpcap 20 0 &cpcap 19 0 &cpcap 54 0
&cpcap 22 0 &cpcap 21 0 &cpcap 20 0 &cpcap 19 0
&cpcap 54 0
>;
interrupt-names =
"chrg_det", "rvrs_chrg", "chrg_se1b", "se0conn",
"rvrs_mode", "chrgcurr1", "vbusvld", "battdetb";
"rvrs_mode", "chrgcurr2", "chrgcurr1", "vbusvld",
"battdetb";
mode-gpios = <&gpio3 29 GPIO_ACTIVE_LOW
&gpio3 23 GPIO_ACTIVE_LOW>;
io-channels = <&cpcap_adc 0 &cpcap_adc 1
......
......@@ -40,7 +40,8 @@ comment "Native drivers"
config SENSORS_AB8500
tristate "AB8500 thermal monitoring"
depends on AB8500_GPADC && AB8500_BM
depends on AB8500_GPADC && AB8500_BM && (IIO = y)
default n
help
If you say yes here you get support for the thermal sensor part
of the AB8500 chip. The driver includes thermal management for
......
......@@ -17,19 +17,23 @@
#include <linux/hwmon-sysfs.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500-bm.h>
#include <linux/mfd/abx500/ab8500-gpadc.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/power/ab8500.h>
#include <linux/reboot.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/iio/consumer.h>
#include "abx500.h"
#define DEFAULT_POWER_OFF_DELAY (HZ * 10)
#define THERMAL_VCC 1800
#define PULL_UP_RESISTOR 47000
/* Number of monitored sensors should not greater than NUM_SENSORS */
#define AB8500_SENSOR_AUX1 0
#define AB8500_SENSOR_AUX2 1
#define AB8500_SENSOR_BTEMP_BALL 2
#define AB8500_SENSOR_BAT_CTRL 3
#define NUM_MONITORED_SENSORS 4
struct ab8500_gpadc_cfg {
......@@ -40,7 +44,8 @@ struct ab8500_gpadc_cfg {
};
struct ab8500_temp {
struct ab8500_gpadc *gpadc;
struct iio_channel *aux1;
struct iio_channel *aux2;
struct ab8500_btemp *btemp;
struct delayed_work power_off_work;
struct ab8500_gpadc_cfg cfg;
......@@ -82,15 +87,21 @@ static int ab8500_read_sensor(struct abx500_temp *data, u8 sensor, int *temp)
int voltage, ret;
struct ab8500_temp *ab8500_data = data->plat_data;
if (sensor == BAT_CTRL) {
*temp = ab8500_btemp_get_batctrl_temp(ab8500_data->btemp);
} else if (sensor == BTEMP_BALL) {
if (sensor == AB8500_SENSOR_BTEMP_BALL) {
*temp = ab8500_btemp_get_temp(ab8500_data->btemp);
} else {
voltage = ab8500_gpadc_convert(ab8500_data->gpadc, sensor);
if (voltage < 0)
return voltage;
} else if (sensor == AB8500_SENSOR_BAT_CTRL) {
*temp = ab8500_btemp_get_batctrl_temp(ab8500_data->btemp);
} else if (sensor == AB8500_SENSOR_AUX1) {
ret = iio_read_channel_processed(ab8500_data->aux1, &voltage);
if (ret < 0)
return ret;
ret = ab8500_voltage_to_temp(&ab8500_data->cfg, voltage, temp);
if (ret < 0)
return ret;
} else if (sensor == AB8500_SENSOR_AUX2) {
ret = iio_read_channel_processed(ab8500_data->aux2, &voltage);
if (ret < 0)
return ret;
ret = ab8500_voltage_to_temp(&ab8500_data->cfg, voltage, temp);
if (ret < 0)
return ret;
......@@ -164,10 +175,6 @@ int abx500_hwmon_init(struct abx500_temp *data)
if (!ab8500_data)
return -ENOMEM;
ab8500_data->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
if (IS_ERR(ab8500_data->gpadc))
return PTR_ERR(ab8500_data->gpadc);
ab8500_data->btemp = ab8500_btemp_get();
if (IS_ERR(ab8500_data->btemp))
return PTR_ERR(ab8500_data->btemp);
......@@ -181,15 +188,25 @@ int abx500_hwmon_init(struct abx500_temp *data)
ab8500_data->cfg.tbl_sz = ab8500_temp_tbl_a_size;
data->plat_data = ab8500_data;
ab8500_data->aux1 = devm_iio_channel_get(&data->pdev->dev, "aux1");
if (IS_ERR(ab8500_data->aux1)) {
if (PTR_ERR(ab8500_data->aux1) == -ENODEV)
return -EPROBE_DEFER;
dev_err(&data->pdev->dev, "failed to get AUX1 ADC channel\n");
return PTR_ERR(ab8500_data->aux1);
}
ab8500_data->aux2 = devm_iio_channel_get(&data->pdev->dev, "aux2");
if (IS_ERR(ab8500_data->aux2)) {
if (PTR_ERR(ab8500_data->aux2) == -ENODEV)
return -EPROBE_DEFER;
dev_err(&data->pdev->dev, "failed to get AUX2 ADC channel\n");
return PTR_ERR(ab8500_data->aux2);
}
/*
* ADC_AUX1 and ADC_AUX2, connected to external NTC
* BTEMP_BALL and BAT_CTRL, fixed usage
*/
data->gpadc_addr[0] = ADC_AUX1;
data->gpadc_addr[1] = ADC_AUX2;
data->gpadc_addr[2] = BTEMP_BALL;
data->gpadc_addr[3] = BAT_CTRL;
data->gpadc_addr[0] = AB8500_SENSOR_AUX1;
data->gpadc_addr[1] = AB8500_SENSOR_AUX2;
data->gpadc_addr[2] = AB8500_SENSOR_BTEMP_BALL;
data->gpadc_addr[3] = AB8500_SENSOR_BAT_CTRL;
data->monitored_sensors = NUM_MONITORED_SENSORS;
data->ops.read_sensor = ab8500_read_sensor;
......
......@@ -6,6 +6,16 @@
menu "Analog to digital converters"
config AB8500_GPADC
bool "ST-Ericsson AB8500 GPADC driver"
depends on AB8500_CORE && REGULATOR_AB8500
default y
help
AB8500 Analog Baseband, mixed signal integrated circuit GPADC
(General Purpose Analog to Digital Converter) driver used to monitor
internal voltages, convert accessory and battery, AC (charger, mains)
and USB voltages integral to the U8500 platform.
config AD_SIGMA_DELTA
tristate
select IIO_BUFFER
......
......@@ -4,6 +4,7 @@
#
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
obj-$(CONFIG_AD7124) += ad7124.o
obj-$(CONFIG_AD7266) += ad7266.o
......
......@@ -1210,13 +1210,6 @@ config AB8500_DEBUG
Select this option if you want debug information using the debug
filesystem, debugfs.
config AB8500_GPADC
bool "ST-Ericsson AB8500 GPADC driver"
depends on AB8500_CORE && REGULATOR_AB8500
default y
help
AB8500 GPADC driver used to convert Acc and battery/ac/usb voltage
config MFD_DB8500_PRCMU
bool "ST-Ericsson DB8500 Power Reset Control Management Unit"
depends on UX500_SOC_DB8500
......
......@@ -177,7 +177,6 @@ obj-$(CONFIG_ABX500_CORE) += abx500-core.o
obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o
obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o
# ab8500-core need to come after db8500-prcmu (which provides the channel)
obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o
......
This diff is collapsed.
......@@ -131,7 +131,7 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode,
static int sama5d3_restart(struct notifier_block *this, unsigned long mode,
void *cmd)
{
writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST),
writel(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST,
at91_rstc_base);
return NOTIFY_DONE;
......@@ -140,9 +140,7 @@ static int sama5d3_restart(struct notifier_block *this, unsigned long mode,
static int samx7_restart(struct notifier_block *this, unsigned long mode,
void *cmd)
{
writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PROCRST),
at91_rstc_base);
writel(AT91_RSTC_KEY | AT91_RSTC_PROCRST, at91_rstc_base);
return NOTIFY_DONE;
}
......
......@@ -269,6 +269,12 @@ static const struct of_device_id at91_shdwc_of_match[] = {
};
MODULE_DEVICE_TABLE(of, at91_shdwc_of_match);
static const struct of_device_id at91_pmc_ids[] = {
{ .compatible = "atmel,sama5d2-pmc" },
{ .compatible = "microchip,sam9x60-pmc" },
{ /* Sentinel. */ }
};
static int __init at91_shdwc_probe(struct platform_device *pdev)
{
struct resource *res;
......@@ -313,7 +319,7 @@ static int __init at91_shdwc_probe(struct platform_device *pdev)
at91_shdwc_dt_configure(pdev);
np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-pmc");
np = of_find_matching_node(NULL, at91_pmc_ids);
if (!np) {
ret = -ENODEV;
goto clk_disable;
......
......@@ -629,7 +629,7 @@ config BATTERY_GAUGE_LTC2941
config AB8500_BM
bool "AB8500 Battery Management Driver"
depends on AB8500_CORE && AB8500_GPADC
depends on AB8500_CORE && AB8500_GPADC && (IIO = y)
help
Say Y to include support for AB8500 battery management.
......
......@@ -26,7 +26,7 @@
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/abx500/ab8500-bm.h>
#include <linux/mfd/abx500/ab8500-gpadc.h>
#include <linux/iio/consumer.h>
#define VTVOUT_V 1800
......@@ -79,7 +79,8 @@ struct ab8500_btemp_ranges {
* @bat_temp: Dispatched battery temperature in degree Celsius
* @prev_bat_temp Last measured battery temperature in degree Celsius
* @parent: Pointer to the struct ab8500
* @gpadc: Pointer to the struct gpadc
* @adc_btemp_ball: ADC channel for the battery ball temperature
* @adc_bat_ctrl: ADC channel for the battery control
* @fg: Pointer to the struct fg
* @bm: Platform specific battery management information
* @btemp_psy: Structure for BTEMP specific battery properties
......@@ -96,7 +97,8 @@ struct ab8500_btemp {
int bat_temp;
int prev_bat_temp;
struct ab8500 *parent;
struct ab8500_gpadc *gpadc;
struct iio_channel *btemp_ball;
struct iio_channel *bat_ctrl;
struct ab8500_fg *fg;
struct abx500_bm_data *bm;
struct power_supply *btemp_psy;
......@@ -177,13 +179,13 @@ static int ab8500_btemp_batctrl_volt_to_res(struct ab8500_btemp *di,
*/
static int ab8500_btemp_read_batctrl_voltage(struct ab8500_btemp *di)
{
int vbtemp;
int vbtemp, ret;
static int prev;
vbtemp = ab8500_gpadc_convert(di->gpadc, BAT_CTRL);
if (vbtemp < 0) {
ret = iio_read_channel_processed(di->bat_ctrl, &vbtemp);
if (ret < 0) {
dev_err(di->dev,
"%s gpadc conversion failed, using previous value",
"%s ADC conversion failed, using previous value",
__func__);
return prev;
}
......@@ -455,7 +457,7 @@ static int ab8500_btemp_res_to_temp(struct ab8500_btemp *di,
*/
static int ab8500_btemp_measure_temp(struct ab8500_btemp *di)
{
int temp;
int temp, ret;
static int prev;
int rbat, rntc, vntc;
u8 id;
......@@ -480,10 +482,10 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di)
di->bm->bat_type[id].r_to_t_tbl,
di->bm->bat_type[id].n_temp_tbl_elements, rbat);
} else {
vntc = ab8500_gpadc_convert(di->gpadc, BTEMP_BALL);
if (vntc < 0) {
ret = iio_read_channel_processed(di->btemp_ball, &vntc);
if (ret < 0) {
dev_err(di->dev,
"%s gpadc conversion failed,"
"%s ADC conversion failed,"
" using previous value\n", __func__);
return prev;
}
......@@ -1024,7 +1026,22 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
/* get parent data */
di->dev = &pdev->dev;
di->parent = dev_get_drvdata(pdev->dev.parent);
di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
/* Get ADC channels */
di->btemp_ball = devm_iio_channel_get(&pdev->dev, "btemp_ball");
if (IS_ERR(di->btemp_ball)) {
if (PTR_ERR(di->btemp_ball) == -ENODEV)
return -EPROBE_DEFER;
dev_err(&pdev->dev, "failed to get BTEMP BALL ADC channel\n");
return PTR_ERR(di->btemp_ball);
}
di->bat_ctrl = devm_iio_channel_get(&pdev->dev, "bat_ctrl");
if (IS_ERR(di->bat_ctrl)) {
if (PTR_ERR(di->bat_ctrl) == -ENODEV)
return -EPROBE_DEFER;
dev_err(&pdev->dev, "failed to get BAT CTRL ADC channel\n");
return PTR_ERR(di->bat_ctrl);
}
di->initialized = false;
......@@ -1082,6 +1099,11 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
/* Register interrupts */
for (i = 0; i < ARRAY_SIZE(ab8500_btemp_irq); i++) {
irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name);
if (irq < 0) {
ret = irq;
goto free_irq;
}
ret = request_threaded_irq(irq, NULL, ab8500_btemp_irq[i].isr,
IRQF_SHARED | IRQF_NO_SUSPEND,
ab8500_btemp_irq[i].name, di);
......@@ -1104,13 +1126,13 @@ static int ab8500_btemp_probe(struct platform_device *pdev)
return ret;
free_irq:
power_supply_unregister(di->btemp_psy);
/* We also have to free all successfully registered irqs */
for (i = i - 1; i >= 0; i--) {
irq = platform_get_irq_byname(pdev, ab8500_btemp_irq[i].name);
free_irq(irq, di);
}
power_supply_unregister(di->btemp_psy);
free_btemp_wq:
destroy_workqueue(di->btemp_wq);
return ret;
......
......@@ -29,10 +29,10 @@
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500-bm.h>
#include <linux/mfd/abx500/ab8500-gpadc.h>
#include <linux/mfd/abx500/ux500_chargalg.h>
#include <linux/usb/otg.h>
#include <linux/mutex.h>
#include <linux/iio/consumer.h>
/* Charger constants */
#define NO_PW_CONN 0
......@@ -233,7 +233,10 @@ struct ab8500_charger_max_usb_in_curr {
* @current_stepping_sessions:
* Counter for current stepping sessions
* @parent: Pointer to the struct ab8500
* @gpadc: Pointer to the struct gpadc
* @adc_main_charger_v ADC channel for main charger voltage
* @adc_main_charger_c ADC channel for main charger current
* @adc_vbus_v ADC channel for USB charger voltage
* @adc_usb_charger_c ADC channel for USB charger current
* @bm: Platform specific battery management information
* @flags: Structure for information about events triggered
* @usb_state: Structure for usb stack information
......@@ -283,7 +286,10 @@ struct ab8500_charger {
int is_aca_rid;
atomic_t current_stepping_sessions;
struct ab8500 *parent;
struct ab8500_gpadc *gpadc;
struct iio_channel *adc_main_charger_v;
struct iio_channel *adc_main_charger_c;
struct iio_channel *adc_vbus_v;
struct iio_channel *adc_usb_charger_c;
struct abx500_bm_data *bm;
struct ab8500_charger_event_flags flags;
struct ab8500_charger_usb_state usb_state;
......@@ -459,13 +465,13 @@ static void ab8500_charger_set_usb_connected(struct ab8500_charger *di,
*/
static int ab8500_charger_get_ac_voltage(struct ab8500_charger *di)
{
int vch;
int vch, ret;
/* Only measure voltage if the charger is connected */
if (di->ac.charger_connected) {
vch = ab8500_gpadc_convert(di->gpadc, MAIN_CHARGER_V);
if (vch < 0)
dev_err(di->dev, "%s gpadc conv failed,\n", __func__);
ret = iio_read_channel_processed(di->adc_main_charger_v, &vch);
if (ret < 0)
dev_err(di->dev, "%s ADC conv failed,\n", __func__);
} else {
vch = 0;
}
......@@ -510,13 +516,13 @@ static int ab8500_charger_ac_cv(struct ab8500_charger *di)
*/
static int ab8500_charger_get_vbus_voltage(struct ab8500_charger *di)
{
int vch;
int vch, ret;
/* Only measure voltage if the charger is connected */
if (di->usb.charger_connected) {
vch = ab8500_gpadc_convert(di->gpadc, VBUS_V);
if (vch < 0)
dev_err(di->dev, "%s gpadc conv failed\n", __func__);
ret = iio_read_channel_processed(di->adc_vbus_v, &vch);
if (ret < 0)
dev_err(di->dev, "%s ADC conv failed,\n", __func__);
} else {
vch = 0;
}
......@@ -532,13 +538,13 @@ static int ab8500_charger_get_vbus_voltage(struct ab8500_charger *di)
*/
static int ab8500_charger_get_usb_current(struct ab8500_charger *di)
{
int ich;
int ich, ret;
/* Only measure current if the charger is online */
if (di->usb.charger_online) {
ich = ab8500_gpadc_convert(di->gpadc, USB_CHARGER_C);
if (ich < 0)
dev_err(di->dev, "%s gpadc conv failed\n", __func__);
ret = iio_read_channel_processed(di->adc_usb_charger_c, &ich);
if (ret < 0)
dev_err(di->dev, "%s ADC conv failed,\n", __func__);
} else {
ich = 0;
}
......@@ -554,13 +560,13 @@ static int ab8500_charger_get_usb_current(struct ab8500_charger *di)
*/
static int ab8500_charger_get_ac_current(struct ab8500_charger *di)
{
int ich;
int ich, ret;
/* Only measure current if the charger is online */
if (di->ac.charger_online) {
ich = ab8500_gpadc_convert(di->gpadc, MAIN_CHARGER_C);
if (ich < 0)
dev_err(di->dev, "%s gpadc conv failed\n", __func__);
ret = iio_read_channel_processed(di->adc_main_charger_c, &ich);
if (ret < 0)
dev_err(di->dev, "%s ADC conv failed,\n", __func__);
} else {
ich = 0;
}
......@@ -3371,7 +3377,39 @@ static int ab8500_charger_probe(struct platform_device *pdev)
/* get parent data */
di->dev = &pdev->dev;
di->parent = dev_get_drvdata(pdev->dev.parent);
di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
/* Get ADC channels */
di->adc_main_charger_v = devm_iio_channel_get(&pdev->dev,
"main_charger_v");
if (IS_ERR(di->adc_main_charger_v)) {
if (PTR_ERR(di->adc_main_charger_v) == -ENODEV)
return -EPROBE_DEFER;
dev_err(&pdev->dev, "failed to get ADC main charger voltage\n");
return PTR_ERR(di->adc_main_charger_v);
}
di->adc_main_charger_c = devm_iio_channel_get(&pdev->dev,
"main_charger_c");
if (IS_ERR(di->adc_main_charger_c)) {
if (PTR_ERR(di->adc_main_charger_c) == -ENODEV)
return -EPROBE_DEFER;
dev_err(&pdev->dev, "failed to get ADC main charger current\n");
return PTR_ERR(di->adc_main_charger_c);
}
di->adc_vbus_v = devm_iio_channel_get(&pdev->dev, "vbus_v");
if (IS_ERR(di->adc_vbus_v)) {
if (PTR_ERR(di->adc_vbus_v) == -ENODEV)
return -EPROBE_DEFER;
dev_err(&pdev->dev, "failed to get ADC USB charger voltage\n");
return PTR_ERR(di->adc_vbus_v);
}
di->adc_usb_charger_c = devm_iio_channel_get(&pdev->dev,
"usb_charger_c");
if (IS_ERR(di->adc_usb_charger_c)) {
if (PTR_ERR(di->adc_usb_charger_c) == -ENODEV)
return -EPROBE_DEFER;
dev_err(&pdev->dev, "failed to get ADC USB charger current\n");
return PTR_ERR(di->adc_usb_charger_c);
}
/* initialize lock */
spin_lock_init(&di->usb_state.usb_lock);
......@@ -3556,6 +3594,11 @@ static int ab8500_charger_probe(struct platform_device *pdev)
/* Register interrupts */
for (i = 0; i < ARRAY_SIZE(ab8500_charger_irq); i++) {
irq = platform_get_irq_byname(pdev, ab8500_charger_irq[i].name);
if (irq < 0) {
ret = irq;
goto free_irq;
}
ret = request_threaded_irq(irq, NULL, ab8500_charger_irq[i].isr,
IRQF_SHARED | IRQF_NO_SUSPEND,
ab8500_charger_irq[i].name, di);
......
......@@ -32,7 +32,7 @@
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/abx500/ab8500-bm.h>
#include <linux/mfd/abx500/ab8500-gpadc.h>
#include <linux/iio/consumer.h>
#include <linux/kernel.h>
#define MILLI_TO_MICRO 1000
......@@ -182,7 +182,7 @@ struct inst_curr_result_list {
* @bat_cap: Structure for battery capacity specific parameters
* @avg_cap: Average capacity filter
* @parent: Pointer to the struct ab8500
* @gpadc: Pointer to the struct gpadc
* @main_bat_v: ADC channel for the main battery voltage
* @bm: Platform specific battery management information
* @fg_psy: Structure that holds the FG specific battery properties
* @fg_wq: Work queue for running the FG algorithm
......@@ -224,7 +224,7 @@ struct ab8500_fg {
struct ab8500_fg_battery_capacity bat_cap;
struct ab8500_fg_avg_cap avg_cap;
struct ab8500 *parent;
struct ab8500_gpadc *gpadc;
struct iio_channel *main_bat_v;
struct abx500_bm_data *bm;
struct power_supply *fg_psy;
struct workqueue_struct *fg_wq;
......@@ -829,13 +829,13 @@ static void ab8500_fg_acc_cur_work(struct work_struct *work)
*/
static int ab8500_fg_bat_voltage(struct ab8500_fg *di)
{
int vbat;
int vbat, ret;
static int prev;
vbat = ab8500_gpadc_convert(di->gpadc, MAIN_BAT_V);
if (vbat < 0) {
ret = iio_read_channel_processed(di->main_bat_v, &vbat);
if (ret < 0) {
dev_err(di->dev,
"%s gpadc conversion failed, using previous value\n",
"%s ADC conversion failed, using previous value\n",
__func__);
return prev;
}
......@@ -3066,7 +3066,14 @@ static int ab8500_fg_probe(struct platform_device *pdev)
/* get parent data */
di->dev = &pdev->dev;
di->parent = dev_get_drvdata(pdev->dev.parent);
di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
di->main_bat_v = devm_iio_channel_get(&pdev->dev, "main_bat_v");
if (IS_ERR(di->main_bat_v)) {
if (PTR_ERR(di->main_bat_v) == -ENODEV)
return -EPROBE_DEFER;
dev_err(&pdev->dev, "failed to get main battery ADC channel\n");
return PTR_ERR(di->main_bat_v);
}
psy_cfg.supplied_to = supply_interface;
psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface);
......@@ -3151,6 +3158,11 @@ static int ab8500_fg_probe(struct platform_device *pdev)
/* Register primary interrupt handlers */
for (i = 0; i < ARRAY_SIZE(ab8500_fg_irq_th); i++) {
irq = platform_get_irq_byname(pdev, ab8500_fg_irq_th[i].name);
if (irq < 0) {
ret = irq;
goto free_irq_th;
}
ret = request_irq(irq, ab8500_fg_irq_th[i].isr,
IRQF_SHARED | IRQF_NO_SUSPEND,
ab8500_fg_irq_th[i].name, di);
......@@ -3158,7 +3170,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
if (ret != 0) {
dev_err(di->dev, "failed to request %s IRQ %d: %d\n",
ab8500_fg_irq_th[i].name, irq, ret);
goto free_irq;
goto free_irq_th;
}
dev_dbg(di->dev, "Requested %s IRQ %d: %d\n",
ab8500_fg_irq_th[i].name, irq, ret);
......@@ -3166,6 +3178,11 @@ static int ab8500_fg_probe(struct platform_device *pdev)
/* Register threaded interrupt handler */
irq = platform_get_irq_byname(pdev, ab8500_fg_irq_bh[0].name);
if (irq < 0) {
ret = irq;
goto free_irq_th;
}
ret = request_threaded_irq(irq, NULL, ab8500_fg_irq_bh[0].isr,
IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT,
ab8500_fg_irq_bh[0].name, di);
......@@ -3173,7 +3190,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
if (ret != 0) {
dev_err(di->dev, "failed to request %s IRQ %d: %d\n",
ab8500_fg_irq_bh[0].name, irq, ret);
goto free_irq;
goto free_irq_th;
}
dev_dbg(di->dev, "Requested %s IRQ %d: %d\n",
ab8500_fg_irq_bh[0].name, irq, ret);
......@@ -3212,15 +3229,17 @@ static int ab8500_fg_probe(struct platform_device *pdev)
return ret;
free_irq:
power_supply_unregister(di->fg_psy);
/* We also have to free all registered irqs */
for (i = 0; i < ARRAY_SIZE(ab8500_fg_irq_th); i++) {
irq = platform_get_irq_byname(pdev, ab8500_fg_irq_bh[0].name);
free_irq(irq, di);
free_irq_th:
while (--i >= 0) {
/* Last assignment of i from primary interrupt handlers */
irq = platform_get_irq_byname(pdev, ab8500_fg_irq_th[i].name);
free_irq(irq, di);
}
irq = platform_get_irq_byname(pdev, ab8500_fg_irq_bh[0].name);
free_irq(irq, di);
power_supply_unregister(di->fg_psy);
free_inst_curr_wq:
destroy_workqueue(di->fg_wq);
return ret;
......
......@@ -48,6 +48,8 @@
#define AXP20X_VBUS_MON_VBUS_VALID BIT(3)
#define AXP813_BC_EN BIT(0)
/*
* Note do not raise the debounce time, we must report Vusb high within
* 100ms otherwise we get Vbus errors in musb.
......@@ -495,6 +497,12 @@ static int axp20x_usb_power_probe(struct platform_device *pdev)
return -EINVAL;
}
if (power->axp20x_id == AXP813_ID) {
/* Enable USB Battery Charging specification detection */
regmap_update_bits(axp20x->regmap, AXP288_BC_GLOBAL,
AXP813_BC_EN, AXP813_BC_EN);
}
psy_cfg.of_node = pdev->dev.of_node;
psy_cfg.drv_data = power;
......
......@@ -741,3 +741,4 @@ module_platform_driver(bd70528_power);
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
MODULE_DESCRIPTION("BD70528 power-supply driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:bd70528-power");
This diff is collapsed.
......@@ -120,6 +120,13 @@ enum {
CPCAP_CHARGER_IIO_NR,
};
enum {
CPCAP_CHARGER_DISCONNECTED,
CPCAP_CHARGER_DETECTING,
CPCAP_CHARGER_CHARGING,
CPCAP_CHARGER_DONE,
};
struct cpcap_charger_ddata {
struct device *dev;
struct regmap *reg;
......@@ -138,6 +145,8 @@ struct cpcap_charger_ddata {
atomic_t active;
int status;
int state;
int voltage;
};
struct cpcap_interrupt_desc {
......@@ -153,6 +162,7 @@ struct cpcap_charger_ints_state {
bool chrg_se1b;
bool rvrs_mode;
bool chrgcurr2;
bool chrgcurr1;
bool vbusvld;
......@@ -162,24 +172,26 @@ struct cpcap_charger_ints_state {
static enum power_supply_property cpcap_charger_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CURRENT_NOW,
};
/* No battery always shows temperature of -40000 */
static bool cpcap_charger_battery_found(struct cpcap_charger_ddata *ddata)
{
struct iio_channel *channel;
int error, value;
int error, temperature;
channel = ddata->channels[CPCAP_CHARGER_IIO_BATTDET];
error = iio_read_channel_raw(channel, &value);
error = iio_read_channel_processed(channel, &temperature);
if (error < 0) {
dev_warn(ddata->dev, "%s failed: %i\n", __func__, error);
return false;
}
return value == 1;
return temperature > -20000 && temperature < 60000;
}
static int cpcap_charger_get_charge_voltage(struct cpcap_charger_ddata *ddata)
......@@ -224,6 +236,9 @@ static int cpcap_charger_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_STATUS:
val->intval = ddata->status;
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
val->intval = ddata->voltage;
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
if (ddata->status == POWER_SUPPLY_STATUS_CHARGING)
val->intval = cpcap_charger_get_charge_voltage(ddata) *
......@@ -248,6 +263,83 @@ static int cpcap_charger_get_property(struct power_supply *psy,
return 0;
}
static int cpcap_charger_match_voltage(int voltage)
{
switch (voltage) {
case 0 ... 4100000 - 1: return 3800000;
case 4100000 ... 4120000 - 1: return 4100000;
case 4120000 ... 4150000 - 1: return 4120000;
case 4150000 ... 4170000 - 1: return 4150000;
case 4170000 ... 4200000 - 1: return 4170000;
case 4200000 ... 4230000 - 1: return 4200000;
case 4230000 ... 4250000 - 1: return 4230000;
case 4250000 ... 4270000 - 1: return 4250000;
case 4270000 ... 4300000 - 1: return 4270000;
case 4300000 ... 4330000 - 1: return 4300000;
case 4330000 ... 4350000 - 1: return 4330000;
case 4350000 ... 4380000 - 1: return 4350000;
case 4380000 ... 4400000 - 1: return 4380000;
case 4400000 ... 4420000 - 1: return 4400000;
case 4420000 ... 4440000 - 1: return 4420000;
case 4440000: return 4440000;
default: return 0;
}
}
static int
cpcap_charger_get_bat_const_charge_voltage(struct cpcap_charger_ddata *ddata)
{
union power_supply_propval prop;
struct power_supply *battery;
int voltage = ddata->voltage;
int error;
battery = power_supply_get_by_name("battery");
if (battery) {
error = power_supply_get_property(battery,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
&prop);
if (!error)
voltage = prop.intval;
}
return voltage;
}
static int cpcap_charger_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
struct cpcap_charger_ddata *ddata = dev_get_drvdata(psy->dev.parent);
int voltage, batvolt;
switch (psp) {
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
voltage = cpcap_charger_match_voltage(val->intval);
batvolt = cpcap_charger_get_bat_const_charge_voltage(ddata);
if (voltage > batvolt)
voltage = batvolt;
ddata->voltage = voltage;
schedule_delayed_work(&ddata->detect_work, 0);
break;
default:
return -EINVAL;
}
return 0;
}
static int cpcap_charger_property_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
switch (psp) {
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
return 1;
default:
return 0;
}
}
static void cpcap_charger_set_cable_path(struct cpcap_charger_ddata *ddata,
bool enabled)
{
......@@ -422,6 +514,7 @@ static int cpcap_charger_get_ints_state(struct cpcap_charger_ddata *ddata,
s->chrg_se1b = val & BIT(13);
s->rvrs_mode = val & BIT(6);
s->chrgcurr2 = val & BIT(5);
s->chrgcurr1 = val & BIT(4);
s->vbusvld = val & BIT(3);
......@@ -434,6 +527,79 @@ static int cpcap_charger_get_ints_state(struct cpcap_charger_ddata *ddata,
return 0;
}
static void cpcap_charger_update_state(struct cpcap_charger_ddata *ddata,
int state)
{
const char *status;
if (state > CPCAP_CHARGER_DONE) {
dev_warn(ddata->dev, "unknown state: %i\n", state);
return;
}
ddata->state = state;
switch (state) {
case CPCAP_CHARGER_DISCONNECTED:
status = "DISCONNECTED";
break;
case CPCAP_CHARGER_DETECTING:
status = "DETECTING";
break;
case CPCAP_CHARGER_CHARGING:
status = "CHARGING";
break;
case CPCAP_CHARGER_DONE:
status = "DONE";
break;
default:
return;
}
dev_dbg(ddata->dev, "state: %s\n", status);
}
static int cpcap_charger_voltage_to_regval(int voltage)
{
int offset;
switch (voltage) {
case 0 ... 4100000 - 1:
return 0;
case 4100000 ... 4200000 - 1:
offset = 1;
break;
case 4200000 ... 4300000 - 1:
offset = 0;
break;
case 4300000 ... 4380000 - 1:
offset = -1;
break;
case 4380000 ... 4440000:
offset = -2;
break;
default:
return 0;
}
return ((voltage - 4100000) / 20000) + offset;
}
static void cpcap_charger_disconnect(struct cpcap_charger_ddata *ddata,
int state, unsigned long delay)
{
int error;
error = cpcap_charger_set_state(ddata, 0, 0, 0);
if (error)
return;
cpcap_charger_update_state(ddata, state);
power_supply_changed(ddata->usb);
schedule_delayed_work(&ddata->detect_work, delay);
}
static void cpcap_usb_detect(struct work_struct *work)
{
struct cpcap_charger_ddata *ddata;
......@@ -447,24 +613,67 @@ static void cpcap_usb_detect(struct work_struct *work)
if (error)
return;
/* Just init the state if a charger is connected with no chrg_det set */
if (!s.chrg_det && s.chrgcurr1 && s.vbusvld) {
cpcap_charger_update_state(ddata, CPCAP_CHARGER_DETECTING);
return;
}
/*
* If battery voltage is higher than charge voltage, it may have been
* charged to 4.35V by Android. Try again in 10 minutes.
*/
if (cpcap_charger_get_charge_voltage(ddata) > ddata->voltage) {
cpcap_charger_disconnect(ddata, CPCAP_CHARGER_DETECTING,
HZ * 60 * 10);
return;
}
/* Throttle chrgcurr2 interrupt for charger done and retry */
switch (ddata->state) {
case CPCAP_CHARGER_CHARGING:
if (s.chrgcurr2)
break;
if (s.chrgcurr1 && s.vbusvld) {
cpcap_charger_disconnect(ddata, CPCAP_CHARGER_DONE,
HZ * 5);
return;
}
break;
case CPCAP_CHARGER_DONE:
if (!s.chrgcurr2)
break;
cpcap_charger_disconnect(ddata, CPCAP_CHARGER_DETECTING,
HZ * 5);
return;
default:
break;
}
if (!ddata->feeding_vbus && cpcap_charger_vbus_valid(ddata) &&
s.chrgcurr1) {
int max_current;
int vchrg;
if (cpcap_charger_battery_found(ddata))
max_current = CPCAP_REG_CRM_ICHRG_1A596;
else
max_current = CPCAP_REG_CRM_ICHRG_0A532;
vchrg = cpcap_charger_voltage_to_regval(ddata->voltage);
error = cpcap_charger_set_state(ddata,
CPCAP_REG_CRM_VCHRG_4V35,
CPCAP_REG_CRM_VCHRG(vchrg),
max_current, 0);
if (error)
goto out_err;
cpcap_charger_update_state(ddata, CPCAP_CHARGER_CHARGING);
} else {
error = cpcap_charger_set_state(ddata, 0, 0, 0);
if (error)
goto out_err;
cpcap_charger_update_state(ddata, CPCAP_CHARGER_DISCONNECTED);
}
power_supply_changed(ddata->usb);
......@@ -524,7 +733,7 @@ static const char * const cpcap_charger_irqs[] = {
"chrg_det", "rvrs_chrg",
/* REG_INT1 */
"chrg_se1b", "se0conn", "rvrs_mode", "chrgcurr1", "vbusvld",
"chrg_se1b", "se0conn", "rvrs_mode", "chrgcurr2", "chrgcurr1", "vbusvld",
/* REG_INT_3 */
"battdetb",
......@@ -596,6 +805,8 @@ static const struct power_supply_desc cpcap_charger_usb_desc = {
.properties = cpcap_charger_props,
.num_properties = ARRAY_SIZE(cpcap_charger_props),
.get_property = cpcap_charger_get_property,
.set_property = cpcap_charger_set_property,
.property_is_writeable = cpcap_charger_property_is_writeable,
};
#ifdef CONFIG_OF
......@@ -625,6 +836,7 @@ static int cpcap_charger_probe(struct platform_device *pdev)
return -ENOMEM;
ddata->dev = &pdev->dev;
ddata->voltage = 4200000;
ddata->reg = dev_get_regmap(ddata->dev->parent, NULL);
if (!ddata->reg)
......
......@@ -33,6 +33,8 @@ static int battery_present = 1; /* true */
static int battery_technology = POWER_SUPPLY_TECHNOLOGY_LION;
static int battery_capacity = 50;
static int battery_voltage = 3300;
static int battery_charge_counter = -1000;
static int battery_current = 1600;
static bool module_initialized;
......@@ -100,6 +102,9 @@ static int test_power_get_battery_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_CHARGE_NOW:
val->intval = battery_capacity;
break;
case POWER_SUPPLY_PROP_CHARGE_COUNTER:
val->intval = battery_charge_counter;
break;
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
case POWER_SUPPLY_PROP_CHARGE_FULL:
val->intval = 100;
......@@ -114,6 +119,10 @@ static int test_power_get_battery_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
val->intval = battery_voltage;
break;
case POWER_SUPPLY_PROP_CURRENT_AVG:
case POWER_SUPPLY_PROP_CURRENT_NOW:
val->intval = battery_current;
break;
default:
pr_info("%s: some properties deliberately report errors.\n",
__func__);
......@@ -135,6 +144,7 @@ static enum power_supply_property test_power_battery_props[] = {
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_CHARGE_COUNTER,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
......@@ -144,6 +154,8 @@ static enum power_supply_property test_power_battery_props[] = {
POWER_SUPPLY_PROP_SERIAL_NUMBER,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CURRENT_AVG,
POWER_SUPPLY_PROP_CURRENT_NOW,
};
static char *test_power_ac_supplied_to[] = {
......@@ -447,6 +459,36 @@ static int param_set_battery_voltage(const char *key,
#define param_get_battery_voltage param_get_int
static int param_set_battery_charge_counter(const char *key,
const struct kernel_param *kp)
{
int tmp;
if (1 != sscanf(key, "%d", &tmp))
return -EINVAL;
battery_charge_counter = tmp;
signal_power_supply_changed(test_power_supplies[TEST_BATTERY]);
return 0;
}
#define param_get_battery_charge_counter param_get_int
static int param_set_battery_current(const char *key,
const struct kernel_param *kp)
{
int tmp;
if (1 != sscanf(key, "%d", &tmp))
return -EINVAL;
battery_current = tmp;
signal_power_supply_changed(test_power_supplies[TEST_BATTERY]);
return 0;
}
#define param_get_battery_current param_get_int
static const struct kernel_param_ops param_ops_ac_online = {
.set = param_set_ac_online,
.get = param_get_ac_online,
......@@ -487,6 +529,16 @@ static const struct kernel_param_ops param_ops_battery_voltage = {
.get = param_get_battery_voltage,
};
static const struct kernel_param_ops param_ops_battery_charge_counter = {
.set = param_set_battery_charge_counter,
.get = param_get_battery_charge_counter,
};
static const struct kernel_param_ops param_ops_battery_current = {
.set = param_set_battery_current,
.get = param_get_battery_current,
};
#define param_check_ac_online(name, p) __param_check(name, p, void);
#define param_check_usb_online(name, p) __param_check(name, p, void);
#define param_check_battery_status(name, p) __param_check(name, p, void);
......@@ -495,6 +547,8 @@ static const struct kernel_param_ops param_ops_battery_voltage = {
#define param_check_battery_health(name, p) __param_check(name, p, void);
#define param_check_battery_capacity(name, p) __param_check(name, p, void);
#define param_check_battery_voltage(name, p) __param_check(name, p, void);
#define param_check_battery_charge_counter(name, p) __param_check(name, p, void);
#define param_check_battery_current(name, p) __param_check(name, p, void);
module_param(ac_online, ac_online, 0644);
......@@ -525,6 +579,13 @@ MODULE_PARM_DESC(battery_capacity, "battery capacity (percentage)");
module_param(battery_voltage, battery_voltage, 0644);
MODULE_PARM_DESC(battery_voltage, "battery voltage (millivolts)");
module_param(battery_charge_counter, battery_charge_counter, 0644);
MODULE_PARM_DESC(battery_charge_counter,
"battery charge counter (microampere-hours)");
module_param(battery_current, battery_current, 0644);
MODULE_PARM_DESC(battery_current, "battery current (milliampere)");
MODULE_DESCRIPTION("Power supply driver for testing");
MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>");
MODULE_LICENSE("GPL");
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2010 ST-Ericsson SA
*
* Author: Arun R Murthy <arun.murthy@stericsson.com>
* Author: Daniel Willerud <daniel.willerud@stericsson.com>
* Author: M'boumba Cedric Madianga <cedric.madianga@stericsson.com>
*/
#ifndef _AB8500_GPADC_H
#define _AB8500_GPADC_H
/* GPADC source: From datasheet(ADCSwSel[4:0] in GPADCCtrl2
* and ADCHwSel[4:0] in GPADCCtrl3 ) */
#define BAT_CTRL 0x01
#define BTEMP_BALL 0x02
#define MAIN_CHARGER_V 0x03
#define ACC_DETECT1 0x04
#define ACC_DETECT2 0x05
#define ADC_AUX1 0x06
#define ADC_AUX2 0x07
#define MAIN_BAT_V 0x08
#define VBUS_V 0x09
#define MAIN_CHARGER_C 0x0A
#define USB_CHARGER_C 0x0B
#define BK_BAT_V 0x0C
#define DIE_TEMP 0x0D
#define USB_ID 0x0E
#define XTAL_TEMP 0x12
#define VBAT_TRUE_MEAS 0x13
#define BAT_CTRL_AND_IBAT 0x1C
#define VBAT_MEAS_AND_IBAT 0x1D
#define VBAT_TRUE_MEAS_AND_IBAT 0x1E
#define BAT_TEMP_AND_IBAT 0x1F
/* Virtual channel used only for ibat convertion to ampere
* Battery current conversion (ibat) cannot be requested as a single conversion
* but it is always in combination with other input requests
*/
#define IBAT_VIRTUAL_CHANNEL 0xFF
#define SAMPLE_1 1
#define SAMPLE_4 4
#define SAMPLE_8 8
#define SAMPLE_16 16
#define RISING_EDGE 0
#define FALLING_EDGE 1
/* Arbitrary ADC conversion type constants */
#define ADC_SW 0
#define ADC_HW 1
struct ab8500_gpadc;
struct ab8500_gpadc *ab8500_gpadc_get(char *name);
int ab8500_gpadc_sw_hw_convert(struct ab8500_gpadc *gpadc, u8 channel,
u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type);
static inline int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 channel)
{
return ab8500_gpadc_sw_hw_convert(gpadc, channel,
SAMPLE_16, 0, 0, ADC_SW);
}
int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type);
int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel,
u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type,
int *ibat);
int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc,
u8 channel, int ad_value);
void ab8540_gpadc_get_otp(struct ab8500_gpadc *gpadc,
u16 *vmain_l, u16 *vmain_h, u16 *btemp_l, u16 *btemp_h,
u16 *vbat_l, u16 *vbat_h, u16 *ibat_l, u16 *ibat_h);
#endif /* _AB8500_GPADC_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment