488 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <linux/property.h>3#include <linux/regmap.h>4#include <net/dsa.h>5 6#include "qca8k.h"7#include "qca8k_leds.h"8 9static u32 qca8k_phy_to_port(int phy)10{11 /* Internal PHY 0 has port at index 1.12 * Internal PHY 1 has port at index 2.13 * Internal PHY 2 has port at index 3.14 * Internal PHY 3 has port at index 4.15 * Internal PHY 4 has port at index 5.16 */17 18 return phy + 1;19}20 21static int22qca8k_get_enable_led_reg(int port_num, int led_num, struct qca8k_led_pattern_en *reg_info)23{24 switch (port_num) {25 case 0:26 reg_info->reg = QCA8K_LED_CTRL_REG(led_num);27 reg_info->shift = QCA8K_LED_PHY0123_CONTROL_RULE_SHIFT;28 break;29 case 1:30 case 2:31 case 3:32 /* Port 123 are controlled on a different reg */33 reg_info->reg = QCA8K_LED_CTRL3_REG;34 reg_info->shift = QCA8K_LED_PHY123_PATTERN_EN_SHIFT(port_num, led_num);35 break;36 case 4:37 reg_info->reg = QCA8K_LED_CTRL_REG(led_num);38 reg_info->shift = QCA8K_LED_PHY4_CONTROL_RULE_SHIFT;39 break;40 default:41 return -EINVAL;42 }43 44 return 0;45}46 47static int48qca8k_get_control_led_reg(int port_num, int led_num, struct qca8k_led_pattern_en *reg_info)49{50 reg_info->reg = QCA8K_LED_CTRL_REG(led_num);51 52 /* 6 total control rule:53 * 3 control rules for phy0-3 that applies to all their leds54 * 3 control rules for phy455 */56 if (port_num == 4)57 reg_info->shift = QCA8K_LED_PHY4_CONTROL_RULE_SHIFT;58 else59 reg_info->shift = QCA8K_LED_PHY0123_CONTROL_RULE_SHIFT;60 61 return 0;62}63 64static int65qca8k_parse_netdev(unsigned long rules, u32 *offload_trigger)66{67 /* Parsing specific to netdev trigger */68 if (test_bit(TRIGGER_NETDEV_TX, &rules))69 *offload_trigger |= QCA8K_LED_TX_BLINK_MASK;70 if (test_bit(TRIGGER_NETDEV_RX, &rules))71 *offload_trigger |= QCA8K_LED_RX_BLINK_MASK;72 if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))73 *offload_trigger |= QCA8K_LED_LINK_10M_EN_MASK;74 if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))75 *offload_trigger |= QCA8K_LED_LINK_100M_EN_MASK;76 if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))77 *offload_trigger |= QCA8K_LED_LINK_1000M_EN_MASK;78 if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules))79 *offload_trigger |= QCA8K_LED_HALF_DUPLEX_MASK;80 if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules))81 *offload_trigger |= QCA8K_LED_FULL_DUPLEX_MASK;82 83 if (rules && !*offload_trigger)84 return -EOPNOTSUPP;85 86 /* Enable some default rule by default to the requested mode:87 * - Blink at 4Hz by default88 */89 *offload_trigger |= QCA8K_LED_BLINK_4HZ;90 91 return 0;92}93 94static int95qca8k_led_brightness_set(struct qca8k_led *led,96 enum led_brightness brightness)97{98 struct qca8k_led_pattern_en reg_info;99 struct qca8k_priv *priv = led->priv;100 u32 mask, val;101 102 qca8k_get_enable_led_reg(led->port_num, led->led_num, ®_info);103 104 val = QCA8K_LED_ALWAYS_OFF;105 if (brightness)106 val = QCA8K_LED_ALWAYS_ON;107 108 /* HW regs to control brightness is special and port 1-2-3109 * are placed in a different reg.110 *111 * To control port 0 brightness:112 * - the 2 bit (15, 14) of:113 * - QCA8K_LED_CTRL0_REG for led1114 * - QCA8K_LED_CTRL1_REG for led2115 * - QCA8K_LED_CTRL2_REG for led3116 *117 * To control port 4:118 * - the 2 bit (31, 30) of:119 * - QCA8K_LED_CTRL0_REG for led1120 * - QCA8K_LED_CTRL1_REG for led2121 * - QCA8K_LED_CTRL2_REG for led3122 *123 * To control port 1:124 * - the 2 bit at (9, 8) of QCA8K_LED_CTRL3_REG are used for led1125 * - the 2 bit at (11, 10) of QCA8K_LED_CTRL3_REG are used for led2126 * - the 2 bit at (13, 12) of QCA8K_LED_CTRL3_REG are used for led3127 *128 * To control port 2:129 * - the 2 bit at (15, 14) of QCA8K_LED_CTRL3_REG are used for led1130 * - the 2 bit at (17, 16) of QCA8K_LED_CTRL3_REG are used for led2131 * - the 2 bit at (19, 18) of QCA8K_LED_CTRL3_REG are used for led3132 *133 * To control port 3:134 * - the 2 bit at (21, 20) of QCA8K_LED_CTRL3_REG are used for led1135 * - the 2 bit at (23, 22) of QCA8K_LED_CTRL3_REG are used for led2136 * - the 2 bit at (25, 24) of QCA8K_LED_CTRL3_REG are used for led3137 *138 * To abstract this and have less code, we use the port and led numm139 * to calculate the shift and the correct reg due to this problem of140 * not having a 1:1 map of LED with the regs.141 */142 if (led->port_num == 0 || led->port_num == 4) {143 mask = QCA8K_LED_PATTERN_EN_MASK;144 val <<= QCA8K_LED_PATTERN_EN_SHIFT;145 } else {146 mask = QCA8K_LED_PHY123_PATTERN_EN_MASK;147 }148 149 return regmap_update_bits(priv->regmap, reg_info.reg,150 mask << reg_info.shift,151 val << reg_info.shift);152}153 154static int155qca8k_cled_brightness_set_blocking(struct led_classdev *ldev,156 enum led_brightness brightness)157{158 struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);159 160 return qca8k_led_brightness_set(led, brightness);161}162 163static enum led_brightness164qca8k_led_brightness_get(struct qca8k_led *led)165{166 struct qca8k_led_pattern_en reg_info;167 struct qca8k_priv *priv = led->priv;168 u32 val;169 int ret;170 171 qca8k_get_enable_led_reg(led->port_num, led->led_num, ®_info);172 173 ret = regmap_read(priv->regmap, reg_info.reg, &val);174 if (ret)175 return 0;176 177 val >>= reg_info.shift;178 179 if (led->port_num == 0 || led->port_num == 4) {180 val &= QCA8K_LED_PATTERN_EN_MASK;181 val >>= QCA8K_LED_PATTERN_EN_SHIFT;182 } else {183 val &= QCA8K_LED_PHY123_PATTERN_EN_MASK;184 }185 186 /* Assume brightness ON only when the LED is set to always ON */187 return val == QCA8K_LED_ALWAYS_ON;188}189 190static int191qca8k_cled_blink_set(struct led_classdev *ldev,192 unsigned long *delay_on,193 unsigned long *delay_off)194{195 struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);196 u32 mask, val = QCA8K_LED_ALWAYS_BLINK_4HZ;197 struct qca8k_led_pattern_en reg_info;198 struct qca8k_priv *priv = led->priv;199 200 if (*delay_on == 0 && *delay_off == 0) {201 *delay_on = 125;202 *delay_off = 125;203 }204 205 if (*delay_on != 125 || *delay_off != 125) {206 /* The hardware only supports blinking at 4Hz. Fall back207 * to software implementation in other cases.208 */209 return -EINVAL;210 }211 212 qca8k_get_enable_led_reg(led->port_num, led->led_num, ®_info);213 214 if (led->port_num == 0 || led->port_num == 4) {215 mask = QCA8K_LED_PATTERN_EN_MASK;216 val <<= QCA8K_LED_PATTERN_EN_SHIFT;217 } else {218 mask = QCA8K_LED_PHY123_PATTERN_EN_MASK;219 }220 221 regmap_update_bits(priv->regmap, reg_info.reg, mask << reg_info.shift,222 val << reg_info.shift);223 224 return 0;225}226 227static int228qca8k_cled_trigger_offload(struct led_classdev *ldev, bool enable)229{230 struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);231 232 struct qca8k_led_pattern_en reg_info;233 struct qca8k_priv *priv = led->priv;234 u32 mask, val = QCA8K_LED_ALWAYS_OFF;235 236 qca8k_get_enable_led_reg(led->port_num, led->led_num, ®_info);237 238 if (enable)239 val = QCA8K_LED_RULE_CONTROLLED;240 241 if (led->port_num == 0 || led->port_num == 4) {242 mask = QCA8K_LED_PATTERN_EN_MASK;243 val <<= QCA8K_LED_PATTERN_EN_SHIFT;244 } else {245 mask = QCA8K_LED_PHY123_PATTERN_EN_MASK;246 }247 248 return regmap_update_bits(priv->regmap, reg_info.reg, mask << reg_info.shift,249 val << reg_info.shift);250}251 252static bool253qca8k_cled_hw_control_status(struct led_classdev *ldev)254{255 struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);256 257 struct qca8k_led_pattern_en reg_info;258 struct qca8k_priv *priv = led->priv;259 u32 val;260 261 qca8k_get_enable_led_reg(led->port_num, led->led_num, ®_info);262 263 regmap_read(priv->regmap, reg_info.reg, &val);264 265 val >>= reg_info.shift;266 267 if (led->port_num == 0 || led->port_num == 4) {268 val &= QCA8K_LED_PATTERN_EN_MASK;269 val >>= QCA8K_LED_PATTERN_EN_SHIFT;270 } else {271 val &= QCA8K_LED_PHY123_PATTERN_EN_MASK;272 }273 274 return val == QCA8K_LED_RULE_CONTROLLED;275}276 277static int278qca8k_cled_hw_control_is_supported(struct led_classdev *ldev, unsigned long rules)279{280 u32 offload_trigger = 0;281 282 return qca8k_parse_netdev(rules, &offload_trigger);283}284 285static int286qca8k_cled_hw_control_set(struct led_classdev *ldev, unsigned long rules)287{288 struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);289 struct qca8k_led_pattern_en reg_info;290 struct qca8k_priv *priv = led->priv;291 u32 offload_trigger = 0;292 int ret;293 294 ret = qca8k_parse_netdev(rules, &offload_trigger);295 if (ret)296 return ret;297 298 ret = qca8k_cled_trigger_offload(ldev, true);299 if (ret)300 return ret;301 302 qca8k_get_control_led_reg(led->port_num, led->led_num, ®_info);303 304 return regmap_update_bits(priv->regmap, reg_info.reg,305 QCA8K_LED_RULE_MASK << reg_info.shift,306 offload_trigger << reg_info.shift);307}308 309static int310qca8k_cled_hw_control_get(struct led_classdev *ldev, unsigned long *rules)311{312 struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);313 struct qca8k_led_pattern_en reg_info;314 struct qca8k_priv *priv = led->priv;315 u32 val;316 int ret;317 318 /* With hw control not active return err */319 if (!qca8k_cled_hw_control_status(ldev))320 return -EINVAL;321 322 qca8k_get_control_led_reg(led->port_num, led->led_num, ®_info);323 324 ret = regmap_read(priv->regmap, reg_info.reg, &val);325 if (ret)326 return ret;327 328 val >>= reg_info.shift;329 val &= QCA8K_LED_RULE_MASK;330 331 /* Parsing specific to netdev trigger */332 if (val & QCA8K_LED_TX_BLINK_MASK)333 set_bit(TRIGGER_NETDEV_TX, rules);334 if (val & QCA8K_LED_RX_BLINK_MASK)335 set_bit(TRIGGER_NETDEV_RX, rules);336 if (val & QCA8K_LED_LINK_10M_EN_MASK)337 set_bit(TRIGGER_NETDEV_LINK_10, rules);338 if (val & QCA8K_LED_LINK_100M_EN_MASK)339 set_bit(TRIGGER_NETDEV_LINK_100, rules);340 if (val & QCA8K_LED_LINK_1000M_EN_MASK)341 set_bit(TRIGGER_NETDEV_LINK_1000, rules);342 if (val & QCA8K_LED_HALF_DUPLEX_MASK)343 set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules);344 if (val & QCA8K_LED_FULL_DUPLEX_MASK)345 set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules);346 347 return 0;348}349 350static struct device *qca8k_cled_hw_control_get_device(struct led_classdev *ldev)351{352 struct qca8k_led *led = container_of(ldev, struct qca8k_led, cdev);353 struct qca8k_priv *priv = led->priv;354 struct dsa_port *dp;355 356 dp = dsa_to_port(priv->ds, qca8k_phy_to_port(led->port_num));357 if (!dp)358 return NULL;359 if (dp->user)360 return &dp->user->dev;361 return NULL;362}363 364static int365qca8k_parse_port_leds(struct qca8k_priv *priv, struct fwnode_handle *port, int port_num)366{367 struct fwnode_handle *led = NULL, *leds = NULL;368 struct led_init_data init_data = { };369 enum led_default_state state;370 struct qca8k_led *port_led;371 int led_num, led_index;372 int ret;373 374 leds = fwnode_get_named_child_node(port, "leds");375 if (!leds) {376 dev_dbg(priv->dev, "No Leds node specified in device tree for port %d!\n",377 port_num);378 return 0;379 }380 381 fwnode_for_each_child_node(leds, led) {382 /* Reg represent the led number of the port.383 * Each port can have at most 3 leds attached384 * Commonly:385 * 1. is gigabit led386 * 2. is mbit led387 * 3. additional status led388 */389 if (fwnode_property_read_u32(led, "reg", &led_num))390 continue;391 392 if (led_num >= QCA8K_LED_PORT_COUNT) {393 dev_warn(priv->dev, "Invalid LED reg %d defined for port %d",394 led_num, port_num);395 continue;396 }397 398 led_index = QCA8K_LED_PORT_INDEX(port_num, led_num);399 400 port_led = &priv->ports_led[led_index];401 port_led->port_num = port_num;402 port_led->led_num = led_num;403 port_led->priv = priv;404 405 state = led_init_default_state_get(led);406 switch (state) {407 case LEDS_DEFSTATE_ON:408 port_led->cdev.brightness = 1;409 qca8k_led_brightness_set(port_led, 1);410 break;411 case LEDS_DEFSTATE_KEEP:412 port_led->cdev.brightness =413 qca8k_led_brightness_get(port_led);414 break;415 default:416 port_led->cdev.brightness = 0;417 qca8k_led_brightness_set(port_led, 0);418 }419 420 port_led->cdev.max_brightness = 1;421 port_led->cdev.brightness_set_blocking = qca8k_cled_brightness_set_blocking;422 port_led->cdev.blink_set = qca8k_cled_blink_set;423 port_led->cdev.hw_control_is_supported = qca8k_cled_hw_control_is_supported;424 port_led->cdev.hw_control_set = qca8k_cled_hw_control_set;425 port_led->cdev.hw_control_get = qca8k_cled_hw_control_get;426 port_led->cdev.hw_control_get_device = qca8k_cled_hw_control_get_device;427 port_led->cdev.hw_control_trigger = "netdev";428 init_data.default_label = ":port";429 init_data.fwnode = led;430 init_data.devname_mandatory = true;431 init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d",432 priv->internal_mdio_bus->id,433 port_num);434 if (!init_data.devicename) {435 fwnode_handle_put(led);436 fwnode_handle_put(leds);437 return -ENOMEM;438 }439 440 ret = devm_led_classdev_register_ext(priv->dev, &port_led->cdev, &init_data);441 if (ret)442 dev_warn(priv->dev, "Failed to init LED %d for port %d", led_num, port_num);443 444 kfree(init_data.devicename);445 }446 447 fwnode_handle_put(leds);448 return 0;449}450 451int452qca8k_setup_led_ctrl(struct qca8k_priv *priv)453{454 struct fwnode_handle *ports, *port;455 int port_num;456 int ret;457 458 ports = device_get_named_child_node(priv->dev, "ports");459 if (!ports) {460 dev_info(priv->dev, "No ports node specified in device tree!");461 return 0;462 }463 464 fwnode_for_each_child_node(ports, port) {465 if (fwnode_property_read_u32(port, "reg", &port_num))466 continue;467 468 /* Skip checking for CPU port 0 and CPU port 6 as not supported */469 if (port_num == 0 || port_num == 6)470 continue;471 472 /* Each port can have at most 3 different leds attached.473 * Switch port starts from 0 to 6, but port 0 and 6 are CPU474 * port. The port index needs to be decreased by one to identify475 * the correct port for LED setup.476 */477 ret = qca8k_parse_port_leds(priv, port, qca8k_port_to_phy(port_num));478 if (ret) {479 fwnode_handle_put(port);480 fwnode_handle_put(ports);481 return ret;482 }483 }484 485 fwnode_handle_put(ports);486 return 0;487}488