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.

phy: add phy_get_rx_polarity() and phy_get_tx_polarity()

Add helpers in the generic PHY folder which can be used using 'select
PHY_COMMON_PROPS' from Kconfig, without otherwise needing to
enable GENERIC_PHY.

These helpers need to deal with the slight messiness of the fact that
the polarity properties are arrays per protocol, and with the fact that
there is no default value mandated by the standard properties, all
default values depend on driver and protocol (PHY_POL_NORMAL may be a
good default for SGMII, whereas PHY_POL_AUTO may be a good default for
PCIe).

Push the supported mask of polarities to these helpers, to simplify
drivers such that they don't need to validate what's in the device tree
(or other firmware description).

Add a KUnit test suite to make sure that the API produces the expected
results. The fact that we use fwnode structures means we can validate
with software nodes, and as opposed to the device_property API, we can
bypass the need to have a device structure.

Co-developed-by: Bjørn Mork <bjorn@mork.no>
Signed-off-by: Bjørn Mork <bjorn@mork.no>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Link: https://patch.msgid.link/20260111093940.975359-6-vladimir.oltean@nxp.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Vladimir Oltean and committed by
Vinod Koul
e7556b59 fceb17ac

+697
+10
MAINTAINERS
··· 20515 20515 S: Maintained 20516 20516 F: drivers/mtd/devices/phram.c 20517 20517 20518 + PHY COMMON PROPERTIES 20519 + M: Vladimir Oltean <vladimir.oltean@nxp.com> 20520 + L: netdev@vger.kernel.org 20521 + S: Maintained 20522 + Q: https://patchwork.kernel.org/project/netdevbpf/list/ 20523 + F: Documentation/devicetree/bindings/phy/phy-common-props.yaml 20524 + F: drivers/phy/phy-common-props-test.c 20525 + F: drivers/phy/phy-common-props.c 20526 + F: include/linux/phy/phy-common-props.h 20527 + 20518 20528 PICOLCD HID DRIVER 20519 20529 M: Bruno Prémont <bonbons@linux-vserver.org> 20520 20530 L: linux-input@vger.kernel.org
+22
drivers/phy/Kconfig
··· 5 5 6 6 menu "PHY Subsystem" 7 7 8 + config PHY_COMMON_PROPS 9 + bool 10 + help 11 + This parses properties common between generic PHYs and Ethernet PHYs. 12 + 13 + Select this from consumer drivers to gain access to helpers for 14 + parsing properties from the 15 + Documentation/devicetree/bindings/phy/phy-common-props.yaml schema. 16 + 17 + config PHY_COMMON_PROPS_TEST 18 + tristate "KUnit tests for PHY common props" if !KUNIT_ALL_TESTS 19 + select PHY_COMMON_PROPS 20 + depends on KUNIT 21 + default KUNIT_ALL_TESTS 22 + help 23 + This builds KUnit tests for the PHY common property API. 24 + 25 + For more information on KUnit and unit tests in general, 26 + please refer to the KUnit documentation in Documentation/dev-tools/kunit/. 27 + 28 + When in doubt, say N. 29 + 8 30 config GENERIC_PHY 9 31 bool "PHY Core" 10 32 help
+2
drivers/phy/Makefile
··· 3 3 # Makefile for the phy drivers. 4 4 # 5 5 6 + obj-$(CONFIG_PHY_COMMON_PROPS) += phy-common-props.o 7 + obj-$(CONFIG_PHY_COMMON_PROPS_TEST) += phy-common-props-test.o 6 8 obj-$(CONFIG_GENERIC_PHY) += phy-core.o 7 9 obj-$(CONFIG_GENERIC_PHY_MIPI_DPHY) += phy-core-mipi-dphy.o 8 10 obj-$(CONFIG_PHY_CAN_TRANSCEIVER) += phy-can-transceiver.o
+422
drivers/phy/phy-common-props-test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * phy-common-props-test.c -- Unit tests for PHY common properties API 4 + * 5 + * Copyright 2025-2026 NXP 6 + */ 7 + #include <kunit/test.h> 8 + #include <linux/property.h> 9 + #include <linux/phy/phy-common-props.h> 10 + #include <dt-bindings/phy/phy.h> 11 + 12 + /* Test: rx-polarity property is missing */ 13 + static void phy_test_rx_polarity_is_missing(struct kunit *test) 14 + { 15 + static const struct property_entry entries[] = { 16 + {} 17 + }; 18 + struct fwnode_handle *node; 19 + unsigned int val; 20 + int ret; 21 + 22 + node = fwnode_create_software_node(entries, NULL); 23 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 24 + 25 + ret = phy_get_manual_rx_polarity(node, "sgmii", &val); 26 + KUNIT_EXPECT_EQ(test, ret, 0); 27 + KUNIT_EXPECT_EQ(test, val, PHY_POL_NORMAL); 28 + 29 + fwnode_remove_software_node(node); 30 + } 31 + 32 + /* Test: rx-polarity has more values than rx-polarity-names */ 33 + static void phy_test_rx_polarity_more_values_than_names(struct kunit *test) 34 + { 35 + static const u32 rx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT, PHY_POL_NORMAL }; 36 + static const char * const rx_pol_names[] = { "sgmii", "2500base-x" }; 37 + static const struct property_entry entries[] = { 38 + PROPERTY_ENTRY_U32_ARRAY("rx-polarity", rx_pol), 39 + PROPERTY_ENTRY_STRING_ARRAY("rx-polarity-names", rx_pol_names), 40 + {} 41 + }; 42 + struct fwnode_handle *node; 43 + unsigned int val; 44 + int ret; 45 + 46 + node = fwnode_create_software_node(entries, NULL); 47 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 48 + 49 + ret = phy_get_manual_rx_polarity(node, "sgmii", &val); 50 + KUNIT_EXPECT_EQ(test, ret, -EINVAL); 51 + 52 + fwnode_remove_software_node(node); 53 + } 54 + 55 + /* Test: rx-polarity has 1 value and rx-polarity-names does not exist */ 56 + static void phy_test_rx_polarity_single_value_no_names(struct kunit *test) 57 + { 58 + static const u32 rx_pol[] = { PHY_POL_INVERT }; 59 + static const struct property_entry entries[] = { 60 + PROPERTY_ENTRY_U32_ARRAY("rx-polarity", rx_pol), 61 + {} 62 + }; 63 + struct fwnode_handle *node; 64 + unsigned int val; 65 + int ret; 66 + 67 + node = fwnode_create_software_node(entries, NULL); 68 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 69 + 70 + ret = phy_get_manual_rx_polarity(node, "sgmii", &val); 71 + KUNIT_EXPECT_EQ(test, ret, 0); 72 + KUNIT_EXPECT_EQ(test, val, PHY_POL_INVERT); 73 + 74 + fwnode_remove_software_node(node); 75 + } 76 + 77 + /* Test: rx-polarity-names has more values than rx-polarity */ 78 + static void phy_test_rx_polarity_more_names_than_values(struct kunit *test) 79 + { 80 + static const u32 rx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT }; 81 + static const char * const rx_pol_names[] = { "sgmii", "2500base-x", "1000base-x" }; 82 + static const struct property_entry entries[] = { 83 + PROPERTY_ENTRY_U32_ARRAY("rx-polarity", rx_pol), 84 + PROPERTY_ENTRY_STRING_ARRAY("rx-polarity-names", rx_pol_names), 85 + {} 86 + }; 87 + struct fwnode_handle *node; 88 + unsigned int val; 89 + int ret; 90 + 91 + node = fwnode_create_software_node(entries, NULL); 92 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 93 + 94 + ret = phy_get_manual_rx_polarity(node, "sgmii", &val); 95 + KUNIT_EXPECT_EQ(test, ret, -EINVAL); 96 + 97 + fwnode_remove_software_node(node); 98 + } 99 + 100 + /* Test: rx-polarity and rx-polarity-names have same length, find the name */ 101 + static void phy_test_rx_polarity_find_by_name(struct kunit *test) 102 + { 103 + static const u32 rx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT, PHY_POL_AUTO }; 104 + static const char * const rx_pol_names[] = { "sgmii", "2500base-x", "usb-ss" }; 105 + static const struct property_entry entries[] = { 106 + PROPERTY_ENTRY_U32_ARRAY("rx-polarity", rx_pol), 107 + PROPERTY_ENTRY_STRING_ARRAY("rx-polarity-names", rx_pol_names), 108 + {} 109 + }; 110 + struct fwnode_handle *node; 111 + unsigned int val; 112 + int ret; 113 + 114 + node = fwnode_create_software_node(entries, NULL); 115 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 116 + 117 + ret = phy_get_manual_rx_polarity(node, "sgmii", &val); 118 + KUNIT_EXPECT_EQ(test, ret, 0); 119 + KUNIT_EXPECT_EQ(test, val, PHY_POL_NORMAL); 120 + 121 + ret = phy_get_manual_rx_polarity(node, "2500base-x", &val); 122 + KUNIT_EXPECT_EQ(test, ret, 0); 123 + KUNIT_EXPECT_EQ(test, val, PHY_POL_INVERT); 124 + 125 + ret = phy_get_rx_polarity(node, "usb-ss", BIT(PHY_POL_AUTO), 126 + PHY_POL_AUTO, &val); 127 + KUNIT_EXPECT_EQ(test, ret, 0); 128 + KUNIT_EXPECT_EQ(test, val, PHY_POL_AUTO); 129 + 130 + fwnode_remove_software_node(node); 131 + } 132 + 133 + /* Test: same length, name not found, no "default" - error */ 134 + static void phy_test_rx_polarity_name_not_found_no_default(struct kunit *test) 135 + { 136 + static const u32 rx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT }; 137 + static const char * const rx_pol_names[] = { "2500base-x", "1000base-x" }; 138 + static const struct property_entry entries[] = { 139 + PROPERTY_ENTRY_U32_ARRAY("rx-polarity", rx_pol), 140 + PROPERTY_ENTRY_STRING_ARRAY("rx-polarity-names", rx_pol_names), 141 + {} 142 + }; 143 + struct fwnode_handle *node; 144 + unsigned int val; 145 + int ret; 146 + 147 + node = fwnode_create_software_node(entries, NULL); 148 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 149 + 150 + ret = phy_get_manual_rx_polarity(node, "sgmii", &val); 151 + KUNIT_EXPECT_EQ(test, ret, -EINVAL); 152 + 153 + fwnode_remove_software_node(node); 154 + } 155 + 156 + /* Test: same length, name not found, but "default" exists */ 157 + static void phy_test_rx_polarity_name_not_found_with_default(struct kunit *test) 158 + { 159 + static const u32 rx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT }; 160 + static const char * const rx_pol_names[] = { "2500base-x", "default" }; 161 + static const struct property_entry entries[] = { 162 + PROPERTY_ENTRY_U32_ARRAY("rx-polarity", rx_pol), 163 + PROPERTY_ENTRY_STRING_ARRAY("rx-polarity-names", rx_pol_names), 164 + {} 165 + }; 166 + struct fwnode_handle *node; 167 + unsigned int val; 168 + int ret; 169 + 170 + node = fwnode_create_software_node(entries, NULL); 171 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 172 + 173 + ret = phy_get_manual_rx_polarity(node, "sgmii", &val); 174 + KUNIT_EXPECT_EQ(test, ret, 0); 175 + KUNIT_EXPECT_EQ(test, val, PHY_POL_INVERT); 176 + 177 + fwnode_remove_software_node(node); 178 + } 179 + 180 + /* Test: polarity found but value is unsupported */ 181 + static void phy_test_rx_polarity_unsupported_value(struct kunit *test) 182 + { 183 + static const u32 rx_pol[] = { PHY_POL_AUTO }; 184 + static const char * const rx_pol_names[] = { "sgmii" }; 185 + static const struct property_entry entries[] = { 186 + PROPERTY_ENTRY_U32_ARRAY("rx-polarity", rx_pol), 187 + PROPERTY_ENTRY_STRING_ARRAY("rx-polarity-names", rx_pol_names), 188 + {} 189 + }; 190 + struct fwnode_handle *node; 191 + unsigned int val; 192 + int ret; 193 + 194 + node = fwnode_create_software_node(entries, NULL); 195 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 196 + 197 + ret = phy_get_manual_rx_polarity(node, "sgmii", &val); 198 + KUNIT_EXPECT_EQ(test, ret, -EOPNOTSUPP); 199 + 200 + fwnode_remove_software_node(node); 201 + } 202 + 203 + /* Test: tx-polarity property is missing */ 204 + static void phy_test_tx_polarity_is_missing(struct kunit *test) 205 + { 206 + static const struct property_entry entries[] = { 207 + {} 208 + }; 209 + struct fwnode_handle *node; 210 + unsigned int val; 211 + int ret; 212 + 213 + node = fwnode_create_software_node(entries, NULL); 214 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 215 + 216 + ret = phy_get_manual_tx_polarity(node, "sgmii", &val); 217 + KUNIT_EXPECT_EQ(test, ret, 0); 218 + KUNIT_EXPECT_EQ(test, val, PHY_POL_NORMAL); 219 + 220 + fwnode_remove_software_node(node); 221 + } 222 + 223 + /* Test: tx-polarity has more values than tx-polarity-names */ 224 + static void phy_test_tx_polarity_more_values_than_names(struct kunit *test) 225 + { 226 + static const u32 tx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT, PHY_POL_NORMAL }; 227 + static const char * const tx_pol_names[] = { "sgmii", "2500base-x" }; 228 + static const struct property_entry entries[] = { 229 + PROPERTY_ENTRY_U32_ARRAY("tx-polarity", tx_pol), 230 + PROPERTY_ENTRY_STRING_ARRAY("tx-polarity-names", tx_pol_names), 231 + {} 232 + }; 233 + struct fwnode_handle *node; 234 + unsigned int val; 235 + int ret; 236 + 237 + node = fwnode_create_software_node(entries, NULL); 238 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 239 + 240 + ret = phy_get_manual_tx_polarity(node, "sgmii", &val); 241 + KUNIT_EXPECT_EQ(test, ret, -EINVAL); 242 + 243 + fwnode_remove_software_node(node); 244 + } 245 + 246 + /* Test: tx-polarity has 1 value and tx-polarity-names does not exist */ 247 + static void phy_test_tx_polarity_single_value_no_names(struct kunit *test) 248 + { 249 + static const u32 tx_pol[] = { PHY_POL_INVERT }; 250 + static const struct property_entry entries[] = { 251 + PROPERTY_ENTRY_U32_ARRAY("tx-polarity", tx_pol), 252 + {} 253 + }; 254 + struct fwnode_handle *node; 255 + unsigned int val; 256 + int ret; 257 + 258 + node = fwnode_create_software_node(entries, NULL); 259 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 260 + 261 + ret = phy_get_manual_tx_polarity(node, "sgmii", &val); 262 + KUNIT_EXPECT_EQ(test, ret, 0); 263 + KUNIT_EXPECT_EQ(test, val, PHY_POL_INVERT); 264 + 265 + fwnode_remove_software_node(node); 266 + } 267 + 268 + /* Test: tx-polarity-names has more values than tx-polarity */ 269 + static void phy_test_tx_polarity_more_names_than_values(struct kunit *test) 270 + { 271 + static const u32 tx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT }; 272 + static const char * const tx_pol_names[] = { "sgmii", "2500base-x", "1000base-x" }; 273 + static const struct property_entry entries[] = { 274 + PROPERTY_ENTRY_U32_ARRAY("tx-polarity", tx_pol), 275 + PROPERTY_ENTRY_STRING_ARRAY("tx-polarity-names", tx_pol_names), 276 + {} 277 + }; 278 + struct fwnode_handle *node; 279 + unsigned int val; 280 + int ret; 281 + 282 + node = fwnode_create_software_node(entries, NULL); 283 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 284 + 285 + ret = phy_get_manual_tx_polarity(node, "sgmii", &val); 286 + KUNIT_EXPECT_EQ(test, ret, -EINVAL); 287 + 288 + fwnode_remove_software_node(node); 289 + } 290 + 291 + /* Test: tx-polarity and tx-polarity-names have same length, find the name */ 292 + static void phy_test_tx_polarity_find_by_name(struct kunit *test) 293 + { 294 + static const u32 tx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT, PHY_POL_NORMAL }; 295 + static const char * const tx_pol_names[] = { "sgmii", "2500base-x", "1000base-x" }; 296 + static const struct property_entry entries[] = { 297 + PROPERTY_ENTRY_U32_ARRAY("tx-polarity", tx_pol), 298 + PROPERTY_ENTRY_STRING_ARRAY("tx-polarity-names", tx_pol_names), 299 + {} 300 + }; 301 + struct fwnode_handle *node; 302 + unsigned int val; 303 + int ret; 304 + 305 + node = fwnode_create_software_node(entries, NULL); 306 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 307 + 308 + ret = phy_get_manual_tx_polarity(node, "sgmii", &val); 309 + KUNIT_EXPECT_EQ(test, ret, 0); 310 + KUNIT_EXPECT_EQ(test, val, PHY_POL_NORMAL); 311 + 312 + ret = phy_get_manual_tx_polarity(node, "2500base-x", &val); 313 + KUNIT_EXPECT_EQ(test, ret, 0); 314 + KUNIT_EXPECT_EQ(test, val, PHY_POL_INVERT); 315 + 316 + ret = phy_get_manual_tx_polarity(node, "1000base-x", &val); 317 + KUNIT_EXPECT_EQ(test, ret, 0); 318 + KUNIT_EXPECT_EQ(test, val, PHY_POL_NORMAL); 319 + 320 + fwnode_remove_software_node(node); 321 + } 322 + 323 + /* Test: same length, name not found, no "default" - error */ 324 + static void phy_test_tx_polarity_name_not_found_no_default(struct kunit *test) 325 + { 326 + static const u32 tx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT }; 327 + static const char * const tx_pol_names[] = { "2500base-x", "1000base-x" }; 328 + static const struct property_entry entries[] = { 329 + PROPERTY_ENTRY_U32_ARRAY("tx-polarity", tx_pol), 330 + PROPERTY_ENTRY_STRING_ARRAY("tx-polarity-names", tx_pol_names), 331 + {} 332 + }; 333 + struct fwnode_handle *node; 334 + unsigned int val; 335 + int ret; 336 + 337 + node = fwnode_create_software_node(entries, NULL); 338 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 339 + 340 + ret = phy_get_manual_tx_polarity(node, "sgmii", &val); 341 + KUNIT_EXPECT_EQ(test, ret, -EINVAL); 342 + 343 + fwnode_remove_software_node(node); 344 + } 345 + 346 + /* Test: same length, name not found, but "default" exists */ 347 + static void phy_test_tx_polarity_name_not_found_with_default(struct kunit *test) 348 + { 349 + static const u32 tx_pol[] = { PHY_POL_NORMAL, PHY_POL_INVERT }; 350 + static const char * const tx_pol_names[] = { "2500base-x", "default" }; 351 + static const struct property_entry entries[] = { 352 + PROPERTY_ENTRY_U32_ARRAY("tx-polarity", tx_pol), 353 + PROPERTY_ENTRY_STRING_ARRAY("tx-polarity-names", tx_pol_names), 354 + {} 355 + }; 356 + struct fwnode_handle *node; 357 + unsigned int val; 358 + int ret; 359 + 360 + node = fwnode_create_software_node(entries, NULL); 361 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 362 + 363 + ret = phy_get_manual_tx_polarity(node, "sgmii", &val); 364 + KUNIT_EXPECT_EQ(test, ret, 0); 365 + KUNIT_EXPECT_EQ(test, val, PHY_POL_INVERT); 366 + 367 + fwnode_remove_software_node(node); 368 + } 369 + 370 + /* Test: polarity found but value is unsupported (AUTO for TX) */ 371 + static void phy_test_tx_polarity_unsupported_value(struct kunit *test) 372 + { 373 + static const u32 tx_pol[] = { PHY_POL_AUTO }; 374 + static const char * const tx_pol_names[] = { "sgmii" }; 375 + static const struct property_entry entries[] = { 376 + PROPERTY_ENTRY_U32_ARRAY("tx-polarity", tx_pol), 377 + PROPERTY_ENTRY_STRING_ARRAY("tx-polarity-names", tx_pol_names), 378 + {} 379 + }; 380 + struct fwnode_handle *node; 381 + unsigned int val; 382 + int ret; 383 + 384 + node = fwnode_create_software_node(entries, NULL); 385 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node); 386 + 387 + ret = phy_get_manual_tx_polarity(node, "sgmii", &val); 388 + KUNIT_EXPECT_EQ(test, ret, -EOPNOTSUPP); 389 + 390 + fwnode_remove_software_node(node); 391 + } 392 + 393 + static struct kunit_case phy_common_props_test_cases[] = { 394 + KUNIT_CASE(phy_test_rx_polarity_is_missing), 395 + KUNIT_CASE(phy_test_rx_polarity_more_values_than_names), 396 + KUNIT_CASE(phy_test_rx_polarity_single_value_no_names), 397 + KUNIT_CASE(phy_test_rx_polarity_more_names_than_values), 398 + KUNIT_CASE(phy_test_rx_polarity_find_by_name), 399 + KUNIT_CASE(phy_test_rx_polarity_name_not_found_no_default), 400 + KUNIT_CASE(phy_test_rx_polarity_name_not_found_with_default), 401 + KUNIT_CASE(phy_test_rx_polarity_unsupported_value), 402 + KUNIT_CASE(phy_test_tx_polarity_is_missing), 403 + KUNIT_CASE(phy_test_tx_polarity_more_values_than_names), 404 + KUNIT_CASE(phy_test_tx_polarity_single_value_no_names), 405 + KUNIT_CASE(phy_test_tx_polarity_more_names_than_values), 406 + KUNIT_CASE(phy_test_tx_polarity_find_by_name), 407 + KUNIT_CASE(phy_test_tx_polarity_name_not_found_no_default), 408 + KUNIT_CASE(phy_test_tx_polarity_name_not_found_with_default), 409 + KUNIT_CASE(phy_test_tx_polarity_unsupported_value), 410 + {} 411 + }; 412 + 413 + static struct kunit_suite phy_common_props_test_suite = { 414 + .name = "phy-common-props", 415 + .test_cases = phy_common_props_test_cases, 416 + }; 417 + 418 + kunit_test_suite(phy_common_props_test_suite); 419 + 420 + MODULE_DESCRIPTION("Test module for PHY common properties API"); 421 + MODULE_AUTHOR("Vladimir Oltean <vladimir.oltean@nxp.com>"); 422 + MODULE_LICENSE("GPL");
+209
drivers/phy/phy-common-props.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * phy-common-props.c -- Common PHY properties 4 + * 5 + * Copyright 2025-2026 NXP 6 + */ 7 + #include <linux/export.h> 8 + #include <linux/fwnode.h> 9 + #include <linux/phy/phy-common-props.h> 10 + #include <linux/printk.h> 11 + #include <linux/property.h> 12 + #include <linux/slab.h> 13 + 14 + /** 15 + * fwnode_get_u32_prop_for_name - Find u32 property by name, or default value 16 + * @fwnode: Pointer to firmware node, or NULL to use @default_val 17 + * @name: Property name used as lookup key in @names_title (must not be NULL) 18 + * @props_title: Name of u32 array property holding values 19 + * @names_title: Name of string array property holding lookup keys 20 + * @default_val: Default value if @fwnode is NULL or @props_title is empty 21 + * @val: Pointer to store the returned value 22 + * 23 + * This function retrieves a u32 value from @props_title based on a name lookup 24 + * in @names_title. The value stored in @val is determined as follows: 25 + * 26 + * - If @fwnode is NULL or @props_title is empty: @default_val is used 27 + * - If @props_title has exactly one element and @names_title is empty: 28 + * that element is used 29 + * - Otherwise: @val is set to the element at the same index where @name is 30 + * found in @names_title. 31 + * - If @name is not found, the function looks for a "default" entry in 32 + * @names_title and uses the corresponding value from @props_title 33 + * 34 + * When both @props_title and @names_title are present, they must have the 35 + * same number of elements (except when @props_title has exactly one element). 36 + * 37 + * Return: zero on success, negative error on failure. 38 + */ 39 + static int fwnode_get_u32_prop_for_name(struct fwnode_handle *fwnode, 40 + const char *name, 41 + const char *props_title, 42 + const char *names_title, 43 + unsigned int default_val, 44 + unsigned int *val) 45 + { 46 + int err, n_props, n_names, idx; 47 + u32 *props; 48 + 49 + if (!name) { 50 + pr_err("Lookup key inside \"%s\" is mandatory\n", names_title); 51 + return -EINVAL; 52 + } 53 + 54 + n_props = fwnode_property_count_u32(fwnode, props_title); 55 + if (n_props <= 0) { 56 + /* fwnode is NULL, or is missing requested property */ 57 + *val = default_val; 58 + return 0; 59 + } 60 + 61 + n_names = fwnode_property_string_array_count(fwnode, names_title); 62 + if (n_names >= 0 && n_props != n_names) { 63 + pr_err("%pfw mismatch between \"%s\" and \"%s\" property count (%d vs %d)\n", 64 + fwnode, props_title, names_title, n_props, n_names); 65 + return -EINVAL; 66 + } 67 + 68 + idx = fwnode_property_match_string(fwnode, names_title, name); 69 + if (idx < 0) 70 + idx = fwnode_property_match_string(fwnode, names_title, "default"); 71 + /* 72 + * If the mode name is missing, it can only mean the specified property 73 + * is the default one for all modes, so reject any other property count 74 + * than 1. 75 + */ 76 + if (idx < 0 && n_props != 1) { 77 + pr_err("%pfw \"%s \" property has %d elements, but cannot find \"%s\" in \"%s\" and there is no default value\n", 78 + fwnode, props_title, n_props, name, names_title); 79 + return -EINVAL; 80 + } 81 + 82 + if (n_props == 1) { 83 + err = fwnode_property_read_u32(fwnode, props_title, val); 84 + if (err) 85 + return err; 86 + 87 + return 0; 88 + } 89 + 90 + /* We implicitly know idx >= 0 here */ 91 + props = kcalloc(n_props, sizeof(*props), GFP_KERNEL); 92 + if (!props) 93 + return -ENOMEM; 94 + 95 + err = fwnode_property_read_u32_array(fwnode, props_title, props, n_props); 96 + if (err >= 0) 97 + *val = props[idx]; 98 + 99 + kfree(props); 100 + 101 + return err; 102 + } 103 + 104 + static int phy_get_polarity_for_mode(struct fwnode_handle *fwnode, 105 + const char *mode_name, 106 + unsigned int supported, 107 + unsigned int default_val, 108 + const char *polarity_prop, 109 + const char *names_prop, 110 + unsigned int *val) 111 + { 112 + int err; 113 + 114 + err = fwnode_get_u32_prop_for_name(fwnode, mode_name, polarity_prop, 115 + names_prop, default_val, val); 116 + if (err) 117 + return err; 118 + 119 + if (!(supported & BIT(*val))) { 120 + pr_err("%d is not a supported value for %pfw '%s' element '%s'\n", 121 + *val, fwnode, polarity_prop, mode_name); 122 + err = -EOPNOTSUPP; 123 + } 124 + 125 + return err; 126 + } 127 + 128 + /** 129 + * phy_get_rx_polarity - Get RX polarity for PHY differential lane 130 + * @fwnode: Pointer to the PHY's firmware node. 131 + * @mode_name: The name of the PHY mode to look up. 132 + * @supported: Bit mask of PHY_POL_NORMAL, PHY_POL_INVERT and PHY_POL_AUTO 133 + * @default_val: Default polarity value if property is missing 134 + * @val: Pointer to returned polarity. 135 + * 136 + * Return: zero on success, negative error on failure. 137 + */ 138 + int __must_check phy_get_rx_polarity(struct fwnode_handle *fwnode, 139 + const char *mode_name, 140 + unsigned int supported, 141 + unsigned int default_val, 142 + unsigned int *val) 143 + { 144 + return phy_get_polarity_for_mode(fwnode, mode_name, supported, 145 + default_val, "rx-polarity", 146 + "rx-polarity-names", val); 147 + } 148 + EXPORT_SYMBOL_GPL(phy_get_rx_polarity); 149 + 150 + /** 151 + * phy_get_tx_polarity - Get TX polarity for PHY differential lane 152 + * @fwnode: Pointer to the PHY's firmware node. 153 + * @mode_name: The name of the PHY mode to look up. 154 + * @supported: Bit mask of PHY_POL_NORMAL and PHY_POL_INVERT 155 + * @default_val: Default polarity value if property is missing 156 + * @val: Pointer to returned polarity. 157 + * 158 + * Return: zero on success, negative error on failure. 159 + */ 160 + int __must_check phy_get_tx_polarity(struct fwnode_handle *fwnode, 161 + const char *mode_name, unsigned int supported, 162 + unsigned int default_val, unsigned int *val) 163 + { 164 + return phy_get_polarity_for_mode(fwnode, mode_name, supported, 165 + default_val, "tx-polarity", 166 + "tx-polarity-names", val); 167 + } 168 + EXPORT_SYMBOL_GPL(phy_get_tx_polarity); 169 + 170 + /** 171 + * phy_get_manual_rx_polarity - Get manual RX polarity for PHY differential lane 172 + * @fwnode: Pointer to the PHY's firmware node. 173 + * @mode_name: The name of the PHY mode to look up. 174 + * @val: Pointer to returned polarity. 175 + * 176 + * Helper for PHYs which do not support protocols with automatic RX polarity 177 + * detection and correction. 178 + * 179 + * Return: zero on success, negative error on failure. 180 + */ 181 + int __must_check phy_get_manual_rx_polarity(struct fwnode_handle *fwnode, 182 + const char *mode_name, 183 + unsigned int *val) 184 + { 185 + return phy_get_rx_polarity(fwnode, mode_name, 186 + BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT), 187 + PHY_POL_NORMAL, val); 188 + } 189 + EXPORT_SYMBOL_GPL(phy_get_manual_rx_polarity); 190 + 191 + /** 192 + * phy_get_manual_tx_polarity - Get manual TX polarity for PHY differential lane 193 + * @fwnode: Pointer to the PHY's firmware node. 194 + * @mode_name: The name of the PHY mode to look up. 195 + * @val: Pointer to returned polarity. 196 + * 197 + * Helper for PHYs without any custom default value for the TX polarity. 198 + * 199 + * Return: zero on success, negative error on failure. 200 + */ 201 + int __must_check phy_get_manual_tx_polarity(struct fwnode_handle *fwnode, 202 + const char *mode_name, 203 + unsigned int *val) 204 + { 205 + return phy_get_tx_polarity(fwnode, mode_name, 206 + BIT(PHY_POL_NORMAL) | BIT(PHY_POL_INVERT), 207 + PHY_POL_NORMAL, val); 208 + } 209 + EXPORT_SYMBOL_GPL(phy_get_manual_tx_polarity);
+32
include/linux/phy/phy-common-props.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* 3 + * phy-common-props.h -- Common properties for generic PHYs 4 + * 5 + * Copyright 2025 NXP 6 + */ 7 + 8 + #ifndef __PHY_COMMON_PROPS_H 9 + #define __PHY_COMMON_PROPS_H 10 + 11 + #include <dt-bindings/phy/phy.h> 12 + 13 + struct fwnode_handle; 14 + 15 + int __must_check phy_get_rx_polarity(struct fwnode_handle *fwnode, 16 + const char *mode_name, 17 + unsigned int supported, 18 + unsigned int default_val, 19 + unsigned int *val); 20 + int __must_check phy_get_tx_polarity(struct fwnode_handle *fwnode, 21 + const char *mode_name, 22 + unsigned int supported, 23 + unsigned int default_val, 24 + unsigned int *val); 25 + int __must_check phy_get_manual_rx_polarity(struct fwnode_handle *fwnode, 26 + const char *mode_name, 27 + unsigned int *val); 28 + int __must_check phy_get_manual_tx_polarity(struct fwnode_handle *fwnode, 29 + const char *mode_name, 30 + unsigned int *val); 31 + 32 + #endif /* __PHY_COMMON_PROPS_H */