Received: by 2002:ab2:1149:0:b0:1f3:1f8c:d0c6 with SMTP id z9csp1451157lqz; Mon, 1 Apr 2024 06:57:38 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCXBR2bR4hgrRQLZxNR2ov8fhSi3B7wspLWu8nDeAFmC/fOeaAVA0GqezT1hOst8S0i/4WYQAvelqPMerqiqYTQJhCFD2I2s+QUdCZ+G4g== X-Google-Smtp-Source: AGHT+IHiazlNVw18DAxmB1xY5zZxoDl95zR83ESN1vg6Tp39F9nAsd9T3A4t6cUDg5wzyfbBw7Ut X-Received: by 2002:a05:6358:3a0e:b0:183:612d:4499 with SMTP id g14-20020a0563583a0e00b00183612d4499mr11544469rwe.31.1711979857737; Mon, 01 Apr 2024 06:57:37 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1711979857; cv=pass; d=google.com; s=arc-20160816; b=a0q+w5NbxwKkv5aaIB+ym+0ql4Vpo2D2vPe5zdPaFKBFmgy0bs4LHQmz2k82r3vs7Y qhXVLHuv0lG+SIAv/sbfTXGFNEvoMZkksw9zXi9Aa/Y3GkBRga2vZWlLT45+sT4oyMZK prbFYnczeRGEyCAJCqCZzsN5CugMl+xHWG1ygTg9B1AgksmLJ40nOPzDdCK53NENjo6/ v1zOf/IBCxW5/7FN/sXMY5tTkKvdZl0afqcmAuuU6IWqkYFdX0Sds+gVXm3Yeo3H/a+k jg2gsaso8q6uYnh+jNjoX8gkXIoZ2PWPD6PH9O6L2I2JesSJs8F1jOQiG5uXh563OltD FZqA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:in-reply-to:from:content-language :references:cc:to:subject:user-agent:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:date:message-id:dkim-signature; bh=cSkpmLo6oDjRy50TsiDoTn2ryWmugvDSjH5h3qwLNEI=; fh=PvcRYShvmgLgr+IxYuUsc+8s8HVo8L/u5rnYK1dYnzc=; b=lZRrKJclhghAbgvOaoB7CgOk2Htj1bov/dsjesVWUFDYTAawt1PIAluI0dSjGD3TRw F4CTbGqtriz0ktuEL+h21WvATkhaknadR0efULErzsUilC9GumYc5GKozAJbmMaqYfPt Z6ZVYT0IxvRnsBBmwUzaA+U1gWhnBNSO3sEytB40pPT8xrN5HLStCKck+z2P5pktmK3V ynNuNEGWGGkd0NKQKcqkBL055wmMO+cjXGHbf2gQh0MUiywYieMq9Jr7QNKsahdZrxkD WSUvjzTEp39RGZw61lBUX1SAadWCof35tvbpkw0aVFqx+jYrHRrMazC/6aVlAiYj3/kM +F9Q==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b=iJCbodrJ; arc=pass (i=1 spf=pass spfdomain=ti.com dkim=pass dkdomain=ti.com dmarc=pass fromdomain=ti.com); spf=pass (google.com: domain of linux-kernel+bounces-126696-linux.lists.archive=gmail.com@vger.kernel.org designates 139.178.88.99 as permitted sender) smtp.mailfrom="linux-kernel+bounces-126696-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Return-Path: Received: from sv.mirrors.kernel.org (sv.mirrors.kernel.org. [139.178.88.99]) by mx.google.com with ESMTPS id k19-20020a635613000000b005dc425a94d9si9469644pgb.369.2024.04.01.06.57.37 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Apr 2024 06:57:37 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel+bounces-126696-linux.lists.archive=gmail.com@vger.kernel.org designates 139.178.88.99 as permitted sender) client-ip=139.178.88.99; Authentication-Results: mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b=iJCbodrJ; arc=pass (i=1 spf=pass spfdomain=ti.com dkim=pass dkdomain=ti.com dmarc=pass fromdomain=ti.com); spf=pass (google.com: domain of linux-kernel+bounces-126696-linux.lists.archive=gmail.com@vger.kernel.org designates 139.178.88.99 as permitted sender) smtp.mailfrom="linux-kernel+bounces-126696-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sv.mirrors.kernel.org (Postfix) with ESMTPS id 3E62F282046 for ; Mon, 1 Apr 2024 13:57:37 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id D5BEB3FE52; Mon, 1 Apr 2024 13:57:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b="iJCbodrJ" Received: from fllv0015.ext.ti.com (fllv0015.ext.ti.com [198.47.19.141]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DB1623FE4E; Mon, 1 Apr 2024 13:57:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.47.19.141 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711979847; cv=none; b=VerjpMnk81w/qR03Uqmjb3PG0xDPuihV0F+JL0IP7en9ju+TjgFJr8LQVL/BqDBlPYSBXz68Cs1YXCvGuyIvwL1akHR/aaoF28DEJ82jGAbZYEUnlkvG10wEWdSM1RnmT5DvbU3ioJDzn8h6Mwkq9ah9N5hKi86tn7QQRk6S6Mw= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1711979847; c=relaxed/simple; bh=gic5QdbQz3rnf6+SVYiyGjZkeak6aOfejo30F/XPFAQ=; h=Message-ID:Date:MIME-Version:Subject:To:CC:References:From: In-Reply-To:Content-Type; b=uSiVLWL/1bbyr3VdxkB449+HEu2xoqvSKt/qGb4+r8Lf4aqiHsryof4r5pO+rwyvH0nZEvyaT2PplvN2C9+9oO/3ep+U5L3F/qDEHtsLwrVHd3BokHifYhLFCKRNx4S/mVTlsPb973+uWY3o9Kehap82CnuWngMfZ7celEp4+og= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com; spf=pass smtp.mailfrom=ti.com; dkim=pass (1024-bit key) header.d=ti.com header.i=@ti.com header.b=iJCbodrJ; arc=none smtp.client-ip=198.47.19.141 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ti.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ti.com Received: from fllv0035.itg.ti.com ([10.64.41.0]) by fllv0015.ext.ti.com (8.15.2/8.15.2) with ESMTP id 431DvDUu088560; Mon, 1 Apr 2024 08:57:13 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1711979833; bh=cSkpmLo6oDjRy50TsiDoTn2ryWmugvDSjH5h3qwLNEI=; h=Date:Subject:To:CC:References:From:In-Reply-To; b=iJCbodrJPXAi3kGNvDKqHTeU+UIrxD/ndTjjUKc7DrVQWSB0Or1O7ajgOMeiGayce HsmqSsSz2gepNL5TJPC/T+jWL3K2hDpCYAupWQaI20DPmWiaGmKlLk1D6elF8DFsMG SXCAnotNqvLNPG94Hqqx7IF4VOXewadBfrEwu4Fc= Received: from DLEE103.ent.ti.com (dlee103.ent.ti.com [157.170.170.33]) by fllv0035.itg.ti.com (8.15.2/8.15.2) with ESMTPS id 431DvDrw109653 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Mon, 1 Apr 2024 08:57:13 -0500 Received: from DLEE111.ent.ti.com (157.170.170.22) by DLEE103.ent.ti.com (157.170.170.33) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23; Mon, 1 Apr 2024 08:57:13 -0500 Received: from lelvsmtp6.itg.ti.com (10.180.75.249) by DLEE111.ent.ti.com (157.170.170.22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2507.23 via Frontend Transport; Mon, 1 Apr 2024 08:57:13 -0500 Received: from [10.249.42.149] ([10.249.42.149]) by lelvsmtp6.itg.ti.com (8.15.2/8.15.2) with ESMTP id 431DvDbN127935; Mon, 1 Apr 2024 08:57:13 -0500 Message-ID: Date: Mon, 1 Apr 2024 08:57:12 -0500 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH v2] power: supply: bq27xxx: Divide the reg cache to each register To: Sebastian Reichel , Hermes Zhang CC: , =?UTF-8?Q?Pali_Roh=C3=A1r?= , , References: <20240306100904.1914263-1-Hermes.Zhang@axis.com> Content-Language: en-US From: Andrew Davis In-Reply-To: Content-Type: text/plain; charset="UTF-8"; format=flowed Content-Transfer-Encoding: 7bit X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 On 4/1/24 8:15 AM, Sebastian Reichel wrote: > [+cc Andrew Davis] > > Hello Hermes, > > On Wed, Mar 06, 2024 at 06:09:03PM +0800, Hermes Zhang wrote: >> The reg cache used to be grouped and activated for each property >> access, regardless of whether it was part of the group. That will >> lead to a significant increase in I2C transmission. >> Divide the cache group and create a cache for every register. The >> cache won't work until the register has been fetched. This will help >> in reducing the quantity of pointless I2C communication and avoiding >> the error -16 (EBUSY) that occurs while using an I2C bus that is >> shared by many devices. >> >> Signed-off-by: Hermes Zhang >> --- > > Sorry for the delay. This arrived too close to the 6.9 merge window. > I had a look now and while the patch looks fine to me on a conceptual > level, it did not apply. It looks like you used a pre-2024 kernel tree > to generate the patch against. Please always use something recent base > tree (and ideally use git's --base option to document the used > parent commit). > > Other than that I just applied a series from Andrew, which cleans up > the register caching in bq27xxx and removed most registers from the > cache. That's something I did not consider earlier, since I thought > the cache was introduced to fix a different issue. But that was > apparently sbs-battery and not bq27xxx. > The original BQ27000 device did not have an interrupt pin to signal when important updates to the battery occurred, so early devices using it would have userspace poll those values. As the kernel driver added its own polling for updates, it seems the early driver authors simply decided to cache the values between kernel reads and return those to userspace when it reads. This is a problem though for two reasons. 1. If no one is interested in these values the kernel will still poll them anyway, wasting I2C bus time and power. 2. If userspace is actually interested in some value and so checks it often, it will only get real updated values when the kernel next polls, which might not be often enough for some use-cases. > Anyways, there is only two registers left in the cache now. I'm fine > with having a per-register cache for them, if that is still needed > to further reduce I2C traffic on your device. > > And... re-reading your problem description, I wonder if we need to > reintroduce the caching for all registers (on a per register basis) > to avoid userspace being able to do a denial of service by quickly > polling the battery information. > Preventing a DoS of the I2C bus is not the responsibility of a given driver. Userspace has plenty of other ways to spam the I2C bus if it really wants to, no need to try to predict what a system's admin would want and block users from those actions. If we really do want to reduce I2C accesses for registers we know cannot change often (which are few), then we should use the existing regmap_cache mechanism, not roll our own. This driver is complex enough without re-inventing the wheel and adding our own custom register caching scheme. Andrew > Any thoughts? > > -- Sebastian > >> v2: >> - Refactor implementation. >> >> drivers/power/supply/bq27xxx_battery.c | 231 +++++++++++++++++-------- >> include/linux/power/bq27xxx_battery.h | 30 ++-- >> 2 files changed, 179 insertions(+), 82 deletions(-) >> >> diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c >> index 1c4a9d137744..cc724322f4f0 100644 >> --- a/drivers/power/supply/bq27xxx_battery.c >> +++ b/drivers/power/supply/bq27xxx_battery.c >> @@ -1746,14 +1746,16 @@ static bool bq27xxx_battery_capacity_inaccurate(struct bq27xxx_device_info *di, >> >> static int bq27xxx_battery_read_health(struct bq27xxx_device_info *di) >> { >> + int flags = di->cache[CACHE_REG_FLAGS].value; >> + >> /* Unlikely but important to return first */ >> - if (unlikely(bq27xxx_battery_overtemp(di, di->cache.flags))) >> + if (unlikely(bq27xxx_battery_overtemp(di, flags))) >> return POWER_SUPPLY_HEALTH_OVERHEAT; >> - if (unlikely(bq27xxx_battery_undertemp(di, di->cache.flags))) >> + if (unlikely(bq27xxx_battery_undertemp(di, flags))) >> return POWER_SUPPLY_HEALTH_COLD; >> - if (unlikely(bq27xxx_battery_dead(di, di->cache.flags))) >> + if (unlikely(bq27xxx_battery_dead(di, flags))) >> return POWER_SUPPLY_HEALTH_DEAD; >> - if (unlikely(bq27xxx_battery_capacity_inaccurate(di, di->cache.flags))) >> + if (unlikely(bq27xxx_battery_capacity_inaccurate(di, flags))) >> return POWER_SUPPLY_HEALTH_CALIBRATION_REQUIRED; >> >> return POWER_SUPPLY_HEALTH_GOOD; >> @@ -1778,7 +1780,7 @@ static int bq27xxx_battery_current_and_status( >> struct bq27xxx_device_info *di, >> union power_supply_propval *val_curr, >> union power_supply_propval *val_status, >> - struct bq27xxx_reg_cache *cache) >> + struct bq27xxx_cache_reg *reg) >> { >> bool single_flags = (di->opts & BQ27XXX_O_ZERO); >> int curr; >> @@ -1790,8 +1792,8 @@ static int bq27xxx_battery_current_and_status( >> return curr; >> } >> >> - if (cache) { >> - flags = cache->flags; >> + if (reg) { >> + flags = reg->value; >> } else { >> flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, single_flags); >> if (flags < 0) { >> @@ -1832,57 +1834,128 @@ static int bq27xxx_battery_current_and_status( >> return 0; >> } >> >> -static void bq27xxx_battery_update_unlocked(struct bq27xxx_device_info *di) >> +static int bq27xxx_cached_reg_value_unlocked(struct bq27xxx_device_info *di, >> + enum bq27xxx_cache_registers item) >> { >> - union power_supply_propval status = di->last_status; >> - struct bq27xxx_reg_cache cache = {0, }; >> - bool has_singe_flag = di->opts & BQ27XXX_O_ZERO; >> - >> - cache.flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, has_singe_flag); >> - if ((cache.flags & 0xff) == 0xff) >> - cache.flags = -1; /* read error */ >> - if (cache.flags >= 0) { >> - cache.temperature = bq27xxx_battery_read_temperature(di); >> + struct bq27xxx_cache_reg *reg; >> + int tmp = -EINVAL; >> + >> + reg = &di->cache[item]; >> + >> + if (time_is_after_jiffies(reg->last_update + 5 * HZ)) >> + return reg->value; >> + >> + switch (item) { >> + case CACHE_REG_TEMPERATURE: >> + tmp = bq27xxx_battery_read_temperature(di); >> + break; >> + case CACHE_REG_TIME_TO_EMPTY: >> if (di->regs[BQ27XXX_REG_TTE] != INVALID_REG_ADDR) >> - cache.time_to_empty = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTE); >> + tmp = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTE); >> + break; >> + case CACHE_REG_TIME_TO_EMPTY_AVG: >> if (di->regs[BQ27XXX_REG_TTECP] != INVALID_REG_ADDR) >> - cache.time_to_empty_avg = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTECP); >> + tmp = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTECP); >> + break; >> + case CACHE_REG_TIME_TO_FULL: >> if (di->regs[BQ27XXX_REG_TTF] != INVALID_REG_ADDR) >> - cache.time_to_full = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTF); >> - >> - cache.charge_full = bq27xxx_battery_read_fcc(di); >> - cache.capacity = bq27xxx_battery_read_soc(di); >> - if (di->regs[BQ27XXX_REG_AE] != INVALID_REG_ADDR) >> - cache.energy = bq27xxx_battery_read_energy(di); >> - di->cache.flags = cache.flags; >> - cache.health = bq27xxx_battery_read_health(di); >> + tmp = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTF); >> + break; >> + case CACHE_REG_CHARGE_FULL: >> + tmp = bq27xxx_battery_read_fcc(di); >> + break; >> + case CACHE_REG_CYCLE_COUNT: >> if (di->regs[BQ27XXX_REG_CYCT] != INVALID_REG_ADDR) >> - cache.cycle_count = bq27xxx_battery_read_cyct(di); >> - >> - /* >> - * On gauges with signed current reporting the current must be >> - * checked to detect charging <-> discharging status changes. >> - */ >> - if (!(di->opts & BQ27XXX_O_ZERO)) >> - bq27xxx_battery_current_and_status(di, NULL, &status, &cache); >> - >> - /* We only have to read charge design full once */ >> - if (di->charge_design_full <= 0) >> - di->charge_design_full = bq27xxx_battery_read_dcap(di); >> + tmp = bq27xxx_battery_read_cyct(di); >> + break; >> + case CACHE_REG_CAPACITY: >> + tmp = bq27xxx_battery_read_soc(di); >> + break; >> + case CACHE_REG_ENERGY: >> + if (di->regs[BQ27XXX_REG_AE] != INVALID_REG_ADDR) >> + tmp = bq27xxx_battery_read_energy(di); >> + break; >> + case CACHE_REG_FLAGS: >> + bool has_singe_flag = di->opts & BQ27XXX_O_ZERO; >> + >> + tmp = bq27xxx_read(di, BQ27XXX_REG_FLAGS, has_singe_flag); >> + if ((tmp & 0xff) == 0xff) >> + tmp = -1; /* read error */ >> + break; >> + default: >> + break; >> + } >> + >> + /* only update cache value when successful */ >> + if (tmp >= 0) { >> + reg->value = tmp; >> + reg->last_update = jiffies; >> } >> >> - if ((di->cache.capacity != cache.capacity) || >> - (di->cache.flags != cache.flags) || >> + return tmp; >> +} >> + >> +static int bq27xxx_cached_reg_value(struct bq27xxx_device_info *di, >> + enum bq27xxx_cache_registers item) >> +{ >> + int ret; >> + >> + mutex_lock(&di->lock); >> + ret = bq27xxx_cached_reg_value_unlocked(di, item); >> + mutex_unlock(&di->lock); >> + >> + return ret; >> +} >> + >> +static void bq27xxx_battery_update_unlocked(struct bq27xxx_device_info *di) >> +{ >> + union power_supply_propval status = di->last_status; >> + int old_flags, flags; >> + int old_capacity, capacity; >> + >> + old_capacity = di->cache[CACHE_REG_CAPACITY].value; >> + capacity = old_capacity; >> + >> + old_flags = di->cache[CACHE_REG_FLAGS].value; >> + flags = bq27xxx_cached_reg_value_unlocked(di, CACHE_REG_FLAGS); >> + >> + if (flags < 0) >> + goto out; >> + >> + bq27xxx_cached_reg_value_unlocked(di, CACHE_REG_TEMPERATURE); >> + if (di->regs[BQ27XXX_REG_TTE] != INVALID_REG_ADDR) >> + bq27xxx_cached_reg_value_unlocked(di, CACHE_REG_TIME_TO_EMPTY); >> + if (di->regs[BQ27XXX_REG_TTECP] != INVALID_REG_ADDR) >> + bq27xxx_cached_reg_value_unlocked(di, CACHE_REG_TIME_TO_EMPTY_AVG); >> + if (di->regs[BQ27XXX_REG_TTF] != INVALID_REG_ADDR) >> + bq27xxx_cached_reg_value_unlocked(di, CACHE_REG_TIME_TO_FULL); >> + >> + bq27xxx_cached_reg_value_unlocked(di, CACHE_REG_CHARGE_FULL); >> + bq27xxx_cached_reg_value_unlocked(di, CACHE_REG_CAPACITY); >> + if (di->regs[BQ27XXX_REG_AE] != INVALID_REG_ADDR) >> + bq27xxx_cached_reg_value_unlocked(di, CACHE_REG_ENERGY); >> + if (di->regs[BQ27XXX_REG_CYCT] != INVALID_REG_ADDR) >> + bq27xxx_cached_reg_value_unlocked(di, CACHE_REG_CYCLE_COUNT); >> + >> + /* >> + * On gauges with signed current reporting the current must be >> + * checked to detect charging <-> discharging status changes. >> + */ >> + if (!(di->opts & BQ27XXX_O_ZERO)) >> + bq27xxx_battery_current_and_status(di, NULL, &status, >> + &di->cache[CACHE_REG_FLAGS]); >> + >> + /* We only have to read charge design full once */ >> + if (di->charge_design_full <= 0) >> + di->charge_design_full = bq27xxx_battery_read_dcap(di); >> + >> +out: >> + if ((old_capacity != capacity) || (old_flags != flags) || >> (di->last_status.intval != status.intval)) { >> di->last_status.intval = status.intval; >> power_supply_changed(di->bat); >> } >> >> - if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) >> - di->cache = cache; >> - >> - di->last_update = jiffies; >> - >> if (!di->removed && poll_interval > 0) >> mod_delayed_work(system_wq, &di->work, poll_interval * HZ); >> } >> @@ -1934,29 +2007,32 @@ static int bq27xxx_battery_capacity_level(struct bq27xxx_device_info *di, >> union power_supply_propval *val) >> { >> int level; >> + int flags; >> + >> + flags = di->cache[CACHE_REG_FLAGS].value; >> >> if (di->opts & BQ27XXX_O_ZERO) { >> - if (di->cache.flags & BQ27000_FLAG_FC) >> + if (flags & BQ27000_FLAG_FC) >> level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; >> - else if (di->cache.flags & BQ27000_FLAG_EDVF) >> + else if (flags & BQ27000_FLAG_EDVF) >> level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; >> - else if (di->cache.flags & BQ27000_FLAG_EDV1) >> + else if (flags & BQ27000_FLAG_EDV1) >> level = POWER_SUPPLY_CAPACITY_LEVEL_LOW; >> else >> level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; >> } else if (di->opts & BQ27Z561_O_BITS) { >> - if (di->cache.flags & BQ27Z561_FLAG_FC) >> + if (flags & BQ27Z561_FLAG_FC) >> level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; >> - else if (di->cache.flags & BQ27Z561_FLAG_FDC) >> + else if (flags & BQ27Z561_FLAG_FDC) >> level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; >> else >> level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; >> } else { >> - if (di->cache.flags & BQ27XXX_FLAG_FC) >> + if (flags & BQ27XXX_FLAG_FC) >> level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; >> - else if (di->cache.flags & BQ27XXX_FLAG_SOCF) >> + else if (flags & BQ27XXX_FLAG_SOCF) >> level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; >> - else if (di->cache.flags & BQ27XXX_FLAG_SOC1) >> + else if (flags & BQ27XXX_FLAG_SOC1) >> level = POWER_SUPPLY_CAPACITY_LEVEL_LOW; >> else >> level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; >> @@ -2004,13 +2080,12 @@ static int bq27xxx_battery_get_property(struct power_supply *psy, >> { >> int ret = 0; >> struct bq27xxx_device_info *di = power_supply_get_drvdata(psy); >> + int flags; >> + int cache; >> >> - mutex_lock(&di->lock); >> - if (time_is_before_jiffies(di->last_update + 5 * HZ)) >> - bq27xxx_battery_update_unlocked(di); >> - mutex_unlock(&di->lock); >> + flags = bq27xxx_cached_reg_value(di, CACHE_REG_FLAGS); >> >> - if (psp != POWER_SUPPLY_PROP_PRESENT && di->cache.flags < 0) >> + if (psp != POWER_SUPPLY_PROP_PRESENT && flags < 0) >> return -ENODEV; >> >> switch (psp) { >> @@ -2021,30 +2096,40 @@ static int bq27xxx_battery_get_property(struct power_supply *psy, >> ret = bq27xxx_battery_voltage(di, val); >> break; >> case POWER_SUPPLY_PROP_PRESENT: >> - val->intval = di->cache.flags < 0 ? 0 : 1; >> + val->intval = flags < 0 ? 0 : 1; >> break; >> case POWER_SUPPLY_PROP_CURRENT_NOW: >> ret = bq27xxx_battery_current_and_status(di, val, NULL, NULL); >> break; >> case POWER_SUPPLY_PROP_CAPACITY: >> - ret = bq27xxx_simple_value(di->cache.capacity, val); >> + cache = bq27xxx_cached_reg_value(di, CACHE_REG_CAPACITY); >> + >> + ret = bq27xxx_simple_value(cache, val); >> break; >> case POWER_SUPPLY_PROP_CAPACITY_LEVEL: >> ret = bq27xxx_battery_capacity_level(di, val); >> break; >> case POWER_SUPPLY_PROP_TEMP: >> - ret = bq27xxx_simple_value(di->cache.temperature, val); >> + cache = bq27xxx_cached_reg_value(di, CACHE_REG_TEMPERATURE); >> + >> + ret = bq27xxx_simple_value(cache, val); >> if (ret == 0) >> val->intval -= 2731; /* convert decidegree k to c */ >> break; >> case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: >> - ret = bq27xxx_simple_value(di->cache.time_to_empty, val); >> + cache = bq27xxx_cached_reg_value(di, CACHE_REG_TIME_TO_EMPTY); >> + >> + ret = bq27xxx_simple_value(cache, val); >> break; >> case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: >> - ret = bq27xxx_simple_value(di->cache.time_to_empty_avg, val); >> + cache = bq27xxx_cached_reg_value(di, CACHE_REG_TIME_TO_EMPTY_AVG); >> + >> + ret = bq27xxx_simple_value(cache, val); >> break; >> case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: >> - ret = bq27xxx_simple_value(di->cache.time_to_full, val); >> + cache = bq27xxx_cached_reg_value(di, CACHE_REG_TIME_TO_FULL); >> + >> + ret = bq27xxx_simple_value(cache, val); >> break; >> case POWER_SUPPLY_PROP_TECHNOLOGY: >> if (di->opts & BQ27XXX_O_MUL_CHEM) >> @@ -2059,7 +2144,9 @@ static int bq27xxx_battery_get_property(struct power_supply *psy, >> ret = bq27xxx_simple_value(bq27xxx_battery_read_rc(di), val); >> break; >> case POWER_SUPPLY_PROP_CHARGE_FULL: >> - ret = bq27xxx_simple_value(di->cache.charge_full, val); >> + cache = bq27xxx_cached_reg_value(di, CACHE_REG_CHARGE_FULL); >> + >> + ret = bq27xxx_simple_value(cache, val); >> break; >> case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: >> ret = bq27xxx_simple_value(di->charge_design_full, val); >> @@ -2072,16 +2159,22 @@ static int bq27xxx_battery_get_property(struct power_supply *psy, >> case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: >> return -EINVAL; >> case POWER_SUPPLY_PROP_CYCLE_COUNT: >> - ret = bq27xxx_simple_value(di->cache.cycle_count, val); >> + cache = bq27xxx_cached_reg_value(di, CACHE_REG_CYCLE_COUNT); >> + >> + ret = bq27xxx_simple_value(cache, val); >> break; >> case POWER_SUPPLY_PROP_ENERGY_NOW: >> - ret = bq27xxx_simple_value(di->cache.energy, val); >> + cache = bq27xxx_cached_reg_value(di, CACHE_REG_ENERGY); >> + >> + ret = bq27xxx_simple_value(cache, val); >> break; >> case POWER_SUPPLY_PROP_POWER_AVG: >> ret = bq27xxx_battery_pwr_avg(di, val); >> break; >> case POWER_SUPPLY_PROP_HEALTH: >> - ret = bq27xxx_simple_value(di->cache.health, val); >> + cache = bq27xxx_battery_read_health(di); >> + >> + ret = bq27xxx_simple_value(cache, val); >> break; >> case POWER_SUPPLY_PROP_MANUFACTURER: >> val->strval = BQ27XXX_MANUFACTURER; >> diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h >> index 7d8025fb74b7..617c8409d80f 100644 >> --- a/include/linux/power/bq27xxx_battery.h >> +++ b/include/linux/power/bq27xxx_battery.h >> @@ -46,17 +46,22 @@ struct bq27xxx_access_methods { >> int (*write_bulk)(struct bq27xxx_device_info *di, u8 reg, u8 *data, int len); >> }; >> >> -struct bq27xxx_reg_cache { >> - int temperature; >> - int time_to_empty; >> - int time_to_empty_avg; >> - int time_to_full; >> - int charge_full; >> - int cycle_count; >> - int capacity; >> - int energy; >> - int flags; >> - int health; >> +struct bq27xxx_cache_reg { >> + int value; >> + unsigned long last_update; >> +}; >> + >> +enum bq27xxx_cache_registers { >> + CACHE_REG_TEMPERATURE = 0, >> + CACHE_REG_TIME_TO_EMPTY, >> + CACHE_REG_TIME_TO_EMPTY_AVG, >> + CACHE_REG_TIME_TO_FULL, >> + CACHE_REG_CHARGE_FULL, >> + CACHE_REG_CYCLE_COUNT, >> + CACHE_REG_CAPACITY, >> + CACHE_REG_ENERGY, >> + CACHE_REG_FLAGS, >> + CACHE_REG_MAX, >> }; >> >> struct bq27xxx_device_info { >> @@ -68,10 +73,9 @@ struct bq27xxx_device_info { >> struct bq27xxx_dm_reg *dm_regs; >> u32 unseal_key; >> struct bq27xxx_access_methods bus; >> - struct bq27xxx_reg_cache cache; >> + struct bq27xxx_cache_reg cache[CACHE_REG_MAX]; >> int charge_design_full; >> bool removed; >> - unsigned long last_update; >> union power_supply_propval last_status; >> struct delayed_work work; >> struct power_supply *bat; >> -- >> 2.39.2 >>