linux/drivers/staging/fbtft/fb_ra8875.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * FBTFT driver for the RA8875 LCD Controller
   4 * Copyright by Pf@nne & NOTRO
   5 */
   6
   7#include <linux/module.h>
   8#include <linux/kernel.h>
   9#include <linux/init.h>
  10#include <linux/delay.h>
  11
  12#include <linux/gpio/consumer.h>
  13#include "fbtft.h"
  14
  15#define DRVNAME "fb_ra8875"
  16
  17static int write_spi(struct fbtft_par *par, void *buf, size_t len)
  18{
  19        struct spi_transfer t = {
  20                .tx_buf = buf,
  21                .len = len,
  22                .speed_hz = 1000000,
  23        };
  24        struct spi_message m;
  25
  26        fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
  27                          "%s(len=%zu): ", __func__, len);
  28
  29        if (!par->spi) {
  30                dev_err(par->info->device,
  31                        "%s: par->spi is unexpectedly NULL\n", __func__);
  32                return -1;
  33        }
  34
  35        spi_message_init(&m);
  36        spi_message_add_tail(&t, &m);
  37        return spi_sync(par->spi, &m);
  38}
  39
  40static int init_display(struct fbtft_par *par)
  41{
  42        gpiod_set_value(par->gpio.dc, 1);
  43
  44        fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
  45                      "%s()\n", __func__);
  46        fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
  47                      "display size %dx%d\n",
  48                par->info->var.xres,
  49                par->info->var.yres);
  50
  51        par->fbtftops.reset(par);
  52
  53        if ((par->info->var.xres == 320) && (par->info->var.yres == 240)) {
  54                /* PLL clock frequency */
  55                write_reg(par, 0x88, 0x0A);
  56                write_reg(par, 0x89, 0x02);
  57                mdelay(10);
  58                /* color deep / MCU Interface */
  59                write_reg(par, 0x10, 0x0C);
  60                /* pixel clock period  */
  61                write_reg(par, 0x04, 0x03);
  62                mdelay(1);
  63                /* horizontal settings */
  64                write_reg(par, 0x14, 0x27);
  65                write_reg(par, 0x15, 0x00);
  66                write_reg(par, 0x16, 0x05);
  67                write_reg(par, 0x17, 0x04);
  68                write_reg(par, 0x18, 0x03);
  69                /* vertical settings */
  70                write_reg(par, 0x19, 0xEF);
  71                write_reg(par, 0x1A, 0x00);
  72                write_reg(par, 0x1B, 0x05);
  73                write_reg(par, 0x1C, 0x00);
  74                write_reg(par, 0x1D, 0x0E);
  75                write_reg(par, 0x1E, 0x00);
  76                write_reg(par, 0x1F, 0x02);
  77        } else if ((par->info->var.xres == 480) &&
  78                   (par->info->var.yres == 272)) {
  79                /* PLL clock frequency  */
  80                write_reg(par, 0x88, 0x0A);
  81                write_reg(par, 0x89, 0x02);
  82                mdelay(10);
  83                /* color deep / MCU Interface */
  84                write_reg(par, 0x10, 0x0C);
  85                /* pixel clock period  */
  86                write_reg(par, 0x04, 0x82);
  87                mdelay(1);
  88                /* horizontal settings */
  89                write_reg(par, 0x14, 0x3B);
  90                write_reg(par, 0x15, 0x00);
  91                write_reg(par, 0x16, 0x01);
  92                write_reg(par, 0x17, 0x00);
  93                write_reg(par, 0x18, 0x05);
  94                /* vertical settings */
  95                write_reg(par, 0x19, 0x0F);
  96                write_reg(par, 0x1A, 0x01);
  97                write_reg(par, 0x1B, 0x02);
  98                write_reg(par, 0x1C, 0x00);
  99                write_reg(par, 0x1D, 0x07);
 100                write_reg(par, 0x1E, 0x00);
 101                write_reg(par, 0x1F, 0x09);
 102        } else if ((par->info->var.xres == 640) &&
 103                   (par->info->var.yres == 480)) {
 104                /* PLL clock frequency */
 105                write_reg(par, 0x88, 0x0B);
 106                write_reg(par, 0x89, 0x02);
 107                mdelay(10);
 108                /* color deep / MCU Interface */
 109                write_reg(par, 0x10, 0x0C);
 110                /* pixel clock period */
 111                write_reg(par, 0x04, 0x01);
 112                mdelay(1);
 113                /* horizontal settings */
 114                write_reg(par, 0x14, 0x4F);
 115                write_reg(par, 0x15, 0x05);
 116                write_reg(par, 0x16, 0x0F);
 117                write_reg(par, 0x17, 0x01);
 118                write_reg(par, 0x18, 0x00);
 119                /* vertical settings */
 120                write_reg(par, 0x19, 0xDF);
 121                write_reg(par, 0x1A, 0x01);
 122                write_reg(par, 0x1B, 0x0A);
 123                write_reg(par, 0x1C, 0x00);
 124                write_reg(par, 0x1D, 0x0E);
 125                write_reg(par, 0x1E, 0x00);
 126                write_reg(par, 0x1F, 0x01);
 127        } else if ((par->info->var.xres == 800) &&
 128                   (par->info->var.yres == 480)) {
 129                /* PLL clock frequency */
 130                write_reg(par, 0x88, 0x0B);
 131                write_reg(par, 0x89, 0x02);
 132                mdelay(10);
 133                /* color deep / MCU Interface */
 134                write_reg(par, 0x10, 0x0C);
 135                /* pixel clock period */
 136                write_reg(par, 0x04, 0x81);
 137                mdelay(1);
 138                /* horizontal settings */
 139                write_reg(par, 0x14, 0x63);
 140                write_reg(par, 0x15, 0x03);
 141                write_reg(par, 0x16, 0x03);
 142                write_reg(par, 0x17, 0x02);
 143                write_reg(par, 0x18, 0x00);
 144                /* vertical settings */
 145                write_reg(par, 0x19, 0xDF);
 146                write_reg(par, 0x1A, 0x01);
 147                write_reg(par, 0x1B, 0x14);
 148                write_reg(par, 0x1C, 0x00);
 149                write_reg(par, 0x1D, 0x06);
 150                write_reg(par, 0x1E, 0x00);
 151                write_reg(par, 0x1F, 0x01);
 152        } else {
 153                dev_err(par->info->device, "display size is not supported!!");
 154                return -1;
 155        }
 156
 157        /* PWM clock */
 158        write_reg(par, 0x8a, 0x81);
 159        write_reg(par, 0x8b, 0xFF);
 160        mdelay(10);
 161
 162        /* Display ON */
 163        write_reg(par, 0x01, 0x80);
 164        mdelay(10);
 165
 166        return 0;
 167}
 168
 169static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
 170{
 171        /* Set_Active_Window */
 172        write_reg(par, 0x30, xs & 0x00FF);
 173        write_reg(par, 0x31, (xs & 0xFF00) >> 8);
 174        write_reg(par, 0x32, ys & 0x00FF);
 175        write_reg(par, 0x33, (ys & 0xFF00) >> 8);
 176        write_reg(par, 0x34, (xs + xe) & 0x00FF);
 177        write_reg(par, 0x35, ((xs + xe) & 0xFF00) >> 8);
 178        write_reg(par, 0x36, (ys + ye) & 0x00FF);
 179        write_reg(par, 0x37, ((ys + ye) & 0xFF00) >> 8);
 180
 181        /* Set_Memory_Write_Cursor */
 182        write_reg(par, 0x46,  xs & 0xff);
 183        write_reg(par, 0x47, (xs >> 8) & 0x03);
 184        write_reg(par, 0x48,  ys & 0xff);
 185        write_reg(par, 0x49, (ys >> 8) & 0x01);
 186
 187        write_reg(par, 0x02);
 188}
 189
 190static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
 191{
 192        va_list args;
 193        int i, ret;
 194        u8 *buf = par->buf;
 195
 196        /* slow down spi-speed for writing registers */
 197        par->fbtftops.write = write_spi;
 198
 199        if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) {
 200                va_start(args, len);
 201                for (i = 0; i < len; i++)
 202                        buf[i] = (u8)va_arg(args, unsigned int);
 203                va_end(args);
 204                fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device,
 205                                  u8, buf, len, "%s: ", __func__);
 206        }
 207
 208        va_start(args, len);
 209        *buf++ = 0x80;
 210        *buf = (u8)va_arg(args, unsigned int);
 211        ret = par->fbtftops.write(par, par->buf, 2);
 212        if (ret < 0) {
 213                va_end(args);
 214                dev_err(par->info->device, "write() failed and returned %dn",
 215                        ret);
 216                return;
 217        }
 218        len--;
 219
 220        udelay(100);
 221
 222        if (len) {
 223                buf = (u8 *)par->buf;
 224                *buf++ = 0x00;
 225                i = len;
 226                while (i--)
 227                        *buf++ = (u8)va_arg(args, unsigned int);
 228
 229                ret = par->fbtftops.write(par, par->buf, len + 1);
 230                if (ret < 0) {
 231                        va_end(args);
 232                        dev_err(par->info->device,
 233                                "write() failed and returned %dn", ret);
 234                        return;
 235                }
 236        }
 237        va_end(args);
 238
 239        /* restore user spi-speed */
 240        par->fbtftops.write = fbtft_write_spi;
 241        udelay(100);
 242}
 243
 244static int write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len)
 245{
 246        u16 *vmem16;
 247        __be16 *txbuf16;
 248        size_t remain;
 249        size_t to_copy;
 250        size_t tx_array_size;
 251        int i;
 252        int ret = 0;
 253        size_t startbyte_size = 0;
 254
 255        fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n",
 256                      __func__, offset, len);
 257
 258        remain = len / 2;
 259        vmem16 = (u16 *)(par->info->screen_buffer + offset);
 260        tx_array_size = par->txbuf.len / 2;
 261        txbuf16 = par->txbuf.buf + 1;
 262        tx_array_size -= 2;
 263        *(u8 *)(par->txbuf.buf) = 0x00;
 264        startbyte_size = 1;
 265
 266        while (remain) {
 267                to_copy = min(tx_array_size, remain);
 268                dev_dbg(par->info->device, "    to_copy=%zu, remain=%zu\n",
 269                        to_copy, remain - to_copy);
 270
 271                for (i = 0; i < to_copy; i++)
 272                        txbuf16[i] = cpu_to_be16(vmem16[i]);
 273
 274                vmem16 = vmem16 + to_copy;
 275                ret = par->fbtftops.write(par, par->txbuf.buf,
 276                        startbyte_size + to_copy * 2);
 277                if (ret < 0)
 278                        return ret;
 279                remain -= to_copy;
 280        }
 281
 282        return ret;
 283}
 284
 285static struct fbtft_display display = {
 286        .regwidth = 8,
 287        .fbtftops = {
 288                .init_display = init_display,
 289                .set_addr_win = set_addr_win,
 290                .write_register = write_reg8_bus8,
 291                .write_vmem = write_vmem16_bus8,
 292                .write = write_spi,
 293        },
 294};
 295
 296FBTFT_REGISTER_DRIVER(DRVNAME, "raio,ra8875", &display);
 297
 298MODULE_ALIAS("spi:" DRVNAME);
 299MODULE_ALIAS("platform:" DRVNAME);
 300MODULE_ALIAS("spi:ra8875");
 301MODULE_ALIAS("platform:ra8875");
 302
 303MODULE_DESCRIPTION("FB driver for the RA8875 LCD Controller");
 304MODULE_AUTHOR("Pf@nne");
 305MODULE_LICENSE("GPL");
 306