Esempio n. 1
0
int mcp2210_irq_probe(struct mcp2210_device *dev)
{
    uint i;
    mutex_init(&dev->irq_lock);

    dev->nr_irqs = 0;
    for (i = 0; i < 9; ++i) {
        struct mcp2210_pin_config *pin = &dev->config->pins[i];

        if (!pin->has_irq)
            continue;

        switch (pin->mode) {
        case MCP2210_PIN_DEDICATED:
            if (i != 6)
                return -EINVAL;

            dev->s.poll_intr = 1;
            break;

        case MCP2210_PIN_GPIO:
            dev->s.poll_gpio = 1;
            break;
        };

        if (pin->irq + 1> dev->nr_irqs)
            dev->nr_irqs = pin->irq + 1;
    }

    BUG_ON(dev->nr_irqs > 7);


#ifdef CONFIG_MCP2210_GPIO
    if (dev->s.poll_gpio) {
        ctl_cmd_init(dev, &dev->cmd_poll_gpio,
                     MCP2210_CMD_GET_PIN_VALUE, 0, NULL, 0, false);
        dev->cmd_poll_gpio.head.complete = complete_poll;
        mcp2210_add_cmd(&dev->cmd_poll_gpio.head, false);
    }
#endif /* CONFIG_MCP2210_GPIO */

    if (dev->s.poll_intr) {
        ctl_cmd_init(dev, &dev->cmd_poll_intr,
                     MCP2210_CMD_GET_INTERRUPTS, 0, NULL, 0, false);
        dev->cmd_poll_intr.head.complete = complete_poll;
        mcp2210_add_cmd(&dev->cmd_poll_intr.head, false);
    }

    return 0;
}
Esempio n. 2
0
static int complete_poll(struct mcp2210_cmd *cmd_head, void *context)
{
	struct mcp2210_device *dev = cmd_head->dev;
	struct mcp2210_cmd_ctl *cmd = (void*)cmd_head;
	unsigned long now = jiffies;
	int enabled;
	unsigned long interval;
	unsigned long interval_j;
	unsigned long next;
	long next_diff;

	mcp2210_debug();

	if (dev->dead)
		return -EINPROGRESS;

	if (cmd->req.cmd == MCP2210_CMD_GET_PIN_VALUE) {
		enabled = dev->poll_gpio;
		interval = dev->config->poll_gpio_usecs;
		dev->last_poll_gpio = now;
	} else {
		enabled = dev->poll_intr;
		interval = dev->config->poll_intr_usecs;
		dev->last_poll_intr = now;
	}

	if (dev->suppress_poll_warn && jiffdiff(dev->suppress_poll_warn, now) <= 0)
		dev->suppress_poll_warn = 0;

	if (!enabled)
		return -EINPROGRESS;

	interval_j = usecs_to_jiffies(interval);
	next = dev->eps[EP_OUT].submit_time + interval_j;
	next_diff = jiffdiff(next, now);
	cmd->head.delayed = 1;

	if (next_diff < 0) {
		next = now + interval_j;
		if (!dev->suppress_poll_warn)
			warn_poll_past_due(dev, now, -next_diff);
	}
	cmd->head.delay_until = next;

#if 0
	mcp2210_debug("interval_j: %lu, submit_time: %lu, next: %lu, jiffies: %lu",
		      interval_j, dev->eps[EP_OUT].submit_time, next, jiffies);
#endif

	cmd->head.state = MCP2210_STATE_NEW;

	mcp2210_add_cmd(cmd_head, false);

	return -EINPROGRESS; /* tell process_commands not to free us */
}
Esempio n. 3
0
static int complete_poll(struct mcp2210_cmd *cmd_head, void *context)
{
    struct mcp2210_device *dev = cmd_head->dev;
    struct mcp2210_cmd_ctl *cmd = (void*)cmd_head;
    int enabled;
    unsigned long interval;
    unsigned long now = jiffies;

    mcp2210_debug();

    if (dev->dead)
        return -EINPROGRESS;

    if (cmd->req.cmd == MCP2210_CMD_GET_PIN_VALUE) {
        enabled = dev->s.poll_gpio;
        interval = dev->config->poll_gpio_usecs;
        dev->s.last_poll_gpio = now;
    } else {
        enabled = dev->s.poll_intr;
        interval = dev->config->poll_intr_usecs;
        dev->s.last_poll_intr = now;
    }

    if (!enabled)
        return -EINPROGRESS;

    if (1) {
        unsigned long interval_j = usecs_to_jiffies(interval);
        unsigned long next = dev->eps[EP_OUT].submit_time + interval_j;
        cmd->head.delayed = 1;

        if (jiffdiff(next, now) < 0) {
            mcp2210_warn("poll interval collapse, restarting universe");
            next = jiffies + interval_j;
        }
        cmd->head.delay_until = next;

#if 0
        mcp2210_debug("interval_j: %lu, submit_time: %lu, next: %lu, jiffies: %lu",
                      interval_j, dev->eps[EP_OUT].submit_time, next, jiffies);
#endif
    }

    cmd->head.state = MCP2210_STATE_NEW;

    mcp2210_add_cmd(cmd_head, false);

    return -EINPROGRESS; /* tell process_commands not to free us */
}
Esempio n. 4
0
/******************************************************************************
 * probe & remove
 */
int mcp2210_irq_probe(struct mcp2210_device *dev)
{
	uint i;
	int ret;

	mcp2210_info();
	mutex_init(&dev->irq_lock);

	dev->nr_irqs = 0;
	dev->poll_intr = 0;
	dev->poll_gpio = 0;

	for (i = 0; i < MCP2210_NUM_PINS; ++i) {
		const struct mcp2210_pin_config *pin = &dev->config->pins[i];

		if (pin->mode == MCP2210_PIN_SPI || !pin->has_irq)
			continue;

		++dev->nr_irqs;
		BUG_ON(dev->irq_revmap[i]);
		dev->irq_revmap[i] = pin->irq;

		if (pin->mode == MCP2210_PIN_DEDICATED)
			dev->poll_intr = 1;
		else if (pin->mode == MCP2210_PIN_GPIO) {
			dev->poll_gpio = 1;
			dev->irq_type[i] = pin->irq_type;
		}
	}

	if (!dev->nr_irqs)
		return 0;

	ret = irq_alloc_descs(-1, 0, dev->nr_irqs, 0);
	if (ret < 0) {
		/* CONFIG_SPARSE_IRQ needed? */
		mcp2210_err("Failed to allocate %u irq descriptors: %d", dev->nr_irqs, ret);
		return ret;
	}
	dev->irq_base = ret;

	for (i = 0; i < dev->nr_irqs; ++i) {
		int virq = dev->irq_base + i;

		dev->irq_descs[i] = irq_to_desc(virq);
		BUG_ON(!dev->irq_descs[i]);
		irq_set_chip_data(virq, dev);
		irq_set_chip(virq, &mcp2210_irq_chip);

#if defined(CONFIG_ARM) && LINUX_VERSION_CODE < KERNEL_VERSION(4,3,0)
		set_irq_flags(virq, 0);
#else
		irq_set_noprobe(virq);
#endif
	}

#ifdef CONFIG_MCP2210_GPIO
	if (dev->poll_gpio) {
		ctl_cmd_init(dev, &dev->cmd_poll_gpio,
			     MCP2210_CMD_GET_PIN_VALUE, 0, NULL, 0, false);
		dev->cmd_poll_gpio.head.complete = complete_poll;
		mcp2210_add_cmd(&dev->cmd_poll_gpio.head, false);
	}
#endif /* CONFIG_MCP2210_GPIO */

	if (dev->poll_intr) {
		/* read and then reset */
		ctl_cmd_init(dev, &dev->cmd_poll_intr,
			     MCP2210_CMD_GET_INTERRUPTS, 0, NULL, 0, false);
		dev->cmd_poll_intr.head.complete = complete_poll;
		mcp2210_add_cmd(&dev->cmd_poll_intr.head, false);
	}

	dev->is_irq_probed = 1;
	dev->suppress_poll_warn = 0;

	return 0;
}