* [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