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