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

#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
27
#include <linux/spi/s3c24xx.h>
28
#include <linux/module.h>
B
Ben Dooks 已提交
29

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

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

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

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

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

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

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

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

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

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

88

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

B
Ben Dooks 已提交
168 169 170 171 172
		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 已提交
173 174 175 176 177
	}

	return 0;
}

B
Ben Dooks 已提交
178 179 180 181 182 183 184 185 186 187 188 189 190 191
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 已提交
192 193
static int s3c24xx_spi_setup(struct spi_device *spi)
{
B
Ben Dooks 已提交
194 195
	struct s3c24xx_spi_devstate *cs = spi->controller_state;
	struct s3c24xx_spi *hw = to_hw(spi);
B
Ben Dooks 已提交
196 197
	int ret;

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

	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 已提交
220
	}
B
Ben Dooks 已提交
221
	spin_unlock(&hw->bitbang.lock);
B
Ben Dooks 已提交
222 223 224 225

	return 0;
}

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

B
Ben Dooks 已提交
231 232
static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count)
{
233
	return hw->tx ? hw->tx[count] : 0;
B
Ben Dooks 已提交
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 278
#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 已提交
279
 * This call updates all the necessary state information if successful,
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 421
 * 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 已提交
422 423 424 425 426 427 428 429 430
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;

431 432
	init_completion(&hw->done);

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

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

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

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

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

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

468 469 470 471 472 473 474 475 476 477 478 479
		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 已提交
480 481

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

 irq_done:
	return IRQ_HANDLED;
}

488 489 490 491 492 493 494 495 496 497 498
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 已提交
499

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

509
static int s3c24xx_spi_probe(struct platform_device *pdev)
B
Ben Dooks 已提交
510
{
511
	struct s3c2410_spi_info *pdata;
B
Ben Dooks 已提交
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
	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);
528
	hw->pdata = pdata = pdev->dev.platform_data;
B
Ben Dooks 已提交
529 530
	hw->dev = &pdev->dev;

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

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

540 541 542 543
	/* initialise fiq handler */

	s3c24xx_spi_initfiq(hw);

544 545
	/* setup the master state. */

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

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

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

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

	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;
	}

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

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

582
	hw->regs = ioremap(res->start, resource_size(res));
B
Ben Dooks 已提交
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 610
	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 */

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

618 619 620 621 622 623 624 625
		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);
626
	} else
627
		hw->set_cs = pdata->set_cs;
B
Ben Dooks 已提交
628

629 630
	s3c24xx_spi_initialsetup(hw);

B
Ben Dooks 已提交
631 632 633 634 635 636 637 638 639 640 641
	/* 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:
642 643 644
	if (hw->set_cs == s3c24xx_spi_gpiocs)
		gpio_free(pdata->pin_cs);

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

 err_nomem:
	return err;
}

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

	platform_set_drvdata(dev, NULL);

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

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

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

680 681 682
	if (hw->set_cs == s3c24xx_spi_gpiocs)
		gpio_free(hw->pdata->pin_cs);

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

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


#ifdef CONFIG_PM

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

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

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

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

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

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

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

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

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