All of lore.kernel.org
 help / color / mirror / Atom feed
From: kgunda@codeaurora.org
To: Bjorn Andersson <bjorn.andersson@linaro.org>
Cc: jingoohan1@gmail.com, lee.jones@linaro.org,
	b.zolnierkie@samsung.com, dri-devel@lists.freedesktop.org,
	Daniel Thompson <daniel.thompson@linaro.org>,
	linux-fbdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-msm@vger.kernel.org, linux-leds@vger.kernel.org,
	linux-arm-msm-owner@vger.kernel.org
Subject: Re: [PATCH V3 7/7] backlight: qcom-wled: Add auto string detection logic
Date: Wed, 20 Jun 2018 18:07:39 +0530	[thread overview]
Message-ID: <f93eafc1faadc1e0357d24cba7392fad@codeaurora.org> (raw)
In-Reply-To: <20180620062256.GK15126@tuxbook-pro>

On 2018-06-20 11:52, Bjorn Andersson wrote:
> On Tue 19 Jun 04:13 PDT 2018, Kiran Gunda wrote:
> 
>> The auto string detection algorithm checks if the current WLED
>> sink configuration is valid. It tries enabling every sink and
>> checks if the OVP fault is observed. Based on this information
>> it detects and enables the valid sink configuration.
>> Auto calibration will be triggered when the OVP fault interrupts
>> are seen frequently thereby it tries to fix the sink configuration.
>> 
>> The auto-detection also kicks in when the connected LED string
>> of the display-backlight malfunctions (because of damage) and
>> requires the damaged string to be turned off to prevent the
>> complete panel and/or board from being damaged.
>> 
>> Signed-off-by: Kiran Gunda <kgunda@codeaurora.org>
>> ---
>>  drivers/video/backlight/qcom-wled.c | 408 
>> +++++++++++++++++++++++++++++++++++-
>>  1 file changed, 403 insertions(+), 5 deletions(-)
>> 
>> diff --git a/drivers/video/backlight/qcom-wled.c 
>> b/drivers/video/backlight/qcom-wled.c
>> index e87ba70..6bc627c 100644
>> --- a/drivers/video/backlight/qcom-wled.c
>> +++ b/drivers/video/backlight/qcom-wled.c
>> @@ -25,13 +25,23 @@
>>  #define WLED_MAX_STRINGS				4
>> 
>>  #define WLED_DEFAULT_BRIGHTNESS				2048
>> -
>> +#define WLED_SOFT_START_DLY_US				10000
>>  #define WLED3_SINK_REG_BRIGHT_MAX			0xFFF
>> 
>>  /* WLED3 control registers */
>> +#define WLED3_CTRL_REG_FAULT_STATUS			0x08
>> +#define  WLED3_CTRL_REG_ILIM_FAULT_BIT			BIT(0)
>> +#define  WLED3_CTRL_REG_OVP_FAULT_BIT			BIT(1)
>> +#define  WLED4_CTRL_REG_SC_FAULT_BIT			BIT(2)
>> +
>> +#define WLED3_CTRL_REG_INT_RT_STS			0x10
>> +#define  WLED3_CTRL_REG_OVP_FAULT_STATUS		BIT(1)
>> +
> 
> These seems to be used in both WLED 3 and 4, so please drop the 3 from
> the name.
> 
Sure. I will change it in the next series.
>>  #define WLED3_CTRL_REG_MOD_EN				0x46
>>  #define  WLED3_CTRL_REG_MOD_EN_MASK			BIT(7)
>> 
>> +#define WLED3_CTRL_REG_FEEDBACK_CONTROL			0x48
>> +
>>  #define WLED3_CTRL_REG_FREQ				0x4c
>>  #define  WLED3_CTRL_REG_FREQ_MASK			GENMASK(3, 0)
>> 
>> @@ -146,6 +156,7 @@ struct wled_config {
>>  	bool ext_gen;
>>  	bool cabc;
>>  	bool external_pfet;
>> +	bool auto_detection_enabled;
>>  };
>> 
>>  struct wled {
>> @@ -154,16 +165,22 @@ struct wled {
>>  	struct regmap *regmap;
>>  	struct mutex lock;	/* Lock to avoid race from ISR */
>>  	ktime_t last_short_event;
>> +	ktime_t start_ovp_fault_time;
>>  	u16 ctrl_addr;
>>  	u16 sink_addr;
>> +	u16 auto_detection_ovp_count;
>>  	u32 brightness;
>>  	u32 max_brightness;
>>  	u32 short_count;
>> +	u32 auto_detect_count;
>>  	const int *version;
>>  	bool disabled_by_short;
>>  	bool has_short_detect;
>> +	int ovp_irq;
>> +	bool ovp_irq_disabled;
>> 
>>  	struct wled_config cfg;
>> +	struct delayed_work ovp_work;
>>  	int (*wled_set_brightness)(struct wled *wled, u16 brightness);
>>  	int (*wled_sync_toggle)(struct wled *wled);
>>  };
>> @@ -209,6 +226,27 @@ static int wled4_set_brightness(struct wled 
>> *wled, u16 brightness)
>>  	return 0;
>>  }
>> 
>> +static void wled_ovp_work(struct work_struct *work)
>> +{
>> +	u32 val;
>> +	int rc;
>> +
>> +	struct wled *wled = container_of(work,
>> +					 struct wled, ovp_work.work);
>> +
>> +	rc = regmap_read(wled->regmap, wled->ctrl_addr + 
>> WLED3_CTRL_REG_MOD_EN,
>> +			 &val);
>> +	if (rc < 0)
>> +		return;
>> +
>> +	if (val & WLED3_CTRL_REG_MOD_EN_MASK) {
> 
> The way you implement this now makes this a "delayed enable_irq" 
> worker,
> as such you shouldn't need to check if the hardware is enabled here but
> just blindly enable_irq() and then in module_enable() you can check the
> return value of cancel_delayed_work() to know if enable_irq() has been
> called.
> 
Ok. I will modify as per your suggestion in the next series.
>> +		if (wled->ovp_irq > 0 && wled->ovp_irq_disabled) {
>> +			enable_irq(wled->ovp_irq);
>> +			wled->ovp_irq_disabled = false;
>> +		}
>> +	}
>> +}
>> +
>>  static int wled_module_enable(struct wled *wled, int val)
>>  {
>>  	int rc;
>> @@ -220,7 +258,20 @@ static int wled_module_enable(struct wled *wled, 
>> int val)
>>  				WLED3_CTRL_REG_MOD_EN,
>>  				WLED3_CTRL_REG_MOD_EN_MASK,
>>  				WLED3_CTRL_REG_MOD_EN_MASK);
>> -	return rc;
>> +	if (rc < 0)
>> +		return rc;
>> +
>> +	if (val) {
>> +		schedule_delayed_work(&wled->ovp_work, WLED_SOFT_START_DLY_US);
>> +	} else {
>> +		cancel_delayed_work(&wled->ovp_work);
> 
> I recommend using cancel_delayed_work_sync() to ensure that htis isn't
> racing with the worker.
> 
Sure. I will modify it in next series.
>> +		if (wled->ovp_irq > 0 && !wled->ovp_irq_disabled) {
>> +			disable_irq(wled->ovp_irq);
>> +			wled->ovp_irq_disabled = true;
>> +		}
>> +	}
>> +
>> +	return 0;
>>  }
>> 
>>  static int wled3_sync_toggle(struct wled *wled)
>> @@ -346,6 +397,305 @@ static irqreturn_t wled_short_irq_handler(int 
>> irq, void *_wled)
>>  	return IRQ_HANDLED;
>>  }
>> 
>> +#define AUTO_DETECT_BRIGHTNESS		200
>> +static int wled_auto_string_detection(struct wled *wled)
> 
> You don't care about the return value of this function in any of the
> callers.
> 
I will make it void in the next series.
>> +{
>> +	int rc = 0, i;
>> +	u32 sink_config = 0, int_sts;
>> +	u8 sink_test = 0, sink_valid = 0, val;
>> +
>> +	/* read configured sink configuration */
>> +	rc = regmap_read(wled->regmap, wled->sink_addr +
>> +			 WLED4_SINK_REG_CURR_SINK, &sink_config);
>> +	if (rc < 0) {
>> +		pr_err("Failed to read SINK configuration rc=%d\n", rc);
>> +		goto failed_detect;
>> +	}
>> +
>> +	/* disable the module before starting detection */
>> +	rc = regmap_update_bits(wled->regmap,
>> +				wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN,
>> +				WLED3_CTRL_REG_MOD_EN_MASK, 0);
>> +	if (rc < 0) {
>> +		pr_err("Failed to disable WLED module rc=%d\n", rc);
>> +		goto failed_detect;
>> +	}
>> +
>> +	/* set low brightness across all sinks */
>> +	rc = wled4_set_brightness(wled, AUTO_DETECT_BRIGHTNESS);
>> +	if (rc < 0) {
>> +		pr_err("Failed to set brightness for auto detection rc=%d\n",
>> +		       rc);
>> +		goto failed_detect;
>> +	}
>> +
>> +	if (wled->cfg.cabc) {
>> +		for (i = 0; i < wled->cfg.num_strings; i++) {
>> +			rc = regmap_update_bits(wled->regmap, wled->sink_addr +
>> +						WLED4_SINK_REG_STR_CABC(i),
>> +						WLED4_SINK_REG_STR_CABC_MASK,
>> +						0);
>> +			if (rc < 0)
>> +				goto failed_detect;
>> +		}
>> +	}
>> +
>> +	/* disable all sinks */
>> +	rc = regmap_write(wled->regmap,
>> +			  wled->sink_addr + WLED4_SINK_REG_CURR_SINK, 0);
>> +	if (rc < 0) {
>> +		pr_err("Failed to disable all sinks rc=%d\n", rc);
>> +		goto failed_detect;
>> +	}
>> +
>> +	/* iterate through the strings one by one */
>> +	for (i = 0; i < wled->cfg.num_strings; i++) {
>> +		sink_test = BIT((WLED4_SINK_REG_CURR_SINK_SHFT + i));
>> +
>> +		/* Enable feedback control */
>> +		rc = regmap_write(wled->regmap, wled->ctrl_addr +
>> +				  WLED3_CTRL_REG_FEEDBACK_CONTROL, i + 1);
>> +		if (rc < 0) {
>> +			pr_err("Failed to enable feedback for SINK %d rc = %d\n",
>> +			       i + 1, rc);
>> +			goto failed_detect;
>> +		}
>> +
>> +		/* enable the sink */
>> +		rc = regmap_write(wled->regmap, wled->sink_addr +
>> +				  WLED4_SINK_REG_CURR_SINK, sink_test);
>> +		if (rc < 0) {
>> +			pr_err("Failed to configure SINK %d rc=%d\n", i + 1,
>> +			       rc);
>> +			goto failed_detect;
>> +		}
>> +
>> +		/* Enable the module */
>> +		rc = regmap_update_bits(wled->regmap, wled->ctrl_addr +
>> +					WLED3_CTRL_REG_MOD_EN,
>> +					WLED3_CTRL_REG_MOD_EN_MASK,
>> +					WLED3_CTRL_REG_MOD_EN_MASK);
>> +		if (rc < 0) {
>> +			pr_err("Failed to enable WLED module rc=%d\n", rc);
>> +			goto failed_detect;
>> +		}
>> +
>> +		usleep_range(WLED_SOFT_START_DLY_US,
>> +			     WLED_SOFT_START_DLY_US + 1000);
>> +
>> +		rc = regmap_read(wled->regmap, wled->ctrl_addr +
>> +				 WLED3_CTRL_REG_INT_RT_STS, &int_sts);
>> +		if (rc < 0) {
>> +			pr_err("Error in reading WLED3_CTRL_INT_RT_STS rc=%d\n",
>> +			       rc);
> 
> You should probably do something about the state of the hardware if it
> fail here.
> 
This is a spmi read and it is very unlikely to fail. If it fails it 
leads the complete
system to go in to bad state.
>> +			goto failed_detect;
>> +		}
>> +
>> +		if (int_sts & WLED3_CTRL_REG_OVP_FAULT_STATUS)
>> +			pr_debug("WLED OVP fault detected with SINK %d\n",
>> +				 i + 1);
>> +		else
>> +			sink_valid |= sink_test;
>> +
>> +		/* Disable the module */
>> +		rc = regmap_update_bits(wled->regmap,
>> +					wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN,
>> +					WLED3_CTRL_REG_MOD_EN_MASK, 0);
>> +		if (rc < 0) {
>> +			pr_err("Failed to disable WLED module rc=%d\n", rc);
>> +			goto failed_detect;
>> +		}
>> +	}
>> +
>> +	if (sink_valid == sink_config) {
>> +		pr_debug("WLED auto-detection complete, default sink-config=%x 
>> OK!\n",
>> +			 sink_config);
> 
> It's not the "default" sink config we're using, it's whatever was
> configured before this function was called.
> 
I will correct it in the next series.
>> +	} else {
>> +		pr_warn("Invalid WLED default sink config=%x changing it to=%x\n",
> 
> Use dev_warn(), and as it's not the "default sink config" that's 
> invalid
> write something like "New WLED string configuration found: %x". Perhaps
> you can print it using %*pbl ?
> 
I will modify it in the next series. I missed to modify here.
>> +			sink_config, sink_valid);
>> +		sink_config = sink_valid;
>> +	}
>> +
>> +	if (!sink_config) {
>> +		pr_err("No valid WLED sinks found\n");
> 
> dev_err() and move this above the other prints, there's no reason to
> first say that you found an "invalid WLED default" and then say that 
> you
> didn't findd a valid config.
> 
Sure. I will move it in the next series.
>> +		wled->disabled_by_short = true;
>> +		goto failed_detect;
>> +	}
>> +
>> +	/* write the new sink configuration */
>> +	rc = regmap_write(wled->regmap,
>> +			  wled->sink_addr + WLED4_SINK_REG_CURR_SINK,
>> +			  sink_config);
>> +	if (rc < 0) {
>> +		pr_err("Failed to reconfigure the default sink rc=%d\n", rc);
>> +		goto failed_detect;
>> +	}
>> +
>> +	/* Enable valid sinks */
>> +	for (i = 0; i < wled->cfg.num_strings; i++) {
>> +		if (wled->cfg.cabc) {
>> +			rc = regmap_update_bits(wled->regmap, wled->sink_addr +
>> +						WLED4_SINK_REG_STR_CABC(i),
>> +						WLED4_SINK_REG_STR_CABC_MASK,
>> +						WLED4_SINK_REG_STR_CABC_MASK);
>> +			if (rc < 0)
>> +				goto failed_detect;
>> +		}
>> +
>> +		if (sink_config & BIT(WLED4_SINK_REG_CURR_SINK_SHFT + i))
>> +			val = WLED4_SINK_REG_STR_MOD_MASK;
>> +		else
>> +			val = 0x0; /* disable modulator_en for unused sink */
>> +
>> +		rc = regmap_write(wled->regmap, wled->sink_addr +
>> +				  WLED4_SINK_REG_STR_MOD_EN(i), val);
>> +		if (rc < 0) {
>> +			pr_err("Failed to configure MODULATOR_EN rc=%d\n", rc);
>> +			goto failed_detect;
>> +		}
>> +	}
>> +
>> +	/* restore the feedback setting */
>> +	rc = regmap_write(wled->regmap,
>> +			  wled->ctrl_addr + WLED3_CTRL_REG_FEEDBACK_CONTROL, 0);
>> +	if (rc < 0) {
>> +		pr_err("Failed to restore feedback setting rc=%d\n", rc);
>> +		goto failed_detect;
>> +	}
>> +
>> +	/* restore  brightness */
> 
> Extra space
> 
Will remove it in the next series.
>> +	rc = wled4_set_brightness(wled, wled->brightness);
>> +	if (rc < 0) {
>> +		pr_err("Failed to set brightness after auto detection rc=%d\n",
>> +		       rc);
>> +		goto failed_detect;
>> +	}
>> +
>> +	rc = regmap_update_bits(wled->regmap,
>> +				wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN,
>> +				WLED3_CTRL_REG_MOD_EN_MASK,
>> +				WLED3_CTRL_REG_MOD_EN_MASK);
>> +	if (rc < 0) {
>> +		pr_err("Failed to enable WLED module rc=%d\n", rc);
>> +		goto failed_detect;
>> +	}
>> +
>> +failed_detect:
>> +	return rc;
>> +}
>> +
>> +#define WLED_AUTO_DETECT_OVP_COUNT		5
>> +#define WLED_AUTO_DETECT_CNT_DLY_US		USEC_PER_SEC
>> +static bool wled_auto_detection_required(struct wled *wled)
>> +{
>> +	s64 elapsed_time_us;
>> +
>> +	if (*wled->version == WLED_PM8941 || 
>> !wled->cfg.auto_detection_enabled)
> 
> Ensure that auto_detection_enabled can't be enabled for pm8941, so that
> you don't need to check the first part.
> 
I will change it in the next series.
>> +		return false;
>> +
>> +	/*
>> +	 * Check if the OVP fault was an occasional one
>> +	 * or if it's firing continuously, the latter qualifies
>> +	 * for an auto-detection check.
>> +	 */
>> +	if (!wled->auto_detection_ovp_count) {
>> +		wled->start_ovp_fault_time = ktime_get();
>> +		wled->auto_detection_ovp_count++;
>> +	} else {
>> +		elapsed_time_us = ktime_us_delta(ktime_get(),
>> +						 wled->start_ovp_fault_time);
>> +		if (elapsed_time_us > WLED_AUTO_DETECT_CNT_DLY_US)
>> +			wled->auto_detection_ovp_count = 0;
>> +		else
>> +			wled->auto_detection_ovp_count++;
>> +
>> +		if (wled->auto_detection_ovp_count >=
>> +				WLED_AUTO_DETECT_OVP_COUNT) {
>> +			wled->auto_detection_ovp_count = 0;
>> +			return true;
>> +		}
>> +	}
>> +
>> +	return false;
>> +}
>> +
>> +static int wled_auto_detection_at_init(struct wled *wled)
>> +{
>> +	int rc;
>> +	u32 fault_status = 0, rt_status = 0;
> 
> No need to initialize these, they will be filled out if regmap_read
> return successfully.
> 
I will remove it in the next series.
>> +
>> +	if (!wled->cfg.auto_detection_enabled)
>> +		return 0;
>> +
> [..]
>> @@ -836,6 +1192,42 @@ static int wled_configure_short_irq(struct wled 
>> *wled,
>>  	return rc;
>>  }
>> 
>> +static int wled_configure_ovp_irq(struct wled *wled,
>> +				  struct platform_device *pdev)
>> +{
>> +	int rc = 0;
> 
> No need to initialize rc here.
> 
I will remove it in the next series.
>> +	u32 val;
>> +
>> +	wled->ovp_irq = platform_get_irq_byname(pdev, "ovp");
>> +	if (wled->ovp_irq < 0) {
>> +		dev_dbg(&pdev->dev, "ovp irq is not used\n");
>> +		return 0;
>> +	}
>> +
>> +	rc = devm_request_threaded_irq(wled->dev, wled->ovp_irq, NULL,
>> +				       wled_ovp_irq_handler, IRQF_ONESHOT,
>> +				       "wled_ovp_irq", wled);
>> +	if (rc < 0) {
>> +		dev_err(wled->dev, "Unable to request ovp_irq (err:%d)\n",
>> +			rc);
>> +		wled->ovp_irq = 0;
>> +		return 0;
>> +	}
>> +
>> +	rc = regmap_read(wled->regmap, wled->ctrl_addr +
>> +			 WLED3_CTRL_REG_MOD_EN, &val);
>> +	if (rc < 0)
>> +		return rc;
>> +
>> +	/* Keep OVP irq disabled until module is enabled */
>> +	if (!rc && !(val & WLED3_CTRL_REG_MOD_EN_MASK)) {
> 
> If rc isn't 0 we returned above.
> 
I will remove it in the next series.
>> +		disable_irq(wled->ovp_irq);
>> +		wled->ovp_irq_disabled = true;
>> +	}
>> +
>> +	return rc;
> 
> As such, it is always 0 here.
> 
I will modify it in the next series.
>> +}
>> +
> 
> Regards,
> Bjorn
> --
> To unsubscribe from this list: send the line "unsubscribe 
> linux-arm-msm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

WARNING: multiple messages have this Message-ID (diff)
From: kgunda@codeaurora.org
To: Bjorn Andersson <bjorn.andersson@linaro.org>
Cc: jingoohan1@gmail.com, lee.jones@linaro.org,
	b.zolnierkie@samsung.com, dri-devel@lists.freedesktop.org,
	Daniel Thompson <daniel.thompson@linaro.org>,
	linux-fbdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-msm@vger.kernel.org, linux-leds@vger.kernel.org,
	linux-arm-msm-owner@vger.kernel.org
Subject: Re: [PATCH V3 7/7] backlight: qcom-wled: Add auto string detection logic
Date: Wed, 20 Jun 2018 12:49:39 +0000	[thread overview]
Message-ID: <f93eafc1faadc1e0357d24cba7392fad@codeaurora.org> (raw)
In-Reply-To: <20180620062256.GK15126@tuxbook-pro>

On 2018-06-20 11:52, Bjorn Andersson wrote:
> On Tue 19 Jun 04:13 PDT 2018, Kiran Gunda wrote:
> 
>> The auto string detection algorithm checks if the current WLED
>> sink configuration is valid. It tries enabling every sink and
>> checks if the OVP fault is observed. Based on this information
>> it detects and enables the valid sink configuration.
>> Auto calibration will be triggered when the OVP fault interrupts
>> are seen frequently thereby it tries to fix the sink configuration.
>> 
>> The auto-detection also kicks in when the connected LED string
>> of the display-backlight malfunctions (because of damage) and
>> requires the damaged string to be turned off to prevent the
>> complete panel and/or board from being damaged.
>> 
>> Signed-off-by: Kiran Gunda <kgunda@codeaurora.org>
>> ---
>>  drivers/video/backlight/qcom-wled.c | 408 
>> +++++++++++++++++++++++++++++++++++-
>>  1 file changed, 403 insertions(+), 5 deletions(-)
>> 
>> diff --git a/drivers/video/backlight/qcom-wled.c 
>> b/drivers/video/backlight/qcom-wled.c
>> index e87ba70..6bc627c 100644
>> --- a/drivers/video/backlight/qcom-wled.c
>> +++ b/drivers/video/backlight/qcom-wled.c
>> @@ -25,13 +25,23 @@
>>  #define WLED_MAX_STRINGS				4
>> 
>>  #define WLED_DEFAULT_BRIGHTNESS				2048
>> -
>> +#define WLED_SOFT_START_DLY_US				10000
>>  #define WLED3_SINK_REG_BRIGHT_MAX			0xFFF
>> 
>>  /* WLED3 control registers */
>> +#define WLED3_CTRL_REG_FAULT_STATUS			0x08
>> +#define  WLED3_CTRL_REG_ILIM_FAULT_BIT			BIT(0)
>> +#define  WLED3_CTRL_REG_OVP_FAULT_BIT			BIT(1)
>> +#define  WLED4_CTRL_REG_SC_FAULT_BIT			BIT(2)
>> +
>> +#define WLED3_CTRL_REG_INT_RT_STS			0x10
>> +#define  WLED3_CTRL_REG_OVP_FAULT_STATUS		BIT(1)
>> +
> 
> These seems to be used in both WLED 3 and 4, so please drop the 3 from
> the name.
> 
Sure. I will change it in the next series.
>>  #define WLED3_CTRL_REG_MOD_EN				0x46
>>  #define  WLED3_CTRL_REG_MOD_EN_MASK			BIT(7)
>> 
>> +#define WLED3_CTRL_REG_FEEDBACK_CONTROL			0x48
>> +
>>  #define WLED3_CTRL_REG_FREQ				0x4c
>>  #define  WLED3_CTRL_REG_FREQ_MASK			GENMASK(3, 0)
>> 
>> @@ -146,6 +156,7 @@ struct wled_config {
>>  	bool ext_gen;
>>  	bool cabc;
>>  	bool external_pfet;
>> +	bool auto_detection_enabled;
>>  };
>> 
>>  struct wled {
>> @@ -154,16 +165,22 @@ struct wled {
>>  	struct regmap *regmap;
>>  	struct mutex lock;	/* Lock to avoid race from ISR */
>>  	ktime_t last_short_event;
>> +	ktime_t start_ovp_fault_time;
>>  	u16 ctrl_addr;
>>  	u16 sink_addr;
>> +	u16 auto_detection_ovp_count;
>>  	u32 brightness;
>>  	u32 max_brightness;
>>  	u32 short_count;
>> +	u32 auto_detect_count;
>>  	const int *version;
>>  	bool disabled_by_short;
>>  	bool has_short_detect;
>> +	int ovp_irq;
>> +	bool ovp_irq_disabled;
>> 
>>  	struct wled_config cfg;
>> +	struct delayed_work ovp_work;
>>  	int (*wled_set_brightness)(struct wled *wled, u16 brightness);
>>  	int (*wled_sync_toggle)(struct wled *wled);
>>  };
>> @@ -209,6 +226,27 @@ static int wled4_set_brightness(struct wled 
>> *wled, u16 brightness)
>>  	return 0;
>>  }
>> 
>> +static void wled_ovp_work(struct work_struct *work)
>> +{
>> +	u32 val;
>> +	int rc;
>> +
>> +	struct wled *wled = container_of(work,
>> +					 struct wled, ovp_work.work);
>> +
>> +	rc = regmap_read(wled->regmap, wled->ctrl_addr + 
>> WLED3_CTRL_REG_MOD_EN,
>> +			 &val);
>> +	if (rc < 0)
>> +		return;
>> +
>> +	if (val & WLED3_CTRL_REG_MOD_EN_MASK) {
> 
> The way you implement this now makes this a "delayed enable_irq" 
> worker,
> as such you shouldn't need to check if the hardware is enabled here but
> just blindly enable_irq() and then in module_enable() you can check the
> return value of cancel_delayed_work() to know if enable_irq() has been
> called.
> 
Ok. I will modify as per your suggestion in the next series.
>> +		if (wled->ovp_irq > 0 && wled->ovp_irq_disabled) {
>> +			enable_irq(wled->ovp_irq);
>> +			wled->ovp_irq_disabled = false;
>> +		}
>> +	}
>> +}
>> +
>>  static int wled_module_enable(struct wled *wled, int val)
>>  {
>>  	int rc;
>> @@ -220,7 +258,20 @@ static int wled_module_enable(struct wled *wled, 
>> int val)
>>  				WLED3_CTRL_REG_MOD_EN,
>>  				WLED3_CTRL_REG_MOD_EN_MASK,
>>  				WLED3_CTRL_REG_MOD_EN_MASK);
>> -	return rc;
>> +	if (rc < 0)
>> +		return rc;
>> +
>> +	if (val) {
>> +		schedule_delayed_work(&wled->ovp_work, WLED_SOFT_START_DLY_US);
>> +	} else {
>> +		cancel_delayed_work(&wled->ovp_work);
> 
> I recommend using cancel_delayed_work_sync() to ensure that htis isn't
> racing with the worker.
> 
Sure. I will modify it in next series.
>> +		if (wled->ovp_irq > 0 && !wled->ovp_irq_disabled) {
>> +			disable_irq(wled->ovp_irq);
>> +			wled->ovp_irq_disabled = true;
>> +		}
>> +	}
>> +
>> +	return 0;
>>  }
>> 
>>  static int wled3_sync_toggle(struct wled *wled)
>> @@ -346,6 +397,305 @@ static irqreturn_t wled_short_irq_handler(int 
>> irq, void *_wled)
>>  	return IRQ_HANDLED;
>>  }
>> 
>> +#define AUTO_DETECT_BRIGHTNESS		200
>> +static int wled_auto_string_detection(struct wled *wled)
> 
> You don't care about the return value of this function in any of the
> callers.
> 
I will make it void in the next series.
>> +{
>> +	int rc = 0, i;
>> +	u32 sink_config = 0, int_sts;
>> +	u8 sink_test = 0, sink_valid = 0, val;
>> +
>> +	/* read configured sink configuration */
>> +	rc = regmap_read(wled->regmap, wled->sink_addr +
>> +			 WLED4_SINK_REG_CURR_SINK, &sink_config);
>> +	if (rc < 0) {
>> +		pr_err("Failed to read SINK configuration rc=%d\n", rc);
>> +		goto failed_detect;
>> +	}
>> +
>> +	/* disable the module before starting detection */
>> +	rc = regmap_update_bits(wled->regmap,
>> +				wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN,
>> +				WLED3_CTRL_REG_MOD_EN_MASK, 0);
>> +	if (rc < 0) {
>> +		pr_err("Failed to disable WLED module rc=%d\n", rc);
>> +		goto failed_detect;
>> +	}
>> +
>> +	/* set low brightness across all sinks */
>> +	rc = wled4_set_brightness(wled, AUTO_DETECT_BRIGHTNESS);
>> +	if (rc < 0) {
>> +		pr_err("Failed to set brightness for auto detection rc=%d\n",
>> +		       rc);
>> +		goto failed_detect;
>> +	}
>> +
>> +	if (wled->cfg.cabc) {
>> +		for (i = 0; i < wled->cfg.num_strings; i++) {
>> +			rc = regmap_update_bits(wled->regmap, wled->sink_addr +
>> +						WLED4_SINK_REG_STR_CABC(i),
>> +						WLED4_SINK_REG_STR_CABC_MASK,
>> +						0);
>> +			if (rc < 0)
>> +				goto failed_detect;
>> +		}
>> +	}
>> +
>> +	/* disable all sinks */
>> +	rc = regmap_write(wled->regmap,
>> +			  wled->sink_addr + WLED4_SINK_REG_CURR_SINK, 0);
>> +	if (rc < 0) {
>> +		pr_err("Failed to disable all sinks rc=%d\n", rc);
>> +		goto failed_detect;
>> +	}
>> +
>> +	/* iterate through the strings one by one */
>> +	for (i = 0; i < wled->cfg.num_strings; i++) {
>> +		sink_test = BIT((WLED4_SINK_REG_CURR_SINK_SHFT + i));
>> +
>> +		/* Enable feedback control */
>> +		rc = regmap_write(wled->regmap, wled->ctrl_addr +
>> +				  WLED3_CTRL_REG_FEEDBACK_CONTROL, i + 1);
>> +		if (rc < 0) {
>> +			pr_err("Failed to enable feedback for SINK %d rc = %d\n",
>> +			       i + 1, rc);
>> +			goto failed_detect;
>> +		}
>> +
>> +		/* enable the sink */
>> +		rc = regmap_write(wled->regmap, wled->sink_addr +
>> +				  WLED4_SINK_REG_CURR_SINK, sink_test);
>> +		if (rc < 0) {
>> +			pr_err("Failed to configure SINK %d rc=%d\n", i + 1,
>> +			       rc);
>> +			goto failed_detect;
>> +		}
>> +
>> +		/* Enable the module */
>> +		rc = regmap_update_bits(wled->regmap, wled->ctrl_addr +
>> +					WLED3_CTRL_REG_MOD_EN,
>> +					WLED3_CTRL_REG_MOD_EN_MASK,
>> +					WLED3_CTRL_REG_MOD_EN_MASK);
>> +		if (rc < 0) {
>> +			pr_err("Failed to enable WLED module rc=%d\n", rc);
>> +			goto failed_detect;
>> +		}
>> +
>> +		usleep_range(WLED_SOFT_START_DLY_US,
>> +			     WLED_SOFT_START_DLY_US + 1000);
>> +
>> +		rc = regmap_read(wled->regmap, wled->ctrl_addr +
>> +				 WLED3_CTRL_REG_INT_RT_STS, &int_sts);
>> +		if (rc < 0) {
>> +			pr_err("Error in reading WLED3_CTRL_INT_RT_STS rc=%d\n",
>> +			       rc);
> 
> You should probably do something about the state of the hardware if it
> fail here.
> 
This is a spmi read and it is very unlikely to fail. If it fails it 
leads the complete
system to go in to bad state.
>> +			goto failed_detect;
>> +		}
>> +
>> +		if (int_sts & WLED3_CTRL_REG_OVP_FAULT_STATUS)
>> +			pr_debug("WLED OVP fault detected with SINK %d\n",
>> +				 i + 1);
>> +		else
>> +			sink_valid |= sink_test;
>> +
>> +		/* Disable the module */
>> +		rc = regmap_update_bits(wled->regmap,
>> +					wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN,
>> +					WLED3_CTRL_REG_MOD_EN_MASK, 0);
>> +		if (rc < 0) {
>> +			pr_err("Failed to disable WLED module rc=%d\n", rc);
>> +			goto failed_detect;
>> +		}
>> +	}
>> +
>> +	if (sink_valid = sink_config) {
>> +		pr_debug("WLED auto-detection complete, default sink-config=%x 
>> OK!\n",
>> +			 sink_config);
> 
> It's not the "default" sink config we're using, it's whatever was
> configured before this function was called.
> 
I will correct it in the next series.
>> +	} else {
>> +		pr_warn("Invalid WLED default sink config=%x changing it to=%x\n",
> 
> Use dev_warn(), and as it's not the "default sink config" that's 
> invalid
> write something like "New WLED string configuration found: %x". Perhaps
> you can print it using %*pbl ?
> 
I will modify it in the next series. I missed to modify here.
>> +			sink_config, sink_valid);
>> +		sink_config = sink_valid;
>> +	}
>> +
>> +	if (!sink_config) {
>> +		pr_err("No valid WLED sinks found\n");
> 
> dev_err() and move this above the other prints, there's no reason to
> first say that you found an "invalid WLED default" and then say that 
> you
> didn't findd a valid config.
> 
Sure. I will move it in the next series.
>> +		wled->disabled_by_short = true;
>> +		goto failed_detect;
>> +	}
>> +
>> +	/* write the new sink configuration */
>> +	rc = regmap_write(wled->regmap,
>> +			  wled->sink_addr + WLED4_SINK_REG_CURR_SINK,
>> +			  sink_config);
>> +	if (rc < 0) {
>> +		pr_err("Failed to reconfigure the default sink rc=%d\n", rc);
>> +		goto failed_detect;
>> +	}
>> +
>> +	/* Enable valid sinks */
>> +	for (i = 0; i < wled->cfg.num_strings; i++) {
>> +		if (wled->cfg.cabc) {
>> +			rc = regmap_update_bits(wled->regmap, wled->sink_addr +
>> +						WLED4_SINK_REG_STR_CABC(i),
>> +						WLED4_SINK_REG_STR_CABC_MASK,
>> +						WLED4_SINK_REG_STR_CABC_MASK);
>> +			if (rc < 0)
>> +				goto failed_detect;
>> +		}
>> +
>> +		if (sink_config & BIT(WLED4_SINK_REG_CURR_SINK_SHFT + i))
>> +			val = WLED4_SINK_REG_STR_MOD_MASK;
>> +		else
>> +			val = 0x0; /* disable modulator_en for unused sink */
>> +
>> +		rc = regmap_write(wled->regmap, wled->sink_addr +
>> +				  WLED4_SINK_REG_STR_MOD_EN(i), val);
>> +		if (rc < 0) {
>> +			pr_err("Failed to configure MODULATOR_EN rc=%d\n", rc);
>> +			goto failed_detect;
>> +		}
>> +	}
>> +
>> +	/* restore the feedback setting */
>> +	rc = regmap_write(wled->regmap,
>> +			  wled->ctrl_addr + WLED3_CTRL_REG_FEEDBACK_CONTROL, 0);
>> +	if (rc < 0) {
>> +		pr_err("Failed to restore feedback setting rc=%d\n", rc);
>> +		goto failed_detect;
>> +	}
>> +
>> +	/* restore  brightness */
> 
> Extra space
> 
Will remove it in the next series.
>> +	rc = wled4_set_brightness(wled, wled->brightness);
>> +	if (rc < 0) {
>> +		pr_err("Failed to set brightness after auto detection rc=%d\n",
>> +		       rc);
>> +		goto failed_detect;
>> +	}
>> +
>> +	rc = regmap_update_bits(wled->regmap,
>> +				wled->ctrl_addr + WLED3_CTRL_REG_MOD_EN,
>> +				WLED3_CTRL_REG_MOD_EN_MASK,
>> +				WLED3_CTRL_REG_MOD_EN_MASK);
>> +	if (rc < 0) {
>> +		pr_err("Failed to enable WLED module rc=%d\n", rc);
>> +		goto failed_detect;
>> +	}
>> +
>> +failed_detect:
>> +	return rc;
>> +}
>> +
>> +#define WLED_AUTO_DETECT_OVP_COUNT		5
>> +#define WLED_AUTO_DETECT_CNT_DLY_US		USEC_PER_SEC
>> +static bool wled_auto_detection_required(struct wled *wled)
>> +{
>> +	s64 elapsed_time_us;
>> +
>> +	if (*wled->version = WLED_PM8941 || 
>> !wled->cfg.auto_detection_enabled)
> 
> Ensure that auto_detection_enabled can't be enabled for pm8941, so that
> you don't need to check the first part.
> 
I will change it in the next series.
>> +		return false;
>> +
>> +	/*
>> +	 * Check if the OVP fault was an occasional one
>> +	 * or if it's firing continuously, the latter qualifies
>> +	 * for an auto-detection check.
>> +	 */
>> +	if (!wled->auto_detection_ovp_count) {
>> +		wled->start_ovp_fault_time = ktime_get();
>> +		wled->auto_detection_ovp_count++;
>> +	} else {
>> +		elapsed_time_us = ktime_us_delta(ktime_get(),
>> +						 wled->start_ovp_fault_time);
>> +		if (elapsed_time_us > WLED_AUTO_DETECT_CNT_DLY_US)
>> +			wled->auto_detection_ovp_count = 0;
>> +		else
>> +			wled->auto_detection_ovp_count++;
>> +
>> +		if (wled->auto_detection_ovp_count >>> +				WLED_AUTO_DETECT_OVP_COUNT) {
>> +			wled->auto_detection_ovp_count = 0;
>> +			return true;
>> +		}
>> +	}
>> +
>> +	return false;
>> +}
>> +
>> +static int wled_auto_detection_at_init(struct wled *wled)
>> +{
>> +	int rc;
>> +	u32 fault_status = 0, rt_status = 0;
> 
> No need to initialize these, they will be filled out if regmap_read
> return successfully.
> 
I will remove it in the next series.
>> +
>> +	if (!wled->cfg.auto_detection_enabled)
>> +		return 0;
>> +
> [..]
>> @@ -836,6 +1192,42 @@ static int wled_configure_short_irq(struct wled 
>> *wled,
>>  	return rc;
>>  }
>> 
>> +static int wled_configure_ovp_irq(struct wled *wled,
>> +				  struct platform_device *pdev)
>> +{
>> +	int rc = 0;
> 
> No need to initialize rc here.
> 
I will remove it in the next series.
>> +	u32 val;
>> +
>> +	wled->ovp_irq = platform_get_irq_byname(pdev, "ovp");
>> +	if (wled->ovp_irq < 0) {
>> +		dev_dbg(&pdev->dev, "ovp irq is not used\n");
>> +		return 0;
>> +	}
>> +
>> +	rc = devm_request_threaded_irq(wled->dev, wled->ovp_irq, NULL,
>> +				       wled_ovp_irq_handler, IRQF_ONESHOT,
>> +				       "wled_ovp_irq", wled);
>> +	if (rc < 0) {
>> +		dev_err(wled->dev, "Unable to request ovp_irq (err:%d)\n",
>> +			rc);
>> +		wled->ovp_irq = 0;
>> +		return 0;
>> +	}
>> +
>> +	rc = regmap_read(wled->regmap, wled->ctrl_addr +
>> +			 WLED3_CTRL_REG_MOD_EN, &val);
>> +	if (rc < 0)
>> +		return rc;
>> +
>> +	/* Keep OVP irq disabled until module is enabled */
>> +	if (!rc && !(val & WLED3_CTRL_REG_MOD_EN_MASK)) {
> 
> If rc isn't 0 we returned above.
> 
I will remove it in the next series.
>> +		disable_irq(wled->ovp_irq);
>> +		wled->ovp_irq_disabled = true;
>> +	}
>> +
>> +	return rc;
> 
> As such, it is always 0 here.
> 
I will modify it in the next series.
>> +}
>> +
> 
> Regards,
> Bjorn
> --
> To unsubscribe from this list: send the line "unsubscribe 
> linux-arm-msm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

  reply	other threads:[~2018-06-20 12:37 UTC|newest]

Thread overview: 59+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-06-19 11:13 [PATCH V3 0/7] backlight: qcom-wled: Support for QCOM wled driver Kiran Gunda
2018-06-19 11:13 ` [PATCH V3 1/7] backlight: qcom-wled: Rename pm8941-wled.c to qcom-wled.c Kiran Gunda
2018-06-19 11:25   ` Kiran Gunda
2018-06-19 22:54   ` Bjorn Andersson
2018-06-19 22:54     ` Bjorn Andersson
2018-06-20  5:23     ` kgunda
2018-06-20  5:35       ` kgunda
2018-06-20 18:27   ` Rob Herring
2018-06-20 18:27     ` Rob Herring
2018-06-20 18:27     ` Rob Herring
2018-06-21 13:05   ` Daniel Thompson
2018-06-21 13:05     ` Daniel Thompson
2018-06-21 13:05     ` Daniel Thompson
2018-06-21 13:12     ` Daniel Thompson
2018-06-21 13:12       ` Daniel Thompson
2018-06-21 13:12       ` Daniel Thompson
2018-06-19 11:13 ` [PATCH V3 2/7] backlight: qcom-wled: restructure the qcom-wled bindings Kiran Gunda
2018-06-19 22:56   ` Bjorn Andersson
2018-06-20 18:29   ` Rob Herring
2018-06-20 18:29     ` Rob Herring
2018-06-21 13:12   ` Daniel Thompson
2018-06-21 13:12     ` Daniel Thompson
2018-06-19 11:13 ` [PATCH V3 3/7] backlight: qcom-wled: Add new properties for PMI8998 Kiran Gunda
2018-06-19 23:03   ` Bjorn Andersson
2018-06-20  5:25     ` kgunda
2018-06-20 19:05   ` Rob Herring
2018-06-20 19:05     ` Rob Herring
2018-06-21  5:14     ` kgunda
2018-06-19 11:13 ` [PATCH V3 4/7] backlight: qcom-wled: Rename PM8941* to WLED3 Kiran Gunda
2018-06-19 11:25   ` Kiran Gunda
2018-06-19 23:11   ` Bjorn Andersson
2018-06-19 23:11     ` Bjorn Andersson
2018-06-20  6:26     ` kgunda
2018-06-20  6:38       ` kgunda
2018-06-19 11:13 ` [PATCH V3 5/7] backlight: qcom-wled: Add support for WLED4 peripheral Kiran Gunda
2018-06-19 11:25   ` Kiran Gunda
2018-06-20  5:14   ` Bjorn Andersson
2018-06-20  5:14     ` Bjorn Andersson
2018-06-20 11:00     ` kgunda
2018-06-20 11:12       ` kgunda
2018-06-22 23:09       ` Bjorn Andersson
2018-06-22 23:09         ` Bjorn Andersson
2018-06-25  5:54         ` kgunda
2018-06-25  6:06           ` kgunda
2018-06-19 11:13 ` [PATCH V3 6/7] backlight: qcom-wled: add support for short circuit handling Kiran Gunda
2018-06-19 11:25   ` Kiran Gunda
2018-06-20  5:33   ` Bjorn Andersson
2018-06-20  5:33     ` Bjorn Andersson
2018-06-20  5:47   ` Vinod
2018-06-20  5:59     ` Vinod
2018-06-20  5:47     ` Vinod
2018-06-20 11:03     ` kgunda
2018-06-20 11:15       ` kgunda
2018-06-19 11:13 ` [PATCH V3 7/7] backlight: qcom-wled: Add auto string detection logic Kiran Gunda
2018-06-19 11:25   ` Kiran Gunda
2018-06-20  6:22   ` Bjorn Andersson
2018-06-20  6:22     ` Bjorn Andersson
2018-06-20 12:37     ` kgunda [this message]
2018-06-20 12:49       ` kgunda

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=f93eafc1faadc1e0357d24cba7392fad@codeaurora.org \
    --to=kgunda@codeaurora.org \
    --cc=b.zolnierkie@samsung.com \
    --cc=bjorn.andersson@linaro.org \
    --cc=daniel.thompson@linaro.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=jingoohan1@gmail.com \
    --cc=lee.jones@linaro.org \
    --cc=linux-arm-msm-owner@vger.kernel.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-fbdev@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-leds@vger.kernel.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.