static irqreturn_t sti_pwm_interrupt()

in pwm-sti.c [403:472]


static irqreturn_t sti_pwm_interrupt(int irq, void *data)
{
	struct sti_pwm_chip *pc = data;
	struct device *dev = pc->dev;
	struct sti_cpt_ddata *ddata;
	int devicenum;
	unsigned int cpt_int_stat;
	unsigned int reg;
	int ret = IRQ_NONE;

	ret = regmap_field_read(pc->pwm_cpt_int_stat, &cpt_int_stat);
	if (ret)
		return ret;

	while (cpt_int_stat) {
		devicenum = ffs(cpt_int_stat) - 1;

		ddata = pwm_get_chip_data(&pc->chip.pwms[devicenum]);

		/*
		 * Capture input:
		 *    _______                   _______
		 *   |       |                 |       |
		 * __|       |_________________|       |________
		 *   ^0      ^1                ^2
		 *
		 * Capture start by the first available rising edge. When a
		 * capture event occurs, capture value (CPT_VALx) is stored,
		 * index incremented, capture edge changed.
		 *
		 * After the capture, if the index > 1, we have collected the
		 * necessary data so we signal the thread waiting for it and
		 * disable the capture by setting capture edge to none
		 */

		regmap_read(pc->regmap,
			    PWM_CPT_VAL(devicenum),
			    &ddata->snapshot[ddata->index]);

		switch (ddata->index) {
		case 0:
		case 1:
			regmap_read(pc->regmap, PWM_CPT_EDGE(devicenum), &reg);
			reg ^= PWM_CPT_EDGE_MASK;
			regmap_write(pc->regmap, PWM_CPT_EDGE(devicenum), reg);

			ddata->index++;
			break;

		case 2:
			regmap_write(pc->regmap,
				     PWM_CPT_EDGE(devicenum),
				     CPT_EDGE_DISABLED);
			wake_up(&ddata->wait);
			break;

		default:
			dev_err(dev, "Internal error\n");
		}

		cpt_int_stat &= ~BIT_MASK(devicenum);

		ret = IRQ_HANDLED;
	}

	/* Just ACK everything */
	regmap_write(pc->regmap, PWM_INT_ACK, PWM_INT_ACK_MASK);

	return ret;
}