hh.org updates
[hh.org.git] / arch / arm / mach-pxa / hx4700 / hx4700_ts.c
blobb175749a307842f72b76f70c37d41f56c555329e
1 /* Touch screen driver for the TI something-or-other
3 * Copyright © 2005 SDG Systems, LLC
5 * Based on code that was based on the SAMCOP driver.
6 * Copyright © 2003, 2004 Compaq Computer Corporation.
8 * Use consistent with the GNU GPL is permitted,
9 * provided that this copyright notice is
10 * preserved in its entirety in all copies and derived works.
12 * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
13 * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
14 * FITNESS FOR ANY PARTICULAR PURPOSE.
16 * Author: Keith Packard <keith.packard@hp.com>
17 * May 2003
19 * Updates:
21 * 2004-02-11 Michael Opdenacker Renamed names from samcop to shamcop,
22 * Goal:support HAMCOP and SAMCOP.
23 * 2004-02-14 Michael Opdenacker Temporary fix for device id handling
25 * 2005-02-18 Aric Blumer Converted basic structure to support hx4700
27 * 2005-06-07 Aric Blumer Added tssim device handling so we can
28 * hook in the fbvncserver.
31 #include <linux/module.h>
32 #include <linux/version.h>
34 #include <linux/init.h>
35 #include <linux/fs.h>
36 #include <linux/cdev.h>
37 #include <linux/interrupt.h>
38 #include <linux/sched.h>
39 #include <linux/pm.h>
40 #include <linux/delay.h>
41 #include <linux/input.h>
42 #include <linux/input_pda.h>
43 #include <linux/platform_device.h>
44 #include <linux/battery.h>
46 #include <asm/arch/hardware.h>
47 #include <asm/irq.h>
48 #include <asm/mach/irq.h>
49 #include <asm/io.h>
50 #include <asm/semaphore.h>
52 #include <asm/arch/pxa-regs.h>
53 #include <asm/arch/hx4700-gpio.h>
54 #include <asm/arch/hx4700-asic.h>
56 #include <asm/hardware/ipaq-asic3.h>
57 #include <linux/soc/asic3_base.h>
59 extern struct platform_device hx4700_asic3;
61 enum touchscreen_state {
62 STATE_WAIT_FOR_TOUCH, /* Waiting for a PEN interrupt */
63 STATE_SAMPLING /* Actively sampling ADC */
66 struct touchscreen_data {
67 enum touchscreen_state state;
68 struct timer_list timer;
69 int irq;
70 struct input_dev *input;
73 struct key_data {
74 int gpiod_val;
75 int gpiod_bit;
76 int rising;
77 int key;
78 int irq;
79 } asic3_key[3];
81 static unsigned long poll_sample_time = 10; /* Sample every 10 milliseconds */
83 static struct touchscreen_data *ts_data;
85 #define TS_SAMPLES 5
87 module_param(poll_sample_time, ulong, 0644);
88 MODULE_PARM_DESC(poll_sample_time, "Poll sample time");
90 static inline void
91 report_touchpanel(struct touchscreen_data *ts, int pressure, int x, int y)
93 input_report_abs(ts->input, ABS_PRESSURE, pressure);
94 input_report_abs(ts->input, ABS_X, x);
95 input_report_abs(ts->input, ABS_Y, y);
96 input_sync(ts->input);
99 static struct work_struct serial_work;
101 static irqreturn_t
102 pen_isr(int irq, void *irq_desc)
104 /* struct touchscreen_data *ts = dev_id->data; */
105 struct touchscreen_data *ts = ts_data;
108 if(irq == HX4700_IRQ(TOUCHPANEL_IRQ_N)) {
110 if (ts->state == STATE_WAIT_FOR_TOUCH) {
112 * There is ground bounce or noise or something going on here:
113 * when you write to the SSP port to get the X and Y values, it
114 * causes a TOUCHPANEL_IRQ_N interrupt to occur. So if that
115 * happens, we can check to make sure the pen is actually down and
116 * disregard the interrupt if it's not.
118 if(GET_HX4700_GPIO(TOUCHPANEL_IRQ_N) == 0) {
120 * Disable the pen interrupt. It's reenabled when the user lifts the
121 * pen.
123 disable_irq(HX4700_IRQ(TOUCHPANEL_IRQ_N));
125 ts->state = STATE_SAMPLING;
126 schedule_work(&serial_work);
128 } else {
129 /* Shouldn't happen */
130 printk(KERN_ERR "Unexpected ts interrupt\n");
134 return IRQ_HANDLED;
137 static int
138 key_isr(int irq, void *dev_id)
140 struct key_data *key = dev_id;
141 int statusd;
144 * alternate between rising and falling, based on pin status
146 statusd = asic3_get_gpio_status_d( &hx4700_asic3.dev );
147 key->rising = (statusd & key->gpiod_bit) == 0;
148 set_irq_type( irq, key->rising ? IRQT_RISING : IRQT_FALLING );
149 input_report_key( ts_data->input, key->key, key->rising );
150 input_sync( ts_data->input );
151 return IRQ_HANDLED;
154 static void
155 ssp_init(void)
158 pxa_set_cken(CKEN3_SSP2, 1);
160 /* *** Set up the SPI Registers *** */
161 SSCR0_P2 =
162 (1 << 20) /* Extended Data Size Select */
163 | (6 << 8) /* Serial Clock Rate */
164 | (0 << 7) /* Synchronous Serial Enable (Disable for now) */
165 | (0 << 4) /* Motorola SPI Interface */
166 | (7 << 0) /* Data Size Select (24-bit) */
168 SSCR1_P2 = 0;
169 SSPSP_P2 = 0;
171 /* Clear the Status */
172 SSSR_P2 = SSSR_P2 & 0x00fcfffc;
174 /* Now enable it */
175 SSCR0_P2 =
176 (1 << 20) /* Extended Data Size Select */
177 | (6 << 8) /* Serial Clock Rate */
178 | (1 << 7) /* Synchronous Serial Enable */
179 | (0 << 4) /* Motorola SPI Interface */
180 | (7 << 0) /* Data Size Select (24-bit) */
182 /* enable_irq(HX4700_IRQ(TOUCHPANEL_IRQ_N)); */
185 DECLARE_MUTEX(serial_mutex);
187 static void
188 start_read(void *in)
190 struct touchscreen_data *touch = in;
191 unsigned long inc = (poll_sample_time * HZ) / 1000;
192 int i;
194 down(&serial_mutex);
196 /* Write here to the serial port.
197 * Then we have to wait for poll_sample_time before we read out the serial
198 * port. Then, when we read it out, we check to see if the pen is still
199 * down. If so, then we issue another request here.
202 for(i = 0; i < TS_SAMPLES; i++) {
203 while(!(SSSR_P2 & (1 << 2)))
205 /* It's not full. Write the command for X */
206 SSDR_P2 = 0xd00000;
207 while(!(SSSR_P2 & (1 << 2)))
209 /* It's not full. Write the command for Y */
210 SSDR_P2 = 0x900000;
214 * Enable the timer. We should get an interrupt, but we want keep a timer
215 * to ensure that we can detect missing data
217 mod_timer(&touch->timer, jiffies + inc);
220 static int
221 do_delta_calc(int x1, int y1, int x2, int y2, int x3, int y3)
223 /* This is based on Jamey Hicks' description on IRC. */
224 int dx2_a, dy2_a, dx2_b, dy2_b;
226 dx2_a = x2 - x1;
227 dx2_a = dx2_a * dx2_a; /* If dx2_a was negative, it's not now */
228 dy2_a = y2 - y1;
229 dy2_a = dy2_a * dy2_a; /* If dy2_a was negative, it's not now */
231 dx2_b = x3 - x2;
232 dx2_b = dx2_b * dx2_b; /* If dx2_b was negative, it's not now */
233 dy2_b = y3 - y2;
234 dy2_b = dy2_b * dy2_b; /* If dy2_b was negative, it's not now */
236 #if 0
237 /* This was described in the algorithm by Jamey, but it doesn't do much
238 * good.
240 if(dx2_a + dy2_a < dx2_b + dy2_b) return 0;
241 #endif
243 /* dx2_a + dy2_a is the distance squared */
245 ((dx2_a + dy2_a) > 8000)
246 || ((dx2_b + dy2_b) > 8000)
248 return 0;
249 } else {
250 return 1;
253 if((dx2_b + dy2_b) > 5000) {
254 return 0;
255 } else {
256 return 1;
260 static void
261 ts_timer_callback(unsigned long data)
263 struct touchscreen_data *ts = (struct touchscreen_data *)data;
264 int x, y;
265 int ssrval;
268 * Check here to see if there is anything in the SPI FIFO. If so,
269 * return it if there has been a change. If not, then we have a
270 * timeout. Generate an erro somehow.
272 ssrval = SSSR_P2;
273 if(ssrval & (1 << 3)) { /* Look at Rx Not Empty bit */
274 int number_of_entries_in_fifo;
276 /* The FIFO is not emtpy. Good! Now make sure there are at least two
277 * entries. */
279 number_of_entries_in_fifo = ((ssrval >> 12) & 0xf) + 1;
281 if(number_of_entries_in_fifo < (TS_SAMPLES * 2)) {
282 /* Not ready yet. Come back later. */
283 unsigned long inc = (poll_sample_time * HZ) / 1000;
284 mod_timer(&ts->timer, jiffies + inc);
285 return;
288 if(number_of_entries_in_fifo == TS_SAMPLES * 2) {
289 int i, result, keep;
290 int X[TS_SAMPLES], Y[TS_SAMPLES];
292 for(i = 0; i < TS_SAMPLES; i++) {
293 X[i] = SSDR_P2;
294 Y[i] = SSDR_P2;
297 up(&serial_mutex);
299 keep = 0;
300 x = y = 0;
302 result = 0;
303 if(do_delta_calc(X[0], Y[0], X[1], Y[1], X[2], Y[2])) {
304 result |= (1 << 2);
306 if(do_delta_calc(X[1], Y[1], X[2], Y[2], X[3], Y[3])) {
307 result |= (1 << 1);
309 if(do_delta_calc(X[2], Y[2], X[3], Y[3], X[4], Y[4])) {
310 result |= (1 << 0);
312 switch(result) {
313 case 0:
314 /* Take average of point 0 and point 3 */
315 X[2] = (X[1] + X[3]) / 2;
316 Y[2] = (Y[1] + Y[3]) / 2;
317 /* don't keep */
318 break;
319 case 1:
320 /* Just ignore this one */
321 break;
322 case 2:
323 case 3:
324 case 6:
325 /* keep this sample */
326 x = (X[1] + (2 * X[2]) + X[3]) / 4;
327 y = (Y[1] + (2 * Y[2]) + Y[3]) / 4;
328 keep = 1;
329 break;
330 case 4:
331 X[1] = (X[0] + X[2]) / 2;
332 Y[1] = (Y[0] + Y[2]) / 2;
333 /* don't keep */
334 break;
335 case 5:
336 case 7:
337 x = (X[0] + (4 * X[1]) + (6 * X[2]) + (4 * X[3]) + X[4]) >> 4;
338 y = (Y[0] + (4 * Y[1]) + (6 * Y[2]) + (4 * Y[3]) + Y[4]) >> 4;
339 keep = 1;
340 break;
343 if(GET_HX4700_GPIO(TOUCHPANEL_IRQ_N) == 0) {
344 /* Still down */
345 if(keep) {
346 report_touchpanel(ts, 1, x, y);
348 start_read(ts);
349 } else {
350 /* Up */
351 report_touchpanel(ts, 0, 0, 0);
352 ts->state = STATE_WAIT_FOR_TOUCH;
353 /* Re-enable pen down interrupt */
354 enable_irq(HX4700_IRQ(TOUCHPANEL_IRQ_N));
357 } else {
358 /* We have an error! Too many entries. */
359 printk(KERN_ERR "TS: Expected %d entries. Got %d\n", 2, number_of_entries_in_fifo);
360 /* Try to clear the FIFO */
361 while(number_of_entries_in_fifo--) {
362 (void)SSDR_P2;
364 up(&serial_mutex);
365 if(GET_HX4700_GPIO(TOUCHPANEL_IRQ_N) == 0) {
366 start_read(ts);
368 return;
370 } else {
371 /* Not ready yet. Come back later. */
372 unsigned long inc = (poll_sample_time * HZ) / 1000;
373 mod_timer(&ts->timer, jiffies + inc);
374 return;
378 static int
379 ts_probe (struct platform_device *pdev)
381 int retval;
382 struct touchscreen_data *ts;
383 unsigned int irq;
384 int err;
386 ts = ts_data = kmalloc (sizeof (*ts), GFP_KERNEL);
387 if (ts == NULL) {
388 printk( KERN_NOTICE "hx4700_ts: unable to allocate memory\n" );
389 return -ENOMEM;
391 memset (ts, 0, sizeof (*ts));
394 /* *** Set up the input subsystem stuff *** */
395 // memset(ts->input, 0, sizeof(struct input_dev));
396 ts->input = input_allocate_device();
397 if (ts->input == NULL) {
398 printk( KERN_NOTICE "hx4700_ts: unable to allocation touchscreen input\n" );
399 kfree(ts);
400 return -ENOMEM;
402 ts->input->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
403 ts->input->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
404 ts->input->absmin[ABS_X] = 0;
405 ts->input->absmax[ABS_X] = 32767;
406 ts->input->absmin[ABS_Y] = 0;
407 ts->input->absmax[ABS_Y] = 32767;
408 ts->input->absmin[ABS_PRESSURE] = 0;
409 ts->input->absmax[ABS_PRESSURE] = 1;
410 ts->input->keybit[LONG(_KEY_RECORD)] |= BIT(_KEY_RECORD); /* record */
411 ts->input->keybit[LONG(_KEY_CALENDAR)] |= BIT(_KEY_CALENDAR); /* calendar */
412 ts->input->keybit[LONG(_KEY_HOMEPAGE)] |= BIT(_KEY_HOMEPAGE);
414 ts->input->name = "hx4700_ts";
415 ts->input->private = ts;
417 input_register_device(ts->input);
419 ts->timer.function = ts_timer_callback;
420 ts->timer.data = (unsigned long)ts;
421 ts->state = STATE_WAIT_FOR_TOUCH;
422 init_timer (&ts->timer);
424 INIT_WORK(&serial_work, start_read, ts);
426 platform_set_drvdata(pdev, ts);
428 /* *** Initialize the SSP interface *** */
429 ssp_init();
431 down(&serial_mutex);
432 /* Make sure the device is in such a state that it can give pen
433 * interrupts. */
434 while(!(SSSR_P2 & (1 << 2)))
436 SSDR_P2 = 0xd00000;
438 for(retval = 0; retval < 100; retval++) {
439 if(SSSR_P2 & (1 << 3)) {
440 while(SSSR_P2 & (1 << 3)) {
441 (void)SSDR_P2;
443 break;
445 mdelay(1);
447 up(&serial_mutex);
450 ts->irq = HX4700_IRQ( TOUCHPANEL_IRQ_N );
451 retval = request_irq(ts->irq, pen_isr, SA_INTERRUPT, "hx4700_ts", ts);
452 if(retval) {
453 printk("Unable to get interrupt\n");
454 input_unregister_device (ts->input);
455 return -ENODEV;
457 set_irq_type(ts->irq, IRQT_FALLING);
459 /* *** Initialize the ASIC3 key interrupts *** */
460 /* Maybe shouldn't do this here, but take advantage of input
461 * device already configured */
462 asic3_key[0].gpiod_val = GPIOD_KEY_AP2_N;
463 asic3_key[0].gpiod_bit = (1<<GPIOD_KEY_AP2_N);
464 asic3_key[0].rising = 0;
465 asic3_key[0].key = _KEY_CALENDAR;
466 irq = asic3_irq_base( &hx4700_asic3.dev ) + ASIC3_GPIOD_IRQ_BASE
467 + GPIOD_KEY_AP2_N;
468 err = request_irq( irq, key_isr, SA_INTERRUPT, "HX4700 AP2 Key",
469 (void *)&asic3_key[0] );
470 if (err) {
471 printk(KERN_ERR "GPIOD_KEY_AP2_N: can't request IRQ\n");
472 } else {
473 set_irq_type( irq, IRQT_FALLING );
474 asic3_key[0].irq = irq;
477 asic3_key[1].gpiod_val = GPIOD_KEY_AP4_N;
478 asic3_key[1].gpiod_bit = (1<<GPIOD_KEY_AP4_N);
479 asic3_key[1].rising = 0;
480 asic3_key[1].key = _KEY_HOMEPAGE;
481 irq = asic3_irq_base( &hx4700_asic3.dev ) + ASIC3_GPIOD_IRQ_BASE
482 + GPIOD_KEY_AP4_N;
483 err = request_irq( irq, key_isr, SA_INTERRUPT, "HX4700 AP4 Key",
484 (void *)&asic3_key[1] );
485 if (err) {
486 printk(KERN_ERR "GPIOD_KEY_AP4_N: can't request IRQ\n");
487 } else {
488 set_irq_type( irq, IRQT_FALLING );
489 asic3_key[1].irq = irq;
492 asic3_key[2].gpiod_val = GPIOD_AUD_RECORD_N;
493 asic3_key[2].gpiod_bit = (1<<GPIOD_AUD_RECORD_N);
494 asic3_key[2].rising = 0;
495 asic3_key[2].key = _KEY_RECORD;
496 irq = asic3_irq_base( &hx4700_asic3.dev ) + ASIC3_GPIOD_IRQ_BASE
497 + GPIOD_AUD_RECORD_N;
498 err = request_irq( irq, key_isr, SA_INTERRUPT, "HX4700 Record",
499 (void *)&asic3_key[2] );
500 if (err) {
501 printk(KERN_ERR "GPIOD_AUD_RECORD_N: can't request IRQ\n");
502 } else {
503 set_irq_type( irq, IRQT_FALLING );
504 asic3_key[2].irq = irq;
507 return 0;
510 static int
511 ts_remove (struct platform_device *pdev)
513 int i;
514 struct touchscreen_data *ts = platform_get_drvdata(pdev);
516 input_unregister_device (ts->input);
517 del_timer_sync (&ts->timer);
518 free_irq (ts->irq, ts);
519 for (i=0; i<3; i++) {
520 if (asic3_key[i].irq != 0)
521 free_irq( asic3_key[i].irq, &asic3_key[i] );
524 kfree(ts);
525 pxa_set_cken(CKEN3_SSP2, 0);
526 return 0;
529 static int
530 ts_suspend (struct platform_device *pdev, pm_message_t state)
532 disable_irq(HX4700_IRQ(TOUCHPANEL_IRQ_N));
533 return 0;
536 static int
537 ts_resume (struct platform_device *pdev)
539 struct touchscreen_data *ts = platform_get_drvdata(pdev);
541 ts->state = STATE_WAIT_FOR_TOUCH;
542 ssp_init();
543 enable_irq(HX4700_IRQ(TOUCHPANEL_IRQ_N));
545 return 0;
548 static struct platform_driver ts_driver = {
549 .probe = ts_probe,
550 .remove = ts_remove,
551 .suspend = ts_suspend,
552 .resume = ts_resume,
553 .driver = {
554 .name = "hx4700-ts",
558 static int tssim_init(void);
560 static int
561 ts_module_init (void)
563 printk(KERN_NOTICE "hx4700 Touch Screen Driver\n");
564 if(tssim_init()) {
565 printk(KERN_NOTICE " TS Simulator Not Installed\n");
566 } else {
567 printk(KERN_NOTICE " TS Simulator Installed\n");
569 return platform_driver_register(&ts_driver);
572 static void tssim_exit(void);
574 static void
575 ts_module_cleanup (void)
577 tssim_exit();
578 platform_driver_unregister (&ts_driver);
581 /************* Code for Touch Screen Simulation for FBVNC Server **********/
582 static dev_t dev;
583 static struct cdev *cdev;
585 static long a0 = -1122, a2 = 33588528, a4 = 1452, a5 = -2970720, a6 = 65536;
587 /* The input into the input subsystem is prior to correction from calibration.
588 * So we have to undo the effects of the calibration. It's actually a
589 * complicated equation where the calibrated value of X depends on the
590 * uncalibrated values of X and Y. Fortunately, at least on the hx4700, the
591 * multiplier for the Y value is zero, so I assume that here. It is a shame
592 * that the tslib does not allow multiple inputs. Then we could do another
593 * driver for this (as it was originally) that give input that does not
594 * require calibration.
596 static int
597 tssim_ioctl(struct inode *inode, struct file *fp, unsigned int ioctlnum, unsigned long parm)
599 switch(ioctlnum) {
600 case 0: a0 = parm; break;
601 case 1: break;
602 case 2: a2 = parm; break;
603 case 3: break;
604 case 4: a4 = parm; break;
605 case 5: a5 = parm; break;
606 case 6:
607 a6 = parm;
608 printk(KERN_DEBUG "a0 = %ld, a2 = %ld, a4 = %ld, a5 = %ld, a6 = %ld\n",
609 a0, a2, a4, a5, a6);
610 break;
611 default: return -ENOTTY;
613 return 0;
616 static int
617 tssim_open(struct inode *inode, struct file *fp)
619 /* Nothing to do here */
620 return 0;
623 static ssize_t
624 tssim_write(struct file *fp, const char __user *data, size_t bytes, loff_t *offset)
626 unsigned long pressure;
627 long y;
628 long x;
630 x = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); data += 4;
631 y = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); data += 4;
632 pressure = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); data += 4;
634 input_report_abs(ts_data->input, ABS_PRESSURE, pressure?1:0);
635 input_report_abs(ts_data->input, ABS_X, ((x * a6) - a2)/a0);
636 input_report_abs(ts_data->input, ABS_Y, ((y * a6) - a5)/a4);
637 input_sync(ts_data->input);
639 return bytes;
642 int tssim_close(struct inode *inode, struct file *fp)
644 return 0;
647 struct file_operations fops = {
648 THIS_MODULE,
649 .write = tssim_write,
650 .open = tssim_open,
651 .release = tssim_close,
652 .ioctl = tssim_ioctl,
655 static int battery_class;
657 static int get_min_voltage(struct battery *b)
659 return 1000;
661 static int get_max_voltage(struct battery *b)
663 return 1400; /* mV */
665 static int get_max_charge(struct battery *b)
667 return 100;
669 static int get_voltage(struct battery *b)
671 static int battery_sample;
673 if(!down_interruptible(&serial_mutex)) {
674 int i;
675 int ssrval;
677 while(!(SSSR_P2 & (1 << 2)))
679 SSDR_P2 = 0xe70000;
680 while(!(SSSR_P2 & (1 << 2)))
682 SSDR_P2 = 0xe70000;
683 while(!(SSSR_P2 & (1 << 2)))
685 SSDR_P2 = 0xd00000; /* Dummy command to allow pen interrupts again */
687 for(i = 0; i < 10; i++) {
688 ssrval = SSSR_P2;
689 if(ssrval & (1 << 3)) { /* Look at Rx Not Empty bit */
690 int number_of_entries_in_fifo;
692 number_of_entries_in_fifo = ((ssrval >> 12) & 0xf) + 1;
693 if(number_of_entries_in_fifo == 3) {
694 break;
697 msleep(1);
700 if(i < 1000) {
701 (void) SSDR_P2;
702 battery_sample = SSDR_P2 & 0xfff;
703 (void) SSDR_P2;
704 } else {
705 /* Make sure the FIFO is empty */
706 while(SSSR_P2 & (1 << 3)) {
707 (void) SSDR_P2;
709 battery_sample = -1;
711 up(&serial_mutex);
714 return battery_sample;
716 static int get_charge(struct battery *b)
718 return 100;
720 static int get_status(struct battery *b)
722 return 1;
725 static struct battery hx4700_power = {
726 .name = "hx4700_backup",
727 .id = "backup",
728 .get_min_voltage = get_min_voltage,
729 .get_min_current = 0,
730 .get_min_charge = 0,
731 .get_max_voltage = get_max_voltage,
732 .get_max_current = 0,
733 .get_max_charge = get_max_charge,
734 .get_temp = 0,
735 .get_voltage = get_voltage,
736 .get_current = 0,
737 .get_charge = get_charge,
738 .get_status = get_status,
741 static int
742 battery_class_uevent(struct class_device *dev, char **envp, int num_envp,
743 char *buffer, int buffer_size)
745 return 0;
748 static void
749 battery_class_release(struct class_device *dev)
753 static void
754 battery_class_class_release(struct class *class)
758 static int
759 tssim_init(void)
761 int retval;
763 retval = alloc_chrdev_region(&dev, 0, 1, "tssim");
764 if(retval) {
765 printk(KERN_ERR "TSSIM Unable to allocate device numbers\n");
766 return retval;
769 cdev = cdev_alloc();
770 cdev->owner = THIS_MODULE;
771 cdev->ops = &fops;
772 retval = cdev_add(cdev, dev, 1);
773 if(retval) {
774 printk(KERN_ERR "Unable to add cdev\n");
775 unregister_chrdev_region(dev, 1);
776 return retval;
779 battery_class = 0;
780 if(battery_class_register(&hx4700_power)) {
781 printk(KERN_ERR "hx4700_ts: Could not register battery class\n");
782 } else {
783 battery_class = 1;
784 hx4700_power.class_dev.class->uevent = battery_class_uevent;
785 hx4700_power.class_dev.class->release = battery_class_release;
786 hx4700_power.class_dev.class->class_release = battery_class_class_release;
789 return 0;
792 static void
793 tssim_exit(void)
795 cdev_del(cdev);
796 unregister_chrdev_region(dev, 1);
797 if(battery_class) {
798 battery_class_unregister(&hx4700_power);
800 return;
803 module_init(ts_module_init);
804 module_exit(ts_module_cleanup);
806 MODULE_LICENSE("GPL");
807 MODULE_AUTHOR("Aric Blumer, SDG Systems, LLC");
808 MODULE_DESCRIPTION("hx4700 Touch Screen Driver");