Received: by 2002:ac0:a5b6:0:0:0:0:0 with SMTP id m51-v6csp20891imm; Thu, 31 May 2018 17:34:04 -0700 (PDT) X-Google-Smtp-Source: ADUXVKKkfVlfjC0Y7TEBgkEeTbVCaYMV1ywqhCjVpAJxOzFBq2BsglTalXTHzDJMNuroDQXXWaDy X-Received: by 2002:a17:902:7c84:: with SMTP id y4-v6mr9119191pll.262.1527813244901; Thu, 31 May 2018 17:34:04 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1527813244; cv=none; d=google.com; s=arc-20160816; b=zq6JDU8IRAcxFcV4wZNeecxp7sytmySUltwJM0FcRg+W3w+OMJoV+MN0NBqL7abhwx zj/FPPI3s4Nzc6gk7UqAZpbx3CieinVHkM5ohG7G58tCEBvcK/nq/gCt4w7jFoF8OnMF CCAlXgXIcI21bmeIiSM8Vj/MnpcympVRPT9R7wx6fPXSioiUShS7qUmOu1Go/LfVBKRf rpNOBSU2CSpbelnDFPt6JSL7XtUr2x54HlrxwdXDqvI9Un4GM2F41v5JBz7bPRmYdOgZ QwBjmjmYcakz3qTxumHVcqqbHp1hhA3bOz9+/fiNYjI3BgC+reEpK4UeNidQhn48jtNm 9wCg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :dkim-signature:arc-authentication-results; bh=92jmJNpVj/LhkyN1ld7O+83thKmmJNUDOeEpmN3GDyw=; b=qhhMrL/HL3YolwEKwd5PM7XshApTaZR3BPMPZJe6vRPRsXW8nBuSTRZQ4cIsp2NmSk bWs5vchoVyAR0cTvy1QsXeM46syw1ReRYQZKG2miA/w5Ew4DlnO6xRhpIsNdnRVK23pT OLdudbpcrLYwK1zIUYtnmZUZeXklBIKrtWeud5Ik5oG3u7Ntib+J5VDPqjOBYppnwARN p4NN3eAfMdAoaCzKzhHb6Xq9/Lr6ybc8L4Ki0YhAJpr6CSx+ceDs2CaEUqyFMUIO30eS slYAnkQh/w7ZWQbJbKYvxoW+MspMlBCrpChTN5RRu1AsglR/tbhRDVoiEvJVPmrFDgJY hnAQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=Km+Nz6yf; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id a11-v6si30389966pgt.680.2018.05.31.17.33.50; Thu, 31 May 2018 17:34:04 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=Km+Nz6yf; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751230AbeFAAdM (ORCPT + 99 others); Thu, 31 May 2018 20:33:12 -0400 Received: from mail-pf0-f193.google.com ([209.85.192.193]:36801 "EHLO mail-pf0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750821AbeFAAdJ (ORCPT ); Thu, 31 May 2018 20:33:09 -0400 Received: by mail-pf0-f193.google.com with SMTP id w129-v6so11607921pfd.3 for ; Thu, 31 May 2018 17:33:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id; bh=92jmJNpVj/LhkyN1ld7O+83thKmmJNUDOeEpmN3GDyw=; b=Km+Nz6yfiTivnM2L2RuTKkT+hSn2K9y+8gkkIj69FSXSOxFN6e2FHZNTTM6zIv76Y3 34ZPrORwqJX+vb9CAoPgND6kWEwmymb5N40NSXYR9HpsfMcRyegWL4TrdgB7+BcYraCR gVL8L80vDG4BOjxklxUrXlH+NWUjMcIg3gdAU= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=92jmJNpVj/LhkyN1ld7O+83thKmmJNUDOeEpmN3GDyw=; b=lX1rkzDC0AOXZsya16hzSusM3Z6RfbnKXXe5S14Xsez/SnH4Ee/rTauqIhm9ErM/He HHnGMVj4ll0WsjMMqnscrpMgcUNhKc44QzdvDcIlLZWfY8LyulN5xiGmYURYMaSSJHBM Cdb7NGoQSqOVI9OXlhk+g9p2wFoZdgiDGJ5buw6bvB4kBxrQVsriL9RgEmpuxSRYUVZY LrdZLceU1oHCCKLNEVncl2YNkHKpFG/IuVp7BJ8rtE5Ju8nspU/kyrn1gV4bpYg+qOz8 MQC8uOruBuBnAmFghtjdtHiD2m8vdmdRbIyzxWAphWSDdJ5GPao/lGapu9iv0VjZvLPj buWQ== X-Gm-Message-State: ALKqPwff5FvQAH8K689a2lV4TTCb/ls9SbfZoOJKjAZJdDCIzvI8eO36 0j9dkyU+g0pblWtA4zfLVdIePA== X-Received: by 2002:a62:883:: with SMTP id 3-v6mr8836486pfi.154.1527813188838; Thu, 31 May 2018 17:33:08 -0700 (PDT) Received: from ban.mtv.corp.google.com ([2620:0:1000:1501:bc2f:3082:9938:5d41]) by smtp.gmail.com with ESMTPSA id u9-v6sm73603636pfi.60.2018.05.31.17.33.06 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 31 May 2018 17:33:07 -0700 (PDT) From: Brian Norris To: Sebastian Reichel Cc: , Rob Herring , linux-pm@vger.kernel.org, devicetree@vger.kernel.org, Alexandru Stan , Guenter Roeck , Doug Anderson , Brian Norris Subject: [PATCH 1/2] power: supply: sbs-battery: don't assume MANUFACTURER_DATA formats Date: Thu, 31 May 2018 17:32:51 -0700 Message-Id: <20180601003252.42810-1-briannorris@chromium.org> X-Mailer: git-send-email 2.17.0.921.gf22659ad46-goog Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This driver was originally submitted for the TI BQ20Z75 battery IC (commit a7640bfa10c5 ("power_supply: Add driver for TI BQ20Z75 gas gauge IC")) and later renamed to express generic SBS support. While it's mostly true that this driver implemented a standard SBS command set, it takes liberties with the REG_MANUFACTURER_DATA register. This register is specified in the SBS spec, but it doesn't make any mention of what its actual contents are. We've sort of noticed this optionality previously, with commit 17c6d3979e5b ("sbs-battery: make writes to ManufacturerAccess optional"), where we found that some batteries NAK writes to this register. What this really means is that so far, we've just been lucky that most batteries have either been compatible with the TI chip, or else at least haven't reported highly-unexpected values. For instance, one battery I have here seems to report either 0x0000 or 0x0100 to the MANUFACTURER_ACCESS_STATUS command -- while this seems to match either Wake Up (bits[11:8] = 0000b) or Normal Discharge (bits[11:8] = 0001b) status for the TI part [1], they don't seem to actually correspond to real states (for instance, I never see 0101b = Charge, even when charging). On other batteries, I'm getting apparently random data in return, which means that occasionally, we interpret this as "battery not present" or "battery is not healthy". All in all, it seems to be a really bad idea to make assumptions about REG_MANUFACTURER_DATA, unless we already know what battery we're using. Therefore, this patch reimplements the "present" and "health" checks to the following on most SBS batteries: 1. HEALTH: report "unknown" -- I couldn't find a standard SBS command that gives us much useful here 2. PRESENT: just send a REG_STATUS command; if it succeeds, then the battery is present Also, we stop sending MANUFACTURER_ACCESS_SLEEP to non-TI parts. I have no proof that this is useful and supported. If someone explicitly provided a 'ti,bq20z75' compatible property, then we retain the existing TI command behaviors. [1] http://www.ti.com/lit/er/sluu265a/sluu265a.pdf Signed-off-by: Brian Norris --- drivers/power/supply/sbs-battery.c | 61 +++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c index 83d7b4115857..e15d0ca4729d 100644 --- a/drivers/power/supply/sbs-battery.c +++ b/drivers/power/supply/sbs-battery.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -84,8 +85,9 @@ static const struct chip_data { int min_value; int max_value; } sbs_data[] = { + /* Manuf. data isn't directly useful as a POWER_SUPPLY_PROP */ [REG_MANUFACTURER_DATA] = - SBS_DATA(POWER_SUPPLY_PROP_PRESENT, 0x00, 0, 65535), + SBS_DATA(-1, 0x00, 0, 65535), [REG_TEMPERATURE] = SBS_DATA(POWER_SUPPLY_PROP_TEMP, 0x08, 0, 65535), [REG_VOLTAGE] = @@ -156,6 +158,9 @@ static enum power_supply_property sbs_properties[] = { POWER_SUPPLY_PROP_MODEL_NAME }; +/* Supports special manufacturer commands from TI BQ20Z75 IC. */ +#define SBS_FLAGS_TI_BQ20Z75 BIT(0) + struct sbs_info { struct i2c_client *client; struct power_supply *power_supply; @@ -168,6 +173,7 @@ struct sbs_info { u32 poll_retry_count; struct delayed_work work; struct mutex mode_lock; + u32 flags; }; static char model_name[I2C_SMBUS_BLOCK_MAX + 1]; @@ -315,6 +321,31 @@ static int sbs_status_correct(struct i2c_client *client, int *intval) static int sbs_get_battery_presence_and_health( struct i2c_client *client, enum power_supply_property psp, union power_supply_propval *val) +{ + int ret; + + switch (psp) { + case POWER_SUPPLY_PROP_PRESENT: + /* Dummy command; if it succeeds, battery is present. */ + ret = sbs_read_word_data(client, sbs_data[REG_STATUS].addr); + if (ret < 0) + val->intval = 0; /* battery disconnected */ + else + val->intval = 1; /* battery present */ + return 0; + case POWER_SUPPLY_PROP_HEALTH: + /* SBS spec doesn't have a general health command. */ + val->intval = POWER_SUPPLY_HEALTH_UNKNOWN; + return 0; + default: + dev_err(&client->dev, "unexpected prop %d\n", psp); + return -EINVAL; + } +} + +static int sbs_get_ti_battery_presence_and_health( + struct i2c_client *client, enum power_supply_property psp, + union power_supply_propval *val) { s32 ret; @@ -600,7 +631,12 @@ static int sbs_get_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_PRESENT: case POWER_SUPPLY_PROP_HEALTH: - ret = sbs_get_battery_presence_and_health(client, psp, val); + if (client->flags & SBS_FLAGS_TI_BQ20Z75) + ret = sbs_get_ti_battery_presence_and_health(client, + psp, val); + else + ret = sbs_get_battery_presence_and_health(client, psp, + val); if (psp == POWER_SUPPLY_PROP_PRESENT) return 0; break; @@ -806,6 +842,7 @@ static int sbs_probe(struct i2c_client *client, if (!chip) return -ENOMEM; + chip->flags = (u32)(uintptr_t)of_device_get_match_data(&client->dev); chip->client = client; chip->enable_detection = false; psy_cfg.of_node = client->dev.of_node; @@ -915,12 +952,15 @@ static int sbs_suspend(struct device *dev) if (chip->poll_time > 0) cancel_delayed_work_sync(&chip->work); - /* - * Write to manufacturer access with sleep command. - * Support is manufacturer dependend, so ignore errors. - */ - sbs_write_word_data(client, sbs_data[REG_MANUFACTURER_DATA].addr, - MANUFACTURER_ACCESS_SLEEP); + if (chip->flags & SBS_FLAGS_TI_BQ20Z75) { + /* + * Write to manufacturer access with sleep command. + * Support is manufacturer dependent, so ignore errors. + */ + sbs_write_word_data(client, + sbs_data[REG_MANUFACTURER_DATA].addr, + MANUFACTURER_ACCESS_SLEEP); + } return 0; } @@ -941,7 +981,10 @@ MODULE_DEVICE_TABLE(i2c, sbs_id); static const struct of_device_id sbs_dt_ids[] = { { .compatible = "sbs,sbs-battery" }, - { .compatible = "ti,bq20z75" }, + { + .compatible = "ti,bq20z75", + .data = (void *)SBS_FLAGS_TI_BQ20Z75, + }, { } }; MODULE_DEVICE_TABLE(of, sbs_dt_ids); -- 2.17.0.921.gf22659ad46-goog