Skip to content

Commit 9bb0a9e

Browse files
AngeloGioacchino Del Regnolag-linaro
authored andcommitted
leds: leds-mt6323: Add support for WLEDs and MT6332
Add basic code to turn on and off WLEDs and wire up MT6332 support to take advantage of it. This is a simple approach due to the aforementioned PMIC supporting only on/off status so, at the time of writing, it is impossible for me to validate more advanced functionality due to lack of hardware. Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com> Signed-off-by: Lee Jones <lee@kernel.org> Link: https://lore.kernel.org/r/20230601110813.2373764-9-angelogioacchino.delregno@collabora.com
1 parent 9540989 commit 9bb0a9e

1 file changed

Lines changed: 164 additions & 7 deletions

File tree

drivers/leds/leds-mt6323.c

Lines changed: 164 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
#define RG_DRV_32K_CK_PDN BIT(11)
2121
#define RG_DRV_32K_CK_PDN_MASK BIT(11)
2222

23+
/* 32K/1M/6M clock common for WLED device */
24+
#define RG_VWLED_1M_CK_PDN BIT(0)
25+
#define RG_VWLED_32K_CK_PDN BIT(12)
26+
#define RG_VWLED_6M_CK_PDN BIT(13)
27+
2328
/*
2429
* Register field for TOP_CKPDN2 to enable
2530
* individual clock for LED device.
@@ -71,7 +76,7 @@ struct mt6323_led {
7176
int id;
7277
struct mt6323_leds *parent;
7378
struct led_classdev cdev;
74-
enum led_brightness current_brightness;
79+
unsigned int current_brightness;
7580
};
7681

7782
/**
@@ -84,6 +89,7 @@ struct mt6323_led {
8489
* @num_isink_con: Number of ISINKx_CON registers
8590
* @isink_max_regs: Number of ISINK[0..x] registers
8691
* @isink_en_ctrl: Offset to ISINK_EN_CTRL register
92+
* @iwled_en_ctrl: Offset to IWLED_EN_CTRL register
8793
*/
8894
struct mt6323_regs {
8995
const u16 *top_ckpdn;
@@ -94,18 +100,21 @@ struct mt6323_regs {
94100
u8 num_isink_con;
95101
u8 isink_max_regs;
96102
u16 isink_en_ctrl;
103+
u16 iwled_en_ctrl;
97104
};
98105

99106
/**
100107
* struct mt6323_hwspec - hardware specific parameters
101108
* @max_period: Maximum period for all LEDs
102109
* @max_leds: Maximum number of supported LEDs
110+
* @max_wleds: Maximum number of WLEDs
103111
* @max_brightness: Maximum brightness for all LEDs
104112
* @unit_duty: Steps of duty per period
105113
*/
106114
struct mt6323_hwspec {
107115
u16 max_period;
108116
u8 max_leds;
117+
u8 max_wleds;
109118
u16 max_brightness;
110119
u16 unit_duty;
111120
};
@@ -377,6 +386,117 @@ static int mt6323_led_set_brightness(struct led_classdev *cdev,
377386
return ret;
378387
}
379388

389+
static int mtk_wled_hw_on(struct led_classdev *cdev)
390+
{
391+
struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
392+
struct mt6323_leds *leds = led->parent;
393+
const struct mt6323_regs *regs = leds->pdata->regs;
394+
struct regmap *regmap = leds->hw->regmap;
395+
int ret;
396+
397+
ret = regmap_clear_bits(regmap, regs->top_ckpdn[0], RG_VWLED_32K_CK_PDN);
398+
if (ret)
399+
return ret;
400+
401+
ret = regmap_clear_bits(regmap, regs->top_ckpdn[0], RG_VWLED_6M_CK_PDN);
402+
if (ret)
403+
return ret;
404+
405+
ret = regmap_clear_bits(regmap, regs->top_ckpdn[0], RG_VWLED_1M_CK_PDN);
406+
if (ret)
407+
return ret;
408+
409+
usleep_range(5000, 6000);
410+
411+
/* Enable WLED channel pair */
412+
ret = regmap_set_bits(regmap, regs->iwled_en_ctrl, BIT(led->id));
413+
if (ret)
414+
return ret;
415+
416+
ret = regmap_set_bits(regmap, regs->iwled_en_ctrl, BIT(led->id + 1));
417+
if (ret)
418+
return ret;
419+
420+
return 0;
421+
}
422+
423+
static int mtk_wled_hw_off(struct led_classdev *cdev)
424+
{
425+
struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
426+
struct mt6323_leds *leds = led->parent;
427+
const struct mt6323_regs *regs = leds->pdata->regs;
428+
struct regmap *regmap = leds->hw->regmap;
429+
int ret;
430+
431+
ret = regmap_clear_bits(regmap, regs->iwled_en_ctrl, BIT(led->id + 1));
432+
if (ret)
433+
return ret;
434+
435+
ret = regmap_clear_bits(regmap, regs->iwled_en_ctrl, BIT(led->id));
436+
if (ret)
437+
return ret;
438+
439+
ret = regmap_set_bits(regmap, regs->top_ckpdn[0], RG_VWLED_32K_CK_PDN);
440+
if (ret)
441+
return ret;
442+
443+
ret = regmap_set_bits(regmap, regs->top_ckpdn[0], RG_VWLED_6M_CK_PDN);
444+
if (ret)
445+
return ret;
446+
447+
ret = regmap_set_bits(regmap, regs->top_ckpdn[0], RG_VWLED_1M_CK_PDN);
448+
if (ret)
449+
return ret;
450+
451+
return 0;
452+
}
453+
454+
static unsigned int mt6323_get_wled_brightness(struct led_classdev *cdev)
455+
{
456+
struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
457+
struct mt6323_leds *leds = led->parent;
458+
const struct mt6323_regs *regs = leds->pdata->regs;
459+
struct regmap *regmap = leds->hw->regmap;
460+
unsigned int status;
461+
int ret;
462+
463+
ret = regmap_read(regmap, regs->iwled_en_ctrl, &status);
464+
if (ret)
465+
return 0;
466+
467+
/* Always two channels per WLED */
468+
status &= BIT(led->id) | BIT(led->id + 1);
469+
470+
return status ? led->current_brightness : 0;
471+
}
472+
473+
static int mt6323_wled_set_brightness(struct led_classdev *cdev,
474+
unsigned int brightness)
475+
{
476+
struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
477+
struct mt6323_leds *leds = led->parent;
478+
int ret = 0;
479+
480+
mutex_lock(&leds->lock);
481+
482+
if (brightness) {
483+
if (!led->current_brightness)
484+
ret = mtk_wled_hw_on(cdev);
485+
if (ret)
486+
goto out;
487+
} else {
488+
ret = mtk_wled_hw_off(cdev);
489+
if (ret)
490+
goto out;
491+
}
492+
493+
led->current_brightness = brightness;
494+
out:
495+
mutex_unlock(&leds->lock);
496+
497+
return ret;
498+
}
499+
380500
static int mt6323_led_set_dt_default(struct led_classdev *cdev,
381501
struct device_node *np)
382502
{
@@ -416,6 +536,7 @@ static int mt6323_led_probe(struct platform_device *pdev)
416536
int ret;
417537
unsigned int status;
418538
u32 reg;
539+
u8 max_leds;
419540

420541
leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL);
421542
if (!leds)
@@ -426,6 +547,7 @@ static int mt6323_led_probe(struct platform_device *pdev)
426547
leds->pdata = device_get_match_data(dev);
427548
regs = leds->pdata->regs;
428549
spec = leds->pdata->spec;
550+
max_leds = spec->max_leds + spec->max_wleds;
429551

430552
/*
431553
* leds->hw points to the underlying bus for the register
@@ -445,14 +567,15 @@ static int mt6323_led_probe(struct platform_device *pdev)
445567

446568
for_each_available_child_of_node(np, child) {
447569
struct led_init_data init_data = {};
570+
bool is_wled;
448571

449572
ret = of_property_read_u32(child, "reg", &reg);
450573
if (ret) {
451574
dev_err(dev, "Failed to read led 'reg' property\n");
452575
goto put_child_node;
453576
}
454577

455-
if (reg >= spec->max_leds || reg >= MAX_SUPPORTED_LEDS ||
578+
if (reg >= max_leds || reg >= MAX_SUPPORTED_LEDS ||
456579
leds->led[reg]) {
457580
dev_err(dev, "Invalid led reg %u\n", reg);
458581
ret = -EINVAL;
@@ -465,14 +588,24 @@ static int mt6323_led_probe(struct platform_device *pdev)
465588
goto put_child_node;
466589
}
467590

591+
is_wled = of_property_read_bool(child, "mediatek,is-wled");
592+
468593
leds->led[reg] = led;
469594
leds->led[reg]->id = reg;
470595
leds->led[reg]->cdev.max_brightness = spec->max_brightness;
471-
leds->led[reg]->cdev.brightness_set_blocking =
472-
mt6323_led_set_brightness;
473-
leds->led[reg]->cdev.blink_set = mt6323_led_set_blink;
474-
leds->led[reg]->cdev.brightness_get =
475-
mt6323_get_led_hw_brightness;
596+
597+
if (is_wled) {
598+
leds->led[reg]->cdev.brightness_set_blocking =
599+
mt6323_wled_set_brightness;
600+
leds->led[reg]->cdev.brightness_get =
601+
mt6323_get_wled_brightness;
602+
} else {
603+
leds->led[reg]->cdev.brightness_set_blocking =
604+
mt6323_led_set_brightness;
605+
leds->led[reg]->cdev.blink_set = mt6323_led_set_blink;
606+
leds->led[reg]->cdev.brightness_get =
607+
mt6323_get_led_hw_brightness;
608+
}
476609
leds->led[reg]->parent = leds;
477610

478611
ret = mt6323_led_set_dt_default(&leds->led[reg]->cdev, child);
@@ -540,13 +673,31 @@ static const struct mt6323_regs mt6331_registers = {
540673
.isink_en_ctrl = 0x43a,
541674
};
542675

676+
static const struct mt6323_regs mt6332_registers = {
677+
.top_ckpdn = (const u16[]){ 0x8094, 0x809a, 0x80a0 },
678+
.num_top_ckpdn = 3,
679+
.top_ckcon = (const u16[]){ 0x80a6, 0x80ac },
680+
.num_top_ckcon = 2,
681+
.isink_con = (const u16[]){ 0x8cd4 },
682+
.num_isink_con = 1,
683+
.isink_max_regs = 12, /* IWLED[0..2, 3..9] */
684+
.iwled_en_ctrl = 0x8cda,
685+
};
686+
543687
static const struct mt6323_hwspec mt6323_spec = {
544688
.max_period = 10000,
545689
.max_leds = 4,
546690
.max_brightness = 6,
547691
.unit_duty = 3125,
548692
};
549693

694+
static const struct mt6323_hwspec mt6332_spec = {
695+
/* There are no LEDs in MT6332. Only WLEDs are present. */
696+
.max_leds = 0,
697+
.max_wleds = 1,
698+
.max_brightness = 1024,
699+
};
700+
550701
static const struct mt6323_data mt6323_pdata = {
551702
.regs = &mt6323_registers,
552703
.spec = &mt6323_spec,
@@ -557,9 +708,15 @@ static const struct mt6323_data mt6331_pdata = {
557708
.spec = &mt6323_spec,
558709
};
559710

711+
static const struct mt6323_data mt6332_pdata = {
712+
.regs = &mt6332_registers,
713+
.spec = &mt6332_spec,
714+
};
715+
560716
static const struct of_device_id mt6323_led_dt_match[] = {
561717
{ .compatible = "mediatek,mt6323-led", .data = &mt6323_pdata},
562718
{ .compatible = "mediatek,mt6331-led", .data = &mt6331_pdata },
719+
{ .compatible = "mediatek,mt6332-led", .data = &mt6332_pdata },
563720
{},
564721
};
565722
MODULE_DEVICE_TABLE(of, mt6323_led_dt_match);

0 commit comments

Comments
 (0)