Blame view
drivers/spi/spi-s3c24xx.c
16.3 KB
ca632f556 spi: reorganize d... |
1 |
/* |
7fba53402 [PATCH] S3C24XX: ... |
2 |
* Copyright (c) 2006 Ben Dooks |
bec0806cf spi_s3c24xx: add ... |
3 |
* Copyright 2006-2009 Simtec Electronics |
7fba53402 [PATCH] S3C24XX: ... |
4 5 6 7 8 9 10 |
* Ben Dooks <ben@simtec.co.uk> * * 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. * */ |
7fba53402 [PATCH] S3C24XX: ... |
11 12 13 14 15 16 17 18 19 |
#include <linux/init.h> #include <linux/spinlock.h> #include <linux/workqueue.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/err.h> #include <linux/clk.h> #include <linux/platform_device.h> |
ee9c1fbfe spi: use generic ... |
20 |
#include <linux/gpio.h> |
1a0c220f7 spi_s3c24xx: fix ... |
21 |
#include <linux/io.h> |
5a0e3ad6a include cleanup: ... |
22 |
#include <linux/slab.h> |
7fba53402 [PATCH] S3C24XX: ... |
23 24 25 |
#include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> |
d7614de42 spi: Add module.h... |
26 |
#include <linux/module.h> |
7fba53402 [PATCH] S3C24XX: ... |
27 |
|
136227087 [ARM] S3C: Move p... |
28 |
#include <plat/regs-spi.h> |
a09e64fbc [ARM] Move includ... |
29 |
#include <mach/spi.h> |
7fba53402 [PATCH] S3C24XX: ... |
30 |
|
bec0806cf spi_s3c24xx: add ... |
31 32 |
#include <plat/fiq.h> #include <asm/fiq.h> |
ca632f556 spi: reorganize d... |
33 |
#include "spi-s3c24xx-fiq.h" |
bec0806cf spi_s3c24xx: add ... |
34 |
|
570327d9f spi_s3c24xx: cach... |
35 36 37 38 39 40 41 42 43 44 45 46 47 |
/** * s3c24xx_spi_devstate - per device data * @hz: Last frequency calculated for @sppre field. * @mode: Last mode setting for the @spcon field. * @spcon: Value to write to the SPCON register. * @sppre: Value to write to the SPPRE register. */ struct s3c24xx_spi_devstate { unsigned int hz; unsigned int mode; u8 spcon; u8 sppre; }; |
bec0806cf spi_s3c24xx: add ... |
48 49 50 51 52 53 |
enum spi_fiq_mode { FIQ_MODE_NONE = 0, FIQ_MODE_TX = 1, FIQ_MODE_RX = 2, FIQ_MODE_TXRX = 3, }; |
7fba53402 [PATCH] S3C24XX: ... |
54 55 56 57 58 59 60 61 62 |
struct s3c24xx_spi { /* bitbang has to be first */ struct spi_bitbang bitbang; struct completion done; void __iomem *regs; int irq; int len; int count; |
bec0806cf spi_s3c24xx: add ... |
63 64 65 66 |
struct fiq_handler fiq_handler; enum spi_fiq_mode fiq_mode; unsigned char fiq_inuse; unsigned char fiq_claimed; |
6c912a3d3 [PATCH] spi_s3c24... |
67 |
void (*set_cs)(struct s3c2410_spi_info *spi, |
8736b9270 [PATCH] S3C24XX: ... |
68 |
int cs, int pol); |
7fba53402 [PATCH] S3C24XX: ... |
69 70 71 72 73 74 75 76 77 78 79 |
/* data buffers */ const unsigned char *tx; unsigned char *rx; struct clk *clk; struct resource *ioarea; struct spi_master *master; struct spi_device *curdev; struct device *dev; struct s3c2410_spi_info *pdata; }; |
bec0806cf spi_s3c24xx: add ... |
80 |
|
7fba53402 [PATCH] S3C24XX: ... |
81 82 83 84 85 86 87 |
#define SPCON_DEFAULT (S3C2410_SPCON_MSTR | S3C2410_SPCON_SMOD_INT) #define SPPIN_DEFAULT (S3C2410_SPPIN_KEEP) static inline struct s3c24xx_spi *to_hw(struct spi_device *sdev) { return spi_master_get_devdata(sdev->master); } |
8736b9270 [PATCH] S3C24XX: ... |
88 89 |
static void s3c24xx_spi_gpiocs(struct s3c2410_spi_info *spi, int cs, int pol) { |
ee9c1fbfe spi: use generic ... |
90 |
gpio_set_value(spi->pin_cs, pol); |
8736b9270 [PATCH] S3C24XX: ... |
91 |
} |
7fba53402 [PATCH] S3C24XX: ... |
92 93 |
static void s3c24xx_spi_chipsel(struct spi_device *spi, int value) { |
570327d9f spi_s3c24xx: cach... |
94 |
struct s3c24xx_spi_devstate *cs = spi->controller_state; |
7fba53402 [PATCH] S3C24XX: ... |
95 96 |
struct s3c24xx_spi *hw = to_hw(spi); unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0; |
570327d9f spi_s3c24xx: cach... |
97 98 |
/* change the chipselect state and the state of the spi engine clock */ |
7fba53402 [PATCH] S3C24XX: ... |
99 100 101 |
switch (value) { case BITBANG_CS_INACTIVE: |
3d2c5b415 spi: fix use of s... |
102 |
hw->set_cs(hw->pdata, spi->chip_select, cspol^1); |
570327d9f spi_s3c24xx: cach... |
103 |
writeb(cs->spcon, hw->regs + S3C2410_SPCON); |
7fba53402 [PATCH] S3C24XX: ... |
104 105 106 |
break; case BITBANG_CS_ACTIVE: |
570327d9f spi_s3c24xx: cach... |
107 108 |
writeb(cs->spcon | S3C2410_SPCON_ENSCK, hw->regs + S3C2410_SPCON); |
3d2c5b415 spi: fix use of s... |
109 |
hw->set_cs(hw->pdata, spi->chip_select, cspol); |
7fba53402 [PATCH] S3C24XX: ... |
110 |
break; |
7fba53402 [PATCH] S3C24XX: ... |
111 112 |
} } |
570327d9f spi_s3c24xx: cach... |
113 114 |
static int s3c24xx_spi_update_state(struct spi_device *spi, struct spi_transfer *t) |
7fba53402 [PATCH] S3C24XX: ... |
115 116 |
{ struct s3c24xx_spi *hw = to_hw(spi); |
570327d9f spi_s3c24xx: cach... |
117 |
struct s3c24xx_spi_devstate *cs = spi->controller_state; |
7fba53402 [PATCH] S3C24XX: ... |
118 119 120 |
unsigned int bpw; unsigned int hz; unsigned int div; |
b89787845 spi_s3c24xx: fix ... |
121 |
unsigned long clk; |
7fba53402 [PATCH] S3C24XX: ... |
122 123 124 |
bpw = t ? t->bits_per_word : spi->bits_per_word; hz = t ? t->speed_hz : spi->max_speed_hz; |
191529756 spi_s3c24xx: fix ... |
125 126 127 128 129 |
if (!bpw) bpw = 8; if (!hz) hz = spi->max_speed_hz; |
7fba53402 [PATCH] S3C24XX: ... |
130 131 132 133 134 |
if (bpw != 8) { dev_err(&spi->dev, "invalid bits-per-word (%d) ", bpw); return -EINVAL; } |
570327d9f spi_s3c24xx: cach... |
135 |
if (spi->mode != cs->mode) { |
bec0806cf spi_s3c24xx: add ... |
136 |
u8 spcon = SPCON_DEFAULT | S3C2410_SPCON_ENSCK; |
570327d9f spi_s3c24xx: cach... |
137 138 139 |
if (spi->mode & SPI_CPHA) spcon |= S3C2410_SPCON_CPHA_FMTB; |
7fba53402 [PATCH] S3C24XX: ... |
140 |
|
570327d9f spi_s3c24xx: cach... |
141 142 |
if (spi->mode & SPI_CPOL) spcon |= S3C2410_SPCON_CPOL_HIGH; |
7fba53402 [PATCH] S3C24XX: ... |
143 |
|
570327d9f spi_s3c24xx: cach... |
144 145 146 |
cs->mode = spi->mode; cs->spcon = spcon; } |
b89787845 spi_s3c24xx: fix ... |
147 |
|
570327d9f spi_s3c24xx: cach... |
148 149 150 |
if (cs->hz != hz) { clk = clk_get_rate(hw->clk); div = DIV_ROUND_UP(clk, hz * 2) - 1; |
b89787845 spi_s3c24xx: fix ... |
151 |
|
570327d9f spi_s3c24xx: cach... |
152 153 |
if (div > 255) div = 255; |
7fba53402 [PATCH] S3C24XX: ... |
154 |
|
570327d9f spi_s3c24xx: cach... |
155 156 157 158 159 160 |
dev_dbg(&spi->dev, "pre-scaler=%d (wanted %d, got %ld) ", div, hz, clk / (2 * (div + 1))); cs->hz = hz; cs->sppre = div; |
7fba53402 [PATCH] S3C24XX: ... |
161 |
} |
7fba53402 [PATCH] S3C24XX: ... |
162 163 164 |
return 0; } |
570327d9f spi_s3c24xx: cach... |
165 166 167 168 169 170 171 172 173 174 175 176 177 |
static int s3c24xx_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t) { struct s3c24xx_spi_devstate *cs = spi->controller_state; struct s3c24xx_spi *hw = to_hw(spi); int ret; ret = s3c24xx_spi_update_state(spi, t); if (!ret) writeb(cs->sppre, hw->regs + S3C2410_SPPRE); return ret; } |
7fba53402 [PATCH] S3C24XX: ... |
178 179 |
static int s3c24xx_spi_setup(struct spi_device *spi) { |
570327d9f spi_s3c24xx: cach... |
180 181 |
struct s3c24xx_spi_devstate *cs = spi->controller_state; struct s3c24xx_spi *hw = to_hw(spi); |
7fba53402 [PATCH] S3C24XX: ... |
182 |
int ret; |
570327d9f spi_s3c24xx: cach... |
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
/* allocate settings on the first call */ if (!cs) { cs = kzalloc(sizeof(struct s3c24xx_spi_devstate), GFP_KERNEL); if (!cs) { dev_err(&spi->dev, "no memory for controller state "); return -ENOMEM; } cs->spcon = SPCON_DEFAULT; cs->hz = -1; spi->controller_state = cs; } /* initialise the state from the device */ ret = s3c24xx_spi_update_state(spi, NULL); if (ret) |
7fba53402 [PATCH] S3C24XX: ... |
200 |
return ret; |
570327d9f spi_s3c24xx: cach... |
201 202 203 204 205 |
spin_lock(&hw->bitbang.lock); if (!hw->bitbang.busy) { hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE); /* need to ndelay for 0.5 clocktick ? */ |
7fba53402 [PATCH] S3C24XX: ... |
206 |
} |
570327d9f spi_s3c24xx: cach... |
207 |
spin_unlock(&hw->bitbang.lock); |
7fba53402 [PATCH] S3C24XX: ... |
208 |
|
7fba53402 [PATCH] S3C24XX: ... |
209 210 |
return 0; } |
570327d9f spi_s3c24xx: cach... |
211 212 213 214 |
static void s3c24xx_spi_cleanup(struct spi_device *spi) { kfree(spi->controller_state); } |
7fba53402 [PATCH] S3C24XX: ... |
215 216 |
static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count) { |
4b1badf5d [PATCH] SPI: defi... |
217 |
return hw->tx ? hw->tx[count] : 0; |
7fba53402 [PATCH] S3C24XX: ... |
218 |
} |
bec0806cf spi_s3c24xx: add ... |
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 |
#ifdef CONFIG_SPI_S3C24XX_FIQ /* Support for FIQ based pseudo-DMA to improve the transfer speed. * * This code uses the assembly helper in spi_s3c24xx_spi.S which is * used by the FIQ core to move data between main memory and the peripheral * block. Since this is code running on the processor, there is no problem * with cache coherency of the buffers, so we can use any buffer we like. */ /** * struct spi_fiq_code - FIQ code and header * @length: The length of the code fragment, excluding this header. * @ack_offset: The offset from @data to the word to place the IRQ ACK bit at. * @data: The code itself to install as a FIQ handler. */ struct spi_fiq_code { u32 length; u32 ack_offset; u8 data[0]; }; extern struct spi_fiq_code s3c24xx_spi_fiq_txrx; extern struct spi_fiq_code s3c24xx_spi_fiq_tx; extern struct spi_fiq_code s3c24xx_spi_fiq_rx; /** * ack_bit - turn IRQ into IRQ acknowledgement bit * @irq: The interrupt number * * Returns the bit to write to the interrupt acknowledge register. */ static inline u32 ack_bit(unsigned int irq) { return 1 << (irq - IRQ_EINT0); } /** * s3c24xx_spi_tryfiq - attempt to claim and setup FIQ for transfer * @hw: The hardware state. * * Claim the FIQ handler (only one can be active at any one time) and * then setup the correct transfer code for this transfer. * |
3ad2f3fbb tree-wide: Assort... |
262 |
* This call updates all the necessary state information if successful, |
bec0806cf spi_s3c24xx: add ... |
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 |
* so the caller does not need to do anything more than start the transfer * as normal, since the IRQ will have been re-routed to the FIQ handler. */ void s3c24xx_spi_tryfiq(struct s3c24xx_spi *hw) { struct pt_regs regs; enum spi_fiq_mode mode; struct spi_fiq_code *code; int ret; if (!hw->fiq_claimed) { /* try and claim fiq if we haven't got it, and if not * then return and simply use another transfer method */ ret = claim_fiq(&hw->fiq_handler); if (ret) return; } if (hw->tx && !hw->rx) mode = FIQ_MODE_TX; else if (hw->rx && !hw->tx) mode = FIQ_MODE_RX; else mode = FIQ_MODE_TXRX; regs.uregs[fiq_rspi] = (long)hw->regs; regs.uregs[fiq_rrx] = (long)hw->rx; regs.uregs[fiq_rtx] = (long)hw->tx + 1; regs.uregs[fiq_rcount] = hw->len - 1; regs.uregs[fiq_rirq] = (long)S3C24XX_VA_IRQ; set_fiq_regs(®s); if (hw->fiq_mode != mode) { u32 *ack_ptr; hw->fiq_mode = mode; switch (mode) { case FIQ_MODE_TX: code = &s3c24xx_spi_fiq_tx; break; case FIQ_MODE_RX: code = &s3c24xx_spi_fiq_rx; break; case FIQ_MODE_TXRX: code = &s3c24xx_spi_fiq_txrx; break; default: code = NULL; } BUG_ON(!code); ack_ptr = (u32 *)&code->data[code->ack_offset]; *ack_ptr = ack_bit(hw->irq); set_fiq_handler(&code->data, code->length); } s3c24xx_set_fiq(hw->irq, true); hw->fiq_mode = mode; hw->fiq_inuse = 1; } /** * s3c24xx_spi_fiqop - FIQ core code callback * @pw: Data registered with the handler * @release: Whether this is a release or a return. * * Called by the FIQ code when another module wants to use the FIQ, so * return whether we are currently using this or not and then update our * internal state. */ static int s3c24xx_spi_fiqop(void *pw, int release) { struct s3c24xx_spi *hw = pw; int ret = 0; if (release) { if (hw->fiq_inuse) ret = -EBUSY; /* note, we do not need to unroute the FIQ, as the FIQ * vector code de-routes it to signal the end of transfer */ hw->fiq_mode = FIQ_MODE_NONE; hw->fiq_claimed = 0; } else { hw->fiq_claimed = 1; } return ret; } /** * s3c24xx_spi_initfiq - setup the information for the FIQ core * @hw: The hardware state. * * Setup the fiq_handler block to pass to the FIQ core. */ static inline void s3c24xx_spi_initfiq(struct s3c24xx_spi *hw) { hw->fiq_handler.dev_id = hw; hw->fiq_handler.name = dev_name(hw->dev); hw->fiq_handler.fiq_op = s3c24xx_spi_fiqop; } /** * s3c24xx_spi_usefiq - return if we should be using FIQ. * @hw: The hardware state. * * Return true if the platform data specifies whether this channel is * allowed to use the FIQ. */ static inline bool s3c24xx_spi_usefiq(struct s3c24xx_spi *hw) { return hw->pdata->use_fiq; } /** * s3c24xx_spi_usingfiq - return if channel is using FIQ * @spi: The hardware state. * * Return whether the channel is currently using the FIQ (separate from * whether the FIQ is claimed). */ static inline bool s3c24xx_spi_usingfiq(struct s3c24xx_spi *spi) { return spi->fiq_inuse; } #else static inline void s3c24xx_spi_initfiq(struct s3c24xx_spi *s) { } static inline void s3c24xx_spi_tryfiq(struct s3c24xx_spi *s) { } static inline bool s3c24xx_spi_usefiq(struct s3c24xx_spi *s) { return false; } static inline bool s3c24xx_spi_usingfiq(struct s3c24xx_spi *s) { return false; } #endif /* CONFIG_SPI_S3C24XX_FIQ */ |
7fba53402 [PATCH] S3C24XX: ... |
404 405 406 |
static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t) { struct s3c24xx_spi *hw = to_hw(spi); |
7fba53402 [PATCH] S3C24XX: ... |
407 408 409 410 |
hw->tx = t->tx_buf; hw->rx = t->rx_buf; hw->len = t->len; hw->count = 0; |
4bb5eba06 spi: spi_s3c24xx ... |
411 |
init_completion(&hw->done); |
bec0806cf spi_s3c24xx: add ... |
412 413 414 |
hw->fiq_inuse = 0; if (s3c24xx_spi_usefiq(hw) && t->len >= 3) s3c24xx_spi_tryfiq(hw); |
7fba53402 [PATCH] S3C24XX: ... |
415 416 |
/* send the first byte */ writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT); |
4bb5eba06 spi: spi_s3c24xx ... |
417 |
|
7fba53402 [PATCH] S3C24XX: ... |
418 |
wait_for_completion(&hw->done); |
7fba53402 [PATCH] S3C24XX: ... |
419 420 |
return hw->count; } |
7d12e780e IRQ: Maintain reg... |
421 |
static irqreturn_t s3c24xx_spi_irq(int irq, void *dev) |
7fba53402 [PATCH] S3C24XX: ... |
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 |
{ struct s3c24xx_spi *hw = dev; unsigned int spsta = readb(hw->regs + S3C2410_SPSTA); unsigned int count = hw->count; if (spsta & S3C2410_SPSTA_DCOL) { dev_dbg(hw->dev, "data-collision "); complete(&hw->done); goto irq_done; } if (!(spsta & S3C2410_SPSTA_READY)) { dev_dbg(hw->dev, "spi not ready for tx? "); complete(&hw->done); goto irq_done; } |
bec0806cf spi_s3c24xx: add ... |
440 441 |
if (!s3c24xx_spi_usingfiq(hw)) { hw->count++; |
7fba53402 [PATCH] S3C24XX: ... |
442 |
|
bec0806cf spi_s3c24xx: add ... |
443 444 |
if (hw->rx) hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT); |
7fba53402 [PATCH] S3C24XX: ... |
445 |
|
bec0806cf spi_s3c24xx: add ... |
446 447 448 449 450 451 452 453 454 455 456 457 |
count++; if (count < hw->len) writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT); else complete(&hw->done); } else { hw->count = hw->len; hw->fiq_inuse = 0; if (hw->rx) hw->rx[hw->len-1] = readb(hw->regs + S3C2410_SPRDAT); |
7fba53402 [PATCH] S3C24XX: ... |
458 |
|
7fba53402 [PATCH] S3C24XX: ... |
459 |
complete(&hw->done); |
bec0806cf spi_s3c24xx: add ... |
460 |
} |
7fba53402 [PATCH] S3C24XX: ... |
461 462 463 464 |
irq_done: return IRQ_HANDLED; } |
5aa6cf302 spi: S3C24XX: res... |
465 466 467 468 469 470 471 472 473 474 475 |
static void s3c24xx_spi_initialsetup(struct s3c24xx_spi *hw) { /* for the moment, permanently enable the clock */ clk_enable(hw->clk); /* program defaults into the registers */ writeb(0xff, hw->regs + S3C2410_SPPRE); writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN); writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON); |
cf46b973f spi_s3c24xx: pin ... |
476 |
|
ee9c1fbfe spi: use generic ... |
477 478 479 480 481 482 483 |
if (hw->pdata) { if (hw->set_cs == s3c24xx_spi_gpiocs) gpio_direction_output(hw->pdata->pin_cs, 1); if (hw->pdata->gpio_setup) hw->pdata->gpio_setup(hw->pdata, 1); } |
5aa6cf302 spi: S3C24XX: res... |
484 |
} |
940ab8896 drivercore: Add h... |
485 |
static int __devinit s3c24xx_spi_probe(struct platform_device *pdev) |
7fba53402 [PATCH] S3C24XX: ... |
486 |
{ |
50f426b55 spi: spi_s3c24xx ... |
487 |
struct s3c2410_spi_info *pdata; |
7fba53402 [PATCH] S3C24XX: ... |
488 489 |
struct s3c24xx_spi *hw; struct spi_master *master; |
7fba53402 [PATCH] S3C24XX: ... |
490 491 |
struct resource *res; int err = 0; |
7fba53402 [PATCH] S3C24XX: ... |
492 493 494 495 496 497 498 499 500 501 502 503 504 |
master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi)); if (master == NULL) { dev_err(&pdev->dev, "No memory for spi_master "); err = -ENOMEM; goto err_nomem; } hw = spi_master_get_devdata(master); memset(hw, 0, sizeof(struct s3c24xx_spi)); hw->master = spi_master_get(master); |
50f426b55 spi: spi_s3c24xx ... |
505 |
hw->pdata = pdata = pdev->dev.platform_data; |
7fba53402 [PATCH] S3C24XX: ... |
506 |
hw->dev = &pdev->dev; |
50f426b55 spi: spi_s3c24xx ... |
507 |
if (pdata == NULL) { |
7fba53402 [PATCH] S3C24XX: ... |
508 509 510 511 512 513 514 515 |
dev_err(&pdev->dev, "No platform data supplied "); err = -ENOENT; goto err_no_pdata; } platform_set_drvdata(pdev, hw); init_completion(&hw->done); |
bec0806cf spi_s3c24xx: add ... |
516 517 518 |
/* initialise fiq handler */ s3c24xx_spi_initfiq(hw); |
d1e778063 spi: spi_s3c24xx ... |
519 |
/* setup the master state. */ |
e7db06b5d spi: move more sp... |
520 521 |
/* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; |
d1e778063 spi: spi_s3c24xx ... |
522 |
master->num_chipselect = hw->pdata->num_cs; |
cb1d0a7a5 spi_s3c24xx: real... |
523 |
master->bus_num = pdata->bus_num; |
d1e778063 spi: spi_s3c24xx ... |
524 |
|
7fba53402 [PATCH] S3C24XX: ... |
525 526 527 528 529 530 |
/* setup the state for the bitbang driver */ hw->bitbang.master = hw->master; hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer; hw->bitbang.chipselect = s3c24xx_spi_chipsel; hw->bitbang.txrx_bufs = s3c24xx_spi_txrx; |
570327d9f spi_s3c24xx: cach... |
531 532 533 |
hw->master->setup = s3c24xx_spi_setup; hw->master->cleanup = s3c24xx_spi_cleanup; |
7fba53402 [PATCH] S3C24XX: ... |
534 535 536 537 538 539 540 541 542 543 544 545 546 |
dev_dbg(hw->dev, "bitbang at %p ", &hw->bitbang); /* find and map our resources */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM "); err = -ENOENT; goto err_no_iores; } |
b5e3afb5e spi_s3c24xx: use ... |
547 |
hw->ioarea = request_mem_region(res->start, resource_size(res), |
7fba53402 [PATCH] S3C24XX: ... |
548 549 550 551 552 553 554 555 |
pdev->name); if (hw->ioarea == NULL) { dev_err(&pdev->dev, "Cannot reserve region "); err = -ENXIO; goto err_no_iores; } |
b5e3afb5e spi_s3c24xx: use ... |
556 |
hw->regs = ioremap(res->start, resource_size(res)); |
7fba53402 [PATCH] S3C24XX: ... |
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 |
if (hw->regs == NULL) { dev_err(&pdev->dev, "Cannot map IO "); err = -ENXIO; goto err_no_iomap; } hw->irq = platform_get_irq(pdev, 0); if (hw->irq < 0) { dev_err(&pdev->dev, "No IRQ specified "); err = -ENOENT; goto err_no_irq; } err = request_irq(hw->irq, s3c24xx_spi_irq, 0, pdev->name, hw); if (err) { dev_err(&pdev->dev, "Cannot claim IRQ "); goto err_no_irq; } hw->clk = clk_get(&pdev->dev, "spi"); if (IS_ERR(hw->clk)) { dev_err(&pdev->dev, "No clock for device "); err = PTR_ERR(hw->clk); goto err_no_clk; } |
7fba53402 [PATCH] S3C24XX: ... |
586 |
/* setup any gpio we can */ |
50f426b55 spi: spi_s3c24xx ... |
587 |
if (!pdata->set_cs) { |
ee9c1fbfe spi: use generic ... |
588 589 590 591 592 |
if (pdata->pin_cs < 0) { dev_err(&pdev->dev, "No chipselect pin "); goto err_register; } |
8736b9270 [PATCH] S3C24XX: ... |
593 |
|
ee9c1fbfe spi: use generic ... |
594 595 596 597 598 599 600 601 602 |
err = gpio_request(pdata->pin_cs, dev_name(&pdev->dev)); if (err) { dev_err(&pdev->dev, "Failed to get gpio for cs "); goto err_register; } hw->set_cs = s3c24xx_spi_gpiocs; gpio_direction_output(pdata->pin_cs, 1); |
8736b9270 [PATCH] S3C24XX: ... |
603 |
} else |
50f426b55 spi: spi_s3c24xx ... |
604 |
hw->set_cs = pdata->set_cs; |
7fba53402 [PATCH] S3C24XX: ... |
605 |
|
ee9c1fbfe spi: use generic ... |
606 |
s3c24xx_spi_initialsetup(hw); |
7fba53402 [PATCH] S3C24XX: ... |
607 608 609 610 611 612 613 614 |
/* register our spi controller */ err = spi_bitbang_start(&hw->bitbang); if (err) { dev_err(&pdev->dev, "Failed to register SPI master "); goto err_register; } |
7fba53402 [PATCH] S3C24XX: ... |
615 616 617 |
return 0; err_register: |
ee9c1fbfe spi: use generic ... |
618 619 |
if (hw->set_cs == s3c24xx_spi_gpiocs) gpio_free(pdata->pin_cs); |
7fba53402 [PATCH] S3C24XX: ... |
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 |
clk_disable(hw->clk); clk_put(hw->clk); err_no_clk: free_irq(hw->irq, hw); err_no_irq: iounmap(hw->regs); err_no_iomap: release_resource(hw->ioarea); kfree(hw->ioarea); err_no_iores: err_no_pdata: |
a419aef8b trivial: remove u... |
635 |
spi_master_put(hw->master); |
7fba53402 [PATCH] S3C24XX: ... |
636 637 638 639 |
err_nomem: return err; } |
940ab8896 drivercore: Add h... |
640 |
static int __devexit s3c24xx_spi_remove(struct platform_device *dev) |
7fba53402 [PATCH] S3C24XX: ... |
641 642 643 644 |
{ struct s3c24xx_spi *hw = platform_get_drvdata(dev); platform_set_drvdata(dev, NULL); |
c6e7b8cb1 spi/spi_s3c24xx: ... |
645 |
spi_bitbang_stop(&hw->bitbang); |
7fba53402 [PATCH] S3C24XX: ... |
646 647 648 649 650 651 |
clk_disable(hw->clk); clk_put(hw->clk); free_irq(hw->irq, hw); iounmap(hw->regs); |
ee9c1fbfe spi: use generic ... |
652 653 |
if (hw->set_cs == s3c24xx_spi_gpiocs) gpio_free(hw->pdata->pin_cs); |
7fba53402 [PATCH] S3C24XX: ... |
654 655 656 657 658 659 660 661 662 |
release_resource(hw->ioarea); kfree(hw->ioarea); spi_master_put(hw->master); return 0; } #ifdef CONFIG_PM |
6d6132070 spi_s3c24xx: use ... |
663 |
static int s3c24xx_spi_suspend(struct device *dev) |
7fba53402 [PATCH] S3C24XX: ... |
664 |
{ |
6d6132070 spi_s3c24xx: use ... |
665 |
struct s3c24xx_spi *hw = platform_get_drvdata(to_platform_device(dev)); |
7fba53402 [PATCH] S3C24XX: ... |
666 |
|
cf46b973f spi_s3c24xx: pin ... |
667 668 |
if (hw->pdata && hw->pdata->gpio_setup) hw->pdata->gpio_setup(hw->pdata, 0); |
7fba53402 [PATCH] S3C24XX: ... |
669 670 671 |
clk_disable(hw->clk); return 0; } |
6d6132070 spi_s3c24xx: use ... |
672 |
static int s3c24xx_spi_resume(struct device *dev) |
7fba53402 [PATCH] S3C24XX: ... |
673 |
{ |
6d6132070 spi_s3c24xx: use ... |
674 |
struct s3c24xx_spi *hw = platform_get_drvdata(to_platform_device(dev)); |
7fba53402 [PATCH] S3C24XX: ... |
675 |
|
5aa6cf302 spi: S3C24XX: res... |
676 |
s3c24xx_spi_initialsetup(hw); |
7fba53402 [PATCH] S3C24XX: ... |
677 678 |
return 0; } |
471452104 const: constify r... |
679 |
static const struct dev_pm_ops s3c24xx_spi_pmops = { |
6d6132070 spi_s3c24xx: use ... |
680 681 682 683 684 |
.suspend = s3c24xx_spi_suspend, .resume = s3c24xx_spi_resume, }; #define S3C24XX_SPI_PMOPS &s3c24xx_spi_pmops |
7fba53402 [PATCH] S3C24XX: ... |
685 |
#else |
6d6132070 spi_s3c24xx: use ... |
686 687 |
#define S3C24XX_SPI_PMOPS NULL #endif /* CONFIG_PM */ |
7fba53402 [PATCH] S3C24XX: ... |
688 |
|
7e38c3c44 spi: fix platform... |
689 |
MODULE_ALIAS("platform:s3c2410-spi"); |
42cde4309 spi_s3c24xx: fix ... |
690 |
static struct platform_driver s3c24xx_spi_driver = { |
940ab8896 drivercore: Add h... |
691 692 |
.probe = s3c24xx_spi_probe, .remove = __devexit_p(s3c24xx_spi_remove), |
7fba53402 [PATCH] S3C24XX: ... |
693 694 695 |
.driver = { .name = "s3c2410-spi", .owner = THIS_MODULE, |
6d6132070 spi_s3c24xx: use ... |
696 |
.pm = S3C24XX_SPI_PMOPS, |
7fba53402 [PATCH] S3C24XX: ... |
697 698 |
}, }; |
940ab8896 drivercore: Add h... |
699 |
module_platform_driver(s3c24xx_spi_driver); |
7fba53402 [PATCH] S3C24XX: ... |
700 701 702 703 |
MODULE_DESCRIPTION("S3C24XX SPI Driver"); MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>"); MODULE_LICENSE("GPL"); |