root/drivers/auxdisplay/cfag12864b.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cfag12864b_getrate
  2. cfag12864b_set
  3. cfag12864b_setbit
  4. cfag12864b_e
  5. cfag12864b_cs1
  6. cfag12864b_cs2
  7. cfag12864b_di
  8. cfag12864b_setcontrollers
  9. cfag12864b_controller
  10. cfag12864b_displaystate
  11. cfag12864b_address
  12. cfag12864b_page
  13. cfag12864b_startline
  14. cfag12864b_writebyte
  15. cfag12864b_nop
  16. cfag12864b_on
  17. cfag12864b_off
  18. cfag12864b_clear
  19. cfag12864b_queue
  20. cfag12864b_enable
  21. cfag12864b_disable
  22. cfag12864b_isenabled
  23. cfag12864b_update
  24. cfag12864b_isinited
  25. cfag12864b_init
  26. cfag12864b_exit

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  *    Filename: cfag12864b.c
   4  *     Version: 0.1.0
   5  * Description: cfag12864b LCD driver
   6  *     Depends: ks0108
   7  *
   8  *      Author: Copyright (C) Miguel Ojeda Sandonis
   9  *        Date: 2006-10-31
  10  */
  11 
  12 #include <linux/init.h>
  13 #include <linux/module.h>
  14 #include <linux/kernel.h>
  15 #include <linux/fs.h>
  16 #include <linux/slab.h>
  17 #include <linux/cdev.h>
  18 #include <linux/delay.h>
  19 #include <linux/device.h>
  20 #include <linux/jiffies.h>
  21 #include <linux/mutex.h>
  22 #include <linux/uaccess.h>
  23 #include <linux/vmalloc.h>
  24 #include <linux/workqueue.h>
  25 #include <linux/ks0108.h>
  26 #include <linux/cfag12864b.h>
  27 
  28 
  29 #define CFAG12864B_NAME "cfag12864b"
  30 
  31 /*
  32  * Module Parameters
  33  */
  34 
  35 static unsigned int cfag12864b_rate = CONFIG_CFAG12864B_RATE;
  36 module_param(cfag12864b_rate, uint, S_IRUGO);
  37 MODULE_PARM_DESC(cfag12864b_rate,
  38         "Refresh rate (hertz)");
  39 
  40 unsigned int cfag12864b_getrate(void)
  41 {
  42         return cfag12864b_rate;
  43 }
  44 
  45 /*
  46  * cfag12864b Commands
  47  *
  48  *      E = Enable signal
  49  *              Every time E switch from low to high,
  50  *              cfag12864b/ks0108 reads the command/data.
  51  *
  52  *      CS1 = First ks0108controller.
  53  *              If high, the first ks0108 controller receives commands/data.
  54  *
  55  *      CS2 = Second ks0108 controller
  56  *              If high, the second ks0108 controller receives commands/data.
  57  *
  58  *      DI = Data/Instruction
  59  *              If low, cfag12864b will expect commands.
  60  *              If high, cfag12864b will expect data.
  61  *
  62  */
  63 
  64 #define bit(n) (((unsigned char)1)<<(n))
  65 
  66 #define CFAG12864B_BIT_E        (0)
  67 #define CFAG12864B_BIT_CS1      (2)
  68 #define CFAG12864B_BIT_CS2      (1)
  69 #define CFAG12864B_BIT_DI       (3)
  70 
  71 static unsigned char cfag12864b_state;
  72 
  73 static void cfag12864b_set(void)
  74 {
  75         ks0108_writecontrol(cfag12864b_state);
  76 }
  77 
  78 static void cfag12864b_setbit(unsigned char state, unsigned char n)
  79 {
  80         if (state)
  81                 cfag12864b_state |= bit(n);
  82         else
  83                 cfag12864b_state &= ~bit(n);
  84 }
  85 
  86 static void cfag12864b_e(unsigned char state)
  87 {
  88         cfag12864b_setbit(state, CFAG12864B_BIT_E);
  89         cfag12864b_set();
  90 }
  91 
  92 static void cfag12864b_cs1(unsigned char state)
  93 {
  94         cfag12864b_setbit(state, CFAG12864B_BIT_CS1);
  95 }
  96 
  97 static void cfag12864b_cs2(unsigned char state)
  98 {
  99         cfag12864b_setbit(state, CFAG12864B_BIT_CS2);
 100 }
 101 
 102 static void cfag12864b_di(unsigned char state)
 103 {
 104         cfag12864b_setbit(state, CFAG12864B_BIT_DI);
 105 }
 106 
 107 static void cfag12864b_setcontrollers(unsigned char first,
 108         unsigned char second)
 109 {
 110         if (first)
 111                 cfag12864b_cs1(0);
 112         else
 113                 cfag12864b_cs1(1);
 114 
 115         if (second)
 116                 cfag12864b_cs2(0);
 117         else
 118                 cfag12864b_cs2(1);
 119 }
 120 
 121 static void cfag12864b_controller(unsigned char which)
 122 {
 123         if (which == 0)
 124                 cfag12864b_setcontrollers(1, 0);
 125         else if (which == 1)
 126                 cfag12864b_setcontrollers(0, 1);
 127 }
 128 
 129 static void cfag12864b_displaystate(unsigned char state)
 130 {
 131         cfag12864b_di(0);
 132         cfag12864b_e(1);
 133         ks0108_displaystate(state);
 134         cfag12864b_e(0);
 135 }
 136 
 137 static void cfag12864b_address(unsigned char address)
 138 {
 139         cfag12864b_di(0);
 140         cfag12864b_e(1);
 141         ks0108_address(address);
 142         cfag12864b_e(0);
 143 }
 144 
 145 static void cfag12864b_page(unsigned char page)
 146 {
 147         cfag12864b_di(0);
 148         cfag12864b_e(1);
 149         ks0108_page(page);
 150         cfag12864b_e(0);
 151 }
 152 
 153 static void cfag12864b_startline(unsigned char startline)
 154 {
 155         cfag12864b_di(0);
 156         cfag12864b_e(1);
 157         ks0108_startline(startline);
 158         cfag12864b_e(0);
 159 }
 160 
 161 static void cfag12864b_writebyte(unsigned char byte)
 162 {
 163         cfag12864b_di(1);
 164         cfag12864b_e(1);
 165         ks0108_writedata(byte);
 166         cfag12864b_e(0);
 167 }
 168 
 169 static void cfag12864b_nop(void)
 170 {
 171         cfag12864b_startline(0);
 172 }
 173 
 174 /*
 175  * cfag12864b Internal Commands
 176  */
 177 
 178 static void cfag12864b_on(void)
 179 {
 180         cfag12864b_setcontrollers(1, 1);
 181         cfag12864b_displaystate(1);
 182 }
 183 
 184 static void cfag12864b_off(void)
 185 {
 186         cfag12864b_setcontrollers(1, 1);
 187         cfag12864b_displaystate(0);
 188 }
 189 
 190 static void cfag12864b_clear(void)
 191 {
 192         unsigned char i, j;
 193 
 194         cfag12864b_setcontrollers(1, 1);
 195         for (i = 0; i < CFAG12864B_PAGES; i++) {
 196                 cfag12864b_page(i);
 197                 cfag12864b_address(0);
 198                 for (j = 0; j < CFAG12864B_ADDRESSES; j++)
 199                         cfag12864b_writebyte(0);
 200         }
 201 }
 202 
 203 /*
 204  * Update work
 205  */
 206 
 207 unsigned char *cfag12864b_buffer;
 208 static unsigned char *cfag12864b_cache;
 209 static DEFINE_MUTEX(cfag12864b_mutex);
 210 static unsigned char cfag12864b_updating;
 211 static void cfag12864b_update(struct work_struct *delayed_work);
 212 static struct workqueue_struct *cfag12864b_workqueue;
 213 static DECLARE_DELAYED_WORK(cfag12864b_work, cfag12864b_update);
 214 
 215 static void cfag12864b_queue(void)
 216 {
 217         queue_delayed_work(cfag12864b_workqueue, &cfag12864b_work,
 218                 HZ / cfag12864b_rate);
 219 }
 220 
 221 unsigned char cfag12864b_enable(void)
 222 {
 223         unsigned char ret;
 224 
 225         mutex_lock(&cfag12864b_mutex);
 226 
 227         if (!cfag12864b_updating) {
 228                 cfag12864b_updating = 1;
 229                 cfag12864b_queue();
 230                 ret = 0;
 231         } else
 232                 ret = 1;
 233 
 234         mutex_unlock(&cfag12864b_mutex);
 235 
 236         return ret;
 237 }
 238 
 239 void cfag12864b_disable(void)
 240 {
 241         mutex_lock(&cfag12864b_mutex);
 242 
 243         if (cfag12864b_updating) {
 244                 cfag12864b_updating = 0;
 245                 cancel_delayed_work(&cfag12864b_work);
 246                 flush_workqueue(cfag12864b_workqueue);
 247         }
 248 
 249         mutex_unlock(&cfag12864b_mutex);
 250 }
 251 
 252 unsigned char cfag12864b_isenabled(void)
 253 {
 254         return cfag12864b_updating;
 255 }
 256 
 257 static void cfag12864b_update(struct work_struct *work)
 258 {
 259         unsigned char c;
 260         unsigned short i, j, k, b;
 261 
 262         if (memcmp(cfag12864b_cache, cfag12864b_buffer, CFAG12864B_SIZE)) {
 263                 for (i = 0; i < CFAG12864B_CONTROLLERS; i++) {
 264                         cfag12864b_controller(i);
 265                         cfag12864b_nop();
 266                         for (j = 0; j < CFAG12864B_PAGES; j++) {
 267                                 cfag12864b_page(j);
 268                                 cfag12864b_nop();
 269                                 cfag12864b_address(0);
 270                                 cfag12864b_nop();
 271                                 for (k = 0; k < CFAG12864B_ADDRESSES; k++) {
 272                                         for (c = 0, b = 0; b < 8; b++)
 273                                                 if (cfag12864b_buffer
 274                                                         [i * CFAG12864B_ADDRESSES / 8
 275                                                         + k / 8 + (j * 8 + b) *
 276                                                         CFAG12864B_WIDTH / 8]
 277                                                         & bit(k % 8))
 278                                                         c |= bit(b);
 279                                         cfag12864b_writebyte(c);
 280                                 }
 281                         }
 282                 }
 283 
 284                 memcpy(cfag12864b_cache, cfag12864b_buffer, CFAG12864B_SIZE);
 285         }
 286 
 287         if (cfag12864b_updating)
 288                 cfag12864b_queue();
 289 }
 290 
 291 /*
 292  * cfag12864b Exported Symbols
 293  */
 294 
 295 EXPORT_SYMBOL_GPL(cfag12864b_buffer);
 296 EXPORT_SYMBOL_GPL(cfag12864b_getrate);
 297 EXPORT_SYMBOL_GPL(cfag12864b_enable);
 298 EXPORT_SYMBOL_GPL(cfag12864b_disable);
 299 EXPORT_SYMBOL_GPL(cfag12864b_isenabled);
 300 
 301 /*
 302  * Is the module inited?
 303  */
 304 
 305 static unsigned char cfag12864b_inited;
 306 unsigned char cfag12864b_isinited(void)
 307 {
 308         return cfag12864b_inited;
 309 }
 310 EXPORT_SYMBOL_GPL(cfag12864b_isinited);
 311 
 312 /*
 313  * Module Init & Exit
 314  */
 315 
 316 static int __init cfag12864b_init(void)
 317 {
 318         int ret = -EINVAL;
 319 
 320         /* ks0108_init() must be called first */
 321         if (!ks0108_isinited()) {
 322                 printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
 323                         "ks0108 is not initialized\n");
 324                 goto none;
 325         }
 326         BUILD_BUG_ON(PAGE_SIZE < CFAG12864B_SIZE);
 327 
 328         cfag12864b_buffer = (unsigned char *) get_zeroed_page(GFP_KERNEL);
 329         if (cfag12864b_buffer == NULL) {
 330                 printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
 331                         "can't get a free page\n");
 332                 ret = -ENOMEM;
 333                 goto none;
 334         }
 335 
 336         cfag12864b_cache = kmalloc(CFAG12864B_SIZE,
 337                                    GFP_KERNEL);
 338         if (cfag12864b_cache == NULL) {
 339                 printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
 340                         "can't alloc cache buffer (%i bytes)\n",
 341                         CFAG12864B_SIZE);
 342                 ret = -ENOMEM;
 343                 goto bufferalloced;
 344         }
 345 
 346         cfag12864b_workqueue = create_singlethread_workqueue(CFAG12864B_NAME);
 347         if (cfag12864b_workqueue == NULL)
 348                 goto cachealloced;
 349 
 350         cfag12864b_clear();
 351         cfag12864b_on();
 352 
 353         cfag12864b_inited = 1;
 354         return 0;
 355 
 356 cachealloced:
 357         kfree(cfag12864b_cache);
 358 
 359 bufferalloced:
 360         free_page((unsigned long) cfag12864b_buffer);
 361 
 362 none:
 363         return ret;
 364 }
 365 
 366 static void __exit cfag12864b_exit(void)
 367 {
 368         cfag12864b_disable();
 369         cfag12864b_off();
 370         destroy_workqueue(cfag12864b_workqueue);
 371         kfree(cfag12864b_cache);
 372         free_page((unsigned long) cfag12864b_buffer);
 373 }
 374 
 375 module_init(cfag12864b_init);
 376 module_exit(cfag12864b_exit);
 377 
 378 MODULE_LICENSE("GPL v2");
 379 MODULE_AUTHOR("Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>");
 380 MODULE_DESCRIPTION("cfag12864b LCD driver");

/* [<][>][^][v][top][bottom][index][help] */