[go: nahoru, domu]

1ca632f556697d45d67ed5cada7cedf3ddfe0db4bGrant Likely/*
27fba53402eb0fb4209c74469814c583b6455e096Ben Dooks * Copyright (c) 2006 Ben Dooks
3bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * Copyright 2006-2009 Simtec Electronics
47fba53402eb0fb4209c74469814c583b6455e096Ben Dooks *	Ben Dooks <ben@simtec.co.uk>
57fba53402eb0fb4209c74469814c583b6455e096Ben Dooks *
67fba53402eb0fb4209c74469814c583b6455e096Ben Dooks * This program is free software; you can redistribute it and/or modify
77fba53402eb0fb4209c74469814c583b6455e096Ben Dooks * it under the terms of the GNU General Public License version 2 as
87fba53402eb0fb4209c74469814c583b6455e096Ben Dooks * published by the Free Software Foundation.
97fba53402eb0fb4209c74469814c583b6455e096Ben Dooks *
107fba53402eb0fb4209c74469814c583b6455e096Ben Dooks*/
117fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
127fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#include <linux/spinlock.h>
137fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#include <linux/interrupt.h>
147fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#include <linux/delay.h>
157fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#include <linux/errno.h>
167fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#include <linux/err.h>
177fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#include <linux/clk.h>
187fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#include <linux/platform_device.h>
19ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks#include <linux/gpio.h>
201a0c220f791be9e15fd897adee257e72ed4134f8Ben Dooks#include <linux/io.h>
215a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
227fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
237fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#include <linux/spi/spi.h>
247fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#include <linux/spi/spi_bitbang.h>
25f35ef7cab2db0a8b577bef59122b59220efdac44Heiko Stuebner#include <linux/spi/s3c24xx.h>
26d7614de422c0b55db0c1013a6c72330187536004Paul Gortmaker#include <linux/module.h>
277fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
2813622708725990b01fbc6d59d54d93820a726d7cBen Dooks#include <plat/regs-spi.h>
297fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
30bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks#include <asm/fiq.h>
31bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
32ca632f556697d45d67ed5cada7cedf3ddfe0db4bGrant Likely#include "spi-s3c24xx-fiq.h"
33bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
34570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks/**
35570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks * s3c24xx_spi_devstate - per device data
36570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks * @hz: Last frequency calculated for @sppre field.
37570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks * @mode: Last mode setting for the @spcon field.
38570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks * @spcon: Value to write to the SPCON register.
39570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks * @sppre: Value to write to the SPPRE register.
40570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks */
41570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooksstruct s3c24xx_spi_devstate {
42570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	unsigned int	hz;
43570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	unsigned int	mode;
44570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	u8		spcon;
45570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	u8		sppre;
46570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks};
47570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks
48bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksenum spi_fiq_mode {
49bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	FIQ_MODE_NONE	= 0,
50bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	FIQ_MODE_TX	= 1,
51bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	FIQ_MODE_RX	= 2,
52bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	FIQ_MODE_TXRX	= 3,
53bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks};
54bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
557fba53402eb0fb4209c74469814c583b6455e096Ben Dooksstruct s3c24xx_spi {
567fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	/* bitbang has to be first */
577fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	struct spi_bitbang	 bitbang;
587fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	struct completion	 done;
597fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
607fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	void __iomem		*regs;
617fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	int			 irq;
627fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	int			 len;
637fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	int			 count;
647fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
65bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	struct fiq_handler	 fiq_handler;
66bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	enum spi_fiq_mode	 fiq_mode;
67bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	unsigned char		 fiq_inuse;
68bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	unsigned char		 fiq_claimed;
69bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
706c912a3d3356e5e51917941ce8505531c6fab003Arnaud Patard	void			(*set_cs)(struct s3c2410_spi_info *spi,
718736b9270c2f8993ca44c30f64d4c6d25e379687Ben Dooks					  int cs, int pol);
728736b9270c2f8993ca44c30f64d4c6d25e379687Ben Dooks
737fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	/* data buffers */
747fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	const unsigned char	*tx;
757fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	unsigned char		*rx;
767fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
777fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	struct clk		*clk;
787fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	struct spi_master	*master;
797fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	struct spi_device	*curdev;
807fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	struct device		*dev;
817fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	struct s3c2410_spi_info *pdata;
827fba53402eb0fb4209c74469814c583b6455e096Ben Dooks};
837fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
847fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#define SPCON_DEFAULT (S3C2410_SPCON_MSTR | S3C2410_SPCON_SMOD_INT)
857fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#define SPPIN_DEFAULT (S3C2410_SPPIN_KEEP)
867fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
877fba53402eb0fb4209c74469814c583b6455e096Ben Dooksstatic inline struct s3c24xx_spi *to_hw(struct spi_device *sdev)
887fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{
897fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	return spi_master_get_devdata(sdev->master);
907fba53402eb0fb4209c74469814c583b6455e096Ben Dooks}
917fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
928736b9270c2f8993ca44c30f64d4c6d25e379687Ben Dooksstatic void s3c24xx_spi_gpiocs(struct s3c2410_spi_info *spi, int cs, int pol)
938736b9270c2f8993ca44c30f64d4c6d25e379687Ben Dooks{
94ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks	gpio_set_value(spi->pin_cs, pol);
958736b9270c2f8993ca44c30f64d4c6d25e379687Ben Dooks}
968736b9270c2f8993ca44c30f64d4c6d25e379687Ben Dooks
977fba53402eb0fb4209c74469814c583b6455e096Ben Dooksstatic void s3c24xx_spi_chipsel(struct spi_device *spi, int value)
987fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{
99570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	struct s3c24xx_spi_devstate *cs = spi->controller_state;
1007fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	struct s3c24xx_spi *hw = to_hw(spi);
1017fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
102570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks
103570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	/* change the chipselect state and the state of the spi engine clock */
1047fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
1057fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	switch (value) {
1067fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	case BITBANG_CS_INACTIVE:
1073d2c5b415ccd6c322e18adaed3a5b21f7ec555efBen Dooks		hw->set_cs(hw->pdata, spi->chip_select, cspol^1);
108570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks		writeb(cs->spcon, hw->regs + S3C2410_SPCON);
1097fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		break;
1107fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
1117fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	case BITBANG_CS_ACTIVE:
112570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks		writeb(cs->spcon | S3C2410_SPCON_ENSCK,
113570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks		       hw->regs + S3C2410_SPCON);
1143d2c5b415ccd6c322e18adaed3a5b21f7ec555efBen Dooks		hw->set_cs(hw->pdata, spi->chip_select, cspol);
1157fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		break;
1167fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	}
1177fba53402eb0fb4209c74469814c583b6455e096Ben Dooks}
1187fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
119570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooksstatic int s3c24xx_spi_update_state(struct spi_device *spi,
120570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks				    struct spi_transfer *t)
1217fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{
1227fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	struct s3c24xx_spi *hw = to_hw(spi);
123570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	struct s3c24xx_spi_devstate *cs = spi->controller_state;
1247fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	unsigned int hz;
1257fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	unsigned int div;
126b8978784544e8b4e8fbacb558df8580957d4f8a5Ben Dooks	unsigned long clk;
1277fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
1287fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	hz  = t ? t->speed_hz : spi->max_speed_hz;
1297fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
130191529756633052680dd9d23ad63744ca5aa02a1Ben Dooks	if (!hz)
131191529756633052680dd9d23ad63744ca5aa02a1Ben Dooks		hz = spi->max_speed_hz;
132191529756633052680dd9d23ad63744ca5aa02a1Ben Dooks
133570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	if (spi->mode != cs->mode) {
134bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		u8 spcon = SPCON_DEFAULT | S3C2410_SPCON_ENSCK;
135570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks
136570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks		if (spi->mode & SPI_CPHA)
137570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks			spcon |= S3C2410_SPCON_CPHA_FMTB;
1387fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
139570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks		if (spi->mode & SPI_CPOL)
140570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks			spcon |= S3C2410_SPCON_CPOL_HIGH;
1417fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
142570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks		cs->mode = spi->mode;
143570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks		cs->spcon = spcon;
144570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	}
145b8978784544e8b4e8fbacb558df8580957d4f8a5Ben Dooks
146570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	if (cs->hz != hz) {
147570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks		clk = clk_get_rate(hw->clk);
148570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks		div = DIV_ROUND_UP(clk, hz * 2) - 1;
149b8978784544e8b4e8fbacb558df8580957d4f8a5Ben Dooks
150570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks		if (div > 255)
151570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks			div = 255;
1527fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
153570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks		dev_dbg(&spi->dev, "pre-scaler=%d (wanted %d, got %ld)\n",
154570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks			div, hz, clk / (2 * (div + 1)));
155570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks
156570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks		cs->hz = hz;
157570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks		cs->sppre = div;
1587fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	}
1597fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
1607fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	return 0;
1617fba53402eb0fb4209c74469814c583b6455e096Ben Dooks}
1627fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
163570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooksstatic int s3c24xx_spi_setupxfer(struct spi_device *spi,
164570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks				 struct spi_transfer *t)
165570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks{
166570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	struct s3c24xx_spi_devstate *cs = spi->controller_state;
167570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	struct s3c24xx_spi *hw = to_hw(spi);
168570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	int ret;
169570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks
170570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	ret = s3c24xx_spi_update_state(spi, t);
171570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	if (!ret)
172570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks		writeb(cs->sppre, hw->regs + S3C2410_SPPRE);
173570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks
174570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	return ret;
175570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks}
176570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks
1777fba53402eb0fb4209c74469814c583b6455e096Ben Dooksstatic int s3c24xx_spi_setup(struct spi_device *spi)
1787fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{
179570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	struct s3c24xx_spi_devstate *cs = spi->controller_state;
180570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	struct s3c24xx_spi *hw = to_hw(spi);
1817fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	int ret;
1827fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
183570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	/* allocate settings on the first call */
184570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	if (!cs) {
185c586feba880d78cab1882e1faee0395bba2b884fAxel Lin		cs = devm_kzalloc(&spi->dev,
186c586feba880d78cab1882e1faee0395bba2b884fAxel Lin				  sizeof(struct s3c24xx_spi_devstate),
187c586feba880d78cab1882e1faee0395bba2b884fAxel Lin				  GFP_KERNEL);
1880375cff5d8c9da86787167da2740b6e5c50963daJingoo Han		if (!cs)
189570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks			return -ENOMEM;
190570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks
191570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks		cs->spcon = SPCON_DEFAULT;
192570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks		cs->hz = -1;
193570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks		spi->controller_state = cs;
194570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	}
195570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks
196570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	/* initialise the state from the device */
197570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	ret = s3c24xx_spi_update_state(spi, NULL);
198570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	if (ret)
1997fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		return ret;
200570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks
201570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	spin_lock(&hw->bitbang.lock);
202570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	if (!hw->bitbang.busy) {
203570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks		hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE);
204570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks		/* need to ndelay for 0.5 clocktick ? */
2057fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	}
206570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	spin_unlock(&hw->bitbang.lock);
2077fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
2087fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	return 0;
2097fba53402eb0fb4209c74469814c583b6455e096Ben Dooks}
2107fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
2117fba53402eb0fb4209c74469814c583b6455e096Ben Dooksstatic inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count)
2127fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{
2134b1badf5d9ddfc46ad075ca5bfc465972c85cc7cDavid Brownell	return hw->tx ? hw->tx[count] : 0;
2147fba53402eb0fb4209c74469814c583b6455e096Ben Dooks}
2157fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
216bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks#ifdef CONFIG_SPI_S3C24XX_FIQ
217bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks/* Support for FIQ based pseudo-DMA to improve the transfer speed.
218bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks *
219bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * This code uses the assembly helper in spi_s3c24xx_spi.S which is
220bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * used by the FIQ core to move data between main memory and the peripheral
221bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * block. Since this is code running on the processor, there is no problem
222bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * with cache coherency of the buffers, so we can use any buffer we like.
223bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks */
224bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
225bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks/**
226bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * struct spi_fiq_code - FIQ code and header
227bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * @length: The length of the code fragment, excluding this header.
228bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * @ack_offset: The offset from @data to the word to place the IRQ ACK bit at.
229bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * @data: The code itself to install as a FIQ handler.
230bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks */
231bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksstruct spi_fiq_code {
232bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	u32	length;
233bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	u32	ack_offset;
234bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	u8	data[0];
235bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks};
236bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
237bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksextern struct spi_fiq_code s3c24xx_spi_fiq_txrx;
238bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksextern struct spi_fiq_code s3c24xx_spi_fiq_tx;
239bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksextern struct spi_fiq_code s3c24xx_spi_fiq_rx;
240bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
241bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks/**
242bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * ack_bit - turn IRQ into IRQ acknowledgement bit
243bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * @irq: The interrupt number
244bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks *
245bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * Returns the bit to write to the interrupt acknowledge register.
246bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks */
247bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksstatic inline u32 ack_bit(unsigned int irq)
248bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks{
249bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	return 1 << (irq - IRQ_EINT0);
250bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks}
251bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
252bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks/**
253bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * s3c24xx_spi_tryfiq - attempt to claim and setup FIQ for transfer
254bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * @hw: The hardware state.
255bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks *
256bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * Claim the FIQ handler (only one can be active at any one time) and
257bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * then setup the correct transfer code for this transfer.
258bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks *
2593ad2f3fbb961429d2aa627465ae4829758bc7e07Daniel Mack * This call updates all the necessary state information if successful,
260bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * so the caller does not need to do anything more than start the transfer
261bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * as normal, since the IRQ will have been re-routed to the FIQ handler.
262bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks*/
263cfeb33127bfd5c248c8633715d75c04186d8fca9Sachin Kamatstatic void s3c24xx_spi_tryfiq(struct s3c24xx_spi *hw)
264bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks{
265bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	struct pt_regs regs;
266bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	enum spi_fiq_mode mode;
267bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	struct spi_fiq_code *code;
268bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	int ret;
269bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
270bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	if (!hw->fiq_claimed) {
271bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		/* try and claim fiq if we haven't got it, and if not
272bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		 * then return and simply use another transfer method */
273bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
274bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		ret = claim_fiq(&hw->fiq_handler);
275bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		if (ret)
276bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks			return;
277bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	}
278bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
279bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	if (hw->tx && !hw->rx)
280bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		mode = FIQ_MODE_TX;
281bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	else if (hw->rx && !hw->tx)
282bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		mode = FIQ_MODE_RX;
283bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	else
284bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		mode = FIQ_MODE_TXRX;
285bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
286bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	regs.uregs[fiq_rspi] = (long)hw->regs;
287bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	regs.uregs[fiq_rrx]  = (long)hw->rx;
288bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	regs.uregs[fiq_rtx]  = (long)hw->tx + 1;
289bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	regs.uregs[fiq_rcount] = hw->len - 1;
290bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	regs.uregs[fiq_rirq] = (long)S3C24XX_VA_IRQ;
291bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
292bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	set_fiq_regs(&regs);
293bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
294bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	if (hw->fiq_mode != mode) {
295bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		u32 *ack_ptr;
296bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
297bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		hw->fiq_mode = mode;
298bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
299bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		switch (mode) {
300bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		case FIQ_MODE_TX:
301bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks			code = &s3c24xx_spi_fiq_tx;
302bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks			break;
303bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		case FIQ_MODE_RX:
304bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks			code = &s3c24xx_spi_fiq_rx;
305bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks			break;
306bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		case FIQ_MODE_TXRX:
307bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks			code = &s3c24xx_spi_fiq_txrx;
308bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks			break;
309bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		default:
310bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks			code = NULL;
311bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		}
312bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
313bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		BUG_ON(!code);
314bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
315bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		ack_ptr = (u32 *)&code->data[code->ack_offset];
316bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		*ack_ptr = ack_bit(hw->irq);
317bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
318bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		set_fiq_handler(&code->data, code->length);
319bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	}
320bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
321bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	s3c24xx_set_fiq(hw->irq, true);
322bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
323bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	hw->fiq_mode = mode;
324bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	hw->fiq_inuse = 1;
325bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks}
326bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
327bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks/**
328bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * s3c24xx_spi_fiqop - FIQ core code callback
329bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * @pw: Data registered with the handler
330bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * @release: Whether this is a release or a return.
331bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks *
332bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * Called by the FIQ code when another module wants to use the FIQ, so
333bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * return whether we are currently using this or not and then update our
334bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * internal state.
335bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks */
336bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksstatic int s3c24xx_spi_fiqop(void *pw, int release)
337bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks{
338bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	struct s3c24xx_spi *hw = pw;
339bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	int ret = 0;
340bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
341bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	if (release) {
342bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		if (hw->fiq_inuse)
343bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks			ret = -EBUSY;
344bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
345bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		/* note, we do not need to unroute the FIQ, as the FIQ
346bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		 * vector code de-routes it to signal the end of transfer */
347bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
348bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		hw->fiq_mode = FIQ_MODE_NONE;
349bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		hw->fiq_claimed = 0;
350bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	} else {
351bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		hw->fiq_claimed = 1;
352bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	}
353bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
354bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	return ret;
355bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks}
356bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
357bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks/**
358bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * s3c24xx_spi_initfiq - setup the information for the FIQ core
359bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * @hw: The hardware state.
360bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks *
361bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * Setup the fiq_handler block to pass to the FIQ core.
362bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks */
363bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksstatic inline void s3c24xx_spi_initfiq(struct s3c24xx_spi *hw)
364bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks{
365bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	hw->fiq_handler.dev_id = hw;
366bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	hw->fiq_handler.name = dev_name(hw->dev);
367bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	hw->fiq_handler.fiq_op = s3c24xx_spi_fiqop;
368bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks}
369bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
370bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks/**
371bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * s3c24xx_spi_usefiq - return if we should be using FIQ.
372bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * @hw: The hardware state.
373bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks *
374bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * Return true if the platform data specifies whether this channel is
375bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * allowed to use the FIQ.
376bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks */
377bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksstatic inline bool s3c24xx_spi_usefiq(struct s3c24xx_spi *hw)
378bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks{
379bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	return hw->pdata->use_fiq;
380bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks}
381bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
382bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks/**
383bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * s3c24xx_spi_usingfiq - return if channel is using FIQ
384bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * @spi: The hardware state.
385bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks *
386bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * Return whether the channel is currently using the FIQ (separate from
387bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks * whether the FIQ is claimed).
388bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks */
389bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksstatic inline bool s3c24xx_spi_usingfiq(struct s3c24xx_spi *spi)
390bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks{
391bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	return spi->fiq_inuse;
392bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks}
393bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks#else
394bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
395bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksstatic inline void s3c24xx_spi_initfiq(struct s3c24xx_spi *s) { }
396bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksstatic inline void s3c24xx_spi_tryfiq(struct s3c24xx_spi *s) { }
397bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksstatic inline bool s3c24xx_spi_usefiq(struct s3c24xx_spi *s) { return false; }
398bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooksstatic inline bool s3c24xx_spi_usingfiq(struct s3c24xx_spi *s) { return false; }
399bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
400bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks#endif /* CONFIG_SPI_S3C24XX_FIQ */
401bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
4027fba53402eb0fb4209c74469814c583b6455e096Ben Dooksstatic int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
4037fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{
4047fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	struct s3c24xx_spi *hw = to_hw(spi);
4057fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
4067fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	hw->tx = t->tx_buf;
4077fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	hw->rx = t->rx_buf;
4087fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	hw->len = t->len;
4097fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	hw->count = 0;
4107fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
4114bb5eba06b4bc57e30b0f6336c9907e85c395197Ben Dooks	init_completion(&hw->done);
4124bb5eba06b4bc57e30b0f6336c9907e85c395197Ben Dooks
413bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	hw->fiq_inuse = 0;
414bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	if (s3c24xx_spi_usefiq(hw) && t->len >= 3)
415bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		s3c24xx_spi_tryfiq(hw);
416bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
4177fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	/* send the first byte */
4187fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT);
4194bb5eba06b4bc57e30b0f6336c9907e85c395197Ben Dooks
4207fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	wait_for_completion(&hw->done);
4217fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	return hw->count;
4227fba53402eb0fb4209c74469814c583b6455e096Ben Dooks}
4237fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
4247d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t s3c24xx_spi_irq(int irq, void *dev)
4257fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{
4267fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	struct s3c24xx_spi *hw = dev;
4277fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	unsigned int spsta = readb(hw->regs + S3C2410_SPSTA);
4287fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	unsigned int count = hw->count;
4297fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
4307fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	if (spsta & S3C2410_SPSTA_DCOL) {
4317fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		dev_dbg(hw->dev, "data-collision\n");
4327fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		complete(&hw->done);
4337fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		goto irq_done;
4347fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	}
4357fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
4367fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	if (!(spsta & S3C2410_SPSTA_READY)) {
4377fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		dev_dbg(hw->dev, "spi not ready for tx?\n");
4387fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		complete(&hw->done);
4397fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		goto irq_done;
4407fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	}
4417fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
442bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	if (!s3c24xx_spi_usingfiq(hw)) {
443bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		hw->count++;
4447fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
445bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		if (hw->rx)
446bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks			hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT);
4477fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
448bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		count++;
449bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
450bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		if (count < hw->len)
451bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks			writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT);
452bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		else
453bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks			complete(&hw->done);
454bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	} else {
455bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		hw->count = hw->len;
456bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		hw->fiq_inuse = 0;
457bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
458bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks		if (hw->rx)
459bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks			hw->rx[hw->len-1] = readb(hw->regs + S3C2410_SPRDAT);
4607fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
4617fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		complete(&hw->done);
462bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	}
4637fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
4647fba53402eb0fb4209c74469814c583b6455e096Ben Dooks irq_done:
4657fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	return IRQ_HANDLED;
4667fba53402eb0fb4209c74469814c583b6455e096Ben Dooks}
4677fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
4685aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooksstatic void s3c24xx_spi_initialsetup(struct s3c24xx_spi *hw)
4695aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks{
4705aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks	/* for the moment, permanently enable the clock */
4715aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks
4725aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks	clk_enable(hw->clk);
4735aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks
4745aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks	/* program defaults into the registers */
4755aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks
4765aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks	writeb(0xff, hw->regs + S3C2410_SPPRE);
4775aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks	writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN);
4785aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks	writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON);
479cf46b973f72ddf9d1e17d6fde9aa14f61aa1afedBen Dooks
480ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks	if (hw->pdata) {
481ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks		if (hw->set_cs == s3c24xx_spi_gpiocs)
482ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks			gpio_direction_output(hw->pdata->pin_cs, 1);
483ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks
484ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks		if (hw->pdata->gpio_setup)
485ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks			hw->pdata->gpio_setup(hw->pdata, 1);
486ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks	}
4875aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks}
4885aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks
489fd4a319bc933ae93e68935b21924a9ca4ba2d060Grant Likelystatic int s3c24xx_spi_probe(struct platform_device *pdev)
4907fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{
49150f426b55d919dd017af35bb6a08753d1f262920Ben Dooks	struct s3c2410_spi_info *pdata;
4927fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	struct s3c24xx_spi *hw;
4937fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	struct spi_master *master;
4947fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	struct resource *res;
4957fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	int err = 0;
4967fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
4977fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));
4987fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	if (master == NULL) {
4997fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		dev_err(&pdev->dev, "No memory for spi_master\n");
500c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han		return -ENOMEM;
5017fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	}
5027fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
5037fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	hw = spi_master_get_devdata(master);
5047fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	memset(hw, 0, sizeof(struct s3c24xx_spi));
5057fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
50694c69f765f1b4a658d96905ec59928e3e3e07e6aAxel Lin	hw->master = master;
5078074cf063e410a2c0cf1704c3b31002e21f5df7cJingoo Han	hw->pdata = pdata = dev_get_platdata(&pdev->dev);
5087fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	hw->dev = &pdev->dev;
5097fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
51050f426b55d919dd017af35bb6a08753d1f262920Ben Dooks	if (pdata == NULL) {
5117fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		dev_err(&pdev->dev, "No platform data supplied\n");
5127fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		err = -ENOENT;
5137fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		goto err_no_pdata;
5147fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	}
5157fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
5167fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	platform_set_drvdata(pdev, hw);
5177fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	init_completion(&hw->done);
5187fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
519bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	/* initialise fiq handler */
520bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
521bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks	s3c24xx_spi_initfiq(hw);
522bec0806cfec6ded1a7e097bb95279e521a796129Ben Dooks
523d1e7780638a9192f15caf590e0081bf915fdef71Ben Dooks	/* setup the master state. */
524d1e7780638a9192f15caf590e0081bf915fdef71Ben Dooks
525e7db06b5d5afcef15c4c3e61c3a7441ed7ad1407David Brownell	/* the spi->mode bits understood by this driver: */
526e7db06b5d5afcef15c4c3e61c3a7441ed7ad1407David Brownell	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
527e7db06b5d5afcef15c4c3e61c3a7441ed7ad1407David Brownell
528d1e7780638a9192f15caf590e0081bf915fdef71Ben Dooks	master->num_chipselect = hw->pdata->num_cs;
529cb1d0a7a5d2e537f2f6ada22883abee1762e94b2Ben Dooks	master->bus_num = pdata->bus_num;
53008850fa94831d374f4d827a85088f6087836dfc8Axel Lin	master->bits_per_word_mask = SPI_BPW_MASK(8);
531d1e7780638a9192f15caf590e0081bf915fdef71Ben Dooks
5327fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	/* setup the state for the bitbang driver */
5337fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
5347fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	hw->bitbang.master         = hw->master;
5357fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;
5367fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	hw->bitbang.chipselect     = s3c24xx_spi_chipsel;
5377fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	hw->bitbang.txrx_bufs      = s3c24xx_spi_txrx;
538570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks
539570327d9f48b0be5ca626bcfd80266b7ee2001aaBen Dooks	hw->master->setup  = s3c24xx_spi_setup;
5407fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
5417fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang);
5427fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
5437fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	/* find and map our resources */
5447fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
545c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han	hw->regs = devm_ioremap_resource(&pdev->dev, res);
546c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han	if (IS_ERR(hw->regs)) {
547c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han		err = PTR_ERR(hw->regs);
548c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han		goto err_no_pdata;
5497fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	}
5507fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
5517fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	hw->irq = platform_get_irq(pdev, 0);
5527fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	if (hw->irq < 0) {
5537fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		dev_err(&pdev->dev, "No IRQ specified\n");
5547fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		err = -ENOENT;
555c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han		goto err_no_pdata;
5567fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	}
5577fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
558c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han	err = devm_request_irq(&pdev->dev, hw->irq, s3c24xx_spi_irq, 0,
559c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han				pdev->name, hw);
5607fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	if (err) {
5617fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		dev_err(&pdev->dev, "Cannot claim IRQ\n");
562c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han		goto err_no_pdata;
5637fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	}
5647fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
565c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han	hw->clk = devm_clk_get(&pdev->dev, "spi");
5667fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	if (IS_ERR(hw->clk)) {
5677fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		dev_err(&pdev->dev, "No clock for device\n");
5687fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		err = PTR_ERR(hw->clk);
569c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han		goto err_no_pdata;
5707fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	}
5717fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
5727fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	/* setup any gpio we can */
5737fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
57450f426b55d919dd017af35bb6a08753d1f262920Ben Dooks	if (!pdata->set_cs) {
575ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks		if (pdata->pin_cs < 0) {
576ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks			dev_err(&pdev->dev, "No chipselect pin\n");
577b2af045c70aa60f7231b22a363d74a1ab5a6297bJulia Lawall			err = -EINVAL;
578ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks			goto err_register;
579ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks		}
5808736b9270c2f8993ca44c30f64d4c6d25e379687Ben Dooks
581c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han		err = devm_gpio_request(&pdev->dev, pdata->pin_cs,
582c9f722e879953f74d3e09023ba339c98d68f1998Jingoo Han					dev_name(&pdev->dev));
583ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks		if (err) {
584ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks			dev_err(&pdev->dev, "Failed to get gpio for cs\n");
585ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks			goto err_register;
586ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks		}
587ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks
588ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks		hw->set_cs = s3c24xx_spi_gpiocs;
589ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks		gpio_direction_output(pdata->pin_cs, 1);
5908736b9270c2f8993ca44c30f64d4c6d25e379687Ben Dooks	} else
59150f426b55d919dd017af35bb6a08753d1f262920Ben Dooks		hw->set_cs = pdata->set_cs;
5927fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
593ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks	s3c24xx_spi_initialsetup(hw);
594ee9c1fbfe130a20e0f23d1693d6427dac97239bcBen Dooks
5957fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	/* register our spi controller */
5967fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
5977fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	err = spi_bitbang_start(&hw->bitbang);
5987fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	if (err) {
5997fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		dev_err(&pdev->dev, "Failed to register SPI master\n");
6007fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		goto err_register;
6017fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	}
6027fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
6037fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	return 0;
6047fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
6057fba53402eb0fb4209c74469814c583b6455e096Ben Dooks err_register:
6067fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	clk_disable(hw->clk);
6077fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
6087fba53402eb0fb4209c74469814c583b6455e096Ben Dooks err_no_pdata:
609a419aef8b858a2bdb98df60336063d28df4b272fJoe Perches	spi_master_put(hw->master);
6107fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	return err;
6117fba53402eb0fb4209c74469814c583b6455e096Ben Dooks}
6127fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
613fd4a319bc933ae93e68935b21924a9ca4ba2d060Grant Likelystatic int s3c24xx_spi_remove(struct platform_device *dev)
6147fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{
6157fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	struct s3c24xx_spi *hw = platform_get_drvdata(dev);
6167fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
617c6e7b8cb11632a3b3968c6f64e179c7619eb70c0Axel Lin	spi_bitbang_stop(&hw->bitbang);
6187fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	clk_disable(hw->clk);
6197fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	spi_master_put(hw->master);
6207fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	return 0;
6217fba53402eb0fb4209c74469814c583b6455e096Ben Dooks}
6227fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
6237fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
6247fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#ifdef CONFIG_PM
6257fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
6266d61320707ac2960bc820616bd5921885b874780Ben Dooksstatic int s3c24xx_spi_suspend(struct device *dev)
6277fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{
628a1216394e620d0dfbb03c712ae3210e7b77c9e11Axel Lin	struct s3c24xx_spi *hw = dev_get_drvdata(dev);
629380603712072145785f19040b9791f4f6cde414eAxel Lin	int ret;
630380603712072145785f19040b9791f4f6cde414eAxel Lin
631380603712072145785f19040b9791f4f6cde414eAxel Lin	ret = spi_master_suspend(hw->master);
632380603712072145785f19040b9791f4f6cde414eAxel Lin	if (ret)
633380603712072145785f19040b9791f4f6cde414eAxel Lin		return ret;
6347fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
635cf46b973f72ddf9d1e17d6fde9aa14f61aa1afedBen Dooks	if (hw->pdata && hw->pdata->gpio_setup)
636cf46b973f72ddf9d1e17d6fde9aa14f61aa1afedBen Dooks		hw->pdata->gpio_setup(hw->pdata, 0);
637cf46b973f72ddf9d1e17d6fde9aa14f61aa1afedBen Dooks
6387fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	clk_disable(hw->clk);
6397fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	return 0;
6407fba53402eb0fb4209c74469814c583b6455e096Ben Dooks}
6417fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
6426d61320707ac2960bc820616bd5921885b874780Ben Dooksstatic int s3c24xx_spi_resume(struct device *dev)
6437fba53402eb0fb4209c74469814c583b6455e096Ben Dooks{
644a1216394e620d0dfbb03c712ae3210e7b77c9e11Axel Lin	struct s3c24xx_spi *hw = dev_get_drvdata(dev);
6457fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
6465aa6cf302c2758702348aab7457e516d3a5121b9Ben Dooks	s3c24xx_spi_initialsetup(hw);
647380603712072145785f19040b9791f4f6cde414eAxel Lin	return spi_master_resume(hw->master);
6487fba53402eb0fb4209c74469814c583b6455e096Ben Dooks}
6497fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
650471452104b8520337ae2fb48c4e61cd4896e025dAlexey Dobriyanstatic const struct dev_pm_ops s3c24xx_spi_pmops = {
6516d61320707ac2960bc820616bd5921885b874780Ben Dooks	.suspend	= s3c24xx_spi_suspend,
6526d61320707ac2960bc820616bd5921885b874780Ben Dooks	.resume		= s3c24xx_spi_resume,
6536d61320707ac2960bc820616bd5921885b874780Ben Dooks};
6546d61320707ac2960bc820616bd5921885b874780Ben Dooks
6556d61320707ac2960bc820616bd5921885b874780Ben Dooks#define S3C24XX_SPI_PMOPS &s3c24xx_spi_pmops
6567fba53402eb0fb4209c74469814c583b6455e096Ben Dooks#else
6576d61320707ac2960bc820616bd5921885b874780Ben Dooks#define S3C24XX_SPI_PMOPS NULL
6586d61320707ac2960bc820616bd5921885b874780Ben Dooks#endif /* CONFIG_PM */
6597fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
6607e38c3c4453bdb5ffdf8bf0ff0d9a760540f0893Kay SieversMODULE_ALIAS("platform:s3c2410-spi");
66142cde4309b8f2671610be049352df2f8716e8809Ben Dooksstatic struct platform_driver s3c24xx_spi_driver = {
662940ab88962bc1aff3273a8356d64577a6e386736Grant Likely	.probe		= s3c24xx_spi_probe,
663fd4a319bc933ae93e68935b21924a9ca4ba2d060Grant Likely	.remove		= s3c24xx_spi_remove,
6647fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	.driver		= {
6657fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		.name	= "s3c2410-spi",
6667fba53402eb0fb4209c74469814c583b6455e096Ben Dooks		.owner	= THIS_MODULE,
6676d61320707ac2960bc820616bd5921885b874780Ben Dooks		.pm	= S3C24XX_SPI_PMOPS,
6687fba53402eb0fb4209c74469814c583b6455e096Ben Dooks	},
6697fba53402eb0fb4209c74469814c583b6455e096Ben Dooks};
670940ab88962bc1aff3273a8356d64577a6e386736Grant Likelymodule_platform_driver(s3c24xx_spi_driver);
6717fba53402eb0fb4209c74469814c583b6455e096Ben Dooks
6727fba53402eb0fb4209c74469814c583b6455e096Ben DooksMODULE_DESCRIPTION("S3C24XX SPI Driver");
6737fba53402eb0fb4209c74469814c583b6455e096Ben DooksMODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
6747fba53402eb0fb4209c74469814c583b6455e096Ben DooksMODULE_LICENSE("GPL");
675