mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-25 05:04:09 +08:00
power supply and reset changes for the v5.5 series
Drivers: * 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 -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE72YNB0Y/i3JqeVQT2O7X88g7+poFAl3dFBkACgkQ2O7X88g7 +ppUPQ/7Bv3GRusMB9Z/nTlhTLyR68P5vOoQ7Axfhi9NUCIq3RRG/pKZkYKKits1 5U9Z13pceDznmWvamPvNkhH6mVjS4JsLsJOSkp8op2DvptQpcrfs5t+XhBamWu/D pmy6FkhbFLhxSRshd3st1VcqPZNc9/PmoYaoBp397wDF+SKZxJ+wI/Fm6LQmqG/q SZv8eBKFmViyv+xYmXGJf2CZanxzZ0DZK2ZMYlp39XQcfOw90ImD5crZJcLlf9zQ HJV69JxurCDb0ovr2JfRjYtyfx8eqYFxSE5o6rqqNWIPGikQs3+TajovMuO5B0D0 FmLxkgMeNAzK1CzccxKKh1qQi65T8Kdv+N6pgVgsR9wVfCmLsfYCeBrZb4PJv5GH hlJSZXxzYKgN00bD/7HA2l0hlUpIepQm0EtNCyjiPwGMVAHr8MerCfHwbzr5oWfq h1G3hGW9OOm1BwVvScff08UdL2xI6A7Aa7lLXqCkwM3oXhdFPAmr3qiv0Rw8wVNS /LY1HiQ2jldWgdVPdSMvPoLqxdfebz/Ro0J7do2amPGj/ebh6H7GvUVIxX/8cNZe iz22kzoJXW+k9173FGNZA+4Ccf49XdplFn2uinX9TsNCf4XCKcyWq+3aPczQ6zSl ZPqGn4mOpjRLm3xl/DbOOWXpNqFszVHhhX4G/WAMB8RMseFfelw= =iHhO -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
00074a7007
@ -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,8 +114,115 @@ 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 {
|
||||
compatible = "stericsson,ab8500-usb";
|
||||
interrupts = < 90 0x4
|
||||
|
@ -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 @@
|
||||
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,20 +17,24 @@
|
||||
#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 NUM_MONITORED_SENSORS 4
|
||||
|
||||
#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 {
|
||||
const struct abx500_res_to_temp *temp_tbl;
|
||||
@ -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
|
||||
|
1218
drivers/iio/adc/ab8500-gpadc.c
Normal file
1218
drivers/iio/adc/ab8500-gpadc.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -84,7 +84,6 @@
|
||||
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/mfd/abx500/ab8500.h>
|
||||
#include <linux/mfd/abx500/ab8500-gpadc.h>
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
#include <linux/string.h>
|
||||
@ -103,11 +102,6 @@ static int num_irqs;
|
||||
static struct device_attribute **dev_attr;
|
||||
static char **event_name;
|
||||
|
||||
static u8 avg_sample = SAMPLE_16;
|
||||
static u8 trig_edge = RISING_EDGE;
|
||||
static u8 conv_type = ADC_SW;
|
||||
static u8 trig_timer;
|
||||
|
||||
/**
|
||||
* struct ab8500_reg_range
|
||||
* @first: the first address of the range
|
||||
@ -152,7 +146,6 @@ static struct hwreg_cfg hwreg_cfg = {
|
||||
};
|
||||
|
||||
#define AB8500_NAME_STRING "ab8500"
|
||||
#define AB8500_ADC_NAME_STRING "gpadc"
|
||||
#define AB8500_NUM_BANKS AB8500_DEBUG_FIELD_LAST
|
||||
|
||||
#define AB8500_REV_REG 0x80
|
||||
@ -1646,633 +1639,6 @@ report_write_failure:
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_modem);
|
||||
|
||||
static int ab8500_gpadc_bat_ctrl_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int bat_ctrl_raw;
|
||||
int bat_ctrl_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
bat_ctrl_raw = ab8500_gpadc_read_raw(gpadc, BAT_CTRL,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
bat_ctrl_convert = ab8500_gpadc_ad_to_voltage(gpadc,
|
||||
BAT_CTRL, bat_ctrl_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", bat_ctrl_convert, bat_ctrl_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_bat_ctrl);
|
||||
|
||||
static int ab8500_gpadc_btemp_ball_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int btemp_ball_raw;
|
||||
int btemp_ball_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
btemp_ball_raw = ab8500_gpadc_read_raw(gpadc, BTEMP_BALL,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
btemp_ball_convert = ab8500_gpadc_ad_to_voltage(gpadc, BTEMP_BALL,
|
||||
btemp_ball_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", btemp_ball_convert, btemp_ball_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_btemp_ball);
|
||||
|
||||
static int ab8500_gpadc_main_charger_v_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int main_charger_v_raw;
|
||||
int main_charger_v_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
main_charger_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_V,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
main_charger_v_convert = ab8500_gpadc_ad_to_voltage(gpadc,
|
||||
MAIN_CHARGER_V, main_charger_v_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", main_charger_v_convert, main_charger_v_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_main_charger_v);
|
||||
|
||||
static int ab8500_gpadc_acc_detect1_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int acc_detect1_raw;
|
||||
int acc_detect1_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
acc_detect1_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT1,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
acc_detect1_convert = ab8500_gpadc_ad_to_voltage(gpadc, ACC_DETECT1,
|
||||
acc_detect1_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", acc_detect1_convert, acc_detect1_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_acc_detect1);
|
||||
|
||||
static int ab8500_gpadc_acc_detect2_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int acc_detect2_raw;
|
||||
int acc_detect2_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
acc_detect2_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT2,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
acc_detect2_convert = ab8500_gpadc_ad_to_voltage(gpadc,
|
||||
ACC_DETECT2, acc_detect2_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", acc_detect2_convert, acc_detect2_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_acc_detect2);
|
||||
|
||||
static int ab8500_gpadc_aux1_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int aux1_raw;
|
||||
int aux1_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
aux1_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX1,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
aux1_convert = ab8500_gpadc_ad_to_voltage(gpadc, ADC_AUX1,
|
||||
aux1_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", aux1_convert, aux1_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_aux1);
|
||||
|
||||
static int ab8500_gpadc_aux2_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int aux2_raw;
|
||||
int aux2_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
aux2_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX2,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
aux2_convert = ab8500_gpadc_ad_to_voltage(gpadc, ADC_AUX2,
|
||||
aux2_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", aux2_convert, aux2_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_aux2);
|
||||
|
||||
static int ab8500_gpadc_main_bat_v_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int main_bat_v_raw;
|
||||
int main_bat_v_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
main_bat_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_BAT_V,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
main_bat_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, MAIN_BAT_V,
|
||||
main_bat_v_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", main_bat_v_convert, main_bat_v_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_main_bat_v);
|
||||
|
||||
static int ab8500_gpadc_vbus_v_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int vbus_v_raw;
|
||||
int vbus_v_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
vbus_v_raw = ab8500_gpadc_read_raw(gpadc, VBUS_V,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
vbus_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, VBUS_V,
|
||||
vbus_v_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", vbus_v_convert, vbus_v_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_vbus_v);
|
||||
|
||||
static int ab8500_gpadc_main_charger_c_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int main_charger_c_raw;
|
||||
int main_charger_c_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
main_charger_c_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_C,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
main_charger_c_convert = ab8500_gpadc_ad_to_voltage(gpadc,
|
||||
MAIN_CHARGER_C, main_charger_c_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", main_charger_c_convert, main_charger_c_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_main_charger_c);
|
||||
|
||||
static int ab8500_gpadc_usb_charger_c_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int usb_charger_c_raw;
|
||||
int usb_charger_c_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
usb_charger_c_raw = ab8500_gpadc_read_raw(gpadc, USB_CHARGER_C,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
usb_charger_c_convert = ab8500_gpadc_ad_to_voltage(gpadc,
|
||||
USB_CHARGER_C, usb_charger_c_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", usb_charger_c_convert, usb_charger_c_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_usb_charger_c);
|
||||
|
||||
static int ab8500_gpadc_bk_bat_v_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int bk_bat_v_raw;
|
||||
int bk_bat_v_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
bk_bat_v_raw = ab8500_gpadc_read_raw(gpadc, BK_BAT_V,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
bk_bat_v_convert = ab8500_gpadc_ad_to_voltage(gpadc,
|
||||
BK_BAT_V, bk_bat_v_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", bk_bat_v_convert, bk_bat_v_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_bk_bat_v);
|
||||
|
||||
static int ab8500_gpadc_die_temp_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int die_temp_raw;
|
||||
int die_temp_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
die_temp_raw = ab8500_gpadc_read_raw(gpadc, DIE_TEMP,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
die_temp_convert = ab8500_gpadc_ad_to_voltage(gpadc, DIE_TEMP,
|
||||
die_temp_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", die_temp_convert, die_temp_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_die_temp);
|
||||
|
||||
static int ab8500_gpadc_usb_id_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int usb_id_raw;
|
||||
int usb_id_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
usb_id_raw = ab8500_gpadc_read_raw(gpadc, USB_ID,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
usb_id_convert = ab8500_gpadc_ad_to_voltage(gpadc, USB_ID,
|
||||
usb_id_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", usb_id_convert, usb_id_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_usb_id);
|
||||
|
||||
static int ab8540_gpadc_xtal_temp_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int xtal_temp_raw;
|
||||
int xtal_temp_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
xtal_temp_raw = ab8500_gpadc_read_raw(gpadc, XTAL_TEMP,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
xtal_temp_convert = ab8500_gpadc_ad_to_voltage(gpadc, XTAL_TEMP,
|
||||
xtal_temp_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", xtal_temp_convert, xtal_temp_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_xtal_temp);
|
||||
|
||||
static int ab8540_gpadc_vbat_true_meas_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int vbat_true_meas_raw;
|
||||
int vbat_true_meas_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
vbat_true_meas_raw = ab8500_gpadc_read_raw(gpadc, VBAT_TRUE_MEAS,
|
||||
avg_sample, trig_edge, trig_timer, conv_type);
|
||||
vbat_true_meas_convert =
|
||||
ab8500_gpadc_ad_to_voltage(gpadc, VBAT_TRUE_MEAS,
|
||||
vbat_true_meas_raw);
|
||||
|
||||
seq_printf(s, "%d,0x%X\n", vbat_true_meas_convert, vbat_true_meas_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_vbat_true_meas);
|
||||
|
||||
static int ab8540_gpadc_bat_ctrl_and_ibat_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int bat_ctrl_raw;
|
||||
int bat_ctrl_convert;
|
||||
int ibat_raw;
|
||||
int ibat_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
bat_ctrl_raw = ab8500_gpadc_double_read_raw(gpadc, BAT_CTRL_AND_IBAT,
|
||||
avg_sample, trig_edge, trig_timer, conv_type, &ibat_raw);
|
||||
|
||||
bat_ctrl_convert = ab8500_gpadc_ad_to_voltage(gpadc, BAT_CTRL,
|
||||
bat_ctrl_raw);
|
||||
ibat_convert = ab8500_gpadc_ad_to_voltage(gpadc, IBAT_VIRTUAL_CHANNEL,
|
||||
ibat_raw);
|
||||
|
||||
seq_printf(s,
|
||||
"%d,0x%X\n"
|
||||
"%d,0x%X\n",
|
||||
bat_ctrl_convert, bat_ctrl_raw,
|
||||
ibat_convert, ibat_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_bat_ctrl_and_ibat);
|
||||
|
||||
static int ab8540_gpadc_vbat_meas_and_ibat_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int vbat_meas_raw;
|
||||
int vbat_meas_convert;
|
||||
int ibat_raw;
|
||||
int ibat_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
vbat_meas_raw = ab8500_gpadc_double_read_raw(gpadc, VBAT_MEAS_AND_IBAT,
|
||||
avg_sample, trig_edge, trig_timer, conv_type, &ibat_raw);
|
||||
vbat_meas_convert = ab8500_gpadc_ad_to_voltage(gpadc, MAIN_BAT_V,
|
||||
vbat_meas_raw);
|
||||
ibat_convert = ab8500_gpadc_ad_to_voltage(gpadc, IBAT_VIRTUAL_CHANNEL,
|
||||
ibat_raw);
|
||||
|
||||
seq_printf(s,
|
||||
"%d,0x%X\n"
|
||||
"%d,0x%X\n",
|
||||
vbat_meas_convert, vbat_meas_raw,
|
||||
ibat_convert, ibat_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_vbat_meas_and_ibat);
|
||||
|
||||
static int ab8540_gpadc_vbat_true_meas_and_ibat_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int vbat_true_meas_raw;
|
||||
int vbat_true_meas_convert;
|
||||
int ibat_raw;
|
||||
int ibat_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
vbat_true_meas_raw = ab8500_gpadc_double_read_raw(gpadc,
|
||||
VBAT_TRUE_MEAS_AND_IBAT, avg_sample, trig_edge,
|
||||
trig_timer, conv_type, &ibat_raw);
|
||||
vbat_true_meas_convert = ab8500_gpadc_ad_to_voltage(gpadc,
|
||||
VBAT_TRUE_MEAS, vbat_true_meas_raw);
|
||||
ibat_convert = ab8500_gpadc_ad_to_voltage(gpadc, IBAT_VIRTUAL_CHANNEL,
|
||||
ibat_raw);
|
||||
|
||||
seq_printf(s,
|
||||
"%d,0x%X\n"
|
||||
"%d,0x%X\n",
|
||||
vbat_true_meas_convert, vbat_true_meas_raw,
|
||||
ibat_convert, ibat_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_vbat_true_meas_and_ibat);
|
||||
|
||||
static int ab8540_gpadc_bat_temp_and_ibat_show(struct seq_file *s, void *p)
|
||||
{
|
||||
int bat_temp_raw;
|
||||
int bat_temp_convert;
|
||||
int ibat_raw;
|
||||
int ibat_convert;
|
||||
struct ab8500_gpadc *gpadc;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
bat_temp_raw = ab8500_gpadc_double_read_raw(gpadc, BAT_TEMP_AND_IBAT,
|
||||
avg_sample, trig_edge, trig_timer, conv_type, &ibat_raw);
|
||||
bat_temp_convert = ab8500_gpadc_ad_to_voltage(gpadc, BTEMP_BALL,
|
||||
bat_temp_raw);
|
||||
ibat_convert = ab8500_gpadc_ad_to_voltage(gpadc, IBAT_VIRTUAL_CHANNEL,
|
||||
ibat_raw);
|
||||
|
||||
seq_printf(s,
|
||||
"%d,0x%X\n"
|
||||
"%d,0x%X\n",
|
||||
bat_temp_convert, bat_temp_raw,
|
||||
ibat_convert, ibat_raw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_bat_temp_and_ibat);
|
||||
|
||||
static int ab8540_gpadc_otp_calib_show(struct seq_file *s, void *p)
|
||||
{
|
||||
struct ab8500_gpadc *gpadc;
|
||||
u16 vmain_l, vmain_h, btemp_l, btemp_h;
|
||||
u16 vbat_l, vbat_h, ibat_l, ibat_h;
|
||||
|
||||
gpadc = ab8500_gpadc_get("ab8500-gpadc.0");
|
||||
ab8540_gpadc_get_otp(gpadc, &vmain_l, &vmain_h, &btemp_l, &btemp_h,
|
||||
&vbat_l, &vbat_h, &ibat_l, &ibat_h);
|
||||
seq_printf(s,
|
||||
"VMAIN_L:0x%X\n"
|
||||
"VMAIN_H:0x%X\n"
|
||||
"BTEMP_L:0x%X\n"
|
||||
"BTEMP_H:0x%X\n"
|
||||
"VBAT_L:0x%X\n"
|
||||
"VBAT_H:0x%X\n"
|
||||
"IBAT_L:0x%X\n"
|
||||
"IBAT_H:0x%X\n",
|
||||
vmain_l, vmain_h, btemp_l, btemp_h,
|
||||
vbat_l, vbat_h, ibat_l, ibat_h);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_otp_calib);
|
||||
|
||||
static int ab8500_gpadc_avg_sample_print(struct seq_file *s, void *p)
|
||||
{
|
||||
seq_printf(s, "%d\n", avg_sample);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ab8500_gpadc_avg_sample_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, ab8500_gpadc_avg_sample_print,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
static ssize_t ab8500_gpadc_avg_sample_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct device *dev = ((struct seq_file *)(file->private_data))->private;
|
||||
unsigned long user_avg_sample;
|
||||
int err;
|
||||
|
||||
err = kstrtoul_from_user(user_buf, count, 0, &user_avg_sample);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if ((user_avg_sample == SAMPLE_1) || (user_avg_sample == SAMPLE_4)
|
||||
|| (user_avg_sample == SAMPLE_8)
|
||||
|| (user_avg_sample == SAMPLE_16)) {
|
||||
avg_sample = (u8) user_avg_sample;
|
||||
} else {
|
||||
dev_err(dev,
|
||||
"debugfs err input: should be egal to 1, 4, 8 or 16\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations ab8500_gpadc_avg_sample_fops = {
|
||||
.open = ab8500_gpadc_avg_sample_open,
|
||||
.read = seq_read,
|
||||
.write = ab8500_gpadc_avg_sample_write,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int ab8500_gpadc_trig_edge_print(struct seq_file *s, void *p)
|
||||
{
|
||||
seq_printf(s, "%d\n", trig_edge);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ab8500_gpadc_trig_edge_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, ab8500_gpadc_trig_edge_print,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
static ssize_t ab8500_gpadc_trig_edge_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct device *dev = ((struct seq_file *)(file->private_data))->private;
|
||||
unsigned long user_trig_edge;
|
||||
int err;
|
||||
|
||||
err = kstrtoul_from_user(user_buf, count, 0, &user_trig_edge);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if ((user_trig_edge == RISING_EDGE)
|
||||
|| (user_trig_edge == FALLING_EDGE)) {
|
||||
trig_edge = (u8) user_trig_edge;
|
||||
} else {
|
||||
dev_err(dev, "Wrong input:\n"
|
||||
"Enter 0. Rising edge\n"
|
||||
"Enter 1. Falling edge\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations ab8500_gpadc_trig_edge_fops = {
|
||||
.open = ab8500_gpadc_trig_edge_open,
|
||||
.read = seq_read,
|
||||
.write = ab8500_gpadc_trig_edge_write,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int ab8500_gpadc_trig_timer_print(struct seq_file *s, void *p)
|
||||
{
|
||||
seq_printf(s, "%d\n", trig_timer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ab8500_gpadc_trig_timer_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, ab8500_gpadc_trig_timer_print,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
static ssize_t ab8500_gpadc_trig_timer_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct device *dev = ((struct seq_file *)(file->private_data))->private;
|
||||
unsigned long user_trig_timer;
|
||||
int err;
|
||||
|
||||
err = kstrtoul_from_user(user_buf, count, 0, &user_trig_timer);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (user_trig_timer & ~0xFF) {
|
||||
dev_err(dev,
|
||||
"debugfs error input: should be between 0 to 255\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
trig_timer = (u8) user_trig_timer;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations ab8500_gpadc_trig_timer_fops = {
|
||||
.open = ab8500_gpadc_trig_timer_open,
|
||||
.read = seq_read,
|
||||
.write = ab8500_gpadc_trig_timer_write,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int ab8500_gpadc_conv_type_print(struct seq_file *s, void *p)
|
||||
{
|
||||
seq_printf(s, "%d\n", conv_type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ab8500_gpadc_conv_type_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, ab8500_gpadc_conv_type_print,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
static ssize_t ab8500_gpadc_conv_type_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct device *dev = ((struct seq_file *)(file->private_data))->private;
|
||||
unsigned long user_conv_type;
|
||||
int err;
|
||||
|
||||
err = kstrtoul_from_user(user_buf, count, 0, &user_conv_type);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if ((user_conv_type == ADC_SW)
|
||||
|| (user_conv_type == ADC_HW)) {
|
||||
conv_type = (u8) user_conv_type;
|
||||
} else {
|
||||
dev_err(dev, "Wrong input:\n"
|
||||
"Enter 0. ADC SW conversion\n"
|
||||
"Enter 1. ADC HW conversion\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations ab8500_gpadc_conv_type_fops = {
|
||||
.open = ab8500_gpadc_conv_type_open,
|
||||
.read = seq_read,
|
||||
.write = ab8500_gpadc_conv_type_write,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
/*
|
||||
* return length of an ASCII numerical value, 0 is string is not a
|
||||
* numerical value.
|
||||
@ -2647,7 +2013,6 @@ static const struct file_operations ab8500_hwreg_fops = {
|
||||
static int ab8500_debug_probe(struct platform_device *plf)
|
||||
{
|
||||
struct dentry *ab8500_dir;
|
||||
struct dentry *ab8500_gpadc_dir;
|
||||
struct ab8500 *ab8500;
|
||||
struct resource *res;
|
||||
|
||||
@ -2689,9 +2054,6 @@ static int ab8500_debug_probe(struct platform_device *plf)
|
||||
|
||||
ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL);
|
||||
|
||||
ab8500_gpadc_dir = debugfs_create_dir(AB8500_ADC_NAME_STRING,
|
||||
ab8500_dir);
|
||||
|
||||
debugfs_create_file("all-bank-registers", S_IRUGO, ab8500_dir,
|
||||
&plf->dev, &ab8500_bank_registers_fops);
|
||||
debugfs_create_file("all-banks", S_IRUGO, ab8500_dir,
|
||||
@ -2727,83 +2089,6 @@ static int ab8500_debug_probe(struct platform_device *plf)
|
||||
&plf->dev, &ab8500_hwreg_fops);
|
||||
debugfs_create_file("all-modem-registers", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_dir, &plf->dev, &ab8500_modem_fops);
|
||||
debugfs_create_file("bat_ctrl", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_bat_ctrl_fops);
|
||||
debugfs_create_file("btemp_ball", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_btemp_ball_fops);
|
||||
debugfs_create_file("main_charger_v", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_main_charger_v_fops);
|
||||
debugfs_create_file("acc_detect1", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_acc_detect1_fops);
|
||||
debugfs_create_file("acc_detect2", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_acc_detect2_fops);
|
||||
debugfs_create_file("adc_aux1", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_aux1_fops);
|
||||
debugfs_create_file("adc_aux2", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_aux2_fops);
|
||||
debugfs_create_file("main_bat_v", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_main_bat_v_fops);
|
||||
debugfs_create_file("vbus_v", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_vbus_v_fops);
|
||||
debugfs_create_file("main_charger_c", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_main_charger_c_fops);
|
||||
debugfs_create_file("usb_charger_c", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_usb_charger_c_fops);
|
||||
debugfs_create_file("bk_bat_v", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_bk_bat_v_fops);
|
||||
debugfs_create_file("die_temp", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_die_temp_fops);
|
||||
debugfs_create_file("usb_id", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_usb_id_fops);
|
||||
if (is_ab8540(ab8500)) {
|
||||
debugfs_create_file("xtal_temp", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8540_gpadc_xtal_temp_fops);
|
||||
debugfs_create_file("vbattruemeas", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8540_gpadc_vbat_true_meas_fops);
|
||||
debugfs_create_file("batctrl_and_ibat", (S_IRUGO | S_IWUGO),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8540_gpadc_bat_ctrl_and_ibat_fops);
|
||||
debugfs_create_file("vbatmeas_and_ibat", (S_IRUGO | S_IWUGO),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8540_gpadc_vbat_meas_and_ibat_fops);
|
||||
debugfs_create_file("vbattruemeas_and_ibat", (S_IRUGO | S_IWUGO),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8540_gpadc_vbat_true_meas_and_ibat_fops);
|
||||
debugfs_create_file("battemp_and_ibat", (S_IRUGO | S_IWUGO),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8540_gpadc_bat_temp_and_ibat_fops);
|
||||
debugfs_create_file("otp_calib", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8540_gpadc_otp_calib_fops);
|
||||
}
|
||||
debugfs_create_file("avg_sample", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_avg_sample_fops);
|
||||
debugfs_create_file("trig_edge", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_trig_edge_fops);
|
||||
debugfs_create_file("trig_timer", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_trig_timer_fops);
|
||||
debugfs_create_file("conv_type", (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
ab8500_gpadc_dir, &plf->dev,
|
||||
&ab8500_gpadc_conv_type_fops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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 @@ exit:
|
||||
*/
|
||||
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;
|
||||
|
@ -354,13 +354,13 @@ static int abx500_chargalg_check_charger_enable(struct abx500_chargalg *di)
|
||||
|
||||
if (di->chg_info.charger_type & USB_CHG) {
|
||||
return di->usb_chg->ops.check_enable(di->usb_chg,
|
||||
di->bm->bat_type[di->bm->batt_id].normal_vol_lvl,
|
||||
di->bm->bat_type[di->bm->batt_id].normal_cur_lvl);
|
||||
di->bm->bat_type[di->bm->batt_id].normal_vol_lvl,
|
||||
di->bm->bat_type[di->bm->batt_id].normal_cur_lvl);
|
||||
} else if ((di->chg_info.charger_type & AC_CHG) &&
|
||||
!(di->ac_chg->external)) {
|
||||
return di->ac_chg->ops.check_enable(di->ac_chg,
|
||||
di->bm->bat_type[di->bm->batt_id].normal_vol_lvl,
|
||||
di->bm->bat_type[di->bm->batt_id].normal_cur_lvl);
|
||||
di->bm->bat_type[di->bm->batt_id].normal_vol_lvl,
|
||||
di->bm->bat_type[di->bm->batt_id].normal_cur_lvl);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -33,8 +33,6 @@
|
||||
#include <linux/iio/types.h>
|
||||
#include <linux/mfd/motorola-cpcap.h>
|
||||
|
||||
#include <asm/div64.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"
|
||||
@ -52,6 +50,26 @@
|
||||
#define CPCAP_REG_BPEOL_BIT_BATTDETEN BIT(1) /* Enable battery detect */
|
||||
#define CPCAP_REG_BPEOL_BIT_EOLSEL BIT(0) /* BPDET = 0, EOL = 1 */
|
||||
|
||||
/*
|
||||
* 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 BIT(4) /* Update rate */
|
||||
#define CPCAP_REG_CCC1_ACTIVE_MODE0 BIT(3) /* Update rate */
|
||||
#define CPCAP_REG_CCC1_AUTOCLEAR BIT(2) /* Resets sample registers */
|
||||
#define CPCAP_REG_CCC1_CAL_EN BIT(1) /* Clears after write in 1s */
|
||||
#define CPCAP_REG_CCC1_PAUSE BIT(0) /* Stop counters, allow write */
|
||||
#define CPCAP_REG_CCC1_RESET_MASK (CPCAP_REG_CCC1_AUTOCLEAR | \
|
||||
CPCAP_REG_CCC1_CAL_EN)
|
||||
|
||||
#define CPCAP_REG_CCCC2_RATE1 BIT(5)
|
||||
#define CPCAP_REG_CCCC2_RATE0 BIT(4)
|
||||
#define CPCAP_REG_CCCC2_ENABLE BIT(3)
|
||||
|
||||
#define CPCAP_BATTERY_CC_SAMPLE_PERIOD_MS 250
|
||||
|
||||
enum {
|
||||
@ -64,6 +82,7 @@ enum {
|
||||
|
||||
enum cpcap_battery_irq_action {
|
||||
CPCAP_BATTERY_IRQ_ACTION_NONE,
|
||||
CPCAP_BATTERY_IRQ_ACTION_CC_CAL_DONE,
|
||||
CPCAP_BATTERY_IRQ_ACTION_BATTERY_LOW,
|
||||
CPCAP_BATTERY_IRQ_ACTION_POWEROFF,
|
||||
};
|
||||
@ -76,15 +95,16 @@ struct cpcap_interrupt_desc {
|
||||
};
|
||||
|
||||
struct cpcap_battery_config {
|
||||
int ccm;
|
||||
int cd_factor;
|
||||
struct power_supply_info info;
|
||||
struct power_supply_battery_info bat;
|
||||
};
|
||||
|
||||
struct cpcap_coulomb_counter_data {
|
||||
s32 sample; /* 24 or 32 bits */
|
||||
s32 accumulator;
|
||||
s16 offset; /* 9 bits */
|
||||
s16 integrator; /* 13 or 16 bits */
|
||||
};
|
||||
|
||||
enum cpcap_battery_state {
|
||||
@ -110,6 +130,7 @@ struct cpcap_battery_ddata {
|
||||
struct power_supply *psy;
|
||||
struct cpcap_battery_config config;
|
||||
struct cpcap_battery_state_data state[CPCAP_BATTERY_STATE_NR];
|
||||
u32 cc_lsb; /* μAms per LSB */
|
||||
atomic_t active;
|
||||
int status;
|
||||
u16 vendor;
|
||||
@ -217,41 +238,17 @@ static int cpcap_battery_cc_raw_div(struct cpcap_battery_ddata *ddata,
|
||||
s16 offset, u32 divider)
|
||||
{
|
||||
s64 acc;
|
||||
u64 tmp;
|
||||
int avg_current;
|
||||
u32 cc_lsb;
|
||||
|
||||
if (!divider)
|
||||
return 0;
|
||||
|
||||
switch (ddata->vendor) {
|
||||
case CPCAP_VENDOR_ST:
|
||||
cc_lsb = 95374; /* μAms per LSB */
|
||||
break;
|
||||
case CPCAP_VENDOR_TI:
|
||||
cc_lsb = 91501; /* μAms per LSB */
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
acc = accumulator;
|
||||
acc = acc - ((s64)sample * offset);
|
||||
cc_lsb = (cc_lsb * ddata->config.cd_factor) / 1000;
|
||||
acc -= (s64)sample * offset;
|
||||
acc *= ddata->cc_lsb;
|
||||
acc *= -1;
|
||||
acc = div_s64(acc, divider);
|
||||
|
||||
if (acc >= 0)
|
||||
tmp = acc;
|
||||
else
|
||||
tmp = acc * -1;
|
||||
|
||||
tmp = tmp * cc_lsb;
|
||||
do_div(tmp, divider);
|
||||
avg_current = tmp;
|
||||
|
||||
if (acc >= 0)
|
||||
return -avg_current;
|
||||
else
|
||||
return avg_current;
|
||||
return acc;
|
||||
}
|
||||
|
||||
/* 3600000μAms = 1μAh */
|
||||
@ -293,12 +290,13 @@ static int
|
||||
cpcap_battery_read_accumulated(struct cpcap_battery_ddata *ddata,
|
||||
struct cpcap_coulomb_counter_data *ccd)
|
||||
{
|
||||
u16 buf[7]; /* CPCAP_REG_CC1 to CCI */
|
||||
u16 buf[7]; /* CPCAP_REG_CCS1 to CCI */
|
||||
int error;
|
||||
|
||||
ccd->sample = 0;
|
||||
ccd->accumulator = 0;
|
||||
ccd->offset = 0;
|
||||
ccd->integrator = 0;
|
||||
|
||||
/* Read coulomb counter register range */
|
||||
error = regmap_bulk_read(ddata->reg, CPCAP_REG_CCS1,
|
||||
@ -323,6 +321,12 @@ cpcap_battery_read_accumulated(struct cpcap_battery_ddata *ddata,
|
||||
ccd->offset = buf[4];
|
||||
ccd->offset = sign_extend32(ccd->offset, 9);
|
||||
|
||||
/* Integrator register CPCAP_REG_CCI */
|
||||
if (ddata->vendor == CPCAP_VENDOR_TI)
|
||||
ccd->integrator = sign_extend32(buf[6], 13);
|
||||
else
|
||||
ccd->integrator = (s16)buf[6];
|
||||
|
||||
return cpcap_battery_cc_to_uah(ddata,
|
||||
ccd->sample,
|
||||
ccd->accumulator,
|
||||
@ -336,31 +340,28 @@ cpcap_battery_read_accumulated(struct cpcap_battery_ddata *ddata,
|
||||
static int cpcap_battery_cc_get_avg_current(struct cpcap_battery_ddata *ddata)
|
||||
{
|
||||
int value, acc, error;
|
||||
s32 sample = 1;
|
||||
s32 sample;
|
||||
s16 offset;
|
||||
|
||||
if (ddata->vendor == CPCAP_VENDOR_ST)
|
||||
sample = 4;
|
||||
|
||||
/* Coulomb counter integrator */
|
||||
error = regmap_read(ddata->reg, CPCAP_REG_CCI, &value);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if ((ddata->vendor == CPCAP_VENDOR_TI) && (value > 0x2000))
|
||||
value = value | 0xc000;
|
||||
if (ddata->vendor == CPCAP_VENDOR_TI) {
|
||||
acc = sign_extend32(value, 13);
|
||||
sample = 1;
|
||||
} else {
|
||||
acc = (s16)value;
|
||||
sample = 4;
|
||||
}
|
||||
|
||||
acc = (s16)value;
|
||||
|
||||
/* Coulomb counter sample time */
|
||||
/* Coulomb counter calibration offset */
|
||||
error = regmap_read(ddata->reg, CPCAP_REG_CCM, &value);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (value < 0x200)
|
||||
offset = value;
|
||||
else
|
||||
offset = value | 0xfc00;
|
||||
offset = sign_extend32(value, 9);
|
||||
|
||||
return cpcap_battery_cc_to_ua(ddata, sample, acc, offset);
|
||||
}
|
||||
@ -369,8 +370,8 @@ static bool cpcap_battery_full(struct cpcap_battery_ddata *ddata)
|
||||
{
|
||||
struct cpcap_battery_state_data *state = cpcap_battery_latest(ddata);
|
||||
|
||||
/* Basically anything that measures above 4347000 is full */
|
||||
if (state->voltage >= (ddata->config.info.voltage_max_design - 4000))
|
||||
if (state->voltage >=
|
||||
(ddata->config.bat.constant_charge_voltage_max_uv - 18000))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -417,6 +418,7 @@ static enum power_supply_property cpcap_battery_props[] = {
|
||||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
|
||||
POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
|
||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
|
||||
POWER_SUPPLY_PROP_CURRENT_AVG,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW,
|
||||
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
|
||||
@ -475,6 +477,9 @@ static int cpcap_battery_get_property(struct power_supply *psy,
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
|
||||
val->intval = ddata->config.info.voltage_min_design;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
|
||||
val->intval = ddata->config.bat.constant_charge_voltage_max_uv;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CURRENT_AVG:
|
||||
sample = latest->cc.sample - previous->cc.sample;
|
||||
if (!sample) {
|
||||
@ -540,6 +545,69 @@ static int cpcap_battery_get_property(struct power_supply *psy,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cpcap_battery_update_charger(struct cpcap_battery_ddata *ddata,
|
||||
int const_charge_voltage)
|
||||
{
|
||||
union power_supply_propval prop;
|
||||
union power_supply_propval val;
|
||||
struct power_supply *charger;
|
||||
int error;
|
||||
|
||||
charger = power_supply_get_by_name("usb");
|
||||
if (!charger)
|
||||
return -ENODEV;
|
||||
|
||||
error = power_supply_get_property(charger,
|
||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
|
||||
&prop);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
/* Allow charger const voltage lower than battery const voltage */
|
||||
if (const_charge_voltage > prop.intval)
|
||||
return 0;
|
||||
|
||||
val.intval = const_charge_voltage;
|
||||
|
||||
return power_supply_set_property(charger,
|
||||
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
|
||||
&val);
|
||||
}
|
||||
|
||||
static int cpcap_battery_set_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
const union power_supply_propval *val)
|
||||
{
|
||||
struct cpcap_battery_ddata *ddata = power_supply_get_drvdata(psy);
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
|
||||
if (val->intval < ddata->config.info.voltage_min_design)
|
||||
return -EINVAL;
|
||||
if (val->intval > ddata->config.info.voltage_max_design)
|
||||
return -EINVAL;
|
||||
|
||||
ddata->config.bat.constant_charge_voltage_max_uv = val->intval;
|
||||
|
||||
return cpcap_battery_update_charger(ddata, val->intval);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cpcap_battery_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 irqreturn_t cpcap_battery_irq_thread(int irq, void *data)
|
||||
{
|
||||
struct cpcap_battery_ddata *ddata = data;
|
||||
@ -560,14 +628,19 @@ static irqreturn_t cpcap_battery_irq_thread(int irq, void *data)
|
||||
latest = cpcap_battery_latest(ddata);
|
||||
|
||||
switch (d->action) {
|
||||
case CPCAP_BATTERY_IRQ_ACTION_CC_CAL_DONE:
|
||||
dev_info(ddata->dev, "Coulomb counter calibration done\n");
|
||||
break;
|
||||
case CPCAP_BATTERY_IRQ_ACTION_BATTERY_LOW:
|
||||
if (latest->current_ua >= 0)
|
||||
dev_warn(ddata->dev, "Battery low at 3.3V!\n");
|
||||
dev_warn(ddata->dev, "Battery low at %imV!\n",
|
||||
latest->voltage / 1000);
|
||||
break;
|
||||
case CPCAP_BATTERY_IRQ_ACTION_POWEROFF:
|
||||
if (latest->current_ua >= 0) {
|
||||
if (latest->current_ua >= 0 && latest->voltage <= 3200000) {
|
||||
dev_emerg(ddata->dev,
|
||||
"Battery empty at 3.1V, powering off\n");
|
||||
"Battery empty at %imV, powering off\n",
|
||||
latest->voltage / 1000);
|
||||
orderly_poweroff(true);
|
||||
}
|
||||
break;
|
||||
@ -609,7 +682,9 @@ static int cpcap_battery_init_irq(struct platform_device *pdev,
|
||||
d->name = name;
|
||||
d->irq = irq;
|
||||
|
||||
if (!strncmp(name, "lowbph", 6))
|
||||
if (!strncmp(name, "cccal", 5))
|
||||
d->action = CPCAP_BATTERY_IRQ_ACTION_CC_CAL_DONE;
|
||||
else if (!strncmp(name, "lowbph", 6))
|
||||
d->action = CPCAP_BATTERY_IRQ_ACTION_BATTERY_LOW;
|
||||
else if (!strncmp(name, "lowbpl", 6))
|
||||
d->action = CPCAP_BATTERY_IRQ_ACTION_POWEROFF;
|
||||
@ -635,6 +710,9 @@ static int cpcap_battery_init_interrupts(struct platform_device *pdev,
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Enable calibration interrupt if already available in dts */
|
||||
cpcap_battery_init_irq(pdev, ddata, "cccal");
|
||||
|
||||
/* Enable low battery interrupts for 3.3V high and 3.1V low */
|
||||
error = regmap_update_bits(ddata->reg, CPCAP_REG_BPEOL,
|
||||
0xffff,
|
||||
@ -676,6 +754,60 @@ out_err:
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Calibrate coulomb counter */
|
||||
static int cpcap_battery_calibrate(struct cpcap_battery_ddata *ddata)
|
||||
{
|
||||
int error, ccc1, value;
|
||||
unsigned long timeout;
|
||||
|
||||
error = regmap_read(ddata->reg, CPCAP_REG_CCC1, &ccc1);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(6000);
|
||||
|
||||
/* Start calibration */
|
||||
error = regmap_update_bits(ddata->reg, CPCAP_REG_CCC1,
|
||||
0xffff,
|
||||
CPCAP_REG_CCC1_CAL_EN);
|
||||
if (error)
|
||||
goto restore;
|
||||
|
||||
while (time_before(jiffies, timeout)) {
|
||||
error = regmap_read(ddata->reg, CPCAP_REG_CCC1, &value);
|
||||
if (error)
|
||||
goto restore;
|
||||
|
||||
if (!(value & CPCAP_REG_CCC1_CAL_EN))
|
||||
break;
|
||||
|
||||
error = regmap_read(ddata->reg, CPCAP_REG_CCM, &value);
|
||||
if (error)
|
||||
goto restore;
|
||||
|
||||
msleep(300);
|
||||
}
|
||||
|
||||
/* Read calibration offset from CCM */
|
||||
error = regmap_read(ddata->reg, CPCAP_REG_CCM, &value);
|
||||
if (error)
|
||||
goto restore;
|
||||
|
||||
dev_info(ddata->dev, "calibration done: 0x%04x\n", value);
|
||||
|
||||
restore:
|
||||
if (error)
|
||||
dev_err(ddata->dev, "%s: error %i\n", __func__, error);
|
||||
|
||||
error = regmap_update_bits(ddata->reg, CPCAP_REG_CCC1,
|
||||
0xffff, ccc1);
|
||||
if (error)
|
||||
dev_err(ddata->dev, "%s: restore error %i\n",
|
||||
__func__, error);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Based on the values from Motorola mapphone Linux kernel. In the
|
||||
* the Motorola mapphone Linux kernel tree the value for pm_cd_factor
|
||||
@ -687,12 +819,12 @@ out_err:
|
||||
* at 3078000. The device will die around 2743000.
|
||||
*/
|
||||
static const struct cpcap_battery_config cpcap_battery_default_data = {
|
||||
.ccm = 0x3ff,
|
||||
.cd_factor = 0x3cc,
|
||||
.info.technology = POWER_SUPPLY_TECHNOLOGY_LION,
|
||||
.info.voltage_max_design = 4351000,
|
||||
.info.voltage_min_design = 3100000,
|
||||
.info.charge_full_design = 1740000,
|
||||
.bat.constant_charge_voltage_max_uv = 4200000,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
@ -741,12 +873,19 @@ static int cpcap_battery_probe(struct platform_device *pdev)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
switch (ddata->vendor) {
|
||||
case CPCAP_VENDOR_ST:
|
||||
ddata->cc_lsb = 95374; /* μAms per LSB */
|
||||
break;
|
||||
case CPCAP_VENDOR_TI:
|
||||
ddata->cc_lsb = 91501; /* μAms per LSB */
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
ddata->cc_lsb = (ddata->cc_lsb * ddata->config.cd_factor) / 1000;
|
||||
|
||||
error = regmap_update_bits(ddata->reg, CPCAP_REG_CCM,
|
||||
0xffff, ddata->config.ccm);
|
||||
if (error)
|
||||
return error;
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
|
||||
error = cpcap_battery_init_interrupts(pdev, ddata);
|
||||
if (error)
|
||||
@ -760,11 +899,13 @@ static int cpcap_battery_probe(struct platform_device *pdev)
|
||||
if (!psy_desc)
|
||||
return -ENOMEM;
|
||||
|
||||
psy_desc->name = "battery",
|
||||
psy_desc->type = POWER_SUPPLY_TYPE_BATTERY,
|
||||
psy_desc->properties = cpcap_battery_props,
|
||||
psy_desc->num_properties = ARRAY_SIZE(cpcap_battery_props),
|
||||
psy_desc->get_property = cpcap_battery_get_property,
|
||||
psy_desc->name = "battery";
|
||||
psy_desc->type = POWER_SUPPLY_TYPE_BATTERY;
|
||||
psy_desc->properties = cpcap_battery_props;
|
||||
psy_desc->num_properties = ARRAY_SIZE(cpcap_battery_props);
|
||||
psy_desc->get_property = cpcap_battery_get_property;
|
||||
psy_desc->set_property = cpcap_battery_set_property;
|
||||
psy_desc->property_is_writeable = cpcap_battery_property_is_writeable;
|
||||
|
||||
psy_cfg.of_node = pdev->dev.of_node;
|
||||
psy_cfg.drv_data = ddata;
|
||||
@ -779,6 +920,10 @@ static int cpcap_battery_probe(struct platform_device *pdev)
|
||||
|
||||
atomic_set(&ddata->active, 1);
|
||||
|
||||
error = cpcap_battery_calibrate(ddata);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
@ -1,75 +0,0 @@
|
||||
/* 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 */
|
Loading…
Reference in New Issue
Block a user