Re: [PATCH v3 1/2] leds: mt6360: Add LED driver for MT6360
From: Gene Chen <hidden>
Date: 2020-09-10 08:11:35
Also in:
linux-arm-kernel, linux-leds, linux-mediatek, lkml
Andy Shevchenko [off-list ref] 於 2020年9月9日 週三 下午9:48寫道:
On Mon, Sep 7, 2020 at 1:31 PM Gene Chen [off-list ref] wrote:quoted
From: Gene Chen <redacted> Add MT6360 LED driver include 2-channel Flash LED with torch/strobe mode, and 4-channel RGB LED support Register/Flash/Breath ModeI'm wondering why you don't use struct led_classdev_flash. ...
Both Flash and RGB LED use led_classdev_flash by "devm_led_classdev_flash_register_ext".
quoted
+// +// Copyright (C) 2020 MediaTek Inc. +//Do you really need these two // lines?
ACK, I will remove it
...quoted
+enum { + MT6360_LED_ISNK1 = 0, + MT6360_LED_ISNK2, + MT6360_LED_ISNK3, + MT6360_LED_ISNK4, + MT6360_LED_FLASH1, + MT6360_LED_FLASH2,quoted
+ MT6360_MAX_LEDS,No comma for terminator entry.
ACK
quoted
+};...quoted
+#define MT6360_ISNK_MASK 0x1FGENMASK() ...quoted
+#define MT6360_ITORCH_MIN 25000 +#define MT6360_ITORCH_STEP 12500 +#define MT6360_ITORCH_MAX 400000 +#define MT6360_ISTRB_MIN 50000 +#define MT6360_ISTRB_STEP 12500 +#define MT6360_ISTRB_MAX 1500000 +#define MT6360_STRBTO_MIN 64000 +#define MT6360_STRBTO_STEP 32000 +#define MT6360_STRBTO_MAX 2432000Add unit suffixes, please.
ACK
...quoted
+#define FLED_TORCH_FLAG_MASK 0x0cquoted
+#define FLED_STROBE_FLAG_MASK 0x03GENMASK()
ACK
...quoted
+ dev_dbg(lcdev->dev, "[%d] brightness %d\n", led->led_no, level);Not production noise.
ACK
...quoted
+ ret = regmap_update_bits(priv->regmap, MT6360_REG_RGBEN, enable_mask, val); + if (ret) + return ret; + + return 0;return regmap...quoted
+ u32 val = (level) ? MT6360_FLCSEN_MASK(led->led_no) : 0;Why parens?
ACK
...quoted
+ dev_dbg(lcdev->dev, "[%d] brightness %d\n", led->led_no, level);Noise.
ACK
...quoted
+ if (priv->fled_strobe_used) { + dev_warn(lcdev->dev, "Please disable strobe first [%d]\n", priv->fled_strobe_used); + return -EINVAL;Hmm... Shouldn't be guaranteed by some framework?
Because both Flash LED use single logically control. It doesn't exist one LED is torch mode, and the other is strobe mode.
...quoted
+ curr = prev & (~BIT(led->led_no));Too many parens.
ACK
...quoted
+static int mt6360_strobe_brightness_set(struct led_classdev_flash *fl_cdev, u32 brightness) +{ + struct mt6360_led *led = container_of(fl_cdev, struct mt6360_led, flash); + struct led_classdev *lcdev = &fl_cdev->led_cdev; +quoted
+ dev_dbg(lcdev->dev, "[%d] strobe brightness %d\n", led->led_no, brightness);Noise. Point of this entire function?
ACK, I will remove it, reserve function entry only for register ledcass_dev check ops exist
quoted
+ return 0; +}...quoted
+ dev_dbg(lcdev->dev, "[%d] strobe state %d\n", led->led_no, state);Noise. If you wish to do it right, add trace events to the framework.
ACK, I will remove it.
...quoted
+ if (priv->fled_torch_used) {quoted
+ dev_warn(lcdev->dev, "Please disable torch first [0x%x]\n", priv->fled_torch_used);Again, why the warning? Can this be a part of the framework?
Same as above.
quoted
+ return -EINVAL; + }...quoted
+ curr = prev & (~BIT(led->led_no));Too many parens.
ACK
...quoted
+ if (!prev && curr) + usleep_range(5000, 6000); + else if (prev && !curr) + udelay(500);These delays must be explained.
ACK
...quoted
+ if (led->led_no == MT6360_LED_FLASH1) { + strobe_timeout_mask = MT6360_FLED1STRBTO_MASK; + fled_short_mask = MT6360_FLED1SHORT_MASK;quoted
+Redundant blank line.
ACK
quoted
+ } else { + strobe_timeout_mask = MT6360_FLED2STRBTO_MASK; + fled_short_mask = MT6360_FLED2SHORT_MASK; + }...quoted
+static int mt6360_flash_external_strobe_set(struct v4l2_flash *v4l2_flash, bool enable) +{ + struct led_classdev_flash *flash = v4l2_flash->fled_cdev; + struct mt6360_led *led = container_of(flash, struct mt6360_led, flash); + struct mt6360_priv *priv = led->priv;quoted
+ u32 enable_mask = MT6360_FLCSEN_MASK(led->led_no);enable_mask -> mask u32 value = enable ? mask : 0;quoted
+ int ret; + + ret = regmap_update_bits(priv->regmap, MT6360_REG_FLEDEN, enable_mask,quoted
+ enable ? enable_mask : 0);ret = ... mask, value);
ACK
quoted
+ if (ret) + return ret; + + if (enable) + priv->fled_strobe_used |= BIT(led->led_no); + else + priv->fled_strobe_used &= (~BIT(led->led_no));Too many parens.
ACK
quoted
+ + return 0; +}...quoted
+ s->val = s->max = (s->min) + (lcdev->max_brightness - 1) * s->step;Ditto.
ACK
...quoted
+static void clamp_align(u32 *v, u32 min, u32 max, u32 step)Can we keep a similar API, i.e. return a new value rather than update old?quoted
+{quoted
+ *v = clamp_val(*v, min, max);I would rather use a temporary variable (and it actually will be required with above).quoted
+ if (step > 1) + *v = (*v - min) / step * step + min;Sounds like open coded rounddown().
ACK
quoted
+}...quoted
+ lcdev->max_brightness = (val - MT6360_ITORCH_MIN) / MT6360_ITORCH_STEP + 1;DIV_ROUND_UP(val - MT6360_ITORCH_MIN, MT6360_ITORCH_STEP) ?
This is mapping 0~val to 1~max_brightness as level. I convert val below MT6360_ITORCH_STEP to 1 for ignore max_brightness = 0, because 0 means disable. There is a little difference from DIV_ROUND_UP.
...quoted
+static int mt6360_init_common_properties(struct mt6360_led *led, struct led_init_data *init_data) +{ + const char *str; + + if (!fwnode_property_read_string(init_data->fwnode, "default-state", &str)) { + if (!strcmp(str, "on")) + led->default_state = STATE_ON; + else if (!strcmp(str, "keep")) + led->default_state = STATE_KEEP;quoted
+ elseI wouldn't allow some garbage to be off.
ACK
quoted
+ led->default_state = STATE_OFF; + }What about static const char * const states = { "on", "keep", "off" }; int ret; ret = match_string(states, ARRAY_SIZE(states), str); if (ret) ... default_state = ret; ?quoted
+ return 0; +}
ACK
...quoted
+static int mt6360_led_probe(struct platform_device *pdev) +{ + struct mt6360_priv *priv; + struct fwnode_handle *child; + int i, ret; +quoted
+ priv->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!priv->regmap) { + dev_err(&pdev->dev, "Failed to get parent regmap\n"); + return -ENODEV; + }...quoted
+out:out_flash_leds_release: ?
ACK
quoted
+ for (i = MT6360_LED_FLASH1; i <= MT6360_LED_FLASH2; i++) { + struct mt6360_led *led = priv->leds[i]; + + if (led && led->v4l2_flash) + v4l2_flash_release(led->v4l2_flash); + + }...quoted
+static int mt6360_led_remove(struct platform_device *pdev) +{ + struct mt6360_priv *priv = platform_get_drvdata(pdev); + int i; + + for (i = MT6360_LED_FLASH1; i <= MT6360_LED_FLASH2; i++) { + struct mt6360_led *led = priv->leds[i]; + + if (led && led->v4l2_flash) + v4l2_flash_release(led->v4l2_flash); + + }Looks like a code duplication.
ACK
quoted
+ + return 0; +} + +static const struct of_device_id __maybe_unused mt6360_led_of_id[] = { + { .compatible = "mediatek,mt6360-led", },quoted
+ {},No need comma.
ACK
quoted
+};-- With Best Regards, Andy Shevchenko