diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c index f78aefd2d7a36..fc5d67ff4016d 100644 --- a/drivers/bus/mhi/host/init.c +++ b/drivers/bus/mhi/host/init.c @@ -79,6 +79,29 @@ const char *to_mhi_pm_state_str(u32 state) return mhi_pm_state_str[index]; } +static ssize_t fw_update_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct mhi_device *mhi_dev = to_mhi_device(dev); + struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; + + return sysfs_emit(buf, "%u\n", mhi_cntrl->xfp); +} + +static ssize_t fw_update_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) +{ + struct mhi_device *mhi_dev = to_mhi_device(dev); + struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; + bool enable; + + if (strtobool(buf, &enable)) + return -EINVAL; + + mhi_cntrl->xfp = enable ? XFP_STATE_FLASHING : XFP_STATE_NEED_RESET; + + return len; +} +static DEVICE_ATTR_RW(fw_update); + static ssize_t serial_number_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -124,6 +147,7 @@ static struct attribute *mhi_dev_attrs[] = { &dev_attr_serial_number.attr, &dev_attr_oem_pk_hash.attr, &dev_attr_soc_reset.attr, + &dev_attr_fw_update.attr, NULL, }; ATTRIBUTE_GROUPS(mhi_dev); diff --git a/drivers/bus/mhi/host/internal.h b/drivers/bus/mhi/host/internal.h index 2e139e76de4c0..3bdcd2321aa5b 100644 --- a/drivers/bus/mhi/host/internal.h +++ b/drivers/bus/mhi/host/internal.h @@ -56,7 +56,7 @@ extern const char * const mhi_ee_str[MHI_EE_MAX]; #define MHI_IN_PBL(ee) (ee == MHI_EE_PBL || ee == MHI_EE_PTHRU || \ ee == MHI_EE_EDL) -#define MHI_POWER_UP_CAPABLE(ee) (MHI_IN_PBL(ee) || ee == MHI_EE_AMSS) +#define MHI_POWER_UP_CAPABLE(ee) (MHI_IN_PBL(ee) || ee == MHI_EE_AMSS || ee == MHI_EE_SBL) #define MHI_FW_LOAD_CAPABLE(ee) (ee == MHI_EE_PBL || ee == MHI_EE_EDL) #define MHI_IN_MISSION_MODE(ee) (ee == MHI_EE_AMSS || ee == MHI_EE_WFW || \ ee == MHI_EE_FP) diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c index dcf627b36e829..50445e6134c4c 100644 --- a/drivers/bus/mhi/host/main.c +++ b/drivers/bus/mhi/host/main.c @@ -323,6 +323,11 @@ int mhi_destroy_device(struct device *dev, void *data) dev_dbg(&mhi_cntrl->mhi_dev->dev, "destroy device for chan:%s\n", mhi_dev->name); + if (!strcmp(mhi_dev->name, "IP_CTRL")) { + dev_dbg(dev, "destroying IP_CTRL\n"); + mhi_cntrl->mhi_dev_ip_ctrl = NULL; + } + /* Notify the client and remove the device from MHI bus */ device_del(dev); put_device(dev); @@ -423,6 +428,12 @@ void mhi_create_devices(struct mhi_controller *mhi_cntrl) ret = device_add(&mhi_dev->dev); if (ret) put_device(&mhi_dev->dev); + else { + if (!strcmp(mhi_dev->name, "IP_CTRL")) { + dev_dbg(dev, "IP_CTRL supported\n"); + mhi_cntrl->mhi_dev_ip_ctrl = mhi_dev; + } + } } } diff --git a/drivers/bus/mhi/host/pci_generic.c b/drivers/bus/mhi/host/pci_generic.c index 08f3f039dbddc..3f06083a9b731 100644 --- a/drivers/bus/mhi/host/pci_generic.c +++ b/drivers/bus/mhi/host/pci_generic.c @@ -21,7 +21,7 @@ #define MHI_POST_RESET_DELAY_MS 2000 -#define HEALTH_CHECK_PERIOD (HZ * 2) +#define HEALTH_CHECK_PERIOD (HZ / 2) /* PCI VID definitions */ #define PCI_VENDOR_ID_THALES 0x1269 @@ -50,6 +50,36 @@ struct mhi_pci_dev_info { bool sideband_wake; }; +#define MHI_CHANNEL_CONFIG_AMSS_SBL_UL(ch_num, ch_name, el_count, ev_ring) \ + { \ + .num = ch_num, \ + .name = ch_name, \ + .num_elements = el_count, \ + .event_ring = ev_ring, \ + .dir = DMA_TO_DEVICE, \ + .ee_mask = BIT(MHI_EE_SBL) | BIT(MHI_EE_AMSS), \ + .pollcfg = 0, \ + .doorbell = MHI_DB_BRST_DISABLE, \ + .lpm_notify = false, \ + .offload_channel = false, \ + .doorbell_mode_switch = false, \ + } \ + +#define MHI_CHANNEL_CONFIG_AMSS_SBL_DL(ch_num, ch_name, el_count, ev_ring) \ + { \ + .num = ch_num, \ + .name = ch_name, \ + .num_elements = el_count, \ + .event_ring = ev_ring, \ + .dir = DMA_FROM_DEVICE, \ + .ee_mask = BIT(MHI_EE_SBL) | BIT(MHI_EE_AMSS), \ + .pollcfg = 0, \ + .doorbell = MHI_DB_BRST_DISABLE, \ + .lpm_notify = false, \ + .offload_channel = false, \ + .doorbell_mode_switch = false, \ + } + #define MHI_CHANNEL_CONFIG_UL(ch_num, ch_name, el_count, ev_ring) \ { \ .num = ch_num, \ @@ -538,17 +568,69 @@ static const struct mhi_pci_dev_info mhi_telit_fn980_hw_v1_info = { .sideband_wake = false, }; +static const struct mhi_channel_config mhi_telit_fn980_hw_v2_channels[] = { + MHI_CHANNEL_CONFIG_UL_SBL(2, "SAHARA", 32, 0), + MHI_CHANNEL_CONFIG_DL_SBL(3, "SAHARA", 32, 0), + MHI_CHANNEL_CONFIG_AMSS_SBL_UL(4, "DIAG", 64, 1), + MHI_CHANNEL_CONFIG_AMSS_SBL_DL(5, "DIAG", 64, 1), + MHI_CHANNEL_CONFIG_UL(14, "QMI", 32, 0), + MHI_CHANNEL_CONFIG_DL(15, "QMI", 32, 0), + MHI_CHANNEL_CONFIG_UL(18, "IP_CTRL", 8, 1), + MHI_CHANNEL_CONFIG_DL_AUTOQUEUE(19, "IP_CTRL", 8, 1), + MHI_CHANNEL_CONFIG_UL(20, "IPCR", 16, 0), + MHI_CHANNEL_CONFIG_DL_AUTOQUEUE(21, "IPCR", 16, 0), + MHI_CHANNEL_CONFIG_UL(32, "DUN", 8, 1), + MHI_CHANNEL_CONFIG_DL(33, "DUN", 8, 1), + MHI_CHANNEL_CONFIG_UL(92, "DUN2", 8, 1), + MHI_CHANNEL_CONFIG_DL(93, "DUN2", 8, 1), + MHI_CHANNEL_CONFIG_UL(94, "NMEA", 8, 1), + MHI_CHANNEL_CONFIG_DL(95, "NMEA", 8, 1), + MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0", 128, 2), + MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0", 128, 3), +}; + +static struct mhi_event_config mhi_telit_fn980_hw_v2_events[] = { + MHI_EVENT_CONFIG_CTRL(0, 128), + MHI_EVENT_CONFIG_DATA(1, 128), + MHI_EVENT_CONFIG_HW_DATA(2, 1024, 100), + MHI_EVENT_CONFIG_HW_DATA(3, 2048, 101), +}; + +static struct mhi_controller_config modem_telit_fn980_hw_v2_config = { + .max_channels = 128, + .timeout_ms = 20000, + .num_channels = ARRAY_SIZE(mhi_telit_fn980_hw_v2_channels), + .ch_cfg = mhi_telit_fn980_hw_v2_channels, + .num_events = ARRAY_SIZE(mhi_telit_fn980_hw_v2_events), + .event_cfg = mhi_telit_fn980_hw_v2_events, +}; + +static const struct mhi_pci_dev_info mhi_telit_fn980_hw_v2_info = { + .name = "telit-fn980", + .fw = "qcom/sdx55m/sbl1.mbn", + .edl = "qcom/sdx55m/edl.mbn", + .config = &modem_telit_fn980_hw_v2_config, + .bar_num = MHI_PCI_DEFAULT_BAR_NUM, + .dma_data_width = 32, + .mru_default = 32768, + .sideband_wake = false, +}; + static const struct mhi_channel_config mhi_telit_fn990_channels[] = { MHI_CHANNEL_CONFIG_UL_SBL(2, "SAHARA", 32, 0), MHI_CHANNEL_CONFIG_DL_SBL(3, "SAHARA", 32, 0), - MHI_CHANNEL_CONFIG_UL(4, "DIAG", 64, 1), - MHI_CHANNEL_CONFIG_DL(5, "DIAG", 64, 1), + MHI_CHANNEL_CONFIG_AMSS_SBL_UL(4, "DIAG", 64, 1), + MHI_CHANNEL_CONFIG_AMSS_SBL_DL(5, "DIAG", 64, 1), MHI_CHANNEL_CONFIG_UL(12, "MBIM", 32, 0), MHI_CHANNEL_CONFIG_DL(13, "MBIM", 32, 0), + MHI_CHANNEL_CONFIG_UL(18, "IP_CTRL", 8, 1), + MHI_CHANNEL_CONFIG_DL_AUTOQUEUE(19, "IP_CTRL", 8, 1), MHI_CHANNEL_CONFIG_UL(32, "DUN", 32, 0), MHI_CHANNEL_CONFIG_DL(33, "DUN", 32, 0), MHI_CHANNEL_CONFIG_UL(92, "DUN2", 32, 1), MHI_CHANNEL_CONFIG_DL(93, "DUN2", 32, 1), + MHI_CHANNEL_CONFIG_UL(94, "NMEA", 8, 1), + MHI_CHANNEL_CONFIG_DL(95, "NMEA", 8, 1), MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0_MBIM", 128, 2), MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0_MBIM", 128, 3), }; @@ -582,16 +664,15 @@ static const struct mhi_pci_dev_info mhi_telit_fn990_info = { static const struct pci_device_id mhi_pci_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0304), .driver_data = (kernel_ulong_t) &mhi_qcom_sdx24_info }, - { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, PCI_VENDOR_ID_QCOM, 0x010c), - .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info }, /* EM919x (sdx55), use the same vid:pid as qcom-sdx55m */ { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, 0x18d7, 0x0200), .driver_data = (kernel_ulong_t) &mhi_sierra_em919x_info }, /* Telit FN980 hardware revision v1 */ { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0306, 0x1C5D, 0x2000), .driver_data = (kernel_ulong_t) &mhi_telit_fn980_hw_v1_info }, + /* Modified Qualcomm default entry for FN980 firmware release without Telit SSIDs */ { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0306), - .driver_data = (kernel_ulong_t) &mhi_qcom_sdx55_info }, + .driver_data = (kernel_ulong_t) &mhi_telit_fn980_hw_v2_info }, /* Telit FN990 */ { PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0308, 0x1c5d, 0x2010), .driver_data = (kernel_ulong_t) &mhi_telit_fn990_info }, @@ -859,6 +940,10 @@ static void mhi_pci_recovery_work(struct work_struct *work) mhi_unprepare_after_power_down(mhi_cntrl); } + dev_dbg(&pdev->dev, "Waiting 40 seconds for allowing the modem to restore PCIe\n"); + msleep(40000); + dev_dbg(&pdev->dev, "Restoring PCI saved state\n"); + pci_set_power_state(pdev, PCI_D0); pci_load_saved_state(pdev, mhi_pdev->pci_state); pci_restore_state(pdev); @@ -896,6 +981,18 @@ static void health_check(struct timer_list *t) test_bit(MHI_PCI_DEV_SUSPENDED, &mhi_pdev->status)) return; + if (mhi_cntrl->xfp == XFP_STATE_FLASHING) { + mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD); + return; + } + + if (mhi_cntrl->xfp == XFP_STATE_NEED_RESET) { + mhi_cntrl->xfp = XFP_STATE_IDLE; + dev_dbg(mhi_cntrl->cntrl_dev, "Device needs to be resetted EE = %d\n", mhi_cntrl->ee); + queue_work(system_long_wq, &mhi_pdev->recovery_work); + return; + } + if (!mhi_pci_is_alive(mhi_cntrl)) { dev_err(mhi_cntrl->cntrl_dev, "Device died\n"); queue_work(system_long_wq, &mhi_pdev->recovery_work); diff --git a/drivers/bus/mhi/host/pm.c b/drivers/bus/mhi/host/pm.c index 8a4362d75fc43..5590be89b6fdb 100644 --- a/drivers/bus/mhi/host/pm.c +++ b/drivers/bus/mhi/host/pm.c @@ -1208,10 +1208,11 @@ int mhi_sync_power_up(struct mhi_controller *mhi_cntrl) wait_event_timeout(mhi_cntrl->state_event, MHI_IN_MISSION_MODE(mhi_cntrl->ee) || + mhi_cntrl->ee == MHI_EE_SBL || MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state), msecs_to_jiffies(mhi_cntrl->timeout_ms)); - ret = (MHI_IN_MISSION_MODE(mhi_cntrl->ee)) ? 0 : -ETIMEDOUT; + ret = (MHI_IN_MISSION_MODE(mhi_cntrl->ee) || mhi_cntrl->ee == MHI_EE_SBL) ? 0 : -ETIMEDOUT; if (ret) mhi_power_down(mhi_cntrl, false); diff --git a/drivers/net/wwan/Kconfig b/drivers/net/wwan/Kconfig index 410b0245114e8..66794849b5324 100644 --- a/drivers/net/wwan/Kconfig +++ b/drivers/net/wwan/Kconfig @@ -39,6 +39,7 @@ config WWAN_HWSIM config MHI_WWAN_CTRL tristate "MHI WWAN control driver for QCOM-based PCIe modems" depends on MHI_BUS + select MHI_WWAN_DTR help MHI WWAN CTRL allows QCOM-based PCIe modems to expose different modem control protocols/ports to userspace, including AT, MBIM, QMI, DIAG @@ -49,6 +50,16 @@ config MHI_WWAN_CTRL To compile this driver as a module, choose M here: the module will be called mhi_wwan_ctrl. +config MHI_WWAN_DTR + tristate "MHI WWAN DTR driver for QCOM-based PCIe modems" + depends on MHI_BUS + help + MHI WWAN DTR allows to set DTR and RTS signals on QCOM-based PCIe + DUN ports. + + To compile this driver as a module, choose M here: the module will be + called mhi_wwan_dtr. + config MHI_WWAN_MBIM tristate "MHI WWAN MBIM network driver for QCOM-based PCIe modems" depends on MHI_BUS diff --git a/drivers/net/wwan/Makefile b/drivers/net/wwan/Makefile index 3960c0ae2445c..c37396680f330 100644 --- a/drivers/net/wwan/Makefile +++ b/drivers/net/wwan/Makefile @@ -8,6 +8,7 @@ wwan-objs += wwan_core.o obj-$(CONFIG_WWAN_HWSIM) += wwan_hwsim.o +obj-$(CONFIG_MHI_WWAN_DTR) += mhi_wwan_dtr.o obj-$(CONFIG_MHI_WWAN_CTRL) += mhi_wwan_ctrl.o obj-$(CONFIG_MHI_WWAN_MBIM) += mhi_wwan_mbim.o obj-$(CONFIG_QCOM_BAM_DMUX) += qcom_bam_dmux.o diff --git a/drivers/net/wwan/mhi_wwan_ctrl.c b/drivers/net/wwan/mhi_wwan_ctrl.c index e9f979d2d851f..2f2777f2b28bd 100644 --- a/drivers/net/wwan/mhi_wwan_ctrl.c +++ b/drivers/net/wwan/mhi_wwan_ctrl.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2021, Linaro Ltd */ +/* Copyright (c) 2023, Linaro Ltd */ #include #include #include @@ -104,6 +104,8 @@ static void mhi_wwan_ctrl_refill_work(struct work_struct *work) } } +int mhi_wwan_dtr_set(struct wwan_port *port, int dtr, int rts); + static int mhi_wwan_ctrl_start(struct wwan_port *port) { struct mhi_wwan_dev *mhiwwan = wwan_port_get_drvdata(port); @@ -123,6 +125,11 @@ static int mhi_wwan_ctrl_start(struct wwan_port *port) mhi_wwan_ctrl_refill_work(&mhiwwan->rx_refill); } + if (wwan_port_get_type(port) == WWAN_PORT_AT) { + dev_dbg(&mhiwwan->mhi_dev->dev, "Setting DTR and RTS for port\n"); + mhi_wwan_dtr_set(port, 1, 1); + } + return 0; } @@ -130,6 +137,11 @@ static void mhi_wwan_ctrl_stop(struct wwan_port *port) { struct mhi_wwan_dev *mhiwwan = wwan_port_get_drvdata(port); + if (wwan_port_get_type(port) == WWAN_PORT_AT) { + dev_dbg(&mhiwwan->mhi_dev->dev, "Unsetting DTR and RTS for port\n"); + mhi_wwan_dtr_set(port, 0, 0); + } + spin_lock_bh(&mhiwwan->rx_lock); clear_bit(MHI_WWAN_RX_REFILL, &mhiwwan->flags); spin_unlock_bh(&mhiwwan->rx_lock); @@ -263,6 +275,8 @@ static const struct mhi_device_id mhi_wwan_ctrl_match_table[] = { { .chan = "QMI", .driver_data = WWAN_PORT_QMI }, { .chan = "DIAG", .driver_data = WWAN_PORT_QCDM }, { .chan = "FIREHOSE", .driver_data = WWAN_PORT_FIREHOSE }, + { .chan = "SAHARA", .driver_data = WWAN_PORT_SAHARA }, + { .chan = "NMEA", .driver_data = WWAN_PORT_NMEA }, {}, }; MODULE_DEVICE_TABLE(mhi, mhi_wwan_ctrl_match_table); diff --git a/drivers/net/wwan/mhi_wwan_dtr.c b/drivers/net/wwan/mhi_wwan_dtr.c new file mode 100644 index 0000000000000..961e982bc7099 --- /dev/null +++ b/drivers/net/wwan/mhi_wwan_dtr.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2023, Daniele Palmas */ +#include +#include +#include +#include +#include + +struct mhi_wwan_dev { + struct mhi_device *mhi_dev; +}; + +int mhi_wwan_dtr_set(struct wwan_port *port, int dtr, int rts) +{ + struct mhi_wwan_dev *mhiwwan = wwan_port_get_drvdata(port); + int ret; + + if (mhiwwan->mhi_dev->mhi_cntrl->mhi_dev_ip_ctrl) { + struct __packed dtr_ctrl_msg { + u32 preamble; + u32 msg_id; + u32 dest_id; + u32 size; + u32 msg; + }; + + struct dtr_ctrl_msg dtr_msg = {0}; + struct sk_buff *skb; + + dtr_msg.preamble = 0x4C525443; + dtr_msg.msg_id = 0x10; + dtr_msg.dest_id = mhiwwan->mhi_dev->ul_chan_id; + dtr_msg.size = sizeof(u32); + if (dtr) + dtr_msg.msg |= BIT(0); + if (rts) + dtr_msg.msg |= BIT(1); + skb = alloc_skb(sizeof(dtr_msg), GFP_KERNEL); + skb_put_data(skb, &dtr_msg, sizeof(dtr_msg)); + dev_dbg(&mhiwwan->mhi_dev->mhi_cntrl->mhi_dev_ip_ctrl->dev, "Queuing DTR skb %u...\n", skb->len); + ret = mhi_queue_skb(mhiwwan->mhi_dev->mhi_cntrl->mhi_dev_ip_ctrl, DMA_TO_DEVICE, skb, skb->len, MHI_EOT); + if (ret) { + dev_dbg(&mhiwwan->mhi_dev->mhi_cntrl->mhi_dev_ip_ctrl->dev, "Unable to send UART signals\n"); + kfree_skb(skb); + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(mhi_wwan_dtr_set); + +static int mhi_wwan_dtr_start(struct wwan_port *port) +{ + return 0; +} + +static void mhi_wwan_dtr_stop(struct wwan_port *port) +{ +} + +static int mhi_wwan_dtr_tx(struct wwan_port *port, struct sk_buff *skb) +{ + struct mhi_wwan_dev *mhiwwan = wwan_port_get_drvdata(port); + + /* Queue the packet for MHI transfer */ + return mhi_queue_skb(mhiwwan->mhi_dev, DMA_TO_DEVICE, skb, skb->len, MHI_EOT); +} + +static const struct wwan_port_ops wwan_pops = { + .start = mhi_wwan_dtr_start, + .stop = mhi_wwan_dtr_stop, + .tx = mhi_wwan_dtr_tx, +}; + +static void mhi_dtr_ul_xfer_cb(struct mhi_device *mhi_dev, + struct mhi_result *mhi_result) +{ + struct sk_buff *skb = mhi_result->buf_addr; + + dev_dbg(&mhi_dev->dev, "%s: status: %d xfer_len: %zu\n", __func__, + mhi_result->transaction_status, mhi_result->bytes_xferd); + + /* MHI core has done with the buffer, release it */ + consume_skb(skb); +} + +static void mhi_dtr_dl_xfer_cb(struct mhi_device *mhi_dev, + struct mhi_result *mhi_result) +{ + /* Currently we don't use the information provided by the modem */ + dev_dbg(&mhi_dev->dev, "%s: status: %d receive_len: %zu\n", __func__, + mhi_result->transaction_status, mhi_result->bytes_xferd); +} + +static int mhi_wwan_dtr_probe(struct mhi_device *mhi_dev, + const struct mhi_device_id *id) +{ + struct mhi_wwan_dev *mhiwwan; + + mhiwwan = kzalloc(sizeof(*mhiwwan), GFP_KERNEL); + if (!mhiwwan) + return -ENOMEM; + + mhiwwan->mhi_dev = mhi_dev; + + dev_set_drvdata(&mhi_dev->dev, mhiwwan); + + /* Start mhi device's channel(s) */ + return mhi_prepare_for_transfer_autoqueue(mhiwwan->mhi_dev); +}; + +static void mhi_wwan_dtr_remove(struct mhi_device *mhi_dev) +{ + struct mhi_wwan_dev *mhiwwan = dev_get_drvdata(&mhi_dev->dev); + + mhi_unprepare_from_transfer(mhiwwan->mhi_dev); + + kfree(mhiwwan); +} + +static const struct mhi_device_id mhi_wwan_dtr_match_table[] = { + { .chan = "IP_CTRL", .driver_data = 0 }, + {} +}; +MODULE_DEVICE_TABLE(mhi, mhi_wwan_dtr_match_table); + +static struct mhi_driver mhi_wwan_dtr_simple_driver = { + .id_table = mhi_wwan_dtr_match_table, + .remove = mhi_wwan_dtr_remove, + .probe = mhi_wwan_dtr_probe, + .ul_xfer_cb = mhi_dtr_ul_xfer_cb, + .dl_xfer_cb = mhi_dtr_dl_xfer_cb, + .driver = { + .name = "mhi_wwan_dtr_simple", + }, +}; + +module_mhi_driver(mhi_wwan_dtr_simple_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MHI WWAN DTR Simple Driver"); +MODULE_AUTHOR("Daniele Palmas "); diff --git a/drivers/net/wwan/wwan_core.c b/drivers/net/wwan/wwan_core.c index 284ab1f56391a..4c3c6da0572d9 100644 --- a/drivers/net/wwan/wwan_core.c +++ b/drivers/net/wwan/wwan_core.c @@ -327,6 +327,14 @@ static const struct { .name = "XMMRPC", .devsuf = "xmmrpc", }, + [WWAN_PORT_SAHARA] = { + .name = "SAHARA", + .devsuf = "sahara", + }, + [WWAN_PORT_NMEA] = { + .name = "NMEA", + .devsuf = "nmea", + }, }; static ssize_t type_show(struct device *dev, struct device_attribute *attr, @@ -553,6 +561,12 @@ void *wwan_port_get_drvdata(struct wwan_port *port) } EXPORT_SYMBOL_GPL(wwan_port_get_drvdata); +enum wwan_port_type wwan_port_get_type(struct wwan_port *port) +{ + return port->type; +} +EXPORT_SYMBOL_GPL(wwan_port_get_type); + static int wwan_port_op_start(struct wwan_port *port) { int ret = 0; diff --git a/include/linux/mhi.h b/include/linux/mhi.h index 039943ec4d4e7..13d858c143e3c 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -286,6 +286,18 @@ struct mhi_controller_config { bool m2_no_db; }; +/** + * enum xfp_state - xfp flashing state + * @XFP_STATE_IDLE: not flashing + * @XFP_STATE_FLASHING: flashing + * @XFP_STATE_NEED_RESET: mhi stack needs to be resetted + */ +enum xfp_state { + XFP_STATE_IDLE = 0x0, + XFP_STATE_FLASHING = 0x1, + XFP_STATE_NEED_RESET = 0x2, +}; + /** * struct mhi_controller - Master MHI controller structure * @cntrl_dev: Pointer to the struct device of physical bus acting as the MHI @@ -361,6 +373,7 @@ struct mhi_controller_config { * @fbc_download: MHI host needs to do complete image transfer (optional) * @wake_set: Device wakeup set flag * @irq_flags: irq flags passed to request_irq (optional) + * @xfp: xfp state used for flashing * @mru: the default MRU for the MHI device * * Fields marked as (required) need to be populated by the controller driver @@ -380,6 +393,8 @@ struct mhi_controller { struct device *cntrl_dev; struct mhi_device *mhi_dev; struct dentry *debugfs_dentry; + /* Reference to ip_ctrl device for managing DUN signals */ + struct mhi_device *mhi_dev_ip_ctrl; void __iomem *regs; void __iomem *bhi; void __iomem *bhie; @@ -458,6 +473,8 @@ struct mhi_controller { bool wake_set; unsigned long irq_flags; u32 mru; + /* Flag to manage flashing status */ + enum xfp_state xfp; }; /** diff --git a/include/linux/wwan.h b/include/linux/wwan.h index 01fa15506286d..d7ffdbcce2d82 100644 --- a/include/linux/wwan.h +++ b/include/linux/wwan.h @@ -28,6 +28,8 @@ enum wwan_port_type { WWAN_PORT_QCDM, WWAN_PORT_FIREHOSE, WWAN_PORT_XMMRPC, + WWAN_PORT_SAHARA, + WWAN_PORT_NMEA, /* Add new port types above this line */ @@ -141,6 +143,12 @@ void wwan_port_txon(struct wwan_port *port); */ void *wwan_port_get_drvdata(struct wwan_port *port); +/** + * wwan_port_get_type - Retrieve the WWAN port type + * @port: Related WWAN port + */ +enum wwan_port_type wwan_port_get_type(struct wwan_port *port); + /** * struct wwan_netdev_priv - WWAN core network device private data * @link_id: WWAN device data link id