diff options
author | Yunhong Jiang <yunhong.jiang@intel.com> | 2015-08-04 12:17:53 -0700 |
---|---|---|
committer | Yunhong Jiang <yunhong.jiang@intel.com> | 2015-08-04 15:44:42 -0700 |
commit | 9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (patch) | |
tree | 1c9cafbcd35f783a87880a10f85d1a060db1a563 /kernel/drivers/staging/fbtft/fbtft-io.c | |
parent | 98260f3884f4a202f9ca5eabed40b1354c489b29 (diff) |
Add the rt linux 4.1.3-rt3 as base
Import the rt linux 4.1.3-rt3 as OPNFV kvm base.
It's from git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git linux-4.1.y-rt and
the base is:
commit 0917f823c59692d751951bf5ea699a2d1e2f26a2
Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Date: Sat Jul 25 12:13:34 2015 +0200
Prepare v4.1.3-rt3
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
We lose all the git history this way and it's not good. We
should apply another opnfv project repo in future.
Change-Id: I87543d81c9df70d99c5001fbdf646b202c19f423
Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
Diffstat (limited to 'kernel/drivers/staging/fbtft/fbtft-io.c')
-rw-r--r-- | kernel/drivers/staging/fbtft/fbtft-io.c | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/kernel/drivers/staging/fbtft/fbtft-io.c b/kernel/drivers/staging/fbtft/fbtft-io.c new file mode 100644 index 000000000..a6f091fb9 --- /dev/null +++ b/kernel/drivers/staging/fbtft/fbtft-io.c @@ -0,0 +1,238 @@ +#include <linux/export.h> +#include <linux/errno.h> +#include <linux/gpio.h> +#include <linux/spi/spi.h> +#include "fbtft.h" + +int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len) +{ + struct spi_transfer t = { + .tx_buf = buf, + .len = len, + }; + struct spi_message m; + + fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, + "%s(len=%d): ", __func__, len); + + if (!par->spi) { + dev_err(par->info->device, + "%s: par->spi is unexpectedly NULL\n", __func__); + return -1; + } + + spi_message_init(&m); + if (par->txbuf.dma && buf == par->txbuf.buf) { + t.tx_dma = par->txbuf.dma; + m.is_dma_mapped = 1; + } + spi_message_add_tail(&t, &m); + return spi_sync(par->spi, &m); +} +EXPORT_SYMBOL(fbtft_write_spi); + +/** + * fbtft_write_spi_emulate_9() - write SPI emulating 9-bit + * @par: Driver data + * @buf: Buffer to write + * @len: Length of buffer (must be divisible by 8) + * + * When 9-bit SPI is not available, this function can be used to emulate that. + * par->extra must hold a transformation buffer used for transfer. + */ +int fbtft_write_spi_emulate_9(struct fbtft_par *par, void *buf, size_t len) +{ + u16 *src = buf; + u8 *dst = par->extra; + size_t size = len / 2; + size_t added = 0; + int bits, i, j; + u64 val, dc, tmp; + + fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, + "%s(len=%d): ", __func__, len); + + if (!par->extra) { + dev_err(par->info->device, "%s: error: par->extra is NULL\n", + __func__); + return -EINVAL; + } + if ((len % 8) != 0) { + dev_err(par->info->device, + "error: len=%zu must be divisible by 8\n", len); + return -EINVAL; + } + + for (i = 0; i < size; i += 8) { + tmp = 0; + bits = 63; + for (j = 0; j < 7; j++) { + dc = (*src & 0x0100) ? 1 : 0; + val = *src & 0x00FF; + tmp |= dc << bits; + bits -= 8; + tmp |= val << bits--; + src++; + } + tmp |= ((*src & 0x0100) ? 1 : 0); + *(u64 *)dst = cpu_to_be64(tmp); + dst += 8; + *dst++ = (u8)(*src++ & 0x00FF); + added++; + } + + return spi_write(par->spi, par->extra, size + added); +} +EXPORT_SYMBOL(fbtft_write_spi_emulate_9); + +int fbtft_read_spi(struct fbtft_par *par, void *buf, size_t len) +{ + int ret; + u8 txbuf[32] = { 0, }; + struct spi_transfer t = { + .speed_hz = 2000000, + .rx_buf = buf, + .len = len, + }; + struct spi_message m; + + if (!par->spi) { + dev_err(par->info->device, + "%s: par->spi is unexpectedly NULL\n", __func__); + return -ENODEV; + } + + if (par->startbyte) { + if (len > 32) { + dev_err(par->info->device, + "len=%zu can't be larger than 32 when using 'startbyte'\n", + len); + return -EINVAL; + } + txbuf[0] = par->startbyte | 0x3; + t.tx_buf = txbuf; + fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8, + txbuf, len, "%s(len=%d) txbuf => ", __func__, len); + } + + spi_message_init(&m); + spi_message_add_tail(&t, &m); + ret = spi_sync(par->spi, &m); + fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8, buf, len, + "%s(len=%d) buf <= ", __func__, len); + + return ret; +} +EXPORT_SYMBOL(fbtft_read_spi); + +/* + * Optimized use of gpiolib is twice as fast as no optimization + * only one driver can use the optimized version at a time + */ +int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len) +{ + u8 data; + int i; +#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO + static u8 prev_data; +#endif + + fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, + "%s(len=%d): ", __func__, len); + + while (len--) { + data = *(u8 *) buf; + + /* Start writing by pulling down /WR */ + gpio_set_value(par->gpio.wr, 0); + + /* Set data */ +#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO + if (data == prev_data) { + gpio_set_value(par->gpio.wr, 0); /* used as delay */ + } else { + for (i = 0; i < 8; i++) { + if ((data & 1) != (prev_data & 1)) + gpio_set_value(par->gpio.db[i], + data & 1); + data >>= 1; + prev_data >>= 1; + } + } +#else + for (i = 0; i < 8; i++) { + gpio_set_value(par->gpio.db[i], data & 1); + data >>= 1; + } +#endif + + /* Pullup /WR */ + gpio_set_value(par->gpio.wr, 1); + +#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO + prev_data = *(u8 *) buf; +#endif + buf++; + } + + return 0; +} +EXPORT_SYMBOL(fbtft_write_gpio8_wr); + +int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len) +{ + u16 data; + int i; +#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO + static u16 prev_data; +#endif + + fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len, + "%s(len=%d): ", __func__, len); + + while (len) { + data = *(u16 *) buf; + + /* Start writing by pulling down /WR */ + gpio_set_value(par->gpio.wr, 0); + + /* Set data */ +#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO + if (data == prev_data) { + gpio_set_value(par->gpio.wr, 0); /* used as delay */ + } else { + for (i = 0; i < 16; i++) { + if ((data & 1) != (prev_data & 1)) + gpio_set_value(par->gpio.db[i], + data & 1); + data >>= 1; + prev_data >>= 1; + } + } +#else + for (i = 0; i < 16; i++) { + gpio_set_value(par->gpio.db[i], data & 1); + data >>= 1; + } +#endif + + /* Pullup /WR */ + gpio_set_value(par->gpio.wr, 1); + +#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO + prev_data = *(u16 *) buf; +#endif + buf += 2; + len -= 2; + } + + return 0; +} +EXPORT_SYMBOL(fbtft_write_gpio16_wr); + +int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, void *buf, size_t len) +{ + dev_err(par->info->device, "%s: function not implemented\n", __func__); + return -1; +} +EXPORT_SYMBOL(fbtft_write_gpio16_wr_latched); |