Blame view

arch/arm/mach-sa1100/jornada720_ssp.c 4.39 KB
69ebb2227   Kristoffer Ericson   [ARM] 4506/1: HP ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  /**
   *  arch/arm/mac-sa1100/jornada720_ssp.c
   *
   *  Copyright (C) 2006/2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
   *   Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl>
   *
   * 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
   * published by the Free Software Foundation.
   *
   *  SSP driver for the HP Jornada 710/720/728
   */
  
  #include <linux/delay.h>
  #include <linux/errno.h>
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/platform_device.h>
  #include <linux/sched.h>
69ebb2227   Kristoffer Ericson   [ARM] 4506/1: HP ...
21

a09e64fbc   Russell King   [ARM] Move includ...
22
  #include <mach/hardware.h>
a09e64fbc   Russell King   [ARM] Move includ...
23
  #include <mach/jornada720.h>
58005b325   Kristoffer Ericson   [ARM] 5255/1: Upd...
24
  #include <asm/hardware/ssp.h>
69ebb2227   Kristoffer Ericson   [ARM] 4506/1: HP ...
25
26
27
28
29
30
31
  
  static DEFINE_SPINLOCK(jornada_ssp_lock);
  static unsigned long jornada_ssp_flags;
  
  /**
   * jornada_ssp_reverse - reverses input byte
   *
25985edce   Lucas De Marchi   Fix common misspe...
32
   * we need to reverse all data we receive from the mcu due to its physical location
69ebb2227   Kristoffer Ericson   [ARM] 4506/1: HP ...
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
   * returns : 01110111 -> 11101110
   */
  u8 inline jornada_ssp_reverse(u8 byte)
  {
  	return
  		((0x80 & byte) >> 7) |
  		((0x40 & byte) >> 5) |
  		((0x20 & byte) >> 3) |
  		((0x10 & byte) >> 1) |
  		((0x08 & byte) << 1) |
  		((0x04 & byte) << 3) |
  		((0x02 & byte) << 5) |
  		((0x01 & byte) << 7);
  };
  EXPORT_SYMBOL(jornada_ssp_reverse);
  
  /**
   * jornada_ssp_byte - waits for ready ssp bus and sends byte
   *
   * waits for fifo buffer to clear and then transmits, if it doesn't then we will
   * timeout after <timeout> rounds. Needs mcu running before its called.
   *
   * returns : %mcu output on success
3ac49a1c9   Jean Delvare   trivial: fix ETIM...
56
   *	   : %-ETIMEDOUT on timeout
69ebb2227   Kristoffer Ericson   [ARM] 4506/1: HP ...
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
   */
  int jornada_ssp_byte(u8 byte)
  {
  	int timeout = 400000;
  	u16 ret;
  
  	while ((GPLR & GPIO_GPIO10)) {
  		if (!--timeout) {
  			printk(KERN_WARNING "SSP: timeout while waiting for transmit
  ");
  			return -ETIMEDOUT;
  		}
  		cpu_relax();
  	}
  
  	ret = jornada_ssp_reverse(byte) << 8;
  
  	ssp_write_word(ret);
  	ssp_read_word(&ret);
  
  	return jornada_ssp_reverse(ret);
  };
  EXPORT_SYMBOL(jornada_ssp_byte);
  
  /**
   * jornada_ssp_inout - decide if input is command or trading byte
   *
   * returns : (jornada_ssp_byte(byte)) on success
3ac49a1c9   Jean Delvare   trivial: fix ETIM...
85
   *         : %-ETIMEDOUT on timeout failure
69ebb2227   Kristoffer Ericson   [ARM] 4506/1: HP ...
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
   */
  int jornada_ssp_inout(u8 byte)
  {
  	int ret, i;
  
  	/* true means command byte */
  	if (byte != TXDUMMY) {
  		ret = jornada_ssp_byte(byte);
  		/* Proper return to commands is TxDummy */
  		if (ret != TXDUMMY) {
  			for (i = 0; i < 256; i++)/* flushing bus */
  				if (jornada_ssp_byte(TXDUMMY) == -1)
  					break;
  			return -ETIMEDOUT;
  		}
  	} else /* Exchange TxDummy for data */
  		ret = jornada_ssp_byte(TXDUMMY);
  
  	return ret;
  };
  EXPORT_SYMBOL(jornada_ssp_inout);
  
  /**
   * jornada_ssp_start - enable mcu
   *
   */
58005b325   Kristoffer Ericson   [ARM] 5255/1: Upd...
112
  void jornada_ssp_start(void)
69ebb2227   Kristoffer Ericson   [ARM] 4506/1: HP ...
113
114
115
116
  {
  	spin_lock_irqsave(&jornada_ssp_lock, jornada_ssp_flags);
  	GPCR = GPIO_GPIO25;
  	udelay(50);
58005b325   Kristoffer Ericson   [ARM] 5255/1: Upd...
117
  	return;
69ebb2227   Kristoffer Ericson   [ARM] 4506/1: HP ...
118
119
120
121
122
123
124
  };
  EXPORT_SYMBOL(jornada_ssp_start);
  
  /**
   * jornada_ssp_end - disable mcu and turn off lock
   *
   */
58005b325   Kristoffer Ericson   [ARM] 5255/1: Upd...
125
  void jornada_ssp_end(void)
69ebb2227   Kristoffer Ericson   [ARM] 4506/1: HP ...
126
127
128
  {
  	GPSR = GPIO_GPIO25;
  	spin_unlock_irqrestore(&jornada_ssp_lock, jornada_ssp_flags);
58005b325   Kristoffer Ericson   [ARM] 5255/1: Upd...
129
  	return;
69ebb2227   Kristoffer Ericson   [ARM] 4506/1: HP ...
130
131
  };
  EXPORT_SYMBOL(jornada_ssp_end);
91a99dfc6   Uwe Kleine-König   platform-drivers:...
132
  static int __devinit jornada_ssp_probe(struct platform_device *dev)
69ebb2227   Kristoffer Ericson   [ARM] 4506/1: HP ...
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
  {
  	int ret;
  
  	GPSR = GPIO_GPIO25;
  
  	ret = ssp_init();
  
  	/* worked fine, lets not bother with anything else */
  	if (!ret) {
  		printk(KERN_INFO "SSP: device initialized with irq
  ");
  		return ret;
  	}
  
  	printk(KERN_WARNING "SSP: initialization failed, trying non-irq solution 
  ");
  
  	/* init of Serial 4 port */
  	Ser4MCCR0 = 0;
  	Ser4SSCR0 = 0x0387;
  	Ser4SSCR1 = 0x18;
  
  	/* clear out any left over data */
  	ssp_flush();
  
  	/* enable MCU */
  	jornada_ssp_start();
  
  	/* see if return value makes sense */
  	ret = jornada_ssp_inout(GETBRIGHTNESS);
  
  	/* seems like it worked, just feed it with TxDummy to get rid of data */
219e3dcd1   Kristoffer Ericson   [ARM] 4528/1: [HP...
165
  	if (ret == TXDUMMY)
69ebb2227   Kristoffer Ericson   [ARM] 4506/1: HP ...
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
  		jornada_ssp_inout(TXDUMMY);
  
  	jornada_ssp_end();
  
  	/* failed, lets just kill everything */
  	if (ret == -ETIMEDOUT) {
  		printk(KERN_WARNING "SSP: attempts failed, bailing
  ");
  		ssp_exit();
  		return -ENODEV;
  	}
  
  	/* all fine */
  	printk(KERN_INFO "SSP: device initialized
  ");
  	return 0;
  };
  
  static int jornada_ssp_remove(struct platform_device *dev)
  {
25985edce   Lucas De Marchi   Fix common misspe...
186
  	/* Note that this doesn't actually remove the driver, since theres nothing to remove
69ebb2227   Kristoffer Ericson   [ARM] 4506/1: HP ...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
  	 * It just makes sure everything is turned off */
  	GPSR = GPIO_GPIO25;
  	ssp_exit();
  	return 0;
  };
  
  struct platform_driver jornadassp_driver = {
  	.probe	= jornada_ssp_probe,
  	.remove	= jornada_ssp_remove,
  	.driver	= {
  		.name	= "jornada_ssp",
  	},
  };
  
  static int __init jornada_ssp_init(void)
  {
  	return platform_driver_register(&jornadassp_driver);
  }