struct link_device *shmem_create_link_device(struct platform_device *pdev)
{
	struct modem_data *modem;
	struct mem_link_device *mld;
	struct link_device *ld;
	unsigned long start;
	unsigned long size;
	int err;
	mif_err("+++\n");

	/**
	 * Get the modem (platform) data
	 */
	modem = (struct modem_data *)pdev->dev.platform_data;
	if (!modem) {
		mif_err("ERR! modem == NULL\n");
		return NULL;
	}

	if (!modem->mbx) {
		mif_err("%s: ERR! mbx == NULL\n", modem->link_name);
		return NULL;
	}

	mif_err("MODEM:%s LINK:%s\n", modem->name, modem->link_name);

	/**
	 * Create a MEMORY link device instance
	 */
	mld = mem_create_link_device(MEM_SYS_SHMEM, modem);
	if (!mld) {
		mif_err("%s: ERR! create_link_device fail\n", modem->link_name);
		return NULL;
	}

	ld = &mld->link_dev;

	/**
	 * Link local functions to the corresponding function pointers that are
	 * optional for some link device
	 */
	ld->ioctl = shmem_ioctl;

	/**
	 * Link local functions to the corresponding function pointers that are
	 * mandatory for all memory-type link devices
	 */
	mld->remap_region = shm_request_region;
	mld->recv_cp2ap_irq = recv_cp2ap_irq;
	mld->send_ap2cp_irq = send_ap2cp_irq;

	/**
	 * Link local functions to the corresponding function pointers that are
	 * optional for some memory-type link devices
	 */
	mld->read_ap2cp_irq = read_ap2cp_irq;
	mld->unmap_region = shm_release_region;

	/**
	 * Initialize SHMEM maps for BOOT (physical map -> logical map)
	 */
	start = shm_get_phys_base() + shm_get_boot_rgn_offset();
	size = shm_get_boot_rgn_size();
	err = mem_setup_boot_map(mld, start, size);
	if (err < 0) {
		mif_err("%s: ERR! setup_boot_map fail (%d)\n", ld->name, err);
		goto error;
	}

	/**
	 * Initialize SHMEM maps for IPC (physical map -> logical map)
	 */
	start = shm_get_phys_base() + shm_get_ipc_rgn_offset();
	size = shm_get_ipc_rgn_size();
	err = mem_setup_ipc_map(mld, start, size);
	if (err < 0) {
		mif_err("%s: ERR! setup_ipc_map fail (%d)\n", ld->name, err);
		goto error;
	}

	/**
	 * Retrieve SHMEM MBOX#, IRQ#, etc.
	 */
	mld->mbx_cp2ap_msg = modem->mbx->mbx_cp2ap_msg;
	mld->irq_cp2ap_msg = modem->mbx->irq_cp2ap_msg;

	mld->mbx_ap2cp_msg = modem->mbx->mbx_ap2cp_msg;
	mld->int_ap2cp_msg = modem->mbx->int_ap2cp_msg;

	/**
	 * Register interrupt handlers
	 */
	err = mbox_request_irq(mld->irq_cp2ap_msg, shmem_irq_handler, mld);
	if (err) {
		mif_err("%s: ERR! mbox_request_irq fail (%d)\n", ld->name, err);
		goto error;
	}

	mif_err("---\n");
	return ld;

error:
	kfree(mld);
	mif_err("xxx\n");
	return NULL;
}
struct link_device *lli_create_link_device(struct platform_device *pdev)
{
	struct modem_data *modem;
	struct mem_link_device *mld;
	struct link_device *ld;
	int err;
	unsigned long start;
	unsigned long size;
#ifdef DEBUG_MODEM_IF
	struct dentry *debug_dir = debugfs_create_dir("svnet", NULL);
#endif
	mif_err("+++\n");

	/**
	 * Get the modem (platform) data
	 */
	modem = (struct modem_data *)pdev->dev.platform_data;
	if (!modem) {
		mif_err("ERR! modem == NULL\n");
		return NULL;
	}

	if (!modem->gpio_ap_wakeup) {
		mif_err("ERR! no gpio_ap_wakeup\n");
		return NULL;
	}

	if (!modem->gpio_cp_status) {
		mif_err("ERR! no gpio_cp_status\n");
		return NULL;
	}

	mif_err("MODEM:%s LINK:%s\n", modem->name, modem->link_name);

	/**
	 * Create a MEMORY link device instance
	 */
	mld = mem_create_link_device(MEM_LLI_SHMEM, modem);
	if (!mld) {
		mif_err("%s: ERR! create_link_device fail\n", modem->link_name);
		return NULL;
	}

	g_mld = mld;

	ld = &mld->link_dev;

	ld->ready = lli_link_ready;
	ld->reset = lli_link_reset;
	ld->reload = lli_link_reload;
	ld->off = lli_link_off;

	ld->unmounted = lli_link_unmounted;
	ld->suspended = lli_link_suspended;

	ld->enable_irq = lli_enable_irq;
	ld->disable_irq = lli_disable_irq;

	/**
	 * Link local functions to the corresponding function pointers that are
	 * mandatory for all memory-type link devices
	 */
	mld->send_ap2cp_irq = send_ap2cp_irq;

	/*
	** Link local functions to the corresponding function pointers
	*/
#ifndef CONFIG_LINK_POWER_MANAGEMENT_WITH_FSM
	mld->finalize_cp_start = finalize_cp_start;
#endif

#ifdef CONFIG_LINK_POWER_MANAGEMENT
	mld->start_pm = start_pm;
	mld->stop_pm = stop_pm;
	mld->forbid_cp_sleep = forbid_cp_sleep;
	mld->permit_cp_sleep = permit_cp_sleep;
	mld->link_active = check_link_status;
#endif

#ifdef DEBUG_MODEM_IF
	mld->debug_info = mipi_lli_debug_info;
#endif

	/**
	 * Initialize SHMEM maps for IPC (physical map -> logical map)
	 */
	start = mipi_lli_get_phys_base();
	size = mipi_lli_get_phys_size();
	err = mem_register_ipc_rgn(mld, start, size);
	if (err < 0) {
		mif_err("%s: ERR! register_ipc_rgn fail (%d)\n", ld->name, err);
		goto error;
	}
	err = mem_setup_ipc_map(mld);
	if (err < 0) {
		mif_err("%s: ERR! setup_ipc_map fail (%d)\n", ld->name, err);
		mem_unregister_ipc_rgn(mld);
		goto error;
	}

#ifdef CONFIG_LINK_DEVICE_WITH_SBD_ARCH
	if (ld->sbd_ipc) {
		struct sbd_link_device *sld = &mld->sbd_link_dev;

		err = create_sbd_link_device(ld, sld, mld->base, mld->size);
		if (err < 0)
			goto error;
	}
#endif

	/**
	 * Register interrupt handlers
	 */
	err = mipi_lli_register_handler(lli_irq_handler, mld);
	if (err) {
		mif_err("%s: ERR! register_handler fail (%d)\n", ld->name, err);
		goto error;
	}

	/*
	** Retrieve GPIO#, IRQ#, and IRQ flags for PM
	*/
	mld->gpio_ap_wakeup = modem->gpio_ap_wakeup;
	mld->gpio_cp_wakeup = modem->gpio_cp_wakeup;
	mld->gpio_cp_status = modem->gpio_cp_status;
	mld->gpio_ap_status = modem->gpio_ap_status;
	mld->gpio_ipc_int2cp = modem->gpio_ipc_int2cp;

#ifdef CONFIG_LINK_POWER_MANAGEMENT
	err = init_pm(mld);
	if (err)
		goto error;
#endif

#ifdef DEBUG_MODEM_IF
	mld->mem_dump_blob.data = mld->base;
	mld->mem_dump_blob.size = mld->size;
	debugfs_create_blob("mem_dump", S_IRUGO, debug_dir,
						&mld->mem_dump_blob);
#endif

	mif_err("---\n");
	return ld;

error:
	kfree(mld);
	mif_err("xxx\n");
	return NULL;
}
struct link_device *c2c_create_link_device(struct platform_device *pdev)
{
	struct modem_data *modem;
	struct mem_link_device *mld;
	struct link_device *ld;
	int err;
	int i;
	unsigned int irq;
	unsigned long flags;
	char name[MAX_NAME_LEN];
	mif_err("+++\n");

	/**
	 * Get the modem (platform) data
	 */
	modem = (struct modem_data *)pdev->dev.platform_data;
	if (!modem) {
		mif_err("ERR! modem == NULL\n");
		return NULL;
	}

	if (modem->irq_ap_wakeup == 0) {
		mif_err("ERR! no irq_ap_wakeup\n");
		return NULL;
	}

	if (modem->irq_cp_status == 0) {
		mif_err("ERR! no irq_cp_status\n");
		return NULL;
	}

	mif_err("MODEM:%s LINK:%s\n", modem->name, modem->link_name);

	/**
	 * Create a MEMORY link device instance
	 */
	mld = mem_create_link_device(MEM_C2C_SHMEM, modem);
	if (!mld) {
		mif_err("%s: ERR! create_link_device fail\n", modem->link_name);
		return NULL;
	}

	ld = &mld->link_dev;

	/*
	** Link local functions to the corresponding function pointers
	*/
	mld->send_ap2cp_irq = send_int2cp;

	mld->finalize_cp_start = finalize_cp_start;

	mld->forbid_cp_sleep = forbid_cp_sleep;
	mld->permit_cp_sleep = permit_cp_sleep;
	mld->link_active = link_active;

	/*
	** Retrieve SHMEM resource
	*/
	mld->start = c2c_get_phys_base() + c2c_get_sh_rgn_offset();
	mld->size = c2c_get_sh_rgn_size();
	mld->base = mem_register_ipc_rgn(mld, mld->start, mld->size);
	if (!mld->base) {
		mif_err("%s: ERR! register_ipc_rgn fail\n", ld->name);
		goto error;
	}

	/*
	** Initialize SHMEM maps (physical map -> logical map)
	*/
	err = mem_setup_ipc_map(mld);
	if (err < 0) {
		mif_err("%s: ERR! init_ipc_map fail (err %d)\n", ld->name, err);
		goto error;
	}

	/*
	** Register interrupt handlers
	*/
	err = c2c_register_handler(c2c_irq_handler, mld);
	if (err) {
		mif_err("%s: ERR! c2c_register_handler fail (err %d)\n",
			ld->name, err);
		goto error;
	}

	/*
	** Retrieve GPIO#, IRQ#, and IRQ flags for PM
	*/
	mld->gpio_ap_wakeup = modem->gpio_ap_wakeup;
	mld->irq_ap_wakeup = modem->irq_ap_wakeup;

	mld->gpio_cp_wakeup = modem->gpio_cp_wakeup;

	mld->gpio_cp_status = modem->gpio_cp_status;
	mld->irq_cp_status = modem->irq_cp_status;

	mld->gpio_ap_status = modem->gpio_ap_status;

	snprintf(name, MAX_NAME_LEN, "%s_ap_wakeup", ld->name);
	irq = mld->irq_ap_wakeup;
	flags = (IRQF_NO_THREAD | IRQF_NO_SUSPEND | IRQF_TRIGGER_HIGH);
	err = mif_register_isr(irq, ap_wakeup_handler, flags, name, mld);
	if (err)
		goto error;

	snprintf(name, MAX_NAME_LEN, "%s_cp_status", ld->name);
	irq = mld->irq_cp_status;
	flags = (IRQF_NO_THREAD | IRQF_NO_SUSPEND | IRQF_TRIGGER_HIGH);
	err = mif_register_isr(irq, cp_status_handler, flags, name, mld);
	if (err)
		goto error;

	mif_err("CP2AP_WAKEUP GPIO# = %d\n", mld->gpio_ap_wakeup);
	mif_err("CP2AP_WAKEUP IRQ# = %d\n", mld->irq_ap_wakeup);

	mif_err("AP2CP_WAKEUP GPIO# = %d\n", mld->gpio_cp_wakeup);

	mif_err("CP2AP_STATUS GPIO# = %d\n", mld->gpio_cp_status);
	mif_err("CP2AP_STATUS IRQ# = %d\n", mld->irq_cp_status);

	mif_err("AP2CP_STATUS GPIO# = %d\n", mld->gpio_ap_status);

	/*
	** Initialize locks, completions, bottom halves, etc. for PM
	*/
	sprintf(name, "%s_ap_wlock", ld->name);
	wake_lock_init(&mld->ap_wlock, WAKE_LOCK_SUSPEND, name);

	sprintf(name, "%s_cp_wlock", ld->name);
	wake_lock_init(&mld->cp_wlock, WAKE_LOCK_SUSPEND, name);

	INIT_DELAYED_WORK(&mld->cp_sleep_dwork, release_cp_wakeup);

	spin_lock_init(&mld->pm_lock);
	atomic_set(&mld->ref_cnt, 0);

	gpio_set_value(mld->gpio_ap_status, 0);

	c2c_assign_gpio_ap_wakeup(mld->gpio_ap_wakeup);
	c2c_assign_gpio_ap_status(mld->gpio_ap_status);
	c2c_assign_gpio_cp_wakeup(mld->gpio_cp_wakeup);
	c2c_assign_gpio_cp_status(mld->gpio_cp_status);

	mif_err("---\n");
	return ld;

error:
	kfree(mld);
	mif_err("xxx\n");
	return NULL;
}