Example #1
0
static int usbhs_status_get_each_irq(struct usbhs_priv *priv,
				     struct usbhs_irq_state *state)
{
	struct usbhs_mod *mod = usbhs_mod_get_current(priv);
	u16 intenb0, intenb1;
	unsigned long flags;

	/********************  spin lock ********************/
	usbhs_lock(priv, flags);
	state->intsts0 = usbhs_read(priv, INTSTS0);
	intenb0 = usbhs_read(priv, INTENB0);

	if (usbhs_mod_is_host(priv)) {
		state->intsts1 = usbhs_read(priv, INTSTS1);
		intenb1 = usbhs_read(priv, INTENB1);
	} else {
		state->intsts1 = intenb1 = 0;
	}

	/* mask */
	if (mod) {
		state->brdysts = usbhs_read(priv, BRDYSTS);
		state->nrdysts = usbhs_read(priv, NRDYSTS);
		state->bempsts = usbhs_read(priv, BEMPSTS);

		state->bempsts &= mod->irq_bempsts;
		state->brdysts &= mod->irq_brdysts;
	}
	usbhs_unlock(priv, flags);
	/********************  spin unlock ******************/

	/*
	 * Check whether the irq enable registers and the irq status are set
	 * when IRQF_SHARED is set.
	 */
	if (priv->irqflags & IRQF_SHARED) {
		if (!(intenb0 & state->intsts0) &&
		    !(intenb1 & state->intsts1) &&
		    !(state->bempsts) &&
		    !(state->brdysts))
			return -EIO;
	}

	return 0;
}
Example #2
0
static int usbhsf_fifo_select(struct usbhs_pipe *pipe,
			      struct usbhs_fifo *fifo,
			      int write)
{
	struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
	struct device *dev = usbhs_priv_to_dev(priv);
	int timeout = 1024;
	u16 mask = ((1 << 5) | 0xF);		/* mask of ISEL | CURPIPE */
	u16 base = usbhs_pipe_number(pipe);	/* CURPIPE */

	if (usbhs_pipe_is_busy(pipe) ||
	    usbhsf_fifo_is_busy(fifo))
		return -EBUSY;

	if (usbhs_pipe_is_dcp(pipe)) {
		base |= (1 == write) << 5;	/* ISEL */

		if (usbhs_mod_is_host(priv))
			usbhs_dcp_dir_for_host(pipe, write);
	}

	/* "base" will be used below  */
	if (usbhs_get_dparam(priv, has_sudmac) && !usbhsf_is_cfifo(priv, fifo))
		usbhs_write(priv, fifo->sel, base);
	else
		usbhs_write(priv, fifo->sel, base | MBW_32);

	/* check ISEL and CURPIPE value */
	while (timeout--) {
		if (base == (mask & usbhs_read(priv, fifo->sel))) {
			usbhs_pipe_select_fifo(pipe, fifo);
			return 0;
		}
		udelay(10);
	}

	dev_err(dev, "fifo select error\n");

	return -EIO;
}
Example #3
0
File: pipe.c Project: 020gzh/linux
static int usbhsp_pipe_barrier(struct usbhs_pipe *pipe)
{
	struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
	int timeout = 1024;
	u16 mask = usbhs_mod_is_host(priv) ? (CSSTS | PID_MASK) : PID_MASK;

	/*
	 * make sure....
	 *
	 * Modify these bits when CSSTS = 0, PID = NAK, and no pipe number is
	 * specified by the CURPIPE bits.
	 * When changing the setting of this bit after changing
	 * the PID bits for the selected pipe from BUF to NAK,
	 * check that CSSTS = 0 and PBUSY = 0.
	 */

	/*
	 * CURPIPE bit = 0
	 *
	 * see also
	 *  "Operation"
	 *  - "Pipe Control"
	 *   - "Pipe Control Registers Switching Procedure"
	 */
	usbhs_write(priv, CFIFOSEL, 0);
	usbhs_pipe_disable(pipe);

	do {
		if (!(usbhsp_pipectrl_get(pipe) & mask))
			return 0;

		udelay(10);

	} while (timeout--);

	return -EBUSY;
}
Example #4
0
void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod)
{
	u16 intenb0 = 0;
	u16 intenb1 = 0;
	struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);

	/*
	 * BEMPENB/BRDYENB are picky.
	 * below method is required
	 *
	 *  - clear  INTSTS0
	 *  - update BEMPENB/BRDYENB
	 *  - update INTSTS0
	 */
	usbhs_write(priv, INTENB0, 0);
	if (usbhs_mod_is_host(priv))
		usbhs_write(priv, INTENB1, 0);

	usbhs_write(priv, BEMPENB, 0);
	usbhs_write(priv, BRDYENB, 0);

	/*
	 * see also
	 *	usbhs_interrupt
	 */

	/*
	 * it don't enable DVSE (intenb0) here
	 * but "mod->irq_dev_state" will be called.
	 */
	if (info->irq_vbus)
		intenb0 |= VBSE;

	if (mod) {
		/*
		 * INTSTS0
		 */
		if (mod->irq_ctrl_stage)
			intenb0 |= CTRE;

		if (mod->irq_empty && mod->irq_bempsts) {
			usbhs_write(priv, BEMPENB, mod->irq_bempsts);
			intenb0 |= BEMPE;
		}

		if (mod->irq_ready && mod->irq_brdysts) {
			usbhs_write(priv, BRDYENB, mod->irq_brdysts);
			intenb0 |= BRDYE;
		}

		if (usbhs_mod_is_host(priv)) {
			/*
			 * INTSTS1
			 */
			if (mod->irq_attch)
				intenb1 |= ATTCHE;

			if (mod->irq_dtch)
				intenb1 |= DTCHE;

			if (mod->irq_sign)
				intenb1 |= SIGNE;

			if (mod->irq_sack)
				intenb1 |= SACKE;
		}
	}

	if (intenb0)
		usbhs_write(priv, INTENB0, intenb0);

	if (usbhs_mod_is_host(priv) && intenb1)
		usbhs_write(priv, INTENB1, intenb1);
}
Example #5
0
/*
 *		interrupt
 */
#define INTSTS0_MAGIC 0xF800 /* acknowledge magical interrupt sources */
#define INTSTS1_MAGIC 0xA870 /* acknowledge magical interrupt sources */
static irqreturn_t usbhs_interrupt(int irq, void *data)
{
	struct usbhs_priv *priv = data;
	struct usbhs_irq_state irq_state;

	if (usbhs_status_get_each_irq(priv, &irq_state) < 0)
		return IRQ_NONE;

	/*
	 * clear interrupt
	 *
	 * The hardware is _very_ picky to clear interrupt bit.
	 * Especially INTSTS0_MAGIC, INTSTS1_MAGIC value.
	 *
	 * see
	 *	"Operation"
	 *	 - "Control Transfer (DCP)"
	 *	   - Function :: VALID bit should 0
	 */
	usbhs_write(priv, INTSTS0, ~irq_state.intsts0 & INTSTS0_MAGIC);
	if (usbhs_mod_is_host(priv))
		usbhs_write(priv, INTSTS1, ~irq_state.intsts1 & INTSTS1_MAGIC);

	/*
	 * The driver should not clear the xxxSTS after the line of
	 * "call irq callback functions" because each "if" statement is
	 * possible to call the callback function for avoiding any side effects.
	 */
	if (irq_state.intsts0 & BRDY)
		usbhs_write(priv, BRDYSTS, ~irq_state.brdysts);
	usbhs_write(priv, NRDYSTS, ~irq_state.nrdysts);
	if (irq_state.intsts0 & BEMP)
		usbhs_write(priv, BEMPSTS, ~irq_state.bempsts);

	/*
	 * call irq callback functions
	 * see also
	 *	usbhs_irq_setting_update
	 */

	/* INTSTS0 */
	if (irq_state.intsts0 & VBINT)
		usbhs_mod_info_call(priv, irq_vbus, priv, &irq_state);

	if (irq_state.intsts0 & DVST)
		usbhs_mod_call(priv, irq_dev_state, priv, &irq_state);

	if (irq_state.intsts0 & CTRT)
		usbhs_mod_call(priv, irq_ctrl_stage, priv, &irq_state);

	if (irq_state.intsts0 & BEMP)
		usbhs_mod_call(priv, irq_empty, priv, &irq_state);

	if (irq_state.intsts0 & BRDY)
		usbhs_mod_call(priv, irq_ready, priv, &irq_state);

	if (usbhs_mod_is_host(priv)) {
		/* INTSTS1 */
		if (irq_state.intsts1 & ATTCH)
			usbhs_mod_call(priv, irq_attch, priv, &irq_state);

		if (irq_state.intsts1 & DTCH)
			usbhs_mod_call(priv, irq_dtch, priv, &irq_state);

		if (irq_state.intsts1 & SIGN)
			usbhs_mod_call(priv, irq_sign, priv, &irq_state);

		if (irq_state.intsts1 & SACK)
			usbhs_mod_call(priv, irq_sack, priv, &irq_state);
	}
	return IRQ_HANDLED;
}