解决mini2440 LCD(型号:P43)驱动的背光失效问题

目录

概述

1 LCD(P43)背光问题

1 移植LCD驱动程序

1.1 编写驱动代码

1.2 编写LCD的配置参数

1.3 配置LCD驱动至内核

2 移植触摸功能程序

2.1 移植ADC驱动程序

2.1.1 编写ADC驱动代码

2.1.2 编写配置文件

2.2 移植P43的一线触摸程序

2.2.1 编写代码

2.2.2 编写配置链接文件

2.3 移植S3C2410触摸功能程序

2.3.1 编写驱动代码

2.3.2 编写配置链接文件

2.4 在内核中查看触摸功能的配置

3 功能测试


概述

本文介绍了 解决mini2440 LCD(型号:P43)驱动的背光失效问题的方法,并通过实操方式,详细记录整个LCD driver的移植过程,还移植触摸功能的驱动,并且烧写到mini2440开发板上,且能正常的工作。

1 LCD(P43)背光问题

根据官方网址给的信息,得知P43型号的LCD采用的是一线触摸的方式驱动触摸功能,而背光控制也被集成在这个功能里。采用文档《Mini2440 Linux移植开发实战指南.pdf》中的方法是不行的,要解决背光问题,必须移植整个LCD的触摸驱动功能,顺便也移植了LCD的驱动,彻底解决LCD不能正常工作的问题。

本程序参考mini2440光盘中的内核源码: linux-2.6.32.2-mini2440-20150709.tgz

笔者选取的内核源码为: linux-2.6.32.24.tar.bz2,下载地址:

wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.32.24.tar.gz

官方LCD P43资料介绍网址:

https://wiki.friendlyelec.com/wiki/index.php/LCD-P43/zh

2 移植LCD驱动程序

2.1 编写驱动代码

Linux-2.6.32.24 内核已经支持 S3C2440 的 LCD 控制器驱动,打开 linux-2.6.32.24/arch/arm/mach-s3c2440/mach-mini2440.c,先删除之前的 LCD 设备平台代码,添加新的代码,笔者使用的LCD硬件为P43,所以驱动中只支持该屏的驱动。具体代码如下:

代码86 ~ 100行: 定义和LCD相关的参数

源代码内容:

#define LCD_WIDTH          480
#define LCD_HEIGHT         272
#define LCD_PIXCLOCK       100000
​
#define LCD_RIGHT_MARGIN   0x27
#define LCD_LEFT_MARGIN    0x03
#define LCD_HSYNC_LEN      0x01
​
#define LCD_UPPER_MARGIN   0x08
#define LCD_LOWER_MARGIN   0x09
#define LCD_VSYNC_LEN      0x01
​
#define LCD_CON5 (S3C2410_LCDCON5_FRM565 |S3C2410_LCDCON5_INVVLINE |\S3C2410_LCDCON5_INVVFRAME |S3C2410_LCDCON5_PWREN |\S3C2410_LCDCON5_HWSWP | S3C2410_LCDCON5_INVVCLK)

代码104 ~ 129行: 将定义的参数填充到s3c2410fb_display 的数据结构中

源代码内容:

static struct s3c2410fb_display mini2440_lcd_cfg __initdata = {
​
#if !defined (LCD_CON5).lcdcon5    = S3C2410_LCDCON5_FRM565    |S3C2410_LCDCON5_INVVLINE  |S3C2410_LCDCON5_INVVFRAME |S3C2410_LCDCON5_PWREN     |S3C2410_LCDCON5_HWSWP,
#else.lcdcon5    = LCD_CON5,
#endif
​.type        = S3C2410_LCDCON1_TFT,
​.width       = 0,.height      = 0,
​.pixclock    = LCD_PIXCLOCK,.xres        = LCD_WIDTH,.yres        = LCD_HEIGHT,.bpp         = 16,
​.left_margin   = LCD_LEFT_MARGIN + 1,.right_margin  = LCD_RIGHT_MARGIN + 1,.hsync_len     = LCD_HSYNC_LEN + 1,.upper_margin  = LCD_UPPER_MARGIN + 1,.lower_margin  = LCD_LOWER_MARGIN + 1,.vsync_len     = LCD_VSYNC_LEN + 1,
};
​
static struct s3c2410fb_mach_info mini2440_fb_info __initdata = {.displays        = &mini2440_lcd_cfg,.num_displays    = 1,.default_display = 0,
​.gpccon      =  0xaa955699,.gpccon_mask =  0xffc003cc,.gpcup       =  0x0000ffff,.gpcup_mask  =  0xffffffff,
​.gpdcon      =  0xaa95aaa1,.gpdcon_mask =  0xffc0fff0,.gpdup       =  0x0000faff,.gpdup_mask  =  0xffffffff,.lpcsel      =  0xf82,
};

代码261行:注册LCD的驱动到mini2440板卡上

源代码内容:

static struct platform_device *mini2440_devices[] __initdata = {&s3c_device_usb,&s3c_device_lcd,   // LCD driver&s3c_device_wdt,&s3c_device_i2c0,&s3c_device_iis,&s3c_device_nand,&mini2440_device_eth,&s3c_device_rtc,&s3c24xx_uda134x,&s3c_device_sdi,&s3c_device_usbgadget,
};

2.2 编写LCD的配置参数

linux-2.6.32.24/drivers/video/Kconfig文件中,编写如下内容:

源代码内容:

config FB_S3C2410_P480272tristate "4.3 inch 480X272 LCD(P43)"depends on MACH_MINI2440 && FB_S3C2410help4.3 inch 480x272 LCD(P43)
 

2.3 配置LCD驱动至内核

使用make menuconfig命令,打开配置页面:

Device Drivers --->     
     Graphics support --->

选中这两项配置:

在进入代下一级目录中:

Device Drivers --->
      Graphics support --->
            <*> Support for frame buffer devices --->

选中如下两项配置

配置完成后,保存配置文件

3 移植触摸功能程序

3.1 移植ADC驱动程序

根据P43的屏资料可得,其使用一线触摸功能,实现方式和ADC相关,所以在移植其他驱动前,先移植ADC驱动

3.1.1 编写ADC驱动代码

在linux-2.6.32.24/drivers/char/mini2440_adc.c文件中编写如下代码:

#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <mach/regs-clock.h>
#include <plat/regs-timer.h>#include <plat/regs-adc.h>
#include <mach/regs-gpio.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
​
#include "s3c24xx-adc.h"
​
#undef DEBUG
//#define DEBUG
#ifdef DEBUG
#define DPRINTK(x...) {printk(__FUNCTION__"(%d): ",__LINE__);printk(##x);}
#else
#define DPRINTK(x...) (void)(0)
#endif
​
#define DEVICE_NAME "adc"
​
static void __iomem *base_addr;
​
typedef struct {wait_queue_head_t wait;int channel;int prescale;
}ADC_DEV;
​
DECLARE_MUTEX(ADC_LOCK);
static int OwnADC = 0;
​
static ADC_DEV adcdev;
static volatile int ev_adc = 0;
static int adc_data;
​
static struct clk   *adc_clock;
​
#define ADCCON      (*(volatile unsigned long *)(base_addr + S3C2410_ADCCON))   //ADC control
#define ADCTSC      (*(volatile unsigned long *)(base_addr + S3C2410_ADCTSC))   //ADC touch screen control
#define ADCDLY      (*(volatile unsigned long *)(base_addr + S3C2410_ADCDLY))   //ADC start or Interval Delay
#define ADCDAT0     (*(volatile unsigned long *)(base_addr + S3C2410_ADCDAT0))  //ADC conversion data 0
#define ADCDAT1     (*(volatile unsigned long *)(base_addr + S3C2410_ADCDAT1))  //ADC conversion data 1
#define ADCUPDN     (*(volatile unsigned long *)(base_addr + 0x14)) //Stylus Up/Down interrupt status
​
#define PRESCALE_DIS        (0 << 14)
#define PRESCALE_EN         (1 << 14)
#define PRSCVL(x)           ((x) << 6)
#define ADC_INPUT(x)        ((x) << 3)
#define ADC_START           (1 << 0)
#define ADC_ENDCVT          (1 << 15)
​
#define START_ADC_AIN(ch, prescale) \do{ \ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; \ADCCON |= ADC_START; \}while(0)
​
​
static irqreturn_t adcdone_int_handler(int irq, void *dev_id)
{if (OwnADC) {adc_data = ADCDAT0 & 0x3ff;
​ev_adc = 1;wake_up_interruptible(&adcdev.wait);}
​return IRQ_HANDLED;
}
​
static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{char str[20];int value;size_t len;if (down_trylock(&ADC_LOCK) == 0) {OwnADC = 1;START_ADC_AIN(adcdev.channel, adcdev.prescale);wait_event_interruptible(adcdev.wait, ev_adc);
​ev_adc = 0;
​DPRINTK("AIN[%d] = 0x%04x, %d\n", adcdev.channel, adc_data, ADCCON & 0x80 ? 1:0);
​value = adc_data;
​OwnADC = 0;up(&ADC_LOCK);} else {value = -1;}
​len = sprintf(str, "%d\n", value);if (count >= len) {int r = copy_to_user(buffer, str, len);return r ? r : len;} else {return -EINVAL;}
}
​
static int s3c2410_adc_open(struct inode *inode, struct file *filp)
{init_waitqueue_head(&(adcdev.wait));
​adcdev.channel=0;adcdev.prescale=0xff;
​DPRINTK( "adc opened\n");return 0;
}
​
static int s3c2410_adc_release(struct inode *inode, struct file *filp)
{DPRINTK( "adc closed\n");return 0;
}
​
​
static struct file_operations dev_fops = {owner:  THIS_MODULE,open:   s3c2410_adc_open,read:   s3c2410_adc_read,   release:    s3c2410_adc_release,
};
​
static struct miscdevice misc = {.minor = MISC_DYNAMIC_MINOR,.name = DEVICE_NAME,.fops = &dev_fops,
};
​
static int __init dev_init(void)
{int ret;
​base_addr=ioremap(S3C2410_PA_ADC,0x20);if (base_addr == NULL) {printk(KERN_ERR "Failed to remap register block\n");return -ENOMEM;}
​adc_clock = clk_get(NULL, "adc");if (!adc_clock) {printk(KERN_ERR "failed to get adc clock source\n");return -ENOENT;}clk_enable(adc_clock);/* normal ADC */ADCTSC = 0;
​ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DEVICE_NAME, &adcdev);if (ret) {iounmap(base_addr);return ret;}
​ret = misc_register(&misc);
​printk (DEVICE_NAME"\tinitialized\n");return ret;
}
​
static void __exit dev_exit(void)
{free_irq(IRQ_ADC, &adcdev);iounmap(base_addr);
​if (adc_clock) {clk_disable(adc_clock);clk_put(adc_clock);adc_clock = NULL;}
​misc_deregister(&misc);
}
​
EXPORT_SYMBOL(ADC_LOCK);
module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("redistributed by tangmingfei2013@126.com");
MODULE_DESCRIPTION("Mini2440 adc Driver");

3.1.2 编写配置文件

linux-2.6.32.24/drivers/char/Kconfig中添加如下代码:

源代码内容:

config MINI2440_ADCbool "ADC driver for mftang's Mini2440 development boards"depends on MACH_MINI2440default y if MACH_MINI2440helpthis is ADC driver for mftang's Mini2440 development boardsNotes: the touch-screen-driver required this option

linux-2.6.32.24/drivers/char/Makefile中添加如下链接代码

3.2 移植P43的一线触摸程序

3.2.1 编写代码

linux-2.6.32.24/drivers/input/touchscreen/mini2440_1wire_host.c文件中编写如下代码:

  /*  * mini2440_1wire_host.c* 2010-10-14: Russell Guo <russell.grey@gmail.com>*      - Initial version*      -- request touch-screen data*      -- request LCD type, Firmware version*      -  Backlight control* the CRC-8 functions is based on web page from http://lfh1986.blogspot.com*/#include <linux/errno.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/input.h>#include <linux/init.h>#include <linux/serio.h>#include <linux/delay.h>#include <linux/clk.h>#include <linux/miscdevice.h>#include <linux/timer.h>#include <linux/param.h>#include <linux/poll.h>#include <linux/proc_fs.h>
​#include <asm/io.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <plat/regs-timer.h>#include <plat/gpio-cfg.h>#include <mach/regs-clock.h>#include <mach/regs-gpio.h>
​#include <mach/gpio.h>
​#include <linux/cdev.h>
​#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/irq.h>#include <linux/err.h>#include <linux/io.h>
​#include <asm/system.h>#include <asm/leds.h>#include <asm/mach-types.h>
​#include <asm/irq.h>#include <mach/map.h>#include <mach/regs-irq.h>#include <asm/mach/time.h>
​#include <plat/clock.h>#include <plat/cpu.h>
​#undef DEBUG#define DEBUG#ifdef DEBUG#define DPRINTK(x...) {printk("%s(%d): ",__FUNCTION__ ,__LINE__);printk(x);}#else#define DPRINTK(x...) (void)(0)#endif
​#define TOUCH_DEVICE_NAME           "touchscreen-1wire"#define BACKLIGHT_DEVICE_NAME       "backlight-1wire"#define SAMPLE_BPS                  9600
​#define REQ_TS                      0x40U#define REQ_INFO                    0x60U
​// Touch Screen driver interface//static DECLARE_WAIT_QUEUE_HEAD(ts_waitq);static int ts_ready;static unsigned ts_status;
​
​static inline void notify_ts_data(unsigned x, unsigned y, unsigned down){if (!down && !(ts_status &(1U << 31))) {// up repeat, give it upreturn;}
​ts_status = ((x << 16) | (y)) | (down << 31);ts_ready = 1;
​wake_up_interruptible(&ts_waitq);}
​static ssize_t ts_read(struct file *filp, char *buffer, size_t count, loff_t *ppos){unsigned long err;
​if (!ts_ready) {if (filp->f_flags & O_NONBLOCK)return -EAGAIN;elsewait_event_interruptible(ts_waitq, ts_ready);}
​ts_ready = 0;
​if (count < sizeof ts_status) {return -EINVAL;} else {count = sizeof ts_status;}
​err = copy_to_user((void *)buffer, (const void *)(&ts_status), sizeof ts_status);return err ? -EFAULT : sizeof ts_status;}
​static unsigned int ts_poll( struct file *file, struct poll_table_struct *wait){unsigned int mask = 0;
​poll_wait(file, &ts_waitq, wait);
​if (ts_ready){mask |= POLLIN | POLLRDNORM;}
​return mask;}
​static struct file_operations ts_fops = {owner:  THIS_MODULE,read:   ts_read,    poll:   ts_poll,};
​static struct miscdevice ts_misc = {.minor = 181,.name  = TOUCH_DEVICE_NAME,.fops  = &ts_fops,};
​static DECLARE_WAIT_QUEUE_HEAD(bl_waitq);static int bl_ready;static unsigned char backlight_req = 0;static unsigned char backlight_init_success;
​static inline void notify_bl_data(unsigned char a, unsigned char b, unsigned char c){bl_ready = 1;backlight_init_success = 1;wake_up_interruptible(&bl_waitq);}
​static ssize_t bl_write(struct file *file, const char *buffer, size_t count, loff_t * ppos){int ret;char buf[4] = {0, 0, 0, 0};unsigned v;unsigned len;
​if (count == 0) {return -EINVAL;}
​if (count > sizeof buf - 1) {len = sizeof buf - 1;} else {len = count;}
​ret = copy_from_user(buf, buffer, len);if (ret) {return -EFAULT;}
​if (sscanf(buf, "%u", &v) != 1) {return -EINVAL;}
​if (v > 127) {v = 127;}
​bl_ready = 0;backlight_req = v + 0x80U;
​ret = wait_event_interruptible_timeout(bl_waitq, bl_ready, HZ / 10);if (ret < 0) {return ret;}if (ret == 0) {return -ETIMEDOUT;}
​return count;}
​static struct file_operations bl_fops = {owner:  THIS_MODULE,write:  bl_write,};
​static struct miscdevice bl_misc = {.minor = MISC_DYNAMIC_MINOR,.name  = BACKLIGHT_DEVICE_NAME,.fops  = &bl_fops,};
​// for query base info//static unsigned lcd_type, firmware_ver;
​static inline void notify_info_data(unsigned char _lcd_type, unsigned char ver_year, unsigned char week){if (_lcd_type != 0xFF) {lcd_type = _lcd_type;firmware_ver = ver_year * 100 + week;}}
​// Pin access//static inline void set_pin_up(void){s3c2410_gpio_pullup(S3C2410_GPB(1), 0);}
​static inline void set_pin_as_input(void){s3c2410_gpio_cfgpin(S3C2410_GPB(1), S3C2410_GPIO_INPUT);}
​static inline void set_pin_as_output(void){s3c2410_gpio_cfgpin(S3C2410_GPB(1), S3C2410_GPIO_OUTPUT);}
​static inline void set_pin_value(int v){s3c2410_gpio_setpin(S3C2410_GPB(1), !!v);}
​static inline int get_pin_value(void){int v = !!s3c2410_gpio_getpin(S3C2410_GPB(1));return v;}
​// CRC//static const unsigned char crc8_tab[] = {0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3,};
​#define crc8_init(crc) ((crc) = 0XACU)#define crc8(crc, v) ( (crc) = crc8_tab[(crc) ^(v)])
​// once a session completestatic unsigned total_received, total_error;static unsigned last_req, last_res;static void one_wire_session_complete(unsigned char req, unsigned int res){unsigned char crc;const unsigned char *p = (const unsigned char*)&res;total_received ++;
​last_res = res;
​crc8_init(crc);crc8(crc, p[3]);crc8(crc, p[2]);crc8(crc, p[1]);
​if (crc != p[0]) {// CRC dismatchif (total_received > 100) {total_error++;}return;}
​switch(req) {case REQ_TS:{unsigned short x,y;unsigned pressed;x =  ((p[3] >>   4U) << 8U) + p[2];y =  ((p[3] &  0xFU) << 8U) + p[1];pressed = (x != 0xFFFU) && (y != 0xFFFU); notify_ts_data(x, y, pressed);}break;
​case REQ_INFO:notify_info_data(p[3], p[2], p[1]);break;
​default:notify_bl_data(p[3], p[2], p[1]);break;}}
​// one-wire protocol corestatic unsigned long TCNT_FOR_SAMPLE_BIT;static int init_timer_for_1wire(void){unsigned long tcfg1;unsigned long tcfg0;
​unsigned prescale1_value;
​unsigned long pclk;struct clk *clk;
​// get pclkclk = clk_get(NULL, "timers");
​if (IS_ERR(clk)) {DPRINTK("ERROR to get PCLK\n");return -EIO;}
​pclk = clk_get_rate(clk);
​// get prescalertcfg0 = __raw_readl(S3C2410_TCFG0);// we use system prescaler value because timer 4 uses same oneprescale1_value = (tcfg0 >> 8) & 0xFF;
​// calc the TCNT_FOR_SAMPLE_BIT, that is one of the goalTCNT_FOR_SAMPLE_BIT = pclk / 2 / (prescale1_value + 1) / SAMPLE_BPS - 1;
​// select timer 3, the 2rd goaltcfg1 = __raw_readl(S3C2410_TCFG1);tcfg1 &= ~S3C2410_TCFG1_MUX3_MASK;writel(tcfg1, S3C2410_TCFG1);
​return 0;}
​static inline void stop_timer_for_1wire(void){unsigned long tcon;
​tcon = __raw_readl(S3C2410_TCON);tcon &= ~S3C2410_TCON_T3START;
​writel(tcon, S3C2410_TCON);}
​enum {IDLE,START,REQUEST,WAITING,RESPONSE,STOPING,} one_wire_status = IDLE;
​static volatile unsigned int io_bit_count;static volatile unsigned int io_data;static volatile unsigned char one_wire_request;static irqreturn_t timer_for_1wire_interrupt(int irq, void *dev_id){io_bit_count--;switch(one_wire_status) {case START:if (io_bit_count == 0) {io_bit_count = 16;one_wire_status = REQUEST;}break;
​case REQUEST:// Send a bitset_pin_value(io_data & (1U << 31));io_data <<= 1;if (io_bit_count == 0) {io_bit_count = 2;one_wire_status = WAITING;}break;case WAITING:if (io_bit_count == 0) {io_bit_count = 32;one_wire_status = RESPONSE;}if (io_bit_count == 1) {set_pin_as_input();set_pin_value(1);}break;case RESPONSE:// Get a bitio_data = (io_data << 1) | get_pin_value();if (io_bit_count == 0) {io_bit_count = 2;one_wire_status = STOPING;set_pin_value(1);set_pin_as_output();one_wire_session_complete(one_wire_request, io_data);}break;
​case STOPING:if (io_bit_count == 0) {one_wire_status = IDLE;stop_timer_for_1wire();}break;default:stop_timer_for_1wire();}return IRQ_HANDLED;}
​static struct irqaction timer_for_1wire_irq = {.name    = "1-wire Timer Tick",.flags   = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,.handler = timer_for_1wire_interrupt,.dev_id  = &timer_for_1wire_irq,};
​
​static void start_one_wire_session(unsigned char req){unsigned long tcon;unsigned long flags;if (one_wire_status != IDLE) {printk("one_wire_status: %d\n", one_wire_status);return;}
​one_wire_status = START;
​set_pin_value(1);set_pin_as_output();// IDLE to START{unsigned char crc;crc8_init(crc);crc8(crc, req);io_data = (req << 8) + crc;io_data <<= 16;}last_req = (io_data >> 16);one_wire_request = req;io_bit_count = 1;set_pin_as_output();
​writel(TCNT_FOR_SAMPLE_BIT, S3C2410_TCNTB(3));// init tranfer and start timertcon = __raw_readl(S3C2410_TCON);tcon &= ~(0xF << 16);tcon |= S3C2410_TCON_T3MANUALUPD;writel(tcon, S3C2410_TCON);
​
​tcon |= S3C2410_TCON_T3START;tcon |= S3C2410_TCON_T3RELOAD;tcon &= ~S3C2410_TCON_T3MANUALUPD;
​local_irq_save(flags);writel(tcon, S3C2410_TCON);set_pin_value(0);local_irq_restore(flags);}
​// poll the device// following is Linux timer not HW timerstatic int exitting;static struct timer_list one_wire_timer;
​void one_wire_timer_proc(unsigned long v){unsigned char req;if (exitting) {return;}one_wire_timer.expires = jiffies + HZ / 50;add_timer(&one_wire_timer);if (lcd_type == 0) {req = REQ_INFO;} else if (!backlight_init_success) {req = 127;} else if (backlight_req) {req = backlight_req;backlight_req = 0;} else {req = REQ_TS;}start_one_wire_session(req);
​}
​static struct timer_list one_wire_timer = {.function = one_wire_timer_proc,};
​static int read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *data){int len;len = sprintf(buf, "%u %u %u %u %04X %08X\n", lcd_type, firmware_ver, total_received, total_error, last_req, last_res);*eof = 1;
​return len;}static int __init dev_init(void){int ret;
​ret = misc_register(&ts_misc) | misc_register(&bl_misc) ;set_pin_up();set_pin_value(1);set_pin_as_output();
​if (ret == 0) {setup_irq(IRQ_TIMER3, &timer_for_1wire_irq);ret = init_timer_for_1wire();init_timer(&one_wire_timer);one_wire_timer_proc(0);create_proc_read_entry("driver/one-wire-info", 0, NULL, read_proc, NULL);}
​if (ret == 0) {printk (TOUCH_DEVICE_NAME"\tinitialized\n");printk (BACKLIGHT_DEVICE_NAME"\tinitialized\n");}
​return ret;}
​
​static void __exit dev_exit(void){exitting = 1;
​remove_proc_entry("driver/one-wire-info", NULL);del_timer_sync(&one_wire_timer);free_irq(IRQ_TIMER3, &timer_for_1wire_irq);misc_deregister(&ts_misc);misc_deregister(&bl_misc);}
​module_init(dev_init);module_exit(dev_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("redistributed by tangmingfei2013@126.com");MODULE_DESCRIPTION("Mini2440 one-wire host and Touch Screen Driver");
 

3.2.2 编写配置链接文件

linux-2.6.32.24/drivers/input/touchscreen/Kconfig文件中编写如下代码:

代码内容:

config TOUCHSCREEN_1WIREtristate "Mini2440 1-Wire host and Touch Screen Driver by mftang "depends on MACH_MINI2440helpSay Y here to enable the 1-Wire host and Touch Screen driver forFriendlyARM Mini2440 development board.
​If unsure, say N.
​To compile this driver as a module, choose M here: themodule will be called mini2440_1wire_host.

在linux-2.6.32.24/drivers/input/touchscreen/Makefile中编写链接代码:

3.3 移植S3C2410触摸功能程序

3.3.1 编写驱动代码

linux-2.6.32.24/drivers/input/touchscreen/s3c2410_ts.c文件中编写如下代码:

#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <asm/io.h>
#include <asm/irq.h>
​
#include <plat/regs-adc.h>
#include <mach/regs-gpio.h>
​
/* For ts.dev.id.version */
#define S3C2410TSVERSION      0x0101
​
#define WAIT4INT(x)           (((x)<<8) | \S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \S3C2410_ADCTSC_XY_PST(3))
​
#define AUTOPST               (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0))
​
static char *s3c2410ts_name = "s3c2410 TouchScreen";
​
static struct input_dev *dev;
static long xp;
static long yp;
static int count;
​
extern struct semaphore ADC_LOCK;
static int OwnADC = 0;
​
static void __iomem *base_addr;
​
static inline void s3c2410_ts_connect(void)
{s3c2410_gpio_cfgpin(S3C2410_GPG(12), S3C2410_GPG12_XMON);s3c2410_gpio_cfgpin(S3C2410_GPG(13), S3C2410_GPG13_nXPON);s3c2410_gpio_cfgpin(S3C2410_GPG(14), S3C2410_GPG14_YMON);s3c2410_gpio_cfgpin(S3C2410_GPG(15), S3C2410_GPG15_nYPON);
}
​
static void touch_timer_fire(unsigned long data)
{unsigned long data0;unsigned long data1;int updown;
​data0 = ioread32(base_addr+S3C2410_ADCDAT0);data1 = ioread32(base_addr+S3C2410_ADCDAT1);
​updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
​if (updown) {if (count != 0) {long tmp;tmp = xp;xp = yp;yp = tmp;xp >>= 2;yp >>= 2;
​input_report_abs(dev, ABS_X, xp);input_report_abs(dev, ABS_Y, yp);
​input_report_key(dev, BTN_TOUCH, 1);input_report_abs(dev, ABS_PRESSURE, 1);input_sync(dev);}
​xp = 0;yp = 0;count = 0;
​iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);} else {count = 0;
​input_report_key(dev, BTN_TOUCH, 0);input_report_abs(dev, ABS_PRESSURE, 0);input_sync(dev);
​iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);if (OwnADC) {OwnADC = 0;up(&ADC_LOCK);}}
}
​
static struct timer_list touch_timer = TIMER_INITIALIZER(touch_timer_fire, 0, 0);
​
static irqreturn_t stylus_updown(int irq, void *dev_id)
{unsigned long data0;unsigned long data1;int updown;
​if (down_trylock(&ADC_LOCK) == 0) {OwnADC = 1;data0 = ioread32(base_addr+S3C2410_ADCDAT0);data1 = ioread32(base_addr+S3C2410_ADCDAT1);
​updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
​if (updown) {touch_timer_fire(0);} else {OwnADC = 0;up(&ADC_LOCK);}}
​return IRQ_HANDLED;
}
​
​
static irqreturn_t stylus_action(int irq, void *dev_id)
{unsigned long data0;unsigned long data1;
​if (OwnADC) {data0 = ioread32(base_addr+S3C2410_ADCDAT0);data1 = ioread32(base_addr+S3C2410_ADCDAT1);
​xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK;yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;count++;
​if (count < (1<<2)) {iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);} else {mod_timer(&touch_timer, jiffies+1);iowrite32(WAIT4INT(1), base_addr+S3C2410_ADCTSC);}}
​return IRQ_HANDLED;
}
​
static struct clk   *adc_clock;
​
static int __init s3c2410ts_init(void)
{struct input_dev *input_dev;
​adc_clock = clk_get(NULL, "adc");if (!adc_clock) {printk(KERN_ERR "failed to get adc clock source\n");return -ENOENT;}clk_enable(adc_clock);
​base_addr=ioremap(S3C2410_PA_ADC,0x20);if (base_addr == NULL) {printk(KERN_ERR "Failed to remap register block\n");return -ENOMEM;}
​/* Configure GPIOs */s3c2410_ts_connect();
​iowrite32(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(0xFF),\base_addr+S3C2410_ADCCON);iowrite32(0xffff,  base_addr+S3C2410_ADCDLY);iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
​/* Initialise input stuff */input_dev = input_allocate_device();
​if (!input_dev) {printk(KERN_ERR "Unable to allocate the input device !!\n");return -ENOMEM;}
​dev = input_dev;dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);dev->keybit[BITS_TO_LONGS(BTN_TOUCH)] = BIT(BTN_TOUCH);input_set_abs_params(dev, ABS_X, 0, 0x3FF, 0, 0);input_set_abs_params(dev, ABS_Y, 0, 0x3FF, 0, 0);input_set_abs_params(dev, ABS_PRESSURE, 0, 1, 0, 0);
​dev->name = s3c2410ts_name;dev->id.bustype = BUS_RS232;dev->id.vendor = 0xDEAD;dev->id.product = 0xBEEF;dev->id.version = S3C2410TSVERSION;
​/* Get irqs */if (request_irq(IRQ_ADC, stylus_action, IRQF_SHARED|IRQF_SAMPLE_RANDOM,"s3c2410_action", dev)) {printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_ADC !\n");iounmap(base_addr);return -EIO;}if (request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM,"s3c2410_action", dev)) {printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_TC !\n");iounmap(base_addr);return -EIO;}
​printk(KERN_INFO "%s successfully loaded\n", s3c2410ts_name);
​/* All went ok, so register to the input system */input_register_device(dev);
​return 0;
}
​
static void __exit s3c2410ts_exit(void)
{disable_irq(IRQ_ADC);disable_irq(IRQ_TC);free_irq(IRQ_TC,dev);free_irq(IRQ_ADC,dev);
​if (adc_clock) {clk_disable(adc_clock);clk_put(adc_clock);adc_clock = NULL;}
​input_unregister_device(dev);iounmap(base_addr);
}
​
​
module_init(s3c2410ts_init);
module_exit(s3c2410ts_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("redistributed by tangmingfei2013@126.com");
MODULE_DESCRIPTION("Mini2440 Touch Screen Driver");

3.3.2 编写配置链接文件

linux-2.6.32.24/drivers/input/touchscreen/Kconfig中添加代码:

源代码:

config TOUCHSCREEN_S3C2410tristate "Samsung S3C2410 touchscreen input driver by mftang "depends on MACH_MINI2440 && INPUT && INPUT_TOUCHSCREEN && MINI2440_ADChelpSay Y here if you have the s3c2410 touchscreen.
​If unsure, say N.
​To compile this driver as a module, choose M here: themodule will be called s3c2410_ts.

在linux-2.6.32.24/drivers/input/touchscreen/Makefile中编写链接代码:

源代码:

obj-$(CONFIG_TOUCHSCREEN_S3C2410)   += s3c2410_ts.o

3.4 在内核中查看触摸功能的配置

使用make menuconfig命令,运行命令后,进入:

在进入代下一级目录中:

Device Drivers --->Input device support ---><*> Touchscreens --->

选中如下两项配置

退出配置界面,然后编译内核

4 功能测试

编译完成内核,生成zImage文件

下载zImage到mini2440,重新启动开发板:

屏幕能正常显示UI,触摸功能也能正常工作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/761916.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

-bash: ./1.sh: /bin/bash^M: bad interpreter: No such file or directory解决方法

1、执行脚本 ./1.sh时报如下错误 -bash: ./1.sh: /bin/bash^M: bad interpreter: No such file or directory 2、在Windows编辑的脚本导入Linux系统中&#xff0c;执行报错问题 yum install -y dos2unix 3、或者本地安装 rpm -ivh /mnt/Packages/dos...... 4、然…

基于python+vue中医学习服务管理系统flask-django-php-nodejs

随着世界经济信息化、全球化的到来和互联网的飞速发展&#xff0c;推动了各行业的改革。若想达到安全&#xff0c;快捷的目的&#xff0c;就需要拥有信息化的组织和管理模式&#xff0c;建立一套合理、动态的、交互友好的、高效的中医学习服务管理系统。当前的信息管理存在工作…

利用Jmeter工具对服务器,数据库进行性能监控,压测,导出性能测试报告

Jmeter是Apache基金会旗下的一款免费,开源,轻量级的性能测试工具,主要针对web应用程序客户端/服务器进行性能测试.它可以分别测试静态、动态资源(Java Servlet,CGI Scripts,Java Object,数据库和FTP服务器等),它可以通过线程组来模拟数个用户,在一段时间内同时登录服务器,数个用…

Matlab使用教程(持续更新)

1. Matlab Matlab被广泛的应用在数据分析&#xff0c;汽车仿真&#xff0c;机器人以及医学研究等众多方面。 它可以帮助我们理解研究复杂的系统。 在60年代和70年代&#xff0c;计算机使得科学家和工程师完成了以前不可能进行的计算&#xff1b;但是需要懂得计算机编程。 C…

CMU 10-414/714: Deep Learning Systems --hw4

通过之前作业中完成的所有组件,使用高性能的网络结构来解决一些问题。首先会增加一些新的算子(使用CPU/CUDA后端),然后完成卷积、以及用一个卷积神经网络来在CIFAR-10图像数据集上训练一个分类器。接着需要完成循环神经网络(带LSTM),并在Penn Treebank数据集上完成字符级…

AI原生安全 亚信安全首个“人工智能安全实用手册”开放阅览

不断涌现的AI技术新应用和大模型技术革新&#xff0c;让我们感叹从没有像今天这样&#xff0c;离人工智能的未来如此之近。 追逐AI原生&#xff1f;企业组织基于并利用大模型技术探索和开发AI应用的无限可能&#xff0c;迎接生产与业务模式的全面的革新。 我们更应关心AI安全原…

【高频SQL题目进阶版】1440.计算布尔表达式的值

错误答案&#xff1a; 我一开始以为&#xff0c;既然都能拿到值了&#xff0c; 那么把它们合并起来就可以了。后来发现不行。。 1 concat concat(v1.value ,operator ,v2.value) 它不是一个条件&#xff0c;而只是一个字符串 。 而if (condition, true_value, false_value)…

从后端获取文件数据并导出

导出文件的公共方法 export const download (res, tools) > {const { message, hide } tools;const fileReader: any new FileReader();console.log(fileReader-res>>>, res);fileReader.onload (e) > {if (res?.data?.type application/json) {try {co…

docker方式进行pytorch多机多卡分布式训练

docker ip共享与gpu指定 1)ip共享 docker网络有多种,这里选择host直接用宿主机的ip 2)指定gpu docker方式进行pytorch多机多卡分布式训练 nvidia docker 容器介绍链接:https://docs.nvidia.com/deeplearning/frameworks/pytorch-release-notes/ docker用的nvidia官方镜像…

数字孪生与智慧城市:重塑城市生活的新模式

随着信息技术的迅猛发展&#xff0c;数字孪生作为一种新兴的技术理念&#xff0c;正在逐渐改变城市建设和管理的传统模式。智慧城市作为数字孪生技术应用的重要领域&#xff0c;正在以其独特的优势和潜力&#xff0c;重塑着城市生活的方方面面。本文将从数字孪生的概念、智慧城…

中文编程入门(Lua5.4.6中文版)第十一章 Lua 模块与包 参考星争际霸游戏

在遥远的星争际霸世界中&#xff0c;代码模块就如同星际基地中的高科技仓库&#xff0c;储存着各类经过封装优化的战术指令和战略资源。自Lua 5.1版本起&#xff0c;星际编程者们引入了标准化的模块管理系统&#xff0c;使得不同战舰之间能够共享和调用核心战斗算法&#xff0c…

StarRocks学习笔记

介绍场景建表明细模型聚合模型更新模型主键模型 介绍 StarRocks是一款经过业界检验、现代化&#xff0c;面向多种数据分析场景的、兼容MySQL协议的、高性能分布式关系型分析数据库。 StarRocks充分吸收关系型 OLAP 数据库和分布式存储系统在大数据时代的优秀研究成果&#xff…

算法体系-14 第十四 贪心算法(上)

一 、 递归套路解决判断完全二叉树 1.1 描述 1.2 分析 1.3 代码 public static boolean isCBT2(Node head) {return process(head).isCBT;}public static class Info {public boolean isFull;public boolean isCBT;public int height;public Info(boolean full, boolean cbt…

UI自动测试框架-selenium(1) selenium介绍和选择器

目录 1.selenium是什么 2.定位元素 2.1 css选择器 2.1.1 选择id 2.1.2 class 2.1.3使用标签选择 2.1.4父类选择器 子类选择器 2.2 xpath 1.selenium是什么 selenium是用来做web端自动化测试的框架,它支持各种游览器,各种平台,支持各种语言(如 Python,Java,C#,JS,Ruby..…

[flask]flask的路由

路由的基本定义 路由就是一种映射关系。是绑定应用程序&#xff08;视图&#xff09;和url地址的一种一对一的映射关系&#xff01;在开发过程中&#xff0c;编写项目时所使用的路由往往是指代了框架/项目中用于完成路由功能的类&#xff0c;这个类一般就是路由类&#xff0c;…

全国产飞腾+FPGA架构,支持B码+12网口+多串电力通讯管理机解决方案

行业痛点: 中国的电力网络已经成为当今世界覆盖范围最广、结构最为复杂的人造科技系统。随着国家和各部委颁布了一系列法律法规&#xff0c;如国家颁布的《中华人民共和国网络安全法》、工信部颁布的《工业控制系统信息安全防护指南》、发改委颁布的14号令《电力监控系统安全防…

基于微信小程序的电影票务系统

文章目录 项目介绍主要功能截图&#xff1a;部分代码展示设计总结项目获取方式 &#x1f345; 作者主页&#xff1a;超级无敌暴龙战士塔塔开 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关注我&#xff0c;都给你】 &…

python智慧农业小程序flask-django-php-nodejs

当今社会已经步入了科学技术进步和经济社会快速发展的新时期&#xff0c;国际信息和学术交流也不断加强&#xff0c;计算机技术对经济社会发展和人民生活改善的影响也日益突出&#xff0c;人类的生存和思考方式也产生了变化。传统智慧农业采取了人工的管理方法&#xff0c;但这…

python自定义日历库,与对应calendar库函数功能基本一致

目录 自定义日历库 常用列表 日期列表 常用函数 闰年判断 月份天数 元旦序号 日历表头 星期序号 序号及天数 月历字串 打印月历 年历字串 打印年历 对比测试 测试结果 完整代码 运行结果 自定义日历库 自定义日历库函数&#xff0c;并使得其与python calend…

国际期货英文版配资系统/VUE源码包搭建

要搭建一个国际期货英文版配资系统的Vue源码包&#xff0c;你需要遵循一系列的开发步骤。这涉及到前端和后端的开发&#xff0c;以及确保系统的安全性、稳定性和可扩展性。以下是一个大致的指南&#xff0c;帮助你开始这个项目&#xff1a; 1. 需求分析 用户角色与权限&#…