Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'net-phy-generic-polarity-led-support-for-qca808x'

Christian Marangi says:

====================
net: phy: generic polarity + LED support for qca808x

This small series add LEDs support for qca808x.

QCA808x apply on PHY reset a strange polarity settings and require
some tweak to apply a more common configuration found on devices.
On adding support for it, it was pointed out that a similar
feature is also being implemented for a marvell PHY where
LED polarity is set per LED (and not global) and also have
a special mode where the LED is tristated.

The first 3 patch are to generalize this as we expect more PHY
in the future to have a similar configuration.

The implementation is extensible to support additional special
mode in the future with minimal changes and don't create regression
on already implemented PHY drivers.
====================

Link: https://lore.kernel.org/r/20240125203702.4552-1-ansuelsmth@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+431 -19
+12
Documentation/devicetree/bindings/leds/common.yaml
··· 200 200 #trigger-source-cells property in the source node. 201 201 $ref: /schemas/types.yaml#/definitions/phandle-array 202 202 203 + active-low: 204 + type: boolean 205 + description: 206 + Makes LED active low. To turn the LED ON, line needs to be 207 + set to low voltage instead of high. 208 + 209 + inactive-high-impedance: 210 + type: boolean 211 + description: 212 + Set LED to high-impedance mode to turn the LED OFF. LED might also 213 + describe this mode as tristate. 214 + 203 215 # Required properties for flash LED child nodes: 204 216 flash-max-microamp: 205 217 description:
-4
Documentation/devicetree/bindings/leds/leds-bcm63138.yaml
··· 52 52 maxItems: 1 53 53 description: LED pin number 54 54 55 - active-low: 56 - type: boolean 57 - description: Makes LED active low 58 - 59 55 required: 60 56 - reg 61 57
-4
Documentation/devicetree/bindings/leds/leds-bcm6328.yaml
··· 78 78 - maximum: 23 79 79 description: LED pin number (only LEDs 0 to 23 are valid). 80 80 81 - active-low: 82 - type: boolean 83 - description: Makes LED active low. 84 - 85 81 brcm,hardware-controlled: 86 82 type: boolean 87 83 description: Makes this LED hardware controlled.
-2
Documentation/devicetree/bindings/leds/leds-bcm6358.txt
··· 25 25 26 26 LED sub-node optional properties: 27 27 - label : see Documentation/devicetree/bindings/leds/common.txt 28 - - active-low : Boolean, makes LED active low. 29 - Default : false 30 28 - default-state : see 31 29 Documentation/devicetree/bindings/leds/common.txt 32 30 - linux,default-trigger : see
-4
Documentation/devicetree/bindings/leds/leds-pwm-multicolor.yaml
··· 41 41 42 42 pwm-names: true 43 43 44 - active-low: 45 - description: For PWMs where the LED is wired to supply rather than ground. 46 - type: boolean 47 - 48 44 color: true 49 45 50 46 required:
-5
Documentation/devicetree/bindings/leds/leds-pwm.yaml
··· 34 34 Maximum brightness possible for the LED 35 35 $ref: /schemas/types.yaml#/definitions/uint32 36 36 37 - active-low: 38 - description: 39 - For PWMs where the LED is wired to supply rather than ground. 40 - type: boolean 41 - 42 37 required: 43 38 - pwms 44 39 - max-brightness
+54
Documentation/devicetree/bindings/net/qca,qca808x.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/net/qca,qca808x.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Qualcomm Atheros QCA808X PHY 8 + 9 + maintainers: 10 + - Christian Marangi <ansuelsmth@gmail.com> 11 + 12 + description: 13 + QCA808X PHYs can have up to 3 LEDs attached. 14 + All 3 LEDs are disabled by default. 15 + 2 LEDs have dedicated pins with the 3rd LED having the 16 + double function of Interrupt LEDs/GPIO or additional LED. 17 + 18 + By default this special PIN is set to LED function. 19 + 20 + allOf: 21 + - $ref: ethernet-phy.yaml# 22 + 23 + properties: 24 + compatible: 25 + enum: 26 + - ethernet-phy-id004d.d101 27 + 28 + unevaluatedProperties: false 29 + 30 + examples: 31 + - | 32 + #include <dt-bindings/leds/common.h> 33 + 34 + mdio { 35 + #address-cells = <1>; 36 + #size-cells = <0>; 37 + 38 + ethernet-phy@0 { 39 + compatible = "ethernet-phy-id004d.d101"; 40 + reg = <0>; 41 + 42 + leds { 43 + #address-cells = <1>; 44 + #size-cells = <0>; 45 + 46 + led@0 { 47 + reg = <0>; 48 + color = <LED_COLOR_ID_GREEN>; 49 + function = LED_FUNCTION_WAN; 50 + default-state = "keep"; 51 + }; 52 + }; 53 + }; 54 + };
+327
drivers/net/phy/at803x.c
··· 301 301 /* Added for reference of existence but should be handled by wait_for_completion already */ 302 302 #define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3)) 303 303 304 + #define QCA808X_MMD7_LED_GLOBAL 0x8073 305 + #define QCA808X_LED_BLINK_1 GENMASK(11, 6) 306 + #define QCA808X_LED_BLINK_2 GENMASK(5, 0) 307 + /* Values are the same for both BLINK_1 and BLINK_2 */ 308 + #define QCA808X_LED_BLINK_FREQ_MASK GENMASK(5, 3) 309 + #define QCA808X_LED_BLINK_FREQ_2HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x0) 310 + #define QCA808X_LED_BLINK_FREQ_4HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x1) 311 + #define QCA808X_LED_BLINK_FREQ_8HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x2) 312 + #define QCA808X_LED_BLINK_FREQ_16HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x3) 313 + #define QCA808X_LED_BLINK_FREQ_32HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x4) 314 + #define QCA808X_LED_BLINK_FREQ_64HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x5) 315 + #define QCA808X_LED_BLINK_FREQ_128HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x6) 316 + #define QCA808X_LED_BLINK_FREQ_256HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x7) 317 + #define QCA808X_LED_BLINK_DUTY_MASK GENMASK(2, 0) 318 + #define QCA808X_LED_BLINK_DUTY_50_50 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x0) 319 + #define QCA808X_LED_BLINK_DUTY_75_25 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x1) 320 + #define QCA808X_LED_BLINK_DUTY_25_75 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x2) 321 + #define QCA808X_LED_BLINK_DUTY_33_67 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x3) 322 + #define QCA808X_LED_BLINK_DUTY_67_33 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x4) 323 + #define QCA808X_LED_BLINK_DUTY_17_83 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x5) 324 + #define QCA808X_LED_BLINK_DUTY_83_17 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x6) 325 + #define QCA808X_LED_BLINK_DUTY_8_92 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x7) 326 + 327 + #define QCA808X_MMD7_LED2_CTRL 0x8074 328 + #define QCA808X_MMD7_LED2_FORCE_CTRL 0x8075 329 + #define QCA808X_MMD7_LED1_CTRL 0x8076 330 + #define QCA808X_MMD7_LED1_FORCE_CTRL 0x8077 331 + #define QCA808X_MMD7_LED0_CTRL 0x8078 332 + #define QCA808X_MMD7_LED_CTRL(x) (0x8078 - ((x) * 2)) 333 + 334 + /* LED hw control pattern is the same for every LED */ 335 + #define QCA808X_LED_PATTERN_MASK GENMASK(15, 0) 336 + #define QCA808X_LED_SPEED2500_ON BIT(15) 337 + #define QCA808X_LED_SPEED2500_BLINK BIT(14) 338 + /* Follow blink trigger even if duplex or speed condition doesn't match */ 339 + #define QCA808X_LED_BLINK_CHECK_BYPASS BIT(13) 340 + #define QCA808X_LED_FULL_DUPLEX_ON BIT(12) 341 + #define QCA808X_LED_HALF_DUPLEX_ON BIT(11) 342 + #define QCA808X_LED_TX_BLINK BIT(10) 343 + #define QCA808X_LED_RX_BLINK BIT(9) 344 + #define QCA808X_LED_TX_ON_10MS BIT(8) 345 + #define QCA808X_LED_RX_ON_10MS BIT(7) 346 + #define QCA808X_LED_SPEED1000_ON BIT(6) 347 + #define QCA808X_LED_SPEED100_ON BIT(5) 348 + #define QCA808X_LED_SPEED10_ON BIT(4) 349 + #define QCA808X_LED_COLLISION_BLINK BIT(3) 350 + #define QCA808X_LED_SPEED1000_BLINK BIT(2) 351 + #define QCA808X_LED_SPEED100_BLINK BIT(1) 352 + #define QCA808X_LED_SPEED10_BLINK BIT(0) 353 + 354 + #define QCA808X_MMD7_LED0_FORCE_CTRL 0x8079 355 + #define QCA808X_MMD7_LED_FORCE_CTRL(x) (0x8079 - ((x) * 2)) 356 + 357 + /* LED force ctrl is the same for every LED 358 + * No documentation exist for this, not even internal one 359 + * with NDA as QCOM gives only info about configuring 360 + * hw control pattern rules and doesn't indicate any way 361 + * to force the LED to specific mode. 362 + * These define comes from reverse and testing and maybe 363 + * lack of some info or some info are not entirely correct. 364 + * For the basic LED control and hw control these finding 365 + * are enough to support LED control in all the required APIs. 366 + * 367 + * On doing some comparison with implementation with qca807x, 368 + * it was found that it's 1:1 equal to it and confirms all the 369 + * reverse done. It was also found further specification with the 370 + * force mode and the blink modes. 371 + */ 372 + #define QCA808X_LED_FORCE_EN BIT(15) 373 + #define QCA808X_LED_FORCE_MODE_MASK GENMASK(14, 13) 374 + #define QCA808X_LED_FORCE_BLINK_1 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x3) 375 + #define QCA808X_LED_FORCE_BLINK_2 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x2) 376 + #define QCA808X_LED_FORCE_ON FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x1) 377 + #define QCA808X_LED_FORCE_OFF FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x0) 378 + 379 + #define QCA808X_MMD7_LED_POLARITY_CTRL 0x901a 380 + /* QSDK sets by default 0x46 to this reg that sets BIT 6 for 381 + * LED to active high. It's not clear what BIT 3 and BIT 4 does. 382 + */ 383 + #define QCA808X_LED_ACTIVE_HIGH BIT(6) 384 + 304 385 /* QCA808X 1G chip type */ 305 386 #define QCA808X_PHY_MMD7_CHIP_TYPE 0x901d 306 387 #define QCA808X_PHY_CHIP_TYPE_1G BIT(0) ··· 427 346 struct regulator_dev *vddio_rdev; 428 347 struct regulator_dev *vddh_rdev; 429 348 u64 stats[ARRAY_SIZE(qca83xx_hw_stats)]; 349 + int led_polarity_mode; 430 350 }; 431 351 432 352 struct at803x_context { ··· 787 705 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 788 706 if (!priv) 789 707 return -ENOMEM; 708 + 709 + /* Init LED polarity mode to -1 */ 710 + priv->led_polarity_mode = -1; 790 711 791 712 phydev->priv = priv; 792 713 ··· 2320 2235 phydev->link ? QCA8081_PHY_FIFO_RSTN : 0); 2321 2236 } 2322 2237 2238 + static int qca808x_led_parse_netdev(struct phy_device *phydev, unsigned long rules, 2239 + u16 *offload_trigger) 2240 + { 2241 + /* Parsing specific to netdev trigger */ 2242 + if (test_bit(TRIGGER_NETDEV_TX, &rules)) 2243 + *offload_trigger |= QCA808X_LED_TX_BLINK; 2244 + if (test_bit(TRIGGER_NETDEV_RX, &rules)) 2245 + *offload_trigger |= QCA808X_LED_RX_BLINK; 2246 + if (test_bit(TRIGGER_NETDEV_LINK_10, &rules)) 2247 + *offload_trigger |= QCA808X_LED_SPEED10_ON; 2248 + if (test_bit(TRIGGER_NETDEV_LINK_100, &rules)) 2249 + *offload_trigger |= QCA808X_LED_SPEED100_ON; 2250 + if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules)) 2251 + *offload_trigger |= QCA808X_LED_SPEED1000_ON; 2252 + if (test_bit(TRIGGER_NETDEV_LINK_2500, &rules)) 2253 + *offload_trigger |= QCA808X_LED_SPEED2500_ON; 2254 + if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules)) 2255 + *offload_trigger |= QCA808X_LED_HALF_DUPLEX_ON; 2256 + if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules)) 2257 + *offload_trigger |= QCA808X_LED_FULL_DUPLEX_ON; 2258 + 2259 + if (rules && !*offload_trigger) 2260 + return -EOPNOTSUPP; 2261 + 2262 + /* Enable BLINK_CHECK_BYPASS by default to make the LED 2263 + * blink even with duplex or speed mode not enabled. 2264 + */ 2265 + *offload_trigger |= QCA808X_LED_BLINK_CHECK_BYPASS; 2266 + 2267 + return 0; 2268 + } 2269 + 2270 + static int qca808x_led_hw_control_enable(struct phy_device *phydev, u8 index) 2271 + { 2272 + u16 reg; 2273 + 2274 + if (index > 2) 2275 + return -EINVAL; 2276 + 2277 + reg = QCA808X_MMD7_LED_FORCE_CTRL(index); 2278 + 2279 + return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg, 2280 + QCA808X_LED_FORCE_EN); 2281 + } 2282 + 2283 + static int qca808x_led_hw_is_supported(struct phy_device *phydev, u8 index, 2284 + unsigned long rules) 2285 + { 2286 + u16 offload_trigger = 0; 2287 + 2288 + if (index > 2) 2289 + return -EINVAL; 2290 + 2291 + return qca808x_led_parse_netdev(phydev, rules, &offload_trigger); 2292 + } 2293 + 2294 + static int qca808x_led_hw_control_set(struct phy_device *phydev, u8 index, 2295 + unsigned long rules) 2296 + { 2297 + u16 reg, offload_trigger = 0; 2298 + int ret; 2299 + 2300 + if (index > 2) 2301 + return -EINVAL; 2302 + 2303 + reg = QCA808X_MMD7_LED_CTRL(index); 2304 + 2305 + ret = qca808x_led_parse_netdev(phydev, rules, &offload_trigger); 2306 + if (ret) 2307 + return ret; 2308 + 2309 + ret = qca808x_led_hw_control_enable(phydev, index); 2310 + if (ret) 2311 + return ret; 2312 + 2313 + return phy_modify_mmd(phydev, MDIO_MMD_AN, reg, 2314 + QCA808X_LED_PATTERN_MASK, 2315 + offload_trigger); 2316 + } 2317 + 2318 + static bool qca808x_led_hw_control_status(struct phy_device *phydev, u8 index) 2319 + { 2320 + u16 reg; 2321 + int val; 2322 + 2323 + if (index > 2) 2324 + return false; 2325 + 2326 + reg = QCA808X_MMD7_LED_FORCE_CTRL(index); 2327 + 2328 + val = phy_read_mmd(phydev, MDIO_MMD_AN, reg); 2329 + 2330 + return !(val & QCA808X_LED_FORCE_EN); 2331 + } 2332 + 2333 + static int qca808x_led_hw_control_get(struct phy_device *phydev, u8 index, 2334 + unsigned long *rules) 2335 + { 2336 + u16 reg; 2337 + int val; 2338 + 2339 + if (index > 2) 2340 + return -EINVAL; 2341 + 2342 + /* Check if we have hw control enabled */ 2343 + if (qca808x_led_hw_control_status(phydev, index)) 2344 + return -EINVAL; 2345 + 2346 + reg = QCA808X_MMD7_LED_CTRL(index); 2347 + 2348 + val = phy_read_mmd(phydev, MDIO_MMD_AN, reg); 2349 + if (val & QCA808X_LED_TX_BLINK) 2350 + set_bit(TRIGGER_NETDEV_TX, rules); 2351 + if (val & QCA808X_LED_RX_BLINK) 2352 + set_bit(TRIGGER_NETDEV_RX, rules); 2353 + if (val & QCA808X_LED_SPEED10_ON) 2354 + set_bit(TRIGGER_NETDEV_LINK_10, rules); 2355 + if (val & QCA808X_LED_SPEED100_ON) 2356 + set_bit(TRIGGER_NETDEV_LINK_100, rules); 2357 + if (val & QCA808X_LED_SPEED1000_ON) 2358 + set_bit(TRIGGER_NETDEV_LINK_1000, rules); 2359 + if (val & QCA808X_LED_SPEED2500_ON) 2360 + set_bit(TRIGGER_NETDEV_LINK_2500, rules); 2361 + if (val & QCA808X_LED_HALF_DUPLEX_ON) 2362 + set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules); 2363 + if (val & QCA808X_LED_FULL_DUPLEX_ON) 2364 + set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules); 2365 + 2366 + return 0; 2367 + } 2368 + 2369 + static int qca808x_led_hw_control_reset(struct phy_device *phydev, u8 index) 2370 + { 2371 + u16 reg; 2372 + 2373 + if (index > 2) 2374 + return -EINVAL; 2375 + 2376 + reg = QCA808X_MMD7_LED_CTRL(index); 2377 + 2378 + return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg, 2379 + QCA808X_LED_PATTERN_MASK); 2380 + } 2381 + 2382 + static int qca808x_led_brightness_set(struct phy_device *phydev, 2383 + u8 index, enum led_brightness value) 2384 + { 2385 + u16 reg; 2386 + int ret; 2387 + 2388 + if (index > 2) 2389 + return -EINVAL; 2390 + 2391 + if (!value) { 2392 + ret = qca808x_led_hw_control_reset(phydev, index); 2393 + if (ret) 2394 + return ret; 2395 + } 2396 + 2397 + reg = QCA808X_MMD7_LED_FORCE_CTRL(index); 2398 + 2399 + return phy_modify_mmd(phydev, MDIO_MMD_AN, reg, 2400 + QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK, 2401 + QCA808X_LED_FORCE_EN | value ? QCA808X_LED_FORCE_ON : 2402 + QCA808X_LED_FORCE_OFF); 2403 + } 2404 + 2405 + static int qca808x_led_blink_set(struct phy_device *phydev, u8 index, 2406 + unsigned long *delay_on, 2407 + unsigned long *delay_off) 2408 + { 2409 + int ret; 2410 + u16 reg; 2411 + 2412 + if (index > 2) 2413 + return -EINVAL; 2414 + 2415 + reg = QCA808X_MMD7_LED_FORCE_CTRL(index); 2416 + 2417 + /* Set blink to 50% off, 50% on at 4Hz by default */ 2418 + ret = phy_modify_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_LED_GLOBAL, 2419 + QCA808X_LED_BLINK_FREQ_MASK | QCA808X_LED_BLINK_DUTY_MASK, 2420 + QCA808X_LED_BLINK_FREQ_4HZ | QCA808X_LED_BLINK_DUTY_50_50); 2421 + if (ret) 2422 + return ret; 2423 + 2424 + /* We use BLINK_1 for normal blinking */ 2425 + ret = phy_modify_mmd(phydev, MDIO_MMD_AN, reg, 2426 + QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK, 2427 + QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_BLINK_1); 2428 + if (ret) 2429 + return ret; 2430 + 2431 + /* We set blink to 4Hz, aka 250ms */ 2432 + *delay_on = 250 / 2; 2433 + *delay_off = 250 / 2; 2434 + 2435 + return 0; 2436 + } 2437 + 2438 + static int qca808x_led_polarity_set(struct phy_device *phydev, int index, 2439 + unsigned long modes) 2440 + { 2441 + struct at803x_priv *priv = phydev->priv; 2442 + bool active_low = false; 2443 + u32 mode; 2444 + 2445 + for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) { 2446 + switch (mode) { 2447 + case PHY_LED_ACTIVE_LOW: 2448 + active_low = true; 2449 + break; 2450 + default: 2451 + return -EINVAL; 2452 + } 2453 + } 2454 + 2455 + /* PHY polarity is global and can't be set per LED. 2456 + * To detect this, check if last requested polarity mode 2457 + * match the new one. 2458 + */ 2459 + if (priv->led_polarity_mode >= 0 && 2460 + priv->led_polarity_mode != active_low) { 2461 + phydev_err(phydev, "PHY polarity is global. Mismatched polarity on different LED\n"); 2462 + return -EINVAL; 2463 + } 2464 + 2465 + /* Save the last PHY polarity mode */ 2466 + priv->led_polarity_mode = active_low; 2467 + 2468 + return phy_modify_mmd(phydev, MDIO_MMD_AN, 2469 + QCA808X_MMD7_LED_POLARITY_CTRL, 2470 + QCA808X_LED_ACTIVE_HIGH, 2471 + active_low ? 0 : QCA808X_LED_ACTIVE_HIGH); 2472 + } 2473 + 2323 2474 static struct phy_driver at803x_driver[] = { 2324 2475 { 2325 2476 /* Qualcomm Atheros AR8035 */ ··· 2732 2411 .cable_test_start = qca808x_cable_test_start, 2733 2412 .cable_test_get_status = qca808x_cable_test_get_status, 2734 2413 .link_change_notify = qca808x_link_change_notify, 2414 + .led_brightness_set = qca808x_led_brightness_set, 2415 + .led_blink_set = qca808x_led_blink_set, 2416 + .led_hw_is_supported = qca808x_led_hw_is_supported, 2417 + .led_hw_control_set = qca808x_led_hw_control_set, 2418 + .led_hw_control_get = qca808x_led_hw_control_get, 2419 + .led_polarity_set = qca808x_led_polarity_set, 2735 2420 }, }; 2736 2421 2737 2422 module_phy_driver(at803x_driver);
+16
drivers/net/phy/phy_device.c
··· 3097 3097 struct device *dev = &phydev->mdio.dev; 3098 3098 struct led_init_data init_data = {}; 3099 3099 struct led_classdev *cdev; 3100 + unsigned long modes = 0; 3100 3101 struct phy_led *phyled; 3101 3102 u32 index; 3102 3103 int err; ··· 3114 3113 return err; 3115 3114 if (index > U8_MAX) 3116 3115 return -EINVAL; 3116 + 3117 + if (of_property_read_bool(led, "active-low")) 3118 + set_bit(PHY_LED_ACTIVE_LOW, &modes); 3119 + if (of_property_read_bool(led, "inactive-high-impedance")) 3120 + set_bit(PHY_LED_INACTIVE_HIGH_IMPEDANCE, &modes); 3121 + 3122 + if (modes) { 3123 + /* Return error if asked to set polarity modes but not supported */ 3124 + if (!phydev->drv->led_polarity_set) 3125 + return -EINVAL; 3126 + 3127 + err = phydev->drv->led_polarity_set(phydev, index, modes); 3128 + if (err) 3129 + return err; 3130 + } 3117 3131 3118 3132 phyled->index = index; 3119 3133 if (phydev->drv->led_brightness_set)
+22
include/linux/phy.h
··· 852 852 bool pst; 853 853 }; 854 854 855 + /* Modes for PHY LED configuration */ 856 + enum phy_led_modes { 857 + PHY_LED_ACTIVE_LOW = 0, 858 + PHY_LED_INACTIVE_HIGH_IMPEDANCE = 1, 859 + 860 + /* keep it last */ 861 + __PHY_LED_MODES_NUM, 862 + }; 863 + 855 864 /** 856 865 * struct phy_led: An LED driven by the PHY 857 866 * ··· 1154 1145 int (*led_hw_control_get)(struct phy_device *dev, u8 index, 1155 1146 unsigned long *rules); 1156 1147 1148 + /** 1149 + * @led_polarity_set: Set the LED polarity modes 1150 + * @dev: PHY device which has the LED 1151 + * @index: Which LED of the PHY device 1152 + * @modes: bitmap of LED polarity modes 1153 + * 1154 + * Configure LED with all the required polarity modes in @modes 1155 + * to make it correctly turn ON or OFF. 1156 + * 1157 + * Returns 0, or an error code. 1158 + */ 1159 + int (*led_polarity_set)(struct phy_device *dev, int index, 1160 + unsigned long modes); 1157 1161 }; 1158 1162 #define to_phy_driver(d) container_of(to_mdio_common_driver(d), \ 1159 1163 struct phy_driver, mdiodrv)