Beispiel #1
0
static irqreturn_t link_pm_irq_handler(int irq, void *data)
{
	int value;
	struct link_pm_data *pm_data = data;

#if defined(CONFIG_SLP)
	pm_wakeup_event(pm_data->miscdev.this_device, 0);
#endif

	if (!pm_data->link_pm_active)
		return IRQ_HANDLED;

	/* host wake up HIGH */
	/*
		resume usb runtime pm start
	*/
	/* host wake up LOW */
	/*
		slave usb enumeration end,
		host can send usb packet after
		runtime pm status changes to ACTIVE
	*/
	value = gpio_get_value(pm_data->gpio_link_hostwake);
	mif_debug("gpio [HWK] get [%d]\n", value);

	/*
	* igonore host wakeup interrupt at suspending kernel
	*/
	if (pm_data->dpm_suspending) {
		mif_info("ignore request by suspending\n");
		/* Ignore HWK but AP got to L2 by suspending fail */
		wake_lock(&pm_data->l2_wake);
		return IRQ_HANDLED;
	}

	if (value == HOSTWAKE_TRIGLEVEL) {
		/* move to slave wake function */
		/* runtime pm goes to active */
		/*
		if (gpio_get_value(pm_data->gpio_link_active)) {
			mif_err("gpio [H ACTV : %d] set 1\n",
				gpio_get_value(pm_data->gpio_link_active));
			gpio_set_value(pm_data->gpio_link_active, 1);
		}
		*/
		queue_delayed_work(pm_data->wq, &pm_data->link_pm_work, 0);
	} else {
		/* notification of enumeration process from slave device
		 * But it does not mean whole connection is in resume, so do not
		 * notify resume completion here.

		if (pm_data->link_pm_active && !pm_data->active_done.done)
			complete(&pm_data->active_done);
		*/
		/* clear slave cpu wake up pin */
		gpio_set_value(pm_data->gpio_link_slavewake, 0);
		mif_debug("gpio [SWK] set [0]\n");
	}
	return IRQ_HANDLED;
}
static int cbp71_on(struct modem_ctl *mc)
{
	int RetVal = 0;
	int dpram_init_RetVal = 0;
	struct link_device *ld = get_current_link(mc->iod);
	struct dpram_link_device *dpram_ld = to_dpram_link_device(ld);

	mif_info("cbp71_on()\n");

	if (!mc->gpio_cp_off || !mc->gpio_cp_reset) {
		mif_err("no gpio data\n");
		return -ENXIO;
	}
	gpio_set_value(mc->gpio_cp_reset, 0);
	gpio_set_value(mc->gpio_cp_on, 1);
	mdelay(300);
	gpio_set_value(mc->gpio_cp_off, 1);
	mdelay(300);
	gpio_set_value(mc->gpio_cp_on, 0);
	gpio_set_value(mc->gpio_cp_reset, 1);
	gpio_set_value(mc->gpio_pda_active, 1);

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

	/* Wait here until the PHONE is up.
	* Waiting as the this called from IOCTL->UM thread */
	mif_debug("power control waiting for INT_MASK_CMD_PIF_INIT_DONE\n");

	/* 1HZ = 1 clock tick, 100 default */
	dpram_ld->dpctl->clear_intr();

	dpram_init_RetVal =
		wait_for_completion_interruptible_timeout(
			&dpram_ld->dpram_init_cmd, DPRAM_INIT_TIMEOUT);

	if (!dpram_init_RetVal) {
		/*RetVal will be 0 on timeout, non zero if interrupted */
		mif_err("INIT_START cmd was not arrived.\n");
		mif_err("init_cmd_wait_condition is 0 and wait timeout happend\n");
		return -ENXIO;
	}

	RetVal = wait_for_completion_interruptible_timeout(
			&dpram_ld->modem_pif_init_done, PIF_TIMEOUT);

	if (!RetVal) {
		/*RetVal will be 0 on timeout, non zero if interrupted */
		mif_err("PIF init failed\n");
		mif_err("pif_init_wait_condition is 0 and wait timeout happend\n");
		return -ENXIO;
	}

	mif_debug("complete cbp71_on\n");

	mc->iod->modem_state_changed(mc->iod, STATE_ONLINE);

	return 0;
}
static int __devinit modem_spi_boot_probe(struct spi_device *spi)
{
	int ret;
	struct modem_boot_spi *loader;
	struct modem_boot_spi_platform_data *pdata;
	mif_debug("+++\n");

	loader = kzalloc(sizeof(*loader), GFP_KERNEL);
	if (!loader) {
		mif_err("failed to allocate for modem_boot_spi\n");
		ret = -ENOMEM;
		goto err_alloc;
	}
	mutex_init(&loader->lock);

	spi->bits_per_word = 8;

	if (spi_setup(spi)) {
		mif_err("ERR! spi_setup fail\n");
		ret = -EINVAL;
		goto err_setup;
	}
	loader->spi_dev = spi;

	if (!spi->dev.platform_data) {
		mif_err("ERR! no platform_data\n");
		ret = -EINVAL;
		goto err_setup;
	}
	pdata = (struct modem_boot_spi_platform_data *)spi->dev.platform_data;

	loader->gpio_cp_status = pdata->gpio_cp_status;

	spi_set_drvdata(spi, loader);

	loader->dev.minor = MISC_DYNAMIC_MINOR;
	loader->dev.name = MODEM_BOOT_DEV_SPI;
	loader->dev.fops = &modem_spi_boot_fops;
	ret = misc_register(&loader->dev);
	if (ret) {
		mif_err("ERR! misc_register fail (err %d)\n", ret);
		goto err_setup;
	}

	mif_debug("---\n");
	return 0;

err_setup:
	mutex_destroy(&loader->lock);
	kfree(loader);

err_alloc:
	mif_err("xxx\n");
	return ret;
}
static int link_pm_runtime_get_active(struct link_pm_data *pm_data)
{
	int ret;
	struct usb_link_device *usb_ld = pm_data->usb_ld;
	struct device *dev = &usb_ld->usbdev->dev;

	if (!usb_ld->if_usb_connected || usb_ld->ld.com_state == COM_NONE)
		return -ENODEV;

	if (pm_data->dpm_suspending) {
		mif_err("Kernel in suspending try get_active later\n");
		/* during dpm_suspending..
		 * if AP get tx data, wake up. */
#ifdef CONFIG_HAS_WAKELOCK
		wake_lock(&pm_data->l2_wake);
#else
		pm_stay_awake(pm_data->miscdev.this_device);
#endif
		return -EAGAIN;
	}

	if (dev->power.runtime_status == RPM_ACTIVE) {
		pm_data->resume_retry_cnt = 0;
		return 0;
	}

	if (!pm_data->resume_requested) {
		mif_debug("QW PM\n");
		queue_delayed_work(pm_data->wq, &pm_data->link_pm_work, 0);
	}
	mif_debug("Wait pm\n");
	INIT_COMPLETION(pm_data->active_done);
	ret = wait_for_completion_timeout(&pm_data->active_done,
						msecs_to_jiffies(500));

	/* If usb link was disconnected while waiting ACTIVE State, usb device
	 * was removed, usb_ld->usbdev->dev is invalid and below
	 * dev->power.runtime_status is also invalid address.
	 * It will be occured LPA L3 -> AP iniated L0 -> disconnect -> link
	 * timeout
	 */
	if (!usb_ld->if_usb_connected || usb_ld->ld.com_state == COM_NONE) {
		mif_info("link disconnected after timed-out\n");
		return -ENODEV;
	}

	if (dev->power.runtime_status != RPM_ACTIVE) {
		mif_info("link_active (%d) retry\n",
						dev->power.runtime_status);
		return -EAGAIN;
	}
	mif_debug("link_active success(%d)\n", ret);
	return 0;
}
static void non_command_handler(struct dpram_link_device *dpld, u16 intr)
{
	struct link_device *ld = &dpld->ld;
	int i = 0;
	int ret = 0;
	u16 tx_mask = 0;

	if (!dpram_ipc_active(dpld))
		return;

	/* Read data from DPRAM */
	for (i = 0; i < dpld->max_ipc_dev; i++) {
		if (dpld->use_skb)
			ret = dpram_ipc_recv_data_with_skb(dpld, i);
		else
			ret = dpram_ipc_recv_data_with_rxb(dpld, i);
		if (ret < 0)
			dpram_reset_rx_circ(dpld, i);

		/* Check and process REQ_ACK (at this time, in == out) */
		if (intr & get_mask_req_ack(dpld, i)) {
			mif_debug("%s: send %s_RES_ACK\n",
				ld->name, get_dev_name(i));
			tx_mask |= get_mask_res_ack(dpld, i);
		}
	}

	if (!dpld->use_skb) {
		/* Schedule soft IRQ for RX */
		tasklet_hi_schedule(&dpld->rx_tsk);
	}

	/* Try TX via DPRAM */
	for (i = 0; i < dpld->max_ipc_dev; i++) {
		if (atomic_read(&dpld->res_required[i]) > 0) {
			ret = dpram_try_ipc_tx(dpld, i);
			if (ret > 0) {
				atomic_set(&dpld->res_required[i], 0);
				tx_mask |= get_mask_send(dpld, i);
			} else if (ret == -ENOSPC) {
				tx_mask |= get_mask_req_ack(dpld, i);
			}
		}
	}

	if (tx_mask) {
		send_intr(dpld, INT_NON_CMD(tx_mask));
		mif_debug("%s: send intr 0x%04X\n", ld->name, tx_mask);
	}
}
static int dpram_ioctl(struct link_device *ld, struct io_device *iod,
		unsigned int cmd, unsigned long arg)
{
	struct dpram_link_device *dpld = to_dpram_link_device(ld);
	int err = 0;

	mif_info("%s: cmd 0x%08X\n", ld->name, cmd);

	switch (cmd) {
	case IOCTL_DPRAM_INIT_STATUS:
		mif_debug("%s: get dpram init status\n", ld->name);
		return dpld->dpram_init_status;

	default:
		if (dpld->ext_ioctl) {
			err = dpld->ext_ioctl(dpld, iod, cmd, arg);
		} else {
			mif_err("%s: ERR! invalid cmd 0x%08X\n", ld->name, cmd);
			err = -EINVAL;
		}

		break;
	}

	return err;
}
static inline int link_pm_slave_wake(struct link_pm_data *pm_data)
{
	int spin = 20;

	/* when slave device is in sleep, wake up slave cpu first */
	if (gpio_get_value(pm_data->gpio_link_hostwake)
				!= HOSTWAKE_TRIGLEVEL) {
		if (gpio_get_value(pm_data->gpio_link_slavewake)) {
			gpio_set_value(pm_data->gpio_link_slavewake, 0);
			mif_info("gpio [SWK] set [0]\n");
			mdelay(5);
		}
		gpio_set_value(pm_data->gpio_link_slavewake, 1);
		mif_info("gpio [SWK] set [1]\n");
		mdelay(5);

		/* wait host wake signal*/
		while (spin-- && gpio_get_value(pm_data->gpio_link_hostwake) !=
							HOSTWAKE_TRIGLEVEL)
			mdelay(5);
	}
	/* runtime pm goes to active */
	if (!gpio_get_value(pm_data->gpio_link_active)) {
		mif_debug("gpio [H ACTV : %d] set 1\n",
				gpio_get_value(pm_data->gpio_link_active));
		gpio_set_value(pm_data->gpio_link_active, 1);
	}
	return spin;
}
/* flow control CM from CP, it use in serial devices */
int link_rx_flowctl_cmd(struct link_device *ld, const char *data, size_t len)
{
    struct modem_shared *msd = ld->msd;
    unsigned short *cmd, *end = (unsigned short *)(data + len);

    mif_debug("flow control cmd: size=%d\n", len);

    for (cmd = (unsigned short *)data; cmd < end; cmd++) {
        switch (*cmd) {
        case CMD_SUSPEND:
            iodevs_for_each(msd, iodev_netif_stop, 0);
            ld->raw_tx_suspended = true;
            mif_info("flowctl CMD_SUSPEND(%04X)\n", *cmd);
            break;

        case CMD_RESUME:
            iodevs_for_each(msd, iodev_netif_wake, 0);
            ld->raw_tx_suspended = false;
            complete_all(&ld->raw_tx_resumed_by_cp);
            mif_info("flowctl CMD_RESUME(%04X)\n", *cmd);
            break;

        default:
            mif_err("flowctl BAD CMD: %04X\n", *cmd);
            break;
        }
    }

    return 0;
}
static int cbp72_boot_off(struct modem_ctl *mc)
{
	int ret;
	struct link_device *ld = get_current_link(mc->bootd);
	struct dpram_link_device *dpld = to_dpram_link_device(ld);
	mif_debug("\n");
	/* Wait here until the PHONE is up.
	 * Waiting as the this called from IOCTL->UM thread */
	mif_info("Waiting for INT_CMD_PHONE_START\n");
	ret = wait_for_completion_interruptible_timeout(
			&dpld->dpram_init_cmd, DPRAM_INIT_TIMEOUT);
	if (!ret) {
		/* ret == 0 on timeout, ret < 0 if interrupted */
		mif_err("Timeout!!! (PHONE_START was not arrived.)\n");
		return -ENXIO;
	}

	mif_info("Waiting for INT_CMD_PIF_INIT_DONE\n");
	ret = wait_for_completion_interruptible_timeout(
			&dpld->modem_pif_init_done, PIF_TIMEOUT);
	if (!ret) {
		mif_err("Timeout!!! (PIF_INIT_DONE was not arrived.)\n");
		return -ENXIO;
	}
	mc->bootd->modem_state_changed(mc->bootd, STATE_ONLINE);

	wake_unlock(&mc->mc_wake_lock);

	return 0;
}
static int exynos_frequency_unlock(struct device *dev)
{
	int ret = 0;
	struct device *busdev = dev_get("exynos-busfreq");

	if (atomic_read(&umts_link_pm_data.freqlock) == 1) {
		/* cpu frequency unlock */
		exynos_cpufreq_lock_free(DVFS_LOCK_ID_USB_IF);

		/* bus frequency unlock */
		ret = dev_unlock(busdev, dev);
		if (ret < 0) {
			mif_err("ERR: dev_unlock error: %d\n", ret);
			goto exit;
		}

		/* unlock minimum number of cpu cores */
		cpufreq_pegasusq_min_cpu_unlock();

		atomic_set(&umts_link_pm_data.freqlock, 0);
		mif_debug("success\n");
	}
exit:
	return ret;
}
static int usb_init_communication(struct link_device *ld,
			struct io_device *iod)
{
	int err = 0;
	switch (iod->format) {
	case IPC_BOOT:
		ld->com_state = COM_BOOT;
		skb_queue_purge(&ld->sk_fmt_tx_q);
		break;

	case IPC_RAMDUMP:
		ld->com_state = COM_CRASH;
		break;

	case IPC_FMT:
		err = start_ipc(ld, iod);
		break;

	case IPC_RFS:
	case IPC_RAW:

	default:
		ld->com_state = COM_ONLINE;
		break;
	}

	mif_debug("com_state = %d\n", ld->com_state);
	return err;
}
Beispiel #12
0
static void idpram_resume_retry(struct work_struct *work)
{
	struct idpram_link_pm_data *pm_data =
		container_of(work, struct idpram_link_pm_data, \
		resume_work.work);

	mif_debug("MIF: %s\n", __func__);

	if (!idpram_resume_check(pm_data)) {
		mif_info("MIF: idpram resume ok\n");
		idpram_write_lock(pm_data, 0);
		wake_lock_timeout(&pm_data->hold_wlock, msecs_to_jiffies(20));
		return;
	}
	if (pm_data->resume_retry--) {
		schedule_delayed_work(&pm_data->resume_work, \
			msecs_to_jiffies(200));
		wake_lock_timeout(&pm_data->hold_wlock, msecs_to_jiffies(260));
	} else {
		mif_info("MIF: idpram resume T-I-M-E-O-UT\n");
		idpram_timeout_handler(pm_data);
		/* hold wakelock until uevnet sent to rild */
		wake_lock_timeout(&pm_data->hold_wlock, HZ*7);
		idpram_write_lock(pm_data, 0);
	}
}
/**
@brief		check whether or not TX is possible via the link

@param mld	the pointer to a mem_link_device instance
@param dev	the pointer to a mem_ipc_device instance (IPC_FMT, etc.)
@param skb	the pointer to an skb that will be transmitted

@retval "> 0"	the size of the data in @b @@skb if there is NO ERROR
@retval "< 0"	an error code (-EIO or -EBUSY)
*/
static inline int check_tx_link(struct mem_link_device *mld,
				struct mem_ipc_device *dev,
				struct sk_buff *skb)
{
	struct link_device *ld = &mld->link_dev;
	struct modem_ctl *mc = ld->mc;
	struct sk_buff_head *skb_txq = dev->skb_txq;
	int ret = skb->len;

	if (unlikely(cp_online(mc) && !ipc_active(mld)))
		return -EIO;

	if (unlikely(skb_txq->qlen >= MAX_SKB_TXQ_DEPTH)) {
#ifdef DEBUG_MODEM_IF
		struct io_device *iod = skbpriv(skb)->iod;
		mif_debug("%s: %s->%s: ERR! %s "\
			  "SKB_TXQ qlen %d >= limit %d\n",
			  ld->name, iod->name, mc->name,
			  dev->name, skb_txq->qlen, MAX_SKB_TXQ_DEPTH);
#endif
		return -EBUSY;
	}

	return ret;
}
static int exynos_frequency_lock(struct device *dev)
{
	unsigned int level, cpufreq = 600; /* 200 ~ 1400 */
	unsigned int busfreq = 400200; /* 100100 ~ 400200 */
	int ret = 0, lock_id;
	atomic_t *freqlock;
	struct device *busdev = dev_get("exynos-busfreq");

	if (!strcmp(dev->bus->name, "usb")) {
		lock_id = DVFS_LOCK_ID_USB_IF;
		cpufreq = 600;
		freqlock = &umts_link_pm_data.freq_usblock;
	} else if (!strcmp(dev->bus->name, "platform")) { // for dpram lock
		lock_id = DVFS_LOCK_ID_DPRAM_IF;
		cpufreq = 800;
		freqlock = &umts_link_pm_data.freq_dpramlock;
	} else {
		mif_err("ERR: Unkown unlock ID (%s)\n", dev->bus->name);
		goto exit;
	}
	
	if (atomic_read(freqlock) == 0) {
		/* cpu frequency lock */
		ret = exynos_cpufreq_get_level(cpufreq * 1000, &level);
		if (ret < 0) {
			mif_err("ERR: exynos_cpufreq_get_level fail: %d\n",
					ret);
			goto exit;
		}

		ret = exynos_cpufreq_lock(lock_id, level);
		if (ret < 0) {
			mif_err("ERR: exynos_cpufreq_lock fail: %d\n", ret);
			goto exit;
		}

		/* bus frequncy lock */
		if (!busdev) {
			mif_err("ERR: busdev is not exist\n");
			ret = -ENODEV;
			goto exit;
		}

		ret = dev_lock(busdev, dev, busfreq);
		if (ret < 0) {
			mif_err("ERR: dev_lock error: %d\n", ret);
			goto exit;
		}

		/* lock minimum number of cpu cores */
		cpufreq_pegasusq_min_cpu_lock(2);

		atomic_set(freqlock, 1);
		mif_debug("level=%d, cpufreq=%d MHz, busfreq=%06d\n",
				level, cpufreq, busfreq);
	}
exit:
	return ret;
}
static void cdc_ncm_status(struct if_usb_devdata *pipe_data, struct urb *urb)
{
	struct cdc_ncm_ctx *ctx;
	struct usb_cdc_notification *event;

	ctx = (struct cdc_ncm_ctx *)pipe_data->sedata;

	if (urb->actual_length < sizeof(*event))
		return;

	/* test for split data in 8-byte chunks */
	if (test_and_clear_bit(EVENT_STS_SPLIT, &pipe_data->flags)) {
		cdc_ncm_speed_change(ctx,
		      (struct usb_cdc_speed_change *)urb->transfer_buffer);
		return;
	}

	event = urb->transfer_buffer;

	mif_debug("event: %d by ep=%d\n", event->bNotificationType,
		usb_pipeendpoint(urb->pipe));

	switch (event->bNotificationType) {
	case USB_CDC_NOTIFY_NETWORK_CONNECTION:
		/*
		 * According to the CDC NCM specification ch.7.1
		 * USB_CDC_NOTIFY_NETWORK_CONNECTION notification shall be
		 * sent by device after USB_CDC_NOTIFY_SPEED_CHANGE.
		 */
		ctx->connected = event->wValue;
		pipe_data->net_connected = (event->wValue) ? true : false;

		printk(KERN_INFO KBUILD_MODNAME
			": network connection: %s connected\n",
			ctx->connected ? "" : "dis");

		if (ctx->connected)
			netif_carrier_on(pipe_data->iod->ndev);
		else {
			netif_carrier_off(pipe_data->iod->ndev);
			ctx->tx_speed = ctx->rx_speed = 0;
		}
		break;

	case USB_CDC_NOTIFY_SPEED_CHANGE:
		if (urb->actual_length < (sizeof(*event) +
					sizeof(struct usb_cdc_speed_change)))
			set_bit(EVENT_STS_SPLIT, &pipe_data->flags);
		else
			cdc_ncm_speed_change(ctx,
				(struct usb_cdc_speed_change *) &event[1]);
		break;

	default:
		mif_err("unexpected notification 0x%02x!\n",
			event->bNotificationType);
		break;
	}
}
static int if_usb_reset_resume(struct usb_interface *intf)
{
	int ret;

	mif_debug("\n");
	ret = if_usb_resume(intf);
	return ret;
}
static void dpram_send_ipc(struct link_device *ld, int dev,
			struct io_device *iod, struct sk_buff *skb)
{
	struct dpram_link_device *dpld = to_dpram_link_device(ld);
	struct sk_buff_head *txq = ld->skb_txq[dev];
	int ret;
	u16 mask;

	skb_queue_tail(txq, skb);
	if (txq->qlen > 1024) {
		mif_debug("%s: %s txq->qlen %d > 1024\n",
			ld->name, get_dev_name(dev), txq->qlen);
	}

	if (dpld->dp_type == CP_IDPRAM) {
		if (dpram_wake_up(dpld) < 0) {
			trigger_force_cp_crash(dpld);
			return;
		}
	}

	if (!dpram_ipc_active(dpld))
		goto exit;

	if (atomic_read(&dpld->res_required[dev]) > 0) {
		mif_debug("%s: %s_TXQ is full\n", ld->name, get_dev_name(dev));
		goto exit;
	}

	ret = dpram_try_ipc_tx(dpld, dev);
	if (ret > 0) {
		mask = get_mask_send(dpld, dev);
		send_intr(dpld, INT_NON_CMD(mask));
	} else if (ret == -ENOSPC) {
		mask = get_mask_req_ack(dpld, dev);
		send_intr(dpld, INT_NON_CMD(mask));
		mif_info("%s: Send REQ_ACK 0x%04X\n", ld->name, mask);
	} else {
		mif_info("%s: dpram_try_ipc_tx fail (err %d)\n", ld->name, ret);
	}

exit:
	if (dpld->dp_type == CP_IDPRAM)
		dpram_allow_sleep(dpld);
}
Beispiel #18
0
static int idpram_pm_resume(struct device *dev)
{
	struct idpram_link_pm_data *pm_data = pm;

	idpram_resume_init(pm_data);
	gpio_set_value(pm_data->mdata->gpio_pda_active, 1);
	mif_debug("MIF: <%s>\n", __func__);
	return 0;
}
Beispiel #19
0
/*
  ret < 0  : error
  ret == 0 : no data
  ret > 0  : valid data
*/
static int dpram_ipc_recv_data(struct dpram_link_device *dpld, int dev)
{
	struct link_device *ld = &dpld->ld;
	struct dpram_rxb *rxb;
	u8 __iomem *src = get_rx_buff(dpld, dev);
	u32 qsize = get_rx_buff_size(dpld, dev);
	u32 in = get_rx_head(dpld, dev);
	u32 out = get_rx_tail(dpld, dev);
	u32 rcvd = 0;
	struct mif_irq_map map;

	if (in == out)
		return 0;

	if (dev == IPC_FMT) {
		set_dpram_map(dpld, &map);
		mif_irq_log(ld->mc->msd, map, "ipc_recv", sizeof("ipc_recv"));
	}

	/* Get data length in DPRAM*/
	rcvd = (in > out) ? (in - out) : (qsize - out + in);

	mif_debug("%s: %s qsize[%u] in[%u] out[%u] rcvd[%u]\n",
		ld->name, get_dev_name(dev), qsize, in, out, rcvd);

	/* Check each queue */
	if (!dpram_circ_valid(qsize, in, out)) {
		mif_err("%s: ERR! %s_RXQ invalid (size:%d in:%d out:%d)\n",
			ld->name, get_dev_name(dev), qsize, in, out);
#if 0
		set_rx_head(dpld, dev, 0);
		set_rx_tail(dpld, dev, 0);
#else
		dpram_trigger_force_cp_crash(dpld);
#endif
		return -EINVAL;
	}

	/* Allocate an rxb */
	rxb = rxbq_get_free_rxb(&dpld->rxbq[dev]);
	if (!rxb) {
		mif_info("%s: ERR! %s rxbq_get_free_rxb fail\n",
			ld->name, get_dev_name(dev));
		return -ENOMEM;
	}

	/* Read data from each DPRAM buffer */
	dpram_ipc_read(dpld, dev, rxb_put(rxb, rcvd), src, out, rcvd, qsize);

	/* Calculate and set new out */
	out += rcvd;
	if (out >= qsize)
		out -= qsize;
	set_rx_tail(dpld, dev, out);

	return rcvd;
}
static inline void start_hub_work(struct link_pm_data *pm_data, int delay)
{
	if (pm_data->hub_work_running == false) {
		pm_data->hub_work_running = true;
		wake_lock(&pm_data->hub_lock);
		mif_debug("link_pm_hub_work is started\n");
	}

	schedule_delayed_work(&pm_data->link_pm_hub, msecs_to_jiffies(delay));
}
static int cmc220_boot_on(struct modem_ctl *mc)
{
	mif_debug("\n");
	mif_err("<%s>\n", mc->bootd->name);

	mif_err("phone_state = STATE_BOOTING\n");
	mc->iod->modem_state_changed(mc->iod, STATE_BOOTING);

	return 0;
}
Beispiel #22
0
static int idpram_pm_suspend(struct device *dev)
{
	struct idpram_link_pm_data *pm_data = pm;

	pm_data->pm_states = IDPRAM_PM_SUSPEND_START;
	gpio_set_value(pm_data->mdata->gpio_pda_active, 0);

	mif_debug("MIF: <%s>\n", __func__);

	return 0;
}
static void cmc221_cpufreq_unlock(struct work_struct *work)
{
	struct modem_ctl *mc;
	int tp_level;

	mc = container_of(work, struct modem_ctl, work_cpu_unlock.work);
	tp_level = gpio_get_value(mc->gpio_cpufreq_lock);

	mif_debug("TP Level is (%d)\n", tp_level);
	if (tp_level) {
		mif_debug("maintain cpufreq lock !!!\n");
		schedule_delayed_work(&mc->work_cpu_unlock, 
					msecs_to_jiffies(5000));
	} else {
		if (mc->mdm_data->link_pm_data->freq_unlock) {
			mif_debug("Call freq unlock func.\n");
			mc->mdm_data->link_pm_data->freq_unlock(mc->dev);
		}
	}
}
void cdc_ncm_intr_complete(struct urb *urb)
{
	struct if_usb_devdata *pipe_data = urb->context;
	struct usb_link_device *usb_ld = pipe_data->usb_ld;
	int ret;

	mif_debug("status = %d\n", urb->status);

	switch (urb->status) {
	/* success */
	case -ENOENT:		/* urb killed by L2 suspend */
	case 0:
		usb_ld->rx_cnt++;
		if (urb->actual_length) {
			mif_info("ep=%d\n", usb_pipeendpoint(urb->pipe));
			pr_urb(__func__, urb);
		}
		cdc_ncm_status(pipe_data, urb);
		break;

	case -ESHUTDOWN:	/* hardware gone */
		mif_err("intr shutdown, code %d\n", urb->status);
		return;

	/* NOTE:  not throttling like RX/TX, since this endpoint
	 * already polls infrequently
	 */
	default:
		mif_err("intr status %d\n", urb->status);
		break;
	}

	if (!urb->status) { /*skip -ENOENT L2 enter status */
		memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
		ret = usb_submit_urb(urb, GFP_ATOMIC);
		mif_debug("status: usb_submit_urb ret=%d\n", ret);
		if (ret != 0)
			mif_err("intr resubmit --> %d\n", ret);
	}
}
Beispiel #25
0
/**
@brief		forbid CP from going to sleep

Wakes up a CP if it can sleep and increases the "ref_cnt" counter in the
mem_link_device instance.

@param mld	the pointer to a mem_link_device instance

@remark		CAUTION!!! permit_cp_sleep() MUST be invoked after
		forbid_cp_sleep() success to decrease the "ref_cnt" counter.
*/
static void forbid_cp_sleep(struct mem_link_device *mld)
{
	struct modem_link_pm *pm = &mld->link_dev.pm;

	atomic_inc(&pm->ref_cnt);
	mif_debug("ref_cnt %d\n", atomic_read(&pm->ref_cnt));

	if (atomic_read(&pm->ref_cnt) > 1)
		return;

	if (pm->request_hold)
		pm->request_hold(pm);
}
Beispiel #26
0
static void dpram_allow_sleep(struct dpram_link_device *dpld)
{
	struct link_device *ld = &dpld->ld;

	if (!dpld->dpctl->sleep)
		return;

	if (atomic_dec_return(&dpld->accessing) <= 0) {
		dpld->dpctl->sleep();
		atomic_set(&dpld->accessing, 0);
		mif_debug("%s: DPRAM sleep possible\n", ld->name);
	}
}
static void handle_no_cp_crash_ack(unsigned long arg)
{
	struct mem_link_device *mld = (struct mem_link_device *)arg;
	struct link_device *ld = &mld->link_dev;
	struct modem_ctl *mc = ld->mc;

	if (cp_crashed(mc)) {
		mif_debug("%s: STATE_CRASH_EXIT without CRASH_ACK\n",
			ld->name);
	} else {
		mif_err("%s: ERR! No CRASH_ACK from CP\n", ld->name);
		mem_handle_cp_crash(mld, STATE_CRASH_EXIT);
	}
}
/**
@brief		forbid CP from going to sleep

Wakes up a CP if it can sleep and increases the "ref_cnt" counter in the
mem_link_device instance.

@param mld	the pointer to a mem_link_device instance

@remark		CAUTION!!! permit_cp_sleep() MUST be invoked after
		forbid_cp_sleep() success to decrease the "ref_cnt" counter.
*/
static void forbid_cp_sleep(struct mem_link_device *mld)
{
	struct modem_link_pm *pm = &mld->link_dev.pm;
	int ref_cnt;

	ref_cnt = atomic_inc_return(&mld->ref_cnt);
	mif_debug("ref_cnt %d\n", ref_cnt);

	if (ref_cnt > 1)
		return;

	if (pm->request_hold)
		pm->request_hold(pm);
}
	/* 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;
}

#ifdef CONFIG_EXYNOS4_CPUFREQ /* Set cpu clock to 800MHz for high TP */
static void cmc221_cpufreq_lock(struct work_struct *work)
{
	struct modem_ctl *mc;

	mc = container_of(work, struct modem_ctl, work_cpu_lock.work);
	if (mc->mdm_data->link_pm_data->freq_lock) {
		mif_debug("Call freq lock func.\n");
		mc->mdm_data->link_pm_data->freq_lock(mc->dev);

		cancel_delayed_work(&mc->work_cpu_unlock);
		schedule_delayed_work(&mc->work_cpu_unlock, 
					msecs_to_jiffies(5000));
	}
}
static int cbp71_off(struct modem_ctl *mc)
{
	mif_debug("cbp71_off()\n");

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

	mif_err("Phone power Off. - do nothing\n");

	mc->iod->modem_state_changed(mc->iod, STATE_OFFLINE);

	return 0;
}