[PATCH 2/4] charger-manager: Use IIO subsystem to read batterytemperature instead of legacy method

From: Chanwoo Choi
Date: Tue Oct 22 2013 - 08:53:10 EST


This patch support charger-manager use IIO(Industrial I/O) subsystem to read
current battery temperature instead of legacy methor about callback function.

Signed-off-by: Chanwoo Choi <cw00.choi@xxxxxxxxxxx>
Signed-off-by: Kyungmin Park <kyungmin.park@xxxxxxxxxxx>
Signed-off-by: Myungjoo Ham <myungjoo.ham@xxxxxxxxxxx>
---
drivers/power/Kconfig | 1 +
drivers/power/charger-manager.c | 88 +++++++++++++++++++++++++++++++++--
include/linux/power/charger-manager.h | 13 ++++++
3 files changed, 97 insertions(+), 5 deletions(-)

diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index e6f92b4..6700191 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -309,6 +309,7 @@ config CHARGER_MANAGER
bool "Battery charger manager for multiple chargers"
depends on REGULATOR && RTC_CLASS
select EXTCON
+ select IIO
help
Say Y to enable charger-manager support, which allows multiple
chargers attached to a battery and multiple batteries attached to a
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c
index cc720f9..02a395c 100644
--- a/drivers/power/charger-manager.c
+++ b/drivers/power/charger-manager.c
@@ -26,6 +26,7 @@
#include <linux/regulator/consumer.h>
#include <linux/sysfs.h>
#include <linux/of.h>
+#include <linux/iio/consumer.h>

static const char * const default_event_names[] = {
[CM_EVENT_UNKNOWN] = "Unknown",
@@ -542,6 +543,50 @@ static int check_charging_duration(struct charger_manager *cm)
}

/**
+ * read_battery_temperature - Read current battery temperature
+ * @cm: the Charger Manager representing the battery.
+ * @last_temp_mC: store current battery temperature
+ *
+ * Returns current state of temperature by using IIO or legacy method
+ * - CM_TEMP_NORMAL
+ * - CM_TEMP_OVERHEAT
+ * - CM_TEMP_COLD
+ */
+static int read_battery_temperature(struct charger_manager *cm,
+ int *last_temp_mC)
+{
+ struct charger_desc *desc = cm->desc;
+ int temp;
+
+ if (desc->channel) {
+ temp = iio_read_channel_raw(desc->channel, last_temp_mC);
+
+ /*
+ * The charger-manager use IIO subsystem to read ADC raw data
+ * from IIO ADC device drvier. The each device driver has
+ * own non-standard ADC table. If user of charger-manager
+ * would like to get correct temperature value, have to convert
+ * 'last_temp_mC' variable according to proper calculation
+ * method and own ADC table.
+ */
+
+ if (*last_temp_mC >= desc->iio_adc_overheat)
+ temp = CM_TEMP_NORMAL; /* Overheat */
+ else if (*last_temp_mC <= desc->iio_adc_cold)
+ temp = CM_TEMP_COLD; /* Cold */
+ else
+ temp = CM_TEMP_NORMAL; /* Normal */
+
+ } else if (desc->temperature_out_of_range) {
+ temp = desc->temperature_out_of_range(last_temp_mC);
+ } else {
+ temp = INT_MAX;
+ }
+
+ return temp;
+}
+
+/**
* _cm_monitor - Monitor the temperature and return true for exceptions.
* @cm: the Charger Manager representing the battery.
*
@@ -551,7 +596,7 @@ static int check_charging_duration(struct charger_manager *cm)
static bool _cm_monitor(struct charger_manager *cm)
{
struct charger_desc *desc = cm->desc;
- int temp = desc->temperature_out_of_range(&cm->last_temp_mC);
+ int temp = read_battery_temperature(cm, &cm->last_temp_mC);

dev_dbg(cm->dev, "monitoring (%2.2d.%3.3dC)\n",
cm->last_temp_mC / 1000, cm->last_temp_mC % 1000);
@@ -805,7 +850,7 @@ static int charger_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_TEMP:
/* in thenth of centigrade */
if (cm->last_temp_mC == INT_MIN)
- desc->temperature_out_of_range(&cm->last_temp_mC);
+ read_battery_temperature(cm, &cm->last_temp_mC);
val->intval = cm->last_temp_mC / 100;
if (!desc->measure_battery_temp)
ret = -ENODEV;
@@ -813,7 +858,7 @@ static int charger_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_TEMP_AMBIENT:
/* in thenth of centigrade */
if (cm->last_temp_mC == INT_MIN)
- desc->temperature_out_of_range(&cm->last_temp_mC);
+ read_battery_temperature(cm, &cm->last_temp_mC);
val->intval = cm->last_temp_mC / 100;
if (desc->measure_battery_temp)
ret = -ENODEV;
@@ -1586,6 +1631,32 @@ static int charger_manager_dt_parse_regulator(struct device *dev,
return 0;
}

+static int charger_manager_dt_parse_iio(struct device *dev,
+ struct charger_desc *desc)
+{
+ struct device_node *np = dev->of_node;
+
+ if (of_property_read_u32(np, "iio-adc-overheat",
+ &desc->iio_adc_overheat)) {
+ dev_warn(dev, "cannot get standard value for hot temperature\n");
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32(np, "iio-adc-cold",
+ &desc->iio_adc_cold)) {
+ dev_warn(dev, "cannot get standard value for cold temperature\n");
+ return -EINVAL;
+ }
+
+ desc->channel = iio_channel_get(dev, NULL);
+ if (IS_ERR(desc->channel)) {
+ dev_err(dev, "cannot get iio channel\n");
+ return PTR_ERR(desc->channel);
+ }
+
+ return 0;
+}
+
static struct charger_desc *charger_manager_dt_parse(struct device *dev)
{
struct device_node *np = dev->of_node;
@@ -1688,6 +1759,11 @@ static struct charger_desc *charger_manager_dt_parse(struct device *dev)
desc->charging_max_duration_ms *= (60 * 1000);
desc->discharging_max_duration_ms *= (60 * 1000);

+ if (charger_manager_dt_parse_iio(dev, desc)) {
+ dev_err(dev, "cannot get iio device to read temperature\n");
+ return NULL;
+ }
+
return desc;
}
#else
@@ -1814,8 +1890,8 @@ static int charger_manager_probe(struct platform_device *pdev)
goto err_chg_stat;
}

- if (!desc->temperature_out_of_range) {
- dev_err(&pdev->dev, "there is no temperature_out_of_range\n");
+ if (!desc->channel && !desc->temperature_out_of_range) {
+ dev_err(&pdev->dev, "there is no temperature function\n");
ret = -EINVAL;
goto err_chg_stat;
}
@@ -1986,6 +2062,8 @@ static int charger_manager_remove(struct platform_device *pdev)

try_charger_enable(cm, false);

+ iio_channel_release(desc->channel);
+
kfree(cm->charger_psy.properties);
kfree(cm->charger_stat);
kfree(cm->desc);
diff --git a/include/linux/power/charger-manager.h b/include/linux/power/charger-manager.h
index 8696fb8..33dfc69 100644
--- a/include/linux/power/charger-manager.h
+++ b/include/linux/power/charger-manager.h
@@ -42,6 +42,12 @@ enum cm_event_types {
CM_EVENT_OTHERS,
};

+enum cm_temperature_types {
+ CM_TEMP_COLD = -1,
+ CM_TEMP_NORMAL = 0,
+ CM_TEMP_OVERHEAT = 1,
+};
+
/**
* struct charger_global_desc
* @rtc_name: the name of RTC used to wake up the system from suspend.
@@ -188,6 +194,9 @@ struct charger_regulator {
* Maximum possible duration for discharging with charger cable
* after full-batt. If discharging duration exceed 'discharging
* max_duration_ms', cm start charging.
+ * @channel: filled with a channel from iio
+ * @iio_adc_overheat: the value of the highest ADC for temperature
+ * @iio_adc_cold: the value of the lowest ADC for temperature
*/
struct charger_desc {
const char *psy_name;
@@ -215,6 +224,10 @@ struct charger_desc {

unsigned int charging_max_duration_ms;
unsigned int discharging_max_duration_ms;
+
+ struct iio_channel *channel;
+ int iio_adc_overheat;
+ int iio_adc_cold;
};

#define PSY_NAME_MAX 30
--
1.8.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/