cw2017电量计芯片_b30c 电量校准

cw2017电量计芯片_b30c 电量校准platform:RK3288OS:Android7.1kernel:4.4cw2015电量计:dts中添加cw2015的设备节点:cw2015@62{status="okay";compatible="cw201x";reg=

大家好,欢迎来到IT知识分享网。

platform: RK3288

OS: Android7.1

kernel:4.4

 

cw2015电量计:

  dts中添加cw2015的设备节点:

cw2015@62 {
        status = "okay";
        compatible = "cw201x";
        reg = <0x62>;
        bat_config_info = <0x15 0x42 0x60 0x59 0x52 0x58 0x4D 0x48 0x48 0x44 0x44 0x46 0x49 0x48 0x32
        0x24 0x20 0x17 0x13 0x0F 0x19 0x3E 0x51 0x45 0x08 0x76 0x0B 0x85 0x0E 0x1C 0x2E 0x3E 0x4D 0x52 0x52
        0x57 0x3D 0x1B 0x6A 0x2D 0x25 0x43 0x52 0x87 0x8F 0x91 0x94 0x52 0x82 0x8C 0x92 0x96 0xFF 0x7B 0xBB
        0xCB 0x2F 0x7D 0x72 0xA5 0xB5 0xC1 0x46 0xAE>;
        monitor_sec = <5>;
        virtual_power = <0>;
        divider_res1 = <200>;
        divider_res2 = <200>;
    };

  对应驱动在drivers/power/cw2015_battery.c,但内核默认是没有编译该驱动的,需要进入menuconfig里面进行设置:make ARCH=arm menuconfig

  Device Drivers  —>

    -*- Power supply class support  —>

      [*]   CW2015 Battery driver

  选择好驱动后,硬件正常的话,一般都能正常跑起来,可以正常上报电池电量。但还不能检测充电器的拔插状态,这个功能下面会加上。

 

兼容bq27541:

  考虑到之前旧的主板电量计(bq27541,电量计是附带在电池里面的)可能也要维护使用,所以dts和驱动里面也要打开

bq27320: bq27320@55 {
        compatible = "ti,bq27541-g1";
        reg = <0x55>;
        status = "okay";
    };

  调试发现,当两个驱动都打开,实际上接的是不带电量计(bq27541)的电池时,这个时候无论接不接AC电源适配器,充电图标都是充电状态。这是因为bq27541的驱动有读取bq27541寄存器的代码,不接该电量计电池的时候,就会报错,导致上报的状态不对。我们需要把它屏蔽掉:

diff --git a/drivers/power/bq27541_battery.c b/drivers/power/bq27541_battery.c
index f46b719..3d84022 100755
--- a/drivers/power/bq27541_battery.c
+++ b/drivers/power/bq27541_battery.c
@@ -40,7 +40,7 @@ static int bq27541_read_reg(unsigned int reg){
 
 
 static void bq27541_battery_work(struct work_struct *work){
-       power_supply_changed(g_di->ac);
+       // power_supply_changed(g_di->ac);
        power_supply_changed(g_di->battery);
        schedule_delayed_work(&g_di->work, 6*HZ);
 }
@@ -64,7 +64,7 @@ static int bq27541_battery_status(void){
        int status = 0;
        status = bq27541_read_reg(0x0a);//REG_FLAGS
        if(status < 0){
-               printk("battery read flags error\n");
+               //printk("battery read flags error\n");
                //return 0;
        }
        status = (status<<0)&0x01;
@@ -203,8 +203,8 @@ static int bq27541_battery_probe(struct i2c_client *client,
        di->battery = power_supply_register(di->dev,&bq27541_bat_desc,
                                &battery_psy_cfg);
        
-       di->ac = power_supply_register(di->dev, &bq27541_ac_desc,
-                               &battery_psy_cfg);
+       // di->ac = power_supply_register(di->dev, &bq27541_ac_desc,
+       //                      &battery_psy_cfg);
 
        INIT_DELAYED_WORK(&di->work, bq27541_battery_work);
        schedule_delayed_work(&di->work, 15*HZ);
@@ -217,7 +217,7 @@ static int bq27541_battery_probe(struct i2c_client *client,
 static int bq27541_battery_remove(struct i2c_client *client){
 
        cancel_delayed_work_sync(&g_di->work);
-       power_supply_unregister(g_di->ac);
+       // power_supply_unregister(g_di->ac);
        power_supply_unregister(g_di->battery);
        return 0;
 }

但这样就没有充电检测功能了,硬件电路里面有加DC检查功能的gpio口,需要把这个功能用起来。

 

GPIO DC检测:

  由于有两个电量计驱动,为了兼容,所以这个gpio检测DC变化的功能就不能做在某一个单独的驱动里面,在 /kernel/drivers/power目录下刚好存在一个gpio-charger.c文件,这个刚好可以符合我们的这个需求。

menuconfig里面选择编译该驱动:

  Device Drivers  —>

    -*- Power supply class support  —>

      <*>   GPIO charger

dts中添加设备节点:

gpio-charger {
        status="okay";
        compatible = "gpio-charger";
        gpios = <&gpio0 8 GPIO_ACTIVE_LOW>;
        charger-type = "mains";
    };

这里的 charger-type选择的是mains,在代码中的解析如下:

cw2017电量计芯片_b30c 电量校准

参考cw2015_battery.c和bq27541_battery.c这两个驱动,ac模式时候type的注册都是POWER_SUPPLY_TYPE_MAINS

cw2017电量计芯片_b30c 电量校准

 

cw2017电量计芯片_b30c 电量校准

附上gpio-charger.c的代码:

  1 /*
  2  *  Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
  3  *  Driver for chargers which report their online status through a GPIO pin
  4  *
  5  *  This program is free software; you can redistribute it and/or modify it
  6  *  under  the terms of the GNU General  Public License as published by the
  7  *  Free Software Foundation;  either version 2 of the License, or (at your
  8  *  option) any later version.
  9  *
 10  *  You should have received a copy of the GNU General Public License along
 11  *  with this program; if not, write to the Free Software Foundation, Inc.,
 12  *  675 Mass Ave, Cambridge, MA 02139, USA.
 13  *
 14  */
 15 
 16 #include <linux/device.h>
 17 #include <linux/gpio.h>
 18 #include <linux/init.h>
 19 #include <linux/interrupt.h>
 20 #include <linux/kernel.h>
 21 #include <linux/module.h>
 22 #include <linux/platform_device.h>
 23 #include <linux/power_supply.h>
 24 #include <linux/slab.h>
 25 #include <linux/of.h>
 26 #include <linux/of_gpio.h>
 27 
 28 #include <linux/power/gpio-charger.h>
 29 
 30 struct gpio_charger {
 31     const struct gpio_charger_platform_data *pdata;
 32     unsigned int irq;
 33     bool wakeup_enabled;
 34 
 35     struct power_supply *charger;
 36     struct power_supply_desc charger_desc;
 37 };
 38 
 39 static irqreturn_t gpio_charger_irq(int irq, void *devid)
 40 {
 41     struct power_supply *charger = devid;
 42 
 43     power_supply_changed(charger);
 44 
 45     return IRQ_HANDLED;
 46 }
 47 
 48 static inline struct gpio_charger *psy_to_gpio_charger(struct power_supply *psy)
 49 {
 50     return power_supply_get_drvdata(psy);
 51 }
 52 
 53 static int gpio_charger_get_property(struct power_supply *psy,
 54         enum power_supply_property psp, union power_supply_propval *val)
 55 {
 56     struct gpio_charger *gpio_charger = psy_to_gpio_charger(psy);
 57     const struct gpio_charger_platform_data *pdata = gpio_charger->pdata;
 58 
 59     switch (psp) {
 60     case POWER_SUPPLY_PROP_ONLINE:
 61         val->intval = !!gpio_get_value_cansleep(pdata->gpio);
 62         val->intval ^= pdata->gpio_active_low;
 63         break;
 64     default:
 65         return -EINVAL;
 66     }
 67 
 68     return 0;
 69 }
 70 
 71 static enum power_supply_property gpio_charger_properties[] = {
 72     POWER_SUPPLY_PROP_ONLINE,
 73 };
 74 
 75 static
 76 struct gpio_charger_platform_data *gpio_charger_parse_dt(struct device *dev)
 77 {
 78     struct device_node *np = dev->of_node;
 79     struct gpio_charger_platform_data *pdata;
 80     const char *chargetype;
 81     enum of_gpio_flags flags;
 82     int ret;
 83 
 84     if (!np)
 85         return ERR_PTR(-ENOENT);
 86 
 87     pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
 88     if (!pdata)
 89         return ERR_PTR(-ENOMEM);
 90 
 91     pdata->name = np->name;
 92 
 93     pdata->gpio = of_get_gpio_flags(np, 0, &flags);
 94     if (pdata->gpio < 0) {
 95         if (pdata->gpio != -EPROBE_DEFER)
 96             dev_err(dev, "could not get charger gpio\n");
 97         return ERR_PTR(pdata->gpio);
 98     }
 99 
100     pdata->gpio_active_low = !!(flags & OF_GPIO_ACTIVE_LOW);
101 
102     pdata->type = POWER_SUPPLY_TYPE_UNKNOWN;
103     ret = of_property_read_string(np, "charger-type", &chargetype);
104     if (ret >= 0) {
105         if (!strncmp("unknown", chargetype, 7))
106             pdata->type = POWER_SUPPLY_TYPE_UNKNOWN;
107         else if (!strncmp("battery", chargetype, 7))
108             pdata->type = POWER_SUPPLY_TYPE_BATTERY;
109         else if (!strncmp("ups", chargetype, 3))
110             pdata->type = POWER_SUPPLY_TYPE_UPS;
111         else if (!strncmp("mains", chargetype, 5))
112             pdata->type = POWER_SUPPLY_TYPE_MAINS;
113         else if (!strncmp("usb-sdp", chargetype, 7))
114             pdata->type = POWER_SUPPLY_TYPE_USB;
115         else if (!strncmp("usb-dcp", chargetype, 7))
116             pdata->type = POWER_SUPPLY_TYPE_USB_DCP;
117         else if (!strncmp("usb-cdp", chargetype, 7))
118             pdata->type = POWER_SUPPLY_TYPE_USB_CDP;
119         else if (!strncmp("usb-aca", chargetype, 7))
120             pdata->type = POWER_SUPPLY_TYPE_USB_ACA;
121         else
122             dev_warn(dev, "unknown charger type %s\n", chargetype);
123     }
124 
125     return pdata;
126 }
127 
128 static int gpio_charger_probe(struct platform_device *pdev)
129 {
130     const struct gpio_charger_platform_data *pdata = pdev->dev.platform_data;
131     struct power_supply_config psy_cfg = {};
132     struct gpio_charger *gpio_charger;
133     struct power_supply_desc *charger_desc;
134     int ret;
135     int irq;
136 
137     if (!pdata) {
138         pdata = gpio_charger_parse_dt(&pdev->dev);
139         if (IS_ERR(pdata)) {
140             ret = PTR_ERR(pdata);
141             if (ret != -EPROBE_DEFER)
142                 dev_err(&pdev->dev, "No platform data\n");
143             return ret;
144         }
145     }
146 
147     if (!gpio_is_valid(pdata->gpio)) {
148         dev_err(&pdev->dev, "Invalid gpio pin\n");
149         return -EINVAL;
150     }
151 
152     gpio_charger = devm_kzalloc(&pdev->dev, sizeof(*gpio_charger),
153                     GFP_KERNEL);
154     if (!gpio_charger) {
155         dev_err(&pdev->dev, "Failed to alloc driver structure\n");
156         return -ENOMEM;
157     }
158 
159     charger_desc = &gpio_charger->charger_desc;
160 
161     charger_desc->name = pdata->name ? pdata->name : "gpio-charger";
162     charger_desc->type = pdata->type;
163     charger_desc->properties = gpio_charger_properties;
164     charger_desc->num_properties = ARRAY_SIZE(gpio_charger_properties);
165     charger_desc->get_property = gpio_charger_get_property;
166 
167     psy_cfg.supplied_to = pdata->supplied_to;
168     psy_cfg.num_supplicants = pdata->num_supplicants;
169     psy_cfg.of_node = pdev->dev.of_node;
170     psy_cfg.drv_data = gpio_charger;
171 
172     ret = gpio_request(pdata->gpio, dev_name(&pdev->dev));
173     if (ret) {
174         dev_err(&pdev->dev, "Failed to request gpio pin: %d\n", ret);
175         goto err_free;
176     }
177     ret = gpio_direction_input(pdata->gpio);
178     if (ret) {
179         dev_err(&pdev->dev, "Failed to set gpio to input: %d\n", ret);
180         goto err_gpio_free;
181     }
182 
183     gpio_charger->pdata = pdata;
184 
185     gpio_charger->charger = power_supply_register(&pdev->dev,
186                               charger_desc, &psy_cfg);
187     if (IS_ERR(gpio_charger->charger)) {
188         ret = PTR_ERR(gpio_charger->charger);
189         dev_err(&pdev->dev, "Failed to register power supply: %d\n",
190             ret);
191         goto err_gpio_free;
192     }
193 
194     irq = gpio_to_irq(pdata->gpio);
195     if (irq > 0) {
196         ret = request_any_context_irq(irq, gpio_charger_irq,
197                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
198                 dev_name(&pdev->dev), gpio_charger->charger);
199         if (ret < 0)
200             dev_warn(&pdev->dev, "Failed to request irq: %d\n", ret);
201         else
202             gpio_charger->irq = irq;
203     }
204 
205     platform_set_drvdata(pdev, gpio_charger);
206 
207     device_init_wakeup(&pdev->dev, 1);
208 
209     return 0;
210 
211 err_gpio_free:
212     gpio_free(pdata->gpio);
213 err_free:
214     return ret;
215 }
216 
217 static int gpio_charger_remove(struct platform_device *pdev)
218 {
219     struct gpio_charger *gpio_charger = platform_get_drvdata(pdev);
220 
221     if (gpio_charger->irq)
222         free_irq(gpio_charger->irq, gpio_charger->charger);
223 
224     power_supply_unregister(gpio_charger->charger);
225 
226     gpio_free(gpio_charger->pdata->gpio);
227 
228     return 0;
229 }
230 
231 #ifdef CONFIG_PM_SLEEP
232 static int gpio_charger_suspend(struct device *dev)
233 {
234     struct gpio_charger *gpio_charger = dev_get_drvdata(dev);
235 
236     if (device_may_wakeup(dev))
237         gpio_charger->wakeup_enabled =
238             !enable_irq_wake(gpio_charger->irq);
239 
240     return 0;
241 }
242 
243 static int gpio_charger_resume(struct device *dev)
244 {
245     struct platform_device *pdev = to_platform_device(dev);
246     struct gpio_charger *gpio_charger = platform_get_drvdata(pdev);
247 
248     if (device_may_wakeup(dev) && gpio_charger->wakeup_enabled)
249         disable_irq_wake(gpio_charger->irq);
250     power_supply_changed(gpio_charger->charger);
251 
252     return 0;
253 }
254 #endif
255 
256 static SIMPLE_DEV_PM_OPS(gpio_charger_pm_ops,
257         gpio_charger_suspend, gpio_charger_resume);
258 
259 static const struct of_device_id gpio_charger_match[] = {
260     { .compatible = "gpio-charger" },
261     { }
262 };
263 MODULE_DEVICE_TABLE(of, gpio_charger_match);
264 
265 static struct platform_driver gpio_charger_driver = {
266     .probe = gpio_charger_probe,
267     .remove = gpio_charger_remove,
268     .driver = {
269         .name = "gpio-charger",
270         .pm = &gpio_charger_pm_ops,
271         .of_match_table = gpio_charger_match,
272     },
273 };
274 
275 module_platform_driver(gpio_charger_driver);
276 
277 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
278 MODULE_DESCRIPTION("Driver for chargers which report their online status through a GPIO");
279 MODULE_LICENSE("GPL");
280 MODULE_ALIAS("platform:gpio-charger");

 

这样,两个电量计的电量读取上报以及充电检测的功能就实现了。

参考:https://blog.csdn.net/oliverJ/article/details/104018558

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/28134.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信