From: Svyatoslav Ryhel <clamor95@gmail.com>
To: Andrew Lunn <andrew+netdev@lunn.ch>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>, Vinod Koul <vkoul@kernel.org>,
Neil Armstrong <neil.armstrong@linaro.org>,
Thierry Reding <thierry.reding@kernel.org>,
Jonathan Hunter <jonathanh@nvidia.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Peter Chen <peter.chen@kernel.org>,
Svyatoslav Ryhel <clamor95@gmail.com>
Cc: netdev@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-phy@lists.infradead.org,
linux-tegra@vger.kernel.org, linux-usb@vger.kernel.org
Subject: [PATCH v1 4/6] net: usb: Add Infineon XMM6260 Baseband modem support
Date: Mon, 11 May 2026 16:56:59 +0300 [thread overview]
Message-ID: <20260511135703.62470-5-clamor95@gmail.com> (raw)
In-Reply-To: <20260511135703.62470-1-clamor95@gmail.com>
The Infineon/Intel XMM6260 is a 3G-focused, slim modem platform designed
for smartphones, data cards, and Machine-to-Machine (M2M) applications.
The modem is usually connected via the application processor's USB line
in HSIC mode; however, to work properly, the modem must control this line
Dmesg with modem appearing on LG Optimus Vu (P895):
[ 9.427014] ci_hdrc ci_hdrc.1: EHCI Host Controller
[ 9.431488] ci_hdrc ci_hdrc.1: new USB bus registered, assigned bus number 1
[ 9.457197] ci_hdrc ci_hdrc.1: USB 2.0 started, EHCI 1.00
[ 9.460370] usb usb1: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 6.16
[ 9.468470] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[ 9.475597] usb usb1: Product: EHCI Host Controller
[ 9.480508] usb usb1: Manufacturer: Linux 6.16.0+ ehci_hcd
[ 9.485913] usb usb1: SerialNumber: ci_hdrc.1
[ 9.490862] hub 1-0:1.0: USB hub found
[ 9.494005] hub 1-0:1.0: 1 port detected
[ 9.657191] usb 1-1: new high-speed USB device number 2 using ci_hdrc
[ 9.844726] usb 1-1: New USB device found, idVendor=1519, idProduct=0020, bcdDevice=12.74
[ 9.850530] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 9.857594] usb 1-1: Product: HSIC Device
[ 9.861606] usb 1-1: Manufacturer: Comneon
[ 9.865627] usb 1-1: SerialNumber: 0123456789
[ 9.908739] cdc_acm 1-1:1.0: ttyACM0: USB ACM device
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/net/usb/Kconfig | 15 ++
drivers/net/usb/Makefile | 1 +
drivers/net/usb/baseband-xmm6260.c | 335 +++++++++++++++++++++++++++++
3 files changed, 351 insertions(+)
create mode 100644 drivers/net/usb/baseband-xmm6260.c
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 52a5c0922c79..503f24a3cfa6 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -642,4 +642,19 @@ config USB_RTL8153_ECM
CONFIG_USB_RTL8152 is not set, or the RTL8153 device is not
supported by r8152 driver.
+config USB_NET_XMM6260
+ tristate "Infineon XMM626X Baseband HSPA/HSUPA modem"
+ depends on GPIOLIB && OF && USB_CHIPIDEA
+ help
+ Select this if you want to use an Infineon XMM626X modem, found in
+ devices such as the LG Optimus 4X P880, LG Optimus Vu P895, Samsung
+ Galaxy S II (GT-I9100), and Galaxy Nexus (GT-I9250). This driver
+ handles the modem configuration and provides a stable way to expose
+ the modem's USB interface. To establish a connection, you will first
+ need a userspace program to send the correct commands to the modem
+ through its CDC ACM port, as well as a DHCP client.
+
+ To compile this driver as a module, choose M here: the module will
+ be called baseband-xmm6260.
+
endif # USB_NET_DRIVERS
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index 4964f7b326fb..ffa532c7d7d6 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -42,3 +42,4 @@ obj-$(CONFIG_USB_NET_CDC_MBIM) += cdc_mbim.o
obj-$(CONFIG_USB_NET_CH9200) += ch9200.o
obj-$(CONFIG_USB_NET_AQC111) += aqc111.o
obj-$(CONFIG_USB_RTL8153_ECM) += r8153_ecm.o
+obj-$(CONFIG_USB_NET_XMM6260) += baseband-xmm6260.o
diff --git a/drivers/net/usb/baseband-xmm6260.c b/drivers/net/usb/baseband-xmm6260.c
new file mode 100644
index 000000000000..658f5351fab7
--- /dev/null
+++ b/drivers/net/usb/baseband-xmm6260.c
@@ -0,0 +1,335 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2011 NVIDIA Corporation
+ * Copyright (C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <linux/array_size.h>
+#include <linux/devm-helpers.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/gpio/consumer.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/rfkill.h>
+#include <linux/usb.h>
+
+#define BASEBAND_XMM_INIT_DELAY 5000
+
+#define BASEBAND_PRODUCT_ID_XMM6260 0x0020
+#define BASEBAND_VENDOR_ID_COMNEON 0x1519
+
+enum ipc_ap_wake_state {
+ IPC_AP_WAKE_IRQ_READY,
+ IPC_AP_WAKE_INIT1,
+ IPC_AP_WAKE_INIT2,
+ IPC_AP_WAKE_L,
+ IPC_AP_WAKE_H,
+ IPC_AP_WAKE_UNINIT,
+};
+
+struct baseband_xmm_data {
+ struct device *dev;
+ struct rfkill *rfkill_dev;
+ struct phy *mphy;
+
+ struct gpio_desc *reset_gpio;
+ struct gpio_desc *enable_gpio;
+
+ struct gpio_desc *ipc_cp_gpio;
+ struct gpio_desc *ipc_ap_gpio;
+
+ struct regulator *vbat_supply;
+
+ struct delayed_work modem_work;
+ struct notifier_block nb;
+
+ enum ipc_ap_wake_state ap_state;
+
+ bool powered; /* tracks usb bus state */
+ bool inited; /* tracks modem state */
+};
+
+static int baseband_xmm_usb_notifier_call(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct baseband_xmm_data *priv =
+ container_of(nb, struct baseband_xmm_data, nb);
+ struct usb_device *udev = data;
+ u16 product = le16_to_cpu(udev->descriptor.idProduct);
+ u16 vendor = le16_to_cpu(udev->descriptor.idVendor);
+
+ switch (action) {
+ case USB_DEVICE_ADD:
+ /* Infineon XMM6260 ID 1519:0020 */
+ if (vendor == BASEBAND_VENDOR_ID_COMNEON &&
+ product == BASEBAND_PRODUCT_ID_XMM6260) {
+ cancel_delayed_work_sync(&priv->modem_work);
+ priv->inited = true;
+ }
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static void baseband_xmm_reset(struct baseband_xmm_data *priv)
+{
+ int ret;
+
+ ret = regulator_enable(priv->vbat_supply);
+ if (ret)
+ dev_err(priv->dev, "failed to enable vbat power supply\n");
+
+ gpiod_set_value_cansleep(priv->enable_gpio, 0);
+ msleep(50);
+
+ gpiod_set_value_cansleep(priv->reset_gpio, 1);
+ msleep(200);
+ gpiod_set_value_cansleep(priv->reset_gpio, 0);
+
+ msleep(50);
+
+ /* falling edge trigger to CP */
+ gpiod_set_value_cansleep(priv->enable_gpio, 1);
+ usleep_range(50, 100);
+ gpiod_set_value_cansleep(priv->enable_gpio, 0);
+ msleep(20);
+}
+
+static int baseband_xmm_set_block(void *data, bool blocked)
+{
+ struct baseband_xmm_data *priv = data;
+
+ if (blocked) {
+ if (priv->inited && priv->powered) {
+ phy_power_off(priv->mphy);
+
+ msleep(500);
+
+ gpiod_set_value_cansleep(priv->reset_gpio, 1);
+ regulator_disable(priv->vbat_supply);
+
+ priv->powered = false;
+ priv->inited = false;
+ }
+ } else {
+ if (priv->inited)
+ return 0;
+
+ priv->ap_state = IPC_AP_WAKE_IRQ_READY;
+ baseband_xmm_reset(priv);
+
+ priv->powered = false;
+ priv->inited = false;
+ }
+
+ return 0;
+}
+
+static const struct rfkill_ops baseband_xmm_rfkill_ops = {
+ .set_block = baseband_xmm_set_block,
+};
+
+static void baseband_xmm_work(struct work_struct *work)
+{
+ struct baseband_xmm_data *priv =
+ container_of(work, struct baseband_xmm_data, modem_work.work);
+
+ switch (priv->ap_state) {
+ case IPC_AP_WAKE_INIT1:
+ if (priv->powered)
+ return;
+
+ phy_power_on(priv->mphy);
+ priv->powered = true;
+ break;
+
+ case IPC_AP_WAKE_INIT2:
+ priv->ap_state = IPC_AP_WAKE_IRQ_READY;
+
+ phy_power_off(priv->mphy);
+
+ priv->powered = false;
+ priv->inited = false;
+
+ msleep(500);
+ break;
+
+ default:
+ break;
+ }
+};
+
+static irqreturn_t baseband_hostwake_interrupt(int irq, void *dev_id)
+{
+ struct baseband_xmm_data *priv = dev_id;
+ int state = gpiod_get_value(priv->ipc_ap_gpio);
+
+ switch (priv->ap_state) {
+ case IPC_AP_WAKE_IRQ_READY:
+ if (!state) {
+ priv->ap_state = IPC_AP_WAKE_INIT1;
+ schedule_delayed_work(&priv->modem_work, 0);
+ }
+
+ break;
+
+ case IPC_AP_WAKE_INIT1:
+ if (state) {
+ priv->ap_state = IPC_AP_WAKE_INIT2;
+ schedule_delayed_work(&priv->modem_work,
+ msecs_to_jiffies(BASEBAND_XMM_INIT_DELAY));
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int baseband_xmm_probe(struct platform_device *pdev)
+{
+ struct baseband_xmm_data *priv;
+ struct device *dev = &pdev->dev;
+ unsigned long irqflags;
+ int irq, ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+ platform_set_drvdata(pdev, priv);
+
+ priv->vbat_supply = devm_regulator_get(dev, "vbat");
+ if (IS_ERR(priv->vbat_supply))
+ return dev_err_probe(dev, PTR_ERR(priv->vbat_supply),
+ "failed to get vbat regulator\n");
+
+ /* Own modem gpios */
+ priv->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(priv->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(priv->reset_gpio),
+ "failed to get reset GPIO\n");
+
+ priv->enable_gpio = devm_gpiod_get_optional(dev, "enable",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(priv->enable_gpio))
+ return dev_err_probe(dev, PTR_ERR(priv->enable_gpio),
+ "failed to get enable GPIO\n");
+
+ /* CP - AP connections */
+ priv->ipc_cp_gpio = devm_gpiod_get_optional(dev, "cp-wake",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(priv->ipc_cp_gpio))
+ return dev_err_probe(dev, PTR_ERR(priv->ipc_cp_gpio),
+ "failed to get CP wake GPIO\n");
+
+ priv->ipc_ap_gpio = devm_gpiod_get_optional(dev, "ap-wake", GPIOD_IN);
+ if (IS_ERR(priv->ipc_ap_gpio))
+ return dev_err_probe(dev, PTR_ERR(priv->ipc_ap_gpio),
+ "failed to get AP wake GPIO\n");
+
+ /* Modem PHY */
+ priv->mphy = devm_phy_optional_get(dev, NULL);
+ if (IS_ERR(priv->mphy))
+ return dev_err_probe(dev, PTR_ERR(priv->mphy),
+ "failed to get modem PHY");
+
+ /*
+ * Strting from ver 1145 modem starts in READY state. AP wake
+ * interrupt keeps low util CP starts to initiate HSIC hw. AP
+ * wake interrupt goes up during CP HSIC init and then it goes
+ * down when CP HSIC is ready.
+ */
+ priv->ap_state = IPC_AP_WAKE_IRQ_READY;
+ priv->inited = false;
+
+ devm_delayed_work_autocancel(dev, &priv->modem_work, baseband_xmm_work);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "failed to get IRQ\n");
+
+ /*
+ * Systems using device tree should set up interrupt via DT,
+ * the rest will use the default edge both interrupt.
+ */
+ irqflags = dev->of_node ? 0 : IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
+
+ ret = devm_request_threaded_irq(dev, irq, NULL,
+ &baseband_hostwake_interrupt,
+ IRQF_ONESHOT | irqflags,
+ "modem-hostwake", priv);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to register IRQ %d\n", irq);
+
+ priv->rfkill_dev = rfkill_alloc("xmm-modem", dev, RFKILL_TYPE_WWAN,
+ &baseband_xmm_rfkill_ops, priv);
+ if (priv->rfkill_dev) {
+ ret = rfkill_register(priv->rfkill_dev);
+ if (ret < 0) {
+ rfkill_destroy(priv->rfkill_dev);
+ return dev_err_probe(dev, ret,
+ "failed to register WWAN rfkill\n");
+ }
+ } else {
+ return dev_err_probe(dev, PTR_ERR(priv->rfkill_dev),
+ "failed to allocate WWAN rfkill\n");
+ }
+
+ priv->nb.notifier_call = baseband_xmm_usb_notifier_call;
+ usb_register_notify(&priv->nb);
+
+ baseband_xmm_reset(priv);
+ priv->powered = false;
+
+ return 0;
+}
+
+static void baseband_xmm_remove(struct platform_device *pdev)
+{
+ struct baseband_xmm_data *priv = platform_get_drvdata(pdev);
+
+ rfkill_unregister(priv->rfkill_dev);
+ rfkill_destroy(priv->rfkill_dev);
+
+ usb_unregister_notify(&priv->nb);
+ phy_power_off(priv->mphy);
+
+ gpiod_set_value_cansleep(priv->reset_gpio, 1);
+ regulator_disable(priv->vbat_supply);
+}
+
+static const struct of_device_id baseband_xmm_match[] = {
+ { .compatible = "infineon,xmm6260" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, baseband_xmm_match);
+
+static struct platform_driver baseband_xmm_driver = {
+ .driver = {
+ .name = "baseband-xmm6260",
+ .of_match_table = baseband_xmm_match,
+ },
+ .probe = baseband_xmm_probe,
+ .remove = baseband_xmm_remove,
+};
+module_platform_driver(baseband_xmm_driver);
+
+MODULE_AUTHOR("Svyatolsav Ryhel <clamor95@gmail.com>");
+MODULE_DESCRIPTION("Baseband Infineon XMM6260 driver");
+MODULE_LICENSE("GPL");
--
2.51.0
next prev parent reply other threads:[~2026-05-11 13:57 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-11 13:56 [PATCH v1 0/6] Add support for Infineon/Intel XMM6260 modem Svyatoslav Ryhel
2026-05-11 13:56 ` [PATCH v1 1/6] dt-bindings: usb: ci-hdrc-usb2: Document nvidia,external-control property Svyatoslav Ryhel
2026-05-11 13:56 ` [PATCH v1 2/6] usb: chipidea: tegra: Avoid controller/PHY init if bus is externally controlled Svyatoslav Ryhel
2026-05-11 13:56 ` [PATCH v1 3/6] dt-bindings: net: Document Infineon/Intel XMM6260 modem Svyatoslav Ryhel
2026-05-11 13:56 ` Svyatoslav Ryhel [this message]
2026-05-11 13:57 ` [PATCH v1 5/6] dt-bindings: phy: tegra: Document Nvidia Tegra XMM6260 PHY Svyatoslav Ryhel
2026-05-11 13:57 ` [PATCH v1 6/6] phy: tegra: Add support for " Svyatoslav Ryhel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260511135703.62470-5-clamor95@gmail.com \
--to=clamor95@gmail.com \
--cc=andrew+netdev@lunn.ch \
--cc=conor+dt@kernel.org \
--cc=davem@davemloft.net \
--cc=devicetree@vger.kernel.org \
--cc=edumazet@google.com \
--cc=gregkh@linuxfoundation.org \
--cc=jonathanh@nvidia.com \
--cc=krzk+dt@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-phy@lists.infradead.org \
--cc=linux-tegra@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=neil.armstrong@linaro.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=peter.chen@kernel.org \
--cc=robh@kernel.org \
--cc=thierry.reding@kernel.org \
--cc=vkoul@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox