diff options
Diffstat (limited to 'packages/linux/gumstix-kernel-2.6.21')
8 files changed, 510 insertions, 602 deletions
diff --git a/packages/linux/gumstix-kernel-2.6.21/gumstix-custom-connex/defconfig b/packages/linux/gumstix-kernel-2.6.21/gumstix-custom-connex/defconfig index 418a1b4402..cfc7babcef 100644 --- a/packages/linux/gumstix-kernel-2.6.21/gumstix-custom-connex/defconfig +++ b/packages/linux/gumstix-kernel-2.6.21/gumstix-custom-connex/defconfig @@ -1031,14 +1031,15 @@ CONFIG_I2C_PXA=m # # Miscellaneous I2C Chip support # -# CONFIG_SENSORS_DS1337 is not set -# CONFIG_SENSORS_DS1374 is not set -# CONFIG_SENSORS_EEPROM is not set -# CONFIG_SENSORS_PCF8574 is not set -# CONFIG_SENSORS_PCA9539 is not set -# CONFIG_SENSORS_PCF8591 is not set -# CONFIG_SENSORS_MAX6875 is not set -# CONFIG_SENSORS_TSC2003 is not set +CONFIG_SENSORS_DS1337=m +CONFIG_SENSORS_DS1374=m +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCA9539=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_MAX6875=m +CONFIG_SENSORS_TSC2003=m +CONFIG_SENSORS_TSC2003_SYSFS=m # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set @@ -1157,8 +1158,8 @@ CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y CONFIG_FONTS=y # CONFIG_FONT_8x8 is not set # CONFIG_FONT_8x16 is not set -# CONFIG_FONT_6x11 is not set -CONFIG_FONT_7x14=y +CONFIG_FONT_6x11=y +# CONFIG_FONT_7x14 is not set # CONFIG_FONT_PEARL_8x8 is not set # CONFIG_FONT_ACORN_8x8 is not set # CONFIG_FONT_MINI_4x6 is not set diff --git a/packages/linux/gumstix-kernel-2.6.21/gumstix-custom-connex/defconfig-nofb b/packages/linux/gumstix-kernel-2.6.21/gumstix-custom-connex/defconfig-nofb index 22e0ef0413..3840a395df 100644 --- a/packages/linux/gumstix-kernel-2.6.21/gumstix-custom-connex/defconfig-nofb +++ b/packages/linux/gumstix-kernel-2.6.21/gumstix-custom-connex/defconfig-nofb @@ -1031,14 +1031,15 @@ CONFIG_I2C_PXA=m # # Miscellaneous I2C Chip support # -# CONFIG_SENSORS_DS1337 is not set -# CONFIG_SENSORS_DS1374 is not set -# CONFIG_SENSORS_EEPROM is not set -# CONFIG_SENSORS_PCF8574 is not set -# CONFIG_SENSORS_PCA9539 is not set -# CONFIG_SENSORS_PCF8591 is not set -# CONFIG_SENSORS_MAX6875 is not set -# CONFIG_SENSORS_TSC2003 is not set +CONFIG_SENSORS_DS1337=m +CONFIG_SENSORS_DS1374=m +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCA9539=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_MAX6875=m +CONFIG_SENSORS_TSC2003=m +CONFIG_SENSORS_TSC2003_SYSFS=m # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set diff --git a/packages/linux/gumstix-kernel-2.6.21/gumstix-custom-verdex/defconfig b/packages/linux/gumstix-kernel-2.6.21/gumstix-custom-verdex/defconfig index 5a8728d26a..70a733a15c 100644 --- a/packages/linux/gumstix-kernel-2.6.21/gumstix-custom-verdex/defconfig +++ b/packages/linux/gumstix-kernel-2.6.21/gumstix-custom-verdex/defconfig @@ -1058,13 +1058,13 @@ CONFIG_I2C_PXA=m # # Miscellaneous I2C Chip support # -# CONFIG_SENSORS_DS1337 is not set -# CONFIG_SENSORS_DS1374 is not set -# CONFIG_SENSORS_EEPROM is not set -# CONFIG_SENSORS_PCF8574 is not set -# CONFIG_SENSORS_PCA9539 is not set -# CONFIG_SENSORS_PCF8591 is not set -# CONFIG_SENSORS_MAX6875 is not set +CONFIG_SENSORS_DS1337=m +CONFIG_SENSORS_DS1374=m +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCA9539=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_MAX6875=m CONFIG_SENSORS_TSC2003=m CONFIG_SENSORS_TSC2003_SYSFS=m # CONFIG_I2C_DEBUG_CORE is not set @@ -1187,8 +1187,8 @@ CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y CONFIG_FONTS=y # CONFIG_FONT_8x8 is not set # CONFIG_FONT_8x16 is not set -# CONFIG_FONT_6x11 is not set -CONFIG_FONT_7x14=y +CONFIG_FONT_6x11=y +# CONFIG_FONT_7x14 is not set # CONFIG_FONT_PEARL_8x8 is not set # CONFIG_FONT_ACORN_8x8 is not set # CONFIG_FONT_MINI_4x6 is not set @@ -1244,7 +1244,7 @@ CONFIG_SND_PXA2XX_AC97=m # # USB devices # -# CONFIG_SND_USB_AUDIO is not set +CONFIG_SND_USB_AUDIO=m # # PCMCIA devices @@ -1426,7 +1426,7 @@ CONFIG_USB_SERIAL_KEYSPAN_PDA=m # CONFIG_USB_SERIAL_TI is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OPTION is not set +CONFIG_USB_SERIAL_OPTION=m # CONFIG_USB_SERIAL_OMNINET is not set # CONFIG_USB_SERIAL_DEBUG is not set CONFIG_USB_EZUSB=y diff --git a/packages/linux/gumstix-kernel-2.6.21/gumstix-custom-verdex/defconfig-nofb b/packages/linux/gumstix-kernel-2.6.21/gumstix-custom-verdex/defconfig-nofb index 0634a90a94..144b3c6e3a 100644 --- a/packages/linux/gumstix-kernel-2.6.21/gumstix-custom-verdex/defconfig-nofb +++ b/packages/linux/gumstix-kernel-2.6.21/gumstix-custom-verdex/defconfig-nofb @@ -1058,13 +1058,13 @@ CONFIG_I2C_PXA=m # # Miscellaneous I2C Chip support # -# CONFIG_SENSORS_DS1337 is not set -# CONFIG_SENSORS_DS1374 is not set -# CONFIG_SENSORS_EEPROM is not set -# CONFIG_SENSORS_PCF8574 is not set -# CONFIG_SENSORS_PCA9539 is not set -# CONFIG_SENSORS_PCF8591 is not set -# CONFIG_SENSORS_MAX6875 is not set +CONFIG_SENSORS_DS1337=m +CONFIG_SENSORS_DS1374=m +CONFIG_SENSORS_EEPROM=m +CONFIG_SENSORS_PCF8574=m +CONFIG_SENSORS_PCA9539=m +CONFIG_SENSORS_PCF8591=m +CONFIG_SENSORS_MAX6875=m CONFIG_SENSORS_TSC2003=m CONFIG_SENSORS_TSC2003_SYSFS=m # CONFIG_I2C_DEBUG_CORE is not set @@ -1244,7 +1244,7 @@ CONFIG_SND_PXA2XX_AC97=m # # USB devices # -# CONFIG_SND_USB_AUDIO is not set +CONFIG_SND_USB_AUDIO=m # # PCMCIA devices @@ -1426,7 +1426,7 @@ CONFIG_USB_SERIAL_KEYSPAN_PDA=m # CONFIG_USB_SERIAL_TI is not set # CONFIG_USB_SERIAL_CYBERJACK is not set # CONFIG_USB_SERIAL_XIRCOM is not set -# CONFIG_USB_SERIAL_OPTION is not set +CONFIG_USB_SERIAL_OPTION=m # CONFIG_USB_SERIAL_OMNINET is not set # CONFIG_USB_SERIAL_DEBUG is not set CONFIG_USB_EZUSB=y diff --git a/packages/linux/gumstix-kernel-2.6.21/one-wire.patch b/packages/linux/gumstix-kernel-2.6.21/one-wire.patch new file mode 100644 index 0000000000..b4994c3e61 --- /dev/null +++ b/packages/linux/gumstix-kernel-2.6.21/one-wire.patch @@ -0,0 +1,35 @@ +--- linux-2.6.21/drivers/w1/w1.c ++++ linux-2.6.21/drivers/w1/w1.c +@@ -675,7 +675,6 @@ static void w1_slave_found(void *data, u64 rn) + struct w1_slave *sl; + struct list_head *ent; + struct w1_reg_num *tmp; +- int family_found = 0; + struct w1_master *dev; + u64 rn_le = cpu_to_le64(rn); + +@@ -698,9 +697,6 @@ static void w1_slave_found(void *data, u64 rn) + sl->reg_num.crc == tmp->crc) { + set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); + break; +- } else if (sl->reg_num.family == tmp->family) { +- family_found = 1; +- break; + } + + slave_count++; +@@ -874,11 +874,9 @@ void w1_search_process(struct w1_master *dev, u8 search_type) + w1_search_devices(dev, search_type, w1_slave_found); + + list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { +- if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) { ++ if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) + w1_slave_detach(sl); +- +- dev->slave_count--; +- } else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) ++ else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags)) + sl->ttl = dev->slave_ttl; + } + + diff --git a/packages/linux/gumstix-kernel-2.6.21/pxafb-backto16.patch b/packages/linux/gumstix-kernel-2.6.21/pxafb-backto16.patch new file mode 100644 index 0000000000..a8b91daf37 --- /dev/null +++ b/packages/linux/gumstix-kernel-2.6.21/pxafb-backto16.patch @@ -0,0 +1,40 @@ +--- linux-2.6.21/arch/arm/mach-pxa/gumstix.c-orig 2008-02-20 16:18:57.000000000 -0800 ++++ linux-2.6.21/arch/arm/mach-pxa/gumstix.c 2008-02-20 16:21:21.000000000 -0800 +@@ -146,8 +146,7 @@ + .pixclock = 110000, + .xres = 480, + .yres = 272, +- .bpp = 18, +- .nonstd = 24, ++ .bpp = 16, + .hsync_len = 41, + .left_margin = 2, + .right_margin = 2, +@@ -161,7 +160,7 @@ + .modes = &gumstix_fb_mode, + .num_modes = 1, + .lccr0 = LCCR0_Act | LCCR0_Sngl | LCCR0_Color, +- .lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg | (3 << 30), ++ .lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg | (0 << 30), + .pxafb_backlight_power = &gumstix_lcd_backlight, + }; + #elif defined(CONFIG_FB_PXA_SAMSUNG_LTE430WQ_F0C) +@@ -175,8 +174,7 @@ + .vsync_len = 10, // VLW from datasheet: 10 typ + .upper_margin = 2, // VBP - VLW from datasheet: 12 - 10 = 2 + .lower_margin = 4, // VFP from datasheet: 4 typ +- .bpp = 18, +- .nonstd = 24, ++ .bpp = 16, + .sync = 0, // Hsync and Vsync both active low + }; + +@@ -184,7 +182,7 @@ + .modes = &gumstix_fb_mode, + .num_modes = 1, + .lccr0 = LCCR0_Act | LCCR0_Sngl | LCCR0_Color, +- .lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg | (3 << 30), ++ .lccr3 = LCCR3_OutEnH | LCCR3_PixFlEdg | (0 << 30), + .pxafb_backlight_power = &gumstix_lcd_backlight, + }; + #endif diff --git a/packages/linux/gumstix-kernel-2.6.21/smc91x-fail-if-no-chip.patch b/packages/linux/gumstix-kernel-2.6.21/smc91x-fail-if-no-chip.patch new file mode 100644 index 0000000000..0d4425412c --- /dev/null +++ b/packages/linux/gumstix-kernel-2.6.21/smc91x-fail-if-no-chip.patch @@ -0,0 +1,58 @@ +--- linux-2.6.21/drivers/net/gumstix-smc91x.c-orig 2008-02-24 22:06:30.000000000 -0800 ++++ linux-2.6.21/drivers/net/gumstix-smc91x.c 2008-02-25 08:12:57.000000000 -0800 +@@ -90,18 +90,42 @@ + pxa_gpio_mode(GPIO49_nPWE_MD); + + pxa_gpio_mode(GPIO78_nCS_2_MD); +- // If either if statement fails, then we'll drop out and turn_off_eth1, ++ ++ // First look for smc91x0 ++ // If either if statement fails, then we'll drop out and turn_off_eth0, ++ // if both succeed, then we'll skip that and just proceed ++ // to test for 2 smc91x chips ++ if(request_mem_region(gumstix_smc91x0_resources[0].start, SMC_IO_EXTENT, "smc91x0 probe")) ++ { ++ ioaddr = ioremap(gumstix_smc91x0_resources[0].start, SMC_IO_EXTENT); ++ val = ioread16(ioaddr + BANK_SELECT); ++ iounmap(ioaddr); ++ release_mem_region(gumstix_smc91x0_resources[0].start, SMC_IO_EXTENT); ++ if ((val & 0xFF00) == 0x3300) { ++ goto proceed; ++ } ++ } ++ ++ printk(KERN_ERR "%s: smc91x chip not found, returning -ENXIO\n", __FUNCTION__); ++ return -ENXIO; ++ ++proceed: ++ printk(KERN_ERR "%s: smc91x chip found\n", __FUNCTION__); ++ ++ // Now look for a second smc91x ++ // If either if statement fails, then we'll drop out and return -ENXIO + // if both succeed, then we'll skip that and just proceed with 2 cards +- if(request_mem_region(gumstix_smc91x1_resources[0].start, SMC_IO_EXTENT, "smc91x probe")) ++ if(request_mem_region(gumstix_smc91x1_resources[0].start, SMC_IO_EXTENT, "smc91x1 probe")) + { + ioaddr = ioremap(gumstix_smc91x1_resources[0].start, SMC_IO_EXTENT); + val = ioread16(ioaddr + BANK_SELECT); + iounmap(ioaddr); + release_mem_region(gumstix_smc91x1_resources[0].start, SMC_IO_EXTENT); + if ((val & 0xFF00) == 0x3300) { +- goto proceed; ++ goto proceed1; + } + } ++ + + turn_off_eth1: + // This is apparently not an SMC91C111 +@@ -110,7 +134,8 @@ + smc91x_devices[1] = NULL; + pxa_gpio_mode(78 | GPIO_IN); + +-proceed: ++proceed1: ++ printk(KERN_ERR "%s: found %d smc91x chip(s)\n", __FUNCTION__); + pxa_gpio_mode(GPIO15_nCS_1_MD); + + if(smc91x_devices[1]) pxa_gpio_mode(GPIO_GUMSTIX_ETH1_RST_MD); diff --git a/packages/linux/gumstix-kernel-2.6.21/tsc2003.c b/packages/linux/gumstix-kernel-2.6.21/tsc2003.c index d0f496617e..a4a68b756d 100644 --- a/packages/linux/gumstix-kernel-2.6.21/tsc2003.c +++ b/packages/linux/gumstix-kernel-2.6.21/tsc2003.c @@ -3,6 +3,7 @@ * * Copyright (C) 2005 Bill Gatliff <bgat at billgatliff.com> * Changes for 2.6.20 kernel by Nicholas Chen <nchen at cs.umd.edu> + * Changes for 2.6.21 kernel by Chris Dollar <chris.dollar at gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -25,669 +26,442 @@ #include <linux/delay.h> #include <asm-arm/arch-pxa/irqs.h> -static unsigned short normal_i2c[] -= {0x48, I2C_CLIENT_END }; +#define DRIVER_NAME "tsc2003" +#define TSC2003_CMD(cn,pdn,m) (((cn) << 4) | ((pdn) << 2) | ((m) << 1)) +#define ADC_MAX ((1 << 12) - 1) -I2C_CLIENT_INSMOD_1(tsc2003); +//#define CONFIG_I2C_DEBUG_CHIP 1 -#define DRIVER_NAME "tsc2003" +static unsigned short normal_i2c[] = { 0x48, I2C_CLIENT_END }; + +I2C_CLIENT_INSMOD_1(tsc2003); enum tsc2003_pd { - PD_POWERDOWN = 0, /* penirq */ - PD_IREFOFF_ADCON = 1, /* no penirq */ - PD_IREFON_ADCOFF = 2, /* penirq */ - PD_IREFON_ADCON = 3, /* no penirq */ - PD_PENIRQ_ARM = PD_IREFON_ADCOFF, - PD_PENIRQ_DISARM = PD_IREFON_ADCON, + PD_POWERDOWN = 0, /* penirq */ + PD_IREFOFF_ADCON = 1, /* no penirq */ + PD_IREFON_ADCOFF = 2, /* penirq */ + PD_IREFON_ADCON = 3, /* no penirq */ + PD_PENIRQ_ARM = PD_IREFON_ADCOFF, + PD_PENIRQ_DISARM = PD_IREFON_ADCON, }; enum tsc2003_m { - M_12BIT = 0, - M_8BIT = 1 + M_12BIT = 0, + M_8BIT = 1 }; enum tsc2003_cmd { - MEAS_TEMP0 = 0, - MEAS_VBAT1 = 1, - MEAS_IN1 = 2, - MEAS_TEMP1 = 4, - MEAS_VBAT2 = 5, - MEAS_IN2 = 6, - ACTIVATE_NX_DRIVERS = 8, - ACTIVATE_NY_DRIVERS = 9, - ACTIVATE_YNX_DRIVERS = 10, - MEAS_XPOS = 12, - MEAS_YPOS = 13, - MEAS_Z1POS = 14, - MEAS_Z2POS = 15 + MEAS_TEMP0 = 0, + MEAS_VBAT1 = 1, + MEAS_IN1 = 2, + MEAS_TEMP1 = 4, + MEAS_VBAT2 = 5, + MEAS_IN2 = 6, + ACTIVATE_NX_DRIVERS = 8, + ACTIVATE_NY_DRIVERS = 9, + ACTIVATE_YNX_DRIVERS = 10, + MEAS_XPOS = 12, + MEAS_YPOS = 13, + MEAS_Z1POS = 14, + MEAS_Z2POS = 15 }; -#define TSC2003_CMD(cn,pdn,m) (((cn) << 4) | ((pdn) << 2) | ((m) << 1)) - -#define ADC_MAX ((1 << 12) - 1) - struct tsc2003_data { - struct i2c_client client; - struct device_driver driver; - struct input_dev *idev; - struct timer_list penirq_timer; - struct semaphore sem; - struct task_struct *tstask; - struct completion tstask_completion; - struct completion penirq_completion; - enum tsc2003_pd pd; - enum tsc2003_m m; - int penirq; - - int vbat1; - int vbat2; - int temp0; - int temp1; - int in1; - int in2; + struct i2c_client client; + struct device_driver driver; + struct input_dev *idev; + struct semaphore sem; + struct task_struct *tstask; + struct completion tstask_completion; + struct completion penirq_completion; + enum tsc2003_pd pd; + enum tsc2003_m m; + int penirq; + + int vbat1; + int vbat2; + int temp0; + int temp1; + int in1; + int in2; }; -static int tsc2003_i2c_detect (struct i2c_adapter *adapter, int address, -int kind); +static int + tsc2003_i2c_detect(struct i2c_adapter *adapter, int address, int kind); -static inline int tsc2003_command (struct tsc2003_data *data, - enum tsc2003_cmd cmd, - enum tsc2003_pd pd) -{ - char c; - int ret; - down(&data->sem); - c = TSC2003_CMD(cmd, pd, data->m); - ret = i2c_master_send(&data->client, &c, 1); - up(&data->sem); - return ret; -} +static int tsc2003_read(struct tsc2003_data *data, enum tsc2003_cmd cmd, + enum tsc2003_pd pd, int *val) { + char c; + char d[2]; + int ret; -static int tsc2003_read (struct tsc2003_data *data, - enum tsc2003_cmd cmd, - enum tsc2003_pd pd, - int *val) -{ - char c; - char d[2]; - int ret; - - c = TSC2003_CMD(cmd, pd, data->m); - ret = i2c_master_send(&data->client, &c, 1); - if (ret <= 0) goto err; - - udelay(20); - ret = i2c_master_recv(&data->client, d, data->m == M_12BIT ? 2 : 1); - if (ret <= 0) goto err; - - if (val) - { - *val = d[0]; - *val <<= 4; - if (data->m == M_12BIT) - *val += (d[1] >> 4); - } + c = TSC2003_CMD(cmd, pd, data->m); + ret = i2c_master_send(&data->client, &c, 1); + if (ret <= 0) + goto err; + + udelay(20); + ret = i2c_master_recv(&data->client, d, data->m == M_12BIT ? 2 : 1); + if (ret <= 0) + goto err; + + if (val) { + *val = d[0]; + *val <<= 4; + if (data->m == M_12BIT) + *val += (d[1] >> 4); + } #if defined(CONFIG_I2C_DEBUG_CHIP) - printk(KERN_ERR "%s: val[%x] = %d\n", - __FUNCTION__, cmd, (((int)d[0]) << 8) + d[1]); + printk(KERN_ERR "%s: val[%x] = %d\n", + __FUNCTION__, cmd, (((int)d[0]) << 8) + d[1]); #endif - return 0; - err: - if (!ret) ret = -ENODEV; - return ret; + return 0; + err: if (!ret) + ret = -ENODEV; + return ret; } -static inline int tsc2003_read_temp0 (struct tsc2003_data *d, enum -tsc2003_pd pd, int *t) -{ - return tsc2003_read(d, MEAS_TEMP0, pd, t); +static inline int tsc2003_read_temp0(struct tsc2003_data *d, enum +tsc2003_pd pd, int *t) { + return tsc2003_read(d, MEAS_TEMP0, pd, t); } -static inline int tsc2003_read_temp1 (struct tsc2003_data *d, enum -tsc2003_pd pd, int *t) -{ - return tsc2003_read(d, MEAS_TEMP1, pd, t); +static inline int tsc2003_read_temp1(struct tsc2003_data *d, enum +tsc2003_pd pd, int *t) { + return tsc2003_read(d, MEAS_TEMP1, pd, t); } -static inline int tsc2003_read_xpos (struct tsc2003_data *d, enum -tsc2003_pd pd, int *x) -{ - return tsc2003_read(d, MEAS_XPOS, pd, x); +static inline int tsc2003_read_xpos(struct tsc2003_data *d, enum +tsc2003_pd pd, int *x) { + return tsc2003_read(d, MEAS_XPOS, pd, x); } -static inline int tsc2003_read_ypos (struct tsc2003_data *d, enum -tsc2003_pd pd, int *y) -{ - return tsc2003_read(d, MEAS_YPOS, pd, y); +static inline int tsc2003_read_ypos(struct tsc2003_data *d, enum +tsc2003_pd pd, int *y) { + return tsc2003_read(d, MEAS_YPOS, pd, y); } -static inline int tsc2003_read_pressure (struct tsc2003_data *d, enum -tsc2003_pd pd, int *p) -{ - return tsc2003_read(d, MEAS_Z1POS, pd, p); +static inline int tsc2003_read_pressure(struct tsc2003_data *d, enum +tsc2003_pd pd, int *p) { + return tsc2003_read(d, MEAS_Z1POS, pd, p); } -static inline int tsc2003_read_in1 (struct tsc2003_data *d, enum -tsc2003_pd pd, int *t) -{ - return tsc2003_read(d, MEAS_IN1, pd, t); +static inline int tsc2003_read_in1(struct tsc2003_data *d, enum +tsc2003_pd pd, int *t) { + return tsc2003_read(d, MEAS_IN1, pd, t); } -static inline int tsc2003_read_in2 (struct tsc2003_data *d, enum -tsc2003_pd pd, int *t) -{ - return tsc2003_read(d, MEAS_IN2, pd, t); +static inline int tsc2003_read_in2(struct tsc2003_data *d, enum +tsc2003_pd pd, int *t) { + return tsc2003_read(d, MEAS_IN2, pd, t); } -static inline int tsc2003_read_vbat1 (struct tsc2003_data *d, enum -tsc2003_pd pd, int *t) -{ - return tsc2003_read(d, MEAS_VBAT1, pd, t); +static inline int tsc2003_read_vbat1(struct tsc2003_data *d, enum +tsc2003_pd pd, int *t) { + return tsc2003_read(d, MEAS_VBAT1, pd, t); } -static inline int tsc2003_read_vbat2 (struct tsc2003_data *d, enum -tsc2003_pd pd, int *t) -{ - return tsc2003_read(d, MEAS_VBAT2, pd, t); +static inline int tsc2003_read_vbat2(struct tsc2003_data *d, enum +tsc2003_pd pd, int *t) { + return tsc2003_read(d, MEAS_VBAT2, pd, t); } -static inline int tsc2003_powerdown (struct tsc2003_data *d) -{ - /* we don't have a distinct powerdown command, - so do a benign read with the PD bits cleared */ - return tsc2003_read(d, MEAS_IN1, PD_POWERDOWN, 0); +static inline int tsc2003_powerdown(struct tsc2003_data *d) { + /* we don't have a distinct powerdown command, + so do a benign read with the PD bits cleared */ + return tsc2003_read(d, MEAS_IN1, PD_POWERDOWN, 0); } -void tsc2003_init_client (struct i2c_client *client) -{ - struct tsc2003_data *data = i2c_get_clientdata(client); +void tsc2003_init_client(struct i2c_client *client) { + struct tsc2003_data *data = i2c_get_clientdata(client); - data->pd = PD_PENIRQ_DISARM; - data->m = M_8BIT; - return; + data->pd = PD_PENIRQ_DISARM; + data->m = M_8BIT; + return; } -#define PENUP_TIMEOUT 50 /* msec */ +static irqreturn_t tsc2003_penirq(int irq, void *v) { + struct tsc2003_data *d = v; -static irqreturn_t tsc2003_penirq (int irq, void *v) -{ - struct tsc2003_data *d = v; - complete(&d->penirq_completion); - return IRQ_HANDLED; -} + printk(KERN_INFO "penirq: %Ld\n", jiffies); -/* -static int tsc2003_remove (struct device *dev) -{ - struct tsc2003_data *d = container_of(dev->driver, struct tsc2003_data, driver); - free_irq(d->penirq,d); - input_unregister_device(d->idev); - return 0; -} -*/ + // disable the penirq while we take the sample + disable_irq_nosync(d->penirq); -static void tsc2003_pen_up (unsigned long v) -{ - struct tsc2003_data *d = (struct tsc2003_data *)v; - input_report_abs(d->idev, ABS_PRESSURE, 0); - input_sync(d->idev); - return; + complete(&d->penirq_completion); + return IRQ_HANDLED; } -static inline void tsc2003_restart_pen_up_timer (struct tsc2003_data *d) -{ - mod_timer(&d->penirq_timer, jiffies + (PENUP_TIMEOUT * HZ) / 1000); +static void tsc2003_pen_up(unsigned long v) { + printk(KERN_INFO "tsc2003_pen_up - re-enable irq now\n"); + struct tsc2003_data *d = (struct tsc2003_data *)v; + + enable_irq(d->penirq); + + input_report_abs(d->idev, ABS_PRESSURE, 0); + input_sync(d->idev); + return; } -static int tsc2003ts_thread (void *v) -{ - struct tsc2003_data *d = v; - struct task_struct *tsk = current; - int ret; - - d->tstask = tsk; +static int tsc2003ts_thread(void *v) { + struct tsc2003_data *d = v; + struct task_struct *tsk = current; + int ret; + int err = 0; + + d->tstask = tsk; - daemonize(DRIVER_NAME "tsd"); - allow_signal(SIGKILL); + daemonize(DRIVER_NAME "tsd"); + allow_signal(SIGKILL); - complete(&d->tstask_completion); + complete(&d->tstask_completion); #if defined(CONFIG_I2C_DEBUG_CHIP) - printk(KERN_INFO "%s: address 0x%x\n", - __FUNCTION__, d->client.addr); -#endif + printk(KERN_INFO "%s: address 0x%x\n", + __FUNCTION__, d->client.addr); +#endif + + do { + unsigned int x, y, p, fp; + int pen_is_up = 0; + + down(&d->sem); + + // take the sample + d->pd = PD_PENIRQ_DISARM; + tsc2003_read_xpos(d, PD_PENIRQ_DISARM, &x); + tsc2003_read_ypos(d, PD_PENIRQ_DISARM, &y); + tsc2003_read_pressure(d, PD_PENIRQ_DISARM, &p); + + if (p < 64) { + p=0; + } - while (!signal_pending(tsk)) - { - unsigned int x, y, p; - - if (!down_interruptible(&d->sem)) - { - d->pd = PD_PENIRQ_DISARM; - disable_irq(d->penirq); - tsc2003_read_xpos(d, PD_PENIRQ_DISARM, &x); - tsc2003_read_ypos(d, PD_PENIRQ_DISARM, &y); - tsc2003_read_pressure(d, PD_PENIRQ_DISARM, &p); - - /* non-X-Y driver read to avoid glitch in penirq (errata?) */ - tsc2003_read_vbat1(d, PD_PENIRQ_DISARM, 0); - enable_irq(d->penirq); - - - input_report_abs(d->idev, ABS_X, 4096 - x); - input_report_abs(d->idev, ABS_Y, 4096 - y); - input_report_abs(d->idev, ABS_PRESSURE, p); - input_sync(d->idev); - - - do - { - ret = wait_for_completion_interruptible_timeout(&d->penirq_completion, HZ / 100); - if (ret) - { - if (d->pd == PD_PENIRQ_DISARM) - { - /* fake penirq, avoid glitch and then start watching for real now */ - d->pd = PD_PENIRQ_ARM; - tsc2003_read_vbat1(d, PD_PENIRQ_ARM, 0); - up(&d->sem); - } - else - { - /* pen down event, (re)start the pen up timer */ - tsc2003_restart_pen_up_timer(d); - } - } - else - { - if (d->pd != PD_PENIRQ_ARM) - { - /* fake penirq never arrived, which would be the case - for a level-triggered irq line */ - tsc2003_read_vbat1(d, PD_PENIRQ_ARM, 0); - d->pd = PD_PENIRQ_ARM; - up(&d->sem); - } - if (timer_pending(&d->penirq_timer)) - { - /* pen is down, time to send (another) sample */ - break; - } - else - { - /* pen is up, nothing to do but wait for it to - come down */ - wait_for_completion_interruptible(&d->penirq_completion); - /* pen is down, (re)start the pen up timer */ - tsc2003_restart_pen_up_timer(d); - break; - } - } - } - while (!signal_pending(tsk)); - } - } - - d->tstask = NULL; - complete_and_exit(&d->tstask_completion, 0); -} +#if defined(CONFIG_I2C_DEBUG_CHIP) + printk(KERN_INFO "TSD X: %d Y: %d P: %d\n", x, y, p); +#endif + + if (!pen_is_up) { + // report our touch to the input layer + input_report_abs(d->idev, ABS_X, 4096 - x); + input_report_abs(d->idev, ABS_Y, 4096 - y); + input_report_abs(d->idev, ABS_PRESSURE, p); + input_sync(d->idev); + } + + if(p == 0) { +#if defined(CONFIG_I2C_DEBUG_CHIP) + printk(KERN_INFO "No pressure - pen is up!\n"); +#endif + // set our pen as up + pen_is_up = 1; + } + else { +#if defined(CONFIG_I2C_DEBUG_CHIP) + printk(KERN_INFO "Pen is still down - sleeping and will re-sample!\n"); +#endif + // set our pen as down + pen_is_up = 0; + } -static int tsc2003_idev_open (struct input_dev *idev) -{ - struct tsc2003_data *d = idev->private; - int ret = 0; + // sleep for 3 jiffies to give us about 30 updates/sec + msleep (3); - if (down_interruptible(&d->sem)) - return -EINTR; + up(&d->sem); - if (d->tstask) - panic(DRIVER_NAME "tsd already running (!). abort."); - - d->penirq_timer.data = (unsigned long)d; - d->penirq_timer.function = tsc2003_pen_up; + } while (!signal_pending(tsk)); - ret = kernel_thread(tsc2003ts_thread, d, CLONE_KERNEL); - if (ret >= 0) - { - wait_for_completion(&d->tstask_completion); - ret = 0; - } + d->tstask = NULL; + complete_and_exit(&d->tstask_completion, 0); +} - +static int tsc2003_idev_open(struct input_dev *idev) { + struct tsc2003_data *d = idev->private; + int ret = 0; - up(&d->sem); - return ret; -} + if (down_interruptible(&d->sem)) + return -EINTR; -static void tsc2003_idev_close (struct input_dev *idev) -{ - struct tsc2003_data *d = idev->private; - down_interruptible(&d->sem); - if (d->tstask) - { - send_sig(SIGKILL, d->tstask, 1); - wait_for_completion(&d->tstask_completion); - } - - if (timer_pending(&d->penirq_timer)) - del_timer(&d->penirq_timer); - up(&d->sem); - return; -} + if (d->tstask) + panic(DRIVER_NAME "tsd already running (!). abort."); -#if defined(CONFIG_SYSFS) && defined(CONFIG_SENSORS_TSC2003_SYSFS) -static ssize_t show_addr (struct device *dev, char *buf) -{ - struct tsc2003_data *d = container_of(dev->driver, struct -tsc2003_data, driver); - return sprintf(buf, "%d\n", d->client.addr); -} -static DEVICE_ATTR(addr, S_IRUGO, show_addr, NULL); + ret = kernel_thread(tsc2003ts_thread, d, CLONE_KERNEL); + if (ret >= 0) { + wait_for_completion(&d->tstask_completion); + ret = 0; + } -static ssize_t show_vbat1 (struct device *dev, char *buf) -{ - struct tsc2003_data *d = container_of(dev->driver, struct -tsc2003_data, driver); - return sprintf(buf, "%d\n", d->vbat1); + up(&d->sem); + return ret; } -static DEVICE_ATTR(vbat1, S_IRUGO, show_vbat1, NULL); -static ssize_t show_vbat2 (struct device *dev, char *buf) -{ - struct tsc2003_data *d = container_of(dev->driver, struct -tsc2003_data, driver); - return sprintf(buf, "%d\n", d->vbat2); -} -static DEVICE_ATTR(vbat2, S_IRUGO, show_vbat2, NULL); +static void tsc2003_idev_close(struct input_dev *idev) { + struct tsc2003_data *d = idev->private; + down_interruptible(&d->sem); + if (d->tstask) { + send_sig(SIGKILL, d->tstask, 1); + wait_for_completion(&d->tstask_completion); + } -static ssize_t show_in1 (struct device *dev, char *buf) -{ - struct tsc2003_data *d = container_of(dev->driver, struct -tsc2003_data, driver); - return sprintf(buf, "%d\n", d->in1); + up(&d->sem); + return; } -static DEVICE_ATTR(in1, S_IRUGO, show_in1, NULL); -static ssize_t show_in2 (struct device *dev, char *buf) -{ - struct tsc2003_data *d = container_of(dev->driver, struct -tsc2003_data, driver); - return sprintf(buf, "%d\n", d->in2); +static int tsc2003_detect_irq(struct tsc2003_data *d) { + d->penirq = IRQ_GPIO(16); //PWM0 GPIO + return 0; } -static DEVICE_ATTR(in2, S_IRUGO, show_in2, NULL); -static ssize_t show_temp0 (struct device *dev, char *buf) -{ - struct tsc2003_data *d = container_of(dev->driver, struct -tsc2003_data, driver); - return sprintf(buf, "%d\n", d->temp0); -} -static DEVICE_ATTR(temp0, S_IRUGO, show_temp0, NULL); +static int tsc2003_driver_register(struct tsc2003_data *data) { + struct input_dev *idev; + int ret = 0; + int error; -static ssize_t show_temp1 (struct device *dev, char *buf) -{ - struct tsc2003_data *d = container_of(dev->driver, struct -tsc2003_data, driver); - return sprintf(buf, "%d\n", d->temp1); -} -static DEVICE_ATTR(temp1, S_IRUGO, show_temp1, NULL); + init_MUTEX(&data->sem); -#warning "TODO: this daemon sometimes hangs the touchscreen daemon" -#warning "TODO: under periods of heavy touch screen activity." -#warning "TODO: Use with caution until the bug is squashed." -static int tsc2003s_thread (void *v) -{ - struct tsc2003_data *d = v; - - daemonize(DRIVER_NAME "sd"); - allow_signal(SIGKILL); - - printk(KERN_INFO "%s: address 0x%x\n", - __FUNCTION__, d->client.addr); - - while (!signal_pending(current)) - { - if (!down_interruptible(&d->sem)) - { - if (!timer_pending(&d->penirq_timer)) - { - tsc2003_read_vbat1(d, d->pd, &d->vbat1); - tsc2003_read_vbat2(d, d->pd, &d->vbat2); - tsc2003_read_in1(d, d->pd, &d->in1); - tsc2003_read_in2(d, d->pd, &d->in2); - tsc2003_read_temp0(d, d->pd, &d->temp0); - tsc2003_read_temp1(d, d->pd, &d->temp1); - } - up(&d->sem); - } - set_task_state(current, TASK_INTERRUPTIBLE); - schedule_timeout(5 * HZ); - } - do_exit(0); -} -#endif + error = tsc2003_detect_irq(data); + if (error) { + printk(KERN_ERR "TSC2003: IRQ probe failed\n"); + } -static int tsc2003_detect_irq (struct tsc2003_data *d) -{ - d->penirq = IRQ_GPIO(16); //PWM0 GPIO - return 0; -} + if (data->penirq) { + ret = request_irq(data->penirq, tsc2003_penirq, SA_INTERRUPT | IRQF_TRIGGER_LOW, + DRIVER_NAME, data); + if (!ret) { + printk(KERN_INFO "%s: irq %d\n", __FUNCTION__, data->penirq); + init_completion(&data->tstask_completion); + init_completion(&data->penirq_completion); + } else { + printk(KERN_ERR "%s: cannot grab irq %d\n", __FUNCTION__, data->penirq); + } + } -/* -static int tsc2003_probe (struct device *dev) -{ - //struct platform_device *p = to_platform_device(dev); - struct tsc2003_data *d = container_of(dev->driver, struct tsc2003_data, driver); - int ret = 0; - int error; - - printk(KERN_ERR "TSC2003: tsc2003_probe probing...\n"); - - error = tsc2003_detect_irq(d); - if(error) - { - printk(KERN_ERR "TSC2003: IRQ probe failed\n"); - } - - if (d->penirq) - { - ret = request_irq(d->penirq, tsc2003_penirq, IRQF_TRIGGER_FALLING, DRIVER_NAME, d); - if (!ret) - { - printk(KERN_INFO "%s: irq %d\n", __FUNCTION__, d->penirq); - } - else - { - printk(KERN_INFO "%s: cannot grab irq %d\n", __FUNCTION__, d->penirq); - } - } - -#if defined(CONFIG_SYSFS) && defined(CONFIG_SENSORS_TSC2003_SYSFS) - ret = kernel_thread(tsc2003s_thread, d, CLONE_KERNEL); - if (ret >= 0) - ret = 0; - - device_create_file(dev, &dev_attr_addr); - device_create_file(dev, &dev_attr_vbat1); - device_create_file(dev, &dev_attr_vbat2); - device_create_file(dev, &dev_attr_in1); - device_create_file(dev, &dev_attr_in2); - device_create_file(dev, &dev_attr_temp0); - device_create_file(dev, &dev_attr_temp1); -#endif + idev = input_allocate_device(); + data->idev = idev; + idev->private = data; + idev->name = DRIVER_NAME; + idev->evbit[0] = BIT(EV_ABS); + idev->open = tsc2003_idev_open; + idev->close = tsc2003_idev_close; + idev->absbit[LONG(ABS_X)] = BIT(ABS_X); + idev->absbit[LONG(ABS_Y)] = BIT(ABS_Y); + idev->absbit[LONG(ABS_PRESSURE)] = BIT(ABS_PRESSURE); + input_set_abs_params(idev, ABS_X, 0, ADC_MAX, 0, 0); + input_set_abs_params(idev, ABS_Y, 0, ADC_MAX, 0, 0); + input_set_abs_params(idev, ABS_PRESSURE, 0, 0, 0, 0); - return ret; -} -*/ + if (!ret) { + input_register_device(idev); + printk(KERN_INFO "tsc2003 - registering input device\n"); + } -static int tsc2003_driver_register (struct tsc2003_data *data) -{ - struct input_dev *idev; - int ret = 0; - int error; - - init_MUTEX(&data->sem); - - init_timer(&data->penirq_timer); - data->penirq_timer.data = (unsigned long)data; - data->penirq_timer.function = tsc2003_pen_up; - - error = tsc2003_detect_irq(data); - if(error) - { - printk(KERN_ERR "TSC2003: IRQ probe failed\n"); - } - - if (data->penirq) - { - ret = request_irq(data->penirq, tsc2003_penirq, IRQF_TRIGGER_FALLING, DRIVER_NAME, data); - if (!ret) - { - printk(KERN_INFO "%s: irq %d\n", __FUNCTION__, data->penirq); - init_completion(&data->tstask_completion); - init_completion(&data->penirq_completion); - } - else - { - printk(KERN_ERR "%s: cannot grab irq %d\n", __FUNCTION__, data->penirq); - } - } - - idev = input_allocate_device(); - data->idev = idev; - - idev->private = data; - idev->name = DRIVER_NAME; - idev->evbit[0] = BIT(EV_ABS); - idev->open = tsc2003_idev_open; - idev->close = tsc2003_idev_close; - idev->absbit[LONG(ABS_X)] = BIT(ABS_X); - idev->absbit[LONG(ABS_Y)] = BIT(ABS_Y); - idev->absbit[LONG(ABS_PRESSURE)] = BIT(ABS_PRESSURE); - input_set_abs_params(idev, ABS_X, 0, ADC_MAX, 0, 0); - input_set_abs_params(idev, ABS_Y, 0, ADC_MAX, 0, 0); - input_set_abs_params(idev, ABS_PRESSURE, 0, 0, 0, 0); - - if (!ret) - { - input_register_device(idev); - printk(KERN_INFO "tsc2003 - registering input device\n"); - } - - return ret; + return ret; } -static int tsc2003_i2c_attach_adapter(struct i2c_adapter *adapter) -{ - printk(KERN_INFO "tsc2003 i2c touch screen controller\n"); - printk(KERN_INFO "Bill Gatliff <bgat at billgatliff.com\n"); - printk(KERN_INFO "Nicholas Chen <nchen at cs.umd.edu>\n"); - - return i2c_probe(adapter, &addr_data, tsc2003_i2c_detect); +static int tsc2003_i2c_attach_adapter(struct i2c_adapter *adapter) { + printk(KERN_INFO "tsc2003 i2c touch screen controller\n"); + printk(KERN_INFO "Bill Gatliff <bgat at billgatliff.com\n"); + printk(KERN_INFO "Nicholas Chen <nchen at cs.umd.edu>\n"); + + return i2c_probe(adapter, &addr_data, tsc2003_i2c_detect); } -static int tsc2003_i2c_detach_client(struct i2c_client *client) -{ - int err; - struct tsc2003_data *d = i2c_get_clientdata(client); +static int tsc2003_i2c_detach_client(struct i2c_client *client) { + int err; + struct tsc2003_data *d = i2c_get_clientdata(client); - free_irq(d->penirq,d); - input_unregister_device(d->idev); + free_irq(d->penirq, d); + input_unregister_device(d->idev); - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, "Client deregistration failed, " - "client not detached.\n"); - return err; - } + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, "Client deregistration failed, " + "client not detached.\n"); + return err; + } - return 0; + return 0; } -static struct i2c_driver tsc2003_driver = { - .driver = { - .owner = THIS_MODULE, - .name = DRIVER_NAME, - }, - .attach_adapter = tsc2003_i2c_attach_adapter, - .detach_client = tsc2003_i2c_detach_client, - // .command = tsc2003_command, +static struct i2c_driver tsc2003_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + }, + .attach_adapter = tsc2003_i2c_attach_adapter, + .detach_client = tsc2003_i2c_detach_client, }; -static int tsc2003_i2c_detect (struct i2c_adapter *adapter, int address, -int kind) -{ - struct i2c_client *new_client; - struct tsc2003_data *data; - - int err = 0; - const char *name = ""; - - if (!i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_BYTE_DATA - | I2C_FUNC_I2C - | I2C_FUNC_SMBUS_WORD_DATA)) - goto exit; - - data = kcalloc(1, sizeof(*data), GFP_KERNEL); - if (!data) { - err = -ENOMEM; - goto exit; - } - - new_client = &data->client; - i2c_set_clientdata(new_client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &tsc2003_driver; - new_client->flags = 0; - - /* TODO: I'm pretty sure I'm not dealing with kind correctly */ - if (kind == 0 /* identification */ || kind < 0 /* detection */) - kind = tsc2003; - - if (kind == tsc2003) - name = DRIVER_NAME; - - /* try a command, see if we get an ack; - if we do, assume it's our device */ - printk(KERN_INFO "%s: probing address 0x%x\n", - __FUNCTION__, address); - err = tsc2003_powerdown(data); - if (err >= 0) - { - strlcpy(new_client->name, name, I2C_NAME_SIZE); - err = i2c_attach_client(new_client); - if (err) goto exit_free; - - tsc2003_init_client(new_client); - - err = tsc2003_driver_register(data); - if (err < 0) goto exit_free; - - printk(KERN_INFO "%s: device address 0x%x attached.\n", - __FUNCTION__, address); - return 0; - } - /* failure to detect when everything else is ok isn't an error */ - else err = 0; - - exit_free: - kfree(new_client); - exit: - return err; +static int tsc2003_i2c_detect(struct i2c_adapter *adapter, int address, int kind) { + struct i2c_client *new_client; + struct tsc2003_data *data; + + int err = 0; + const char *name = ""; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA + | I2C_FUNC_I2C | I2C_FUNC_SMBUS_WORD_DATA)) + goto exit; + + data = kcalloc(1, sizeof(*data), GFP_KERNEL); + if (!data) { + err = -ENOMEM; + goto exit; + } + + new_client = &data->client; + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &tsc2003_driver; + new_client->flags = 0; + + /* TODO: I'm pretty sure I'm not dealing with kind correctly */ + if (kind == 0 /* identification */|| kind < 0 /* detection */) + kind = tsc2003; + + if (kind == tsc2003) + name = DRIVER_NAME; + + /* try a command, see if we get an ack; + if we do, assume it's our device */ + printk(KERN_INFO "%s: probing address 0x%x\n", + __FUNCTION__, address); + err = tsc2003_powerdown(data); + if (err >= 0) { + strlcpy(new_client->name, name, I2C_NAME_SIZE); + err = i2c_attach_client(new_client); + if (err) + goto exit_free; + + tsc2003_init_client(new_client); + + err = tsc2003_driver_register(data); + if (err < 0) + goto exit_free; + + printk(KERN_INFO "%s: device address 0x%x attached.\n", + __FUNCTION__, address); + return 0; + } + /* failure to detect when everything else is ok isn't an error */ + else + err = 0; + + exit_free: kfree(new_client); + exit: return err; } static int __init tsc2003_init(void) { - return i2c_add_driver(&tsc2003_driver); + return i2c_add_driver(&tsc2003_driver); } static void __exit tsc2003_exit(void) { - i2c_del_driver(&tsc2003_driver); + i2c_del_driver(&tsc2003_driver); } MODULE_AUTHOR("Bill Gatliff <bgat at billgatliff.com>"); @@ -696,4 +470,3 @@ MODULE_LICENSE("GPL"); module_init(tsc2003_init); module_exit(tsc2003_exit); - |