• Android充电驱动bq24375源码分析


    这个驱动的源码还是比较简单的,我把源码中的函数都写上了中文注释。驱动虽小,五脏俱全。是学习硬件驱动的好例子。

    看驱动源码, 一定要先看芯片的PDF文档,重点是寄存器部分。对照文档和代码才能明白其中的关键代码。

    文档下载地址:https://download.csdn.net/download/langeldep/87009997

    1. /*
    2. * Battery charger driver for TI BQ24735
    3. *
    4. * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved.
    5. *
    6. * This program is free software; you can redistribute it and/or modify
    7. * it under the terms of the GNU General Public License as published by
    8. * the Free Software Foundation;
    9. *
    10. * This program is distributed in the hope that it will be useful, but WITHOUT
    11. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    12. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
    13. * more details.
    14. *
    15. * You should have received a copy of the GNU General Public License along
    16. * with this program; if not, write to the Free Software Foundation, Inc.,
    17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
    18. */
    19. #include
    20. #include
    21. #include
    22. #include
    23. #include
    24. #include
    25. #include
    26. #include
    27. #include
    28. #include
    29. #include
    30. #include
    31. #include
    32. #include
    33. #define BQ24735_CHG_OPT 0x12
    34. #define BQ24735_CHG_OPT_CHARGE_DISABLE (1 << 0)
    35. #define BQ24735_CHG_OPT_AC_PRESENT (1 << 4)
    36. #define BQ24735_CHARGE_CURRENT 0x14
    37. #define BQ24735_CHARGE_CURRENT_MASK 0x1fc0
    38. #define BQ24735_CHARGE_VOLTAGE 0x15
    39. #define BQ24735_CHARGE_VOLTAGE_MASK 0x7ff0
    40. #define BQ24735_INPUT_CURRENT 0x3f
    41. #define BQ24735_INPUT_CURRENT_MASK 0x1f80
    42. #define BQ24735_MANUFACTURER_ID 0xfe
    43. #define BQ24735_DEVICE_ID 0xff
    44. /*
    45. 0x12H ChargeOption() Read or Write Charger Options Control 0xF902H
    46. 0x14H ChargeCurrent() Read or Write 7-Bit Charge Current Setting 0x0000H
    47. 0x15H ChargeVoltage() Read or Write 11-Bit Charge Voltage Setting 0x0000H
    48. 0x3FH InputCurrent() Read or Write 6-Bit Input Current Setting 0x1000H
    49. 0XFEH ManufacturerID() Read Only Manufacturer ID 0x0040H
    50. 0xFFH DeviceID() Read Only Device ID 0x000BH
    51. */
    52. struct bq24735_platform {
    53. uint32_t charge_current;
    54. uint32_t charge_voltage;
    55. uint32_t input_current;
    56. const char *name;
    57. bool ext_control;
    58. char **supplied_to;
    59. size_t num_supplicants;
    60. };
    61. struct bq24735 {
    62. struct power_supply *charger;
    63. struct power_supply_desc charger_desc;
    64. struct i2c_client *client;
    65. struct bq24735_platform *pdata;
    66. struct mutex lock;
    67. struct gpio_desc *status_gpio;
    68. struct delayed_work poll;
    69. u32 poll_interval;
    70. bool charging;
    71. };
    72. //通过psy的指针获取自定义的结构体指针
    73. static inline struct bq24735 *to_bq24735(struct power_supply *psy)
    74. {
    75. return power_supply_get_drvdata(psy);
    76. }
    77. static enum power_supply_property bq24735_charger_properties[] = {
    78. POWER_SUPPLY_PROP_STATUS,
    79. POWER_SUPPLY_PROP_ONLINE,
    80. };
    81. //判断属性是否可写
    82. static int bq24735_charger_property_is_writeable(struct power_supply *psy, enum power_supply_property psp)
    83. {
    84. switch (psp) {
    85. case POWER_SUPPLY_PROP_STATUS:
    86. return 1;
    87. default:
    88. break;
    89. }
    90. return 0;
    91. }
    92. //给寄存器写2个字节的值
    93. static inline int bq24735_write_word(struct i2c_client *client, u8 reg, u16 value)
    94. {
    95. return i2c_smbus_write_word_data(client, reg, value);
    96. }
    97. //读取寄存器两个字节的值
    98. static inline int bq24735_read_word(struct i2c_client *client, u8 reg)
    99. {
    100. return i2c_smbus_read_word_data(client, reg);
    101. }
    102. //先读取寄存器,再写入寄存器
    103. static int bq24735_update_word(struct i2c_client *client, u8 reg, u16 mask, u16 value)
    104. {
    105. unsigned int tmp;
    106. int ret;
    107. ret = bq24735_read_word(client, reg);
    108. if (ret < 0)
    109. return ret;
    110. tmp = ret & ~mask;
    111. tmp |= value & mask;
    112. return bq24735_write_word(client, reg, tmp);
    113. }
    114. /*
    115. 配置充电器,往寄存器写入电流值,电压值,输入电流值,而这三个值是从设备树中读取出来的
    116. pdata->charge_current = "ti,charge-current"
    117. pdata->charge_voltage = "ti,charge-voltage"
    118. pdata->input_current = "ti,input-current"
    119. */
    120. static int bq24735_config_charger(struct bq24735 *charger)
    121. {
    122. struct bq24735_platform *pdata = charger->pdata;
    123. int ret;
    124. u16 value;
    125. if (pdata->ext_control)
    126. return 0;
    127. if (pdata->charge_current) {
    128. value = pdata->charge_current & BQ24735_CHARGE_CURRENT_MASK;
    129. ret = bq24735_write_word(charger->client, BQ24735_CHARGE_CURRENT, value);//电流
    130. if (ret < 0) {
    131. dev_err(&charger->client->dev, "Failed to write charger current : %d\n", ret);
    132. return ret;
    133. }
    134. }
    135. if (pdata->charge_voltage) {
    136. value = pdata->charge_voltage & BQ24735_CHARGE_VOLTAGE_MASK;
    137. ret = bq24735_write_word(charger->client, BQ24735_CHARGE_VOLTAGE, value);//电压
    138. if (ret < 0) {
    139. dev_err(&charger->client->dev, "Failed to write charger voltage : %d\n", ret);
    140. return ret;
    141. }
    142. }
    143. if (pdata->input_current) {
    144. value = pdata->input_current & BQ24735_INPUT_CURRENT_MASK;
    145. ret = bq24735_write_word(charger->client, BQ24735_INPUT_CURRENT, value);//输入电流
    146. if (ret < 0) {
    147. dev_err(&charger->client->dev, "Failed to write input current : %d\n", ret);
    148. return ret;
    149. }
    150. }
    151. return 0;
    152. }
    153. //使能充电器:先初始化寄存器的值,然后再获取对充电器的控制,就是往BQ24735_CHG_OPT=0x12寄存器写入数据
    154. static inline int bq24735_enable_charging(struct bq24735 *charger)
    155. {
    156. int ret;
    157. if (charger->pdata->ext_control)
    158. return 0;
    159. ret = bq24735_config_charger(charger);
    160. if (ret)
    161. return ret;
    162. return bq24735_update_word(charger->client, BQ24735_CHG_OPT, BQ24735_CHG_OPT_CHARGE_DISABLE, 0);
    163. }
    164. //消能充电器:
    165. static inline int bq24735_disable_charging(struct bq24735 *charger)
    166. {
    167. if (charger->pdata->ext_control)
    168. return 0;
    169. return bq24735_update_word(charger->client, BQ24735_CHG_OPT, BQ24735_CHG_OPT_CHARGE_DISABLE, 1);
    170. }
    171. //判断充电器是否存在,查看pdf文件中的 0x12H 寄存器的值
    172. static bool bq24735_charger_is_present(struct bq24735 *charger)
    173. {
    174. if (charger->status_gpio) {
    175. return !gpiod_get_value_cansleep(charger->status_gpio);
    176. } else {
    177. int ac = 0;
    178. ac = bq24735_read_word(charger->client, BQ24735_CHG_OPT);
    179. if (ac < 0) {
    180. dev_dbg(&charger->client->dev, "Failed to read charger options : %d\n", ac);
    181. return false;
    182. }
    183. return (ac & BQ24735_CHG_OPT_AC_PRESENT) ? true : false;//判断第四位是否为1
    184. }
    185. return false;
    186. }
    187. //判断充电器是否正在充电中。。。。
    188. //
    189. static int bq24735_charger_is_charging(struct bq24735 *charger)
    190. {
    191. int ret;
    192. //设备不存在,则返回0
    193. if (!bq24735_charger_is_present(charger))
    194. return 0;
    195. //读取寄存器的值
    196. ret = bq24735_read_word(charger->client, BQ24735_CHG_OPT);
    197. if (ret < 0)
    198. return ret;
    199. //返回寄存器的第0位的值
    200. return !(ret & BQ24735_CHG_OPT_CHARGE_DISABLE);
    201. }
    202. //更新充电设备状态
    203. static void bq24735_update(struct bq24735 *charger)
    204. {
    205. mutex_lock(&charger->lock);
    206. if (charger->charging && bq24735_charger_is_present(charger))
    207. bq24735_enable_charging(charger);
    208. else
    209. bq24735_disable_charging(charger);
    210. mutex_unlock(&charger->lock);
    211. power_supply_changed(charger->charger);
    212. }
    213. //中断处理回调函数
    214. static irqreturn_t bq24735_charger_isr(int irq, void *devid)
    215. {
    216. struct power_supply *psy = devid;
    217. struct bq24735 *charger = to_bq24735(psy);
    218. bq24735_update(charger);
    219. return IRQ_HANDLED;
    220. }
    221. //设备主循环
    222. static void bq24735_poll(struct work_struct *work)
    223. {
    224. struct bq24735 *charger = container_of(work, struct bq24735, poll.work);
    225. bq24735_update(charger);
    226. schedule_delayed_work(&charger->poll, msecs_to_jiffies(charger->poll_interval));
    227. }
    228. //获取充电设备的属性值
    229. static int bq24735_charger_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val)
    230. {
    231. struct bq24735 *charger = to_bq24735(psy);
    232. switch (psp) {
    233. case POWER_SUPPLY_PROP_ONLINE://设备是否存在
    234. val->intval = bq24735_charger_is_present(charger) ? 1 : 0;
    235. break;
    236. case POWER_SUPPLY_PROP_STATUS://设备状态
    237. switch (bq24735_charger_is_charging(charger)) {
    238. case 1:
    239. val->intval = POWER_SUPPLY_STATUS_CHARGING;
    240. break;
    241. case 0:
    242. val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
    243. break;
    244. default:
    245. val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
    246. break;
    247. }
    248. break;
    249. default:
    250. return -EINVAL;
    251. }
    252. return 0;
    253. }
    254. //设置充电器属性:设置充电状态,取消充电状态
    255. static int bq24735_charger_set_property(struct power_supply *psy, enum power_supply_property psp, const union power_supply_propval *val)
    256. {
    257. struct bq24735 *charger = to_bq24735(psy);
    258. int ret;
    259. switch (psp) {
    260. case POWER_SUPPLY_PROP_STATUS:
    261. switch (val->intval) {
    262. case POWER_SUPPLY_STATUS_CHARGING:
    263. mutex_lock(&charger->lock);
    264. charger->charging = true;
    265. ret = bq24735_enable_charging(charger);
    266. mutex_unlock(&charger->lock);
    267. if (ret)
    268. return ret;
    269. break;
    270. case POWER_SUPPLY_STATUS_DISCHARGING:
    271. case POWER_SUPPLY_STATUS_NOT_CHARGING:
    272. mutex_lock(&charger->lock);
    273. charger->charging = false;
    274. ret = bq24735_disable_charging(charger);
    275. mutex_unlock(&charger->lock);
    276. if (ret)
    277. return ret;
    278. break;
    279. default:
    280. return -EINVAL;
    281. }
    282. power_supply_changed(psy);
    283. break;
    284. default:
    285. return -EPERM;
    286. }
    287. return 0;
    288. }
    289. //解析设备树,读取设备树的属性值
    290. static struct bq24735_platform *bq24735_parse_dt_data(struct i2c_client *client)
    291. {
    292. struct bq24735_platform *pdata;
    293. struct device_node *np = client->dev.of_node;
    294. u32 val;
    295. int ret;
    296. pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
    297. if (!pdata) {
    298. dev_err(&client->dev, "Memory alloc for bq24735 pdata failed\n");
    299. return NULL;
    300. }
    301. ret = of_property_read_u32(np, "ti,charge-current", &val);
    302. if (!ret)
    303. pdata->charge_current = val;
    304. ret = of_property_read_u32(np, "ti,charge-voltage", &val);
    305. if (!ret)
    306. pdata->charge_voltage = val;
    307. ret = of_property_read_u32(np, "ti,input-current", &val);
    308. if (!ret)
    309. pdata->input_current = val;
    310. pdata->ext_control = of_property_read_bool(np, "ti,external-control");
    311. return pdata;
    312. }
    313. //驱动匹配后被系统内核调用的初始化函数
    314. static int bq24735_charger_probe(struct i2c_client *client, const struct i2c_device_id *id)
    315. {
    316. int ret;
    317. struct bq24735 *charger;
    318. struct power_supply_desc *supply_desc;
    319. struct power_supply_config psy_cfg = {};
    320. char *name;
    321. //分配自定义结构体的内存
    322. charger = devm_kzalloc(&client->dev, sizeof(*charger), GFP_KERNEL);
    323. if (!charger)
    324. return -ENOMEM;
    325. //初始化锁
    326. mutex_init(&charger->lock);
    327. charger->charging = true;
    328. charger->pdata = client->dev.platform_data;
    329. if (IS_ENABLED(CONFIG_OF) && !charger->pdata && client->dev.of_node)
    330. charger->pdata = bq24735_parse_dt_data(client);
    331. if (!charger->pdata) {
    332. dev_err(&client->dev, "no platform data provided\n");
    333. return -EINVAL;
    334. }
    335. name = (char *)charger->pdata->name;
    336. if (!name) {
    337. name = devm_kasprintf(&client->dev, GFP_KERNEL, "bq24735@%s", dev_name(&client->dev));
    338. if (!name) {
    339. dev_err(&client->dev, "Failed to alloc device name\n");
    340. return -ENOMEM;
    341. }
    342. }
    343. charger->client = client;
    344. supply_desc = &charger->charger_desc;
    345. supply_desc->name = name;
    346. supply_desc->type = POWER_SUPPLY_TYPE_MAINS;
    347. supply_desc->properties = bq24735_charger_properties;
    348. supply_desc->num_properties = ARRAY_SIZE(bq24735_charger_properties);
    349. supply_desc->get_property = bq24735_charger_get_property;
    350. supply_desc->set_property = bq24735_charger_set_property;
    351. supply_desc->property_is_writeable = bq24735_charger_property_is_writeable;
    352. psy_cfg.supplied_to = charger->pdata->supplied_to;
    353. psy_cfg.num_supplicants = charger->pdata->num_supplicants;
    354. psy_cfg.of_node = client->dev.of_node;
    355. psy_cfg.drv_data = charger;
    356. //注册结构体的数据指针到系统内核中
    357. i2c_set_clientdata(client, charger);
    358. //获取GPIO的状态
    359. charger->status_gpio = devm_gpiod_get_optional(&client->dev, "ti,ac-detect", GPIOD_IN);
    360. if (IS_ERR(charger->status_gpio)) {
    361. ret = PTR_ERR(charger->status_gpio);
    362. dev_err(&client->dev, "Getting gpio failed: %d\n", ret);
    363. return ret;
    364. }
    365. //充电器是否存在
    366. if (bq24735_charger_is_present(charger)) {
    367. //读取寄存器 0xfe 的值
    368. ret = bq24735_read_word(client, BQ24735_MANUFACTURER_ID);
    369. if (ret < 0) {
    370. dev_err(&client->dev, "Failed to read manufacturer id : %d\n", ret);
    371. return ret;
    372. } else if (ret != 0x0040) {
    373. dev_err(&client->dev, "manufacturer id mismatch. 0x0040 != 0x%04x\n", ret);
    374. return -ENODEV;
    375. }
    376. //读取寄存器 0xff 的值
    377. ret = bq24735_read_word(client, BQ24735_DEVICE_ID);
    378. if (ret < 0) {
    379. dev_err(&client->dev, "Failed to read device id : %d\n", ret);
    380. return ret;
    381. } else if (ret != 0x000B) {
    382. dev_err(&client->dev, "device id mismatch. 0x000b != 0x%04x\n", ret);
    383. return -ENODEV;
    384. }
    385. //使能充电器
    386. ret = bq24735_enable_charging(charger);
    387. if (ret < 0) {
    388. dev_err(&client->dev, "Failed to enable charging\n");
    389. return ret;
    390. }
    391. }
    392. //注册驱动为一个power_supply设备
    393. charger->charger = devm_power_supply_register(&client->dev, supply_desc, &psy_cfg);
    394. if (IS_ERR(charger->charger)) {
    395. ret = PTR_ERR(charger->charger);
    396. dev_err(&client->dev, "Failed to register power supply: %d\n", ret);
    397. return ret;
    398. }
    399. //支持中断
    400. //内核提供 request_threaded_irq 和 devm_request_threaded_irq 为中断分配内核线程
    401. //若flags中设置IRQF_ONESHOT标志,内核会自动在中断上下文中屏蔽该中断号
    402. //bq24735_charger_isr 为中断处理函数
    403. if (client->irq) {
    404. ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, bq24735_charger_isr,
    405. IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, supply_desc->name, charger->charger);
    406. if (ret) {
    407. dev_err(&client->dev, "Unable to register IRQ %d err %d\n", client->irq, ret);
    408. return ret;
    409. }
    410. } else {
    411. //不支持中断,通过定时轮询来进入主循环
    412. ret = device_property_read_u32(&client->dev, "poll-interval", &charger->poll_interval);
    413. if (ret)
    414. return 0;
    415. if (!charger->poll_interval)
    416. return 0;
    417. INIT_DELAYED_WORK(&charger->poll, bq24735_poll);
    418. schedule_delayed_work(&charger->poll, msecs_to_jiffies(charger->poll_interval));
    419. }
    420. return 0;
    421. }
    422. //设备移除时被内核调用的函数
    423. static int bq24735_charger_remove(struct i2c_client *client)
    424. {
    425. struct bq24735 *charger = i2c_get_clientdata(client);
    426. if (charger->poll_interval)
    427. cancel_delayed_work_sync(&charger->poll);//取消定时器
    428. return 0;
    429. }
    430. static const struct i2c_device_id bq24735_charger_id[] = {
    431. { "bq24735-charger", 0 },
    432. {}
    433. };
    434. MODULE_DEVICE_TABLE(i2c, bq24735_charger_id);
    435. static const struct of_device_id bq24735_match_ids[] = {
    436. { .compatible = "ti,bq24735", },
    437. { /* end */ }
    438. };
    439. MODULE_DEVICE_TABLE(of, bq24735_match_ids);
    440. static struct i2c_driver bq24735_charger_driver = {
    441. .driver = {
    442. .name = "bq24735-charger",
    443. .of_match_table = bq24735_match_ids,
    444. },
    445. .probe = bq24735_charger_probe,
    446. .remove = bq24735_charger_remove,
    447. .id_table = bq24735_charger_id,
    448. };
    449. //用一个函数完成了好几个函数做的事情
    450. module_i2c_driver(bq24735_charger_driver);
    451. MODULE_DESCRIPTION("bq24735 battery charging driver");
    452. MODULE_AUTHOR("Darbha Sriharsha ");
    453. MODULE_LICENSE("GPL v2");

    #define module_i2c_driver(__i2c_driver)         module_driver(__i2c_driver, i2c_add_driver, i2c_del_driver)

    1. #define module_i2c_driver(__i2c_driver) module_driver(__i2c_driver, i2c_add_driver, i2c_del_driver)
    2. #define module_driver(__driver, __register, __unregister, ...) \
    3. static int __init __driver##_init(void) \
    4. { \
    5. return __register(&(__driver) , ##__VA_ARGS__); \
    6. } \
    7. module_init(__driver##_init); \
    8. static void __exit __driver##_exit(void) \
    9. { \
    10. __unregister(&(__driver) , ##__VA_ARGS__); \
    11. } \
    12. module_exit(__driver##_exit);

  • 相关阅读:
    Vue + Nodejs + socket.io 实现聊天
    Unity开发者——编辑器技巧
    使用Python实现强化学习算法
    实验1 熟悉R语言环境
    详解SpringBoot的常用注解
    联想y7000 y7000p 2018/2019 不插电源 不插充电器, 直接关机 ,电量一直89%/87%/86%,V0005如何解决?
    从Opencv之图像直方图源码,探讨高性能计算设计思想
    CockroachDB-哈希分片索引
    Pycharm远程debug代码,一直进入remote_sources
    Laya---淘宝小程序
  • 原文地址:https://blog.csdn.net/langeldep/article/details/127506764