spi-s3c24xx.c 16.3 KB
Newer Older
G
Grant Likely 已提交
1
/*
B
Ben Dooks 已提交
2
 * Copyright (c) 2006 Ben Dooks
3
 * Copyright 2006-2009 Simtec Electronics
B
Ben Dooks 已提交
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *	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.
 *
*/

#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>
21
#include <linux/gpio.h>
B
Ben Dooks 已提交
22
#include <linux/io.h>
23
#include <linux/slab.h>
B
Ben Dooks 已提交
24 25 26 27

#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>

28
#include <plat/regs-spi.h>
29
#include <mach/spi.h>
B
Ben Dooks 已提交
30

31 32 33
#include <plat/fiq.h>
#include <asm/fiq.h>

G
Grant Likely 已提交
34
#include "spi-s3c24xx-fiq.h"
35

B
Ben Dooks 已提交
36 37 38 39 40 41 42 43 44 45 46 47 48 49
/**
 * 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;
};

50 51 52 53 54 55 56
enum spi_fiq_mode {
	FIQ_MODE_NONE	= 0,
	FIQ_MODE_TX	= 1,
	FIQ_MODE_RX	= 2,
	FIQ_MODE_TXRX	= 3,
};

B
Ben Dooks 已提交
57 58 59 60 61 62 63 64 65 66
struct s3c24xx_spi {
	/* bitbang has to be first */
	struct spi_bitbang	 bitbang;
	struct completion	 done;

	void __iomem		*regs;
	int			 irq;
	int			 len;
	int			 count;

67 68 69 70 71
	struct fiq_handler	 fiq_handler;
	enum spi_fiq_mode	 fiq_mode;
	unsigned char		 fiq_inuse;
	unsigned char		 fiq_claimed;

72
	void			(*set_cs)(struct s3c2410_spi_info *spi,
73 74
					  int cs, int pol);

B
Ben Dooks 已提交
75 76 77 78 79 80 81 82 83 84 85 86
	/* 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;
};

87

B
Ben Dooks 已提交
88 89 90 91 92 93 94 95
#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);
}

96 97
static void s3c24xx_spi_gpiocs(struct s3c2410_spi_info *spi, int cs, int pol)
{
98
	gpio_set_value(spi->pin_cs, pol);
99 100
}

B
Ben Dooks 已提交
101 102
static void s3c24xx_spi_chipsel(struct spi_device *spi, int value)
{
B
Ben Dooks 已提交
103
	struct s3c24xx_spi_devstate *cs = spi->controller_state;
B
Ben Dooks 已提交
104 105
	struct s3c24xx_spi *hw = to_hw(spi);
	unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
B
Ben Dooks 已提交
106 107

	/* change the chipselect state and the state of the spi engine clock */
B
Ben Dooks 已提交
108 109 110

	switch (value) {
	case BITBANG_CS_INACTIVE:
111
		hw->set_cs(hw->pdata, spi->chip_select, cspol^1);
B
Ben Dooks 已提交
112
		writeb(cs->spcon, hw->regs + S3C2410_SPCON);
B
Ben Dooks 已提交
113 114 115
		break;

	case BITBANG_CS_ACTIVE:
B
Ben Dooks 已提交
116 117
		writeb(cs->spcon | S3C2410_SPCON_ENSCK,
		       hw->regs + S3C2410_SPCON);
118
		hw->set_cs(hw->pdata, spi->chip_select, cspol);
B
Ben Dooks 已提交
119 120 121 122
		break;
	}
}

B
Ben Dooks 已提交
123 124
static int s3c24xx_spi_update_state(struct spi_device *spi,
				    struct spi_transfer *t)
B
Ben Dooks 已提交
125 126
{
	struct s3c24xx_spi *hw = to_hw(spi);
B
Ben Dooks 已提交
127
	struct s3c24xx_spi_devstate *cs = spi->controller_state;
B
Ben Dooks 已提交
128 129 130
	unsigned int bpw;
	unsigned int hz;
	unsigned int div;
131
	unsigned long clk;
B
Ben Dooks 已提交
132 133 134 135

	bpw = t ? t->bits_per_word : spi->bits_per_word;
	hz  = t ? t->speed_hz : spi->max_speed_hz;

B
Ben Dooks 已提交
136 137 138 139 140 141
	if (!bpw)
		bpw = 8;

	if (!hz)
		hz = spi->max_speed_hz;

B
Ben Dooks 已提交
142 143 144 145 146
	if (bpw != 8) {
		dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw);
		return -EINVAL;
	}

B
Ben Dooks 已提交
147
	if (spi->mode != cs->mode) {
148
		u8 spcon = SPCON_DEFAULT | S3C2410_SPCON_ENSCK;
B
Ben Dooks 已提交
149 150 151

		if (spi->mode & SPI_CPHA)
			spcon |= S3C2410_SPCON_CPHA_FMTB;
B
Ben Dooks 已提交
152

B
Ben Dooks 已提交
153 154
		if (spi->mode & SPI_CPOL)
			spcon |= S3C2410_SPCON_CPOL_HIGH;
B
Ben Dooks 已提交
155

B
Ben Dooks 已提交
156 157 158
		cs->mode = spi->mode;
		cs->spcon = spcon;
	}
159

B
Ben Dooks 已提交
160 161 162
	if (cs->hz != hz) {
		clk = clk_get_rate(hw->clk);
		div = DIV_ROUND_UP(clk, hz * 2) - 1;
163

B
Ben Dooks 已提交
164 165
		if (div > 255)
			div = 255;
B
Ben Dooks 已提交
166

B
Ben Dooks 已提交
167 168 169 170 171
		dev_dbg(&spi->dev, "pre-scaler=%d (wanted %d, got %ld)\n",
			div, hz, clk / (2 * (div + 1)));

		cs->hz = hz;
		cs->sppre = div;
B
Ben Dooks 已提交
172 173 174 175 176
	}

	return 0;
}

B
Ben Dooks 已提交
177 178 179 180 181 182 183 184 185 186 187 188 189 190
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;
}

B
Ben Dooks 已提交
191 192
static int s3c24xx_spi_setup(struct spi_device *spi)
{
B
Ben Dooks 已提交
193 194
	struct s3c24xx_spi_devstate *cs = spi->controller_state;
	struct s3c24xx_spi *hw = to_hw(spi);
B
Ben Dooks 已提交
195 196
	int ret;

B
Ben Dooks 已提交
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
	/* 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\n");
			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)
B
Ben Dooks 已提交
213
		return ret;
B
Ben Dooks 已提交
214 215 216 217 218

	spin_lock(&hw->bitbang.lock);
	if (!hw->bitbang.busy) {
		hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);
		/* need to ndelay for 0.5 clocktick ? */
B
Ben Dooks 已提交
219
	}
B
Ben Dooks 已提交
220
	spin_unlock(&hw->bitbang.lock);
B
Ben Dooks 已提交
221 222 223 224

	return 0;
}

B
Ben Dooks 已提交
225 226 227 228 229
static void s3c24xx_spi_cleanup(struct spi_device *spi)
{
	kfree(spi->controller_state);
}

B
Ben Dooks 已提交
230 231
static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count)
{
232
	return hw->tx ? hw->tx[count] : 0;
B
Ben Dooks 已提交
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 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
#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.
 *
D
Daniel Mack 已提交
278
 * This call updates all the necessary state information if successful,
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 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
 * 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(&regs);

	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 */

B
Ben Dooks 已提交
421 422 423 424 425 426 427 428 429
static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
{
	struct s3c24xx_spi *hw = to_hw(spi);

	hw->tx = t->tx_buf;
	hw->rx = t->rx_buf;
	hw->len = t->len;
	hw->count = 0;

430 431
	init_completion(&hw->done);

432 433 434 435
	hw->fiq_inuse = 0;
	if (s3c24xx_spi_usefiq(hw) && t->len >= 3)
		s3c24xx_spi_tryfiq(hw);

B
Ben Dooks 已提交
436 437
	/* send the first byte */
	writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT);
438

B
Ben Dooks 已提交
439 440 441 442
	wait_for_completion(&hw->done);
	return hw->count;
}

443
static irqreturn_t s3c24xx_spi_irq(int irq, void *dev)
B
Ben Dooks 已提交
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
{
	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\n");
		complete(&hw->done);
		goto irq_done;
	}

	if (!(spsta & S3C2410_SPSTA_READY)) {
		dev_dbg(hw->dev, "spi not ready for tx?\n");
		complete(&hw->done);
		goto irq_done;
	}

461 462
	if (!s3c24xx_spi_usingfiq(hw)) {
		hw->count++;
B
Ben Dooks 已提交
463

464 465
		if (hw->rx)
			hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT);
B
Ben Dooks 已提交
466

467 468 469 470 471 472 473 474 475 476 477 478
		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);
B
Ben Dooks 已提交
479 480

		complete(&hw->done);
481
	}
B
Ben Dooks 已提交
482 483 484 485 486

 irq_done:
	return IRQ_HANDLED;
}

487 488 489 490 491 492 493 494 495 496 497
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);
B
Ben Dooks 已提交
498

499 500 501 502 503 504 505
	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);
	}
506 507
}

508
static int __devinit s3c24xx_spi_probe(struct platform_device *pdev)
B
Ben Dooks 已提交
509
{
510
	struct s3c2410_spi_info *pdata;
B
Ben Dooks 已提交
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
	struct s3c24xx_spi *hw;
	struct spi_master *master;
	struct resource *res;
	int err = 0;

	master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));
	if (master == NULL) {
		dev_err(&pdev->dev, "No memory for spi_master\n");
		err = -ENOMEM;
		goto err_nomem;
	}

	hw = spi_master_get_devdata(master);
	memset(hw, 0, sizeof(struct s3c24xx_spi));

	hw->master = spi_master_get(master);
527
	hw->pdata = pdata = pdev->dev.platform_data;
B
Ben Dooks 已提交
528 529
	hw->dev = &pdev->dev;

530
	if (pdata == NULL) {
B
Ben Dooks 已提交
531 532 533 534 535 536 537 538
		dev_err(&pdev->dev, "No platform data supplied\n");
		err = -ENOENT;
		goto err_no_pdata;
	}

	platform_set_drvdata(pdev, hw);
	init_completion(&hw->done);

539 540 541 542
	/* initialise fiq handler */

	s3c24xx_spi_initfiq(hw);

543 544
	/* setup the master state. */

545 546 547
	/* the spi->mode bits understood by this driver: */
	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;

548
	master->num_chipselect = hw->pdata->num_cs;
B
Ben Dooks 已提交
549
	master->bus_num = pdata->bus_num;
550

B
Ben Dooks 已提交
551 552 553 554 555 556
	/* 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;
B
Ben Dooks 已提交
557 558 559

	hw->master->setup  = s3c24xx_spi_setup;
	hw->master->cleanup = s3c24xx_spi_cleanup;
B
Ben Dooks 已提交
560 561 562 563 564 565 566 567 568 569 570 571

	dev_dbg(hw->dev, "bitbang at %p\n", &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\n");
		err = -ENOENT;
		goto err_no_iores;
	}

572
	hw->ioarea = request_mem_region(res->start, resource_size(res),
B
Ben Dooks 已提交
573 574 575 576 577 578 579 580
					pdev->name);

	if (hw->ioarea == NULL) {
		dev_err(&pdev->dev, "Cannot reserve region\n");
		err = -ENXIO;
		goto err_no_iores;
	}

581
	hw->regs = ioremap(res->start, resource_size(res));
B
Ben Dooks 已提交
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
	if (hw->regs == NULL) {
		dev_err(&pdev->dev, "Cannot map IO\n");
		err = -ENXIO;
		goto err_no_iomap;
	}

	hw->irq = platform_get_irq(pdev, 0);
	if (hw->irq < 0) {
		dev_err(&pdev->dev, "No IRQ specified\n");
		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\n");
		goto err_no_irq;
	}

	hw->clk = clk_get(&pdev->dev, "spi");
	if (IS_ERR(hw->clk)) {
		dev_err(&pdev->dev, "No clock for device\n");
		err = PTR_ERR(hw->clk);
		goto err_no_clk;
	}

	/* setup any gpio we can */

610
	if (!pdata->set_cs) {
611 612 613 614
		if (pdata->pin_cs < 0) {
			dev_err(&pdev->dev, "No chipselect pin\n");
			goto err_register;
		}
615

616 617 618 619 620 621 622 623
		err = gpio_request(pdata->pin_cs, dev_name(&pdev->dev));
		if (err) {
			dev_err(&pdev->dev, "Failed to get gpio for cs\n");
			goto err_register;
		}

		hw->set_cs = s3c24xx_spi_gpiocs;
		gpio_direction_output(pdata->pin_cs, 1);
624
	} else
625
		hw->set_cs = pdata->set_cs;
B
Ben Dooks 已提交
626

627 628
	s3c24xx_spi_initialsetup(hw);

B
Ben Dooks 已提交
629 630 631 632 633 634 635 636 637 638 639
	/* register our spi controller */

	err = spi_bitbang_start(&hw->bitbang);
	if (err) {
		dev_err(&pdev->dev, "Failed to register SPI master\n");
		goto err_register;
	}

	return 0;

 err_register:
640 641 642
	if (hw->set_cs == s3c24xx_spi_gpiocs)
		gpio_free(pdata->pin_cs);

B
Ben Dooks 已提交
643 644 645 646 647 648 649 650 651 652 653 654 655 656 657
	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:
658
	spi_master_put(hw->master);
B
Ben Dooks 已提交
659 660 661 662 663

 err_nomem:
	return err;
}

664
static int __devexit s3c24xx_spi_remove(struct platform_device *dev)
B
Ben Dooks 已提交
665 666 667 668 669
{
	struct s3c24xx_spi *hw = platform_get_drvdata(dev);

	platform_set_drvdata(dev, NULL);

670
	spi_bitbang_stop(&hw->bitbang);
B
Ben Dooks 已提交
671 672 673 674 675 676 677

	clk_disable(hw->clk);
	clk_put(hw->clk);

	free_irq(hw->irq, hw);
	iounmap(hw->regs);

678 679 680
	if (hw->set_cs == s3c24xx_spi_gpiocs)
		gpio_free(hw->pdata->pin_cs);

B
Ben Dooks 已提交
681 682 683 684 685 686 687 688 689 690
	release_resource(hw->ioarea);
	kfree(hw->ioarea);

	spi_master_put(hw->master);
	return 0;
}


#ifdef CONFIG_PM

B
Ben Dooks 已提交
691
static int s3c24xx_spi_suspend(struct device *dev)
B
Ben Dooks 已提交
692
{
B
Ben Dooks 已提交
693
	struct s3c24xx_spi *hw = platform_get_drvdata(to_platform_device(dev));
B
Ben Dooks 已提交
694

B
Ben Dooks 已提交
695 696 697
	if (hw->pdata && hw->pdata->gpio_setup)
		hw->pdata->gpio_setup(hw->pdata, 0);

B
Ben Dooks 已提交
698 699 700 701
	clk_disable(hw->clk);
	return 0;
}

B
Ben Dooks 已提交
702
static int s3c24xx_spi_resume(struct device *dev)
B
Ben Dooks 已提交
703
{
B
Ben Dooks 已提交
704
	struct s3c24xx_spi *hw = platform_get_drvdata(to_platform_device(dev));
B
Ben Dooks 已提交
705

706
	s3c24xx_spi_initialsetup(hw);
B
Ben Dooks 已提交
707 708 709
	return 0;
}

710
static const struct dev_pm_ops s3c24xx_spi_pmops = {
B
Ben Dooks 已提交
711 712 713 714 715
	.suspend	= s3c24xx_spi_suspend,
	.resume		= s3c24xx_spi_resume,
};

#define S3C24XX_SPI_PMOPS &s3c24xx_spi_pmops
B
Ben Dooks 已提交
716
#else
B
Ben Dooks 已提交
717 718
#define S3C24XX_SPI_PMOPS NULL
#endif /* CONFIG_PM */
B
Ben Dooks 已提交
719

720
MODULE_ALIAS("platform:s3c2410-spi");
B
Ben Dooks 已提交
721
static struct platform_driver s3c24xx_spi_driver = {
722 723
	.probe		= s3c24xx_spi_probe,
	.remove		= __devexit_p(s3c24xx_spi_remove),
B
Ben Dooks 已提交
724 725 726
	.driver		= {
		.name	= "s3c2410-spi",
		.owner	= THIS_MODULE,
B
Ben Dooks 已提交
727
		.pm	= S3C24XX_SPI_PMOPS,
B
Ben Dooks 已提交
728 729
	},
};
730
module_platform_driver(s3c24xx_spi_driver);
B
Ben Dooks 已提交
731 732 733 734

MODULE_DESCRIPTION("S3C24XX SPI Driver");
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_LICENSE("GPL");