static void sossi_stop_transfer(void) { /* WE */ sossi_set_bits(SOSSI_INIT2_REG, 1 << 4); /* CS active low */ sossi_set_bits(SOSSI_INIT1_REG, 1 << 30); /* FIXME: locking? */ }
static void sossi_read_data(void *data, unsigned int len) { clk_enable(sossi.fck); set_timing(RD_ACCESS); _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width); /* CMD#/DATA */ sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); set_cycles(len); sossi_start_transfer(); while (len >= 4) { *(u32 *) data = sossi_read_reg(SOSSI_FIFO_REG); len -= 4; data += 4; } while (len >= 2) { *(u16 *) data = sossi_read_reg16(SOSSI_FIFO_REG); len -= 2; data += 2; } while (len) { *(u8 *) data = sossi_read_reg8(SOSSI_FIFO_REG); len--; data++; } sossi_stop_transfer(); clk_disable(sossi.fck); }
static void sossi_transfer_area(int width, int height, void (callback)(void *data), void *data) { BUG_ON(callback == NULL); sossi.lcdc_callback = callback; sossi.lcdc_callback_data = data; clk_enable(sossi.fck); set_timing(WR_ACCESS); _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width); _set_tearsync_mode(sossi.tearsync_mode, sossi.tearsync_line); /* CMD#/DATA */ sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); set_cycles(width * height * sossi.bus_pick_width / 8); sossi_start_transfer(); if (sossi.tearsync_mode) { /* * Wait for the sync signal and start the transfer only * then. We can't seem to be able to use HW sync DMA for * this since LCD DMA shows huge latencies, as if it * would ignore some of the DMA requests from SoSSI. */ unsigned long flags; spin_lock_irqsave(&sossi.lock, flags); sossi.vsync_dma_pending++; spin_unlock_irqrestore(&sossi.lock, flags); } else /* Just start the transfer right away. */ omap_enable_lcd_dma(); }
static void set_cycles(unsigned int len) { unsigned long nr_cycles = len / (sossi.bus_pick_width / 8); BUG_ON((nr_cycles - 1) & ~0x3ffff); sossi_clear_bits(SOSSI_INIT1_REG, 0x3ffff); sossi_set_bits(SOSSI_INIT1_REG, (nr_cycles - 1) & 0x3ffff); }
static void sossi_write_data(const void *data, unsigned int len) { set_timing(WR_ACCESS); /* CMD#/DATA */ sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); set_cycles(len); sossi_start_transfer(); send_data(data, len); sossi_stop_transfer(); wait_end_of_write(); }
static void sossi_write_data(const void *data, unsigned int len) { clk_enable(sossi.fck); set_timing(WR_ACCESS); _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width); /* CMD#/DATA */ sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); set_cycles(len); sossi_start_transfer(); send_data(data, len); sossi_stop_transfer(); wait_end_of_write(); clk_disable(sossi.fck); }
static void _set_tearsync_mode(int mode, unsigned line) { u32 l; l = sossi_read_reg(SOSSI_TEARING_REG); l &= ~(((1 << 11) - 1) << 15); l |= line << 15; l &= ~(0x3 << 26); l |= mode << 26; sossi_write_reg(SOSSI_TEARING_REG, l); if (mode) sossi_set_bits(SOSSI_INIT2_REG, 1 << 6); /* TE logic */ else sossi_clear_bits(SOSSI_INIT2_REG, 1 << 6); }
static void sossi_transfer_area(int width, int height, void (callback)(void *data), void *data) { BUG_ON(callback == NULL); sossi.lcdc_callback = callback; sossi.lcdc_callback_data = data; set_timing(WR_ACCESS); /* CMD#/DATA */ sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); set_cycles(width * height * sossi.bus_pick_width / 8); sossi_start_transfer(); omap_enable_lcd_dma(); }
static void sossi_read_data(void *data, unsigned int len) { set_timing(RD_ACCESS); /* CMD#/DATA */ sossi_set_bits(SOSSI_INIT1_REG, 1 << 18); set_cycles(len); sossi_start_transfer(); while (len >= 4) { *(u32 *) data = sossi_read_reg(SOSSI_FIFO_REG); len -= 4; data += 4; } while (len >= 2) { *(u16 *) data = sossi_read_reg16(SOSSI_FIFO_REG); len -= 2; data += 2; } while (len) { *(u8 *) data = sossi_read_reg8(SOSSI_FIFO_REG); len--; data++; } sossi_stop_transfer(); }