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