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

can: tcan4x5x: fix reset gpio usage during probe

Fixes reset GPIO usage during probe by ensuring we retrieve the GPIO and
take the device out of reset (if it defaults to being in reset) before
we attempt to communicate with the device. This is achieved by moving
the call to tcan4x5x_get_gpios() before tcan4x5x_find_version() and
avoiding any device communication while getting the GPIOs. Once we
determine the version, we can then take the knowledge of which GPIOs we
obtained and use it to decide whether we need to disable the wake or
state pin functions within the device.

This change is necessary in a situation where the reset GPIO is pulled
high externally before the CPU takes control of it, meaning we need to
explicitly bring the device out of reset before we can start
communicating with it at all.

This also has the effect of fixing an issue where a reset of the device
would occur after having called tcan4x5x_disable_wake(), making the
original behavior not actually disable the wake. This patch should now
disable wake or state pin functions well after the reset occurs.

Signed-off-by: Brett Werling <brett.werling@garmin.com>
Link: https://patch.msgid.link/20250711141728.1826073-1-brett.werling@garmin.com
Cc: Markus Schneider-Pargmann <msp@baylibre.com>
Fixes: 142c6dc6d9d7 ("can: tcan4x5x: Add support for tcan4552/4553")
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Brett Werling and committed by
Marc Kleine-Budde
0f97a758 f0f2b992

+41 -20
+41 -20
drivers/net/can/m_can/tcan4x5x-core.c
··· 343 343 of_property_read_bool(cdev->dev->of_node, "ti,nwkrq-voltage-vio"); 344 344 } 345 345 346 - static int tcan4x5x_get_gpios(struct m_can_classdev *cdev, 347 - const struct tcan4x5x_version_info *version_info) 346 + static int tcan4x5x_get_gpios(struct m_can_classdev *cdev) 348 347 { 349 348 struct tcan4x5x_priv *tcan4x5x = cdev_to_priv(cdev); 350 349 int ret; 351 350 352 - if (version_info->has_wake_pin) { 353 - tcan4x5x->device_wake_gpio = devm_gpiod_get(cdev->dev, "device-wake", 354 - GPIOD_OUT_HIGH); 355 - if (IS_ERR(tcan4x5x->device_wake_gpio)) { 356 - if (PTR_ERR(tcan4x5x->device_wake_gpio) == -EPROBE_DEFER) 357 - return -EPROBE_DEFER; 351 + tcan4x5x->device_wake_gpio = devm_gpiod_get_optional(cdev->dev, 352 + "device-wake", 353 + GPIOD_OUT_HIGH); 354 + if (IS_ERR(tcan4x5x->device_wake_gpio)) { 355 + if (PTR_ERR(tcan4x5x->device_wake_gpio) == -EPROBE_DEFER) 356 + return -EPROBE_DEFER; 358 357 359 - tcan4x5x_disable_wake(cdev); 360 - } 358 + tcan4x5x->device_wake_gpio = NULL; 361 359 } 362 360 363 361 tcan4x5x->reset_gpio = devm_gpiod_get_optional(cdev->dev, "reset", ··· 367 369 if (ret) 368 370 return ret; 369 371 370 - if (version_info->has_state_pin) { 371 - tcan4x5x->device_state_gpio = devm_gpiod_get_optional(cdev->dev, 372 - "device-state", 373 - GPIOD_IN); 374 - if (IS_ERR(tcan4x5x->device_state_gpio)) { 375 - tcan4x5x->device_state_gpio = NULL; 376 - tcan4x5x_disable_state(cdev); 377 - } 372 + tcan4x5x->device_state_gpio = devm_gpiod_get_optional(cdev->dev, 373 + "device-state", 374 + GPIOD_IN); 375 + if (IS_ERR(tcan4x5x->device_state_gpio)) 376 + tcan4x5x->device_state_gpio = NULL; 377 + 378 + return 0; 379 + } 380 + 381 + static int tcan4x5x_check_gpios(struct m_can_classdev *cdev, 382 + const struct tcan4x5x_version_info *version_info) 383 + { 384 + struct tcan4x5x_priv *tcan4x5x = cdev_to_priv(cdev); 385 + int ret; 386 + 387 + if (version_info->has_wake_pin && !tcan4x5x->device_wake_gpio) { 388 + ret = tcan4x5x_disable_wake(cdev); 389 + if (ret) 390 + return ret; 391 + } 392 + 393 + if (version_info->has_state_pin && !tcan4x5x->device_state_gpio) { 394 + ret = tcan4x5x_disable_state(cdev); 395 + if (ret) 396 + return ret; 378 397 } 379 398 380 399 return 0; ··· 483 468 goto out_m_can_class_free_dev; 484 469 } 485 470 471 + ret = tcan4x5x_get_gpios(mcan_class); 472 + if (ret) { 473 + dev_err(&spi->dev, "Getting gpios failed %pe\n", ERR_PTR(ret)); 474 + goto out_power; 475 + } 476 + 486 477 version_info = tcan4x5x_find_version(priv); 487 478 if (IS_ERR(version_info)) { 488 479 ret = PTR_ERR(version_info); 489 480 goto out_power; 490 481 } 491 482 492 - ret = tcan4x5x_get_gpios(mcan_class, version_info); 483 + ret = tcan4x5x_check_gpios(mcan_class, version_info); 493 484 if (ret) { 494 - dev_err(&spi->dev, "Getting gpios failed %pe\n", ERR_PTR(ret)); 485 + dev_err(&spi->dev, "Checking gpios failed %pe\n", ERR_PTR(ret)); 495 486 goto out_power; 496 487 } 497 488