[PATCH] SPI: add spi_butterfly driver

This adds a bitbanging parport based adaptor cable for AVR Butterfly, giving
SPI links to its DataFlash chip and (eventually) firmware running in the card.

Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by David Brownell and committed by Greg Kroah-Hartman 2e10c84b 5d870c8e

+490
+57
Documentation/spi/butterfly
··· 1 + spi_butterfly - parport-to-butterfly adapter driver 2 + =================================================== 3 + 4 + This is a hardware and software project that includes building and using 5 + a parallel port adapter cable, together with an "AVR Butterfly" to run 6 + firmware for user interfacing and/or sensors. A Butterfly is a $US20 7 + battery powered card with an AVR microcontroller and lots of goodies: 8 + sensors, LCD, flash, toggle stick, and more. You can use AVR-GCC to 9 + develop firmware for this, and flash it using this adapter cable. 10 + 11 + You can make this adapter from an old printer cable and solder things 12 + directly to the Butterfly. Or (if you have the parts and skills) you 13 + can come up with something fancier, providing ciruit protection to the 14 + Butterfly and the printer port, or with a better power supply than two 15 + signal pins from the printer port. 16 + 17 + 18 + The first cable connections will hook Linux up to one SPI bus, with the 19 + AVR and a DataFlash chip; and to the AVR reset line. This is all you 20 + need to reflash the firmware, and the pins are the standard Atmel "ISP" 21 + connector pins (used also on non-Butterfly AVR boards). 22 + 23 + Signal Butterfly Parport (DB-25) 24 + ------ --------- --------------- 25 + SCK = J403.PB1/SCK = pin 2/D0 26 + RESET = J403.nRST = pin 3/D1 27 + VCC = J403.VCC_EXT = pin 8/D6 28 + MOSI = J403.PB2/MOSI = pin 9/D7 29 + MISO = J403.PB3/MISO = pin 11/S7,nBUSY 30 + GND = J403.GND = pin 23/GND 31 + 32 + Then to let Linux master that bus to talk to the DataFlash chip, you must 33 + (a) flash new firmware that disables SPI (set PRR.2, and disable pullups 34 + by clearing PORTB.[0-3]); (b) configure the mtd_dataflash driver; and 35 + (c) cable in the chipselect. 36 + 37 + Signal Butterfly Parport (DB-25) 38 + ------ --------- --------------- 39 + VCC = J400.VCC_EXT = pin 7/D5 40 + SELECT = J400.PB0/nSS = pin 17/C3,nSELECT 41 + GND = J400.GND = pin 24/GND 42 + 43 + The "USI" controller, using J405, can be used for a second SPI bus. That 44 + would let you talk to the AVR over SPI, running firmware that makes it act 45 + as an SPI slave, while letting either Linux or the AVR use the DataFlash. 46 + There are plenty of spare parport pins to wire this one up, such as: 47 + 48 + Signal Butterfly Parport (DB-25) 49 + ------ --------- --------------- 50 + SCK = J403.PE4/USCK = pin 5/D3 51 + MOSI = J403.PE5/DI = pin 6/D4 52 + MISO = J403.PE6/DO = pin 12/S5,nPAPEROUT 53 + GND = J403.GND = pin 22/GND 54 + 55 + IRQ = J402.PF4 = pin 10/S6,ACK 56 + GND = J402.GND(P2) = pin 25/GND 57 +
+10
drivers/spi/Kconfig
··· 75 75 inexpensive battery powered microcontroller evaluation board. 76 76 This same cable can be used to flash new firmware. 77 77 78 + config SPI_BUTTERFLY 79 + tristate "Parallel port adapter for AVR Butterfly (DEVELOPMENT)" 80 + depends on SPI_MASTER && PARPORT && EXPERIMENTAL 81 + select SPI_BITBANG 82 + help 83 + This uses a custom parallel port cable to connect to an AVR 84 + Butterfly <http://www.atmel.com/products/avr/butterfly>, an 85 + inexpensive battery powered microcontroller evaluation board. 86 + This same cable can be used to flash new firmware. 87 + 78 88 # 79 89 # Add new SPI master controllers in alphabetical order above this line 80 90 #
+423
drivers/spi/spi_butterfly.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 + #include <linux/config.h> 21 + #include <linux/kernel.h> 22 + #include <linux/init.h> 23 + #include <linux/delay.h> 24 + #include <linux/platform_device.h> 25 + #include <linux/parport.h> 26 + 27 + #include <linux/spi/spi.h> 28 + #include <linux/spi/spi_bitbang.h> 29 + #include <linux/spi/flash.h> 30 + 31 + #include <linux/mtd/partitions.h> 32 + 33 + 34 + /* 35 + * This uses SPI to talk with an "AVR Butterfly", which is a $US20 card 36 + * with a battery powered AVR microcontroller and lots of goodies. You 37 + * can use GCC to develop firmware for this. 38 + * 39 + * See Documentation/spi/butterfly for information about how to build 40 + * and use this custom parallel port cable. 41 + */ 42 + 43 + #undef HAVE_USI /* nyet */ 44 + 45 + 46 + /* DATA output bits (pins 2..9 == D0..D7) */ 47 + #define butterfly_nreset (1 << 1) /* pin 3 */ 48 + 49 + #define spi_sck_bit (1 << 0) /* pin 2 */ 50 + #define spi_mosi_bit (1 << 7) /* pin 9 */ 51 + 52 + #define usi_sck_bit (1 << 3) /* pin 5 */ 53 + #define usi_mosi_bit (1 << 4) /* pin 6 */ 54 + 55 + #define vcc_bits ((1 << 6) | (1 << 5)) /* pins 7, 8 */ 56 + 57 + /* STATUS input bits */ 58 + #define spi_miso_bit PARPORT_STATUS_BUSY /* pin 11 */ 59 + 60 + #define usi_miso_bit PARPORT_STATUS_PAPEROUT /* pin 12 */ 61 + 62 + /* CONTROL output bits */ 63 + #define spi_cs_bit PARPORT_CONTROL_SELECT /* pin 17 */ 64 + /* USI uses no chipselect */ 65 + 66 + 67 + 68 + static inline struct butterfly *spidev_to_pp(struct spi_device *spi) 69 + { 70 + return spi->controller_data; 71 + } 72 + 73 + static inline int is_usidev(struct spi_device *spi) 74 + { 75 + #ifdef HAVE_USI 76 + return spi->chip_select != 1; 77 + #else 78 + return 0; 79 + #endif 80 + } 81 + 82 + 83 + struct butterfly { 84 + /* REVISIT ... for now, this must be first */ 85 + struct spi_bitbang bitbang; 86 + 87 + struct parport *port; 88 + struct pardevice *pd; 89 + 90 + u8 lastbyte; 91 + 92 + struct spi_device *dataflash; 93 + struct spi_device *butterfly; 94 + struct spi_board_info info[2]; 95 + 96 + }; 97 + 98 + /*----------------------------------------------------------------------*/ 99 + 100 + /* 101 + * these routines may be slower than necessary because they're hiding 102 + * the fact that there are two different SPI busses on this cable: one 103 + * to the DataFlash chip (or AVR SPI controller), the other to the 104 + * AVR USI controller. 105 + */ 106 + 107 + static inline void 108 + setsck(struct spi_device *spi, int is_on) 109 + { 110 + struct butterfly *pp = spidev_to_pp(spi); 111 + u8 bit, byte = pp->lastbyte; 112 + 113 + if (is_usidev(spi)) 114 + bit = usi_sck_bit; 115 + else 116 + bit = spi_sck_bit; 117 + 118 + if (is_on) 119 + byte |= bit; 120 + else 121 + byte &= ~bit; 122 + parport_write_data(pp->port, byte); 123 + pp->lastbyte = byte; 124 + } 125 + 126 + static inline void 127 + setmosi(struct spi_device *spi, int is_on) 128 + { 129 + struct butterfly *pp = spidev_to_pp(spi); 130 + u8 bit, byte = pp->lastbyte; 131 + 132 + if (is_usidev(spi)) 133 + bit = usi_mosi_bit; 134 + else 135 + bit = spi_mosi_bit; 136 + 137 + if (is_on) 138 + byte |= bit; 139 + else 140 + byte &= ~bit; 141 + parport_write_data(pp->port, byte); 142 + pp->lastbyte = byte; 143 + } 144 + 145 + static inline int getmiso(struct spi_device *spi) 146 + { 147 + struct butterfly *pp = spidev_to_pp(spi); 148 + int value; 149 + u8 bit; 150 + 151 + if (is_usidev(spi)) 152 + bit = usi_miso_bit; 153 + else 154 + bit = spi_miso_bit; 155 + 156 + /* only STATUS_BUSY is NOT negated */ 157 + value = !(parport_read_status(pp->port) & bit); 158 + return (bit == PARPORT_STATUS_BUSY) ? value : !value; 159 + } 160 + 161 + static void butterfly_chipselect(struct spi_device *spi, int value) 162 + { 163 + struct butterfly *pp = spidev_to_pp(spi); 164 + 165 + /* set default clock polarity */ 166 + if (value) 167 + setsck(spi, spi->mode & SPI_CPOL); 168 + 169 + /* no chipselect on this USI link config */ 170 + if (is_usidev(spi)) 171 + return; 172 + 173 + /* here, value == "activate or not" */ 174 + 175 + /* most PARPORT_CONTROL_* bits are negated */ 176 + if (spi_cs_bit == PARPORT_CONTROL_INIT) 177 + value = !value; 178 + 179 + /* here, value == "bit value to write in control register" */ 180 + 181 + parport_frob_control(pp->port, spi_cs_bit, value ? spi_cs_bit : 0); 182 + } 183 + 184 + 185 + /* we only needed to implement one mode here, and choose SPI_MODE_0 */ 186 + 187 + #define spidelay(X) do{}while(0) 188 + //#define spidelay ndelay 189 + 190 + #define EXPAND_BITBANG_TXRX 191 + #include <linux/spi/spi_bitbang.h> 192 + 193 + static u32 194 + butterfly_txrx_word_mode0(struct spi_device *spi, 195 + unsigned nsecs, 196 + u32 word, u8 bits) 197 + { 198 + return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits); 199 + } 200 + 201 + /*----------------------------------------------------------------------*/ 202 + 203 + /* override default partitioning with cmdlinepart */ 204 + static struct mtd_partition partitions[] = { { 205 + /* JFFS2 wants partitions of 4*N blocks for this device ... */ 206 + 207 + /* sector 0 = 8 pages * 264 bytes/page (1 block) 208 + * sector 1 = 248 pages * 264 bytes/page 209 + */ 210 + .name = "bookkeeping", // 66 KB 211 + .offset = 0, 212 + .size = (8 + 248) * 264, 213 + // .mask_flags = MTD_WRITEABLE, 214 + }, { 215 + /* sector 2 = 256 pages * 264 bytes/page 216 + * sectors 3-5 = 512 pages * 264 bytes/page 217 + */ 218 + .name = "filesystem", // 462 KB 219 + .offset = MTDPART_OFS_APPEND, 220 + .size = MTDPART_SIZ_FULL, 221 + } }; 222 + 223 + static struct flash_platform_data flash = { 224 + .name = "butterflash", 225 + .parts = partitions, 226 + .nr_parts = ARRAY_SIZE(partitions), 227 + }; 228 + 229 + 230 + /* REVISIT remove this ugly global and its "only one" limitation */ 231 + static struct butterfly *butterfly; 232 + 233 + static void butterfly_attach(struct parport *p) 234 + { 235 + struct pardevice *pd; 236 + int status; 237 + struct butterfly *pp; 238 + struct spi_master *master; 239 + struct platform_device *pdev; 240 + 241 + if (butterfly) 242 + return; 243 + 244 + /* REVISIT: this just _assumes_ a butterfly is there ... no probe, 245 + * and no way to be selective about what it binds to. 246 + */ 247 + 248 + /* FIXME where should master->cdev.dev come from? 249 + * e.g. /sys/bus/pnp0/00:0b, some PCI thing, etc 250 + * setting up a platform device like this is an ugly kluge... 251 + */ 252 + pdev = platform_device_register_simple("butterfly", -1, NULL, 0); 253 + 254 + master = spi_alloc_master(&pdev->dev, sizeof *pp); 255 + if (!master) { 256 + status = -ENOMEM; 257 + goto done; 258 + } 259 + pp = spi_master_get_devdata(master); 260 + 261 + /* 262 + * SPI and bitbang hookup 263 + * 264 + * use default setup(), cleanup(), and transfer() methods; and 265 + * only bother implementing mode 0. Start it later. 266 + */ 267 + master->bus_num = 42; 268 + master->num_chipselect = 2; 269 + 270 + pp->bitbang.master = spi_master_get(master); 271 + pp->bitbang.chipselect = butterfly_chipselect; 272 + pp->bitbang.txrx_word[SPI_MODE_0] = butterfly_txrx_word_mode0; 273 + 274 + /* 275 + * parport hookup 276 + */ 277 + pp->port = p; 278 + pd = parport_register_device(p, "spi_butterfly", 279 + NULL, NULL, NULL, 280 + 0 /* FLAGS */, pp); 281 + if (!pd) { 282 + status = -ENOMEM; 283 + goto clean0; 284 + } 285 + pp->pd = pd; 286 + 287 + status = parport_claim(pd); 288 + if (status < 0) 289 + goto clean1; 290 + 291 + /* 292 + * Butterfly reset, powerup, run firmware 293 + */ 294 + pr_debug("%s: powerup/reset Butterfly\n", p->name); 295 + 296 + /* nCS for dataflash (this bit is inverted on output) */ 297 + parport_frob_control(pp->port, spi_cs_bit, 0); 298 + 299 + /* stabilize power with chip in reset (nRESET), and 300 + * both spi_sck_bit and usi_sck_bit clear (CPOL=0) 301 + */ 302 + pp->lastbyte |= vcc_bits; 303 + parport_write_data(pp->port, pp->lastbyte); 304 + msleep(5); 305 + 306 + /* take it out of reset; assume long reset delay */ 307 + pp->lastbyte |= butterfly_nreset; 308 + parport_write_data(pp->port, pp->lastbyte); 309 + msleep(100); 310 + 311 + 312 + /* 313 + * Start SPI ... for now, hide that we're two physical busses. 314 + */ 315 + status = spi_bitbang_start(&pp->bitbang); 316 + if (status < 0) 317 + goto clean2; 318 + 319 + /* Bus 1 lets us talk to at45db041b (firmware disables AVR) 320 + * or AVR (firmware resets at45, acts as spi slave) 321 + */ 322 + pp->info[0].max_speed_hz = 15 * 1000 * 1000; 323 + strcpy(pp->info[0].modalias, "mtd_dataflash"); 324 + pp->info[0].platform_data = &flash; 325 + pp->info[0].chip_select = 1; 326 + pp->info[0].controller_data = pp; 327 + pp->dataflash = spi_new_device(pp->bitbang.master, &pp->info[0]); 328 + if (pp->dataflash) 329 + pr_debug("%s: dataflash at %s\n", p->name, 330 + pp->dataflash->dev.bus_id); 331 + 332 + #ifdef HAVE_USI 333 + /* even more custom AVR firmware */ 334 + pp->info[1].max_speed_hz = 10 /* ?? */ * 1000 * 1000; 335 + strcpy(pp->info[1].modalias, "butterfly"); 336 + // pp->info[1].platform_data = ... TBD ... ; 337 + pp->info[1].chip_select = 2, 338 + pp->info[1].controller_data = pp; 339 + pp->butterfly = spi_new_device(pp->bitbang.master, &pp->info[1]); 340 + if (pp->butterfly) 341 + pr_debug("%s: butterfly at %s\n", p->name, 342 + pp->butterfly->dev.bus_id); 343 + 344 + /* FIXME setup ACK for the IRQ line ... */ 345 + #endif 346 + 347 + // dev_info(_what?_, ...) 348 + pr_info("%s: AVR Butterfly\n", p->name); 349 + butterfly = pp; 350 + return; 351 + 352 + clean2: 353 + /* turn off VCC */ 354 + parport_write_data(pp->port, 0); 355 + 356 + parport_release(pp->pd); 357 + clean1: 358 + parport_unregister_device(pd); 359 + clean0: 360 + (void) spi_master_put(pp->bitbang.master); 361 + done: 362 + platform_device_unregister(pdev); 363 + pr_debug("%s: butterfly probe, fail %d\n", p->name, status); 364 + } 365 + 366 + static void butterfly_detach(struct parport *p) 367 + { 368 + struct butterfly *pp; 369 + struct platform_device *pdev; 370 + int status; 371 + 372 + /* FIXME this global is ugly ... but, how to quickly get from 373 + * the parport to the "struct butterfly" associated with it? 374 + * "old school" driver-internal device lists? 375 + */ 376 + if (!butterfly || butterfly->port != p) 377 + return; 378 + pp = butterfly; 379 + butterfly = NULL; 380 + 381 + #ifdef HAVE_USI 382 + spi_unregister_device(pp->butterfly); 383 + pp->butterfly = NULL; 384 + #endif 385 + spi_unregister_device(pp->dataflash); 386 + pp->dataflash = NULL; 387 + 388 + status = spi_bitbang_stop(&pp->bitbang); 389 + 390 + /* turn off VCC */ 391 + parport_write_data(pp->port, 0); 392 + msleep(10); 393 + 394 + parport_release(pp->pd); 395 + parport_unregister_device(pp->pd); 396 + 397 + pdev = to_platform_device(pp->bitbang.master->cdev.dev); 398 + 399 + (void) spi_master_put(pp->bitbang.master); 400 + 401 + platform_device_unregister(pdev); 402 + } 403 + 404 + static struct parport_driver butterfly_driver = { 405 + .name = "spi_butterfly", 406 + .attach = butterfly_attach, 407 + .detach = butterfly_detach, 408 + }; 409 + 410 + 411 + static int __init butterfly_init(void) 412 + { 413 + return parport_register_driver(&butterfly_driver); 414 + } 415 + device_initcall(butterfly_init); 416 + 417 + static void __exit butterfly_exit(void) 418 + { 419 + parport_unregister_driver(&butterfly_driver); 420 + } 421 + module_exit(butterfly_exit); 422 + 423 + MODULE_LICENSE("GPL");