linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Vaittinen, Matti" <Matti.Vaittinen@fi.rohmeurope.com>
To: "andriy.shevchenko@linux.intel.com"  <andriy.shevchenko@linux.intel.com>
Cc: "robh+dt@kernel.org" <robh+dt@kernel.org>,
	"dan.j.williams@intel.com" <dan.j.williams@intel.com>,
	"tglx@linutronix.de" <tglx@linutronix.de>,
	"talgi@mellanox.com" <talgi@mellanox.com>,
	"olteanv@gmail.com" <olteanv@gmail.com>,
	"davem@davemloft.net" <davem@davemloft.net>,
	"brendanhiggins@google.com" <brendanhiggins@google.com>,
	"linux-pm@vger.kernel.org" <linux-pm@vger.kernel.org>,
	"devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"davidgow@google.com" <davidgow@google.com>,
	"broonie@kernel.org" <broonie@kernel.org>,
	"herbert@gondor.apana.org.au" <herbert@gondor.apana.org.au>,
	"lgirdwood@gmail.com" <lgirdwood@gmail.com>,
	"rdunlap@infradead.org" <rdunlap@infradead.org>,
	"mark.rutland@arm.com" <mark.rutland@arm.com>,
	"yamada.masahiro@socionext.com" <yamada.masahiro@socionext.com>,
	"Mutanen, Mikko" <Mikko.Mutanen@fi.rohmeurope.com>,
	"bp@suse.de" <bp@suse.de>,
	"mhiramat@kernel.org" <mhiramat@kernel.org>,
	"krzk@kernel.org" <krzk@kernel.org>,
	"mazziesaccount@gmail.com" <mazziesaccount@gmail.com>,
	"skhan@linuxfoundation.org" <skhan@linuxfoundation.org>,
	"gregkh@linuxfoundation.org" <gregkh@linuxfoundation.org>,
	"Laine, Markus" <Markus.Laine@fi.rohmeurope.com>,
	"vincenzo.frascino@arm.com" <vincenzo.frascino@arm.com>,
	"sre@kernel.org" <sre@kernel.org>,
	"linus.walleij@linaro.org" <linus.walleij@linaro.org>,
	"zaslonko@linux.ibm.com" <zaslonko@linux.ibm.com>,
	"uwe@kleine-koenig.org" <uwe@kleine-koenig.org>,
	"akpm@linux-foundation.org" <akpm@linux-foundation.org>
Subject: Re: [PATCH v7 09/10] power: supply: Support ROHM bd99954 charger
Date: Wed, 1 Apr 2020 08:08:10 +0000	[thread overview]
Message-ID: <1e85aed72944093cef5385db07e651aac313bf72.camel@fi.rohmeurope.com> (raw)
In-Reply-To: <20200331141933.GK1922688@smile.fi.intel.com>

Hello Again Andy :)

Thanks for looking at this. I appreciate your review work and all the
good tips!

On Tue, 2020-03-31 at 17:19 +0300, Andy Shevchenko wrote:
> On Tue, Mar 31, 2020 at 03:28:17PM +0300, Matti Vaittinen wrote:
> > The ROHM BD99954 is a Battery Management LSI for 1-4 cell Lithium-
> > Ion
> > secondary battery intended to be used in space-constraint equipment
> > such
> > as Low profile Notebook PC, Tablets and other applications. BD99954
> > provides a Dual-source Battery Charger, two port BC1.2 detection
> > and a
> > Battery Monitor.
> > 
> > Support ROHM BD99954 Charger IC.
> 
> ...
> 
> > +static irqreturn_t bd9995x_irq_handler_thread(int irq, void
> > *private)
> > +{
> > +	struct bd9995x_device *bd = private;
> > +	int ret, status, mask, i;
> > +	unsigned long tmp;
> > +	struct bd9995x_state state;
> > +
> > +	/*
> > +	 * The bd9995x does not seem to generate big amount of
> > interrupts.
> > +	 * The logic regarding which interrupts can cause relevant
> > +	 * status changes seem to be pretty complex.
> > +	 *
> > +	 * So lets implement really simple and hopefully bullet-proof
> > handler:
> > +	 * It does not really matter which IRQ we handle, we just go
> > and
> > +	 * re-read all interesting statuses + give the framework a
> > nudge.
> > +	 *
> > +	 * Other option would be building a _complex_ and error prone
> > logic
> > +	 * trying to decide what could have been changed (resulting
> > this IRQ
> > +	 * we are now handling). During the normal operation the
> > BD99954 does
> > +	 * not seem to be generating much of interrupts so benefit from
> > such
> > +	 * logic would probably be minimal.
> > +	 */
> > +
> > +	ret = regmap_read(bd->rmap, INT0_STATUS, &status);
> > +	if (ret) {
> > +		dev_err(bd->dev, "Failed to read IRQ status\n");
> > +		return IRQ_NONE;
> > +	}
> > +
> > +	ret = regmap_field_read(bd->rmap_fields[F_INT0_SET], &mask);
> > +	if (ret) {
> > +		dev_err(bd->dev, "Failed to read IRQ mask\n");
> > +		return IRQ_NONE;
> > +	}
> > +
> > +	/* Handle only IRQs that are not masked */
> > +	status &= mask;
> > +	tmp = status;
> > +
> > +	/* Lowest bit does not represent any sub-registers */
> > +	tmp >>= 1;
> > +
> > +	/*
> > +	 * Mask and ack IRQs we will handle (+ the idiot bit)
> > +	 */
> > +	ret = regmap_field_write(bd->rmap_fields[F_INT0_SET], 0);
> > +	if (ret) {
> > +		dev_err(bd->dev, "Failed to mask F_INT0\n");
> > +		return IRQ_NONE;
> > +	}
> > +
> > +	ret = regmap_write(bd->rmap, INT0_STATUS, status);
> > +	if (ret) {
> > +		dev_err(bd->dev, "Failed to ack F_INT0\n");
> > +		goto err_umask;
> > +	}
> > +
> > +	for_each_set_bit(i, &tmp, 7) {
> > +		int sub_status, sub_mask;
> > +		int sub_status_reg[] = {
> > +			INT1_STATUS, INT2_STATUS, INT3_STATUS,
> > INT4_STATUS,
> > +			INT5_STATUS, INT6_STATUS, INT7_STATUS,
> > +		};
> > +		struct regmap_field *sub_mask_f[] = {
> > +			bd->rmap_fields[F_INT1_SET],
> > +			bd->rmap_fields[F_INT2_SET],
> > +			bd->rmap_fields[F_INT3_SET],
> > +			bd->rmap_fields[F_INT4_SET],
> > +			bd->rmap_fields[F_INT5_SET],
> > +			bd->rmap_fields[F_INT6_SET],
> > +			bd->rmap_fields[F_INT7_SET],
> > +		};
> > +
> > +		/* Clear sub IRQs */
> > +		ret = regmap_read(bd->rmap, sub_status_reg[i],
> > &sub_status);
> > +		if (ret) {
> > +			dev_err(bd->dev, "Failed to read IRQ sub-
> > status\n");
> > +			goto err_umask;
> > +		}
> 
> Looking into it makes me thing that you perhaps need regmap IRQ chip?
> Have you chance to look at drivers/mfd/intel_soc_pmic_bxtwc.c, for
> example?

I've used regmap_irq previously for few cases. And I was considering
using it here but noticed pretty soon that defining and requesting all
the different IRQs just so that they could be handled by this same
handler made no sense.

> 
> > +		ret = regmap_field_read(sub_mask_f[i], &sub_mask);
> > +		if (ret) {
> > +			dev_err(bd->dev, "Failed to read IRQ sub-
> > mask\n");
> > +			goto err_umask;
> > +		}
> > +
> > +		/* Ack active sub-statuses */
> > +		sub_status &= sub_mask;
> > +
> > +		ret = regmap_write(bd->rmap, sub_status_reg[i],
> > sub_status);
> > +		if (ret) {
> > +			dev_err(bd->dev, "Failed to ack sub-IRQ\n");
> > +			goto err_umask;
> > +		}
> > +	}
> > +
> > +	ret = regmap_field_write(bd->rmap_fields[F_INT0_SET], mask);
> > +	if (ret)
> > +		/* May as well retry once */
> > +		goto err_umask;
> > +
> > +	/* Read whole chip state */
> > +	ret = bd9995x_get_chip_state(bd, &state);
> > +	if (ret < 0) {
> > +		dev_err(bd->dev, "Failed to read chip state\n");
> > +	} else {
> > +		mutex_lock(&bd->lock);
> > +		bd->state = state;
> > +		mutex_unlock(&bd->lock);
> > +
> > +		power_supply_changed(bd->charger);
> > +	}
> > +
> > +	return IRQ_HANDLED;
> > +
> > +err_umask:
> > +	ret = regmap_field_write(bd->rmap_fields[F_INT0_SET], mask);
> > +	if (ret)
> > +		dev_err(bd->dev,
> > +		"Failed to un-mask F_INT0 - IRQ permanently
> > disabled\n");
> > +
> > +	return IRQ_NONE;
> > +}
> 
> ...
> 
> > +static int bd9995x_fw_probe(struct bd9995x_device *bd)
> > +{
> > +	int ret;
> > +	struct power_supply_battery_info info;
> > +	u32 property;
> > +	int i;
> > +	int regval;
> > +	bool found;
> > +	struct bd9995x_init_data *init = &bd->init_data;
> > +	struct battery_init battery_inits[] = {
> > +		{
> > +			.name = "trickle-charging current",
> > +			.info_data = &info.tricklecharge_current_ua,
> > +			.range = &charging_current_ranges[0],
> > +			.ranges = 2,
> > +			.data = &init->itrich_set,
> > +		}, {
> > +			.name = "pre-charging current",
> > +			.info_data = &info.precharge_current_ua,
> > +			.range = &charging_current_ranges[0],
> > +			.ranges = 2,
> > +			.data = &init->iprech_set,
> > +		}, {
> > +			.name = "pre-to-trickle charge voltage
> > threshold",
> > +			.info_data = &info.precharge_voltage_max_uv,
> > +			.range = &trickle_to_pre_threshold_ranges[0],
> > +			.ranges = 2,
> > +			.data = &init->vprechg_th_set,
> > +		}, {
> > +			.name = "charging termination current",
> > +			.info_data = &info.charge_term_current_ua,
> > +			.range = &charging_current_ranges[0],
> > +			.ranges = 2,
> > +			.data = &init->iterm_set,
> > +		}, {
> > +			.name = "charging re-start voltage",
> > +			.info_data = &info.charge_restart_voltage_uv,
> > +			.range = &charge_voltage_regulation_ranges[0],
> > +			.ranges = 2,
> > +			.data = &init->vrechg_set,
> > +		}, {
> > +			.name = "battery overvoltage limit",
> > +			.info_data = &info.overvoltage_limit_uv,
> > +			.range = &charge_voltage_regulation_ranges[0],
> > +			.ranges = 2,
> > +			.data = &init->vbatovp_set,
> > +		}, {
> > +			.name = "fast-charging max current",
> > +			.info_data =
> > &info.constant_charge_current_max_ua,
> > +			.range = &fast_charge_current_ranges[0],
> > +			.ranges = 1,
> > +			.data = &init->ichg_set,
> > +		}, {
> > +			.name = "fast-charging voltage",
> > +			.info_data =
> > &info.constant_charge_voltage_max_uv,
> > +			.range = &charge_voltage_regulation_ranges[0],
> > +			.ranges = 2,
> > +			.data = &init->vfastchg_reg_set1,
> > +		},
> > +	};
> > +	struct dt_init props[] = {
> > +		{
> > +			.prop = "rohm,vsys-regulation-microvolt",
> > +			.range = &vsys_voltage_regulation_ranges[0],
> > +			.ranges = 2,
> > +			.data = &init->vsysreg_set,
> > +		}, {
> > +			.prop = "rohm,vbus-input-current-limit-
> > microamp",
> > +			.range = &input_current_limit_ranges[0],
> > +			.ranges = 1,
> > +			.data = &init->ibus_lim_set,
> > +		}, {
> > +			.prop = "rohm,vcc-input-current-limit-
> > microamp",
> > +			.range = &input_current_limit_ranges[0],
> > +			.ranges = 1,
> > +			.data = &init->icc_lim_set,
> > +		},
> > +	};
> > +
> > +	/*
> > +	 * The power_supply_get_battery_info() does not support getting
> > values
> > +	 * from ACPI. Let's fix it if ACPI is required here.
> > +	 */
> 
> Previously we discussed this and you told that you don't need ACPI
> support. Did
> I get your wrong or something has been changed? If the latter,
> perhaps
> converting power supply core to use device property API is not harder
> than what
> you have done below.

I don't need ACPI support for now. But if it comes to play a role, then
these comment work as a reminder for me to fix the
power_supply_get_battery_info().

I am not sure if you noticed that this property parsing is done in two
places (here and in power_supply_get_battery_info() ) because we use
properties from two nodes. power_supply_get_battery_info() gets
properties from static battery node if such is present meanwhile this
driver scans it's own (charger) node for charger related (not battery
related) properties. Currently all of these are expected to be in DT -
but I wouldn't be so surprized if ACPI was required at some point. I
still don't want to invest on fixing power_supply_get_battery_info()
for ACPI as I try to keep size of this series somehow reasonable - and
because I don't have test environment for BD99954 with ACPI in use.

> > +	ret = power_supply_get_battery_info(bd->charger, &info);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	for (i = 0; i < ARRAY_SIZE(battery_inits); i++) {
> > +		int val = *battery_inits[i].info_data;
> > +		const struct linear_range *range =
> > battery_inits[i].range;
> > +		int ranges = battery_inits[i].ranges;
> > +
> > +		if (val == -EINVAL)
> > +			continue;
> > +
> > +		ret = linear_range_get_selector_low_array(range,
> > ranges, val,
> > +							  &regval,
> > &found);
> > +		if (ret) {
> > +			dev_err(bd->dev, "Unsupported value for %s\n",
> > +				battery_inits[i].name);
> > +
> > +			power_supply_put_battery_info(bd->charger,
> > &info);
> > +			return -EINVAL;
> > +		}
> > +		if (!found) {
> > +			dev_warn(bd->dev,
> > +				 "Unsupported value for %s - using
> > smaller\n",
> > +				 battery_inits[i].name);
> > +		}
> > +		*(battery_inits[i].data) = regval;
> > +	}
> > +
> > +	power_supply_put_battery_info(bd->charger, &info);
> > +
> > +	for (i = 0; i < ARRAY_SIZE(props); i++) {
> > +		ret = device_property_read_u32(bd->dev, props[i].prop,
> > +					       &property);
> > +		if (ret < 0) {
> > +			dev_err(bd->dev, "failed to read %s",
> > props[i].prop);
> > +
> > +			return ret;
> > +		}
> > +
> > +		ret =
> > linear_range_get_selector_low_array(props[i].range,
> > +							  props[i].rang
> > es,
> > +							  property,
> > &regval,
> > +							  &found);
> > +		if (ret) {
> > +			dev_err(bd->dev, "Unsupported value for
> > '%s'\n",
> > +				props[i].prop);
> > +
> > +			return -EINVAL;
> > +		}
> > +
> > +		if (!found) {
> > +			dev_warn(bd->dev,
> > +				 "Unsupported value for '%s' - using
> > smaller\n",
> > +				 props[i].prop);
> > +		}
> > +
> > +		*(props[i].data) = regval;
> > +	}
> > +
> > +	return 0;
> > +}


Best Regards
	--Matti

  reply	other threads:[~2020-04-01  8:08 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <cover.1585656143.git.matti.vaittinen@fi.rohmeurope.com>
2020-03-31 12:21 ` [PATCH v7 01/10] dt-bindings: battery: add new battery parameters Matti Vaittinen
2020-03-31 12:22 ` [PATCH v7 02/10] dt_bindings: ROHM BD99954 Charger Matti Vaittinen
2020-03-31 12:23 ` [PATCH v7 04/10] lib/test_linear_ranges: add a test for the 'linear_ranges' Matti Vaittinen
2020-03-31 18:08   ` Brendan Higgins
2020-04-01  8:45     ` Vaittinen, Matti
2020-04-01 18:48       ` Brendan Higgins
2020-04-02 15:39         ` Vaittinen, Matti
2020-03-31 12:24 ` [PATCH v7 05/10] power: supply: bd70528: rename linear_range to avoid collision Matti Vaittinen
2020-03-31 12:26 ` [PATCH v7 07/10] power: supply: bd70528: use linear ranges Matti Vaittinen
2020-03-31 12:26 ` [PATCH v7 08/10] power: supply: add battery parameters Matti Vaittinen
2020-03-31 12:28 ` [PATCH v7 09/10] power: supply: Support ROHM bd99954 charger Matti Vaittinen
2020-03-31 14:19   ` Andy Shevchenko
2020-04-01  8:08     ` Vaittinen, Matti [this message]
2020-03-31 12:29 ` [PATCH v7 10/10] power: supply: Fix Kconfig help text indentiation Matti Vaittinen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1e85aed72944093cef5385db07e651aac313bf72.camel@fi.rohmeurope.com \
    --to=matti.vaittinen@fi.rohmeurope.com \
    --cc=Markus.Laine@fi.rohmeurope.com \
    --cc=Mikko.Mutanen@fi.rohmeurope.com \
    --cc=akpm@linux-foundation.org \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=bp@suse.de \
    --cc=brendanhiggins@google.com \
    --cc=broonie@kernel.org \
    --cc=dan.j.williams@intel.com \
    --cc=davem@davemloft.net \
    --cc=davidgow@google.com \
    --cc=devicetree@vger.kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=herbert@gondor.apana.org.au \
    --cc=krzk@kernel.org \
    --cc=lgirdwood@gmail.com \
    --cc=linus.walleij@linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=mazziesaccount@gmail.com \
    --cc=mhiramat@kernel.org \
    --cc=olteanv@gmail.com \
    --cc=rdunlap@infradead.org \
    --cc=robh+dt@kernel.org \
    --cc=skhan@linuxfoundation.org \
    --cc=sre@kernel.org \
    --cc=talgi@mellanox.com \
    --cc=tglx@linutronix.de \
    --cc=uwe@kleine-koenig.org \
    --cc=vincenzo.frascino@arm.com \
    --cc=yamada.masahiro@socionext.com \
    --cc=zaslonko@linux.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).