hh.org updates
[hh.org.git] / arch / arm / mach-pxa / hx4700 / hx4700_navpt.c
blob84779f0b800c835d9d8e84669006418c01d26675
1 /*
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
8 * more details.
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>
26 #include <asm/irq.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 */
45 * must be power of 2
47 #define SSP_QSIZE 512
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];
60 } hx4700_np;
62 #define SSP_QMASK (SSP_QSIZE-1)
64 static void
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" );
71 else {
72 hx4700_np.dataq[nextw] = octet;
73 hx4700_np.write_ndx = nextw;
77 static void
78 rx_threshold_irq( void *priv, int count )
80 int i;
81 u32 word;
83 for (i=0; i<count; i++) {
84 if (ssp_read_word( &ssp_dev, &word ))
85 return;
87 * ssp mode is 16-bit words, extract and send to
88 * navpoint driver
90 rx_qinsert( (u_int8_t)((word >> 8) & 0xff) );
91 rx_qinsert( (u_int8_t)word );
93 wake_up_interruptible( &hx4700_np.kthread_wait );
96 int
97 hx4700_navptd( void *notused )
99 printk( "hx4700_navptd: receive thread started.\n" );
100 daemonize( "hx4700_navptd" );
101 while (!kthread_should_stop()) {
102 if (must_die)
103 break;
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 );*/
110 try_to_freeze();
112 if (must_die)
113 break;
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 );
123 static int
124 hx4700_navpt_write( u_int8_t *data, int count )
126 int odd, i;
127 u_int32_t word;
130 * SPI bus is in 16-bit word mode. If odd, we must still
131 * shift in a zero byte to fill the word
133 odd = count & 1;
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 );
139 if (odd) {
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 );
144 return 0;
147 static struct ssp_ops hx4700_ssp_ops = {
148 .rx_thresh = rx_threshold_irq,
149 .priv = &ssp_dev,
152 // module_param(qsize, uint, 1024);
154 static void
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;
168 static int
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 );
178 hx4700_ssp_init();
179 SET_HX4700_GPIO( SYNAPTICS_POWER_ON, 1 );
181 * start receiver thread for navpoint data
183 must_die = 0;
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" );
188 return -EIO;
190 navpt_dev.unit = 0;
191 navpt_dev.tx_func = hx4700_navpt_write;
192 navpoint_init( &navpt_dev );
193 ssp_enable( &ssp_dev );
194 // navpoint_reset( &navpt_dev );
195 return 0;
198 #ifdef CONFIG_PM
199 static int
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 );
204 return 0;
207 static int
208 hx4700_navpt_resume( struct platform_device *pdev )
210 hx4700_ssp_init();
211 SET_HX4700_GPIO( SYNAPTICS_POWER_ON, 1 );
212 ssp_enable( &ssp_dev );
213 navpoint_reset( &navpt_dev );
214 return 0;
216 #else
217 #define hx4700_navpt_resume NULL
218 #define hx4700_navpt_suspend NULL
219 #endif
221 static int
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 );
227 must_die = 1;
228 wake_up_interruptible( &hx4700_np.kthread_wait );
229 wait_for_completion( &thread_comp );
230 ssp_exit( &ssp_dev );
231 return 0;
234 static struct platform_driver hx4700_navpt_driver = {
235 .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,
245 static int __init
246 hx4700_navpt_init( void )
248 printk( "hx4700 NavPoint Driver\n" );
249 return platform_driver_register( &hx4700_navpt_driver );
253 static void __exit
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 :*/