Merge tag 'for-v3.10' of git://git.infradead.org/battery-2.6

Pull battery updates from Anton Vorontsov:
 "Highlights:

   - OpenFirmware/DeviceTree support for the Power Supply core: the core
     now automatically populates supplied_from hierarchy from the device
     tree.  With these patches chargers and batteries can now lookup
     each other without the board files support shim.  Rhyland Klein at
     NVIDIA did the work

   - New ST-Ericsson ABX500 hwmon driver.  The driver is heavily using
     the AB85xx core and depends on some recent changes to it, so that
     is why the driver comes through the battery tree.  It has an
     appropriate ack from the hwmon maintainer (i.e.  Guenter Roeck).
     Martin Persson at ST-Ericsson and Hongbo Zhang at Linaro authored
     the driver

   - Final bits to sync AB85xx ST-Ericsson changes into mainline.  The
     changes touch mfd parts, but these were acked by the appropriate
     MFD maintainer (ie Samuel Ortiz).  Lee Jones at Linaro did most of
     the work and lead the submission process.

  Minor changes, but still worth mentioning:

   - Battery temperature reporting fix for Nokia N900 phones
   - Versatile Express poweroff driver moved into drivers/power/reset/
   - Tree-wide: use devm_kzalloc() where appropriate
   - Tree-wide: dev_pm_ops cleanups/fixes"

* tag 'for-v3.10' of git://git.infradead.org/battery-2.6: (112 commits)
  pm2301-charger: Fix suspend/resume
  charger-manager: Use kmemdup instead of kzalloc + memcpy
  power_supply: Populate supplied_from hierarchy from the device tree
  power_supply: Add core support for supplied_from
  power_supply: Define Binding for power-supplies
  rx51_battery: Fix reporting temperature
  hwmon: Add ST-Ericsson ABX500 hwmon driver
  ab8500_bmdata: Export abx500_res_to_temp tables for hwmon
  ab8500_{bmdata,fg}: Add const attributes to some data arrays
  ab8500_bmdata: Eliminate CamelCase warning of some variables
  ab8500_btemp: Make ab8500_btemp_get* interfaces public
  goldfish_battery: Use resource_size()
  lp8788-charger: Use PAGE_SIZE for the sysfs read operation
  max8925_power: Use devm_kzalloc()
  da9030_battery: Use devm_kzalloc()
  da9052-battery: Use devm_kzalloc()
  ds2760_battery: Use devm_kzalloc()
  ds2780_battery: Use devm_kzalloc()
  gpio-charger: Use devm_kzalloc()
  isp1704_charger: Use devm_kzalloc()
  ...
This commit is contained in:
Linus Torvalds
2013-04-30 15:15:24 -07:00
64 changed files with 6024 additions and 1131 deletions

View File

@@ -0,0 +1,23 @@
Power Supply Core Support
Optional Properties:
- power-supplies : This property is added to a supply in order to list the
devices which supply it power, referenced by their phandles.
Example:
usb-charger: power@e {
compatible = "some,usb-charger";
...
};
ac-charger: power@c {
compatible = "some,ac-charger";
...
};
battery@b {
compatible = "some,battery";
...
power-supplies = <&usb-charger>, <&ac-charger>;
};

View File

@@ -0,0 +1,17 @@
TPS65090 Frontend PMU with Switchmode Charger
Required Properties:
-compatible: "ti,tps65090-charger"
Optional Properties:
-ti,enable-low-current-chrg: Enables charging when a low current is detected
while the default logic is to stop charging.
This node is a subnode of the tps65090 PMIC.
Example:
tps65090-charger {
compatible = "ti,tps65090-charger";
ti,enable-low-current-chrg;
};

View File

@@ -0,0 +1,22 @@
Kernel driver ab8500
====================
Supported chips:
* ST-Ericsson AB8500
Prefix: 'ab8500'
Addresses scanned: -
Datasheet: http://www.stericsson.com/developers/documentation.jsp
Authors:
Martin Persson <martin.persson@stericsson.com>
Hongbo Zhang <hongbo.zhang@linaro.org>
Description
-----------
See also Documentation/hwmon/abx500. This is the ST-Ericsson AB8500 specific
driver.
Currently only the AB8500 internal sensor and one external sensor for battery
temperature are monitored. Other GPADC channels can also be monitored if needed
in future.

View File

@@ -0,0 +1,28 @@
Kernel driver abx500
====================
Supported chips:
* ST-Ericsson ABx500 series
Prefix: 'abx500'
Addresses scanned: -
Datasheet: http://www.stericsson.com/developers/documentation.jsp
Authors:
Martin Persson <martin.persson@stericsson.com>
Hongbo Zhang <hongbo.zhang@linaro.org>
Description
-----------
Every ST-Ericsson Ux500 SOC consists of both ABx500 and DBx500 physically,
this is kernel hwmon driver for ABx500.
There are some GPADCs inside ABx500 which are designed for connecting to
thermal sensors, and there is also a thermal sensor inside ABx500 too, which
raises interrupt when critical temperature reached.
This abx500 is a common layer which can monitor all of the sensors, every
specific abx500 chip has its special configurations in its own file, e.g. some
sensors can be configured invisible if they are not available on that chip, and
the corresponding gpadc_addr should be set to 0, thus this sensor won't be
polled.

View File

@@ -17,6 +17,9 @@ config ARCH_VEXPRESS
select NO_IOPORT
select PLAT_VERSATILE
select PLAT_VERSATILE_CLCD
select POWER_RESET
select POWER_RESET_VEXPRESS
select POWER_SUPPLY
select REGULATOR_FIXED_VOLTAGE if REGULATOR
select VEXPRESS_CONFIG
help

View File

@@ -4,7 +4,7 @@
ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
-I$(srctree)/arch/arm/plat-versatile/include
obj-y := v2m.o reset.o
obj-y := v2m.o
obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o
obj-$(CONFIG_SMP) += platsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o

View File

@@ -363,8 +363,6 @@ static void __init v2m_init(void)
for (i = 0; i < ARRAY_SIZE(v2m_amba_devs); i++)
amba_device_register(v2m_amba_devs[i], &iomem_resource);
pm_power_off = vexpress_power_off;
ct_desc->init_tile();
}
@@ -376,7 +374,6 @@ MACHINE_START(VEXPRESS, "ARM-Versatile Express")
.init_irq = v2m_init_irq,
.init_time = v2m_timer_init,
.init_machine = v2m_init,
.restart = vexpress_restart,
MACHINE_END
static struct map_desc v2m_rs1_io_desc __initdata = {
@@ -470,7 +467,6 @@ static void __init v2m_dt_init(void)
{
l2x0_of_init(0x00400000, 0xfe0fffff);
of_platform_populate(NULL, v2m_dt_bus_match, NULL, NULL);
pm_power_off = vexpress_power_off;
}
static const char * const v2m_dt_match[] __initconst = {
@@ -487,5 +483,4 @@ DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express")
.init_irq = irqchip_init,
.init_time = v2m_dt_timer_init,
.init_machine = v2m_dt_init,
.restart = vexpress_restart,
MACHINE_END

View File

@@ -39,6 +39,19 @@ config HWMON_DEBUG_CHIP
comment "Native drivers"
config SENSORS_AB8500
tristate "AB8500 thermal monitoring"
depends on AB8500_GPADC && AB8500_BM
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
AB8500 die and two GPADC channels. The GPADC channel are preferably
used to access sensors outside the AB8500 chip.
This driver can also be built as a module. If so, the module
will be called abx500-temp.
config SENSORS_ABITUGURU
tristate "Abit uGuru (rev 1 & 2)"
depends on X86 && DMI

View File

@@ -19,6 +19,7 @@ obj-$(CONFIG_SENSORS_W83795) += w83795.o
obj-$(CONFIG_SENSORS_W83781D) += w83781d.o
obj-$(CONFIG_SENSORS_W83791D) += w83791d.o
obj-$(CONFIG_SENSORS_AB8500) += abx500.o ab8500.o
obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o
obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
obj-$(CONFIG_SENSORS_AD7314) += ad7314.o

206
drivers/hwmon/ab8500.c Normal file
View File

@@ -0,0 +1,206 @@
/*
* Copyright (C) ST-Ericsson 2010 - 2013
* Author: Martin Persson <martin.persson@stericsson.com>
* Hongbo Zhang <hongbo.zhang@linaro.org>
* License Terms: GNU General Public License v2
*
* When the AB8500 thermal warning temperature is reached (threshold cannot
* be changed by SW), an interrupt is set, and if no further action is taken
* within a certain time frame, pm_power off will be called.
*
* When AB8500 thermal shutdown temperature is reached a hardware shutdown of
* the AB8500 will occur.
*/
#include <linux/err.h>
#include <linux/hwmon.h>
#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/slab.h>
#include <linux/sysfs.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
struct ab8500_gpadc_cfg {
const struct abx500_res_to_temp *temp_tbl;
int tbl_sz;
int vcc;
int r_up;
};
struct ab8500_temp {
struct ab8500_gpadc *gpadc;
struct ab8500_btemp *btemp;
struct delayed_work power_off_work;
struct ab8500_gpadc_cfg cfg;
struct abx500_temp *abx500_data;
};
/*
* The hardware connection is like this:
* VCC----[ R_up ]-----[ NTC ]----GND
* where R_up is pull-up resistance, and GPADC measures voltage on NTC.
* and res_to_temp table is strictly sorted by falling resistance values.
*/
static int ab8500_voltage_to_temp(struct ab8500_gpadc_cfg *cfg,
int v_ntc, int *temp)
{
int r_ntc, i = 0, tbl_sz = cfg->tbl_sz;
const struct abx500_res_to_temp *tbl = cfg->temp_tbl;
if (cfg->vcc < 0 || v_ntc >= cfg->vcc)
return -EINVAL;
r_ntc = v_ntc * cfg->r_up / (cfg->vcc - v_ntc);
if (r_ntc > tbl[0].resist || r_ntc < tbl[tbl_sz - 1].resist)
return -EINVAL;
while (!(r_ntc <= tbl[i].resist && r_ntc > tbl[i + 1].resist) &&
i < tbl_sz - 2)
i++;
/* return milli-Celsius */
*temp = tbl[i].temp * 1000 + ((tbl[i + 1].temp - tbl[i].temp) * 1000 *
(r_ntc - tbl[i].resist)) / (tbl[i + 1].resist - tbl[i].resist);
return 0;
}
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) {
*temp = ab8500_btemp_get_temp(ab8500_data->btemp);
} else {
voltage = ab8500_gpadc_convert(ab8500_data->gpadc, sensor);
if (voltage < 0)
return voltage;
ret = ab8500_voltage_to_temp(&ab8500_data->cfg, voltage, temp);
if (ret < 0)
return ret;
}
return 0;
}
static void ab8500_thermal_power_off(struct work_struct *work)
{
struct ab8500_temp *ab8500_data = container_of(work,
struct ab8500_temp, power_off_work.work);
struct abx500_temp *abx500_data = ab8500_data->abx500_data;
dev_warn(&abx500_data->pdev->dev, "Power off due to critical temp\n");
pm_power_off();
}
static ssize_t ab8500_show_name(struct device *dev,
struct device_attribute *devattr, char *buf)
{
return sprintf(buf, "ab8500\n");
}
static ssize_t ab8500_show_label(struct device *dev,
struct device_attribute *devattr, char *buf)
{
char *label;
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
int index = attr->index;
switch (index) {
case 1:
label = "ext_adc1";
break;
case 2:
label = "ext_adc2";
break;
case 3:
label = "bat_temp";
break;
case 4:
label = "bat_ctrl";
break;
default:
return -EINVAL;
}
return sprintf(buf, "%s\n", label);
}
static int ab8500_temp_irq_handler(int irq, struct abx500_temp *data)
{
struct ab8500_temp *ab8500_data = data->plat_data;
dev_warn(&data->pdev->dev, "Power off in %d s\n",
DEFAULT_POWER_OFF_DELAY / HZ);
schedule_delayed_work(&ab8500_data->power_off_work,
DEFAULT_POWER_OFF_DELAY);
return 0;
}
int abx500_hwmon_init(struct abx500_temp *data)
{
struct ab8500_temp *ab8500_data;
ab8500_data = devm_kzalloc(&data->pdev->dev, sizeof(*ab8500_data),
GFP_KERNEL);
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);
INIT_DELAYED_WORK(&ab8500_data->power_off_work,
ab8500_thermal_power_off);
ab8500_data->cfg.vcc = THERMAL_VCC;
ab8500_data->cfg.r_up = PULL_UP_RESISTOR;
ab8500_data->cfg.temp_tbl = ab8500_temp_tbl_a_thermistor;
ab8500_data->cfg.tbl_sz = ab8500_temp_tbl_a_size;
data->plat_data = ab8500_data;
/*
* 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->monitored_sensors = NUM_MONITORED_SENSORS;
data->ops.read_sensor = ab8500_read_sensor;
data->ops.irq_handler = ab8500_temp_irq_handler;
data->ops.show_name = ab8500_show_name;
data->ops.show_label = ab8500_show_label;
data->ops.is_visible = NULL;
return 0;
}
EXPORT_SYMBOL(abx500_hwmon_init);
MODULE_AUTHOR("Hongbo Zhang <hongbo.zhang@linaro.org>");
MODULE_DESCRIPTION("AB8500 temperature driver");
MODULE_LICENSE("GPL");

491
drivers/hwmon/abx500.c Normal file
View File

@@ -0,0 +1,491 @@
/*
* Copyright (C) ST-Ericsson 2010 - 2013
* Author: Martin Persson <martin.persson@stericsson.com>
* Hongbo Zhang <hongbo.zhang@linaro.org>
* License Terms: GNU General Public License v2
*
* ABX500 does not provide auto ADC, so to monitor the required temperatures,
* a periodic work is used. It is more important to not wake up the CPU than
* to perform this job, hence the use of a deferred delay.
*
* A deferred delay for thermal monitor is considered safe because:
* If the chip gets too hot during a sleep state it's most likely due to
* external factors, such as the surrounding temperature. I.e. no SW decisions
* will make any difference.
*/
#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/workqueue.h>
#include "abx500.h"
#define DEFAULT_MONITOR_DELAY HZ
#define DEFAULT_MAX_TEMP 130
static inline void schedule_monitor(struct abx500_temp *data)
{
data->work_active = true;
schedule_delayed_work(&data->work, DEFAULT_MONITOR_DELAY);
}
static void threshold_updated(struct abx500_temp *data)
{
int i;
for (i = 0; i < data->monitored_sensors; i++)
if (data->max[i] != 0 || data->min[i] != 0) {
schedule_monitor(data);
return;
}
dev_dbg(&data->pdev->dev, "No active thresholds.\n");
cancel_delayed_work_sync(&data->work);
data->work_active = false;
}
static void gpadc_monitor(struct work_struct *work)
{
int temp, i, ret;
char alarm_node[30];
bool updated_min_alarm, updated_max_alarm;
struct abx500_temp *data;
data = container_of(work, struct abx500_temp, work.work);
mutex_lock(&data->lock);
for (i = 0; i < data->monitored_sensors; i++) {
/* Thresholds are considered inactive if set to 0 */
if (data->max[i] == 0 && data->min[i] == 0)
continue;
if (data->max[i] < data->min[i])
continue;
ret = data->ops.read_sensor(data, data->gpadc_addr[i], &temp);
if (ret < 0) {
dev_err(&data->pdev->dev, "GPADC read failed\n");
continue;
}
updated_min_alarm = false;
updated_max_alarm = false;
if (data->min[i] != 0) {
if (temp < data->min[i]) {
if (data->min_alarm[i] == false) {
data->min_alarm[i] = true;
updated_min_alarm = true;
}
} else {
if (data->min_alarm[i] == true) {
data->min_alarm[i] = false;
updated_min_alarm = true;
}
}
}
if (data->max[i] != 0) {
if (temp > data->max[i]) {
if (data->max_alarm[i] == false) {
data->max_alarm[i] = true;
updated_max_alarm = true;
}
} else if (temp < data->max[i] - data->max_hyst[i]) {
if (data->max_alarm[i] == true) {
data->max_alarm[i] = false;
updated_max_alarm = true;
}
}
}
if (updated_min_alarm) {
ret = sprintf(alarm_node, "temp%d_min_alarm", i + 1);
sysfs_notify(&data->pdev->dev.kobj, NULL, alarm_node);
}
if (updated_max_alarm) {
ret = sprintf(alarm_node, "temp%d_max_alarm", i + 1);
sysfs_notify(&data->pdev->dev.kobj, NULL, alarm_node);
}
}
schedule_monitor(data);
mutex_unlock(&data->lock);
}
/* HWMON sysfs interfaces */
static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
char *buf)
{
struct abx500_temp *data = dev_get_drvdata(dev);
/* Show chip name */
return data->ops.show_name(dev, devattr, buf);
}
static ssize_t show_label(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct abx500_temp *data = dev_get_drvdata(dev);
/* Show each sensor label */
return data->ops.show_label(dev, devattr, buf);
}
static ssize_t show_input(struct device *dev,
struct device_attribute *devattr, char *buf)
{
int ret, temp;
struct abx500_temp *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
u8 gpadc_addr = data->gpadc_addr[attr->index];
ret = data->ops.read_sensor(data, gpadc_addr, &temp);
if (ret < 0)
return ret;
return sprintf(buf, "%d\n", temp);
}
/* Set functions (RW nodes) */
static ssize_t set_min(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
unsigned long val;
struct abx500_temp *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
int res = kstrtol(buf, 10, &val);
if (res < 0)
return res;
val = clamp_val(val, 0, DEFAULT_MAX_TEMP);
mutex_lock(&data->lock);
data->min[attr->index] = val;
threshold_updated(data);
mutex_unlock(&data->lock);
return count;
}
static ssize_t set_max(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count)
{
unsigned long val;
struct abx500_temp *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
int res = kstrtol(buf, 10, &val);
if (res < 0)
return res;
val = clamp_val(val, 0, DEFAULT_MAX_TEMP);
mutex_lock(&data->lock);
data->max[attr->index] = val;
threshold_updated(data);
mutex_unlock(&data->lock);
return count;
}
static ssize_t set_max_hyst(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
unsigned long val;
struct abx500_temp *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
int res = kstrtoul(buf, 10, &val);
if (res < 0)
return res;
val = clamp_val(val, 0, DEFAULT_MAX_TEMP);
mutex_lock(&data->lock);
data->max_hyst[attr->index] = val;
threshold_updated(data);
mutex_unlock(&data->lock);
return count;
}
/* Show functions (RO nodes) */
static ssize_t show_min(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct abx500_temp *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
return sprintf(buf, "%ld\n", data->min[attr->index]);
}
static ssize_t show_max(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct abx500_temp *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
return sprintf(buf, "%ld\n", data->max[attr->index]);
}
static ssize_t show_max_hyst(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct abx500_temp *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
return sprintf(buf, "%ld\n", data->max_hyst[attr->index]);
}
static ssize_t show_min_alarm(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct abx500_temp *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
return sprintf(buf, "%d\n", data->min_alarm[attr->index]);
}
static ssize_t show_max_alarm(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct abx500_temp *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
return sprintf(buf, "%d\n", data->max_alarm[attr->index]);
}
static mode_t abx500_attrs_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct abx500_temp *data = dev_get_drvdata(dev);
if (data->ops.is_visible)
return data->ops.is_visible(attr, n);
return attr->mode;
}
/* Chip name, required by hwmon */
static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
/* GPADC - SENSOR1 */
static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_min, set_min, 0);
static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_max, set_max, 0);
static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
show_max_hyst, set_max_hyst, 0);
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_min_alarm, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_max_alarm, NULL, 0);
/* GPADC - SENSOR2 */
static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, show_label, NULL, 1);
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_input, NULL, 1);
static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_min, set_min, 1);
static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_max, set_max, 1);
static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IWUSR | S_IRUGO,
show_max_hyst, set_max_hyst, 1);
static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_min_alarm, NULL, 1);
static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_max_alarm, NULL, 1);
/* GPADC - SENSOR3 */
static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, show_label, NULL, 2);
static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_input, NULL, 2);
static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_min, set_min, 2);
static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max, set_max, 2);
static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IWUSR | S_IRUGO,
show_max_hyst, set_max_hyst, 2);
static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO, show_min_alarm, NULL, 2);
static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_max_alarm, NULL, 2);
/* GPADC - SENSOR4 */
static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, show_label, NULL, 3);
static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_input, NULL, 3);
static SENSOR_DEVICE_ATTR(temp4_min, S_IWUSR | S_IRUGO, show_min, set_min, 3);
static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_max, set_max, 3);
static SENSOR_DEVICE_ATTR(temp4_max_hyst, S_IWUSR | S_IRUGO,
show_max_hyst, set_max_hyst, 3);
static SENSOR_DEVICE_ATTR(temp4_min_alarm, S_IRUGO, show_min_alarm, NULL, 3);
static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_max_alarm, NULL, 3);
struct attribute *abx500_temp_attributes[] = {
&sensor_dev_attr_name.dev_attr.attr,
&sensor_dev_attr_temp1_label.dev_attr.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp1_min.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_label.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
&sensor_dev_attr_temp2_min.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr,
&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_label.dev_attr.attr,
&sensor_dev_attr_temp3_input.dev_attr.attr,
&sensor_dev_attr_temp3_min.dev_attr.attr,
&sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp4_label.dev_attr.attr,
&sensor_dev_attr_temp4_input.dev_attr.attr,
&sensor_dev_attr_temp4_min.dev_attr.attr,
&sensor_dev_attr_temp4_max.dev_attr.attr,
&sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp4_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
NULL
};
static const struct attribute_group abx500_temp_group = {
.attrs = abx500_temp_attributes,
.is_visible = abx500_attrs_visible,
};
static irqreturn_t abx500_temp_irq_handler(int irq, void *irq_data)
{
struct platform_device *pdev = irq_data;
struct abx500_temp *data = platform_get_drvdata(pdev);
data->ops.irq_handler(irq, data);
return IRQ_HANDLED;
}
static int setup_irqs(struct platform_device *pdev)
{
int ret;
int irq = platform_get_irq_byname(pdev, "ABX500_TEMP_WARM");
if (irq < 0) {
dev_err(&pdev->dev, "Get irq by name failed\n");
return irq;
}
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
abx500_temp_irq_handler, IRQF_NO_SUSPEND, "abx500-temp", pdev);
if (ret < 0)
dev_err(&pdev->dev, "Request threaded irq failed (%d)\n", ret);
return ret;
}
static int abx500_temp_probe(struct platform_device *pdev)
{
struct abx500_temp *data;
int err;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->pdev = pdev;
mutex_init(&data->lock);
/* Chip specific initialization */
err = abx500_hwmon_init(data);
if (err < 0 || !data->ops.read_sensor || !data->ops.show_name ||
!data->ops.show_label)
return err;
INIT_DEFERRABLE_WORK(&data->work, gpadc_monitor);
platform_set_drvdata(pdev, data);
err = sysfs_create_group(&pdev->dev.kobj, &abx500_temp_group);
if (err < 0) {
dev_err(&pdev->dev, "Create sysfs group failed (%d)\n", err);
return err;
}
data->hwmon_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
goto exit_sysfs_group;
}
if (data->ops.irq_handler) {
err = setup_irqs(pdev);
if (err < 0)
goto exit_hwmon_reg;
}
return 0;
exit_hwmon_reg:
hwmon_device_unregister(data->hwmon_dev);
exit_sysfs_group:
sysfs_remove_group(&pdev->dev.kobj, &abx500_temp_group);
return err;
}
static int abx500_temp_remove(struct platform_device *pdev)
{
struct abx500_temp *data = platform_get_drvdata(pdev);
cancel_delayed_work_sync(&data->work);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &abx500_temp_group);
return 0;
}
static int abx500_temp_suspend(struct platform_device *pdev,
pm_message_t state)
{
struct abx500_temp *data = platform_get_drvdata(pdev);
if (data->work_active)
cancel_delayed_work_sync(&data->work);
return 0;
}
static int abx500_temp_resume(struct platform_device *pdev)
{
struct abx500_temp *data = platform_get_drvdata(pdev);
if (data->work_active)
schedule_monitor(data);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id abx500_temp_match[] = {
{ .compatible = "stericsson,abx500-temp" },
{},
};
#endif
static struct platform_driver abx500_temp_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "abx500-temp",
.of_match_table = of_match_ptr(abx500_temp_match),
},
.suspend = abx500_temp_suspend,
.resume = abx500_temp_resume,
.probe = abx500_temp_probe,
.remove = abx500_temp_remove,
};
module_platform_driver(abx500_temp_driver);
MODULE_AUTHOR("Martin Persson <martin.persson@stericsson.com>");
MODULE_DESCRIPTION("ABX500 temperature driver");
MODULE_LICENSE("GPL");

69
drivers/hwmon/abx500.h Normal file
View File

@@ -0,0 +1,69 @@
/*
* Copyright (C) ST-Ericsson 2010 - 2013
* License terms: GNU General Public License v2
* Author: Martin Persson <martin.persson@stericsson.com>
* Hongbo Zhang <hongbo.zhang@linaro.com>
*/
#ifndef _ABX500_H
#define _ABX500_H
#define NUM_SENSORS 5
struct abx500_temp;
/*
* struct abx500_temp_ops - abx500 chip specific ops
* @read_sensor: reads gpadc output
* @irq_handler: irq handler
* @show_name: hwmon device name
* @show_label: hwmon attribute label
* @is_visible: is attribute visible
*/
struct abx500_temp_ops {
int (*read_sensor)(struct abx500_temp *, u8, int *);
int (*irq_handler)(int, struct abx500_temp *);
ssize_t (*show_name)(struct device *,
struct device_attribute *, char *);
ssize_t (*show_label) (struct device *,
struct device_attribute *, char *);
int (*is_visible)(struct attribute *, int);
};
/*
* struct abx500_temp - representation of temp mon device
* @pdev: platform device
* @hwmon_dev: hwmon device
* @ops: abx500 chip specific ops
* @gpadc_addr: gpadc channel address
* @min: sensor temperature min value
* @max: sensor temperature max value
* @max_hyst: sensor temperature hysteresis value for max limit
* @min_alarm: sensor temperature min alarm
* @max_alarm: sensor temperature max alarm
* @work: delayed work scheduled to monitor temperature periodically
* @work_active: True if work is active
* @lock: mutex
* @monitored_sensors: number of monitored sensors
* @plat_data: private usage, usually points to platform specific data
*/
struct abx500_temp {
struct platform_device *pdev;
struct device *hwmon_dev;
struct abx500_temp_ops ops;
u8 gpadc_addr[NUM_SENSORS];
unsigned long min[NUM_SENSORS];
unsigned long max[NUM_SENSORS];
unsigned long max_hyst[NUM_SENSORS];
bool min_alarm[NUM_SENSORS];
bool max_alarm[NUM_SENSORS];
struct delayed_work work;
bool work_active;
struct mutex lock;
int monitored_sensors;
void *plat_data;
};
int abx500_hwmon_init(struct abx500_temp *data);
#endif /* _ABX500_H */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -15,19 +15,30 @@
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/abx500/ab8500-sysctrl.h>
/* RtcCtrl bits */
#define AB8500_ALARM_MIN_LOW 0x08
#define AB8500_ALARM_MIN_MID 0x09
#define RTC_CTRL 0x0B
#define RTC_ALARM_ENABLE 0x4
static struct device *sysctrl_dev;
void ab8500_power_off(void)
{
sigset_t old;
sigset_t all;
static char *pss[] = {"ab8500_ac", "ab8500_usb"};
static char *pss[] = {"ab8500_ac", "pm2301", "ab8500_usb"};
int i;
bool charger_present = false;
union power_supply_propval val;
struct power_supply *psy;
int ret;
if (sysctrl_dev == NULL) {
pr_err("%s: sysctrl not initialized\n", __func__);
return;
}
/*
* If we have a charger connected and we're powering off,
* reboot into charge-only mode.
@@ -74,6 +85,63 @@ shutdown:
}
}
/*
* Use the AB WD to reset the platform. It will perform a hard
* reset instead of a soft reset. Write the reset reason to
* the AB before reset, which can be read upon restart.
*/
void ab8500_restart(char mode, const char *cmd)
{
struct ab8500_platform_data *plat;
struct ab8500_sysctrl_platform_data *pdata;
u16 reason = 0;
u8 val;
if (sysctrl_dev == NULL) {
pr_err("%s: sysctrl not initialized\n", __func__);
return;
}
plat = dev_get_platdata(sysctrl_dev->parent);
pdata = plat->sysctrl;
if (pdata->reboot_reason_code)
reason = pdata->reboot_reason_code(cmd);
else
pr_warn("[%s] No reboot reason set. Default reason %d\n",
__func__, reason);
/*
* Disable RTC alarm, just a precaution so that no alarm
* is running when WD reset is executed.
*/
abx500_get_register_interruptible(sysctrl_dev, AB8500_RTC,
RTC_CTRL , &val);
abx500_set_register_interruptible(sysctrl_dev, AB8500_RTC,
RTC_CTRL , (val & ~RTC_ALARM_ENABLE));
/*
* Android is not using the RTC alarm registers during reboot
* so we borrow them for writing the reason of reset
*/
/* reason[8 LSB] */
val = reason & 0xFF;
abx500_set_register_interruptible(sysctrl_dev, AB8500_RTC,
AB8500_ALARM_MIN_LOW , val);
/* reason[8 MSB] */
val = (reason>>8) & 0xFF;
abx500_set_register_interruptible(sysctrl_dev, AB8500_RTC,
AB8500_ALARM_MIN_MID , val);
/* Setting WD timeout to 0 */
ab8500_sysctrl_write(AB8500_MAINWDOGTIMER, 0xFF, 0x0);
/* Setting the parameters to AB8500 WD*/
ab8500_sysctrl_write(AB8500_MAINWDOGCTRL, 0xFF, (AB8500_ENABLE_WD |
AB8500_WD_RESTART_ON_EXPIRE | AB8500_KICK_WD));
}
static inline bool valid_bank(u8 bank)
{
return ((bank == AB8500_SYS_CTRL1_BLOCK) ||
@@ -85,7 +153,7 @@ int ab8500_sysctrl_read(u16 reg, u8 *value)
u8 bank;
if (sysctrl_dev == NULL)
return -EAGAIN;
return -EINVAL;
bank = (reg >> 8);
if (!valid_bank(bank))
@@ -101,7 +169,7 @@ int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
u8 bank;
if (sysctrl_dev == NULL)
return -EAGAIN;
return -EINVAL;
bank = (reg >> 8);
if (!valid_bank(bank))
@@ -114,28 +182,36 @@ EXPORT_SYMBOL(ab8500_sysctrl_write);
static int ab8500_sysctrl_probe(struct platform_device *pdev)
{
struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
struct ab8500_platform_data *plat;
struct ab8500_sysctrl_platform_data *pdata;
sysctrl_dev = &pdev->dev;
plat = dev_get_platdata(pdev->dev.parent);
if (!(plat && plat->sysctrl))
return -EINVAL;
if (plat->pm_power_off)
pm_power_off = ab8500_power_off;
pdata = plat->sysctrl;
if (pdata) {
int ret, i, j;
int last, ret, i, j;
for (i = AB8500_SYSCLKREQ1RFCLKBUF;
i <= AB8500_SYSCLKREQ8RFCLKBUF; i++) {
if (is_ab8505(ab8500))
last = AB8500_SYSCLKREQ4RFCLKBUF;
else
last = AB8500_SYSCLKREQ8RFCLKBUF;
for (i = AB8500_SYSCLKREQ1RFCLKBUF; i <= last; i++) {
j = i - AB8500_SYSCLKREQ1RFCLKBUF;
ret = ab8500_sysctrl_write(i, 0xff,
pdata->initial_req_buf_config[j]);
pdata->initial_req_buf_config[j]);
dev_dbg(&pdev->dev,
"Setting SysClkReq%dRfClkBuf 0x%X\n",
j + 1,
pdata->initial_req_buf_config[j]);
"Setting SysClkReq%dRfClkBuf 0x%X\n",
j + 1,
pdata->initial_req_buf_config[j]);
if (ret < 0) {
dev_err(&pdev->dev,
"unable to set sysClkReq%dRfClkBuf: "

View File

@@ -714,7 +714,6 @@ out_irq:
while (--i >= 0)
free_irq(info->irq[i], info);
out:
kfree(info);
return ret;
}
@@ -728,7 +727,6 @@ static int pm860x_charger_remove(struct platform_device *pdev)
free_irq(info->irq[0], info);
for (i = 0; i < info->irq_nums; i++)
free_irq(info->irq[i], info);
kfree(info);
return 0;
}

View File

@@ -340,6 +340,13 @@ config CHARGER_SMB347
Say Y to include support for Summit Microelectronics SMB347
Battery Charger.
config CHARGER_TPS65090
tristate "TPS65090 battery charger driver"
depends on MFD_TPS65090
help
Say Y here to enable support for battery charging with TPS65090
PMIC chips.
config AB8500_BM
bool "AB8500 Battery Management Driver"
depends on AB8500_CORE && AB8500_GPADC
@@ -353,13 +360,6 @@ config BATTERY_GOLDFISH
Say Y to enable support for the battery and AC power in the
Goldfish emulator.
config CHARGER_PM2301
bool "PM2301 Battery Charger Driver"
depends on AB8500_BM
help
Say Y to include support for PM2301 charger driver.
Depends on AB8500 battery management core.
source "drivers/power/reset/Kconfig"
endif # POWER_SUPPLY

View File

@@ -39,7 +39,7 @@ obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o
obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o
obj-$(CONFIG_BATTERY_RX51) += rx51_battery.o
obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o
obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o pm2301_charger.o
obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o
obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
@@ -47,10 +47,10 @@ obj-$(CONFIG_CHARGER_LP8727) += lp8727_charger.o
obj-$(CONFIG_CHARGER_LP8788) += lp8788-charger.o
obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o
obj-$(CONFIG_CHARGER_PM2301) += pm2301_charger.o
obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o
obj-$(CONFIG_POWER_AVS) += avs/
obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o
obj-$(CONFIG_POWER_RESET) += reset/

View File

@@ -11,7 +11,7 @@
* Note that the res_to_temp table must be strictly sorted by falling resistance
* values to work.
*/
static struct abx500_res_to_temp temp_tbl_A_thermistor[] = {
const struct abx500_res_to_temp ab8500_temp_tbl_a_thermistor[] = {
{-5, 53407},
{ 0, 48594},
{ 5, 43804},
@@ -28,8 +28,12 @@ static struct abx500_res_to_temp temp_tbl_A_thermistor[] = {
{60, 13437},
{65, 12500},
};
EXPORT_SYMBOL(ab8500_temp_tbl_a_thermistor);
static struct abx500_res_to_temp temp_tbl_B_thermistor[] = {
const int ab8500_temp_tbl_a_size = ARRAY_SIZE(ab8500_temp_tbl_a_thermistor);
EXPORT_SYMBOL(ab8500_temp_tbl_a_size);
const struct abx500_res_to_temp ab8500_temp_tbl_b_thermistor[] = {
{-5, 200000},
{ 0, 159024},
{ 5, 151921},
@@ -46,8 +50,12 @@ static struct abx500_res_to_temp temp_tbl_B_thermistor[] = {
{60, 85461},
{65, 82869},
};
EXPORT_SYMBOL(ab8500_temp_tbl_b_thermistor);
static struct abx500_v_to_cap cap_tbl_A_thermistor[] = {
const int ab8500_temp_tbl_b_size = ARRAY_SIZE(ab8500_temp_tbl_b_thermistor);
EXPORT_SYMBOL(ab8500_temp_tbl_b_size);
static const struct abx500_v_to_cap cap_tbl_a_thermistor[] = {
{4171, 100},
{4114, 95},
{4009, 83},
@@ -70,7 +78,7 @@ static struct abx500_v_to_cap cap_tbl_A_thermistor[] = {
{3247, 0},
};
static struct abx500_v_to_cap cap_tbl_B_thermistor[] = {
static const struct abx500_v_to_cap cap_tbl_b_thermistor[] = {
{4161, 100},
{4124, 98},
{4044, 90},
@@ -93,7 +101,7 @@ static struct abx500_v_to_cap cap_tbl_B_thermistor[] = {
{3250, 0},
};
static struct abx500_v_to_cap cap_tbl[] = {
static const struct abx500_v_to_cap cap_tbl[] = {
{4186, 100},
{4163, 99},
{4114, 95},
@@ -124,7 +132,7 @@ static struct abx500_v_to_cap cap_tbl[] = {
* Note that the res_to_temp table must be strictly sorted by falling
* resistance values to work.
*/
static struct abx500_res_to_temp temp_tbl[] = {
static const struct abx500_res_to_temp temp_tbl[] = {
{-5, 214834},
{ 0, 162943},
{ 5, 124820},
@@ -146,7 +154,7 @@ static struct abx500_res_to_temp temp_tbl[] = {
* Note that the batres_vs_temp table must be strictly sorted by falling
* temperature values to work.
*/
static struct batres_vs_temp temp_to_batres_tbl_thermistor[] = {
static const struct batres_vs_temp temp_to_batres_tbl_thermistor[] = {
{ 40, 120},
{ 30, 135},
{ 20, 165},
@@ -160,7 +168,7 @@ static struct batres_vs_temp temp_to_batres_tbl_thermistor[] = {
* Note that the batres_vs_temp table must be strictly sorted by falling
* temperature values to work.
*/
static struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[] = {
static const struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[] = {
{ 60, 300},
{ 30, 300},
{ 20, 300},
@@ -171,7 +179,7 @@ static struct batres_vs_temp temp_to_batres_tbl_ext_thermistor[] = {
};
/* battery resistance table for LI ION 9100 battery */
static struct batres_vs_temp temp_to_batres_tbl_9100[] = {
static const struct batres_vs_temp temp_to_batres_tbl_9100[] = {
{ 60, 180},
{ 30, 180},
{ 20, 180},
@@ -230,10 +238,10 @@ static struct abx500_battery_type bat_type_thermistor[] = {
.maint_b_chg_timer_h = 200,
.low_high_cur_lvl = 300,
.low_high_vol_lvl = 4000,
.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_A_thermistor),
.r_to_t_tbl = temp_tbl_A_thermistor,
.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_A_thermistor),
.v_to_cap_tbl = cap_tbl_A_thermistor,
.n_temp_tbl_elements = ARRAY_SIZE(ab8500_temp_tbl_a_thermistor),
.r_to_t_tbl = ab8500_temp_tbl_a_thermistor,
.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_a_thermistor),
.v_to_cap_tbl = cap_tbl_a_thermistor,
.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
.batres_tbl = temp_to_batres_tbl_thermistor,
@@ -258,10 +266,10 @@ static struct abx500_battery_type bat_type_thermistor[] = {
.maint_b_chg_timer_h = 200,
.low_high_cur_lvl = 300,
.low_high_vol_lvl = 4000,
.n_temp_tbl_elements = ARRAY_SIZE(temp_tbl_B_thermistor),
.r_to_t_tbl = temp_tbl_B_thermistor,
.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_B_thermistor),
.v_to_cap_tbl = cap_tbl_B_thermistor,
.n_temp_tbl_elements = ARRAY_SIZE(ab8500_temp_tbl_b_thermistor),
.r_to_t_tbl = ab8500_temp_tbl_b_thermistor,
.n_v_cap_tbl_elements = ARRAY_SIZE(cap_tbl_b_thermistor),
.v_to_cap_tbl = cap_tbl_b_thermistor,
.n_batres_tbl_elements = ARRAY_SIZE(temp_to_batres_tbl_thermistor),
.batres_tbl = temp_to_batres_tbl_thermistor,
},
@@ -407,15 +415,27 @@ static const struct abx500_fg_parameters fg = {
.battok_raising_th_sel1 = 2860,
.maint_thres = 95,
.user_cap_limit = 15,
.pcut_enable = 1,
.pcut_max_time = 127,
.pcut_flag_time = 112,
.pcut_max_restart = 15,
.pcut_debounce_time = 2,
};
static const struct abx500_maxim_parameters maxi_params = {
static const struct abx500_maxim_parameters ab8500_maxi_params = {
.ena_maxi = true,
.chg_curr = 910,
.wait_cycles = 10,
.charger_curr_step = 100,
};
static const struct abx500_maxim_parameters abx540_maxi_params = {
.ena_maxi = true,
.chg_curr = 3000,
.wait_cycles = 10,
.charger_curr_step = 200,
};
static const struct abx500_bm_charger_parameters chg = {
.usb_volt_max = 5500,
.usb_curr_max = 1500,
@@ -423,6 +443,46 @@ static const struct abx500_bm_charger_parameters chg = {
.ac_curr_max = 1500,
};
/*
* This array maps the raw hex value to charger output current used by the
* AB8500 values
*/
static int ab8500_charge_output_curr_map[] = {
100, 200, 300, 400, 500, 600, 700, 800,
900, 1000, 1100, 1200, 1300, 1400, 1500, 1500,
};
static int ab8540_charge_output_curr_map[] = {
0, 0, 0, 75, 100, 125, 150, 175,
200, 225, 250, 275, 300, 325, 350, 375,
400, 425, 450, 475, 500, 525, 550, 575,
600, 625, 650, 675, 700, 725, 750, 775,
800, 825, 850, 875, 900, 925, 950, 975,
1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175,
1200, 1225, 1250, 1275, 1300, 1325, 1350, 1375,
1400, 1425, 1450, 1500, 1600, 1700, 1900, 2000,
};
/*
* This array maps the raw hex value to charger input current used by the
* AB8500 values
*/
static int ab8500_charge_input_curr_map[] = {
50, 98, 193, 290, 380, 450, 500, 600,
700, 800, 900, 1000, 1100, 1300, 1400, 1500,
};
static int ab8540_charge_input_curr_map[] = {
25, 50, 75, 100, 125, 150, 175, 200,
225, 250, 275, 300, 325, 350, 375, 400,
425, 450, 475, 500, 525, 550, 575, 600,
625, 650, 675, 700, 725, 750, 775, 800,
825, 850, 875, 900, 925, 950, 975, 1000,
1025, 1050, 1075, 1100, 1125, 1150, 1175, 1200,
1225, 1250, 1275, 1300, 1325, 1350, 1375, 1400,
1425, 1450, 1475, 1500, 1500, 1500, 1500, 1500,
};
struct abx500_bm_data ab8500_bm_data = {
.temp_under = 3,
.temp_low = 8,
@@ -442,22 +502,60 @@ struct abx500_bm_data ab8500_bm_data = {
.fg_res = 100,
.cap_levels = &cap_levels,
.bat_type = bat_type_thermistor,
.n_btypes = 3,
.n_btypes = ARRAY_SIZE(bat_type_thermistor),
.batt_id = 0,
.interval_charging = 5,
.interval_not_charging = 120,
.temp_hysteresis = 3,
.gnd_lift_resistance = 34,
.maxi = &maxi_params,
.chg_output_curr = ab8500_charge_output_curr_map,
.n_chg_out_curr = ARRAY_SIZE(ab8500_charge_output_curr_map),
.maxi = &ab8500_maxi_params,
.chg_params = &chg,
.fg_params = &fg,
.chg_input_curr = ab8500_charge_input_curr_map,
.n_chg_in_curr = ARRAY_SIZE(ab8500_charge_input_curr_map),
};
struct abx500_bm_data ab8540_bm_data = {
.temp_under = 3,
.temp_low = 8,
.temp_high = 43,
.temp_over = 48,
.main_safety_tmr_h = 4,
.temp_interval_chg = 20,
.temp_interval_nochg = 120,
.usb_safety_tmr_h = 4,
.bkup_bat_v = BUP_VCH_SEL_2P6V,
.bkup_bat_i = BUP_ICH_SEL_150UA,
.no_maintenance = false,
.capacity_scaling = false,
.adc_therm = ABx500_ADC_THERM_BATCTRL,
.chg_unknown_bat = false,
.enable_overshoot = false,
.fg_res = 100,
.cap_levels = &cap_levels,
.bat_type = bat_type_thermistor,
.n_btypes = ARRAY_SIZE(bat_type_thermistor),
.batt_id = 0,
.interval_charging = 5,
.interval_not_charging = 120,
.temp_hysteresis = 3,
.gnd_lift_resistance = 0,
.maxi = &abx540_maxi_params,
.chg_params = &chg,
.fg_params = &fg,
.chg_output_curr = ab8540_charge_output_curr_map,
.n_chg_out_curr = ARRAY_SIZE(ab8540_charge_output_curr_map),
.chg_input_curr = ab8540_charge_input_curr_map,
.n_chg_in_curr = ARRAY_SIZE(ab8540_charge_input_curr_map),
};
int ab8500_bm_of_probe(struct device *dev,
struct device_node *np,
struct abx500_bm_data *bm)
{
struct batres_vs_temp *tmp_batres_tbl;
const struct batres_vs_temp *tmp_batres_tbl;
struct device_node *battery_node;
const char *btech;
int i;

Some files were not shown because too many files have changed in this diff Show More