linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/4] leds: flash: mt6360: Apply the fixes and hardware features
@ 2022-04-28  9:32 cy_huang
  2022-04-28  9:32 ` [PATCH 1/4] leds: flash: mt6360: Fix the wrong enable_reg in multicolor brightness set cy_huang
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: cy_huang @ 2022-04-28  9:32 UTC (permalink / raw)
  To: pavel, matthias.bgg
  Cc: cy_huang, jacek.anaszewski, gene_chen, linux-leds,
	linux-arm-kernel, linux-mediatek, linux-kernel

From: ChiYuan Huang <cy_huang@richtek.com>

This patch series includes some fixes and add supproted ISNK hardware features.
From MT6360, ISNK can support three modes (CC, PWM, and Breath). The previous
one can only support CC mode.

ChiYuan Huang (4):
  leds: flash: mt6360: Fix the wrong enable_reg in multicolor brightness
    set
  leds: flash: mt6360: Remove unused dependency in Kconfig
  leds: flash: mt6360: Add mt6360 isnk channel hardware timer dimming
    mode support
  leds: flash: mt6360: Add mt6360 isnk channel hardwre breath mode
    support

 drivers/leds/flash/Kconfig       |   4 +-
 drivers/leds/flash/leds-mt6360.c | 413 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 410 insertions(+), 7 deletions(-)

-- 
2.7.4


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/4] leds: flash: mt6360: Fix the wrong enable_reg in multicolor brightness set
  2022-04-28  9:32 [PATCH 0/4] leds: flash: mt6360: Apply the fixes and hardware features cy_huang
@ 2022-04-28  9:32 ` cy_huang
  2022-04-28  9:32 ` [PATCH 2/4] leds: flash: mt6360: Remove unused dependency in Kconfig cy_huang
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: cy_huang @ 2022-04-28  9:32 UTC (permalink / raw)
  To: pavel, matthias.bgg
  Cc: cy_huang, jacek.anaszewski, gene_chen, linux-leds,
	linux-arm-kernel, linux-mediatek, linux-kernel

From: ChiYuan Huang <cy_huang@richtek.com>

Fix the wrong enable_reg in multicolor brightness set.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
---
 drivers/leds/flash/leds-mt6360.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/leds/flash/leds-mt6360.c b/drivers/leds/flash/leds-mt6360.c
index e1066a5..712cd46 100644
--- a/drivers/leds/flash/leds-mt6360.c
+++ b/drivers/leds/flash/leds-mt6360.c
@@ -115,7 +115,8 @@ static int mt6360_mc_brightness_set(struct led_classdev *lcdev,
 		struct mc_subled *subled = mccdev->subled_info + i;
 
 		real_bright = min(lcdev->max_brightness, subled->brightness);
-		ret = regmap_update_bits(priv->regmap, MT6360_REG_ISNK(i),
+		ret = regmap_update_bits(priv->regmap,
+					 MT6360_REG_ISNK(subled->channel),
 					 MT6360_ISNK_MASK, real_bright);
 		if (ret)
 			goto out;
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/4] leds: flash: mt6360: Remove unused dependency in Kconfig
  2022-04-28  9:32 [PATCH 0/4] leds: flash: mt6360: Apply the fixes and hardware features cy_huang
  2022-04-28  9:32 ` [PATCH 1/4] leds: flash: mt6360: Fix the wrong enable_reg in multicolor brightness set cy_huang
@ 2022-04-28  9:32 ` cy_huang
  2022-04-28  9:32 ` [PATCH 3/4] leds: flash: mt6360: Add mt6360 isnk channel hardware timer dimming mode support cy_huang
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: cy_huang @ 2022-04-28  9:32 UTC (permalink / raw)
  To: pavel, matthias.bgg
  Cc: cy_huang, jacek.anaszewski, gene_chen, linux-leds,
	linux-arm-kernel, linux-mediatek, linux-kernel

From: ChiYuan Huang <cy_huang@richtek.com>

Kconfig already guarantee LED_CLASS_FLASH will be selected.
Remove useless dependency for LEDS_CLASS/LEDS_CLASS_FLASH.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
---
 drivers/leds/flash/Kconfig | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig
index d3eb689..38b325c 100644
--- a/drivers/leds/flash/Kconfig
+++ b/drivers/leds/flash/Kconfig
@@ -50,8 +50,7 @@ config LEDS_MAX77693
 
 config LEDS_MT6360
 	tristate "LED Support for Mediatek MT6360 PMIC"
-	depends on LEDS_CLASS && OF
-	depends on LEDS_CLASS_FLASH || !LEDS_CLASS_FLASH
+	depends on OF
 	depends on LEDS_CLASS_MULTICOLOR || !LEDS_CLASS_MULTICOLOR
 	depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
 	depends on MFD_MT6360
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/4] leds: flash: mt6360: Add mt6360 isnk channel hardware timer dimming mode support
  2022-04-28  9:32 [PATCH 0/4] leds: flash: mt6360: Apply the fixes and hardware features cy_huang
  2022-04-28  9:32 ` [PATCH 1/4] leds: flash: mt6360: Fix the wrong enable_reg in multicolor brightness set cy_huang
  2022-04-28  9:32 ` [PATCH 2/4] leds: flash: mt6360: Remove unused dependency in Kconfig cy_huang
@ 2022-04-28  9:32 ` cy_huang
  2022-04-28  9:32 ` [PATCH 4/4] leds: flash: mt6360: Add mt6360 isnk channel hardwre breath " cy_huang
  2022-06-14  7:36 ` [PATCH 0/4] leds: flash: mt6360: Apply the fixes and hardware features ChiYuan Huang
  4 siblings, 0 replies; 8+ messages in thread
From: cy_huang @ 2022-04-28  9:32 UTC (permalink / raw)
  To: pavel, matthias.bgg
  Cc: cy_huang, jacek.anaszewski, gene_chen, linux-leds,
	linux-arm-kernel, linux-mediatek, linux-kernel

From: ChiYuan Huang <cy_huang@richtek.com>

Add mt6360 isnk channel hardware timer dimming mode support.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
---
 drivers/leds/flash/leds-mt6360.c | 209 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 203 insertions(+), 6 deletions(-)

diff --git a/drivers/leds/flash/leds-mt6360.c b/drivers/leds/flash/leds-mt6360.c
index 712cd46..8fe3dc4 100644
--- a/drivers/leds/flash/leds-mt6360.c
+++ b/drivers/leds/flash/leds-mt6360.c
@@ -24,9 +24,19 @@ enum {
 	MT6360_MAX_LEDS
 };
 
+#define MT6360_ISNK_PWM_MODE		0
+#define MT6360_ISNK_CC_MODE		2
+
 #define MT6360_REG_RGBEN		0x380
 #define MT6360_REG_ISNK(_led_no)	(0x381 + (_led_no))
+#define MT6360_REG_DIM(_led_no)		(0x385 + (_led_no))
+#define MT6360_REG_FREQ1		0x389
+#define MT6360_REG_FREQ2		0x38A
 #define MT6360_ISNK_ENMASK(_led_no)	BIT(7 - (_led_no))
+#define MT6360_FREQ13_MASK		GENMASK(7, 5)
+#define MT6360_FREQ2_MASK		GENMASK(4, 2)
+#define MT6360_ISNK_MODE_MASK		GENMASK(7, 6)
+#define MT6360_ISNK_MODE_SHFT		6
 #define MT6360_ISNK_MASK		GENMASK(4, 0)
 #define MT6360_CHRINDSEL_MASK		BIT(3)
 
@@ -98,13 +108,128 @@ struct mt6360_priv {
 	struct mt6360_led leds[];
 };
 
+static int mt6360_get_selected_freq_duty(unsigned long on, unsigned long off,
+					 unsigned int *fsel, unsigned int *dsel)
+{
+	static const unsigned int freq_ms[] = { 8000, 4000, 2000, 1000,
+						500, 250, 8, 4 };
+	unsigned int sum = on + off;
+	int i;
+
+	/* Check if val is less than the smallest or larger then the largest */
+	if (sum > freq_ms[0] || sum < freq_ms[ARRAY_SIZE(freq_ms) - 1])
+		return -EINVAL;
+
+	/* Find the frequency for less or equal one */
+	for (i = 0; i < ARRAY_SIZE(freq_ms) - 1; i++) {
+		if (sum >= freq_ms[i])
+			break;
+	}
+
+	*fsel = i;
+	*dsel = on * 255 / sum;
+	return 0;
+}
+
+static int mt6360_set_pwm_dimming_param(struct mt6360_priv *priv,
+					unsigned int led_no, unsigned int fsel,
+					unsigned int dsel)
+{
+	unsigned int freq_reg, freq_mask, freq_shift;
+	int ret;
+
+	switch (led_no) {
+	case MT6360_LED_ISNK1:
+		freq_reg = MT6360_REG_FREQ1;
+		freq_mask = MT6360_FREQ13_MASK;
+		break;
+	case MT6360_LED_ISNK2:
+		freq_reg = MT6360_REG_FREQ1;
+		freq_mask = MT6360_FREQ2_MASK;
+		break;
+	case MT6360_LED_ISNK3:
+		freq_reg = MT6360_REG_FREQ2;
+		freq_mask = MT6360_FREQ13_MASK;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	freq_shift = ffs(freq_mask) - 1;
+
+	ret = regmap_update_bits(priv->regmap, freq_reg, freq_mask,
+				 fsel << freq_shift);
+	if (ret)
+		return ret;
+
+	return regmap_write(priv->regmap, MT6360_REG_DIM(led_no), dsel);
+}
+
+static int mt6360_mc_blink_set(struct led_classdev *lcdev, unsigned long *don,
+			       unsigned long *doff)
+{
+	struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev);
+	struct mt6360_led *led = container_of(mccdev, struct mt6360_led, mc);
+	struct mt6360_priv *priv = led->priv;
+	unsigned int freq_sel, duty_sel;
+	u8 mc_reg[3];
+	int i, ret;
+
+	if (!*don && !*doff)
+		*don = *doff = 500;
+
+	mutex_lock(&priv->lock);
+
+	ret = regmap_raw_read(priv->regmap, MT6360_REG_ISNK(0), mc_reg, 3);
+	if (ret)
+		goto out;
+
+	/* Configure all subleds to CC mode first */
+	for (i = 0; i < mccdev->num_colors; i++) {
+		struct mc_subled *subled = mccdev->subled_info + i;
+		int ch_idx = subled->channel;
+
+		mc_reg[ch_idx] &= ~MT6360_ISNK_MODE_MASK;
+		mc_reg[ch_idx] |= MT6360_ISNK_CC_MODE << MT6360_ISNK_MODE_SHFT;
+	}
+
+	ret = regmap_raw_write(priv->regmap, MT6360_REG_ISNK(0), mc_reg, 3);
+	if (ret)
+		goto out;
+
+	/* Get the desired selector for frequency and duty */
+	ret = mt6360_get_selected_freq_duty(*don, *doff, &freq_sel, &duty_sel);
+	if (ret)
+		goto out;
+
+	/* Configure all subleds dim freq/duty and change to PWM mode */
+	for (i = 0; i < mccdev->num_colors; i++) {
+		struct mc_subled *subled = mccdev->subled_info + i;
+		int ch_idx = subled->channel;
+
+		ret = mt6360_set_pwm_dimming_param(priv, ch_idx, freq_sel,
+						   duty_sel);
+		if (ret)
+			goto out;
+
+		mc_reg[ch_idx] &= ~MT6360_ISNK_MODE_MASK;
+		mc_reg[ch_idx] |= MT6360_ISNK_PWM_MODE << MT6360_ISNK_MODE_SHFT;
+	}
+
+	ret = regmap_raw_write(priv->regmap, MT6360_REG_ISNK(0), mc_reg, 3);
+
+out:
+	mutex_unlock(&priv->lock);
+	return ret;
+}
+
 static int mt6360_mc_brightness_set(struct led_classdev *lcdev,
 				    enum led_brightness level)
 {
 	struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev);
 	struct mt6360_led *led = container_of(mccdev, struct mt6360_led, mc);
 	struct mt6360_priv *priv = led->priv;
-	u32 real_bright, enable_mask = 0, enable = 0;
+	u32 real_bright, enable_mask = 0, enable = 0, val;
 	int i, ret;
 
 	mutex_lock(&priv->lock);
@@ -113,11 +238,25 @@ static int mt6360_mc_brightness_set(struct led_classdev *lcdev,
 
 	for (i = 0; i < mccdev->num_colors; i++) {
 		struct mc_subled *subled = mccdev->subled_info + i;
+		unsigned int bright_reg = MT6360_REG_ISNK(subled->channel);
 
 		real_bright = min(lcdev->max_brightness, subled->brightness);
-		ret = regmap_update_bits(priv->regmap,
-					 MT6360_REG_ISNK(subled->channel),
-					 MT6360_ISNK_MASK, real_bright);
+
+		ret = regmap_read(priv->regmap, bright_reg, &val);
+		if (ret)
+			goto out;
+
+		/* Assign the new brightness value */
+		val &= ~MT6360_ISNK_MASK;
+		val |= (real_bright & MT6360_ISNK_MASK);
+
+		/* If LED_OFF, always configure back to CC mode */
+		if (level == LED_OFF) {
+			val &= ~MT6360_ISNK_MODE_MASK;
+			val |= MT6360_ISNK_CC_MODE << MT6360_ISNK_MODE_SHFT;
+		}
+
+		ret = regmap_write(priv->regmap, bright_reg, val);
 		if (ret)
 			goto out;
 
@@ -134,6 +273,44 @@ static int mt6360_mc_brightness_set(struct led_classdev *lcdev,
 	return ret;
 }
 
+static int mt6360_isnk_blink_set(struct led_classdev *lcdev, unsigned long *don,
+				 unsigned long *doff)
+{
+	struct mt6360_led *led = container_of(lcdev, struct mt6360_led, isnk);
+	struct mt6360_priv *priv = led->priv;
+	unsigned int freq_sel, duty_sel;
+	int ret;
+
+	if (!*don && !*doff)
+		*don = *doff = 500;
+
+	mutex_lock(&priv->lock);
+
+	ret = regmap_update_bits(priv->regmap, MT6360_REG_ISNK(led->led_no),
+				 MT6360_ISNK_MODE_MASK,
+				 MT6360_ISNK_CC_MODE << MT6360_ISNK_MODE_SHFT);
+	if (ret)
+		goto out;
+
+	/* Get the desired selector for frequency and duty */
+	ret = mt6360_get_selected_freq_duty(*don, *doff, &freq_sel, &duty_sel);
+	if (ret)
+		goto out;
+
+	ret = mt6360_set_pwm_dimming_param(priv, led->led_no, freq_sel,
+					   duty_sel);
+	if (ret)
+		goto out;
+
+	ret = regmap_update_bits(priv->regmap, MT6360_REG_ISNK(led->led_no),
+				 MT6360_ISNK_MODE_MASK,
+				 MT6360_ISNK_PWM_MODE << MT6360_ISNK_MODE_SHFT);
+
+out:
+	mutex_unlock(&priv->lock);
+	return ret;
+}
+
 static int mt6360_isnk_brightness_set(struct led_classdev *lcdev,
 				      enum led_brightness level)
 {
@@ -141,12 +318,27 @@ static int mt6360_isnk_brightness_set(struct led_classdev *lcdev,
 	struct mt6360_priv *priv = led->priv;
 	u32 enable_mask = MT6360_ISNK_ENMASK(led->led_no);
 	u32 val = level ? MT6360_ISNK_ENMASK(led->led_no) : 0;
+	unsigned int bright_val;
 	int ret;
 
 	mutex_lock(&priv->lock);
 
-	ret = regmap_update_bits(priv->regmap, MT6360_REG_ISNK(led->led_no),
-				 MT6360_ISNK_MASK, level);
+	ret = regmap_read(priv->regmap, MT6360_REG_ISNK(led->led_no),
+			  &bright_val);
+	if (ret)
+		goto out;
+
+	bright_val &= ~MT6360_ISNK_MASK;
+	bright_val |= (level & MT6360_ISNK_MASK);
+
+	/* If LED_OFF, always configure back to CC mode */
+	if (led->led_no != MT6360_LED_ISNKML && level == LED_OFF) {
+		bright_val &= ~MT6360_ISNK_MODE_MASK;
+		bright_val |= MT6360_ISNK_CC_MODE << MT6360_ISNK_MODE_SHFT;
+	}
+
+	ret = regmap_write(priv->regmap, MT6360_REG_ISNK(led->led_no),
+			   bright_val);
 	if (ret)
 		goto out;
 
@@ -666,6 +858,7 @@ static int mt6360_init_isnk_properties(struct mt6360_led *led,
 
 		lcdev = &led->mc.led_cdev;
 		lcdev->brightness_set_blocking = mt6360_mc_brightness_set;
+		lcdev->blink_set = mt6360_mc_blink_set;
 	} else {
 		if (led->led_no == MT6360_LED_ISNKML) {
 			step_uA = MT6360_ISNKML_STEPUA;
@@ -674,6 +867,10 @@ static int mt6360_init_isnk_properties(struct mt6360_led *led,
 
 		lcdev = &led->isnk;
 		lcdev->brightness_set_blocking = mt6360_isnk_brightness_set;
+
+		/* Suppose only ISNK1/2/3 support mode change */
+		if (led->led_no != MT6360_LED_ISNKML)
+			lcdev->blink_set = mt6360_isnk_blink_set;
 	}
 
 	ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp",
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 4/4] leds: flash: mt6360: Add mt6360 isnk channel hardwre breath mode support
  2022-04-28  9:32 [PATCH 0/4] leds: flash: mt6360: Apply the fixes and hardware features cy_huang
                   ` (2 preceding siblings ...)
  2022-04-28  9:32 ` [PATCH 3/4] leds: flash: mt6360: Add mt6360 isnk channel hardware timer dimming mode support cy_huang
@ 2022-04-28  9:32 ` cy_huang
  2022-04-28 11:50   ` Matti Vaittinen
  2022-06-14  7:36 ` [PATCH 0/4] leds: flash: mt6360: Apply the fixes and hardware features ChiYuan Huang
  4 siblings, 1 reply; 8+ messages in thread
From: cy_huang @ 2022-04-28  9:32 UTC (permalink / raw)
  To: pavel, matthias.bgg
  Cc: cy_huang, jacek.anaszewski, gene_chen, linux-leds,
	linux-arm-kernel, linux-mediatek, linux-kernel

From: ChiYuan Huang <cy_huang@richtek.com>

Add mt6360 isnk channel hardware breath mode support.

Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
---
 drivers/leds/flash/Kconfig       |   1 +
 drivers/leds/flash/leds-mt6360.c | 207 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 207 insertions(+), 1 deletion(-)

diff --git a/drivers/leds/flash/Kconfig b/drivers/leds/flash/Kconfig
index 38b325c..039ff50 100644
--- a/drivers/leds/flash/Kconfig
+++ b/drivers/leds/flash/Kconfig
@@ -54,6 +54,7 @@ config LEDS_MT6360
 	depends on LEDS_CLASS_MULTICOLOR || !LEDS_CLASS_MULTICOLOR
 	depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS
 	depends on MFD_MT6360
+	select LINEAR_RANGE
 	help
 	  This option enables support for dual Flash LED drivers found on
 	  Mediatek MT6360 PMIC.
diff --git a/drivers/leds/flash/leds-mt6360.c b/drivers/leds/flash/leds-mt6360.c
index 8fe3dc4..b4a702c 100644
--- a/drivers/leds/flash/leds-mt6360.c
+++ b/drivers/leds/flash/leds-mt6360.c
@@ -7,6 +7,7 @@
 #include <linux/kernel.h>
 #include <linux/led-class-flash.h>
 #include <linux/led-class-multicolor.h>
+#include <linux/linear_range.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
@@ -24,7 +25,14 @@ enum {
 	MT6360_MAX_LEDS
 };
 
+enum mt6360_iled_range {
+	MT6360_ILED_RANGE_TRF12ON = 0, /* tr1, tr2, ton, tf1, tf2 */
+	MT6360_ILED_RANGE_TOFF,
+	MT6360_ILED_RANGE_MAX
+};
+
 #define MT6360_ISNK_PWM_MODE		0
+#define MT6360_ISNK_BREATH_MODE		1
 #define MT6360_ISNK_CC_MODE		2
 
 #define MT6360_REG_RGBEN		0x380
@@ -32,6 +40,7 @@ enum {
 #define MT6360_REG_DIM(_led_no)		(0x385 + (_led_no))
 #define MT6360_REG_FREQ1		0x389
 #define MT6360_REG_FREQ2		0x38A
+#define MT6360_REG_ISNK_BREATH(_ledno)	(0x38B + ((_ledno) * 3))
 #define MT6360_ISNK_ENMASK(_led_no)	BIT(7 - (_led_no))
 #define MT6360_FREQ13_MASK		GENMASK(7, 5)
 #define MT6360_FREQ2_MASK		GENMASK(4, 2)
@@ -39,6 +48,14 @@ enum {
 #define MT6360_ISNK_MODE_SHFT		6
 #define MT6360_ISNK_MASK		GENMASK(4, 0)
 #define MT6360_CHRINDSEL_MASK		BIT(3)
+#define MT6360_ISNK_TR1_MASK		GENMASK(7, 4)
+#define MT6360_ISNK_TR2_MASK		GENMASK(3, 0)
+#define MT6360_ISNK_TF1_MASK		GENMASK(7, 4)
+#define MT6360_ISNK_TF2_MASK		GENMASK(3, 0)
+#define MT6360_ISNK_TON_MASK		GENMASK(7, 4)
+#define MT6360_ISNK_TOFF_MASK		GENMASK(3, 0)
+#define MT6360_BREATH_PATTERN_CNT	6
+#define MT6360_BREATH_CFGRG_CNT		3
 
 /* Virtual definition for multicolor */
 #define MT6360_VIRTUAL_MULTICOLOR	(MT6360_MAX_LEDS + 1)
@@ -108,6 +125,46 @@ struct mt6360_priv {
 	struct mt6360_led leds[];
 };
 
+static int mt6360_gen_breath_reg_config(struct led_pattern *pattern, u32 len,
+					u8 *vals, int val_len)
+{
+	static const struct linear_range tranges[MT6360_ILED_RANGE_MAX] = {
+		{ 125, 0, 15, 250 }, /* tr/f12 and ton, unit: millisecond */
+		{ 250, 0, 15, 500 }, /* toff, unit: millisecond */
+	};
+	static const struct {
+		int rg_offset;
+		int mask;
+		enum mt6360_iled_range rid;
+	} params[MT6360_BREATH_PATTERN_CNT] = {
+		{ 0, MT6360_ISNK_TR1_MASK, MT6360_ILED_RANGE_TRF12ON },
+		{ 0, MT6360_ISNK_TR2_MASK, MT6360_ILED_RANGE_TRF12ON },
+		{ 2, MT6360_ISNK_TON_MASK, MT6360_ILED_RANGE_TRF12ON },
+		{ 1, MT6360_ISNK_TF1_MASK, MT6360_ILED_RANGE_TRF12ON },
+		{ 1, MT6360_ISNK_TF2_MASK, MT6360_ILED_RANGE_TRF12ON },
+		{ 2, MT6360_ISNK_TOFF_MASK, MT6360_ILED_RANGE_TOFF }
+	};
+	unsigned int sel;
+	int i, shift;
+
+	/* Must contain 6 tuples to configure tr1, tr2, ton, tf1, tf2, toff */
+	if (len != MT6360_BREATH_PATTERN_CNT ||
+	    val_len != MT6360_BREATH_CFGRG_CNT)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(params); i++) {
+		linear_range_get_selector_within(tranges + params[i].rid,
+						 pattern[i].delta_t, &sel);
+
+		shift = ffs(params[i].mask) - 1;
+
+		vals[params[i].rg_offset] &= ~params[i].mask;
+		vals[params[i].rg_offset] |= sel << shift;
+	}
+
+	return 0;
+}
+
 static int mt6360_get_selected_freq_duty(unsigned long on, unsigned long off,
 					 unsigned int *fsel, unsigned int *dsel)
 {
@@ -165,6 +222,95 @@ static int mt6360_set_pwm_dimming_param(struct mt6360_priv *priv,
 	return regmap_write(priv->regmap, MT6360_REG_DIM(led_no), dsel);
 }
 
+static int mt6360_mc_pattern_set(struct led_classdev *lcdev,
+				 struct led_pattern *pattern, u32 len,
+				 int repeat)
+{
+	struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev);
+	struct mt6360_led *led = container_of(mccdev, struct mt6360_led, mc);
+	struct mt6360_priv *priv = led->priv;
+	unsigned int reg_base;
+	u8 cfg_vals[MT6360_BREATH_CFGRG_CNT] = {0};
+	u8 mc_reg[3];
+	int i, ret;
+
+	ret = mt6360_gen_breath_reg_config(pattern, len, cfg_vals,
+					   sizeof(cfg_vals));
+	if (ret)
+		return ret;
+
+	mutex_lock(&priv->lock);
+
+	ret = regmap_raw_read(priv->regmap, MT6360_REG_ISNK(0), mc_reg, 3);
+	if (ret)
+		goto out;
+
+	/* Configure all subleds to CC mode first */
+	for (i = 0; i < mccdev->num_colors; i++) {
+		struct mc_subled *subled = mccdev->subled_info + i;
+		int ch_idx = subled->channel;
+
+		mc_reg[ch_idx] &= ~MT6360_ISNK_MODE_MASK;
+		mc_reg[ch_idx] |= MT6360_ISNK_CC_MODE << MT6360_ISNK_MODE_SHFT;
+	}
+
+	ret = regmap_raw_write(priv->regmap, MT6360_REG_ISNK(0), mc_reg, 3);
+	if (ret)
+		goto out;
+
+	for (i = 0; i < mccdev->num_colors; i++) {
+		struct mc_subled *subled = mccdev->subled_info + i;
+		int ch_idx = subled->channel;
+
+		reg_base = MT6360_REG_ISNK_BREATH(ch_idx);
+
+		ret = regmap_raw_write(priv->regmap, reg_base, cfg_vals,
+				       sizeof(cfg_vals));
+		if (ret)
+			goto out;
+
+		mc_reg[ch_idx] &= ~MT6360_ISNK_MODE_MASK;
+		mc_reg[ch_idx] |=
+			MT6360_ISNK_BREATH_MODE << MT6360_ISNK_MODE_SHFT;
+	}
+
+	ret = regmap_raw_write(priv->regmap, MT6360_REG_ISNK(0), mc_reg, 3);
+
+out:
+	mutex_unlock(&priv->lock);
+	return ret;
+}
+
+static int mt6360_mc_pattern_clear(struct led_classdev *lcdev)
+{
+	struct led_classdev_mc *mccdev = lcdev_to_mccdev(lcdev);
+	struct mt6360_led *led = container_of(mccdev, struct mt6360_led, mc);
+	struct mt6360_priv *priv = led->priv;
+	u8 mc_reg[3];
+	int i, ret;
+
+	mutex_lock(&priv->lock);
+
+	ret = regmap_raw_read(priv->regmap, MT6360_REG_ISNK(0), mc_reg, 3);
+	if (ret)
+		goto out;
+
+	/* Configure all subleds to CC mode first */
+	for (i = 0; i < mccdev->num_colors; i++) {
+		struct mc_subled *subled = mccdev->subled_info + i;
+		int ch_idx = subled->channel;
+
+		mc_reg[ch_idx] &= ~MT6360_ISNK_MODE_MASK;
+		mc_reg[ch_idx] |= MT6360_ISNK_CC_MODE << MT6360_ISNK_MODE_SHFT;
+	}
+
+	ret = regmap_raw_write(priv->regmap, MT6360_REG_ISNK(0), mc_reg, 3);
+
+out:
+	mutex_unlock(&priv->lock);
+	return ret;
+}
+
 static int mt6360_mc_blink_set(struct led_classdev *lcdev, unsigned long *don,
 			       unsigned long *doff)
 {
@@ -273,6 +419,60 @@ static int mt6360_mc_brightness_set(struct led_classdev *lcdev,
 	return ret;
 }
 
+static int mt6360_isnk_pattern_set(struct led_classdev *lcdev,
+				   struct led_pattern *pattern, u32 len,
+				   int repeat)
+{
+	struct mt6360_led *led = container_of(lcdev, struct mt6360_led, isnk);
+	struct mt6360_priv *priv = led->priv;
+	unsigned int reg_base = MT6360_REG_ISNK_BREATH(led->led_no);
+	u8 cfg_vals[MT6360_BREATH_CFGRG_CNT] = {0};
+	int ret;
+
+	ret = mt6360_gen_breath_reg_config(pattern, len, cfg_vals,
+					   sizeof(cfg_vals));
+	if (ret)
+		return ret;
+
+	mutex_lock(&priv->lock);
+
+	ret = regmap_raw_write(priv->regmap, reg_base, cfg_vals,
+			       sizeof(cfg_vals));
+	if (ret)
+		goto out;
+
+	/* Toggle mode change to make new parameter applied */
+	ret = regmap_update_bits(priv->regmap, MT6360_REG_ISNK(led->led_no),
+				 MT6360_ISNK_MODE_MASK, MT6360_ISNK_CC_MODE
+				 << MT6360_ISNK_MODE_SHFT);
+	if (ret)
+		goto out;
+
+	ret = regmap_update_bits(priv->regmap, MT6360_REG_ISNK(led->led_no),
+				 MT6360_ISNK_MODE_MASK, MT6360_ISNK_BREATH_MODE
+				 << MT6360_ISNK_MODE_SHFT);
+
+out:
+	mutex_unlock(&priv->lock);
+	return 0;
+}
+
+static int mt6360_isnk_pattern_clear(struct led_classdev *lcdev)
+{
+	struct mt6360_led *led = container_of(lcdev, struct mt6360_led, isnk);
+	struct mt6360_priv *priv = led->priv;
+	int ret;
+
+	mutex_lock(&priv->lock);
+
+	ret = regmap_update_bits(priv->regmap, MT6360_REG_ISNK(led->led_no),
+				 MT6360_ISNK_MODE_MASK, MT6360_ISNK_CC_MODE
+				 << MT6360_ISNK_MODE_SHFT);
+
+	mutex_unlock(&priv->lock);
+	return ret;
+}
+
 static int mt6360_isnk_blink_set(struct led_classdev *lcdev, unsigned long *don,
 				 unsigned long *doff)
 {
@@ -859,6 +1059,8 @@ static int mt6360_init_isnk_properties(struct mt6360_led *led,
 		lcdev = &led->mc.led_cdev;
 		lcdev->brightness_set_blocking = mt6360_mc_brightness_set;
 		lcdev->blink_set = mt6360_mc_blink_set;
+		lcdev->pattern_set = mt6360_mc_pattern_set;
+		lcdev->pattern_clear = mt6360_mc_pattern_clear;
 	} else {
 		if (led->led_no == MT6360_LED_ISNKML) {
 			step_uA = MT6360_ISNKML_STEPUA;
@@ -869,8 +1071,11 @@ static int mt6360_init_isnk_properties(struct mt6360_led *led,
 		lcdev->brightness_set_blocking = mt6360_isnk_brightness_set;
 
 		/* Suppose only ISNK1/2/3 support mode change */
-		if (led->led_no != MT6360_LED_ISNKML)
+		if (led->led_no != MT6360_LED_ISNKML) {
 			lcdev->blink_set = mt6360_isnk_blink_set;
+			lcdev->pattern_set = mt6360_isnk_pattern_set;
+			lcdev->pattern_clear = mt6360_isnk_pattern_clear;
+		}
 	}
 
 	ret = fwnode_property_read_u32(init_data->fwnode, "led-max-microamp",
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 4/4] leds: flash: mt6360: Add mt6360 isnk channel hardwre breath mode support
  2022-04-28  9:32 ` [PATCH 4/4] leds: flash: mt6360: Add mt6360 isnk channel hardwre breath " cy_huang
@ 2022-04-28 11:50   ` Matti Vaittinen
  2022-04-28 14:57     ` ChiYuan Huang
  0 siblings, 1 reply; 8+ messages in thread
From: Matti Vaittinen @ 2022-04-28 11:50 UTC (permalink / raw)
  To: cy_huang
  Cc: Pavel Machek, Matthias Brugger, ChiYuan Huang, Jacek Anaszewski,
	Gene Chen, linux-leds, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List

Hi ChiYuan!

On Thu, Apr 28, 2022 at 1:03 PM cy_huang <u0084500@gmail.com> wrote:
> From: ChiYuan Huang <cy_huang@richtek.com>
>
> Add mt6360 isnk channel hardware breath mode support.
>
> Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
>
> +static int mt6360_gen_breath_reg_config(struct led_pattern *pattern, u32 len,
> +                                       u8 *vals, int val_len)
> +{
> +       static const struct linear_range tranges[MT6360_ILED_RANGE_MAX] = {
> +               { 125, 0, 15, 250 }, /* tr/f12 and ton, unit: millisecond */
> +               { 250, 0, 15, 500 }, /* toff, unit: millisecond */
> +       };

It's nice to see you are using the linear_ranges helpers here! Just a
minor remark - do you think you could use field names in linear_ranges
initializations? That would make it less likely the driver breaks if
someone changes the struct linear_range definition. Eg, use something
like:

static const struct linear_range tranges[MT6360_ILED_RANGE_MAX] = {
        /* tr/f12 and ton, unit: millisecond */
        { .min = 125, .min_sel = 0, .max_sel = 15, .step = 250 },
        /* toff, unit: millisecond */
        { .min = 250, .min_sel = 0, .max_sel = 15, .step = 500 },
};

Do you think that would work?

Best Regards
-- Matti

-- 

Matti Vaittinen
Linux kernel developer at ROHM Semiconductors
Oulu Finland

~~ When things go utterly wrong vim users can always type :help! ~~

Discuss - Estimate - Plan - Report and finally accomplish this:
void do_work(int time) __attribute__ ((const));

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 4/4] leds: flash: mt6360: Add mt6360 isnk channel hardwre breath mode support
  2022-04-28 11:50   ` Matti Vaittinen
@ 2022-04-28 14:57     ` ChiYuan Huang
  0 siblings, 0 replies; 8+ messages in thread
From: ChiYuan Huang @ 2022-04-28 14:57 UTC (permalink / raw)
  To: Matti Vaittinen
  Cc: Pavel Machek, Matthias Brugger, ChiYuan Huang, Jacek Anaszewski,
	Gene Chen, Linux LED Subsystem, linux-arm Mailing List,
	moderated list:ARM/Mediatek SoC support,
	Linux Kernel Mailing List

Matti Vaittinen <mazziesaccount@gmail.com> 於 2022年4月28日 週四 下午7:51寫道:
>
> Hi ChiYuan!
>
> On Thu, Apr 28, 2022 at 1:03 PM cy_huang <u0084500@gmail.com> wrote:
> > From: ChiYuan Huang <cy_huang@richtek.com>
> >
> > Add mt6360 isnk channel hardware breath mode support.
> >
> > Signed-off-by: ChiYuan Huang <cy_huang@richtek.com>
> >
> > +static int mt6360_gen_breath_reg_config(struct led_pattern *pattern, u32 len,
> > +                                       u8 *vals, int val_len)
> > +{
> > +       static const struct linear_range tranges[MT6360_ILED_RANGE_MAX] = {
> > +               { 125, 0, 15, 250 }, /* tr/f12 and ton, unit: millisecond */
> > +               { 250, 0, 15, 500 }, /* toff, unit: millisecond */
> > +       };
>
> It's nice to see you are using the linear_ranges helpers here! Just a
> minor remark - do you think you could use field names in linear_ranges
> initializations? That would make it less likely the driver breaks if
> someone changes the struct linear_range definition. Eg, use something
> like:
>
> static const struct linear_range tranges[MT6360_ILED_RANGE_MAX] = {
>         /* tr/f12 and ton, unit: millisecond */
>         { .min = 125, .min_sel = 0, .max_sel = 15, .step = 250 },
>         /* toff, unit: millisecond */
>         { .min = 250, .min_sel = 0, .max_sel = 15, .step = 500 },
> };
>
> Do you think that would work?
Sure, it works.
To specify the field name can be compatible if the struct changes in the future.
Thanks.
>
> Best Regards
> -- Matti
>
> --
>
> Matti Vaittinen
> Linux kernel developer at ROHM Semiconductors
> Oulu Finland
>
> ~~ When things go utterly wrong vim users can always type :help! ~~
>
> Discuss - Estimate - Plan - Report and finally accomplish this:
> void do_work(int time) __attribute__ ((const));

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/4] leds: flash: mt6360: Apply the fixes and hardware features
  2022-04-28  9:32 [PATCH 0/4] leds: flash: mt6360: Apply the fixes and hardware features cy_huang
                   ` (3 preceding siblings ...)
  2022-04-28  9:32 ` [PATCH 4/4] leds: flash: mt6360: Add mt6360 isnk channel hardwre breath " cy_huang
@ 2022-06-14  7:36 ` ChiYuan Huang
  4 siblings, 0 replies; 8+ messages in thread
From: ChiYuan Huang @ 2022-06-14  7:36 UTC (permalink / raw)
  To: Pavel Machek, Matthias Brugger
  Cc: cy_huang, Jacek Anaszewski, Gene Chen, Linux LED Subsystem,
	linux-arm Mailing List, moderated list:ARM/Mediatek SoC support,
	lkml

Hi:

    Is there any comment about this patch series?
One is for the fix, second is Kconfig refine, others are for the HW
PWM/Breath feature added.

cy_huang <u0084500@gmail.com> 於 2022年4月28日 週四 下午5:33寫道:
>
> From: ChiYuan Huang <cy_huang@richtek.com>
>
> This patch series includes some fixes and add supproted ISNK hardware features.
> From MT6360, ISNK can support three modes (CC, PWM, and Breath). The previous
> one can only support CC mode.
>
> ChiYuan Huang (4):
>   leds: flash: mt6360: Fix the wrong enable_reg in multicolor brightness
>     set
>   leds: flash: mt6360: Remove unused dependency in Kconfig
>   leds: flash: mt6360: Add mt6360 isnk channel hardware timer dimming
>     mode support
>   leds: flash: mt6360: Add mt6360 isnk channel hardwre breath mode
>     support
>
>  drivers/leds/flash/Kconfig       |   4 +-
>  drivers/leds/flash/leds-mt6360.c | 413 ++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 410 insertions(+), 7 deletions(-)
>
> --
> 2.7.4
>

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2022-06-14  7:36 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-28  9:32 [PATCH 0/4] leds: flash: mt6360: Apply the fixes and hardware features cy_huang
2022-04-28  9:32 ` [PATCH 1/4] leds: flash: mt6360: Fix the wrong enable_reg in multicolor brightness set cy_huang
2022-04-28  9:32 ` [PATCH 2/4] leds: flash: mt6360: Remove unused dependency in Kconfig cy_huang
2022-04-28  9:32 ` [PATCH 3/4] leds: flash: mt6360: Add mt6360 isnk channel hardware timer dimming mode support cy_huang
2022-04-28  9:32 ` [PATCH 4/4] leds: flash: mt6360: Add mt6360 isnk channel hardwre breath " cy_huang
2022-04-28 11:50   ` Matti Vaittinen
2022-04-28 14:57     ` ChiYuan Huang
2022-06-14  7:36 ` [PATCH 0/4] leds: flash: mt6360: Apply the fixes and hardware features ChiYuan Huang

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).