0001
0002
0003
0004
0005
0006 #include <linux/types.h>
0007 #include <linux/errno.h>
0008 #include <linux/kernel.h>
0009 #include <linux/miscdevice.h>
0010 #include <linux/fcntl.h>
0011 #include <linux/module.h>
0012 #include <linux/delay.h>
0013 #include <linux/fs.h>
0014 #include <linux/of.h>
0015
0016 #include <linux/uaccess.h>
0017 #include <asm/sections.h>
0018 #include <asm/io.h>
0019
0020 #include "ans-lcd.h"
0021
0022 #define ANSLCD_ADDR 0xf301c000
0023 #define ANSLCD_CTRL_IX 0x00
0024 #define ANSLCD_DATA_IX 0x10
0025
0026 static unsigned long anslcd_short_delay = 80;
0027 static unsigned long anslcd_long_delay = 3280;
0028 static volatile unsigned char __iomem *anslcd_ptr;
0029 static DEFINE_MUTEX(anslcd_mutex);
0030
0031 #undef DEBUG
0032
0033 static void
0034 anslcd_write_byte_ctrl ( unsigned char c )
0035 {
0036 #ifdef DEBUG
0037 printk(KERN_DEBUG "LCD: CTRL byte: %02x\n",c);
0038 #endif
0039 out_8(anslcd_ptr + ANSLCD_CTRL_IX, c);
0040 switch(c) {
0041 case 1:
0042 case 2:
0043 case 3:
0044 udelay(anslcd_long_delay); break;
0045 default: udelay(anslcd_short_delay);
0046 }
0047 }
0048
0049 static void
0050 anslcd_write_byte_data ( unsigned char c )
0051 {
0052 out_8(anslcd_ptr + ANSLCD_DATA_IX, c);
0053 udelay(anslcd_short_delay);
0054 }
0055
0056 static ssize_t
0057 anslcd_write( struct file * file, const char __user * buf,
0058 size_t count, loff_t *ppos )
0059 {
0060 const char __user *p = buf;
0061 int i;
0062
0063 #ifdef DEBUG
0064 printk(KERN_DEBUG "LCD: write\n");
0065 #endif
0066
0067 if (!access_ok(buf, count))
0068 return -EFAULT;
0069
0070 mutex_lock(&anslcd_mutex);
0071 for ( i = *ppos; count > 0; ++i, ++p, --count )
0072 {
0073 char c;
0074 __get_user(c, p);
0075 anslcd_write_byte_data( c );
0076 }
0077 mutex_unlock(&anslcd_mutex);
0078 *ppos = i;
0079 return p - buf;
0080 }
0081
0082 static long
0083 anslcd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
0084 {
0085 char ch, __user *temp;
0086 long ret = 0;
0087
0088 #ifdef DEBUG
0089 printk(KERN_DEBUG "LCD: ioctl(%d,%d)\n",cmd,arg);
0090 #endif
0091
0092 mutex_lock(&anslcd_mutex);
0093
0094 switch ( cmd )
0095 {
0096 case ANSLCD_CLEAR:
0097 anslcd_write_byte_ctrl ( 0x38 );
0098 anslcd_write_byte_ctrl ( 0x0f );
0099 anslcd_write_byte_ctrl ( 0x06 );
0100 anslcd_write_byte_ctrl ( 0x01 );
0101 anslcd_write_byte_ctrl ( 0x02 );
0102 break;
0103 case ANSLCD_SENDCTRL:
0104 temp = (char __user *) arg;
0105 __get_user(ch, temp);
0106 for (; ch; temp++) {
0107 anslcd_write_byte_ctrl ( ch );
0108 __get_user(ch, temp);
0109 }
0110 break;
0111 case ANSLCD_SETSHORTDELAY:
0112 if (!capable(CAP_SYS_ADMIN))
0113 ret =-EACCES;
0114 else
0115 anslcd_short_delay=arg;
0116 break;
0117 case ANSLCD_SETLONGDELAY:
0118 if (!capable(CAP_SYS_ADMIN))
0119 ret = -EACCES;
0120 else
0121 anslcd_long_delay=arg;
0122 break;
0123 default:
0124 ret = -EINVAL;
0125 }
0126
0127 mutex_unlock(&anslcd_mutex);
0128 return ret;
0129 }
0130
0131 static int
0132 anslcd_open( struct inode * inode, struct file * file )
0133 {
0134 return 0;
0135 }
0136
0137 const struct file_operations anslcd_fops = {
0138 .write = anslcd_write,
0139 .unlocked_ioctl = anslcd_ioctl,
0140 .open = anslcd_open,
0141 .llseek = default_llseek,
0142 };
0143
0144 static struct miscdevice anslcd_dev = {
0145 LCD_MINOR,
0146 "anslcd",
0147 &anslcd_fops
0148 };
0149
0150 static const char anslcd_logo[] __initconst =
0151 "********************"
0152 "* LINUX! *"
0153 "* Welcome to *"
0154 "********************";
0155
0156 static int __init
0157 anslcd_init(void)
0158 {
0159 int a;
0160 int retval;
0161 struct device_node* node;
0162
0163 node = of_find_node_by_name(NULL, "lcd");
0164 if (!node || !of_node_name_eq(node->parent, "gc")) {
0165 of_node_put(node);
0166 return -ENODEV;
0167 }
0168 of_node_put(node);
0169
0170 anslcd_ptr = ioremap(ANSLCD_ADDR, 0x20);
0171
0172 retval = misc_register(&anslcd_dev);
0173 if(retval < 0){
0174 printk(KERN_INFO "LCD: misc_register failed\n");
0175 iounmap(anslcd_ptr);
0176 return retval;
0177 }
0178
0179 #ifdef DEBUG
0180 printk(KERN_DEBUG "LCD: init\n");
0181 #endif
0182
0183 mutex_lock(&anslcd_mutex);
0184 anslcd_write_byte_ctrl ( 0x38 );
0185 anslcd_write_byte_ctrl ( 0x0c );
0186 anslcd_write_byte_ctrl ( 0x06 );
0187 anslcd_write_byte_ctrl ( 0x01 );
0188 anslcd_write_byte_ctrl ( 0x02 );
0189 for(a=0;a<80;a++) {
0190 anslcd_write_byte_data(anslcd_logo[a]);
0191 }
0192 mutex_unlock(&anslcd_mutex);
0193 return 0;
0194 }
0195
0196 static void __exit
0197 anslcd_exit(void)
0198 {
0199 misc_deregister(&anslcd_dev);
0200 iounmap(anslcd_ptr);
0201 }
0202
0203 module_init(anslcd_init);
0204 module_exit(anslcd_exit);
0205 MODULE_LICENSE("GPL v2");