brintos

brintos / linux-shallow public Read only

0
0
Text · 13.1 KiB · 43ac680 Raw
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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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, &reg_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