1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /* Copyright(c) 2026 Realtek Corporation
3 */
4
5 #include "core.h"
6 #include "debug.h"
7 #include "led.h"
8 #include "reg.h"
9
10 static const struct rtw89_led_gpio_entry rtw89_common_led_gpios[] = {{
11 .pin = 8,
12 .pinmux = {.addr = R_AX_GPIO8_15_FUNC_SEL, .mask = GENMASK(3, 0), .data = 0xf},
13 .mode = {.addr = R_AX_GPIO_EXT_CTRL + 2, .data = BIT(0) | BIT(8)},
14 .out = {.addr = R_AX_GPIO_EXT_CTRL + 1, .data = BIT(0)},
15 }};
16
17 static const struct rtw89_led_desc rtw89_common_led_desc = {
18 .gpios = rtw89_common_led_gpios,
19 .n_gpio = ARRAY_SIZE(rtw89_common_led_gpios),
20 };
21
rtw89_led_gpio_config(struct rtw89_dev * rtwdev,const struct rtw89_led_gpio_entry * e)22 void rtw89_led_gpio_config(struct rtw89_dev *rtwdev,
23 const struct rtw89_led_gpio_entry *e)
24 {
25 rtw89_write32_mask(rtwdev, e->pinmux.addr, e->pinmux.mask, e->pinmux.data);
26 rtw89_write16_clr(rtwdev, e->mode.addr, e->mode.data);
27 }
28
rtw89_led_gpio_set(struct rtw89_dev * rtwdev,const struct rtw89_led_gpio_entry * e,enum led_brightness brightness)29 void rtw89_led_gpio_set(struct rtw89_dev *rtwdev,
30 const struct rtw89_led_gpio_entry *e,
31 enum led_brightness brightness)
32 {
33 if (brightness == LED_OFF) {
34 rtw89_write16_clr(rtwdev, e->mode.addr, e->mode.data);
35 } else {
36 rtw89_write16_set(rtwdev, e->mode.addr, e->mode.data);
37 rtw89_write8_clr(rtwdev, e->out.addr, e->out.data);
38 }
39 }
40
rtw89_led_set(struct led_classdev * led,enum led_brightness brightness)41 static int rtw89_led_set(struct led_classdev *led, enum led_brightness brightness)
42 {
43 struct rtw89_led *rtw_led = container_of(led, struct rtw89_led, led);
44 struct rtw89_dev *rtwdev = container_of(rtw_led, struct rtw89_dev, led);
45 const struct rtw89_led_desc *desc = rtw_led->desc;
46 const struct rtw89_led_gpio_entry *e = &desc->gpios[0];
47
48 if (rtw_led->brightness_cache[0] == brightness) {
49 rtw89_debug(rtwdev, RTW89_DBG_LED, "led_set: pin=%u skip (no change)\n",
50 e->pin);
51 return 0;
52 }
53
54 wiphy_lock(rtwdev->hw->wiphy);
55
56 rtw89_debug(rtwdev, RTW89_DBG_LED, "led_set: pin=%u brightness=%u\n",
57 e->pin, brightness);
58 rtw89_led_gpio_set(rtwdev, e, brightness);
59 rtw_led->brightness_cache[0] = brightness;
60
61 wiphy_unlock(rtwdev->hw->wiphy);
62
63 return 0;
64 }
65
rtw89_led_sc_init(struct rtw89_dev * rtwdev,const struct rtw89_led_desc * desc)66 static int rtw89_led_sc_init(struct rtw89_dev *rtwdev, const struct rtw89_led_desc *desc)
67 {
68 struct rtw89_led *rtw_led = &rtwdev->led;
69 int ret;
70
71 snprintf(rtw_led->name, sizeof(rtw_led->name), "rtw89-%s",
72 wiphy_name(rtwdev->hw->wiphy));
73 rtw_led->led.name = rtw_led->name;
74 rtw_led->led.brightness_set_blocking = rtw89_led_set;
75 rtw_led->led.max_brightness = LED_ON;
76 rtw_led->led.default_trigger = ieee80211_get_assoc_led_name(rtwdev->hw);
77
78 ret = led_classdev_register(rtwdev->dev, &rtw_led->led);
79 if (ret) {
80 rtw89_warn(rtwdev, "failed to register LED, ret=%d\n", ret);
81 return ret;
82 }
83
84 rtw89_led_gpio_config(rtwdev, &desc->gpios[0]);
85
86 return 0;
87 }
88
rtw89_led_sc_deinit(struct rtw89_dev * rtwdev)89 static void rtw89_led_sc_deinit(struct rtw89_dev *rtwdev)
90 {
91 struct rtw89_led *rtw_led = &rtwdev->led;
92
93 led_classdev_unregister(&rtw_led->led);
94 }
95
rtw89_led_init(struct rtw89_dev * rtwdev)96 void rtw89_led_init(struct rtw89_dev *rtwdev)
97 {
98 const struct rtw89_led_desc *desc = &rtw89_common_led_desc;
99 struct rtw89_led *rtw_led = &rtwdev->led;
100 const struct rtw89_board_variant *board = rtwdev->board;
101 int ret;
102 int i;
103
104 /* single-GPIO monochrome LED is the only supported layout */
105 BUILD_BUG_ON(ARRAY_SIZE(rtw89_common_led_gpios) != 1);
106
107 if (board)
108 desc = board->led_desc;
109 if (!desc->n_gpio || desc->n_gpio > RTW89_LED_MAX_NUM)
110 return;
111
112 rtw_led->desc = desc;
113 for (i = 0; i < ARRAY_SIZE(rtw_led->brightness_cache); i++)
114 rtw_led->brightness_cache[i] = LED_OFF;
115
116 if (desc->n_gpio == 1)
117 ret = rtw89_led_sc_init(rtwdev, desc);
118 else
119 ret = rtw89_led_mc_init(rtwdev, desc);
120
121 if (ret)
122 return;
123
124 rtw_led->registered = true;
125 }
126
rtw89_led_deinit(struct rtw89_dev * rtwdev)127 void rtw89_led_deinit(struct rtw89_dev *rtwdev)
128 {
129 struct rtw89_led *rtw_led = &rtwdev->led;
130 const struct rtw89_led_desc *desc = rtw_led->desc;
131
132 if (!rtw_led->registered)
133 return;
134
135 if (desc->n_gpio == 1)
136 rtw89_led_sc_deinit(rtwdev);
137 else
138 rtw89_led_mc_deinit(rtwdev);
139 }
140