From: Kiran Gunda <kgunda@codeaurora.org> To: bjorn.andersson@linaro.org, jingoohan1@gmail.com, lee.jones@linaro.org, b.zolnierkie@samsung.com, dri-devel@lists.freedesktop.org, daniel.thompson@linaro.org, jacek.anaszewski@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, mark.rutland@arm.com, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Andy Gross <agross@kernel.org>, linux-arm-msm@vger.kernel.org, linux-fbdev@vger.kernel.org Cc: Kiran Gunda <kgunda@codeaurora.org> Subject: [PATCH V6 7/8] backlight: qcom-wled: add support for short circuit handling. Date: Mon, 30 Sep 2019 12:09:12 +0530 [thread overview] Message-ID: <1569825553-26039-8-git-send-email-kgunda@codeaurora.org> (raw) In-Reply-To: <1569825553-26039-1-git-send-email-kgunda@codeaurora.org> Handle the short circuit interrupt and check if the short circuit interrupt is valid. Re-enable the module to check if it goes away. Disable the module altogether if the short circuit event persists. Change-Id: Ia3f5272e1a50927467611bef4a0d2218dbeb95e6 Signed-off-by: Kiran Gunda <kgunda@codeaurora.org> Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org> --- drivers/video/backlight/qcom-wled.c | 132 ++++++++++++++++++++++++++++++++++-- 1 file changed, 128 insertions(+), 4 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index b012a2a..556c734 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -2,6 +2,9 @@ /* Copyright (c) 2015, Sony Mobile Communications, AB. */ +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/ktime.h> #include <linux/kernel.h> #include <linux/backlight.h> #include <linux/module.h> @@ -56,6 +59,16 @@ #define WLED3_SINK_REG_STR_CABC(n) (0x66 + (n * 0x10)) #define WLED3_SINK_REG_STR_CABC_MASK BIT(7) +/* WLED4 specific control registers */ +#define WLED4_CTRL_REG_SHORT_PROTECT 0x5e +#define WLED4_CTRL_REG_SHORT_EN_MASK BIT(7) + +#define WLED4_CTRL_REG_SEC_ACCESS 0xd0 +#define WLED4_CTRL_REG_SEC_UNLOCK 0xa5 + +#define WLED4_CTRL_REG_TEST1 0xe2 +#define WLED4_CTRL_REG_TEST1_EXT_FET_DTEST2 0x09 + /* WLED4 specific sink registers */ #define WLED4_SINK_REG_CURR_SINK 0x46 #define WLED4_SINK_REG_CURR_SINK_MASK GENMASK(7, 4) @@ -105,17 +118,23 @@ struct wled_config { bool cs_out_en; bool ext_gen; bool cabc; + bool external_pfet; }; struct wled { const char *name; struct device *dev; struct regmap *regmap; + struct mutex lock; /* Lock to avoid race from thread irq handler */ + ktime_t last_short_event; u16 ctrl_addr; u16 sink_addr; u16 max_string_count; u32 brightness; u32 max_brightness; + u32 short_count; + bool disabled_by_short; + bool has_short_detect; struct wled_config cfg; int (*wled_set_brightness)(struct wled *wled, u16 brightness); @@ -166,6 +185,9 @@ static int wled_module_enable(struct wled *wled, int val) { int rc; + if (wled->disabled_by_short) + return -ENXIO; + rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED_CTRL_REG_MOD_EN, WLED_CTRL_REG_MOD_EN_MASK, @@ -202,18 +224,19 @@ static int wled_update_status(struct backlight_device *bl) bl->props.state & BL_CORE_FBBLANK) brightness = 0; + mutex_lock(&wled->lock); if (brightness) { rc = wled->wled_set_brightness(wled, brightness); if (rc < 0) { dev_err(wled->dev, "wled failed to set brightness rc:%d\n", rc); - return rc; + goto unlock_mutex; } rc = wled_sync_toggle(wled); if (rc < 0) { dev_err(wled->dev, "wled sync failed rc:%d\n", rc); - return rc; + goto unlock_mutex; } } @@ -221,15 +244,61 @@ static int wled_update_status(struct backlight_device *bl) rc = wled_module_enable(wled, !!brightness); if (rc < 0) { dev_err(wled->dev, "wled enable failed rc:%d\n", rc); - return rc; + goto unlock_mutex; } } wled->brightness = brightness; +unlock_mutex: + mutex_unlock(&wled->lock); + return rc; } +#define WLED_SHORT_DLY_MS 20 +#define WLED_SHORT_CNT_MAX 5 +#define WLED_SHORT_RESET_CNT_DLY_US USEC_PER_SEC + +static irqreturn_t wled_short_irq_handler(int irq, void *_wled) +{ + struct wled *wled = _wled; + int rc; + s64 elapsed_time; + + wled->short_count++; + mutex_lock(&wled->lock); + rc = wled_module_enable(wled, false); + if (rc < 0) { + dev_err(wled->dev, "wled disable failed rc:%d\n", rc); + goto unlock_mutex; + } + + elapsed_time = ktime_us_delta(ktime_get(), + wled->last_short_event); + if (elapsed_time > WLED_SHORT_RESET_CNT_DLY_US) + wled->short_count = 1; + + if (wled->short_count > WLED_SHORT_CNT_MAX) { + dev_err(wled->dev, "Short trigged %d times, disabling WLED forever!\n", + wled->short_count); + wled->disabled_by_short = true; + goto unlock_mutex; + } + + wled->last_short_event = ktime_get(); + + msleep(WLED_SHORT_DLY_MS); + rc = wled_module_enable(wled, true); + if (rc < 0) + dev_err(wled->dev, "wled enable failed rc:%d\n", rc); + +unlock_mutex: + mutex_unlock(&wled->lock); + + return IRQ_HANDLED; +} + static int wled3_setup(struct wled *wled) { u16 addr; @@ -318,7 +387,7 @@ static int wled4_setup(struct wled *wled) int rc, temp, i, j; u16 addr; u8 sink_en = 0; - u32 sink_cfg = 0; + u32 sink_cfg; rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED_CTRL_REG_OVP, @@ -340,6 +409,21 @@ static int wled4_setup(struct wled *wled) if (rc < 0) return rc; + if (wled->cfg.external_pfet) { + /* Unlock the secure register access */ + rc = regmap_write(wled->regmap, wled->ctrl_addr + + WLED4_CTRL_REG_SEC_ACCESS, + WLED4_CTRL_REG_SEC_UNLOCK); + if (rc < 0) + return rc; + + rc = regmap_write(wled->regmap, + wled->ctrl_addr + WLED4_CTRL_REG_TEST1, + WLED4_CTRL_REG_TEST1_EXT_FET_DTEST2); + if (rc < 0) + return rc; + } + rc = regmap_read(wled->regmap, wled->sink_addr + WLED4_SINK_REG_CURR_SINK, &sink_cfg); if (rc < 0) @@ -425,6 +509,7 @@ static int wled4_setup(struct wled *wled) .num_strings = 4, .switch_freq = 11, .cabc = false, + .external_pfet = false, }; static const u32 wled3_boost_i_limit_values[] = { @@ -590,6 +675,7 @@ static int wled_configure(struct wled *wled, int version) { "qcom,cs-out", &cfg->cs_out_en, }, { "qcom,ext-gen", &cfg->ext_gen, }, { "qcom,cabc", &cfg->cabc, }, + { "qcom,external-pfet", &cfg->external_pfet, }, }; prop_addr = of_get_address(dev->of_node, 0, NULL, NULL); @@ -678,6 +764,38 @@ static int wled_configure(struct wled *wled, int version) return 0; } +static int wled_configure_short_irq(struct wled *wled, + struct platform_device *pdev) +{ + int rc, short_irq; + + if (!wled->has_short_detect) + return 0; + + rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + + WLED4_CTRL_REG_SHORT_PROTECT, + WLED4_CTRL_REG_SHORT_EN_MASK, + WLED4_CTRL_REG_SHORT_EN_MASK); + if (rc < 0) + return rc; + + short_irq = platform_get_irq_byname(pdev, "short"); + if (short_irq < 0) { + dev_dbg(&pdev->dev, "short irq is not used\n"); + return 0; + } + + rc = devm_request_threaded_irq(wled->dev, short_irq, + NULL, wled_short_irq_handler, + IRQF_ONESHOT, + "wled_short_irq", wled); + if (rc < 0) + dev_err(wled->dev, "Unable to request short_irq (err:%d)\n", + rc); + + return rc; +} + static const struct backlight_ops wled_ops = { .update_status = wled_update_status, }; @@ -711,6 +829,7 @@ static int wled_probe(struct platform_device *pdev) return -ENODEV; } + mutex_init(&wled->lock); rc = wled_configure(wled, version); if (rc) return rc; @@ -725,6 +844,7 @@ static int wled_probe(struct platform_device *pdev) break; case 4: + wled->has_short_detect = true; rc = wled4_setup(wled); if (rc) { dev_err(&pdev->dev, "wled4_setup failed\n"); @@ -737,6 +857,10 @@ static int wled_probe(struct platform_device *pdev) break; } + rc = wled_configure_short_irq(wled, pdev); + if (rc < 0) + return rc; + val = WLED_DEFAULT_BRIGHTNESS; of_property_read_u32(pdev->dev.of_node, "default-brightness", &val); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
WARNING: multiple messages have this Message-ID (diff)
From: Kiran Gunda <kgunda@codeaurora.org> To: bjorn.andersson@linaro.org, jingoohan1@gmail.com, lee.jones@linaro.org, b.zolnierkie@samsung.com, dri-devel@lists.freedesktop.org, daniel.thompson@linaro.org, jacek.anaszewski@gmail.com, pavel@ucw.cz, robh+dt@kernel.org, mark.rutland@arm.com, linux-leds@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Andy Gross <agross@kernel.org>, linux-arm-msm@vger.kernel.org, linux-fbdev@vger.kernel.org Cc: Kiran Gunda <kgunda@codeaurora.org> Subject: [PATCH V6 7/8] backlight: qcom-wled: add support for short circuit handling. Date: Mon, 30 Sep 2019 06:51:12 +0000 [thread overview] Message-ID: <1569825553-26039-8-git-send-email-kgunda@codeaurora.org> (raw) In-Reply-To: <1569825553-26039-1-git-send-email-kgunda@codeaurora.org> Handle the short circuit interrupt and check if the short circuit interrupt is valid. Re-enable the module to check if it goes away. Disable the module altogether if the short circuit event persists. Change-Id: Ia3f5272e1a50927467611bef4a0d2218dbeb95e6 Signed-off-by: Kiran Gunda <kgunda@codeaurora.org> Reviewed-by: Bjorn Andersson <bjorn.andersson@linaro.org> --- drivers/video/backlight/qcom-wled.c | 132 ++++++++++++++++++++++++++++++++++-- 1 file changed, 128 insertions(+), 4 deletions(-) diff --git a/drivers/video/backlight/qcom-wled.c b/drivers/video/backlight/qcom-wled.c index b012a2a..556c734 100644 --- a/drivers/video/backlight/qcom-wled.c +++ b/drivers/video/backlight/qcom-wled.c @@ -2,6 +2,9 @@ /* Copyright (c) 2015, Sony Mobile Communications, AB. */ +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/ktime.h> #include <linux/kernel.h> #include <linux/backlight.h> #include <linux/module.h> @@ -56,6 +59,16 @@ #define WLED3_SINK_REG_STR_CABC(n) (0x66 + (n * 0x10)) #define WLED3_SINK_REG_STR_CABC_MASK BIT(7) +/* WLED4 specific control registers */ +#define WLED4_CTRL_REG_SHORT_PROTECT 0x5e +#define WLED4_CTRL_REG_SHORT_EN_MASK BIT(7) + +#define WLED4_CTRL_REG_SEC_ACCESS 0xd0 +#define WLED4_CTRL_REG_SEC_UNLOCK 0xa5 + +#define WLED4_CTRL_REG_TEST1 0xe2 +#define WLED4_CTRL_REG_TEST1_EXT_FET_DTEST2 0x09 + /* WLED4 specific sink registers */ #define WLED4_SINK_REG_CURR_SINK 0x46 #define WLED4_SINK_REG_CURR_SINK_MASK GENMASK(7, 4) @@ -105,17 +118,23 @@ struct wled_config { bool cs_out_en; bool ext_gen; bool cabc; + bool external_pfet; }; struct wled { const char *name; struct device *dev; struct regmap *regmap; + struct mutex lock; /* Lock to avoid race from thread irq handler */ + ktime_t last_short_event; u16 ctrl_addr; u16 sink_addr; u16 max_string_count; u32 brightness; u32 max_brightness; + u32 short_count; + bool disabled_by_short; + bool has_short_detect; struct wled_config cfg; int (*wled_set_brightness)(struct wled *wled, u16 brightness); @@ -166,6 +185,9 @@ static int wled_module_enable(struct wled *wled, int val) { int rc; + if (wled->disabled_by_short) + return -ENXIO; + rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED_CTRL_REG_MOD_EN, WLED_CTRL_REG_MOD_EN_MASK, @@ -202,18 +224,19 @@ static int wled_update_status(struct backlight_device *bl) bl->props.state & BL_CORE_FBBLANK) brightness = 0; + mutex_lock(&wled->lock); if (brightness) { rc = wled->wled_set_brightness(wled, brightness); if (rc < 0) { dev_err(wled->dev, "wled failed to set brightness rc:%d\n", rc); - return rc; + goto unlock_mutex; } rc = wled_sync_toggle(wled); if (rc < 0) { dev_err(wled->dev, "wled sync failed rc:%d\n", rc); - return rc; + goto unlock_mutex; } } @@ -221,15 +244,61 @@ static int wled_update_status(struct backlight_device *bl) rc = wled_module_enable(wled, !!brightness); if (rc < 0) { dev_err(wled->dev, "wled enable failed rc:%d\n", rc); - return rc; + goto unlock_mutex; } } wled->brightness = brightness; +unlock_mutex: + mutex_unlock(&wled->lock); + return rc; } +#define WLED_SHORT_DLY_MS 20 +#define WLED_SHORT_CNT_MAX 5 +#define WLED_SHORT_RESET_CNT_DLY_US USEC_PER_SEC + +static irqreturn_t wled_short_irq_handler(int irq, void *_wled) +{ + struct wled *wled = _wled; + int rc; + s64 elapsed_time; + + wled->short_count++; + mutex_lock(&wled->lock); + rc = wled_module_enable(wled, false); + if (rc < 0) { + dev_err(wled->dev, "wled disable failed rc:%d\n", rc); + goto unlock_mutex; + } + + elapsed_time = ktime_us_delta(ktime_get(), + wled->last_short_event); + if (elapsed_time > WLED_SHORT_RESET_CNT_DLY_US) + wled->short_count = 1; + + if (wled->short_count > WLED_SHORT_CNT_MAX) { + dev_err(wled->dev, "Short trigged %d times, disabling WLED forever!\n", + wled->short_count); + wled->disabled_by_short = true; + goto unlock_mutex; + } + + wled->last_short_event = ktime_get(); + + msleep(WLED_SHORT_DLY_MS); + rc = wled_module_enable(wled, true); + if (rc < 0) + dev_err(wled->dev, "wled enable failed rc:%d\n", rc); + +unlock_mutex: + mutex_unlock(&wled->lock); + + return IRQ_HANDLED; +} + static int wled3_setup(struct wled *wled) { u16 addr; @@ -318,7 +387,7 @@ static int wled4_setup(struct wled *wled) int rc, temp, i, j; u16 addr; u8 sink_en = 0; - u32 sink_cfg = 0; + u32 sink_cfg; rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + WLED_CTRL_REG_OVP, @@ -340,6 +409,21 @@ static int wled4_setup(struct wled *wled) if (rc < 0) return rc; + if (wled->cfg.external_pfet) { + /* Unlock the secure register access */ + rc = regmap_write(wled->regmap, wled->ctrl_addr + + WLED4_CTRL_REG_SEC_ACCESS, + WLED4_CTRL_REG_SEC_UNLOCK); + if (rc < 0) + return rc; + + rc = regmap_write(wled->regmap, + wled->ctrl_addr + WLED4_CTRL_REG_TEST1, + WLED4_CTRL_REG_TEST1_EXT_FET_DTEST2); + if (rc < 0) + return rc; + } + rc = regmap_read(wled->regmap, wled->sink_addr + WLED4_SINK_REG_CURR_SINK, &sink_cfg); if (rc < 0) @@ -425,6 +509,7 @@ static int wled4_setup(struct wled *wled) .num_strings = 4, .switch_freq = 11, .cabc = false, + .external_pfet = false, }; static const u32 wled3_boost_i_limit_values[] = { @@ -590,6 +675,7 @@ static int wled_configure(struct wled *wled, int version) { "qcom,cs-out", &cfg->cs_out_en, }, { "qcom,ext-gen", &cfg->ext_gen, }, { "qcom,cabc", &cfg->cabc, }, + { "qcom,external-pfet", &cfg->external_pfet, }, }; prop_addr = of_get_address(dev->of_node, 0, NULL, NULL); @@ -678,6 +764,38 @@ static int wled_configure(struct wled *wled, int version) return 0; } +static int wled_configure_short_irq(struct wled *wled, + struct platform_device *pdev) +{ + int rc, short_irq; + + if (!wled->has_short_detect) + return 0; + + rc = regmap_update_bits(wled->regmap, wled->ctrl_addr + + WLED4_CTRL_REG_SHORT_PROTECT, + WLED4_CTRL_REG_SHORT_EN_MASK, + WLED4_CTRL_REG_SHORT_EN_MASK); + if (rc < 0) + return rc; + + short_irq = platform_get_irq_byname(pdev, "short"); + if (short_irq < 0) { + dev_dbg(&pdev->dev, "short irq is not used\n"); + return 0; + } + + rc = devm_request_threaded_irq(wled->dev, short_irq, + NULL, wled_short_irq_handler, + IRQF_ONESHOT, + "wled_short_irq", wled); + if (rc < 0) + dev_err(wled->dev, "Unable to request short_irq (err:%d)\n", + rc); + + return rc; +} + static const struct backlight_ops wled_ops = { .update_status = wled_update_status, }; @@ -711,6 +829,7 @@ static int wled_probe(struct platform_device *pdev) return -ENODEV; } + mutex_init(&wled->lock); rc = wled_configure(wled, version); if (rc) return rc; @@ -725,6 +844,7 @@ static int wled_probe(struct platform_device *pdev) break; case 4: + wled->has_short_detect = true; rc = wled4_setup(wled); if (rc) { dev_err(&pdev->dev, "wled4_setup failed\n"); @@ -737,6 +857,10 @@ static int wled_probe(struct platform_device *pdev) break; } + rc = wled_configure_short_irq(wled, pdev); + if (rc < 0) + return rc; + val = WLED_DEFAULT_BRIGHTNESS; of_property_read_u32(pdev->dev.of_node, "default-brightness", &val); -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
next prev parent reply other threads:[~2019-09-30 6:41 UTC|newest] Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top 2019-09-30 6:39 [PATCH V6 0/8] backlight: qcom-wled: Support for QCOM wled driver Kiran Gunda 2019-09-30 6:39 ` [PATCH V6 1/8] backlight: qcom-wled: Rename pm8941-wled.c to qcom-wled.c Kiran Gunda 2019-09-30 6:51 ` Kiran Gunda 2019-10-01 15:03 ` Dan Murphy 2019-10-01 15:03 ` Dan Murphy 2019-10-01 15:03 ` Dan Murphy 2019-09-30 6:39 ` [PATCH V6 2/8] backlight: qcom-wled: restructure the qcom-wled bindings Kiran Gunda 2019-10-01 15:04 ` Dan Murphy 2019-10-01 15:04 ` Dan Murphy 2019-10-13 12:10 ` Pavel Machek 2019-10-13 12:10 ` Pavel Machek 2019-10-14 6:35 ` Lee Jones 2019-11-04 9:09 ` Pavel Machek 2019-11-04 9:09 ` Pavel Machek 2019-09-30 6:39 ` [PATCH V6 3/8] backlight: qcom-wled: Add new properties for PMI8998 Kiran Gunda 2019-10-01 15:12 ` Dan Murphy 2019-10-01 15:12 ` Dan Murphy 2019-10-15 8:54 ` kgunda 2019-09-30 6:39 ` [PATCH V6 4/8] backlight: qcom-wled: Rename PM8941* to WLED3 Kiran Gunda 2019-09-30 6:51 ` Kiran Gunda 2019-09-30 6:39 ` [PATCH V6 5/8] backlight: qcom-wled: Restructure the driver for WLED3 Kiran Gunda 2019-09-30 6:51 ` Kiran Gunda 2019-10-01 15:17 ` Dan Murphy 2019-10-01 15:17 ` Dan Murphy 2019-10-01 15:17 ` Dan Murphy 2019-10-04 11:40 ` kgunda 2019-10-04 11:52 ` kgunda 2019-09-30 6:39 ` [PATCH V6 6/8] backlight: qcom-wled: Add support for WLED4 peripheral Kiran Gunda 2019-09-30 6:51 ` Kiran Gunda 2019-09-30 6:39 ` Kiran Gunda [this message] 2019-09-30 6:51 ` [PATCH V6 7/8] backlight: qcom-wled: add support for short circuit handling Kiran Gunda 2019-09-30 6:39 ` [PATCH V6 8/8] backlight: qcom-wled: Add auto string detection logic Kiran Gunda 2019-09-30 6:51 ` Kiran Gunda
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=1569825553-26039-8-git-send-email-kgunda@codeaurora.org \ --to=kgunda@codeaurora.org \ --cc=agross@kernel.org \ --cc=b.zolnierkie@samsung.com \ --cc=bjorn.andersson@linaro.org \ --cc=daniel.thompson@linaro.org \ --cc=devicetree@vger.kernel.org \ --cc=dri-devel@lists.freedesktop.org \ --cc=jacek.anaszewski@gmail.com \ --cc=jingoohan1@gmail.com \ --cc=lee.jones@linaro.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 \ --cc=mark.rutland@arm.com \ --cc=pavel@ucw.cz \ --cc=robh+dt@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: linkBe 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.