Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | /* * BQ27xxx battery monitor HDQ/1-wire driver * * Copyright (C) 2007-2017 Texas Instruments Incorporated - http://www.ti.com/ * * 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. * * This program is distributed "as is" WITHOUT ANY WARRANTY of any * kind, whether express or implied; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/device.h> #include <linux/types.h> #include <linux/platform_device.h> #include <linux/mutex.h> #include <linux/power/bq27xxx_battery.h> #include <linux/w1.h> #define W1_FAMILY_BQ27000 0x01 #define HDQ_CMD_READ (0 << 7) #define HDQ_CMD_WRITE (1 << 7) static int F_ID; module_param(F_ID, int, S_IRUSR); MODULE_PARM_DESC(F_ID, "1-wire slave FID for BQ27xxx device"); static int w1_bq27000_read(struct w1_slave *sl, unsigned int reg) { u8 val; mutex_lock(&sl->master->bus_mutex); w1_write_8(sl->master, HDQ_CMD_READ | reg); val = w1_read_8(sl->master); mutex_unlock(&sl->master->bus_mutex); return val; } static int bq27xxx_battery_hdq_read(struct bq27xxx_device_info *di, u8 reg, bool single) { struct w1_slave *sl = dev_to_w1_slave(di->dev); unsigned int timeout = 3; int upper, lower; int temp; if (!single) { /* * Make sure the value has not changed in between reading the * lower and the upper part */ upper = w1_bq27000_read(sl, reg + 1); do { temp = upper; if (upper < 0) return upper; lower = w1_bq27000_read(sl, reg); if (lower < 0) return lower; upper = w1_bq27000_read(sl, reg + 1); } while (temp != upper && --timeout); if (timeout == 0) return -EIO; return (upper << 8) | lower; } return w1_bq27000_read(sl, reg); } static int bq27xxx_battery_hdq_add_slave(struct w1_slave *sl) { struct bq27xxx_device_info *di; di = devm_kzalloc(&sl->dev, sizeof(*di), GFP_KERNEL); if (!di) return -ENOMEM; dev_set_drvdata(&sl->dev, di); di->dev = &sl->dev; di->chip = BQ27000; di->name = "bq27000-battery"; di->bus.read = bq27xxx_battery_hdq_read; return bq27xxx_battery_setup(di); } static void bq27xxx_battery_hdq_remove_slave(struct w1_slave *sl) { struct bq27xxx_device_info *di = dev_get_drvdata(&sl->dev); bq27xxx_battery_teardown(di); } static struct w1_family_ops bq27xxx_battery_hdq_fops = { .add_slave = bq27xxx_battery_hdq_add_slave, .remove_slave = bq27xxx_battery_hdq_remove_slave, }; static struct w1_family bq27xxx_battery_hdq_family = { .fid = W1_FAMILY_BQ27000, .fops = &bq27xxx_battery_hdq_fops, }; static int __init bq27xxx_battery_hdq_init(void) { if (F_ID) bq27xxx_battery_hdq_family.fid = F_ID; return w1_register_family(&bq27xxx_battery_hdq_family); } module_init(bq27xxx_battery_hdq_init); static void __exit bq27xxx_battery_hdq_exit(void) { w1_unregister_family(&bq27xxx_battery_hdq_family); } module_exit(bq27xxx_battery_hdq_exit); MODULE_AUTHOR("Texas Instruments Ltd"); MODULE_DESCRIPTION("BQ27xxx battery monitor HDQ/1-wire driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_BQ27000)); |