通过ntc热敏电阻实现电池温度检测

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:

  • 28
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沫沫罗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值