コード例 #1
0
static int ss300_dump_reset(struct modem_ctl *mc)
{
	struct io_device *iod = mc->iod;
	struct link_device *ld = get_current_link(iod);
	unsigned int gpio_cp_reset = mc->gpio_cp_reset;
	unsigned long flags;

	mif_disable_irq(&mc->irq_cp_active);

	mif_info("%s: %s: +++\n", mc->name, FUNC);

	print_mc_state(mc);

	spin_lock_irqsave(&mc->lock, flags);

	iod->modem_state_changed(iod, STATE_CRASH_EXIT);

	if (mc->wake_lock && !wake_lock_active(mc->wake_lock)) {
		wake_lock(mc->wake_lock);
		mif_err("%s->wake_lock locked\n", mc->name);
	}

	if (ld->ready)
		ld->ready(ld);

	spin_unlock_irqrestore(&mc->lock, flags);

	gpio_set_value(gpio_cp_reset, 0);
	print_mc_state(mc);
	udelay(200);

	if (ld->reset)
		ld->reset(ld);

	gpio_set_value(gpio_cp_reset, 1);
	print_mc_state(mc);
	msleep(300);

	gpio_set_value(mc->gpio_ap_status, 1);

	mif_info("%s: %s: ---\n", mc->name, FUNC);
	return 0;
}
static int cmc221_dump_reset(struct modem_ctl *mc)
{
	mif_err("%s\n", mc->name);

	if (!wake_lock_active(&mc->mc_wake_lock))
		wake_lock(&mc->mc_wake_lock);
	set_sromc_access(true);

	gpio_set_value(mc->gpio_host_active, 0);
	gpio_set_value(mc->gpio_cp_reset, 0);

	udelay(200);

	gpio_set_value(mc->gpio_cp_reset, 1);

	msleep(300);

	return 0;
}
コード例 #3
0
static irqreturn_t cp_status_handler(int irq, void *data)
{
	struct mem_link_device *mld = (struct mem_link_device *)data;
	struct link_device *ld = &mld->link_dev;
	int cp_status = gpio_get_value(mld->gpio_cp_status);
	unsigned long flags;

	spin_lock_irqsave(&mld->pm_lock, flags);

	s5p_change_irq_type(irq, cp_status);

	if (!cp_online(ld->mc))
		goto exit;

	print_pm_status(mld);

	if (cp_status) {
		if (!wake_lock_active(&mld->cp_wlock))
			wake_lock(&mld->cp_wlock);
	} else {
		if (atomic_read(&mld->ref_cnt) > 0) {
			/*
			** This status means that IPC TX is in progress from AP
			** to CP. So, CP_WAKEUP must be set to 1. Otherwise, it
			** is a critically erroneous status.
			*/
			if (gpio_get_value(mld->gpio_cp_wakeup) == 0) {
				mif_err("%s: ERR! cp_wakeup == 0\n", ld->name);
				goto exit;
			}
			/* CP_STATUS will be reset to 1 soon due to CP_WAKEUP.*/
		} else {
			gpio_set_value(mld->gpio_ap_status, 0);

			if (wake_lock_active(&mld->cp_wlock))
				wake_unlock(&mld->cp_wlock);
		}
	}

exit:
	spin_unlock_irqrestore(&mld->pm_lock, flags);
	return IRQ_HANDLED;
}
コード例 #4
0
int mem_register_ipc_rgn(struct mem_link_device *mld, phys_addr_t start,
			 size_t size)
{
	struct link_device *ld = &mld->link_dev;
	unsigned int num_pages = (size >> PAGE_SHIFT);
	struct page **pages;

	pages = kmalloc(sizeof(struct page *) * num_pages, GFP_ATOMIC);
	if (!pages)
		return -ENOMEM;

	mif_err("%s: IPC_RGN start:%pa size:%zu\n", ld->name, &start, size);

	mld->start = start;
	mld->size = size;
	mld->pages = pages;

	return 0;
}
static void usb_tx_complete(struct urb *urb)
{
	int ret = 0;
	struct sk_buff *skb = urb->context;

	switch (urb->status) {
	case 0:
		break;
	default:
		mif_err("TX error (%d)\n", urb->status);
	}

	usb_mark_last_busy(urb->dev);
	ret = pm_runtime_put_autosuspend(&urb->dev->dev);
	if (ret < 0 && ret != -EAGAIN)
		mif_debug("pm_runtime_put_autosuspend failed: %d\n", ret);
	usb_free_urb(urb);
	dev_kfree_skb_any(skb);
}
static int cbp72_boot_on(struct modem_ctl *mc)
{
	mif_info("\n");

	if (!mc->gpio_cp_reset) {
		mif_err("no gpio data\n");
		return -ENXIO;
	}

	gpio_set_value(mc->gpio_cp_reset, 0);

	msleep(600);

	gpio_set_value(mc->gpio_cp_reset, 1);

	mc->bootd->modem_state_changed(mc->bootd, STATE_BOOTING);

	return 0;
}
/* TX dynamic switching between DPRAM and USB in one modem */
static irqreturn_t dynamic_switching_handler(int irq, void *arg)
{
	struct modem_ctl *mc = (struct modem_ctl *)arg;
	int txpath = gpio_get_value(mc->gpio_link_switch);
	bool enumerated = usb_is_enumerated(mc->msd);

	mif_err("txpath=%d, enumeration=%d\n", txpath, enumerated);

	/* do not switch to USB, when USB is not enumerated. */
	if (!enumerated && txpath) {
		mc->need_switch_to_usb = true;
		return IRQ_HANDLED;
	}

	mc->need_switch_to_usb = false;
	rawdevs_set_tx_link(mc->msd, txpath ? LINKDEV_USB : LINKDEV_DPRAM);

	return IRQ_HANDLED;
}
コード例 #8
0
void mif_print_dump(const char *data, int len, int width)
{
	char *buff;

	buff = kzalloc(len << 3, GFP_ATOMIC);
	if (!buff) {
		mif_err("ERR! kzalloc fail\n");
		return;
	}

	if (width == 16)
		mif_dump2format16(data, len, buff, LOG_TAG);
	else
		mif_dump2format4(data, len, buff, LOG_TAG);

	pr_info("%s", buff);

	kfree(buff);
}
コード例 #9
0
static int xmm6262_on(struct modem_ctl *mc)
{
	mif_info("\n");

	if (!mc->gpio_cp_reset || !mc->gpio_cp_on || !mc->gpio_reset_req_n) {
		mif_err("no gpio data\n");
		return -ENXIO;
	}

	if (mc->gpio_revers_bias_clear)
		mc->gpio_revers_bias_clear();

#ifdef CONFIG_SEC_DUAL_MODEM_MODE
	gpio_set_value(mc->gpio_sim_io_sel, 0);
	gpio_set_value(mc->gpio_cp_ctrl1, 1);
	gpio_set_value(mc->gpio_cp_ctrl2, 0);
#endif

	/* TODO */
	gpio_set_value(mc->gpio_reset_req_n, 0);
	gpio_set_value(mc->gpio_cp_on, 0);
	gpio_set_value(mc->gpio_cp_reset, 0);
	msleep(100);
	gpio_set_value(mc->gpio_cp_reset, 1);
	/* If XMM6262 was connected with C2C, AP wait 50ms to BB Reset*/
	msleep(50);
	gpio_set_value(mc->gpio_reset_req_n, 1);

	gpio_set_value(mc->gpio_cp_on, 1);
	udelay(60);
	gpio_set_value(mc->gpio_cp_on, 0);
	msleep(20);

	mc->phone_state = STATE_BOOTING;

	if (mc->gpio_revers_bias_restore)
		mc->gpio_revers_bias_restore();
	gpio_set_value(mc->gpio_pda_active, 1);


	return 0;
}
コード例 #10
0
static void link_pm_runtime_start(struct work_struct *work)
{
	struct link_pm_data *pm_data =
		container_of(work, struct link_pm_data, link_pm_start.work);
	struct usb_device *usbdev = pm_data->usb_ld->usbdev;
	struct device *dev, *hdev;
	struct link_device *ld = &pm_data->usb_ld->ld;

	if (!pm_data->usb_ld->if_usb_connected
		|| pm_data->usb_ld->ld.com_state == COM_NONE) {
		mif_err("disconnect status, ignore\n");
		return;
	}

	dev = &pm_data->usb_ld->usbdev->dev;

	/* wait interface driver resumming */
	if (dev->power.runtime_status == RPM_SUSPENDED) {
		mif_info("suspended yet, delayed work\n");
		queue_delayed_work(pm_data->wq, &pm_data->link_pm_start,
			msecs_to_jiffies(20));
		return;
	}

	if (pm_data->usb_ld->usbdev && dev->parent) {
		mif_info("rpm_status: %d\n",
			dev->power.runtime_status);
		pm_runtime_set_autosuspend_delay(dev, 200);
		hdev = usbdev->bus->root_hub->dev.parent;
		mif_info("EHCI runtime %s, %s\n", dev_driver_string(hdev),
			dev_name(hdev));
		pm_runtime_allow(dev);
		pm_runtime_allow(hdev);/*ehci*/
		pm_data->link_pm_active = true;
		pm_data->resume_requested = false;
		pm_data->link_reconnect_cnt = 5;
		pm_data->resume_retry_cnt = 0;

		/* retry prvious link tx q */
		queue_delayed_work(ld->tx_wq, &ld->tx_delayed_work, 0);
	}
}
コード例 #11
0
static void dpram_ipc_write(struct dpram_link_device *dpld, int dev,
		u32 qsize, u32 in, u32 out, struct sk_buff *skb)
{
	struct link_device *ld = &dpld->ld;
	u8 __iomem *buff = get_tx_buff(dpld, dev);
	u8 *src = skb->data;
	u32 len = skb->len;
	u32 inp;
	struct mif_irq_map map;

	if (in < out) {
		/* +++++++++ in ---------- out ++++++++++ */
		memcpy((buff + in), src, len);
	} else {
		/* ------ out +++++++++++ in ------------ */
		u32 space = qsize - in;

		/* 1) in -> buffer end */
		memcpy((buff + in), src, ((len > space) ? space : len));

		/* 2) buffer start -> out */
		if (len > space)
			memcpy(buff, (src + space), (len - space));
	}

	/* update new in pointer */
	inp = in + len;
	if (inp >= qsize)
		inp -= qsize;
	set_tx_head(dpld, dev, inp);

	if (dev == IPC_FMT) {
		set_dpram_map(dpld, &map);
		mif_irq_log(ld->mc->msd, map, "ipc_write", sizeof("ipc_write"));
		mif_ipc_log(MIF_IPC_AP2CP, ld->mc->msd, skb->data, skb->len);
	}

	if (ld->aligned && memcmp16_to_io((buff + in), src, 4)) {
		mif_err("%s: memcmp16_to_io fail\n", ld->name);
		dpram_trigger_force_cp_crash(dpld);
	}
}
コード例 #12
0
static void cmd_crash_exit_handler(struct dpram_link_device *dpld)
{
	struct link_device *ld = &dpld->ld;

	ld->mode = LINK_MODE_ULOAD;

	if (!wake_lock_active(&dpld->wlock))
		wake_lock(&dpld->wlock);

	mif_err("%s: Recv 0xC9 (CRASH_EXIT)\n", ld->name);

	dpram_wake_up(dpld);

	del_timer(&dpld->crash_ack_timer);

	if (dpld->ext_op && dpld->ext_op->crash_log)
		dpld->ext_op->crash_log(dpld);

	handle_cp_crash(dpld);
}
コード例 #13
0
bool link_pm_is_connected(struct usb_link_device *usb_ld)
{
	if (has_hub(usb_ld)) {
		if (usb_ld->link_pm_data->hub_init_lock)
			return false;

		if (usb_ld->link_pm_data->hub_status != HUB_STATE_ACTIVE) {
			schedule_delayed_work(
					&usb_ld->link_pm_data->link_pm_hub, 0);
			return false;
		}
	}

	if (!usb_ld->if_usb_connected) {
		mif_err("mif: if not connected\n");
		return false;
	}

	return true;
}
コード例 #14
0
static inline void stop_pm_wdog(struct modem_link_pm *pm, enum pm_state state,
				enum pm_event event)
{
	struct pm_wdog *wdog = &pm->wdog;

	if (state == wdog->state) {
		struct timer_list *timer = &wdog->timer;

		if (timer_pending(timer))
			del_timer(timer);

		mif_debug("%s: PM WDOG kicked by {%s@%s}\n",
			pm->link_name, pm_event2str(event),
			pm_state2str(state));
	} else {
		mif_err("%s: ERR! PM WDOG illegal state {%s@%s}\n",
			pm->link_name, pm_event2str(event),
			pm_state2str(state));
	}
}
コード例 #15
0
static int cmc221_ioctl(struct dpram_link_device *dpld, struct io_device *iod,
			unsigned int cmd, unsigned long arg)
{
	int err = 0;

	switch (cmd) {
	case IOCTL_DPRAM_SEND_BOOT:
		err = cmc221_xmit_boot(dpld, arg);
		if (err < 0)
			mif_info("ERR! xmit_boot fail\n");
		break;

	default:
		mif_err("ERR! invalid cmd 0x%08X\n", cmd);
		err = -EINVAL;
		break;
	}

	return err;
}
コード例 #16
0
static void qc_dload_cmd_handler(struct dpram_link_device *dpld, u16 cmd)
{
	switch (cmd) {
	case 0x1234:
		dpld->udl_check.copy_start = 1;
		break;

	case 0xDBAB:
		if (dpld->udl_check.total_size)
			tasklet_schedule(&dpld->dl_tsk);
		break;

	case 0xABCD:
		dpld->udl_check.boot_complete = 1;
		break;

	default:
		mif_err("ERR! unknown command 0x%04X\n", cmd);
	}
}
コード例 #17
0
/**
@brief		function for the @b dload_start method in a link_device instance

Set all flags and environments for CP binary download

@param ld	the pointer to a link_device instance
@param iod	the pointer to an io_device instance
*/
static int mem_start_download(struct link_device *ld, struct io_device *iod)
{
	struct mem_link_device *mld = to_mem_link_device(ld);
	unsigned int magic;

	atomic_set(&mld->cp_boot_done, 0);

	reset_ipc_map(mld);
	reset_ipc_devices(mld);

	set_magic(mld, SHM_BOOT_MAGIC);
	magic = get_magic(mld);
	if (magic != SHM_BOOT_MAGIC) {
		mif_err("%s: ERR! magic 0x%08X != SHM_BOOT_MAGIC 0x%08X\n",
			ld->name, magic, SHM_BOOT_MAGIC);
		return -EFAULT;
	}

	return 0;
}
コード例 #18
0
static void pm_wdog_bark(unsigned long data)
{
	struct pm_wdog *wdog = (struct pm_wdog *)data;
	struct modem_link_pm *pm = wdog_to_pm(wdog);
	struct pm_fsm *fsm = &pm->fsm;
	enum pm_state c_state;
	unsigned long flags;

	spin_lock_irqsave(&pm->lock, flags);
	c_state = fsm->state;
	spin_unlock_irqrestore(&pm->lock, flags);

	if (wdog->w_state == c_state) {
		mif_err("%s: PM WDOG lost event {%s@%s}\n", pm->link_name,
			pm_event2str(wdog->w_event), pm_state2str(wdog->state));
		return;
	}

	run_pm_fsm(pm, PM_EVENT_WDOG_TIMEOUT);
}
コード例 #19
0
/**
@brief		check the free space in a SBD RB

@param rb	the pointer to an SBD RB instance

@retval "> 0"	the size of free space in the @b @@dev TXQ
@retval "< 0"	an error code
*/
static inline int check_rb_space(struct sbd_ring_buffer *rb, unsigned int qlen,
				 unsigned int in, unsigned int out)
{
	unsigned int space;

	if (!circ_valid(qlen, in, out)) {
		mif_err("ERR! TXQ[%d:%d] DIRTY (qlen:%d in:%d out:%d)\n",
			rb->id, rb->ch, qlen, in, out);
		return -EIO;
	}

	space = circ_get_space(qlen, in, out);
	if (unlikely(space < 1)) {
		mif_err_limited("TXQ[%d:%d] NOSPC (qlen:%d in:%d out:%d)\n",
				rb->id, rb->ch, qlen, in, out);
		return -ENOSPC;
	}

	return space;
}
コード例 #20
0
static int cmc220_off(struct modem_ctl *mc)
{
	mif_info("off\n");
	mif_err("<%s>\n", mc->bootd->name);

	if (!mc->gpio_cp_off || !mc->gpio_cp_on || !mc->gpio_cp_reset)
		return 0;

	gpio_set_value(mc->gpio_cp_on, 0);
	gpio_set_value(mc->gpio_cp_reset, 0);
	mdelay(300);

	gpio_set_value(mc->gpio_cp_off, 0);
	mdelay(300);


	mc->phone_state = STATE_OFFLINE;

	return 0;
}
コード例 #21
0
static void qc_dload_cmd_handler(struct pld_link_device *pld, u16 cmd)
{
    switch (cmd) {
    case 0x1234:
        pld->udl_check.copy_start = 1;
        break;

    case 0xDBAB:
        tasklet_schedule(&pld->dl_tsk);
        break;

    case 0xABCD:
        mif_info("[%s] booting Start\n", pld->ld.name);
        pld->udl_check.boot_complete = 1;
        break;

    default:
        mif_err("ERR! unknown command 0x%04X\n", cmd);
    }
}
コード例 #22
0
int sbd_pio_tx(struct sbd_ring_buffer *rb, struct sk_buff *skb)
{
	int ret;
	unsigned int qlen = rb->len;
	unsigned int in = *rb->wp;
	unsigned int out = *rb->rp;
	unsigned int count = skb->len;
	unsigned int space = (rb->buff_size - rb->payload_offset);
	u8 *dst;

	pktlog_tx_bottom_skb(rb->sl, skb);

	ret = check_rb_space(rb, qlen, in, out);
	if (unlikely(ret < 0))
		return ret;

	if (unlikely(count > space)) {
		mif_err("ERR! {id:%d ch:%d} count %d > space %d\n",
			rb->id, rb->ch, count, space);
		return -ENOSPC;
	}

	barrier();

	dst = rb->buff[in] + rb->payload_offset;

	barrier();

	skb_copy_from_linear_data(skb, dst, count);

	rb->size_v[in] = skb->len;

	barrier();

	*rb->wp = circ_new_ptr(qlen, in, 1);

	/* Commit the item before incrementing the head */
	smp_mb();

	return count;
}
コード例 #23
0
static int qc_boot_post_process(struct dpram_link_device *dpld)
{
	int count = 0;

	while (1) {
		if (dpld->boot_start_complete) {
			dpld->boot_start_complete = 0;
			break;
		}

		msleep_interruptible(10);

		count++;
		if (count > 200) {
			mif_err("ERR! count %d\n", count);
			return -1;
		}
	}

	return 0;
}
コード例 #24
0
static int cmc221_ioctl(struct dpram_link_device *dpld, struct io_device *iod,
		unsigned int cmd, unsigned long arg)
{
	struct link_device *ld = &dpld->ld;
	int err = 0;

	switch (cmd) {
	case IOCTL_DPRAM_SEND_BOOT:
		err = cmc221_download_boot(dpld, (void *)arg);
		if (err < 0)
			mif_info("%s: ERR! download_boot fail\n", ld->name);
		break;

	default:
		mif_err("%s: ERR! invalid cmd 0x%08X\n", ld->name, cmd);
		err = -EINVAL;
		break;
	}

	return err;
}
コード例 #25
0
void xmm6262_start_loopback(struct io_device *iod, struct modem_shared *msd)
{
	struct link_device *ld = get_current_link(iod);
	struct sk_buff *skb = alloc_skb(16, GFP_ATOMIC);
	int ret;

	if (unlikely(!skb))
		return;
	memcpy(skb_put(skb, 1), (msd->loopback_ipaddr) ? "s" : "x", 1);
	skbpriv(skb)->iod = iod;
	skbpriv(skb)->ld = ld;

	ret = ld->send(ld, iod, skb);
	if (ret < 0) {
		mif_err("usb_tx_urb fail\n");
		dev_kfree_skb_any(skb);
	}
	mif_info("Send loopback key '%s'\n",
					(msd->loopback_ipaddr) ? "s" : "x");

}
コード例 #26
0
static int dt_gpio_config(struct modem_ctl *mc,
			struct modem_data *pdata)
{
	int ret = 0;

	struct device_node *np = mc->dev->of_node;

	/* GPIO_RESET_REQ_N */
	pdata->gpio_reset_req_n =
		of_get_named_gpio(np, "mif,gpio_reset_req_n", 0);
	if (!gpio_is_valid(pdata->gpio_reset_req_n)) {
		mif_err("reset_req_n: Invalied gpio pins\n");
		return -EINVAL;
	}

	ret = gpio_request(pdata->gpio_reset_req_n, "RESET_REQ_N");
	if (ret)
		mif_err("fail to request gpio %s:%d\n", "RESET_REQ_N", ret);
	gpio_direction_output(pdata->gpio_reset_req_n, 0);

	/* GPIO_CP_DUMP_INT */
	pdata->gpio_cp_dump_int =
		of_get_named_gpio(np, "mif,gpio_cp_dump_int", 0);
	if (!gpio_is_valid(pdata->gpio_cp_dump_int)) {
		mif_err("cp_dump_int: Invalied gpio pins\n");
		return -EINVAL;
	}

	ret = gpio_request(pdata->gpio_cp_dump_int, "CP_DUMP_INT");
	if (ret)
		mif_err("fail to request gpio %s:%d\n", "CP_DUMP_INT", ret);
	gpio_direction_input(pdata->gpio_cp_dump_int);

	/* GPIO_AP_DUMP_INT */
	pdata->gpio_ap_dump_int =
		of_get_named_gpio(np, "mif,gpio_ap_dump_int", 0);
	if (!gpio_is_valid(pdata->gpio_ap_dump_int)) {
		mif_err("ap_dump_int: Invalied gpio pins\n");
		return -EINVAL;
	}

	ret = gpio_request(pdata->gpio_ap_dump_int, "AP_DUMP_INT");
	if (ret)
		mif_err("fail to request gpio %s:%d\n", "AP_DUMP_INT", ret);
	gpio_direction_output(pdata->gpio_ap_dump_int, 0);

	return ret;
}
コード例 #27
0
bool link_pm_is_connected(struct usb_link_device *usb_ld)
{
	if (has_hub(usb_ld)) {
		struct link_pm_data *pm_data = usb_ld->link_pm_data;
		if (pm_data->hub_init_lock)
			return false;

		if (pm_data->hub_status == HUB_STATE_OFF) {
			if (pm_data->hub_work_running == false)
				start_hub_work(pm_data, 0);
			return false;
		}
	}

	if (!usb_ld->if_usb_connected) {
		mif_err("mif: if not connected\n");
		return false;
	}

	return true;
}
コード例 #28
0
static int qc_boot_post_process(struct pld_link_device *pld)
{
    int count = 0;

    while (1) {
        if (pld->boot_start_complete) {
            pld->boot_start_complete = 0;
            break;
        }

        usleep_range(10000, 11000);

        count++;
        if (count > 200) {
            mif_err("ERR! count %d\n", count);
            return -1;
        }
    }

    return 0;
}
コード例 #29
0
ファイル: modem_ctrl_ss333.c プロジェクト: myjang0507/a8elte
static void handle_no_response_cp_crash(unsigned long arg)
{
	struct modem_ctl *mc = (struct modem_ctl *)arg;
	unsigned long flags;

	if (cp_crashed(mc)) {
		mif_info("%s: STATE_CRASH_EXIT without response from CP\n", mc->name);
		return;
	}

	mif_err("%s: ERR! No response from CP\n", mc->name);

	spin_lock_irqsave(&mc->lock, flags);
	/* Change the modem state for RIL */
	if (mc->iod)
		mc->iod->modem_state_changed(mc->iod, STATE_CRASH_EXIT);
	/* Change the modem state for CBD */
	if (mc->bootd)
		mc->bootd->modem_state_changed(mc->bootd, STATE_CRASH_EXIT);
	spin_unlock_irqrestore(&mc->lock, flags);
}
コード例 #30
0
static int cbp82_boot_off(struct modem_ctl *mc)
{
	struct link_device *ld = get_current_link(mc->bootd);
	int ret;
	mif_err("+++\n");

	/* Wait here until the PHONE is up.
	 * Waiting as the this called from IOCTL->UM thread */
	mif_err("Waiting for PHONE_START\n");
	ret = wait_for_completion_timeout(&ld->init_cmpl, DPRAM_INIT_TIMEOUT);
	if (!ret) {
		/* ret == 0 on timeout */
		mif_err("T-I-M-E-O-U-T (PHONE_START)\n");
		cbp82_off(mc);
		ret = -EIO;
		goto exit;
	}
	mif_err("recv PHONE_START\n");

	mif_err("Waiting for PIF_INIT_DONE\n");
	ret = wait_for_completion_timeout(&ld->pif_cmpl, PIF_TIMEOUT);
	if (!ret) {
		/* ret == 0 on timeout */
		mif_err("T-I-M-E-O-U-T (PIF_INIT_DONE)!!!\n");
		cbp82_off(mc);
		ret = -EIO;
		goto exit;
	}
	mif_err("recv PIF_INIT_DONE\n");

	mc->bootd->modem_state_changed(mc->bootd, STATE_ONLINE);
	ret = 0;

exit:
	wake_unlock(&mc->mc_wake_lock);
	mif_err("---\n");
	return ret;
}