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

ARM: OMAP1: ams-delta: Fix MODEM initialization failure

Regulator drivers were modified to use asynchronous device probe. Since
then, the board .init_late hook fails to acquire a GPIO based fixed
regulator needed by an on-board voice MODEM device, and unregisters the
MODEM. That in turn triggers a so far not discovered bug of device
unregister function called for a device with no associated release() op.

serial8250 serial8250.1: incomplete constraints, dummy supplies not allowed
WARNING: CPU: 0 PID: 1 at drivers/base/core.c:2486 device_release+0x98/0xa8
Device 'serial8250.1' does not have a release() function, it is broken and
must be fixed. See Documentation/core-api/kobject.rst.
...
put_device from platform_device_put+0x1c/0x24
platform_device_put from ams_delta_init_late+0x4c/0x68
ams_delta_init_late from init_machine_late+0x1c/0x94
init_machine_late from do_one_initcall+0x60/0x1d4

As a consequence, ASoC CODEC driver is no longer able to control its
device over the voice MODEM's tty interface.

cx20442-codec: ASoC: error at soc_component_write_no_lock
on cx20442-codec for register: [0x00000000] -5
cx20442-codec: ASoC: error at snd_soc_component_update_bits_legacy
on cx20442-codec for register: [0x00000000] -5
cx20442-codec: ASoC: error at snd_soc_component_update_bits
on cx20442-codec for register: [0x00000000] -5

The regulator hangs of a GPIO pin controlled by basic-mmio-gpio driver.
Unlike most GPIO drivers, that driver doesn't probe for devices before
device_initcall, then GPIO pins under its control are not availabele to
majority of devices probed at that phase, including regulators. On the
other hand, serial8250 driver used by the MODEM device neither accepts via
platform data nor handles regulators, then the board file is not able to
teach that driver to return -EPROBE_DEFER when the regulator is not ready
so the failed probe is retried after late_initcall.

Resolve the issue by extending description of the MODEM device with a
dedicated power management domain. Acquire the regulator from the
domain's .activate hook and return -EPROBE_DEFER if the regulator is not
available. Having that under control, add the regulator device
description to the list of platform devices initialized from .init_machine
and drop the no longer needed custom .init_late hook.

v2: Trim down the warning for prettier git log output (Tony).

Fixes: 259b93b21a9f ("regulator: Set PROBE_PREFER_ASYNCHRONOUS for drivers that existed in 4.14")
Signed-off-by: Janusz Krzysztofik <jmkrzyszt@gmail.com>
Cc: stable@vger.kernel.org # v6.4+
Message-ID: <20231011175038.1907629-1-jmkrzyszt@gmail.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>

authored by

Janusz Krzysztofik and committed by
Tony Lindgren
5447da5d 7eeca8cc

+16 -44
+16 -44
arch/arm/mach-omap1/board-ams-delta.c
··· 550 550 &ams_delta_nand_device, 551 551 &ams_delta_lcd_device, 552 552 &cx20442_codec_device, 553 + &modem_nreset_device, 553 554 }; 554 555 555 556 static struct gpiod_lookup_table *ams_delta_gpio_tables[] __initdata = { ··· 783 782 { }, 784 783 }; 785 784 785 + static int ams_delta_modem_pm_activate(struct device *dev) 786 + { 787 + modem_priv.regulator = regulator_get(dev, "RESET#"); 788 + if (IS_ERR(modem_priv.regulator)) 789 + return -EPROBE_DEFER; 790 + 791 + return 0; 792 + } 793 + 794 + static struct dev_pm_domain ams_delta_modem_pm_domain = { 795 + .activate = ams_delta_modem_pm_activate, 796 + }; 797 + 786 798 static struct platform_device ams_delta_modem_device = { 787 799 .name = "serial8250", 788 800 .id = PLAT8250_DEV_PLATFORM1, 789 801 .dev = { 790 802 .platform_data = ams_delta_modem_ports, 803 + .pm_domain = &ams_delta_modem_pm_domain, 791 804 }, 792 805 }; 793 - 794 - static int __init modem_nreset_init(void) 795 - { 796 - int err; 797 - 798 - err = platform_device_register(&modem_nreset_device); 799 - if (err) 800 - pr_err("Couldn't register the modem regulator device\n"); 801 - 802 - return err; 803 - } 804 - 805 806 806 807 /* 807 808 * This function expects MODEM IRQ number already assigned to the port. ··· 836 833 } 837 834 arch_initcall_sync(ams_delta_modem_init); 838 835 839 - static int __init late_init(void) 840 - { 841 - int err; 842 - 843 - err = modem_nreset_init(); 844 - if (err) 845 - return err; 846 - 847 - /* 848 - * Once the modem device is registered, the modem_nreset 849 - * regulator can be requested on behalf of that device. 850 - */ 851 - modem_priv.regulator = regulator_get(&ams_delta_modem_device.dev, 852 - "RESET#"); 853 - if (IS_ERR(modem_priv.regulator)) { 854 - err = PTR_ERR(modem_priv.regulator); 855 - goto unregister; 856 - } 857 - return 0; 858 - 859 - unregister: 860 - platform_device_unregister(&ams_delta_modem_device); 861 - return err; 862 - } 863 - 864 - static void __init ams_delta_init_late(void) 865 - { 866 - omap1_init_late(); 867 - late_init(); 868 - } 869 - 870 836 static void __init ams_delta_map_io(void) 871 837 { 872 838 omap1_map_io(); ··· 849 877 .init_early = omap1_init_early, 850 878 .init_irq = omap1_init_irq, 851 879 .init_machine = ams_delta_init, 852 - .init_late = ams_delta_init_late, 880 + .init_late = omap1_init_late, 853 881 .init_time = omap1_timer_init, 854 882 .restart = omap1_restart, 855 883 MACHINE_END