1,硬件实现:电池 NTC电阻电路如下图左侧,NTC电阻与一个10K电阻并联分压,上拉电阻为10K。CPU端通过ADC_IN2读取电压值
2,查看使用的10KC热敏电阻CN0603R103B3435JT芯片书册,查看电阻温度对照表:
3,软件实现,请参考如下:
diff --git a/arch/arm64/boot/dts/rockchip/tablet.dtsi b/arch/arm64/boot/dts/rockchip/tablet.dtsi
index ff7d463..e6ea15d 100644
--- a/arch/arm64/boot/dts/rockchip/tablet.dtsi
+++ b/arch/arm64/boot/dts/rockchip/tablet.dtsi
@@ -195,6 +195,12 @@
};
};
+ adc_temp: adc-temp {
+ compatible = "adc-bat-temperature";
+ io-channels = <&saradc 0>;
+ io-channel-names = "temp";
+ };
+
sdio_pwrseq: sdio-pwrseq {
compatible = "mmc-pwrseq-simple";
clocks = <&rk808 1>;
@@ -798,6 +804,7 @@
};
&saradc {
+ vref-supply = <&vcc18_flash>;
status = "okay";
};
diff --git a/arch/arm64/configs/tablet_defconfig b/arch/arm64/configs/tablet_defconfig
index 3697548..4a14f6d 100644
--- a/arch/arm64/configs/tablet_defconfig
+++ b/arch/arm64/configs/tablet_defconfig
@@ -516,6 +516,7 @@ CONFIG_BATTERY_RK817=y
CONFIG_CHARGER_RK817=y
CONFIG_BATTERY_RK818=y
CONFIG_CHARGER_RK818=y
+CONFIG_BAT_TEMP=y
CONFIG_THERMAL=y
CONFIG_THERMAL_WRITABLE_TRIPS=y
CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR=y
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index a972ebd..3b25573 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -558,6 +558,11 @@ config CHARGER_SGM41510
help
Say Y to enable support for the SGM41510 battery charger.
+config BAT_TEMP
+ tristate "battery temperature driver"
+ help
+ Say Y to enable support for the battery temperature.
+
config CHARGER_BQ24257
tristate "TI BQ24250/24251/24257 battery charger driver"
depends on I2C
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 02e7794..409cdc3 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -93,3 +93,4 @@ obj-$(CONFIG_CHARGER_RK817) += rk817_charger.o
obj-$(CONFIG_BATTERY_RK818) += rk818_battery.o
obj-$(CONFIG_CHARGER_RK818) += rk818_charger.o
obj-$(CONFIG_CHARGER_SGM41510) += sgm41510_charger.o
+obj-$(CONFIG_BAT_TEMP) += battery_temp.o
diff --git a/drivers/power/supply/battery_temp.c b/drivers/power/supply/battery_temp.c
new file mode 100644
index 0000000..e5684c7
--- /dev/null
+++ b/drivers/power/supply/battery_temp.c
@@ -0,0 +1,220 @@
+/*
+ * Input driver for resistor ladder connected on ADC
+ *
+ * Copyright (c) 2016 Alexandre Belloni
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/iio/consumer.h>
+#include <linux/iio/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/jiffies.h>
+
+
+struct adc_bat_temp_state {
+ struct delayed_work update_work;
+ struct iio_channel *channel;
+ int temperature;
+};
+
+struct temp_data {
+ int tempR;
+ int tempC;
+};
+
+struct adc_bat_temp_state *g_adc_bat_temp;
+
+int g_value = -1;
+
+static const struct temp_data bat_temp_table[] = {
+ {1956520, -40}, {1849171, -39}, {1748452, -38}, {1653910, -37}, {1565125, -36},
+ {1481710, -35}, {1403304, -34}, {1329576, -33}, {1260215, -32}, {1194936, -31},
+ {1133471, -30}, {1075649, -29}, {1021155, -28}, {969776, -27}, {921315, -26},
+ {875588, -25}, {832424, -24}, {791663, -23}, {753157, -22}, {716768, -21},
+ {682367, -20}, {649907, -19}, {619190, -18}, {590113, -17}, {562579, -16},
+ {536496, -15}, {511779, -14}, {488349, -13}, {466132, -12}, {445058, -11},
+ {425062, -10}, {405997, -9}, {387905, -8}, {370729, -7}, {354417, -6},
+ {338922, -5}, {324197, -4}, {310200, -3}, {296890, -2}, {284231, -1},
+ {272186, 0}, {260760, 1}, {249877, 2}, {239509, 3}, {229629, 4},
+ {220211, 5}, {211230, 6}, {202666, 7}, {194495, 8}, {186698, 9},
+ {179255, 10}, {172139, 11}, {165344, 12}, {158856, 13}, {152658, 14},
+ {146735, 15}, {141075, 16}, {135664, 17}, {130489, 18}, {125540, 19},
+ {120805, 20}, {116281, 21}, {111947, 22}, {107795, 23}, {103815, 24},
+ {100000, 25}, {96342, 26}, {92835, 27}, {89470, 28}, {86242, 29},
+ {83145, 30}, {80181, 31}, {77337, 32}, {74609, 33}, {71991, 34},
+ {69479, 35}, {67067, 36}, {64751, 37}, {62526, 38}, {60390, 39},
+ {58336, 40}, {56357, 41}, {54454, 42}, {52623, 43}, {50863, 44},
+ {49169, 45}, {47539, 46}, {45971, 47}, {44461, 48}, {43008, 49},
+ {41609, 50}, {40262, 51}, {38964, 52}, {37714, 53}, {36510, 54},
+ {35350, 55}, {34231, 56}, {33152, 57}, {32113, 58}, {31110, 59},
+ {30143, 60}, {29224, 61}, {28337, 62}, {27482, 63}, {26657, 64},
+ {25861, 65}, {25093, 66}, {24351, 67}, {23635, 68}, {22943, 69},
+ {22275, 70}, {21627, 71}, {21001, 72}, {20396, 73}, {19811, 74},
+ {19245, 75}, {18698, 76}, {18170, 77}, {17658, 78}, {17164, 79},
+ {16685, 80}, {16224, 81}, {15777, 82}, {15345, 83}, {14927, 84},
+ {14521, 85}, {14129, 86}, {13749, 87}, {13381, 88}, {13025, 89},
+ {12680, 90}, {12343, 91}, {12016, 92}, {11700, 93}, {11393, 94},
+ {11096, 95}, {10807, 96}, {10528, 97}, {10256, 98}, {9993, 99},
+ {9738, 100}, {9492, 101}, {9254, 102}, {9022, 103}, {8798, 104},
+
+};
+
+#define BAT_TEMP_TEBLE_NUM (sizeof(bat_temp_table) / sizeof(bat_temp_table[0]))
+
+static int temp_adc_cal(const int val)
+{
+ int i = 0;
+ int tempR = 0;
+ int retV = 0;
+
+ if (val <= 0)
+ {
+ return -1;
+ }
+
+ /* V = 1.8/1024*ADC_VAL */
+ //tempC = (val / (1024 / 18));
+
+ /* V(NTC)=1.8/(10+R)*R */
+ tempR = ((10000 * val) / (1800 - val))*10;
+ if (tempR <= 0)
+ {
+ tempR = (-tempR);
+ }
+
+ /* tempR -> tempC */
+ for (i = 0; i < (BAT_TEMP_TEBLE_NUM - 1); i++)
+ {
+ if ((tempR > bat_temp_table[i + 1].tempR) && (tempR <= bat_temp_table[i].tempR))
+ {
+ retV = bat_temp_table[i].tempC;
+ break;
+ }
+ }
+ //printk("%s---%d: tempR= %d, retV=%d\n",__func__,__LINE__,tempR,retV);
+
+ return retV;
+}
+
+int get_bat_temp(void)
+{
+ return g_value;
+}
+EXPORT_SYMBOL(get_bat_temp);
+
+static void adc_bat_temp_poll(struct adc_bat_temp_state *state)
+{
+ struct adc_bat_temp_state *st = state;
+ int value, ret;
+
+ ret = iio_read_channel_processed(st->channel, &value);
+ if (unlikely(ret < 0)) {
+ /* Forcibly release key if any was pressed */
+ printk("%s --- %d adc chanel error\n", __func__,__LINE__);
+ } else {
+ //printk("%s --- %d adc chanel val=%d\n", __func__,__LINE__,value);
+ st->temperature = temp_adc_cal(value)*10;
+ }
+ g_value = st->temperature;
+ //printk("%s --- %d, temperature = %d\n", __func__,__LINE__,g_value);
+}
+
+static void my_work(struct work_struct *work)
+{
+ struct adc_bat_temp_state *st = container_of(work, struct adc_bat_temp_state,
+ update_work.work);
+ //int ret;
+ //printk("%s %d\n",__func__,__LINE__);
+ adc_bat_temp_poll(st);
+ queue_delayed_work(system_wq, &st->update_work,
+ msecs_to_jiffies(1000));
+}
+
+static int adc_keys_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct adc_bat_temp_state *st;
+ enum iio_chan_type type;
+ //int value;
+ int error;
+
+ st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
+ if (!st)
+ return -ENOMEM;
+
+ st->channel = devm_iio_channel_get(dev, "temp");
+ if (IS_ERR(st->channel))
+ return PTR_ERR(st->channel);
+
+ if (!st->channel->indio_dev)
+ return -ENXIO;
+
+ error = iio_get_channel_type(st->channel, &type);
+ if (error < 0)
+ return error;
+
+ if (type != IIO_VOLTAGE) {
+ dev_err(dev, "Incompatible channel type %d\n", type);
+ return -EINVAL;
+ }
+/*
+ if (device_property_read_u32(dev, "keyup-threshold-microvolt",
+ &st->keyup_voltage)) {
+ dev_err(dev, "Invalid or missing keyup voltage\n");
+ return -EINVAL;
+ }
+*/
+ st->temperature = -1;
+ g_adc_bat_temp = st;
+
+ INIT_DELAYED_WORK(&st->update_work,
+ my_work);
+ queue_delayed_work(system_wq, &st->update_work, msecs_to_jiffies(300));
+
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id adc_bat_temp_of_match[] = {
+ { .compatible = "adc-bat-temperature", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, adc_bat_temp_of_match);
+#endif
+
+static struct platform_driver __refdata adc_battery_temp_driver = {
+ .driver = {
+ .name = "adc_batterry_temp",
+ .of_match_table = of_match_ptr(adc_bat_temp_of_match),
+ },
+ .probe = adc_keys_probe,
+};
+
+static int __init bat_temp_driver_init(void)
+{
+ return platform_driver_register(&adc_battery_temp_driver);
+}
+
+fs_initcall_sync(bat_temp_driver_init);
+
+static void __exit bat_temp_driver_exit(void)
+{
+ platform_driver_unregister(&adc_battery_temp_driver);
+}
+module_exit(bat_temp_driver_exit);
+
+MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>");
+MODULE_DESCRIPTION("Battery temp for resistor ladder connected on ADC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/supply/cw2015_battery.c b/drivers/power/supply/cw2015_battery.c
index a1d9ab9..ce6678e 100644
--- a/drivers/power/supply/cw2015_battery.c
+++ b/drivers/power/supply/cw2015_battery.c
@@ -49,6 +49,8 @@ static int cw_read_word(struct i2c_client *client, u8 reg, u8 buf[])
return i2c_smbus_read_i2c_block_data(client, reg, 2, buf);
}
+extern int get_bat_temp(void);//add by andy
+
int cw_update_config_info(struct cw_battery *cw_bat)
{
int ret;
@@ -661,7 +663,7 @@ static int cw_battery_get_property(struct power_supply *psy,
break;
case POWER_SUPPLY_PROP_TEMP:
- val->intval = VIRTUAL_TEMPERATURE;
+ val->intval = get_bat_temp();
break;
default: