summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/mfd/ab8500.txt119
-rw-r--r--Documentation/devicetree/bindings/power/supply/cpcap-charger.txt9
-rw-r--r--MAINTAINERS1
-rw-r--r--arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi6
-rw-r--r--drivers/hwmon/Kconfig3
-rw-r--r--drivers/hwmon/ab8500.c65
-rw-r--r--drivers/iio/adc/Kconfig10
-rw-r--r--drivers/iio/adc/Makefile1
-rw-r--r--drivers/iio/adc/ab8500-gpadc.c1218
-rw-r--r--drivers/mfd/Kconfig7
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/ab8500-debugfs.c715
-rw-r--r--drivers/mfd/ab8500-gpadc.c1075
-rw-r--r--drivers/power/reset/at91-reset.c6
-rw-r--r--drivers/power/reset/at91-sama5d2_shdwc.c8
-rw-r--r--drivers/power/supply/Kconfig2
-rw-r--r--drivers/power/supply/ab8500_btemp.c50
-rw-r--r--drivers/power/supply/ab8500_charger.c83
-rw-r--r--drivers/power/supply/ab8500_fg.c49
-rw-r--r--drivers/power/supply/abx500_chargalg.c8
-rw-r--r--drivers/power/supply/axp20x_usb_power.c8
-rw-r--r--drivers/power/supply/bd70528-charger.c1
-rw-r--r--drivers/power/supply/cpcap-battery.c271
-rw-r--r--drivers/power/supply/cpcap-charger.c222
-rw-r--r--drivers/power/supply/test_power.c61
-rw-r--r--include/linux/mfd/abx500/ab8500-gpadc.h75
26 files changed, 2044 insertions, 2030 deletions
diff --git a/Documentation/devicetree/bindings/mfd/ab8500.txt b/Documentation/devicetree/bindings/mfd/ab8500.txt
index cd9e90c5d171..b6bc30d7777e 100644
--- a/Documentation/devicetree/bindings/mfd/ab8500.txt
+++ b/Documentation/devicetree/bindings/mfd/ab8500.txt
@@ -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
diff --git a/Documentation/devicetree/bindings/power/supply/cpcap-charger.txt b/Documentation/devicetree/bindings/power/supply/cpcap-charger.txt
index 80bd873c3b1d..6048f636783f 100644
--- a/Documentation/devicetree/bindings/power/supply/cpcap-charger.txt
+++ b/Documentation/devicetree/bindings/power/supply/cpcap-charger.txt
@@ -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
diff --git a/MAINTAINERS b/MAINTAINERS
index 08bbf9649a1b..ee326c051612 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -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*
diff --git a/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi b/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
index d1eae47b83f6..08bae935605c 100644
--- a/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
+++ b/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
@@ -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
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 13a6b4afb4b3..5308c59d7001 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -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
diff --git a/drivers/hwmon/ab8500.c b/drivers/hwmon/ab8500.c
index 207f77f85a40..53f3379d799d 100644
--- a/drivers/hwmon/ab8500.c
+++ b/drivers/hwmon/ab8500.c
@@ -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;
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index f0af3a42f53c..0b21dd405dd5 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -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
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index ef9cc485fb67..fc1b6ebb0cde 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -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
diff --git a/drivers/iio/adc/ab8500-gpadc.c b/drivers/iio/adc/ab8500-gpadc.c
new file mode 100644
index 000000000000..fd5b18d7f0c2
--- /dev/null
+++ b/drivers/iio/adc/ab8500-gpadc.c
@@ -0,0 +1,1218 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Arun R Murthy <arun.murthy@stericsson.com>
+ * Author: Daniel Willerud <daniel.willerud@stericsson.com>
+ * Author: Johan Palsson <johan.palsson@stericsson.com>
+ * Author: M'boumba Cedric Madianga
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * AB8500 General Purpose ADC driver. The AB8500 uses reference voltages:
+ * VinVADC, and VADC relative to GND to do its job. It monitors main and backup
+ * battery voltages, AC (mains) voltage, USB cable voltage, as well as voltages
+ * representing the temperature of the chip die and battery, accessory
+ * detection by resistance measurements using relative voltages and GSM burst
+ * information.
+ *
+ * Some of the voltages are measured on external pins on the IC, such as
+ * battery temperature or "ADC aux" 1 and 2. Other voltages are internal rails
+ * from other parts of the ASIC such as main charger voltage, main and battery
+ * backup voltage or USB VBUS voltage. For this reason drivers for other
+ * parts of the system are required to obtain handles to the ADC to do work
+ * for them and the IIO driver provides arbitration among these consumers.
+ */
+#include <linux/init.h>
+#include <linux/bits.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/regulator/consumer.h>
+#include <linux/random.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
+
+/* GPADC register offsets and bit definitions */
+
+#define AB8500_GPADC_CTRL1_REG 0x00
+/* GPADC control register 1 bits */
+#define AB8500_GPADC_CTRL1_DISABLE 0x00
+#define AB8500_GPADC_CTRL1_ENABLE BIT(0)
+#define AB8500_GPADC_CTRL1_TRIG_ENA BIT(1)
+#define AB8500_GPADC_CTRL1_START_SW_CONV BIT(2)
+#define AB8500_GPADC_CTRL1_BTEMP_PULL_UP BIT(3)
+/* 0 = use rising edge, 1 = use falling edge */
+#define AB8500_GPADC_CTRL1_TRIG_EDGE BIT(4)
+/* 0 = use VTVOUT, 1 = use VRTC as pull-up supply for battery temp NTC */
+#define AB8500_GPADC_CTRL1_PUPSUPSEL BIT(5)
+#define AB8500_GPADC_CTRL1_BUF_ENA BIT(6)
+#define AB8500_GPADC_CTRL1_ICHAR_ENA BIT(7)
+
+#define AB8500_GPADC_CTRL2_REG 0x01
+#define AB8500_GPADC_CTRL3_REG 0x02
+/*
+ * GPADC control register 2 and 3 bits
+ * the bit layout is the same for SW and HW conversion set-up
+ */
+#define AB8500_GPADC_CTRL2_AVG_1 0x00
+#define AB8500_GPADC_CTRL2_AVG_4 BIT(5)
+#define AB8500_GPADC_CTRL2_AVG_8 BIT(6)
+#define AB8500_GPADC_CTRL2_AVG_16 (BIT(5) | BIT(6))
+
+enum ab8500_gpadc_channel {
+ AB8500_GPADC_CHAN_UNUSED = 0x00,
+ AB8500_GPADC_CHAN_BAT_CTRL = 0x01,
+ AB8500_GPADC_CHAN_BAT_TEMP = 0x02,
+ /* This is not used on AB8505 */
+ AB8500_GPADC_CHAN_MAIN_CHARGER = 0x03,
+ AB8500_GPADC_CHAN_ACC_DET_1 = 0x04,
+ AB8500_GPADC_CHAN_ACC_DET_2 = 0x05,
+ AB8500_GPADC_CHAN_ADC_AUX_1 = 0x06,
+ AB8500_GPADC_CHAN_ADC_AUX_2 = 0x07,
+ AB8500_GPADC_CHAN_VBAT_A = 0x08,
+ AB8500_GPADC_CHAN_VBUS = 0x09,
+ AB8500_GPADC_CHAN_MAIN_CHARGER_CURRENT = 0x0a,
+ AB8500_GPADC_CHAN_USB_CHARGER_CURRENT = 0x0b,
+ AB8500_GPADC_CHAN_BACKUP_BAT = 0x0c,
+ /* Only on AB8505 */
+ AB8505_GPADC_CHAN_DIE_TEMP = 0x0d,
+ AB8500_GPADC_CHAN_ID = 0x0e,
+ AB8500_GPADC_CHAN_INTERNAL_TEST_1 = 0x0f,
+ AB8500_GPADC_CHAN_INTERNAL_TEST_2 = 0x10,
+ AB8500_GPADC_CHAN_INTERNAL_TEST_3 = 0x11,
+ /* FIXME: Applicable to all ASIC variants? */
+ AB8500_GPADC_CHAN_XTAL_TEMP = 0x12,
+ AB8500_GPADC_CHAN_VBAT_TRUE_MEAS = 0x13,
+ /* FIXME: Doesn't seem to work with pure AB8500 */
+ AB8500_GPADC_CHAN_BAT_CTRL_AND_IBAT = 0x1c,
+ AB8500_GPADC_CHAN_VBAT_MEAS_AND_IBAT = 0x1d,
+ AB8500_GPADC_CHAN_VBAT_TRUE_MEAS_AND_IBAT = 0x1e,
+ AB8500_GPADC_CHAN_BAT_TEMP_AND_IBAT = 0x1f,
+ /*
+ * Virtual channel used only for ibat conversion to ampere.
+ * Battery current conversion (ibat) cannot be requested as a
+ * single conversion but it is always requested in combination
+ * with other input requests.
+ */
+ AB8500_GPADC_CHAN_IBAT_VIRTUAL = 0xFF,
+};
+
+#define AB8500_GPADC_AUTO_TIMER_REG 0x03
+
+#define AB8500_GPADC_STAT_REG 0x04
+#define AB8500_GPADC_STAT_BUSY BIT(0)
+
+#define AB8500_GPADC_MANDATAL_REG 0x05
+#define AB8500_GPADC_MANDATAH_REG 0x06
+#define AB8500_GPADC_AUTODATAL_REG 0x07
+#define AB8500_GPADC_AUTODATAH_REG 0x08
+#define AB8500_GPADC_MUX_CTRL_REG 0x09
+#define AB8540_GPADC_MANDATA2L_REG 0x09
+#define AB8540_GPADC_MANDATA2H_REG 0x0A
+#define AB8540_GPADC_APEAAX_REG 0x10
+#define AB8540_GPADC_APEAAT_REG 0x11
+#define AB8540_GPADC_APEAAM_REG 0x12
+#define AB8540_GPADC_APEAAH_REG 0x13
+#define AB8540_GPADC_APEAAL_REG 0x14
+
+/*
+ * OTP register offsets
+ * Bank : 0x15
+ */
+#define AB8500_GPADC_CAL_1 0x0F
+#define AB8500_GPADC_CAL_2 0x10
+#define AB8500_GPADC_CAL_3 0x11
+#define AB8500_GPADC_CAL_4 0x12
+#define AB8500_GPADC_CAL_5 0x13
+#define AB8500_GPADC_CAL_6 0x14
+#define AB8500_GPADC_CAL_7 0x15
+/* New calibration for 8540 */
+#define AB8540_GPADC_OTP4_REG_7 0x38
+#define AB8540_GPADC_OTP4_REG_6 0x39
+#define AB8540_GPADC_OTP4_REG_5 0x3A
+
+#define AB8540_GPADC_DIS_ZERO 0x00
+#define AB8540_GPADC_EN_VBIAS_XTAL_TEMP 0x02
+
+/* GPADC constants from AB8500 spec, UM0836 */
+#define AB8500_ADC_RESOLUTION 1024
+#define AB8500_ADC_CH_BTEMP_MIN 0
+#define AB8500_ADC_CH_BTEMP_MAX 1350
+#define AB8500_ADC_CH_DIETEMP_MIN 0
+#define AB8500_ADC_CH_DIETEMP_MAX 1350
+#define AB8500_ADC_CH_CHG_V_MIN 0
+#define AB8500_ADC_CH_CHG_V_MAX 20030
+#define AB8500_ADC_CH_ACCDET2_MIN 0
+#define AB8500_ADC_CH_ACCDET2_MAX 2500
+#define AB8500_ADC_CH_VBAT_MIN 2300
+#define AB8500_ADC_CH_VBAT_MAX 4800
+#define AB8500_ADC_CH_CHG_I_MIN 0
+#define AB8500_ADC_CH_CHG_I_MAX 1500
+#define AB8500_ADC_CH_BKBAT_MIN 0
+#define AB8500_ADC_CH_BKBAT_MAX 3200
+
+/* GPADC constants from AB8540 spec */
+#define AB8500_ADC_CH_IBAT_MIN (-6000) /* mA range measured by ADC for ibat */
+#define AB8500_ADC_CH_IBAT_MAX 6000
+#define AB8500_ADC_CH_IBAT_MIN_V (-60) /* mV range measured by ADC for ibat */
+#define AB8500_ADC_CH_IBAT_MAX_V 60
+#define AB8500_GPADC_IBAT_VDROP_L (-56) /* mV */
+#define AB8500_GPADC_IBAT_VDROP_H 56
+
+/* This is used to not lose precision when dividing to get gain and offset */
+#define AB8500_GPADC_CALIB_SCALE 1000
+/*
+ * Number of bits shift used to not lose precision
+ * when dividing to get ibat gain.
+ */
+#define AB8500_GPADC_CALIB_SHIFT_IBAT 20
+
+/* Time in ms before disabling regulator */
+#define AB8500_GPADC_AUTOSUSPEND_DELAY 1
+
+#define AB8500_GPADC_CONVERSION_TIME 500 /* ms */
+
+enum ab8500_cal_channels {
+ AB8500_CAL_VMAIN = 0,
+ AB8500_CAL_BTEMP,
+ AB8500_CAL_VBAT,
+ AB8500_CAL_IBAT,
+ AB8500_CAL_NR,
+};
+
+/**
+ * struct ab8500_adc_cal_data - Table for storing gain and offset for the
+ * calibrated ADC channels
+ * @gain: Gain of the ADC channel
+ * @offset: Offset of the ADC channel
+ * @otp_calib_hi: Calibration from OTP
+ * @otp_calib_lo: Calibration from OTP
+ */
+struct ab8500_adc_cal_data {
+ s64 gain;
+ s64 offset;
+ u16 otp_calib_hi;
+ u16 otp_calib_lo;
+};
+
+/**
+ * struct ab8500_gpadc_chan_info - per-channel GPADC info
+ * @name: name of the channel
+ * @id: the internal AB8500 ID number for the channel
+ * @hardware_control: indicate that we want to use hardware ADC control
+ * on this channel, the default is software ADC control. Hardware control
+ * is normally only used to test the battery voltage during GSM bursts
+ * and needs a hardware trigger on the GPADCTrig pin of the ASIC.
+ * @falling_edge: indicate that we want to trigger on falling edge
+ * rather than rising edge, rising edge is the default
+ * @avg_sample: how many samples to average: must be 1, 4, 8 or 16.
+ * @trig_timer: how long to wait for the trigger, in 32kHz periods:
+ * 0 .. 255 periods
+ */
+struct ab8500_gpadc_chan_info {
+ const char *name;
+ u8 id;
+ bool hardware_control;
+ bool falling_edge;
+ u8 avg_sample;
+ u8 trig_timer;
+};
+
+/**
+ * struct ab8500_gpadc - AB8500 GPADC device information
+ * @dev: pointer to the containing device
+ * @ab8500: pointer to the parent AB8500 device
+ * @chans: internal per-channel information container
+ * @nchans: number of channels
+ * @complete: pointer to the completion that indicates
+ * the completion of an gpadc conversion cycle
+ * @vddadc: pointer to the regulator supplying VDDADC
+ * @irq_sw: interrupt number that is used by gpadc for software ADC conversion
+ * @irq_hw: interrupt number that is used by gpadc for hardware ADC conversion
+ * @cal_data: array of ADC calibration data structs
+ */
+struct ab8500_gpadc {
+ struct device *dev;
+ struct ab8500 *ab8500;
+ struct ab8500_gpadc_chan_info *chans;
+ unsigned int nchans;
+ struct completion complete;
+ struct regulator *vddadc;
+ int irq_sw;
+ int irq_hw;
+ struct ab8500_adc_cal_data cal_data[AB8500_CAL_NR];
+};
+
+static struct ab8500_gpadc_chan_info *
+ab8500_gpadc_get_channel(struct ab8500_gpadc *gpadc, u8 chan)
+{
+ struct ab8500_gpadc_chan_info *ch;
+ int i;
+
+ for (i = 0; i < gpadc->nchans; i++) {
+ ch = &gpadc->chans[i];
+ if (ch->id == chan)
+ break;
+ }
+ if (i == gpadc->nchans)
+ return NULL;
+
+ return ch;
+}
+
+/**
+ * ab8500_gpadc_ad_to_voltage() - Convert a raw ADC value to a voltage
+ * @gpadc: GPADC instance
+ * @ch: the sampled channel this raw value is coming from
+ * @ad_value: the raw value
+ */
+static int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc,
+ enum ab8500_gpadc_channel ch,
+ int ad_value)
+{
+ int res;
+
+ switch (ch) {
+ case AB8500_GPADC_CHAN_MAIN_CHARGER:
+ /* No calibration data available: just interpolate */
+ if (!gpadc->cal_data[AB8500_CAL_VMAIN].gain) {
+ res = AB8500_ADC_CH_CHG_V_MIN + (AB8500_ADC_CH_CHG_V_MAX -
+ AB8500_ADC_CH_CHG_V_MIN) * ad_value /
+ AB8500_ADC_RESOLUTION;
+ break;
+ }
+ /* Here we can use calibration */
+ res = (int) (ad_value * gpadc->cal_data[AB8500_CAL_VMAIN].gain +
+ gpadc->cal_data[AB8500_CAL_VMAIN].offset) / AB8500_GPADC_CALIB_SCALE;
+ break;
+
+ case AB8500_GPADC_CHAN_BAT_CTRL:
+ case AB8500_GPADC_CHAN_BAT_TEMP:
+ case AB8500_GPADC_CHAN_ACC_DET_1:
+ case AB8500_GPADC_CHAN_ADC_AUX_1:
+ case AB8500_GPADC_CHAN_ADC_AUX_2:
+ case AB8500_GPADC_CHAN_XTAL_TEMP:
+ /* No calibration data available: just interpolate */
+ if (!gpadc->cal_data[AB8500_CAL_BTEMP].gain) {
+ res = AB8500_ADC_CH_BTEMP_MIN + (AB8500_ADC_CH_BTEMP_MAX -
+ AB8500_ADC_CH_BTEMP_MIN) * ad_value /
+ AB8500_ADC_RESOLUTION;
+ break;
+ }
+ /* Here we can use calibration */
+ res = (int) (ad_value * gpadc->cal_data[AB8500_CAL_BTEMP].gain +
+ gpadc->cal_data[AB8500_CAL_BTEMP].offset) / AB8500_GPADC_CALIB_SCALE;
+ break;
+
+ case AB8500_GPADC_CHAN_VBAT_A:
+ case AB8500_GPADC_CHAN_VBAT_TRUE_MEAS:
+ /* No calibration data available: just interpolate */
+ if (!gpadc->cal_data[AB8500_CAL_VBAT].gain) {
+ res = AB8500_ADC_CH_VBAT_MIN + (AB8500_ADC_CH_VBAT_MAX -
+ AB8500_ADC_CH_VBAT_MIN) * ad_value /
+ AB8500_ADC_RESOLUTION;
+ break;
+ }
+ /* Here we can use calibration */
+ res = (int) (ad_value * gpadc->cal_data[AB8500_CAL_VBAT].gain +
+ gpadc->cal_data[AB8500_CAL_VBAT].offset) / AB8500_GPADC_CALIB_SCALE;
+ break;
+
+ case AB8505_GPADC_CHAN_DIE_TEMP:
+ res = AB8500_ADC_CH_DIETEMP_MIN +
+ (AB8500_ADC_CH_DIETEMP_MAX - AB8500_ADC_CH_DIETEMP_MIN) * ad_value /
+ AB8500_ADC_RESOLUTION;
+ break;
+
+ case AB8500_GPADC_CHAN_ACC_DET_2:
+ res = AB8500_ADC_CH_ACCDET2_MIN +
+ (AB8500_ADC_CH_ACCDET2_MAX - AB8500_ADC_CH_ACCDET2_MIN) * ad_value /
+ AB8500_ADC_RESOLUTION;
+ break;
+
+ case AB8500_GPADC_CHAN_VBUS:
+ res = AB8500_ADC_CH_CHG_V_MIN +
+ (AB8500_ADC_CH_CHG_V_MAX - AB8500_ADC_CH_CHG_V_MIN) * ad_value /
+ AB8500_ADC_RESOLUTION;
+ break;
+
+ case AB8500_GPADC_CHAN_MAIN_CHARGER_CURRENT:
+ case AB8500_GPADC_CHAN_USB_CHARGER_CURRENT:
+ res = AB8500_ADC_CH_CHG_I_MIN +
+ (AB8500_ADC_CH_CHG_I_MAX - AB8500_ADC_CH_CHG_I_MIN) * ad_value /
+ AB8500_ADC_RESOLUTION;
+ break;
+
+ case AB8500_GPADC_CHAN_BACKUP_BAT:
+ res = AB8500_ADC_CH_BKBAT_MIN +
+ (AB8500_ADC_CH_BKBAT_MAX - AB8500_ADC_CH_BKBAT_MIN) * ad_value /
+ AB8500_ADC_RESOLUTION;
+ break;
+
+ case AB8500_GPADC_CHAN_IBAT_VIRTUAL:
+ /* No calibration data available: just interpolate */
+ if (!gpadc->cal_data[AB8500_CAL_IBAT].gain) {
+ res = AB8500_ADC_CH_IBAT_MIN + (AB8500_ADC_CH_IBAT_MAX -
+ AB8500_ADC_CH_IBAT_MIN) * ad_value /
+ AB8500_ADC_RESOLUTION;
+ break;
+ }
+ /* Here we can use calibration */
+ res = (int) (ad_value * gpadc->cal_data[AB8500_CAL_IBAT].gain +
+ gpadc->cal_data[AB8500_CAL_IBAT].offset)
+ >> AB8500_GPADC_CALIB_SHIFT_IBAT;
+ break;
+
+ default:
+ dev_err(gpadc->dev,
+ "unknown channel ID: %d, not possible to convert\n",
+ ch);
+ res = -EINVAL;
+ break;
+
+ }
+
+ return res;
+}
+
+static int ab8500_gpadc_read(struct ab8500_gpadc *gpadc,
+ const struct ab8500_gpadc_chan_info *ch,
+ int *ibat)
+{
+ int ret;
+ int looplimit = 0;
+ unsigned long completion_timeout;
+ u8 val;
+ u8 low_data, high_data, low_data2, high_data2;
+ u8 ctrl1;
+ u8 ctrl23;
+ unsigned int delay_min = 0;
+ unsigned int delay_max = 0;
+ u8 data_low_addr, data_high_addr;
+
+ if (!gpadc)
+ return -ENODEV;
+
+ /* check if conversion is supported */
+ if ((gpadc->irq_sw <= 0) && !ch->hardware_control)
+ return -ENOTSUPP;
+ if ((gpadc->irq_hw <= 0) && ch->hardware_control)
+ return -ENOTSUPP;
+
+ /* Enable vddadc by grabbing PM runtime */
+ pm_runtime_get_sync(gpadc->dev);
+
+ /* Check if ADC is not busy, lock and proceed */
+ do {
+ ret = abx500_get_register_interruptible(gpadc->dev,
+ AB8500_GPADC, AB8500_GPADC_STAT_REG, &val);
+ if (ret < 0)
+ goto out;
+ if (!(val & AB8500_GPADC_STAT_BUSY))
+ break;
+ msleep(20);
+ } while (++looplimit < 10);
+ if (looplimit >= 10 && (val & AB8500_GPADC_STAT_BUSY)) {
+ dev_err(gpadc->dev, "gpadc_conversion: GPADC busy");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* Enable GPADC */
+ ctrl1 = AB8500_GPADC_CTRL1_ENABLE;
+
+ /* Select the channel source and set average samples */
+ switch (ch->avg_sample) {
+ case 1:
+ ctrl23 = ch->id | AB8500_GPADC_CTRL2_AVG_1;
+ break;
+ case 4:
+ ctrl23 = ch->id | AB8500_GPADC_CTRL2_AVG_4;
+ break;
+ case 8:
+ ctrl23 = ch->id | AB8500_GPADC_CTRL2_AVG_8;
+ break;
+ default:
+ ctrl23 = ch->id | AB8500_GPADC_CTRL2_AVG_16;
+ break;
+ }
+
+ if (ch->hardware_control) {
+ ret = abx500_set_register_interruptible(gpadc->dev,
+ AB8500_GPADC, AB8500_GPADC_CTRL3_REG, ctrl23);
+ ctrl1 |= AB8500_GPADC_CTRL1_TRIG_ENA;
+ if (ch->falling_edge)
+ ctrl1 |= AB8500_GPADC_CTRL1_TRIG_EDGE;
+ } else {
+ ret = abx500_set_register_interruptible(gpadc->dev,
+ AB8500_GPADC, AB8500_GPADC_CTRL2_REG, ctrl23);
+ }
+ if (ret < 0) {
+ dev_err(gpadc->dev,
+ "gpadc_conversion: set avg samples failed\n");
+ goto out;
+ }
+
+ /*
+ * Enable ADC, buffering, select rising edge and enable ADC path
+ * charging current sense if it needed, ABB 3.0 needs some special
+ * treatment too.
+ */
+ switch (ch->id) {
+ case AB8500_GPADC_CHAN_MAIN_CHARGER_CURRENT:
+ case AB8500_GPADC_CHAN_USB_CHARGER_CURRENT:
+ ctrl1 |= AB8500_GPADC_CTRL1_BUF_ENA |
+ AB8500_GPADC_CTRL1_ICHAR_ENA;
+ break;
+ case AB8500_GPADC_CHAN_BAT_TEMP:
+ if (!is_ab8500_2p0_or_earlier(gpadc->ab8500)) {
+ ctrl1 |= AB8500_GPADC_CTRL1_BUF_ENA |
+ AB8500_GPADC_CTRL1_BTEMP_PULL_UP;
+ /*
+ * Delay might be needed for ABB8500 cut 3.0, if not,
+ * remove when hardware will be available
+ */
+ delay_min = 1000; /* Delay in micro seconds */
+ delay_max = 10000; /* large range optimises sleepmode */
+ break;
+ }
+ /* Fall through */
+ default:
+ ctrl1 |= AB8500_GPADC_CTRL1_BUF_ENA;
+ break;
+ }
+
+ /* Write configuration to control register 1 */
+ ret = abx500_set_register_interruptible(gpadc->dev,
+ AB8500_GPADC, AB8500_GPADC_CTRL1_REG, ctrl1);
+ if (ret < 0) {
+ dev_err(gpadc->dev,
+ "gpadc_conversion: set Control register failed\n");
+ goto out;
+ }
+
+ if (delay_min != 0)
+ usleep_range(delay_min, delay_max);
+
+ if (ch->hardware_control) {
+ /* Set trigger delay timer */
+ ret = abx500_set_register_interruptible(gpadc->dev,
+ AB8500_GPADC, AB8500_GPADC_AUTO_TIMER_REG,
+ ch->trig_timer);</