linux/drivers/staging/fbtft/fb_pcd8544.c
<<
>>
Prefs
   1/*
   2 * FB driver for the PCD8544 LCD Controller
   3 *
   4 * The display is monochrome and the video memory is RGB565.
   5 * Any pixel value except 0 turns the pixel on.
   6 *
   7 * Copyright (C) 2013 Noralf Tronnes
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License as published by
  11 * the Free Software Foundation; either version 2 of the License, or
  12 * (at your option) any later version.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 * GNU General Public License for more details.
  18 */
  19
  20#include <linux/module.h>
  21#include <linux/kernel.h>
  22#include <linux/init.h>
  23#include <linux/gpio.h>
  24#include <linux/spi/spi.h>
  25#include <linux/delay.h>
  26
  27#include "fbtft.h"
  28
  29#define DRVNAME        "fb_pcd8544"
  30#define WIDTH          84
  31#define HEIGHT         48
  32#define TXBUFLEN       (84 * 6)
  33#define DEFAULT_GAMMA  "40" /* gamma controls the contrast in this driver */
  34
  35static unsigned tc;
  36module_param(tc, uint, 0);
  37MODULE_PARM_DESC(tc, "TC[1:0] Temperature coefficient: 0-3 (default: 0)");
  38
  39static unsigned bs = 4;
  40module_param(bs, uint, 0);
  41MODULE_PARM_DESC(bs, "BS[2:0] Bias voltage level: 0-7 (default: 4)");
  42
  43static int init_display(struct fbtft_par *par)
  44{
  45        par->fbtftops.reset(par);
  46
  47        /* Function set
  48         *
  49         * 5:1  1
  50         * 2:0  PD - Powerdown control: chip is active
  51         * 1:0  V  - Entry mode: horizontal addressing
  52         * 0:1  H  - Extended instruction set control: extended
  53         */
  54        write_reg(par, 0x21);
  55
  56        /* H=1 Temperature control
  57         *
  58         * 2:1  1
  59         * 1:x  TC1 - Temperature Coefficient: 0x10
  60         * 0:x  TC0
  61         */
  62        write_reg(par, 0x04 | (tc & 0x3));
  63
  64        /* H=1 Bias system
  65         *
  66         * 4:1  1
  67         * 3:0  0
  68         * 2:x  BS2 - Bias System
  69         * 1:x  BS1
  70         * 0:x  BS0
  71         */
  72        write_reg(par, 0x10 | (bs & 0x7));
  73
  74        /* Function set
  75         *
  76         * 5:1  1
  77         * 2:0  PD - Powerdown control: chip is active
  78         * 1:1  V  - Entry mode: vertical addressing
  79         * 0:0  H  - Extended instruction set control: basic
  80         */
  81        write_reg(par, 0x22);
  82
  83        /* H=0 Display control
  84         *
  85         * 3:1  1
  86         * 2:1  D  - DE: 10=normal mode
  87         * 1:0  0
  88         * 0:0  E
  89         */
  90        write_reg(par, 0x08 | 4);
  91
  92        return 0;
  93}
  94
  95static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
  96{
  97        /* H=0 Set X address of RAM
  98         *
  99         * 7:1  1
 100         * 6-0: X[6:0] - 0x00
 101         */
 102        write_reg(par, 0x80);
 103
 104        /* H=0 Set Y address of RAM
 105         *
 106         * 7:0  0
 107         * 6:1  1
 108         * 2-0: Y[2:0] - 0x0
 109         */
 110        write_reg(par, 0x40);
 111}
 112
 113static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
 114{
 115        u16 *vmem16 = (u16 *)par->info->screen_buffer;
 116        u8 *buf = par->txbuf.buf;
 117        int x, y, i;
 118        int ret = 0;
 119
 120        for (x = 0; x < 84; x++) {
 121                for (y = 0; y < 6; y++) {
 122                        *buf = 0x00;
 123                        for (i = 0; i < 8; i++)
 124                                *buf |= (vmem16[(y * 8 + i) * 84 + x] ?
 125                                         1 : 0) << i;
 126                        buf++;
 127                }
 128        }
 129
 130        /* Write data */
 131        gpio_set_value(par->gpio.dc, 1);
 132        ret = par->fbtftops.write(par, par->txbuf.buf, 6 * 84);
 133        if (ret < 0)
 134                dev_err(par->info->device, "write failed and returned: %d\n",
 135                        ret);
 136
 137        return ret;
 138}
 139
 140static int set_gamma(struct fbtft_par *par, unsigned long *curves)
 141{
 142        /* apply mask */
 143        curves[0] &= 0x7F;
 144
 145        write_reg(par, 0x23); /* turn on extended instruction set */
 146        write_reg(par, 0x80 | curves[0]);
 147        write_reg(par, 0x22); /* turn off extended instruction set */
 148
 149        return 0;
 150}
 151
 152static struct fbtft_display display = {
 153        .regwidth = 8,
 154        .width = WIDTH,
 155        .height = HEIGHT,
 156        .txbuflen = TXBUFLEN,
 157        .gamma_num = 1,
 158        .gamma_len = 1,
 159        .gamma = DEFAULT_GAMMA,
 160        .fbtftops = {
 161                .init_display = init_display,
 162                .set_addr_win = set_addr_win,
 163                .write_vmem = write_vmem,
 164                .set_gamma = set_gamma,
 165        },
 166        .backlight = 1,
 167};
 168
 169FBTFT_REGISTER_DRIVER(DRVNAME, "philips,pdc8544", &display);
 170
 171MODULE_ALIAS("spi:" DRVNAME);
 172MODULE_ALIAS("spi:pdc8544");
 173
 174MODULE_DESCRIPTION("FB driver for the PCD8544 LCD Controller");
 175MODULE_AUTHOR("Noralf Tronnes");
 176MODULE_LICENSE("GPL");
 177