static u32 ug_io_transaction(u32 in) { u32 *csr_reg = ug_io_base + EXI_CSR; u32 *data_reg = ug_io_base + EXI_DATA; u32 *cr_reg = ug_io_base + EXI_CR; u32 csr, data, cr; /* select */ csr = EXI_CSR_CLK_32MHZ | EXI_CSR_CS_0; out_be32(csr_reg, csr); /* read/write */ data = in; out_be32(data_reg, data); cr = EXI_CR_TLEN(2) | EXI_CR_READ_WRITE | EXI_CR_TSTART; out_be32(cr_reg, cr); while (in_be32(cr_reg) & EXI_CR_TSTART) barrier(); /* deselect */ out_be32(csr_reg, 0); data = in_be32(data_reg); return data; }
/* * Internal. Start a transfer using "interrupt-driven immediate" mode. */ static void exi_start_idi_transfer_raw(struct exi_channel *exi_channel, void *data, size_t len, int mode) { void __iomem *io_base = exi_channel->io_base; u32 __iomem *csr_reg = io_base + EXI_CSR; u32 val = ~0; unsigned long flags; BUG_ON(len < 1 || len > 4); exi_channel->stats_idi_xfers++; exi_channel->stats_xfers++; if ((mode & EXI_OP_WRITE)) { switch (len) { case 1: val = *((u8 *)data) << 24; break; case 2: val = *((u16 *)data) << 16; break; case 3: val = *((u16 *)data) << 16; val |= *((u8 *)data+2) << 8; break; case 4: val = *((u32 *)data); break; default: break; } } out_be32(io_base + EXI_DATA, val); /* enable the Transfer Complete interrupt */ spin_lock_irqsave(&exi_channel->io_lock, flags); out_be32(csr_reg, in_be32(csr_reg) | EXI_CSR_TCINTMASK); spin_unlock_irqrestore(&exi_channel->io_lock, flags); /* start the transfer */ out_be32(io_base + EXI_CR, EXI_CR_TSTART | EXI_CR_TLEN(len) | (mode&0xf)); }