2 * Synaptics NavPoint(tm) support in the hx470x.
4 * Copyright (c) 2005 SDG Systems, LLC
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive for
10 * 10-Feb-2005 Todd Blumer <todd@sdgsystems.com>
13 #include <linux/module.h>
14 #include <linux/version.h>
15 #include <linux/errno.h>
16 #include <linux/kthread.h>
17 #include <linux/wait.h>
18 #include <linux/platform_device.h>
20 #include <linux/init.h>
21 #include <linux/interrupt.h>
22 #include <linux/navpoint.h>
23 #include <linux/input.h>
25 #include <asm/hardware.h>
27 #include <asm/mach/irq.h>
28 #include <asm/arch/pxa-regs.h>
29 #include <asm/arch/hx4700-gpio.h>
30 #include <asm/arch/ssp.h>
33 * The iPAQ hx4700 uses several subsystems for input: PXA GPIOs for 2 keys,
34 * ASIC3 GPIOs for 3 other keys, NavPoint(tm) for input. We'll have each of
35 * these tie into the kernel input system. That seems to be the most straight-
36 * forward thing to do.
38 * Components that make up this driver: PXA SSP1 (SPI), input subsystem.
41 #define HX4700_NAVPT_SSP_PORT 1
42 #define HX4700_NAVPT_SSP_TIMEOUT 0x17777 /* from WinCE */
49 static struct ssp_dev ssp_dev
;
50 static struct navpoint_dev navpt_dev
;
51 static struct completion thread_comp
;
52 static volatile int must_die
;
54 static struct hx4700_navpoint
{
55 struct task_struct
*kthread
;
56 wait_queue_head_t kthread_wait
;
57 volatile unsigned int read_ndx
;
58 volatile unsigned int write_ndx
;
59 u_int8_t dataq
[SSP_QSIZE
];
62 #define SSP_QMASK (SSP_QSIZE-1)
65 rx_qinsert( u_int8_t octet
)
67 unsigned int nextw
= (hx4700_np
.write_ndx
+1) & SSP_QMASK
;
68 if (nextw
== hx4700_np
.read_ndx
) {
69 printk( KERN_ERR
"hx4700 navpoint queue full\n" );
72 hx4700_np
.dataq
[nextw
] = octet
;
73 hx4700_np
.write_ndx
= nextw
;
78 rx_threshold_irq( void *priv
, int count
)
83 for (i
=0; i
<count
; i
++) {
84 if (ssp_read_word( &ssp_dev
, &word
))
87 * ssp mode is 16-bit words, extract and send to
90 rx_qinsert( (u_int8_t
)((word
>> 8) & 0xff) );
91 rx_qinsert( (u_int8_t
)word
);
93 wake_up_interruptible( &hx4700_np
.kthread_wait
);
97 hx4700_navptd( void *notused
)
99 printk( "hx4700_navptd: receive thread started.\n" );
100 daemonize( "hx4700_navptd" );
101 while (!kthread_should_stop()) {
105 interruptible_sleep_on(&hx4700_np
.kthread_wait
);
106 /*wait_event_interruptible( hx4700_np.kthread_wait,
107 kthread_should_stop()
108 || hx4700_np.read_ndx != hx4700_np.write_ndx );*/
114 while (hx4700_np
.read_ndx
!= hx4700_np
.write_ndx
) {
115 u_int8_t octet
= hx4700_np
.dataq
[hx4700_np
.read_ndx
++];
116 hx4700_np
.read_ndx
&= SSP_QMASK
;
117 navpoint_rx( &navpt_dev
, octet
, hx4700_np
.write_ndx
- hx4700_np
.read_ndx
);
120 complete_and_exit( &thread_comp
, 0 );
124 hx4700_navpt_write( u_int8_t
*data
, int count
)
130 * SPI bus is in 16-bit word mode. If odd, we must still
131 * shift in a zero byte to fill the word
134 for (i
=0; i
<count
-odd
; i
+=2) {
135 word
= (u_int32_t
)data
[i
] << 8 | data
[i
+1];
136 // printk( "ssp write: 0x%x\n", word );
137 (void) ssp_write_word( &ssp_dev
, word
);
140 word
= (u_int32_t
)data
[count
-1] << 8;
141 // printk( "ssp write odd: 0x%x\n", word );
142 (void) ssp_write_word( &ssp_dev
, word
);
147 static struct ssp_ops hx4700_ssp_ops
= {
148 .rx_thresh
= rx_threshold_irq
,
152 // module_param(qsize, uint, 1024);
155 hx4700_ssp_init( void )
157 ssp_dev
.ops
= &hx4700_ssp_ops
;
158 ssp_init( &ssp_dev
, HX4700_NAVPT_SSP_PORT
, 0 );
159 ssp_config( &ssp_dev
, SSCR0_Motorola
| SSCR0_DataSize(16),
160 SSCR1_SCFR
| SSCR1_SCLKDIR
| SSCR1_SFRMDIR
161 | SSCR1_RWOT
| SSCR1_TINTE
| SSCR1_PINTE
162 | SSCR1_SPH
| SSCR1_RIE
163 | SSCR1_TxTresh(1) | SSCR1_RxTresh(1),
164 0, SSCR0_SerClkDiv(2) );
165 SSTO_P(HX4700_NAVPT_SSP_PORT
) = HX4700_NAVPT_SSP_TIMEOUT
;
169 hx4700_navpt_probe( struct platform_device
*pdev
)
171 pxa_gpio_mode( GPIO_NR_HX4700_SYNAPTICS_SPI_CLK_MD
);
172 pxa_gpio_mode( GPIO_NR_HX4700_SYNAPTICS_SPI_CS_N_MD
);
173 pxa_gpio_mode( GPIO_NR_HX4700_SYNAPTICS_SPI_DO_MD
);
174 pxa_gpio_mode( GPIO_NR_HX4700_SYNAPTICS_SPI_DI_MD
);
176 init_waitqueue_head( &hx4700_np
.kthread_wait
);
179 SET_HX4700_GPIO( SYNAPTICS_POWER_ON
, 1 );
181 * start receiver thread for navpoint data
184 init_completion( &thread_comp
);
185 hx4700_np
.kthread
= kthread_run( &hx4700_navptd
, NULL
, "hx4700_navpt" );
186 if (IS_ERR(hx4700_np
.kthread
)) {
187 printk( KERN_ERR
"iPAQ hx470x NavPoint start failure.\n" );
191 navpt_dev
.tx_func
= hx4700_navpt_write
;
192 navpoint_init( &navpt_dev
);
193 ssp_enable( &ssp_dev
);
194 // navpoint_reset( &navpt_dev );
200 hx4700_navpt_suspend( struct platform_device
*pdev
, pm_message_t state
)
202 SET_HX4700_GPIO( SYNAPTICS_POWER_ON
, 0 );
203 ssp_exit( &ssp_dev
);
208 hx4700_navpt_resume( struct platform_device
*pdev
)
211 SET_HX4700_GPIO( SYNAPTICS_POWER_ON
, 1 );
212 ssp_enable( &ssp_dev
);
213 navpoint_reset( &navpt_dev
);
217 #define hx4700_navpt_resume NULL
218 #define hx4700_navpt_suspend NULL
222 hx4700_navpt_remove( struct platform_device
*pdev
)
224 navpoint_exit( &navpt_dev
);
225 ssp_disable( &ssp_dev
);
226 SET_HX4700_GPIO( SYNAPTICS_POWER_ON
, 0 );
228 wake_up_interruptible( &hx4700_np
.kthread_wait
);
229 wait_for_completion( &thread_comp
);
230 ssp_exit( &ssp_dev
);
234 static struct platform_driver hx4700_navpt_driver
= {
236 .name
= "hx4700-navpoint",
238 .probe
= hx4700_navpt_probe
,
239 .suspend
= hx4700_navpt_suspend
,
240 .resume
= hx4700_navpt_resume
,
241 .remove
= hx4700_navpt_remove
,
246 hx4700_navpt_init( void )
248 printk( "hx4700 NavPoint Driver\n" );
249 return platform_driver_register( &hx4700_navpt_driver
);
254 hx4700_navpt_exit( void )
256 platform_driver_unregister( &hx4700_navpt_driver
);
260 module_init( hx4700_navpt_init
);
261 module_exit( hx4700_navpt_exit
);
263 MODULE_AUTHOR( "Todd Blumer <todd@sdgsystems.com>" );
264 MODULE_DESCRIPTION( "PXA27x NavPoint(tm) driver for iPAQ hx470x" );
265 MODULE_LICENSE( "GPL" );
267 /* vim600: set noexpandtab sw=8 ts=8 :*/