static void mdm_image_upgrade(struct mdm_modem_drv *mdm_drv, int type) { switch (type) { case APQ_CONTROLLED_UPGRADE: pr_info("%s: id %d: APQ controlled modem image upgrade\n", __func__, mdm_drv->device_id); atomic_set(&mdm_drv->mdm_ready, 0); mdm_toggle_soft_reset(mdm_drv); break; case MDM_CONTROLLED_UPGRADE: pr_info("%s: id %d: MDM controlled modem image upgrade\n", __func__, mdm_drv->device_id); atomic_set(&mdm_drv->mdm_ready, 0); /* * If we have no image currently present on the modem, then we * would be in PBL, in which case the status gpio would not go * high. */ mdm_drv->disable_status_check = 1; if (GPIO_IS_VALID(MDM_GPIO(USB_SW))) { pr_debug("%s: id %d: Switching usb control to MDM\n", __func__, mdm_drv->device_id); gpio_direction_output(MDM_GPIO(USB_SW), 1); } else pr_err("%s: id %d: usb switch gpio unavailable\n", __func__, mdm_drv->device_id); break; default: pr_err("%s: id %d: invalid upgrade type\n", __func__, mdm_drv->device_id); } }
static void mdm_do_soft_power_on(struct mdm_modem_drv *mdm_drv) { #ifdef USE_MDM_MODEM int i; int pblrdy; #endif pr_err("%s: id %d: soft resetting mdm modem\n", __func__, mdm_drv->device_id); mdm_peripheral_disconnect(mdm_drv); mdm_toggle_soft_reset(mdm_drv); #ifdef USE_MDM_MODEM if (!GPIO_IS_VALID(MDM_GPIO(MDM2AP_PBLRDY))) goto start_mdm_peripheral; for (i = 0; i < MDM_PBLRDY_CNT; i++) { pblrdy = gpio_get_value(MDM_GPIO(MDM2AP_PBLRDY)); if (pblrdy) break; usleep_range(5000, 5000); } pr_info("%s: id %d: pblrdy i:%d\n", __func__, mdm_drv->device_id, i); start_mdm_peripheral: #endif mdm_peripheral_connect(mdm_drv); msleep(200); }
static void mdm_power_on_common(struct mdm_modem_drv *mdm_drv) { mdm_drv->power_on_count++; /* this gpio will be used to indicate apq readiness, * de-assert it now so that it can be asserted later. * May not be used. */ pr_err("%s \n", __func__); if (GPIO_IS_VALID(MDM_GPIO(AP2MDM_CHNLRDY))) gpio_direction_output(MDM_GPIO(AP2MDM_CHNLRDY), 0); /* * If we did an "early power on" then ignore the very next * power-on request because it would the be first request from * user space but we're already powered on. Ignore it. */ if (mdm_drv->pdata->early_power_on && (mdm_drv->power_on_count == 2)) return; if(poweroff_charging){ pr_debug("%s: do not power on in lpm\n", __func__); return; } if (mdm_drv->power_on_count == 1) mdm_do_first_power_on(mdm_drv); else mdm_do_soft_power_on(mdm_drv); }
/* This function can be called from atomic context. */ static void mdm_toggle_soft_reset(struct mdm_modem_drv *mdm_drv) { int soft_reset_direction_assert = 0, soft_reset_direction_de_assert = 1; if (mdm_drv->pdata->soft_reset_inverted) { soft_reset_direction_assert = 1; soft_reset_direction_de_assert = 0; } #if 0// TD_CDMA gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio, soft_reset_direction_assert); /* Use mdelay because this function can be called from atomic * context. */ mdelay(10); gpio_direction_output(mdm_drv->ap2mdm_soft_reset_gpio, soft_reset_direction_de_assert); #endif//TD_CDMA gpio_direction_output(MDM_GPIO(AP2MDM_SOFT_RESET), soft_reset_direction_assert); mdelay(10); mdm_do_clean_reset(mdm_drv); gpio_direction_output(MDM_GPIO(AP2MDM_SOFT_RESET), soft_reset_direction_de_assert); gpio_direction_output(MDM_GPIO(AP2MDM_KPDPWR), 1); mdelay(1000); gpio_direction_output(MDM_GPIO(AP2MDM_KPDPWR), 0); }
/* Fail if any of the required gpios is absent. */ static int mdm_dt_parse_gpios(struct mdm_ctrl *mdm) { int i, val, rc = 0; struct device_node *node = mdm->dev->of_node; enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW; for (i = 0; i < NUM_GPIOS; i++) mdm->gpios[i] = INVALID_GPIO; for (i = 0; i < ARRAY_SIZE(gpio_map); i++) { val = of_get_named_gpio(node, gpio_map[i].name, 0); if (val >= 0) MDM_GPIO(mdm, gpio_map[i].index) = val; } /* These two are special because they can be inverted. */ val = of_get_named_gpio_flags(node, "qcom,ap2mdm-soft-reset-gpio", 0, &flags); if (val >= 0) { MDM_GPIO(mdm, AP2MDM_SOFT_RESET) = val; if (flags & OF_GPIO_ACTIVE_LOW) mdm->soft_reset_inverted = 1; } /* Verify that the required gpios have valid values */ for (i = 0; i < ARRAY_SIZE(required_gpios); i++) { if (MDM_GPIO(mdm, required_gpios[i]) == INVALID_GPIO) { rc = -ENXIO; break; } } mdm_debug_gpio_show(mdm); return rc; }
static void mdm_set_hsic_ready(struct esoc_clink *esoc) { struct mdm_ctrl *mdm = get_esoc_clink_data(esoc); gpio_set_value(MDM_GPIO(mdm, AP2MDM_HSIC_READY), 0); msleep(10); gpio_set_value(MDM_GPIO(mdm, AP2MDM_HSIC_READY), 1); }
static void mdm_update_gpio_configs(struct mdm_ctrl *mdm, enum gpio_update_config gpio_config) { struct device *dev = mdm->dev; /* Some gpio configuration may need updating after modem bootup.*/ switch (gpio_config) { case GPIO_UPDATE_RUNNING_CONFIG: if (mdm->mdm2ap_status_gpio_run_cfg) { if (msm_gpiomux_write(MDM_GPIO(mdm, MDM2AP_STATUS), GPIOMUX_ACTIVE, mdm->mdm2ap_status_gpio_run_cfg, &mdm->mdm2ap_status_old_config)) dev_err(dev, "switch to run failed\n"); else mdm->mdm2ap_status_valid_old_config = 1; } break; case GPIO_UPDATE_BOOTING_CONFIG: if (mdm->mdm2ap_status_valid_old_config) { msm_gpiomux_write(MDM_GPIO(mdm, MDM2AP_STATUS), GPIOMUX_ACTIVE, &mdm->mdm2ap_status_old_config, NULL); mdm->mdm2ap_status_valid_old_config = 0; } break; default: dev_err(dev, "%s: called with no config\n", __func__); break; } }
static void mdm_do_first_power_on(struct mdm_ctrl *mdm) { int i; int pblrdy; struct device *dev = mdm->dev; dev_info(dev, "Powering on modem for the first time\n"); mdm_toggle_soft_reset(mdm); /* Add a delay to allow PON sequence to complete*/ msleep(50); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_STATUS), 1); for (i = 0; i < MDM_PBLRDY_CNT; i++) { pblrdy = gpio_get_value(MDM_GPIO(mdm, MDM2AP_PBLRDY)); if (pblrdy) break; usleep_range(5000, 6000); } dev_info(dev, "pblrdy i:%d\n", i); if (pmdata_gpio_host_ready) { dev_info(dev, "Set qcom,ap2mdm-hostrdy-gpio to 1\n"); gpio_direction_output(pmdata_gpio_host_ready, 1); gpio_set_value(pmdata_gpio_host_ready, 1); } else { dev_info(dev, "Fail to set gpio pin qcom,ap2mdm-hostrdy-gpio\n"); } msleep(200); }
static irqreturn_t mdm_errfatal(int irq, void *dev_id) { struct mdm_ctrl *mdm = (struct mdm_ctrl *)dev_id; struct esoc_clink *esoc; struct device *dev; if (!mdm) goto no_mdm_irq; dev = mdm->dev; if (!mdm->ready) goto mdm_pwroff_irq; esoc = mdm->esoc; if(!gpio_get_value(MDM_GPIO(mdm, MDM2AP_ERRFATAL)) || !gpio_get_value(MDM_GPIO(mdm, MDM2AP_VDDMIN))) { dev_err(dev, "%s: ignore IRQ errfatal: %d, vddmin: %d\n", __func__, gpio_get_value(MDM_GPIO(mdm, MDM2AP_ERRFATAL)), gpio_get_value(MDM_GPIO(mdm, MDM2AP_VDDMIN))); return IRQ_HANDLED; } dev_err(dev, "%s: mdm sent errfatal interrupt\n", __func__); dev_err(dev, "%s: ep0_timeout: %d\n", __func__, ep0_timeout_cnt); exynos_pcie_dump_link_down_status(0); /* disable irq ?*/ esoc_clink_evt_notify(ESOC_ERR_FATAL, esoc); mdm_fatal_debug_gpio_show(mdm); return IRQ_HANDLED; mdm_pwroff_irq: dev_info(dev, "errfatal irq when in pwroff\n"); no_mdm_irq: return IRQ_HANDLED; }
void set_ap2mdm_errfatal(void) { pr_info("[MIF] AP2MDM_ERRFATAL high!!\n"); if(!g_mdm) { pr_err("[MIF] %s, esoc driver is not initialized\n", __func__); return; } gpio_set_value(MDM_GPIO(g_mdm, AP2MDM_ERRFATAL), 1); gpio_set_value(MDM_GPIO(g_mdm, AP2MDM_VDDMIN), 1); }
static void mdm_fatal_debug_gpio_show(struct mdm_ctrl *mdm) { struct device *dev = mdm->dev; dev_err(dev, "%s: MDM2AP_ERRFATAL %d\n", __func__, gpio_get_value(MDM_GPIO(mdm, MDM2AP_ERRFATAL))); dev_err(dev, "%s: AP2MDM_ERRFATAL %d\n", __func__, gpio_get_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL))); dev_err(dev, "%s: MDM2AP_STATUS %d\n", __func__, gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS))); dev_err(dev, "%s: AP2MDM_STATUS %d\n", __func__, gpio_get_value(MDM_GPIO(mdm, AP2MDM_STATUS))); }
static void mdm_deconfigure_ipc(struct mdm_ctrl *mdm) { int i; for (i = 0; i < NUM_GPIOS; ++i) { if (gpio_is_valid(MDM_GPIO(mdm, i))) gpio_free(MDM_GPIO(mdm, i)); } if (mdm->mdm_queue) { destroy_workqueue(mdm->mdm_queue); mdm->mdm_queue = NULL; } }
int mdm_get_fatal_status(void) { if(!g_mdm) { pr_err("[MIF] %s, esoc driver is not initialized\n", __func__); return 1; } if(gpio_get_value(MDM_GPIO(g_mdm, MDM2AP_ERRFATAL))) return 1; if(gpio_get_value(MDM_GPIO(g_mdm, MDM2AP_STATUS)) == 0) return 1; return 0; }
static irqreturn_t mdm_status_change(int irq, void *dev_id) { int value; struct esoc_clink *esoc; struct mdm_ctrl *mdm = (struct mdm_ctrl *)dev_id; struct device *dev; if (!mdm) return IRQ_HANDLED; dev = mdm->dev; esoc = mdm->esoc; value = gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS)); if (value == 0 && mdm->ready) { dev_err(dev, "unexpected reset external modem\n"); esoc_clink_evt_notify(ESOC_UNEXPECTED_RESET, esoc); } else if (value == 1) { cancel_delayed_work(&mdm->mdm2ap_status_check_work); dev_info(dev, "status = 1: mdm is now ready\n"); mdm->ready = true; queue_work(mdm->mdm_queue, &mdm->mdm_status_work); if (mdm->get_restart_reason) queue_work(mdm->mdm_queue, &mdm->restart_reason_work); } return IRQ_HANDLED; }
static void mdm_status_changed(struct mdm_modem_drv *mdm_drv, int value) { if (!mdm_drv->pdata->peripheral_platform_device) return; pr_debug("%s: id %d: value:%d\n", __func__, value, mdm_drv->device_id); if (value) { mdm_peripheral_disconnect(mdm_drv); msleep(100); mdm_peripheral_connect(mdm_drv); if (GPIO_IS_VALID(MDM_GPIO(AP2MDM_WAKEUP))) gpio_direction_output(MDM_GPIO(AP2MDM_WAKEUP), 1); } }
static void mdm_power_down(struct mdm_ctrl *mdm) { struct device *dev = mdm->dev; int soft_reset_direction = mdm->soft_reset_inverted ? 1 : 0; /* Assert the soft reset line whether mdm2ap_status went low or not */ gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), soft_reset_direction); dev_info(dev, "Doing a hard reset\n"); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), soft_reset_direction); /* * Currently, there is a debounce timer on the charm PMIC. It is * necessary to hold the PMIC RESET low for 400ms * for the reset to fully take place. Sleep here to ensure the * reset has occured before the function exits. */ msleep(400); }
/* This function can be called from atomic context. */ static void mdm_toggle_soft_reset(struct mdm_ctrl *mdm) { int soft_reset_direction_assert = 0, soft_reset_direction_de_assert = 1; if (mdm->soft_reset_inverted) { soft_reset_direction_assert = 1; soft_reset_direction_de_assert = 0; } gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), soft_reset_direction_assert); /* * Allow PS hold assert to be detected */ usleep_range(8000, 9000); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), soft_reset_direction_de_assert); }
int mdm_get_modem_status(void) { if(!g_mdm) { pr_err("[MIF] %s, esoc driver is not initialized\n", __func__); return 1; } return gpio_get_value(MDM_GPIO(g_mdm, MDM2AP_STATUS)); }
static void mdm_do_clean_reset(struct mdm_modem_drv *mdm_drv) { /* mdm clean reset * * Shutdown PMIC and up if needed */ #if 0 // no need workardoun code. if (mdm_drv->need_clean_reset) { gpio_direction_output(MDM_GPIO(AP2MDM_PMIC_PWR_EN), 0); mdelay(10); gpio_direction_output(MDM_GPIO(AP2MDM_PMIC_PWR_EN), 1); mdelay(10); mdm_drv->need_clean_reset = false; } #endif }
/* This function can be called from atomic context. */ static void mdm_toggle_soft_reset(struct mdm_modem_drv *mdm_drv) { int soft_reset_direction_assert = 0, soft_reset_direction_de_assert = 1; if (mdm_drv->pdata->soft_reset_inverted) { soft_reset_direction_assert = 1; soft_reset_direction_de_assert = 0; } gpio_direction_output(MDM_GPIO(AP2MDM_SOFT_RESET), soft_reset_direction_assert); /* Use mdelay because this function can be called from atomic * context. */ mdelay(10); gpio_direction_output(MDM_GPIO(AP2MDM_SOFT_RESET), soft_reset_direction_de_assert); }
static int mdm_get_status(u32 *status, struct esoc_clink *esoc) { struct mdm_ctrl *mdm = get_esoc_clink_data(esoc); if (gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS)) == 0) *status = 0; else *status = 1; return 0; }
static void mdm_status_fn(struct work_struct *work) { struct mdm_ctrl *mdm = container_of(work, struct mdm_ctrl, mdm_status_work); struct device *dev = mdm->dev; int value = gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS)); dev_info(dev, "%s: status:%d\n", __func__, value); /* Update gpio configuration to "running" config. */ mdm_update_gpio_configs(mdm, GPIO_UPDATE_RUNNING_CONFIG); }
static void mdm2ap_status_check(struct work_struct *work) { struct mdm_ctrl *mdm = container_of(work, struct mdm_ctrl, mdm2ap_status_check_work.work); struct device *dev = mdm->dev; struct esoc_clink *esoc = mdm->esoc; if (gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS)) == 0) { dev_dbg(dev, "MDM2AP_STATUS did not go high\n"); esoc_clink_evt_notify(ESOC_UNEXPECTED_RESET, esoc); } }
static void mdm_do_first_power_on(struct mdm_modem_drv *mdm_drv) { int i; int pblrdy; if (mdm_drv->power_on_count != 1) { pr_debug("%s:id %d: Calling fn when power_on_count != 1\n", __func__, mdm_drv->device_id); return; } pr_debug("%s:id %d: Powering on modem for the first time\n", __func__, mdm_drv->device_id); mdm_peripheral_disconnect(mdm_drv); /* If this is the first power-up after a panic, the modem may still * be in a power-on state, in which case we need to toggle the gpio * instead of just de-asserting it. No harm done if the modem was * powered down. */ if (!mdm_drv->pdata->no_reset_on_first_powerup) mdm_toggle_soft_reset(mdm_drv); /* If the device has a kpd pwr gpio then toggle it. */ if (GPIO_IS_VALID(MDM_GPIO(AP2MDM_KPDPWR))) { /* Pull AP2MDM_KPDPWR gpio high and wait for PS_HOLD to settle, * then pull it back low. */ pr_debug("%s:id %d: Pulling AP2MDM_KPDPWR gpio high\n", __func__, mdm_drv->device_id); gpio_direction_output(MDM_GPIO(AP2MDM_KPDPWR), 1); gpio_direction_output(MDM_GPIO(AP2MDM_STATUS), 1); msleep(1000); gpio_direction_output(MDM_GPIO(AP2MDM_KPDPWR), 0); } else { gpio_direction_output(MDM_GPIO(AP2MDM_STATUS), 1); } if (!GPIO_IS_VALID(MDM_GPIO(MDM2AP_PBLRDY))) goto start_mdm_peripheral; for (i = 0; i < MDM_PBLRDY_CNT; i++) { pblrdy = gpio_get_value(MDM_GPIO(MDM2AP_PBLRDY)); if (pblrdy) break; usleep_range(5000, 5000); } pr_debug("%s: id %d: pblrdy i:%d\n", __func__, mdm_drv->device_id, i); start_mdm_peripheral: mdm_peripheral_connect(mdm_drv); msleep(200); }
static void mdm_status_fn(struct work_struct *work) { struct mdm_ctrl *mdm = container_of(work, struct mdm_ctrl, mdm_status_work); struct device *dev = mdm->dev; int value = gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS)); dev_info(dev, "%s: status:%d\n", __func__, value); #if defined(CONFIG_MDM_HSIC_PM) request_active_lock_set(rmnet_pm_dev); #endif /* Update gpio configuration to "running" config. */ mdm_update_gpio_configs(mdm, GPIO_UPDATE_RUNNING_CONFIG); }
static void mdm_power_down_common(struct mdm_modem_drv *mdm_drv) { int i = 0; int soft_reset_direction = mdm_drv->pdata->soft_reset_inverted ? 1 : 0; mdm_peripheral_disconnect(mdm_drv); #if 0 // because we don't use the graceful shutdown function, we don't need this checking /* Wait for the modem to complete its power down actions. */ for (i = 20; i > 0; i--) { if (gpio_get_value(MDM_GPIO(MDM2AP_STATUS)) == 0) { if (mdm_debug_mask & MDM_DEBUG_MASK_SHDN_LOG) pr_debug("%s:id %d: mdm2ap_statuswent low, i=%d\n", __func__, mdm_drv->device_id, i); break; } msleep(100); } #endif /* Assert the soft reset line whether mdm2ap_status went low or not */ gpio_direction_output(MDM_GPIO(AP2MDM_SOFT_RESET), soft_reset_direction); if (i == 0) { pr_debug("%s:id %d: MDM2AP_STATUS never went low. Doing a hard reset\n", __func__, mdm_drv->device_id); gpio_direction_output(MDM_GPIO(AP2MDM_SOFT_RESET), soft_reset_direction); } /* * Currently, there is a debounce timer on the charm PMIC. It is * necessary to hold the PMIC RESET low for ~3.5 seconds * for the reset to fully take place. Sleep here to ensure the * reset has occured before the function exits. */ msleep(4000); }
static irqreturn_t mdm_pblrdy_change(int irq, void *dev_id) { struct mdm_ctrl *mdm; struct device *dev; struct esoc_clink *esoc; mdm = (struct mdm_ctrl *)dev_id; if (!mdm) return IRQ_HANDLED; esoc = mdm->esoc; dev = mdm->dev; dev_dbg(dev, "pbl ready %d:\n", gpio_get_value(MDM_GPIO(mdm, MDM2AP_PBLRDY))); if (mdm->init) { mdm->init = 0; esoc_clink_queue_request(ESOC_REQ_IMG, esoc); return IRQ_HANDLED; } if (mdm->debug) esoc_clink_queue_request(ESOC_REQ_DEBUG, esoc); return IRQ_HANDLED; }
static int mdm9x35_setup_hw(struct mdm_ctrl *mdm, struct esoc_clink_ops const *ops, struct platform_device *pdev) { int ret; struct device_node *node; struct esoc_clink *esoc; mdm->dev = &pdev->dev; node = pdev->dev.of_node; esoc = devm_kzalloc(mdm->dev, sizeof(*esoc), GFP_KERNEL); if (IS_ERR(esoc)) { dev_err(mdm->dev, "cannot allocate esoc device\n"); return PTR_ERR(esoc); } mdm->mdm_queue = alloc_workqueue("mdm_queue", 0, 0); if (!mdm->mdm_queue) { dev_err(mdm->dev, "could not create mdm_queue\n"); return -ENOMEM; } mdm->irq_mask = 0; mdm->ready = false; ret = mdm_dt_parse_gpios(mdm); if (ret) return ret; dev_dbg(mdm->dev, "parsing gpio done\n"); ret = mdm_configure_ipc(mdm, pdev); if (ret) return ret; dev_dbg(mdm->dev, "ipc configure done\n"); esoc->name = MDM9x35_LABEL; mdm->dual_interface = of_property_read_bool(node, "qcom,mdm-dual-link"); /* Check if link gpio is available */ if (gpio_is_valid(MDM_GPIO(mdm, MDM_LINK_DETECT))) { if (mdm->dual_interface) { if (gpio_get_value(MDM_GPIO(mdm, MDM_LINK_DETECT))) esoc->link_name = MDM9x35_DUAL_LINK; else esoc->link_name = MDM9x35_PCIE; } else { if (gpio_get_value(MDM_GPIO(mdm, MDM_LINK_DETECT))) esoc->link_name = MDM9x35_HSIC; else esoc->link_name = MDM9x35_PCIE; } } else if (mdm->dual_interface) esoc->link_name = MDM9x35_DUAL_LINK; else esoc->link_name = MDM9x35_HSIC; esoc->clink_ops = ops; esoc->parent = mdm->dev; esoc->owner = THIS_MODULE; esoc->np = pdev->dev.of_node; set_esoc_clink_data(esoc, mdm); ret = esoc_clink_register(esoc); if (ret) { dev_err(mdm->dev, "esoc registration failed\n"); return ret; } dev_dbg(mdm->dev, "esoc registration done\n"); init_completion(&mdm->debug_done); INIT_WORK(&mdm->mdm_status_work, mdm_status_fn); INIT_WORK(&mdm->restart_reason_work, mdm_get_restart_reason); INIT_DELAYED_WORK(&mdm->mdm2ap_status_check_work, mdm2ap_status_check); mdm->get_restart_reason = false; mdm->debug_fail = false; mdm->esoc = esoc; mdm->init = 0; return 0; }
static int mdm_configure_ipc(struct mdm_ctrl *mdm, struct platform_device *pdev) { int ret = -1; int irq; struct device *dev = mdm->dev; struct device_node *node = pdev->dev.of_node; ret = of_property_read_u32(node, "qcom,ramdump-timeout-ms", &mdm->dump_timeout_ms); if (ret) mdm->dump_timeout_ms = DEF_RAMDUMP_TIMEOUT; ret = of_property_read_u32(node, "qcom,ramdump-delay-ms", &mdm->ramdump_delay_ms); if (ret) mdm->ramdump_delay_ms = DEF_RAMDUMP_DELAY; /* Multilple gpio_request calls are allowed */ if (gpio_request(MDM_GPIO(mdm, AP2MDM_STATUS), "AP2MDM_STATUS")) dev_err(dev, "Failed to configure AP2MDM_STATUS gpio\n"); /* Multilple gpio_request calls are allowed */ if (gpio_request(MDM_GPIO(mdm, AP2MDM_ERRFATAL), "AP2MDM_ERRFATAL")) dev_err(dev, "%s Failed to configure AP2MDM_ERRFATAL gpio\n", __func__); if (gpio_request(MDM_GPIO(mdm, MDM2AP_STATUS), "MDM2AP_STATUS")) { dev_err(dev, "%s Failed to configure MDM2AP_STATUS gpio\n", __func__); goto fatal_err; } if (gpio_request(MDM_GPIO(mdm, MDM2AP_ERRFATAL), "MDM2AP_ERRFATAL")) { dev_err(dev, "%s Failed to configure MDM2AP_ERRFATAL gpio\n", __func__); goto fatal_err; } if (gpio_is_valid(MDM_GPIO(mdm, MDM2AP_PBLRDY))) { if (gpio_request(MDM_GPIO(mdm, MDM2AP_PBLRDY), "MDM2AP_PBLRDY")) { dev_err(dev, "Cannot configure MDM2AP_PBLRDY gpio\n"); goto fatal_err; } } if (gpio_is_valid(MDM_GPIO(mdm, AP2MDM_SOFT_RESET))) { if (gpio_request(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), "AP2MDM_SOFT_RESET")) { dev_err(dev, "Cannot config AP2MDM_SOFT_RESET gpio\n"); goto fatal_err; } } if (gpio_is_valid(MDM_GPIO(mdm, AP2MDM_WAKEUP))) { if (gpio_request(MDM_GPIO(mdm, AP2MDM_WAKEUP), "AP2MDM_WAKEUP")) { dev_err(dev, "Cannot configure AP2MDM_WAKEUP gpio\n"); goto fatal_err; } } if (gpio_is_valid(MDM_GPIO(mdm, AP2MDM_CHNLRDY))) { if (gpio_request(MDM_GPIO(mdm, AP2MDM_CHNLRDY), "AP2MDM_CHNLRDY")) { dev_err(dev, "Cannot configure AP2MDM_CHNLRDY gpio\n"); goto fatal_err; } } ret = of_property_read_u32(node, "qcom,sysmon-subsys-id", &mdm->sysmon_subsys_id); if (ret < 0) dev_info(dev, "sysmon_subsys_id not set.\n"); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_STATUS), 0); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 0); if (gpio_is_valid(MDM_GPIO(mdm, AP2MDM_CHNLRDY))) gpio_direction_output(MDM_GPIO(mdm, AP2MDM_CHNLRDY), 0); gpio_direction_input(MDM_GPIO(mdm, MDM2AP_STATUS)); gpio_direction_input(MDM_GPIO(mdm, MDM2AP_ERRFATAL)); /* ERR_FATAL irq. */ irq = platform_get_irq_byname(pdev, "err_fatal_irq"); if (irq < 0) { dev_err(dev, "bad MDM2AP_ERRFATAL IRQ resource\n"); goto errfatal_err; } ret = request_irq(irq, mdm_errfatal, IRQF_TRIGGER_RISING , "mdm errfatal", mdm); if (ret < 0) { dev_err(dev, "%s: MDM2AP_ERRFATAL IRQ#%d request failed,\n", __func__, irq); goto errfatal_err; } mdm->errfatal_irq = irq; errfatal_err: /* status irq */ irq = platform_get_irq_byname(pdev, "status_irq"); if (irq < 0) { dev_err(dev, "%s: bad MDM2AP_STATUS IRQ resource, err = %d\n", __func__, irq); goto status_err; } ret = request_threaded_irq(irq, NULL, mdm_status_change, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "mdm status", mdm); if (ret < 0) { dev_err(dev, "%s: MDM2AP_STATUS IRQ#%d request failed, err=%d", __func__, irq, ret); goto status_err; } mdm->status_irq = irq; status_err: if (gpio_is_valid(MDM_GPIO(mdm, MDM2AP_PBLRDY))) { irq = platform_get_irq_byname(pdev, "plbrdy_irq"); if (irq < 0) { dev_err(dev, "%s: MDM2AP_PBLRDY IRQ request failed\n", __func__); goto pblrdy_err; } ret = request_threaded_irq(irq, NULL, mdm_pblrdy_change, IRQF_TRIGGER_RISING | IRQF_ONESHOT, "mdm pbl ready", mdm); if (ret < 0) { dev_err(dev, "MDM2AP_PBL IRQ#%d request failed %d\n", irq, ret); goto pblrdy_err; } mdm->pblrdy_irq = irq; } mdm_disable_irqs(mdm); pblrdy_err: return 0; fatal_err: mdm_deconfigure_ipc(mdm); return ret; }
static void mdm_notify(enum esoc_notify notify, struct esoc_clink *esoc) { bool status_down; uint64_t timeout; uint64_t now; struct mdm_ctrl *mdm = get_esoc_clink_data(esoc); struct device *dev = mdm->dev; switch (notify) { case ESOC_IMG_XFER_DONE: dev_info(dev, "%s ESOC_IMG_XFER_DONE\n", __func__); if (gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS)) == 0) schedule_delayed_work(&mdm->mdm2ap_status_check_work, msecs_to_jiffies(MDM2AP_STATUS_TIMEOUT_MS)); break; case ESOC_BOOT_DONE: esoc_clink_evt_notify(ESOC_RUN_STATE, esoc); break; case ESOC_IMG_XFER_RETRY: mdm->init = 1; mdm_toggle_soft_reset(mdm); break; case ESOC_IMG_XFER_FAIL: esoc_clink_evt_notify(ESOC_BOOT_FAIL, esoc); break; case ESOC_UPGRADE_AVAILABLE: break; case ESOC_DEBUG_DONE: mdm->debug_fail = false; mdm_update_gpio_configs(mdm, GPIO_UPDATE_BOOTING_CONFIG); complete(&mdm->debug_done); break; case ESOC_DEBUG_FAIL: mdm->debug_fail = true; complete(&mdm->debug_done); break; case ESOC_PRIMARY_CRASH: mdm_disable_irqs(mdm); status_down = false; dev_info(dev, "signal apq err fatal for graceful restart\n"); gpio_set_value(MDM_GPIO(mdm, AP2MDM_ERRFATAL), 1); timeout = local_clock(); do_div(timeout, NSEC_PER_MSEC); timeout += MDM_MODEM_TIMEOUT; do { if (gpio_get_value(MDM_GPIO(mdm, MDM2AP_STATUS)) == 0) { status_down = true; break; } now = local_clock(); do_div(now, NSEC_PER_MSEC); } while (!time_after64(now, timeout)); if (!status_down) { dev_err(mdm->dev, "%s MDM2AP status did not go low\n", __func__); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), !!mdm->soft_reset_inverted); /* * allow PS hold assert to be detected. * pmic requires 6ms for crash reset case. */ mdelay(6); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), !mdm->soft_reset_inverted); } break; case ESOC_PRIMARY_REBOOT: dev_info(mdm->dev, "Triggering mdm cold reset"); mdm->ready = 0; gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), !!mdm->soft_reset_inverted); mdelay(300); gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET), !mdm->soft_reset_inverted); break; }; return; }