Test modalias with spi_tty
[pub/spi-gpio-pp.git] / spi_tty.c
1 /*
2 * spi_butterfly.c - parport-to-butterfly adapter
3 *
4 * Copyright (C) 2005 David Brownell
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 * idea:
21 * separate the butterfly driver into a hotpluggable SPI master controller
22 * use a board description file, which loads the:
23 * - the SPI master controller
24 * - the SPI protocoll driver
25 * call spi_new_device with
26 - spi_master = butterfly parport driver (or parameter configurable)
27 - spi_board_info = infos about Mauro-Lite
28
29 */
30 #include <linux/kernel.h>
31 #include <linux/init.h>
32 #include <linux/delay.h>
33 #include <linux/device.h>
34 #include <linux/parport.h>
35
36 #include <linux/sched.h>
37 #include <linux/spi/spi.h>
38 #include <linux/spi/spi_bitbang.h>
39
40
41
42 /*
43 * This uses SPI to talk with an "AVR Butterfly", which is a $US20 card
44 * with a battery powered AVR microcontroller and lots of goodies. You
45 * can use GCC to develop firmware for this.
46 *
47 * See Documentation/spi/butterfly for information about how to build
48 * and use this custom parallel port cable.
49 */
50
51 /*
52 * spi_device
53 * todo:
54 * - implement SPI mode 1,2,3 is yet missing
55 * - prevent ugly handling of global butterfly structure
56 * - use serial subsystem
57 * - make stuff module configurable during runtime
58 */
59
60 /* DATA output bits (pins 2..9 == D0..D7) */
61 #define MODALIASLEN 10
62 #define DRVNAME "spi_butterfly"
63 #define DRIVER_VERSION "0.2"
64
65 #define butterfly_nreset (1 << 1) /* pin 3 */
66
67 #define spi_sck_bit (1 << 0) /* pin 2 */
68 #define spi_mosi_bit (1 << 7) /* pin 9 */
69
70 #define vcc_bits ((1 << 6) | (1 << 5)) /* pins 7, 8 */
71
72 /* STATUS input bits */
73 #define spi_miso_bit PARPORT_STATUS_BUSY /* pin 11 */
74
75 /* CONTROL output bits */
76 #define spi_cs_bit PARPORT_CONTROL_SELECT /* pin 17 */
77
78 /*
79 * Parallel
80 * Port Direction Signal
81 * ----------- --------- ------------
82 * D0 2 --> SCLK
83 * D1 3 --> nRESET
84 * D2 4 --> --
85 * D3 5 --> --
86 * D4 6 --> --
87 * D5 7 --> --
88 * D6 8 --> --
89 * D7 9 --> MOSI
90 * GND 25 - GND
91 * Busy 11 <-- MISO
92 * Paper 12 <-- --
93 * Select 13 <-- --
94 * Feed 14 --> --
95 * Error 15 <-- --
96 * Init 16 --> --
97 * Select 17 --> nCS
98 */
99
100 //*****************************************************************************
101 // Globals
102 //*****************************************************************************
103 /* module parameters */
104 static char modalias[MODALIASLEN] = "maurol";
105
106 static inline struct butterfly *spidev_to_pp(struct spi_device *spi)
107 {
108 return spi->controller_data;
109 }
110
111
112 struct butterfly {
113 /* REVISIT ... for now, this must be first */
114 struct spi_bitbang bitbang;
115
116 struct parport *port;
117 struct pardevice *pd;
118
119 u8 lastbyte; /* hold copy of partport to be faster */
120
121 struct spi_message *msg;
122 struct spi_device *butterfly;
123 struct spi_board_info info;
124
125 };
126
127 /*----------------------------------------------------------------------*/
128
129
130 static inline void
131 setsck(struct spi_device *spi, int is_on)
132 {
133 struct butterfly *pp = spidev_to_pp(spi);
134 u8 bit, byte = pp->lastbyte;
135
136 bit = spi_sck_bit;
137
138 if (is_on)
139 byte |= bit;
140 else
141 byte &= ~bit;
142 parport_write_data(pp->port, byte);
143 pp->lastbyte = byte; /* use parport mirror to be faster */
144 }
145
146 static inline void
147 setmosi(struct spi_device *spi, int is_on)
148 {
149 struct butterfly *pp = spidev_to_pp(spi);
150 u8 bit, byte = pp->lastbyte;
151
152 bit = spi_mosi_bit;
153
154 if (is_on)
155 byte |= bit;
156 else
157 byte &= ~bit;
158 parport_write_data(pp->port, byte);
159 pp->lastbyte = byte; /* use parport mirror to be faster */
160 }
161
162 static inline int getmiso(struct spi_device *spi)
163 {
164 struct butterfly *pp = spidev_to_pp(spi);
165 int value;
166 u8 bit;
167
168 bit = spi_miso_bit;
169
170 /* only STATUS_BUSY is NOT negated */
171 value = !(parport_read_status(pp->port) & bit);
172 return (bit == PARPORT_STATUS_BUSY) ? value : !value;
173 }
174
175 static void butterfly_chipselect(struct spi_device *spi, int value)
176 {
177 struct butterfly *pp = spidev_to_pp(spi);
178
179 #if 0
180 /* set default clock polarity */
181 if (value != BITBANG_CS_INACTIVE)
182 setsck(spi, spi->mode & SPI_CPOL);
183
184 /* here, value == "activate or not";
185 * most PARPORT_CONTROL_* bits are negated, so we must
186 * morph it to value == "bit value to write in control register"
187 */
188 if (spi_cs_bit == PARPORT_CONTROL_INIT)
189 value = !value;
190
191 parport_frob_control(pp->port, spi_cs_bit, value ? spi_cs_bit : 0);
192 #else
193 u8 bit, byte = pp->lastbyte;
194
195 bit = butterfly_nreset;
196
197 if (value)
198 byte &= ~bit;
199 else
200 byte |= bit;
201 parport_write_data(pp->port, byte);
202 pp->lastbyte = byte; /* use parport mirror to be faster */
203 #endif
204 }
205
206
207 /* we only needed to implement one mode here, and choose SPI_MODE_0 */
208
209 #define spidelay(X) do{}while(0)
210 //#define spidelay ndelay
211
212 #define EXPAND_BITBANG_TXRX
213 #include <linux/spi/spi_bitbang.h>
214
215 static u32
216 butterfly_txrx_word_mode0(struct spi_device *spi,
217 unsigned nsecs,
218 u32 word, u8 bits)
219 {
220 return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
221 }
222
223 /*----------------------------------------------------------------------*/
224
225 /* REVISIT remove this ugly global and its "only one" limitation */
226 static struct butterfly *butterfly;
227
228 static void butterfly_attach(struct parport *p)
229 {
230 struct pardevice *pd;
231 int status;
232 struct butterfly *pp;
233 struct spi_master *master;
234 struct device *dev = p->physport->dev;
235
236 if (butterfly || !dev)
237 return;
238
239 /* REVISIT: this just _assumes_ a butterfly is there ... no probe,
240 * and no way to be selective about what it binds to.
241 */
242
243 master = spi_alloc_master(dev, sizeof *pp);
244 if (!master) {
245 status = -ENOMEM;
246 goto done;
247 }
248 pp = spi_master_get_devdata(master);
249
250 master->bus_num = -1; /* dynamic alloc of a bus number */
251 master->num_chipselect = 1;
252
253 /*
254 * SPI and bitbang hookup
255 *
256 * use default setup(), cleanup(), and transfer() methods; and
257 * only bother implementing mode 0. Start it later.
258 */
259 pp->bitbang.master = spi_master_get(master);
260 pp->bitbang.chipselect = butterfly_chipselect;
261 pp->bitbang.txrx_word[SPI_MODE_0] = butterfly_txrx_word_mode0;
262 pp->bitbang.flags = SPI_3WIRE; // ####################################
263
264 /*
265 * parport hookup
266 */
267 pp->port = p;
268 pd = parport_register_device(p, DRVNAME,
269 NULL, NULL, NULL,
270 0 /* FLAGS */, pp); //PARPORT_FLAG_EXCL, pp);
271 if (!pd) {
272 status = -ENOMEM;
273 goto clean0;
274 }
275 pp->pd = pd;
276
277 status = parport_claim(pd);
278 if (status < 0)
279 goto clean1;
280
281 pp->lastbyte = 0;
282 parport_write_data(pp->port, pp->lastbyte);
283
284 /*
285 * Butterfly reset, powerup, run firmware
286 */
287 pr_debug("%s: powerup/reset Butterfly\n", DRVNAME);
288
289 /* nCS for dataflash (this bit is inverted on output) */
290 parport_frob_control(pp->port, spi_cs_bit, 0);
291
292 /* stabilize power with chip in reset (nRESET), and
293 * spi_sck_bit clear (CPOL=0)
294 */
295 pp->lastbyte |= vcc_bits;
296 parport_write_data(pp->port, pp->lastbyte);
297 msleep(5);
298
299 #if 0
300 /* take it out of reset; assume long reset delay */
301 pp->lastbyte |= butterfly_nreset;
302 parport_write_data(pp->port, pp->lastbyte);
303 msleep(10);
304
305 /* take reset as trigger signal ############# */
306 pp->lastbyte &= ~butterfly_nreset;
307 parport_write_data(pp->port, pp->lastbyte);
308 #endif
309
310 /*
311 * Start SPI ... for now, hide that we're two physical busses.
312 */
313 status = spi_bitbang_start(&pp->bitbang);
314 if (status < 0) {
315 pr_warning("%s: spi_bitbang_start failed with status %d\n",
316 DRVNAME, status);
317 goto clean2;
318 }
319
320 /*
321 * The modalias name MUST match the device_driver name
322 * for the bus glue code to match and subsequently bind them.
323 * We are binding to the generic drivers/hwmon/lm70.c device
324 * driver.
325 */
326 if (modalias[0]) {
327 pr_info("%s: Will load protocol driver: '%s'!\n", DRVNAME, modalias);
328 } else goto clean2;
329
330 /* need to make this parameter loadable */
331 strcpy(pp->info.modalias, modalias);
332 pp->info.max_speed_hz = 15 * 1000 * 1000;
333 pp->info.chip_select = 0; // 0: .. 1:
334 pp->info.mode = SPI_3WIRE | SPI_MODE_0; // ################
335
336 /* Enable access to our primary data structure via
337 * the board info's (void *)controller_data.
338 */
339 pp->info.platform_data = NULL; // here we should add data structures for subsystem driver ???
340 pp->info.controller_data = pp; /* save my structure for later use */
341 pp->butterfly = spi_new_device(pp->bitbang.master, &pp->info);
342 if (pp->butterfly)
343 pr_info("%s: SPI tty at %s\n", DRVNAME,
344 pp->butterfly->dev.bus_id);
345 else {
346 pr_warning("%s: spi_new_device failed\n", DRVNAME);
347 status = -ENODEV;
348 goto out_bitbang_stop;
349 }
350 // pp->butterfly->bits_per_word=16; // ###############
351
352 /* get spi_bitbang_transfer either via global Symbol, or better
353 * ask it from the driver structure
354 */
355 pp->msg = spi_message_alloc(1, GFP_KERNEL);
356 if (master) { /* the same address is also saved in pp->bitbang.master or pp->butterfly->master */
357 struct spi_message *spi_msg;
358 spi_msg = pp->msg;
359 if (spi_msg) {
360 // spi_message_init(spi_msg);
361 pr_info("Alloc SPI message buffer\n");
362 spi_msg->spi = pp->butterfly;
363 spi_msg->actual_length = 1;
364 #if 0
365 spi_msg->list_head ... Addresse der ersten SPI transfer struct
366
367
368 spi_msg->tx_buf = ;
369 spi_msg->len = 1;
370 spi_msg->cs_change = 1;
371 spi_msg->delay_usecs = 0;
372
373 /* fill up message */
374 master->transfer(pp->butterfly, spi_msg);
375 #endif
376 }
377 }
378 butterfly = pp;
379 return;
380
381 out_bitbang_stop:
382 spi_bitbang_stop(&pp->bitbang);
383 clean2:
384 /* turn off VCC */
385 parport_write_data(pp->port, 0);
386
387 parport_release(pp->pd);
388 clean1:
389 parport_unregister_device(pd);
390 clean0:
391 (void) spi_master_put(pp->bitbang.master);
392 done:
393 pr_debug("%s: butterfly probe, fail %d\n", DRVNAME, status);
394 }
395
396 static void butterfly_detach(struct parport *p)
397 {
398 struct butterfly *pp;
399 int status;
400
401 /* FIXME this global is ugly ... but, how to quickly get from
402 * the parport to the "struct butterfly" associated with it?
403 * "old school" driver-internal device lists?
404 */
405 if (!butterfly || butterfly->port != p)
406 return;
407 pp = butterfly;
408 if (pp->msg) {
409 spi_message_free(pp->msg);
410 pr_info("Dealloc SPI message buffer\n");
411 }
412
413 /* stop() unregisters child devices too */
414 status = spi_bitbang_stop(&pp->bitbang);
415
416 /* turn off VCC */
417 parport_write_data(pp->port, 0);
418 msleep(10);
419
420 parport_release(pp->pd);
421 parport_unregister_device(pp->pd);
422
423 (void) spi_master_put(pp->bitbang.master);
424
425 butterfly = NULL;
426 }
427
428 static struct parport_driver butterfly_driver = {
429 .name = DRVNAME,
430 .attach = butterfly_attach,
431 .detach = butterfly_detach,
432 };
433
434
435 static int __init butterfly_init(void)
436 {
437 return parport_register_driver(&butterfly_driver);
438 }
439 device_initcall(butterfly_init);
440
441 static void __exit butterfly_exit(void)
442 {
443 parport_unregister_driver(&butterfly_driver);
444 }
445 module_exit(butterfly_exit);
446
447 MODULE_DESCRIPTION("Parport Adapter driver for SPI tty Butterfly");
448 MODULE_LICENSE("GPL");
449
450 module_param_string(spi_pdrv, modalias, sizeof(modalias), S_IRUGO);
451 MODULE_PARM_DESC(spi_pdrv, "spi protocol driver name");
452
453 MODULE_INFO(Version, DRIVER_VERSION);