コード例 #1
0
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);
	}
}
コード例 #2
0
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);
}
コード例 #3
0
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);
}
コード例 #4
0
/* 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);

}
コード例 #5
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;
}
コード例 #6
0
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);
}
コード例 #7
0
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;
	}
}
コード例 #8
0
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);
}
コード例 #9
0
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;
}
コード例 #10
0
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);
}
コード例 #11
0
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)));
}
コード例 #12
0
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;
	}
}
コード例 #13
0
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;
}
コード例 #14
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;
}
コード例 #15
0
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);
	}
}
コード例 #16
0
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);
}
コード例 #17
0
/* 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);
}
コード例 #18
0
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));
}
コード例 #19
0
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
}
コード例 #20
0
/* 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);
}
コード例 #21
0
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;
}
コード例 #22
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);
}
コード例 #23
0
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);
	}
}
コード例 #24
0
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);
}
コード例 #25
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);
#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);
}
コード例 #26
0
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);
}
コード例 #27
0
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;
}
コード例 #28
0
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;
}
コード例 #29
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;

}
コード例 #30
0
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;
}