Blame view

drivers/spi/spi-s3c64xx.c 39.4 KB
78b5d705b   Andi Shyti   spi: s3c64xx: add...
1
2
3
4
  // SPDX-License-Identifier: GPL-2.0+
  //
  // Copyright (c) 2009 Samsung Electronics Co., Ltd.
  //      Jaswinder Singh <jassi.brar@samsung.com>
230d42d42   Jassi Brar   spi: Add s3c64xx ...
5
6
7
  
  #include <linux/init.h>
  #include <linux/module.h>
c2573128a   Mark Brown   spi/s3c64xx: Log ...
8
  #include <linux/interrupt.h>
230d42d42   Jassi Brar   spi: Add s3c64xx ...
9
10
11
  #include <linux/delay.h>
  #include <linux/clk.h>
  #include <linux/dma-mapping.h>
788437273   Arnd Bergmann   spi: s3c64xx: mov...
12
  #include <linux/dmaengine.h>
230d42d42   Jassi Brar   spi: Add s3c64xx ...
13
  #include <linux/platform_device.h>
b97b66217   Mark Brown   spi/s3c64xx: Impl...
14
  #include <linux/pm_runtime.h>
230d42d42   Jassi Brar   spi: Add s3c64xx ...
15
  #include <linux/spi/spi.h>
1c20c200e   Thomas Abraham   spi: s3c64xx: Rem...
16
  #include <linux/gpio.h>
2b9080754   Thomas Abraham   spi: s3c64xx: add...
17
18
  #include <linux/of.h>
  #include <linux/of_gpio.h>
230d42d42   Jassi Brar   spi: Add s3c64xx ...
19

436d42c61   Arnd Bergmann   ARM: samsung: mov...
20
  #include <linux/platform_data/spi-s3c64xx.h>
230d42d42   Jassi Brar   spi: Add s3c64xx ...
21

bf77cba95   Padmavathi Venna   spi: s3c64xx: add...
22
  #define MAX_SPI_PORTS		6
7e9955567   Girish K S   spi: s3c64xx: add...
23
  #define S3C64XX_SPI_QUIRK_POLL		(1 << 0)
bf77cba95   Padmavathi Venna   spi: s3c64xx: add...
24
  #define S3C64XX_SPI_QUIRK_CS_AUTO	(1 << 1)
483867ee2   Heiner Kallweit   spi: s3c64xx: ext...
25
  #define AUTOSUSPEND_TIMEOUT	2000
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
26

230d42d42   Jassi Brar   spi: Add s3c64xx ...
27
28
29
30
  /* Registers and bit-fields */
  
  #define S3C64XX_SPI_CH_CFG		0x00
  #define S3C64XX_SPI_CLK_CFG		0x04
bfbd0ea85   Sylwester Nawrocki   spi: spi-s3c64xx:...
31
  #define S3C64XX_SPI_MODE_CFG		0x08
913ba5c9e   Łukasz Stelmach   spi: spi-s3c64xx:...
32
  #define S3C64XX_SPI_CS_REG		0x0C
230d42d42   Jassi Brar   spi: Add s3c64xx ...
33
34
35
36
  #define S3C64XX_SPI_INT_EN		0x10
  #define S3C64XX_SPI_STATUS		0x14
  #define S3C64XX_SPI_TX_DATA		0x18
  #define S3C64XX_SPI_RX_DATA		0x1C
bfbd0ea85   Sylwester Nawrocki   spi: spi-s3c64xx:...
37
38
39
  #define S3C64XX_SPI_PACKET_CNT		0x20
  #define S3C64XX_SPI_PENDING_CLR		0x24
  #define S3C64XX_SPI_SWAP_CFG		0x28
230d42d42   Jassi Brar   spi: Add s3c64xx ...
40
41
42
43
44
45
46
47
48
49
50
51
52
  #define S3C64XX_SPI_FB_CLK		0x2C
  
  #define S3C64XX_SPI_CH_HS_EN		(1<<6)	/* High Speed Enable */
  #define S3C64XX_SPI_CH_SW_RST		(1<<5)
  #define S3C64XX_SPI_CH_SLAVE		(1<<4)
  #define S3C64XX_SPI_CPOL_L		(1<<3)
  #define S3C64XX_SPI_CPHA_B		(1<<2)
  #define S3C64XX_SPI_CH_RXCH_ON		(1<<1)
  #define S3C64XX_SPI_CH_TXCH_ON		(1<<0)
  
  #define S3C64XX_SPI_CLKSEL_SRCMSK	(3<<9)
  #define S3C64XX_SPI_CLKSEL_SRCSHFT	9
  #define S3C64XX_SPI_ENCLK_ENABLE	(1<<8)
75bf33611   Jingoo Han   spi/s3c64xx: fix ...
53
  #define S3C64XX_SPI_PSR_MASK		0xff
230d42d42   Jassi Brar   spi: Add s3c64xx ...
54
55
56
57
58
59
60
61
62
63
64
65
  
  #define S3C64XX_SPI_MODE_CH_TSZ_BYTE		(0<<29)
  #define S3C64XX_SPI_MODE_CH_TSZ_HALFWORD	(1<<29)
  #define S3C64XX_SPI_MODE_CH_TSZ_WORD		(2<<29)
  #define S3C64XX_SPI_MODE_CH_TSZ_MASK		(3<<29)
  #define S3C64XX_SPI_MODE_BUS_TSZ_BYTE		(0<<17)
  #define S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD	(1<<17)
  #define S3C64XX_SPI_MODE_BUS_TSZ_WORD		(2<<17)
  #define S3C64XX_SPI_MODE_BUS_TSZ_MASK		(3<<17)
  #define S3C64XX_SPI_MODE_RXDMA_ON		(1<<2)
  #define S3C64XX_SPI_MODE_TXDMA_ON		(1<<1)
  #define S3C64XX_SPI_MODE_4BURST			(1<<0)
913ba5c9e   Łukasz Stelmach   spi: spi-s3c64xx:...
66
67
68
  #define S3C64XX_SPI_CS_NSC_CNT_2		(2<<4)
  #define S3C64XX_SPI_CS_AUTO			(1<<1)
  #define S3C64XX_SPI_CS_SIG_INACT		(1<<0)
230d42d42   Jassi Brar   spi: Add s3c64xx ...
69

230d42d42   Jassi Brar   spi: Add s3c64xx ...
70
71
72
73
74
75
76
77
78
  #define S3C64XX_SPI_INT_TRAILING_EN		(1<<6)
  #define S3C64XX_SPI_INT_RX_OVERRUN_EN		(1<<5)
  #define S3C64XX_SPI_INT_RX_UNDERRUN_EN		(1<<4)
  #define S3C64XX_SPI_INT_TX_OVERRUN_EN		(1<<3)
  #define S3C64XX_SPI_INT_TX_UNDERRUN_EN		(1<<2)
  #define S3C64XX_SPI_INT_RX_FIFORDY_EN		(1<<1)
  #define S3C64XX_SPI_INT_TX_FIFORDY_EN		(1<<0)
  
  #define S3C64XX_SPI_ST_RX_OVERRUN_ERR		(1<<5)
bfbd0ea85   Sylwester Nawrocki   spi: spi-s3c64xx:...
79
  #define S3C64XX_SPI_ST_RX_UNDERRUN_ERR		(1<<4)
230d42d42   Jassi Brar   spi: Add s3c64xx ...
80
  #define S3C64XX_SPI_ST_TX_OVERRUN_ERR		(1<<3)
bfbd0ea85   Sylwester Nawrocki   spi: spi-s3c64xx:...
81
  #define S3C64XX_SPI_ST_TX_UNDERRUN_ERR		(1<<2)
230d42d42   Jassi Brar   spi: Add s3c64xx ...
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  #define S3C64XX_SPI_ST_RX_FIFORDY		(1<<1)
  #define S3C64XX_SPI_ST_TX_FIFORDY		(1<<0)
  
  #define S3C64XX_SPI_PACKET_CNT_EN		(1<<16)
  
  #define S3C64XX_SPI_PND_TX_UNDERRUN_CLR		(1<<4)
  #define S3C64XX_SPI_PND_TX_OVERRUN_CLR		(1<<3)
  #define S3C64XX_SPI_PND_RX_UNDERRUN_CLR		(1<<2)
  #define S3C64XX_SPI_PND_RX_OVERRUN_CLR		(1<<1)
  #define S3C64XX_SPI_PND_TRAILING_CLR		(1<<0)
  
  #define S3C64XX_SPI_SWAP_RX_HALF_WORD		(1<<7)
  #define S3C64XX_SPI_SWAP_RX_BYTE		(1<<6)
  #define S3C64XX_SPI_SWAP_RX_BIT			(1<<5)
  #define S3C64XX_SPI_SWAP_RX_EN			(1<<4)
  #define S3C64XX_SPI_SWAP_TX_HALF_WORD		(1<<3)
  #define S3C64XX_SPI_SWAP_TX_BYTE		(1<<2)
  #define S3C64XX_SPI_SWAP_TX_BIT			(1<<1)
  #define S3C64XX_SPI_SWAP_TX_EN			(1<<0)
bfbd0ea85   Sylwester Nawrocki   spi: spi-s3c64xx:...
101
  #define S3C64XX_SPI_FBCLK_MSK			(3<<0)
230d42d42   Jassi Brar   spi: Add s3c64xx ...
102

a5238e360   Thomas Abraham   spi: s3c64xx: mov...
103
104
105
106
107
108
  #define FIFO_LVL_MASK(i) ((i)->port_conf->fifo_lvl_mask[i->port_id])
  #define S3C64XX_SPI_ST_TX_DONE(v, i) (((v) & \
  				(1 << (i)->port_conf->tx_st_done)) ? 1 : 0)
  #define TX_FIFO_LVL(v, i) (((v) >> 6) & FIFO_LVL_MASK(i))
  #define RX_FIFO_LVL(v, i) (((v) >> (i)->port_conf->rx_lvl_offset) & \
  					FIFO_LVL_MASK(i))
230d42d42   Jassi Brar   spi: Add s3c64xx ...
109
110
111
112
113
114
115
  
  #define S3C64XX_SPI_MAX_TRAILCNT	0x3ff
  #define S3C64XX_SPI_TRAILCNT_OFF	19
  
  #define S3C64XX_SPI_TRAILCNT		S3C64XX_SPI_MAX_TRAILCNT
  
  #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
7e9955567   Girish K S   spi: s3c64xx: add...
116
  #define is_polling(x)	(x->port_conf->quirks & S3C64XX_SPI_QUIRK_POLL)
230d42d42   Jassi Brar   spi: Add s3c64xx ...
117

230d42d42   Jassi Brar   spi: Add s3c64xx ...
118
119
  #define RXBUSY    (1<<2)
  #define TXBUSY    (1<<3)
82ab8cd7e   Boojin Kim   spi/s3c64xx: Merg...
120
  struct s3c64xx_spi_dma_data {
788437273   Arnd Bergmann   spi: s3c64xx: mov...
121
  	struct dma_chan *ch;
2f4db6f70   Łukasz Stelmach   spi: spi-s3c64xx:...
122
  	dma_cookie_t cookie;
c10356b98   Arnd Bergmann   spi/s3c64xx: use ...
123
  	enum dma_transfer_direction direction;
82ab8cd7e   Boojin Kim   spi/s3c64xx: Merg...
124
  };
230d42d42   Jassi Brar   spi: Add s3c64xx ...
125
  /**
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
126
127
128
129
   * struct s3c64xx_spi_info - SPI Controller hardware info
   * @fifo_lvl_mask: Bit-mask for {TX|RX}_FIFO_LVL bits in SPI_STATUS register.
   * @rx_lvl_offset: Bit offset of RX_FIFO_LVL bits in SPI_STATUS regiter.
   * @tx_st_done: Bit offset of TX_DONE bit in SPI_STATUS regiter.
6b8d1e473   Lee Jones   spi: spi-s3c64xx:...
130
   * @quirks: Bitmask of known quirks
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
131
132
133
   * @high_speed: True, if the controller supports HIGH_SPEED_EN bit.
   * @clk_from_cmu: True, if the controller does not include a clock mux and
   *	prescaler unit.
6b8d1e473   Lee Jones   spi: spi-s3c64xx:...
134
   * @clk_ioclk: True if clock is present on this device
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
135
136
137
138
139
140
141
142
143
144
   *
   * The Samsung s3c64xx SPI controller are used on various Samsung SoC's but
   * differ in some aspects such as the size of the fifo and spi bus clock
   * setup. Such differences are specified to the driver using this structure
   * which is provided as driver data to the driver.
   */
  struct s3c64xx_spi_port_config {
  	int	fifo_lvl_mask[MAX_SPI_PORTS];
  	int	rx_lvl_offset;
  	int	tx_st_done;
7e9955567   Girish K S   spi: s3c64xx: add...
145
  	int	quirks;
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
146
147
  	bool	high_speed;
  	bool	clk_from_cmu;
7990b0081   Andi Shyti   spi: s3c64xx: add...
148
  	bool	clk_ioclk;
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
149
150
151
  };
  
  /**
230d42d42   Jassi Brar   spi: Add s3c64xx ...
152
153
   * struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver.
   * @clk: Pointer to the spi clock.
b0d5d6e55   Jassi Brar   spi/s3c64xx: Move...
154
   * @src_clk: Pointer to the clock used to generate SPI signals.
7990b0081   Andi Shyti   spi: s3c64xx: add...
155
   * @ioclk: Pointer to the i/o clock between master and slave
6b8d1e473   Lee Jones   spi: spi-s3c64xx:...
156
   * @pdev: Pointer to device's platform device data
230d42d42   Jassi Brar   spi: Add s3c64xx ...
157
   * @master: Pointer to the SPI Protocol master.
230d42d42   Jassi Brar   spi: Add s3c64xx ...
158
   * @cntrlr_info: Platform specific data for the controller this driver manages.
230d42d42   Jassi Brar   spi: Add s3c64xx ...
159
160
   * @lock: Controller specific lock.
   * @state: Set of FLAGS to indicate status.
230d42d42   Jassi Brar   spi: Add s3c64xx ...
161
162
163
164
165
   * @sfr_start: BUS address of SPI controller regs.
   * @regs: Pointer to ioremap'ed controller registers.
   * @xfer_completion: To indicate completion of xfer task.
   * @cur_mode: Stores the active configuration of the controller.
   * @cur_bpw: Stores the active bits per word settings.
6b8d1e473   Lee Jones   spi: spi-s3c64xx:...
166
167
168
169
170
   * @cur_speed: Current clock speed
   * @rx_dma: Local receive DMA data (e.g. chan and direction)
   * @tx_dma: Local transmit DMA data (e.g. chan and direction)
   * @port_conf: Local SPI port configuartion data
   * @port_id: Port identification number
230d42d42   Jassi Brar   spi: Add s3c64xx ...
171
172
173
174
   */
  struct s3c64xx_spi_driver_data {
  	void __iomem                    *regs;
  	struct clk                      *clk;
b0d5d6e55   Jassi Brar   spi/s3c64xx: Move...
175
  	struct clk                      *src_clk;
7990b0081   Andi Shyti   spi: s3c64xx: add...
176
  	struct clk                      *ioclk;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
177
178
  	struct platform_device          *pdev;
  	struct spi_master               *master;
58d547814   Łukasz Stelmach   spi: spi-s3c64xx:...
179
  	struct s3c64xx_spi_info         *cntrlr_info;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
180
  	spinlock_t                      lock;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
181
182
183
184
185
  	unsigned long                   sfr_start;
  	struct completion               xfer_completion;
  	unsigned                        state;
  	unsigned                        cur_mode, cur_bpw;
  	unsigned                        cur_speed;
82ab8cd7e   Boojin Kim   spi/s3c64xx: Merg...
186
187
  	struct s3c64xx_spi_dma_data	rx_dma;
  	struct s3c64xx_spi_dma_data	tx_dma;
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
188
189
  	struct s3c64xx_spi_port_config	*port_conf;
  	unsigned int			port_id;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
190
  };
3655d30c0   Sylwester Nawrocki   spi: spi-s3c64xx:...
191
  static void s3c64xx_flush_fifo(struct s3c64xx_spi_driver_data *sdd)
230d42d42   Jassi Brar   spi: Add s3c64xx ...
192
  {
230d42d42   Jassi Brar   spi: Add s3c64xx ...
193
194
195
196
197
198
199
  	void __iomem *regs = sdd->regs;
  	unsigned long loops;
  	u32 val;
  
  	writel(0, regs + S3C64XX_SPI_PACKET_CNT);
  
  	val = readl(regs + S3C64XX_SPI_CH_CFG);
7d859ff49   Kyoungil Kim   spi: Change FIFO ...
200
201
202
203
  	val &= ~(S3C64XX_SPI_CH_RXCH_ON | S3C64XX_SPI_CH_TXCH_ON);
  	writel(val, regs + S3C64XX_SPI_CH_CFG);
  
  	val = readl(regs + S3C64XX_SPI_CH_CFG);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
204
205
206
207
208
209
210
211
  	val |= S3C64XX_SPI_CH_SW_RST;
  	val &= ~S3C64XX_SPI_CH_HS_EN;
  	writel(val, regs + S3C64XX_SPI_CH_CFG);
  
  	/* Flush TxFIFO*/
  	loops = msecs_to_loops(1);
  	do {
  		val = readl(regs + S3C64XX_SPI_STATUS);
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
212
  	} while (TX_FIFO_LVL(val, sdd) && loops--);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
213

be7852a83   Mark Brown   spi/spi_s3c64xx: ...
214
215
216
  	if (loops == 0)
  		dev_warn(&sdd->pdev->dev, "Timed out flushing TX FIFO
  ");
230d42d42   Jassi Brar   spi: Add s3c64xx ...
217
218
219
220
  	/* Flush RxFIFO*/
  	loops = msecs_to_loops(1);
  	do {
  		val = readl(regs + S3C64XX_SPI_STATUS);
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
221
  		if (RX_FIFO_LVL(val, sdd))
230d42d42   Jassi Brar   spi: Add s3c64xx ...
222
223
224
225
  			readl(regs + S3C64XX_SPI_RX_DATA);
  		else
  			break;
  	} while (loops--);
be7852a83   Mark Brown   spi/spi_s3c64xx: ...
226
227
228
  	if (loops == 0)
  		dev_warn(&sdd->pdev->dev, "Timed out flushing RX FIFO
  ");
230d42d42   Jassi Brar   spi: Add s3c64xx ...
229
230
231
232
233
234
235
  	val = readl(regs + S3C64XX_SPI_CH_CFG);
  	val &= ~S3C64XX_SPI_CH_SW_RST;
  	writel(val, regs + S3C64XX_SPI_CH_CFG);
  
  	val = readl(regs + S3C64XX_SPI_MODE_CFG);
  	val &= ~(S3C64XX_SPI_MODE_TXDMA_ON | S3C64XX_SPI_MODE_RXDMA_ON);
  	writel(val, regs + S3C64XX_SPI_MODE_CFG);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
236
  }
82ab8cd7e   Boojin Kim   spi/s3c64xx: Merg...
237
  static void s3c64xx_spi_dmacb(void *data)
39d3e8074   Boojin Kim   spi/s3c64xx: Add ...
238
  {
82ab8cd7e   Boojin Kim   spi/s3c64xx: Merg...
239
240
  	struct s3c64xx_spi_driver_data *sdd;
  	struct s3c64xx_spi_dma_data *dma = data;
39d3e8074   Boojin Kim   spi/s3c64xx: Add ...
241
  	unsigned long flags;
054ebcc4a   Kyoungil Kim   spi: Compatibilit...
242
  	if (dma->direction == DMA_DEV_TO_MEM)
82ab8cd7e   Boojin Kim   spi/s3c64xx: Merg...
243
244
245
246
247
  		sdd = container_of(data,
  			struct s3c64xx_spi_driver_data, rx_dma);
  	else
  		sdd = container_of(data,
  			struct s3c64xx_spi_driver_data, tx_dma);
39d3e8074   Boojin Kim   spi/s3c64xx: Add ...
248
  	spin_lock_irqsave(&sdd->lock, flags);
054ebcc4a   Kyoungil Kim   spi: Compatibilit...
249
  	if (dma->direction == DMA_DEV_TO_MEM) {
82ab8cd7e   Boojin Kim   spi/s3c64xx: Merg...
250
251
252
253
254
255
256
257
  		sdd->state &= ~RXBUSY;
  		if (!(sdd->state & TXBUSY))
  			complete(&sdd->xfer_completion);
  	} else {
  		sdd->state &= ~TXBUSY;
  		if (!(sdd->state & RXBUSY))
  			complete(&sdd->xfer_completion);
  	}
39d3e8074   Boojin Kim   spi/s3c64xx: Add ...
258
259
260
  
  	spin_unlock_irqrestore(&sdd->lock, flags);
  }
2f4db6f70   Łukasz Stelmach   spi: spi-s3c64xx:...
261
  static int prepare_dma(struct s3c64xx_spi_dma_data *dma,
6ad45a27c   Mark Brown   spi: Make core DM...
262
  			struct sg_table *sgt)
788437273   Arnd Bergmann   spi: s3c64xx: mov...
263
264
265
  {
  	struct s3c64xx_spi_driver_data *sdd;
  	struct dma_slave_config config;
788437273   Arnd Bergmann   spi: s3c64xx: mov...
266
  	struct dma_async_tx_descriptor *desc;
2f4db6f70   Łukasz Stelmach   spi: spi-s3c64xx:...
267
  	int ret;
788437273   Arnd Bergmann   spi: s3c64xx: mov...
268

b1a8e78d1   Tomasz Figa   spi: s3c64xx: Zer...
269
  	memset(&config, 0, sizeof(config));
788437273   Arnd Bergmann   spi: s3c64xx: mov...
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
  	if (dma->direction == DMA_DEV_TO_MEM) {
  		sdd = container_of((void *)dma,
  			struct s3c64xx_spi_driver_data, rx_dma);
  		config.direction = dma->direction;
  		config.src_addr = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
  		config.src_addr_width = sdd->cur_bpw / 8;
  		config.src_maxburst = 1;
  		dmaengine_slave_config(dma->ch, &config);
  	} else {
  		sdd = container_of((void *)dma,
  			struct s3c64xx_spi_driver_data, tx_dma);
  		config.direction = dma->direction;
  		config.dst_addr = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
  		config.dst_addr_width = sdd->cur_bpw / 8;
  		config.dst_maxburst = 1;
  		dmaengine_slave_config(dma->ch, &config);
  	}
6ad45a27c   Mark Brown   spi: Make core DM...
287
288
  	desc = dmaengine_prep_slave_sg(dma->ch, sgt->sgl, sgt->nents,
  				       dma->direction, DMA_PREP_INTERRUPT);
2f4db6f70   Łukasz Stelmach   spi: spi-s3c64xx:...
289
290
291
292
293
  	if (!desc) {
  		dev_err(&sdd->pdev->dev, "unable to prepare %s scatterlist",
  			dma->direction == DMA_DEV_TO_MEM ? "rx" : "tx");
  		return -ENOMEM;
  	}
788437273   Arnd Bergmann   spi: s3c64xx: mov...
294
295
296
  
  	desc->callback = s3c64xx_spi_dmacb;
  	desc->callback_param = dma;
2f4db6f70   Łukasz Stelmach   spi: spi-s3c64xx:...
297
298
299
300
301
302
  	dma->cookie = dmaengine_submit(desc);
  	ret = dma_submit_error(dma->cookie);
  	if (ret) {
  		dev_err(&sdd->pdev->dev, "DMA submission failed");
  		return -EIO;
  	}
788437273   Arnd Bergmann   spi: s3c64xx: mov...
303
  	dma_async_issue_pending(dma->ch);
2f4db6f70   Łukasz Stelmach   spi: spi-s3c64xx:...
304
  	return 0;
788437273   Arnd Bergmann   spi: s3c64xx: mov...
305
  }
aa4964c4e   Andi Shyti   spi: s3c64xx: gro...
306
307
308
309
  static void s3c64xx_spi_set_cs(struct spi_device *spi, bool enable)
  {
  	struct s3c64xx_spi_driver_data *sdd =
  					spi_master_get_devdata(spi->master);
a92e7c3d8   Andi Shyti   spi: s3c64xx: con...
310
311
  	if (sdd->cntrlr_info->no_cs)
  		return;
aa4964c4e   Andi Shyti   spi: s3c64xx: gro...
312
313
  	if (enable) {
  		if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO)) {
913ba5c9e   Łukasz Stelmach   spi: spi-s3c64xx:...
314
  			writel(0, sdd->regs + S3C64XX_SPI_CS_REG);
aa4964c4e   Andi Shyti   spi: s3c64xx: gro...
315
  		} else {
913ba5c9e   Łukasz Stelmach   spi: spi-s3c64xx:...
316
  			u32 ssel = readl(sdd->regs + S3C64XX_SPI_CS_REG);
aa4964c4e   Andi Shyti   spi: s3c64xx: gro...
317

913ba5c9e   Łukasz Stelmach   spi: spi-s3c64xx:...
318
319
320
  			ssel |= (S3C64XX_SPI_CS_AUTO |
  						S3C64XX_SPI_CS_NSC_CNT_2);
  			writel(ssel, sdd->regs + S3C64XX_SPI_CS_REG);
aa4964c4e   Andi Shyti   spi: s3c64xx: gro...
321
322
323
  		}
  	} else {
  		if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
913ba5c9e   Łukasz Stelmach   spi: spi-s3c64xx:...
324
325
  			writel(S3C64XX_SPI_CS_SIG_INACT,
  			       sdd->regs + S3C64XX_SPI_CS_REG);
aa4964c4e   Andi Shyti   spi: s3c64xx: gro...
326
327
  	}
  }
788437273   Arnd Bergmann   spi: s3c64xx: mov...
328
329
330
  static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
  {
  	struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi);
788437273   Arnd Bergmann   spi: s3c64xx: mov...
331

730d9d4d1   Andi Shyti   spi: s3c64xx: sim...
332
333
  	if (is_polling(sdd))
  		return 0;
730d9d4d1   Andi Shyti   spi: s3c64xx: sim...
334
  	spi->dma_rx = sdd->rx_dma.ch;
730d9d4d1   Andi Shyti   spi: s3c64xx: sim...
335
  	spi->dma_tx = sdd->tx_dma.ch;
fb9d044ef   Mark Brown   spi/s3c64xx: Chec...
336

730d9d4d1   Andi Shyti   spi: s3c64xx: sim...
337
  	return 0;
788437273   Arnd Bergmann   spi: s3c64xx: mov...
338
  }
3f2958879   Mark Brown   spi/s3c64xx: Use ...
339
340
341
342
343
344
345
346
  static bool s3c64xx_spi_can_dma(struct spi_master *master,
  				struct spi_device *spi,
  				struct spi_transfer *xfer)
  {
  	struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
  
  	return xfer->len > (FIFO_LVL_MASK(sdd) >> 1) + 1;
  }
2f4db6f70   Łukasz Stelmach   spi: spi-s3c64xx:...
347
  static int s3c64xx_enable_datapath(struct s3c64xx_spi_driver_data *sdd,
3655d30c0   Sylwester Nawrocki   spi: spi-s3c64xx:...
348
  				    struct spi_transfer *xfer, int dma_mode)
230d42d42   Jassi Brar   spi: Add s3c64xx ...
349
  {
230d42d42   Jassi Brar   spi: Add s3c64xx ...
350
351
  	void __iomem *regs = sdd->regs;
  	u32 modecfg, chcfg;
2f4db6f70   Łukasz Stelmach   spi: spi-s3c64xx:...
352
  	int ret = 0;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
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
  
  	modecfg = readl(regs + S3C64XX_SPI_MODE_CFG);
  	modecfg &= ~(S3C64XX_SPI_MODE_TXDMA_ON | S3C64XX_SPI_MODE_RXDMA_ON);
  
  	chcfg = readl(regs + S3C64XX_SPI_CH_CFG);
  	chcfg &= ~S3C64XX_SPI_CH_TXCH_ON;
  
  	if (dma_mode) {
  		chcfg &= ~S3C64XX_SPI_CH_RXCH_ON;
  	} else {
  		/* Always shift in data in FIFO, even if xfer is Tx only,
  		 * this helps setting PCKT_CNT value for generating clocks
  		 * as exactly needed.
  		 */
  		chcfg |= S3C64XX_SPI_CH_RXCH_ON;
  		writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
  					| S3C64XX_SPI_PACKET_CNT_EN,
  					regs + S3C64XX_SPI_PACKET_CNT);
  	}
  
  	if (xfer->tx_buf != NULL) {
  		sdd->state |= TXBUSY;
  		chcfg |= S3C64XX_SPI_CH_TXCH_ON;
  		if (dma_mode) {
  			modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
2f4db6f70   Łukasz Stelmach   spi: spi-s3c64xx:...
378
  			ret = prepare_dma(&sdd->tx_dma, &xfer->tx_sg);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
379
  		} else {
0c92ecf10   Jassi Brar   spi/s3c64xx: Corr...
380
381
382
383
384
385
386
387
388
389
390
391
392
393
  			switch (sdd->cur_bpw) {
  			case 32:
  				iowrite32_rep(regs + S3C64XX_SPI_TX_DATA,
  					xfer->tx_buf, xfer->len / 4);
  				break;
  			case 16:
  				iowrite16_rep(regs + S3C64XX_SPI_TX_DATA,
  					xfer->tx_buf, xfer->len / 2);
  				break;
  			default:
  				iowrite8_rep(regs + S3C64XX_SPI_TX_DATA,
  					xfer->tx_buf, xfer->len);
  				break;
  			}
230d42d42   Jassi Brar   spi: Add s3c64xx ...
394
395
396
397
398
  		}
  	}
  
  	if (xfer->rx_buf != NULL) {
  		sdd->state |= RXBUSY;
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
399
  		if (sdd->port_conf->high_speed && sdd->cur_speed >= 30000000UL
230d42d42   Jassi Brar   spi: Add s3c64xx ...
400
401
402
403
404
405
406
407
408
  					&& !(sdd->cur_mode & SPI_CPHA))
  			chcfg |= S3C64XX_SPI_CH_HS_EN;
  
  		if (dma_mode) {
  			modecfg |= S3C64XX_SPI_MODE_RXDMA_ON;
  			chcfg |= S3C64XX_SPI_CH_RXCH_ON;
  			writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
  					| S3C64XX_SPI_PACKET_CNT_EN,
  					regs + S3C64XX_SPI_PACKET_CNT);
2f4db6f70   Łukasz Stelmach   spi: spi-s3c64xx:...
409
  			ret = prepare_dma(&sdd->rx_dma, &xfer->rx_sg);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
410
411
  		}
  	}
2f4db6f70   Łukasz Stelmach   spi: spi-s3c64xx:...
412
413
  	if (ret)
  		return ret;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
414
415
  	writel(modecfg, regs + S3C64XX_SPI_MODE_CFG);
  	writel(chcfg, regs + S3C64XX_SPI_CH_CFG);
2f4db6f70   Łukasz Stelmach   spi: spi-s3c64xx:...
416
417
  
  	return 0;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
418
  }
796170733   Mark Brown   spi/s3c64xx: Make...
419
  static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd,
7e9955567   Girish K S   spi: s3c64xx: add...
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
  					int timeout_ms)
  {
  	void __iomem *regs = sdd->regs;
  	unsigned long val = 1;
  	u32 status;
  
  	/* max fifo depth available */
  	u32 max_fifo = (FIFO_LVL_MASK(sdd) >> 1) + 1;
  
  	if (timeout_ms)
  		val = msecs_to_loops(timeout_ms);
  
  	do {
  		status = readl(regs + S3C64XX_SPI_STATUS);
  	} while (RX_FIFO_LVL(status, sdd) < max_fifo && --val);
  
  	/* return the actual received data length */
  	return RX_FIFO_LVL(status, sdd);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
438
  }
3655d30c0   Sylwester Nawrocki   spi: spi-s3c64xx:...
439
440
  static int s3c64xx_wait_for_dma(struct s3c64xx_spi_driver_data *sdd,
  				struct spi_transfer *xfer)
230d42d42   Jassi Brar   spi: Add s3c64xx ...
441
  {
230d42d42   Jassi Brar   spi: Add s3c64xx ...
442
443
  	void __iomem *regs = sdd->regs;
  	unsigned long val;
3700c6eb1   Mark Brown   spi/s3c64xx: Spli...
444
  	u32 status;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
445
446
447
448
  	int ms;
  
  	/* millisecs to xfer 'len' bytes @ 'cur_speed' */
  	ms = xfer->len * 8 * 1000 / sdd->cur_speed;
9fe26adbe   Łukasz Stelmach   spi: spi-s3c64xx:...
449
450
  	ms += 30;               /* some tolerance */
  	ms = max(ms, 100);      /* minimum timeout */
230d42d42   Jassi Brar   spi: Add s3c64xx ...
451

3700c6eb1   Mark Brown   spi/s3c64xx: Spli...
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
  	val = msecs_to_jiffies(ms) + 10;
  	val = wait_for_completion_timeout(&sdd->xfer_completion, val);
  
  	/*
  	 * If the previous xfer was completed within timeout, then
  	 * proceed further else return -EIO.
  	 * DmaTx returns after simply writing data in the FIFO,
  	 * w/o waiting for real transmission on the bus to finish.
  	 * DmaRx returns only after Dma read data from FIFO which
  	 * needs bus transmission to finish, so we don't worry if
  	 * Xfer involved Rx(with or without Tx).
  	 */
  	if (val && !xfer->rx_buf) {
  		val = msecs_to_loops(10);
  		status = readl(regs + S3C64XX_SPI_STATUS);
  		while ((TX_FIFO_LVL(status, sdd)
  			|| !S3C64XX_SPI_ST_TX_DONE(status, sdd))
  		       && --val) {
  			cpu_relax();
c3f139b65   Jassi Brar   spi/s3c64xx: Fix ...
471
  			status = readl(regs + S3C64XX_SPI_STATUS);
3700c6eb1   Mark Brown   spi/s3c64xx: Spli...
472
  		}
230d42d42   Jassi Brar   spi: Add s3c64xx ...
473
  	}
3700c6eb1   Mark Brown   spi/s3c64xx: Spli...
474
475
476
  	/* If timed out while checking rx/tx status return error */
  	if (!val)
  		return -EIO;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
477

3700c6eb1   Mark Brown   spi/s3c64xx: Spli...
478
479
  	return 0;
  }
7e9955567   Girish K S   spi: s3c64xx: add...
480

3655d30c0   Sylwester Nawrocki   spi: spi-s3c64xx:...
481
482
  static int s3c64xx_wait_for_pio(struct s3c64xx_spi_driver_data *sdd,
  				struct spi_transfer *xfer)
3700c6eb1   Mark Brown   spi/s3c64xx: Spli...
483
484
485
486
487
488
489
490
  {
  	void __iomem *regs = sdd->regs;
  	unsigned long val;
  	u32 status;
  	int loops;
  	u32 cpy_len;
  	u8 *buf;
  	int ms;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
491

3700c6eb1   Mark Brown   spi/s3c64xx: Spli...
492
493
494
  	/* millisecs to xfer 'len' bytes @ 'cur_speed' */
  	ms = xfer->len * 8 * 1000 / sdd->cur_speed;
  	ms += 10; /* some tolerance */
7e9955567   Girish K S   spi: s3c64xx: add...
495

3700c6eb1   Mark Brown   spi/s3c64xx: Spli...
496
497
498
499
  	val = msecs_to_loops(ms);
  	do {
  		status = readl(regs + S3C64XX_SPI_STATUS);
  	} while (RX_FIFO_LVL(status, sdd) < xfer->len && --val);
7e9955567   Girish K S   spi: s3c64xx: add...
500

4e0b82ee3   Sylwester Nawrocki   spi: spi-s3c64xx:...
501
502
  	if (!val)
  		return -EIO;
3700c6eb1   Mark Brown   spi/s3c64xx: Spli...
503
504
505
506
507
  
  	/* If it was only Tx */
  	if (!xfer->rx_buf) {
  		sdd->state &= ~TXBUSY;
  		return 0;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
508
  	}
3700c6eb1   Mark Brown   spi/s3c64xx: Spli...
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
  	/*
  	 * If the receive length is bigger than the controller fifo
  	 * size, calculate the loops and read the fifo as many times.
  	 * loops = length / max fifo size (calculated by using the
  	 * fifo mask).
  	 * For any size less than the fifo size the below code is
  	 * executed atleast once.
  	 */
  	loops = xfer->len / ((FIFO_LVL_MASK(sdd) >> 1) + 1);
  	buf = xfer->rx_buf;
  	do {
  		/* wait for data to be received in the fifo */
  		cpy_len = s3c64xx_spi_wait_for_timeout(sdd,
  						       (loops ? ms : 0));
  
  		switch (sdd->cur_bpw) {
  		case 32:
  			ioread32_rep(regs + S3C64XX_SPI_RX_DATA,
  				     buf, cpy_len / 4);
  			break;
  		case 16:
  			ioread16_rep(regs + S3C64XX_SPI_RX_DATA,
  				     buf, cpy_len / 2);
  			break;
  		default:
  			ioread8_rep(regs + S3C64XX_SPI_RX_DATA,
  				    buf, cpy_len);
  			break;
  		}
  
  		buf = buf + cpy_len;
  	} while (loops--);
  	sdd->state &= ~RXBUSY;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
542
543
  	return 0;
  }
2f4db6f70   Łukasz Stelmach   spi: spi-s3c64xx:...
544
  static int s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
230d42d42   Jassi Brar   spi: Add s3c64xx ...
545
  {
230d42d42   Jassi Brar   spi: Add s3c64xx ...
546
  	void __iomem *regs = sdd->regs;
2f4db6f70   Łukasz Stelmach   spi: spi-s3c64xx:...
547
  	int ret;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
548
549
550
  	u32 val;
  
  	/* Disable Clock */
d9aaf1dc9   Andi Shyti   spi: s3c64xx: do ...
551
  	if (!sdd->port_conf->clk_from_cmu) {
b42a81ca0   Jassi Brar   spi/s3c64xx: Cons...
552
553
554
555
  		val = readl(regs + S3C64XX_SPI_CLK_CFG);
  		val &= ~S3C64XX_SPI_ENCLK_ENABLE;
  		writel(val, regs + S3C64XX_SPI_CLK_CFG);
  	}
230d42d42   Jassi Brar   spi: Add s3c64xx ...
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
  
  	/* Set Polarity and Phase */
  	val = readl(regs + S3C64XX_SPI_CH_CFG);
  	val &= ~(S3C64XX_SPI_CH_SLAVE |
  			S3C64XX_SPI_CPOL_L |
  			S3C64XX_SPI_CPHA_B);
  
  	if (sdd->cur_mode & SPI_CPOL)
  		val |= S3C64XX_SPI_CPOL_L;
  
  	if (sdd->cur_mode & SPI_CPHA)
  		val |= S3C64XX_SPI_CPHA_B;
  
  	writel(val, regs + S3C64XX_SPI_CH_CFG);
  
  	/* Set Channel & DMA Mode */
  	val = readl(regs + S3C64XX_SPI_MODE_CFG);
  	val &= ~(S3C64XX_SPI_MODE_BUS_TSZ_MASK
  			| S3C64XX_SPI_MODE_CH_TSZ_MASK);
  
  	switch (sdd->cur_bpw) {
  	case 32:
  		val |= S3C64XX_SPI_MODE_BUS_TSZ_WORD;
0c92ecf10   Jassi Brar   spi/s3c64xx: Corr...
579
  		val |= S3C64XX_SPI_MODE_CH_TSZ_WORD;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
580
581
582
  		break;
  	case 16:
  		val |= S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD;
0c92ecf10   Jassi Brar   spi/s3c64xx: Corr...
583
  		val |= S3C64XX_SPI_MODE_CH_TSZ_HALFWORD;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
584
585
586
  		break;
  	default:
  		val |= S3C64XX_SPI_MODE_BUS_TSZ_BYTE;
0c92ecf10   Jassi Brar   spi/s3c64xx: Corr...
587
  		val |= S3C64XX_SPI_MODE_CH_TSZ_BYTE;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
588
589
  		break;
  	}
230d42d42   Jassi Brar   spi: Add s3c64xx ...
590
591
  
  	writel(val, regs + S3C64XX_SPI_MODE_CFG);
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
592
  	if (sdd->port_conf->clk_from_cmu) {
0dbe70a1f   Andi Shyti   spi: s3c64xx: res...
593
  		/* The src_clk clock is divided internally by 2 */
2f4db6f70   Łukasz Stelmach   spi: spi-s3c64xx:...
594
595
596
  		ret = clk_set_rate(sdd->src_clk, sdd->cur_speed * 2);
  		if (ret)
  			return ret;
20b4016a3   Łukasz Stelmach   spi: spi-s3c64xx:...
597
  		sdd->cur_speed = clk_get_rate(sdd->src_clk) / 2;
b42a81ca0   Jassi Brar   spi/s3c64xx: Cons...
598
599
600
601
602
603
604
605
606
607
608
609
610
  	} else {
  		/* Configure Clock */
  		val = readl(regs + S3C64XX_SPI_CLK_CFG);
  		val &= ~S3C64XX_SPI_PSR_MASK;
  		val |= ((clk_get_rate(sdd->src_clk) / sdd->cur_speed / 2 - 1)
  				& S3C64XX_SPI_PSR_MASK);
  		writel(val, regs + S3C64XX_SPI_CLK_CFG);
  
  		/* Enable Clock */
  		val = readl(regs + S3C64XX_SPI_CLK_CFG);
  		val |= S3C64XX_SPI_ENCLK_ENABLE;
  		writel(val, regs + S3C64XX_SPI_CLK_CFG);
  	}
2f4db6f70   Łukasz Stelmach   spi: spi-s3c64xx:...
611
612
  
  	return 0;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
613
  }
230d42d42   Jassi Brar   spi: Add s3c64xx ...
614
  #define XFER_DMAADDR_INVALID DMA_BIT_MASK(32)
6bb9c0e34   Mark Brown   spi/s3c64xx: Use ...
615
616
  static int s3c64xx_spi_prepare_message(struct spi_master *master,
  				       struct spi_message *msg)
230d42d42   Jassi Brar   spi: Add s3c64xx ...
617
  {
ad2a99af0   Mark Brown   spi/s3c64xx: Conv...
618
  	struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
619
620
  	struct spi_device *spi = msg->spi;
  	struct s3c64xx_spi_csinfo *cs = spi->controller_data;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
621

230d42d42   Jassi Brar   spi: Add s3c64xx ...
622
623
  	/* Configure feedback delay */
  	writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK);
6bb9c0e34   Mark Brown   spi/s3c64xx: Use ...
624
625
  	return 0;
  }
0c92ecf10   Jassi Brar   spi/s3c64xx: Corr...
626

0732a9d2a   Mark Brown   spi/s3c64xx: Use ...
627
628
629
  static int s3c64xx_spi_transfer_one(struct spi_master *master,
  				    struct spi_device *spi,
  				    struct spi_transfer *xfer)
6bb9c0e34   Mark Brown   spi/s3c64xx: Use ...
630
631
  {
  	struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
f6364e66c   Sylwester Nawrocki   spi: spi-s3c64xx:...
632
  	const unsigned int fifo_len = (FIFO_LVL_MASK(sdd) >> 1) + 1;
0af7af7da   Sylwester Nawrocki   spi: spi-s3c64xx:...
633
634
635
636
  	const void *tx_buf = NULL;
  	void *rx_buf = NULL;
  	int target_len = 0, origin_len = 0;
  	int use_dma = 0;
0732a9d2a   Mark Brown   spi/s3c64xx: Use ...
637
  	int status;
6bb9c0e34   Mark Brown   spi/s3c64xx: Use ...
638
639
  	u32 speed;
  	u8 bpw;
0732a9d2a   Mark Brown   spi/s3c64xx: Use ...
640
  	unsigned long flags;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
641

3e83c1949   Geert Uytterhoeven   spi/s3c64xx: Corr...
642
  	reinit_completion(&sdd->xfer_completion);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
643

0732a9d2a   Mark Brown   spi/s3c64xx: Use ...
644
645
  	/* Only BPW and Speed may change across transfers */
  	bpw = xfer->bits_per_word;
88d4a7440   Jarkko Nikula   spi: s3c64xx: Use...
646
  	speed = xfer->speed_hz;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
647

0732a9d2a   Mark Brown   spi/s3c64xx: Use ...
648
649
650
  	if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) {
  		sdd->cur_bpw = bpw;
  		sdd->cur_speed = speed;
11f66f092   Andi Shyti   spi: s3c64xx: do ...
651
  		sdd->cur_mode = spi->mode;
2f4db6f70   Łukasz Stelmach   spi: spi-s3c64xx:...
652
653
654
  		status = s3c64xx_spi_config(sdd);
  		if (status)
  			return status;
0732a9d2a   Mark Brown   spi/s3c64xx: Use ...
655
  	}
230d42d42   Jassi Brar   spi: Add s3c64xx ...
656

f6364e66c   Sylwester Nawrocki   spi: spi-s3c64xx:...
657
  	if (!is_polling(sdd) && (xfer->len > fifo_len) &&
0af7af7da   Sylwester Nawrocki   spi: spi-s3c64xx:...
658
  	    sdd->rx_dma.ch && sdd->tx_dma.ch) {
0732a9d2a   Mark Brown   spi/s3c64xx: Use ...
659
  		use_dma = 1;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
660

0af7af7da   Sylwester Nawrocki   spi: spi-s3c64xx:...
661
662
663
664
  	} else if (is_polling(sdd) && xfer->len > fifo_len) {
  		tx_buf = xfer->tx_buf;
  		rx_buf = xfer->rx_buf;
  		origin_len = xfer->len;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
665

0af7af7da   Sylwester Nawrocki   spi: spi-s3c64xx:...
666
667
668
669
670
671
672
  		target_len = xfer->len;
  		if (xfer->len > fifo_len)
  			xfer->len = fifo_len;
  	}
  
  	do {
  		spin_lock_irqsave(&sdd->lock, flags);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
673

0af7af7da   Sylwester Nawrocki   spi: spi-s3c64xx:...
674
675
676
  		/* Pending only which is to be done */
  		sdd->state &= ~RXBUSY;
  		sdd->state &= ~TXBUSY;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
677

0af7af7da   Sylwester Nawrocki   spi: spi-s3c64xx:...
678
679
  		/* Start the signals */
  		s3c64xx_spi_set_cs(spi, true);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
680

2f4db6f70   Łukasz Stelmach   spi: spi-s3c64xx:...
681
  		status = s3c64xx_enable_datapath(sdd, xfer, use_dma);
581e2b419   Łukasz Stelmach   spi: spi-s3c64xx:...
682

0af7af7da   Sylwester Nawrocki   spi: spi-s3c64xx:...
683
  		spin_unlock_irqrestore(&sdd->lock, flags);
2f4db6f70   Łukasz Stelmach   spi: spi-s3c64xx:...
684
685
686
687
688
  		if (status) {
  			dev_err(&spi->dev, "failed to enable data path for transfer: %d
  ", status);
  			break;
  		}
0af7af7da   Sylwester Nawrocki   spi: spi-s3c64xx:...
689
690
691
692
693
694
695
  		if (use_dma)
  			status = s3c64xx_wait_for_dma(sdd, xfer);
  		else
  			status = s3c64xx_wait_for_pio(sdd, xfer);
  
  		if (status) {
  			dev_err(&spi->dev,
df7cd1bba   Łukasz Stelmach   spi: spi-s3c64xx:...
696
697
  				"I/O Error: rx-%d tx-%d rx-%c tx-%c len-%d dma-%d res-(%d)
  ",
0af7af7da   Sylwester Nawrocki   spi: spi-s3c64xx:...
698
699
700
  				xfer->rx_buf ? 1 : 0, xfer->tx_buf ? 1 : 0,
  				(sdd->state & RXBUSY) ? 'f' : 'p',
  				(sdd->state & TXBUSY) ? 'f' : 'p',
df7cd1bba   Łukasz Stelmach   spi: spi-s3c64xx:...
701
  				xfer->len, use_dma ? 1 : 0, status);
0af7af7da   Sylwester Nawrocki   spi: spi-s3c64xx:...
702
703
  
  			if (use_dma) {
df7cd1bba   Łukasz Stelmach   spi: spi-s3c64xx:...
704
705
706
707
708
  				struct dma_tx_state s;
  
  				if (xfer->tx_buf && (sdd->state & TXBUSY)) {
  					dmaengine_pause(sdd->tx_dma.ch);
  					dmaengine_tx_status(sdd->tx_dma.ch, sdd->tx_dma.cookie, &s);
0af7af7da   Sylwester Nawrocki   spi: spi-s3c64xx:...
709
  					dmaengine_terminate_all(sdd->tx_dma.ch);
df7cd1bba   Łukasz Stelmach   spi: spi-s3c64xx:...
710
711
712
713
714
715
716
  					dev_err(&spi->dev, "TX residue: %d
  ", s.residue);
  
  				}
  				if (xfer->rx_buf && (sdd->state & RXBUSY)) {
  					dmaengine_pause(sdd->rx_dma.ch);
  					dmaengine_tx_status(sdd->rx_dma.ch, sdd->rx_dma.cookie, &s);
0af7af7da   Sylwester Nawrocki   spi: spi-s3c64xx:...
717
  					dmaengine_terminate_all(sdd->rx_dma.ch);
df7cd1bba   Łukasz Stelmach   spi: spi-s3c64xx:...
718
719
720
  					dev_err(&spi->dev, "RX residue: %d
  ", s.residue);
  				}
0af7af7da   Sylwester Nawrocki   spi: spi-s3c64xx:...
721
722
723
  			}
  		} else {
  			s3c64xx_flush_fifo(sdd);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
724
  		}
0af7af7da   Sylwester Nawrocki   spi: spi-s3c64xx:...
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
  		if (target_len > 0) {
  			target_len -= xfer->len;
  
  			if (xfer->tx_buf)
  				xfer->tx_buf += xfer->len;
  
  			if (xfer->rx_buf)
  				xfer->rx_buf += xfer->len;
  
  			if (target_len > fifo_len)
  				xfer->len = fifo_len;
  			else
  				xfer->len = target_len;
  		}
  	} while (target_len > 0);
  
  	if (origin_len) {
  		/* Restore original xfer buffers and length */
  		xfer->tx_buf = tx_buf;
  		xfer->rx_buf = rx_buf;
  		xfer->len = origin_len;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
746
  	}
0732a9d2a   Mark Brown   spi/s3c64xx: Use ...
747
  	return status;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
748
  }
230d42d42   Jassi Brar   spi: Add s3c64xx ...
749

2b9080754   Thomas Abraham   spi: s3c64xx: add...
750
  static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
2b9080754   Thomas Abraham   spi: s3c64xx: add...
751
752
753
  				struct spi_device *spi)
  {
  	struct s3c64xx_spi_csinfo *cs;
4732cc636   Arnd Bergmann   spi/s3c64xx: impr...
754
  	struct device_node *slave_np, *data_np = NULL;
2b9080754   Thomas Abraham   spi: s3c64xx: add...
755
756
757
758
759
760
761
762
  	u32 fb_delay = 0;
  
  	slave_np = spi->dev.of_node;
  	if (!slave_np) {
  		dev_err(&spi->dev, "device node not found
  ");
  		return ERR_PTR(-EINVAL);
  	}
06455bbca   Srinivas Kandagatla   dt/s3c64xx/spi: U...
763
  	data_np = of_get_child_by_name(slave_np, "controller-data");
2b9080754   Thomas Abraham   spi: s3c64xx: add...
764
765
766
767
768
769
770
771
  	if (!data_np) {
  		dev_err(&spi->dev, "child node 'controller-data' not found
  ");
  		return ERR_PTR(-EINVAL);
  	}
  
  	cs = kzalloc(sizeof(*cs), GFP_KERNEL);
  	if (!cs) {
06455bbca   Srinivas Kandagatla   dt/s3c64xx/spi: U...
772
  		of_node_put(data_np);
2b9080754   Thomas Abraham   spi: s3c64xx: add...
773
774
  		return ERR_PTR(-ENOMEM);
  	}
2b9080754   Thomas Abraham   spi: s3c64xx: add...
775
776
  	of_property_read_u32(data_np, "samsung,spi-feedback-delay", &fb_delay);
  	cs->fb_delay = fb_delay;
06455bbca   Srinivas Kandagatla   dt/s3c64xx/spi: U...
777
  	of_node_put(data_np);
2b9080754   Thomas Abraham   spi: s3c64xx: add...
778
779
  	return cs;
  }
230d42d42   Jassi Brar   spi: Add s3c64xx ...
780
781
782
783
784
785
786
787
788
789
  /*
   * Here we only check the validity of requested configuration
   * and save the configuration in a local data-structure.
   * The controller is actually configured only just before we
   * get a message to transfer.
   */
  static int s3c64xx_spi_setup(struct spi_device *spi)
  {
  	struct s3c64xx_spi_csinfo *cs = spi->controller_data;
  	struct s3c64xx_spi_driver_data *sdd;
2b9080754   Thomas Abraham   spi: s3c64xx: add...
790
  	int err;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
791

2b9080754   Thomas Abraham   spi: s3c64xx: add...
792
  	sdd = spi_master_get_devdata(spi->master);
306972ced   Naveen Krishna Chatradhi   spi: s3c64xx: use...
793
  	if (spi->dev.of_node) {
5c725b34d   Matthias Brugger   spi: spi-s3c64xx....
794
  		cs = s3c64xx_get_slave_ctrldata(spi);
2b9080754   Thomas Abraham   spi: s3c64xx: add...
795
  		spi->controller_data = cs;
306972ced   Naveen Krishna Chatradhi   spi: s3c64xx: use...
796
797
798
799
800
801
802
  	} else if (cs) {
  		/* On non-DT platforms the SPI core will set spi->cs_gpio
  		 * to -ENOENT. The GPIO pin used to drive the chip select
  		 * is defined by using platform data so spi->cs_gpio value
  		 * has to be override to have the proper GPIO pin number.
  		 */
  		spi->cs_gpio = cs->line;
2b9080754   Thomas Abraham   spi: s3c64xx: add...
803
804
805
  	}
  
  	if (IS_ERR_OR_NULL(cs)) {
230d42d42   Jassi Brar   spi: Add s3c64xx ...
806
807
808
809
  		dev_err(&spi->dev, "No CS for SPI(%d)
  ", spi->chip_select);
  		return -ENODEV;
  	}
0149871c4   Tomasz Figa   spi: s3c64xx: Do ...
810
  	if (!spi_get_ctldata(spi)) {
306972ced   Naveen Krishna Chatradhi   spi: s3c64xx: use...
811
812
813
814
815
816
817
818
819
820
  		if (gpio_is_valid(spi->cs_gpio)) {
  			err = gpio_request_one(spi->cs_gpio, GPIOF_OUT_INIT_HIGH,
  					       dev_name(&spi->dev));
  			if (err) {
  				dev_err(&spi->dev,
  					"Failed to get /CS gpio [%d]: %d
  ",
  					spi->cs_gpio, err);
  				goto err_gpio_req;
  			}
1c20c200e   Thomas Abraham   spi: s3c64xx: Rem...
821
  		}
1c20c200e   Thomas Abraham   spi: s3c64xx: Rem...
822

3146beec2   Girish K S   spi: s3c64xx: Add...
823
  		spi_set_ctldata(spi, cs);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
824
  	}
b97b66217   Mark Brown   spi/s3c64xx: Impl...
825
  	pm_runtime_get_sync(&sdd->pdev->dev);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
826
  	/* Check if we can provide the requested rate */
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
827
  	if (!sdd->port_conf->clk_from_cmu) {
b42a81ca0   Jassi Brar   spi/s3c64xx: Cons...
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
  		u32 psr, speed;
  
  		/* Max possible */
  		speed = clk_get_rate(sdd->src_clk) / 2 / (0 + 1);
  
  		if (spi->max_speed_hz > speed)
  			spi->max_speed_hz = speed;
  
  		psr = clk_get_rate(sdd->src_clk) / 2 / spi->max_speed_hz - 1;
  		psr &= S3C64XX_SPI_PSR_MASK;
  		if (psr == S3C64XX_SPI_PSR_MASK)
  			psr--;
  
  		speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
  		if (spi->max_speed_hz < speed) {
  			if (psr+1 < S3C64XX_SPI_PSR_MASK) {
  				psr++;
  			} else {
  				err = -EINVAL;
  				goto setup_exit;
  			}
  		}
230d42d42   Jassi Brar   spi: Add s3c64xx ...
850

b42a81ca0   Jassi Brar   spi/s3c64xx: Cons...
851
  		speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
2b9080754   Thomas Abraham   spi: s3c64xx: add...
852
  		if (spi->max_speed_hz >= speed) {
b42a81ca0   Jassi Brar   spi/s3c64xx: Cons...
853
  			spi->max_speed_hz = speed;
2b9080754   Thomas Abraham   spi: s3c64xx: add...
854
  		} else {
e1b0f0df6   Mark Brown   spi/s3c64xx: Comp...
855
856
857
  			dev_err(&spi->dev, "Can't set %dHz transfer speed
  ",
  				spi->max_speed_hz);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
858
  			err = -EINVAL;
2b9080754   Thomas Abraham   spi: s3c64xx: add...
859
860
  			goto setup_exit;
  		}
230d42d42   Jassi Brar   spi: Add s3c64xx ...
861
  	}
483867ee2   Heiner Kallweit   spi: s3c64xx: ext...
862
863
  	pm_runtime_mark_last_busy(&sdd->pdev->dev);
  	pm_runtime_put_autosuspend(&sdd->pdev->dev);
aa4964c4e   Andi Shyti   spi: s3c64xx: gro...
864
  	s3c64xx_spi_set_cs(spi, false);
2b9080754   Thomas Abraham   spi: s3c64xx: add...
865
  	return 0;
b97b66217   Mark Brown   spi/s3c64xx: Impl...
866

230d42d42   Jassi Brar   spi: Add s3c64xx ...
867
  setup_exit:
483867ee2   Heiner Kallweit   spi: s3c64xx: ext...
868
869
  	pm_runtime_mark_last_busy(&sdd->pdev->dev);
  	pm_runtime_put_autosuspend(&sdd->pdev->dev);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
870
  	/* setup() returns with device de-selected */
aa4964c4e   Andi Shyti   spi: s3c64xx: gro...
871
  	s3c64xx_spi_set_cs(spi, false);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
872

306972ced   Naveen Krishna Chatradhi   spi: s3c64xx: use...
873
874
  	if (gpio_is_valid(spi->cs_gpio))
  		gpio_free(spi->cs_gpio);
2b9080754   Thomas Abraham   spi: s3c64xx: add...
875
876
877
  	spi_set_ctldata(spi, NULL);
  
  err_gpio_req:
5bee3b94d   Sylwester Nawrocki   spi/s3c64xx: Don'...
878
879
  	if (spi->dev.of_node)
  		kfree(cs);
2b9080754   Thomas Abraham   spi: s3c64xx: add...
880

230d42d42   Jassi Brar   spi: Add s3c64xx ...
881
882
  	return err;
  }
1c20c200e   Thomas Abraham   spi: s3c64xx: Rem...
883
884
885
  static void s3c64xx_spi_cleanup(struct spi_device *spi)
  {
  	struct s3c64xx_spi_csinfo *cs = spi_get_ctldata(spi);
306972ced   Naveen Krishna Chatradhi   spi: s3c64xx: use...
886
  	if (gpio_is_valid(spi->cs_gpio)) {
dd97e2684   Mark Brown   spi/s3c64xx: Use ...
887
  		gpio_free(spi->cs_gpio);
2b9080754   Thomas Abraham   spi: s3c64xx: add...
888
889
  		if (spi->dev.of_node)
  			kfree(cs);
306972ced   Naveen Krishna Chatradhi   spi: s3c64xx: use...
890
891
892
893
894
895
896
897
  		else {
  			/* On non-DT platforms, the SPI core sets
  			 * spi->cs_gpio to -ENOENT and .setup()
  			 * overrides it with the GPIO pin value
  			 * passed using platform data.
  			 */
  			spi->cs_gpio = -ENOENT;
  		}
2b9080754   Thomas Abraham   spi: s3c64xx: add...
898
  	}
306972ced   Naveen Krishna Chatradhi   spi: s3c64xx: use...
899

1c20c200e   Thomas Abraham   spi: s3c64xx: Rem...
900
901
  	spi_set_ctldata(spi, NULL);
  }
c2573128a   Mark Brown   spi/s3c64xx: Log ...
902
903
904
905
  static irqreturn_t s3c64xx_spi_irq(int irq, void *data)
  {
  	struct s3c64xx_spi_driver_data *sdd = data;
  	struct spi_master *spi = sdd->master;
375981f2e   Girish K S   spi/s3c64xx: modi...
906
  	unsigned int val, clr = 0;
c2573128a   Mark Brown   spi/s3c64xx: Log ...
907

375981f2e   Girish K S   spi/s3c64xx: modi...
908
  	val = readl(sdd->regs + S3C64XX_SPI_STATUS);
c2573128a   Mark Brown   spi/s3c64xx: Log ...
909

375981f2e   Girish K S   spi/s3c64xx: modi...
910
911
  	if (val & S3C64XX_SPI_ST_RX_OVERRUN_ERR) {
  		clr = S3C64XX_SPI_PND_RX_OVERRUN_CLR;
c2573128a   Mark Brown   spi/s3c64xx: Log ...
912
913
  		dev_err(&spi->dev, "RX overrun
  ");
375981f2e   Girish K S   spi/s3c64xx: modi...
914
915
916
  	}
  	if (val & S3C64XX_SPI_ST_RX_UNDERRUN_ERR) {
  		clr |= S3C64XX_SPI_PND_RX_UNDERRUN_CLR;
c2573128a   Mark Brown   spi/s3c64xx: Log ...
917
918
  		dev_err(&spi->dev, "RX underrun
  ");
375981f2e   Girish K S   spi/s3c64xx: modi...
919
920
921
  	}
  	if (val & S3C64XX_SPI_ST_TX_OVERRUN_ERR) {
  		clr |= S3C64XX_SPI_PND_TX_OVERRUN_CLR;
c2573128a   Mark Brown   spi/s3c64xx: Log ...
922
923
  		dev_err(&spi->dev, "TX overrun
  ");
375981f2e   Girish K S   spi/s3c64xx: modi...
924
925
926
  	}
  	if (val & S3C64XX_SPI_ST_TX_UNDERRUN_ERR) {
  		clr |= S3C64XX_SPI_PND_TX_UNDERRUN_CLR;
c2573128a   Mark Brown   spi/s3c64xx: Log ...
927
928
  		dev_err(&spi->dev, "TX underrun
  ");
375981f2e   Girish K S   spi/s3c64xx: modi...
929
930
931
932
933
  	}
  
  	/* Clear the pending irq by setting and then clearing it */
  	writel(clr, sdd->regs + S3C64XX_SPI_PENDING_CLR);
  	writel(0, sdd->regs + S3C64XX_SPI_PENDING_CLR);
c2573128a   Mark Brown   spi/s3c64xx: Log ...
934
935
936
  
  	return IRQ_HANDLED;
  }
1c75862d8   Sylwester Nawrocki   spi: spi-s3c64xx:...
937
  static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd)
230d42d42   Jassi Brar   spi: Add s3c64xx ...
938
  {
ad7de729c   Jassi Brar   spi/s3c64xx: Rena...
939
  	struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
940
941
942
943
  	void __iomem *regs = sdd->regs;
  	unsigned int val;
  
  	sdd->cur_speed = 0;
a92e7c3d8   Andi Shyti   spi: s3c64xx: con...
944
  	if (sci->no_cs)
913ba5c9e   Łukasz Stelmach   spi: spi-s3c64xx:...
945
  		writel(0, sdd->regs + S3C64XX_SPI_CS_REG);
a92e7c3d8   Andi Shyti   spi: s3c64xx: con...
946
  	else if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
913ba5c9e   Łukasz Stelmach   spi: spi-s3c64xx:...
947
  		writel(S3C64XX_SPI_CS_SIG_INACT, sdd->regs + S3C64XX_SPI_CS_REG);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
948
949
950
  
  	/* Disable Interrupts - we use Polling if not DMA mode */
  	writel(0, regs + S3C64XX_SPI_INT_EN);
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
951
  	if (!sdd->port_conf->clk_from_cmu)
b42a81ca0   Jassi Brar   spi/s3c64xx: Cons...
952
  		writel(sci->src_clk_nr << S3C64XX_SPI_CLKSEL_SRCSHFT,
230d42d42   Jassi Brar   spi: Add s3c64xx ...
953
954
955
  				regs + S3C64XX_SPI_CLK_CFG);
  	writel(0, regs + S3C64XX_SPI_MODE_CFG);
  	writel(0, regs + S3C64XX_SPI_PACKET_CNT);
375981f2e   Girish K S   spi/s3c64xx: modi...
956
957
958
959
960
961
962
  	/* Clear any irq pending bits, should set and clear the bits */
  	val = S3C64XX_SPI_PND_RX_OVERRUN_CLR |
  		S3C64XX_SPI_PND_RX_UNDERRUN_CLR |
  		S3C64XX_SPI_PND_TX_OVERRUN_CLR |
  		S3C64XX_SPI_PND_TX_UNDERRUN_CLR;
  	writel(val, regs + S3C64XX_SPI_PENDING_CLR);
  	writel(0, regs + S3C64XX_SPI_PENDING_CLR);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
963
964
965
966
967
968
969
970
  
  	writel(0, regs + S3C64XX_SPI_SWAP_CFG);
  
  	val = readl(regs + S3C64XX_SPI_MODE_CFG);
  	val &= ~S3C64XX_SPI_MODE_4BURST;
  	val &= ~(S3C64XX_SPI_MAX_TRAILCNT << S3C64XX_SPI_TRAILCNT_OFF);
  	val |= (S3C64XX_SPI_TRAILCNT << S3C64XX_SPI_TRAILCNT_OFF);
  	writel(val, regs + S3C64XX_SPI_MODE_CFG);
3655d30c0   Sylwester Nawrocki   spi: spi-s3c64xx:...
971
  	s3c64xx_flush_fifo(sdd);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
972
  }
2b9080754   Thomas Abraham   spi: s3c64xx: add...
973
  #ifdef CONFIG_OF
75bf33611   Jingoo Han   spi/s3c64xx: fix ...
974
  static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev)
2b9080754   Thomas Abraham   spi: s3c64xx: add...
975
976
977
978
979
  {
  	struct s3c64xx_spi_info *sci;
  	u32 temp;
  
  	sci = devm_kzalloc(dev, sizeof(*sci), GFP_KERNEL);
1273eb050   Jingoo Han   spi: s3c64xx: rem...
980
  	if (!sci)
2b9080754   Thomas Abraham   spi: s3c64xx: add...
981
  		return ERR_PTR(-ENOMEM);
2b9080754   Thomas Abraham   spi: s3c64xx: add...
982
983
  
  	if (of_property_read_u32(dev->of_node, "samsung,spi-src-clk", &temp)) {
75bf33611   Jingoo Han   spi/s3c64xx: fix ...
984
985
  		dev_warn(dev, "spi bus clock parent not specified, using clock at index 0 as parent
  ");
2b9080754   Thomas Abraham   spi: s3c64xx: add...
986
987
988
989
990
991
  		sci->src_clk_nr = 0;
  	} else {
  		sci->src_clk_nr = temp;
  	}
  
  	if (of_property_read_u32(dev->of_node, "num-cs", &temp)) {
75bf33611   Jingoo Han   spi/s3c64xx: fix ...
992
993
  		dev_warn(dev, "number of chip select lines not specified, assuming 1 chip select line
  ");
2b9080754   Thomas Abraham   spi: s3c64xx: add...
994
995
996
997
  		sci->num_cs = 1;
  	} else {
  		sci->num_cs = temp;
  	}
379f831a9   Andi Shyti   spi: s3c64xx: fix...
998
  	sci->no_cs = of_property_read_bool(dev->of_node, "no-cs-readback");
a92e7c3d8   Andi Shyti   spi: s3c64xx: con...
999

2b9080754   Thomas Abraham   spi: s3c64xx: add...
1000
1001
1002
1003
1004
  	return sci;
  }
  #else
  static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev)
  {
8074cf063   Jingoo Han   spi: use dev_get_...
1005
  	return dev_get_platdata(dev);
2b9080754   Thomas Abraham   spi: s3c64xx: add...
1006
  }
2b9080754   Thomas Abraham   spi: s3c64xx: add...
1007
1008
1009
  #endif
  
  static const struct of_device_id s3c64xx_spi_dt_match[];
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
1010
1011
1012
  static inline struct s3c64xx_spi_port_config *s3c64xx_spi_get_port_config(
  						struct platform_device *pdev)
  {
2b9080754   Thomas Abraham   spi: s3c64xx: add...
1013
1014
1015
1016
1017
1018
1019
  #ifdef CONFIG_OF
  	if (pdev->dev.of_node) {
  		const struct of_device_id *match;
  		match = of_match_node(s3c64xx_spi_dt_match, pdev->dev.of_node);
  		return (struct s3c64xx_spi_port_config *)match->data;
  	}
  #endif
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
1020
1021
1022
  	return (struct s3c64xx_spi_port_config *)
  			 platform_get_device_id(pdev)->driver_data;
  }
2deff8d60   Grant Likely   spi: Remove erron...
1023
  static int s3c64xx_spi_probe(struct platform_device *pdev)
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1024
  {
2b9080754   Thomas Abraham   spi: s3c64xx: add...
1025
  	struct resource	*mem_res;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1026
  	struct s3c64xx_spi_driver_data *sdd;
8074cf063   Jingoo Han   spi: use dev_get_...
1027
  	struct s3c64xx_spi_info *sci = dev_get_platdata(&pdev->dev);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1028
  	struct spi_master *master;
c2573128a   Mark Brown   spi/s3c64xx: Log ...
1029
  	int ret, irq;
a24d850b9   Padmavathi Venna   spi/s3c64xx: Use ...
1030
  	char clk_name[16];
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1031

2b9080754   Thomas Abraham   spi: s3c64xx: add...
1032
1033
1034
1035
  	if (!sci && pdev->dev.of_node) {
  		sci = s3c64xx_spi_parse_dt(&pdev->dev);
  		if (IS_ERR(sci))
  			return PTR_ERR(sci);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1036
  	}
2b9080754   Thomas Abraham   spi: s3c64xx: add...
1037
  	if (!sci) {
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1038
1039
1040
1041
  		dev_err(&pdev->dev, "platform_data missing!
  ");
  		return -ENODEV;
  	}
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1042
1043
1044
1045
1046
1047
  	mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	if (mem_res == NULL) {
  		dev_err(&pdev->dev, "Unable to get SPI MEM resource
  ");
  		return -ENXIO;
  	}
c2573128a   Mark Brown   spi/s3c64xx: Log ...
1048
1049
1050
1051
1052
1053
  	irq = platform_get_irq(pdev, 0);
  	if (irq < 0) {
  		dev_warn(&pdev->dev, "Failed to get IRQ: %d
  ", irq);
  		return irq;
  	}
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1054
1055
1056
1057
1058
1059
1060
  	master = spi_alloc_master(&pdev->dev,
  				sizeof(struct s3c64xx_spi_driver_data));
  	if (master == NULL) {
  		dev_err(&pdev->dev, "Unable to allocate SPI Master
  ");
  		return -ENOMEM;
  	}
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1061
1062
1063
  	platform_set_drvdata(pdev, master);
  
  	sdd = spi_master_get_devdata(master);
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
1064
  	sdd->port_conf = s3c64xx_spi_get_port_config(pdev);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1065
1066
1067
1068
  	sdd->master = master;
  	sdd->cntrlr_info = sci;
  	sdd->pdev = pdev;
  	sdd->sfr_start = mem_res->start;
2b9080754   Thomas Abraham   spi: s3c64xx: add...
1069
1070
1071
  	if (pdev->dev.of_node) {
  		ret = of_alias_get_id(pdev->dev.of_node, "spi");
  		if (ret < 0) {
75bf33611   Jingoo Han   spi/s3c64xx: fix ...
1072
1073
1074
  			dev_err(&pdev->dev, "failed to get alias id, errno %d
  ",
  				ret);
60a9a9644   Andi Shyti   spi: s3c64xx: ren...
1075
  			goto err_deref_master;
2b9080754   Thomas Abraham   spi: s3c64xx: add...
1076
1077
1078
1079
1080
  		}
  		sdd->port_id = ret;
  	} else {
  		sdd->port_id = pdev->id;
  	}
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1081
1082
  
  	sdd->cur_bpw = 8;
b5be04d35   Padmavathi Venna   spi: s3c64xx: Mod...
1083
1084
  	sdd->tx_dma.direction = DMA_MEM_TO_DEV;
  	sdd->rx_dma.direction = DMA_DEV_TO_MEM;
2b9080754   Thomas Abraham   spi: s3c64xx: add...
1085
1086
  
  	master->dev.of_node = pdev->dev.of_node;
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
1087
  	master->bus_num = sdd->port_id;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1088
  	master->setup = s3c64xx_spi_setup;
1c20c200e   Thomas Abraham   spi: s3c64xx: Rem...
1089
  	master->cleanup = s3c64xx_spi_cleanup;
ad2a99af0   Mark Brown   spi/s3c64xx: Conv...
1090
  	master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer;
6bb9c0e34   Mark Brown   spi/s3c64xx: Use ...
1091
  	master->prepare_message = s3c64xx_spi_prepare_message;
0732a9d2a   Mark Brown   spi/s3c64xx: Use ...
1092
  	master->transfer_one = s3c64xx_spi_transfer_one;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1093
1094
  	master->num_chipselect = sci->num_cs;
  	master->dma_alignment = 8;
24778be20   Stephen Warren   spi: convert driv...
1095
1096
  	master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
  					SPI_BPW_MASK(8);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1097
1098
  	/* the spi->mode bits understood by this driver: */
  	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
fc0f81b76   Mark Brown   spi/s3c64xx: Use ...
1099
  	master->auto_runtime_pm = true;
3f2958879   Mark Brown   spi/s3c64xx: Use ...
1100
1101
  	if (!is_polling(sdd))
  		master->can_dma = s3c64xx_spi_can_dma;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1102

b0ee56052   Thierry Reding   spi: Convert to d...
1103
1104
1105
  	sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res);
  	if (IS_ERR(sdd->regs)) {
  		ret = PTR_ERR(sdd->regs);
60a9a9644   Andi Shyti   spi: s3c64xx: ren...
1106
  		goto err_deref_master;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1107
  	}
00ab5392c   Thomas Abraham   spi/s3c64xx: let ...
1108
  	if (sci->cfg_gpio && sci->cfg_gpio()) {
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1109
1110
1111
  		dev_err(&pdev->dev, "Unable to config gpio
  ");
  		ret = -EBUSY;
60a9a9644   Andi Shyti   spi: s3c64xx: ren...
1112
  		goto err_deref_master;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1113
1114
1115
  	}
  
  	/* Setup clocks */
4eb770067   Jingoo Han   spi/s3c64xx: Use ...
1116
  	sdd->clk = devm_clk_get(&pdev->dev, "spi");
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1117
1118
1119
1120
  	if (IS_ERR(sdd->clk)) {
  		dev_err(&pdev->dev, "Unable to acquire clock 'spi'
  ");
  		ret = PTR_ERR(sdd->clk);
60a9a9644   Andi Shyti   spi: s3c64xx: ren...
1121
  		goto err_deref_master;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1122
  	}
25981d828   Andi Shyti   spi: s3c64xx: use...
1123
1124
  	ret = clk_prepare_enable(sdd->clk);
  	if (ret) {
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1125
1126
  		dev_err(&pdev->dev, "Couldn't enable clock 'spi'
  ");
60a9a9644   Andi Shyti   spi: s3c64xx: ren...
1127
  		goto err_deref_master;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1128
  	}
a24d850b9   Padmavathi Venna   spi/s3c64xx: Use ...
1129
  	sprintf(clk_name, "spi_busclk%d", sci->src_clk_nr);
4eb770067   Jingoo Han   spi/s3c64xx: Use ...
1130
  	sdd->src_clk = devm_clk_get(&pdev->dev, clk_name);
b0d5d6e55   Jassi Brar   spi/s3c64xx: Move...
1131
  	if (IS_ERR(sdd->src_clk)) {
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1132
  		dev_err(&pdev->dev,
a24d850b9   Padmavathi Venna   spi/s3c64xx: Use ...
1133
1134
  			"Unable to acquire clock '%s'
  ", clk_name);
b0d5d6e55   Jassi Brar   spi/s3c64xx: Move...
1135
  		ret = PTR_ERR(sdd->src_clk);
60a9a9644   Andi Shyti   spi: s3c64xx: ren...
1136
  		goto err_disable_clk;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1137
  	}
25981d828   Andi Shyti   spi: s3c64xx: use...
1138
1139
  	ret = clk_prepare_enable(sdd->src_clk);
  	if (ret) {
a24d850b9   Padmavathi Venna   spi/s3c64xx: Use ...
1140
1141
  		dev_err(&pdev->dev, "Couldn't enable clock '%s'
  ", clk_name);
60a9a9644   Andi Shyti   spi: s3c64xx: ren...
1142
  		goto err_disable_clk;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1143
  	}
7990b0081   Andi Shyti   spi: s3c64xx: add...
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
  	if (sdd->port_conf->clk_ioclk) {
  		sdd->ioclk = devm_clk_get(&pdev->dev, "spi_ioclk");
  		if (IS_ERR(sdd->ioclk)) {
  			dev_err(&pdev->dev, "Unable to acquire 'ioclk'
  ");
  			ret = PTR_ERR(sdd->ioclk);
  			goto err_disable_src_clk;
  		}
  
  		ret = clk_prepare_enable(sdd->ioclk);
  		if (ret) {
  			dev_err(&pdev->dev, "Couldn't enable clock 'ioclk'
  ");
  			goto err_disable_src_clk;
  		}
  	}
3d63a47a3   Marek Szyprowski   spi: s3c64xx: Don...
1160
1161
  	if (!is_polling(sdd)) {
  		/* Acquire DMA channels */
df1b01417   Peter Ujfalusi   spi: s3c64xx: Use...
1162
  		sdd->rx_dma.ch = dma_request_chan(&pdev->dev, "rx");
3d63a47a3   Marek Szyprowski   spi: s3c64xx: Don...
1163
1164
1165
1166
1167
1168
  		if (IS_ERR(sdd->rx_dma.ch)) {
  			dev_err(&pdev->dev, "Failed to get RX DMA channel
  ");
  			ret = PTR_ERR(sdd->rx_dma.ch);
  			goto err_disable_io_clk;
  		}
df1b01417   Peter Ujfalusi   spi: s3c64xx: Use...
1169
  		sdd->tx_dma.ch = dma_request_chan(&pdev->dev, "tx");
3d63a47a3   Marek Szyprowski   spi: s3c64xx: Don...
1170
1171
1172
1173
  		if (IS_ERR(sdd->tx_dma.ch)) {
  			dev_err(&pdev->dev, "Failed to get TX DMA channel
  ");
  			ret = PTR_ERR(sdd->tx_dma.ch);
72bc7ae06   Dan Carpenter   spi: s3c64xx: pot...
1174
  			goto err_release_rx_dma;
3d63a47a3   Marek Szyprowski   spi: s3c64xx: Don...
1175
1176
  		}
  	}
483867ee2   Heiner Kallweit   spi: s3c64xx: ext...
1177
1178
1179
1180
1181
  	pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT);
  	pm_runtime_use_autosuspend(&pdev->dev);
  	pm_runtime_set_active(&pdev->dev);
  	pm_runtime_enable(&pdev->dev);
  	pm_runtime_get_sync(&pdev->dev);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1182
  	/* Setup Deufult Mode */
1c75862d8   Sylwester Nawrocki   spi: spi-s3c64xx:...
1183
  	s3c64xx_spi_hwinit(sdd);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1184
1185
1186
  
  	spin_lock_init(&sdd->lock);
  	init_completion(&sdd->xfer_completion);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1187

4eb770067   Jingoo Han   spi/s3c64xx: Use ...
1188
1189
  	ret = devm_request_irq(&pdev->dev, irq, s3c64xx_spi_irq, 0,
  				"spi-s3c64xx", sdd);
c2573128a   Mark Brown   spi/s3c64xx: Log ...
1190
1191
1192
1193
  	if (ret != 0) {
  		dev_err(&pdev->dev, "Failed to request IRQ %d: %d
  ",
  			irq, ret);
60a9a9644   Andi Shyti   spi: s3c64xx: ren...
1194
  		goto err_pm_put;
c2573128a   Mark Brown   spi/s3c64xx: Log ...
1195
1196
1197
1198
1199
  	}
  
  	writel(S3C64XX_SPI_INT_RX_OVERRUN_EN | S3C64XX_SPI_INT_RX_UNDERRUN_EN |
  	       S3C64XX_SPI_INT_TX_OVERRUN_EN | S3C64XX_SPI_INT_TX_UNDERRUN_EN,
  	       sdd->regs + S3C64XX_SPI_INT_EN);
91800f0e9   Mark Brown   spi/s3c64xx: Use ...
1200
1201
1202
1203
  	ret = devm_spi_register_master(&pdev->dev, master);
  	if (ret != 0) {
  		dev_err(&pdev->dev, "cannot register SPI master: %d
  ", ret);
60a9a9644   Andi Shyti   spi: s3c64xx: ren...
1204
  		goto err_pm_put;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1205
  	}
75bf33611   Jingoo Han   spi/s3c64xx: fix ...
1206
1207
  	dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Slaves attached
  ",
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
1208
  					sdd->port_id, master->num_chipselect);
6f8dc9d48   Sylwester Nawrocki   spi: s3c64xx: Do ...
1209
1210
1211
  	dev_dbg(&pdev->dev, "\tIOmem=[%pR]\tFIFO %dbytes
  ",
  					mem_res, (FIFO_LVL_MASK(sdd) >> 1) + 1);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1212

483867ee2   Heiner Kallweit   spi: s3c64xx: ext...
1213
1214
  	pm_runtime_mark_last_busy(&pdev->dev);
  	pm_runtime_put_autosuspend(&pdev->dev);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1215
  	return 0;
60a9a9644   Andi Shyti   spi: s3c64xx: ren...
1216
  err_pm_put:
483867ee2   Heiner Kallweit   spi: s3c64xx: ext...
1217
  	pm_runtime_put_noidle(&pdev->dev);
3c863792e   Heiner Kallweit   spi: s3c64xx: cle...
1218
1219
  	pm_runtime_disable(&pdev->dev);
  	pm_runtime_set_suspended(&pdev->dev);
483867ee2   Heiner Kallweit   spi: s3c64xx: ext...
1220

3d63a47a3   Marek Szyprowski   spi: s3c64xx: Don...
1221
  	if (!is_polling(sdd))
3d63a47a3   Marek Szyprowski   spi: s3c64xx: Don...
1222
  		dma_release_channel(sdd->tx_dma.ch);
72bc7ae06   Dan Carpenter   spi: s3c64xx: pot...
1223
1224
1225
  err_release_rx_dma:
  	if (!is_polling(sdd))
  		dma_release_channel(sdd->rx_dma.ch);
3d63a47a3   Marek Szyprowski   spi: s3c64xx: Don...
1226
  err_disable_io_clk:
7990b0081   Andi Shyti   spi: s3c64xx: add...
1227
1228
  	clk_disable_unprepare(sdd->ioclk);
  err_disable_src_clk:
9f667bff0   Thomas Abraham   spi/s3c64xx: use ...
1229
  	clk_disable_unprepare(sdd->src_clk);
60a9a9644   Andi Shyti   spi: s3c64xx: ren...
1230
  err_disable_clk:
9f667bff0   Thomas Abraham   spi/s3c64xx: use ...
1231
  	clk_disable_unprepare(sdd->clk);
60a9a9644   Andi Shyti   spi: s3c64xx: ren...
1232
  err_deref_master:
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1233
1234
1235
1236
1237
1238
1239
  	spi_master_put(master);
  
  	return ret;
  }
  
  static int s3c64xx_spi_remove(struct platform_device *pdev)
  {
9f135787b   Wei Yongjun   spi: s3c64xx: fix...
1240
  	struct spi_master *master = platform_get_drvdata(pdev);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1241
  	struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1242

8ebe9d163   Heiner Kallweit   spi: s3c64xx: rep...
1243
  	pm_runtime_get_sync(&pdev->dev);
b97b66217   Mark Brown   spi/s3c64xx: Impl...
1244

c2573128a   Mark Brown   spi/s3c64xx: Log ...
1245
  	writel(0, sdd->regs + S3C64XX_SPI_INT_EN);
3d63a47a3   Marek Szyprowski   spi: s3c64xx: Don...
1246
1247
1248
1249
  	if (!is_polling(sdd)) {
  		dma_release_channel(sdd->rx_dma.ch);
  		dma_release_channel(sdd->tx_dma.ch);
  	}
7990b0081   Andi Shyti   spi: s3c64xx: add...
1250
  	clk_disable_unprepare(sdd->ioclk);
9f667bff0   Thomas Abraham   spi/s3c64xx: use ...
1251
  	clk_disable_unprepare(sdd->src_clk);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1252

9f667bff0   Thomas Abraham   spi/s3c64xx: use ...
1253
  	clk_disable_unprepare(sdd->clk);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1254

8ebe9d163   Heiner Kallweit   spi: s3c64xx: rep...
1255
1256
1257
  	pm_runtime_put_noidle(&pdev->dev);
  	pm_runtime_disable(&pdev->dev);
  	pm_runtime_set_suspended(&pdev->dev);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1258
1259
  	return 0;
  }
997230d02   Jingoo Han   spi/s3c64xx: add ...
1260
  #ifdef CONFIG_PM_SLEEP
e25d0bf91   Mark Brown   spi/s3c64xx: Conv...
1261
  static int s3c64xx_spi_suspend(struct device *dev)
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1262
  {
9a2a52452   Guenter Roeck   spi/s3c64xx: Drop...
1263
  	struct spi_master *master = dev_get_drvdata(dev);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1264
  	struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1265

347de6bab   Krzysztof Kozlowski   spi/s3c64xx: Do n...
1266
1267
1268
  	int ret = spi_master_suspend(master);
  	if (ret)
  		return ret;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1269

4fcd9b9e0   Heiner Kallweit   spi: s3c64xx: sim...
1270
1271
1272
  	ret = pm_runtime_force_suspend(dev);
  	if (ret < 0)
  		return ret;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1273
1274
1275
1276
1277
  
  	sdd->cur_speed = 0; /* Output Clock is stopped */
  
  	return 0;
  }
e25d0bf91   Mark Brown   spi/s3c64xx: Conv...
1278
  static int s3c64xx_spi_resume(struct device *dev)
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1279
  {
9a2a52452   Guenter Roeck   spi/s3c64xx: Drop...
1280
  	struct spi_master *master = dev_get_drvdata(dev);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1281
  	struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
ad7de729c   Jassi Brar   spi/s3c64xx: Rena...
1282
  	struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
4fcd9b9e0   Heiner Kallweit   spi: s3c64xx: sim...
1283
  	int ret;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1284

00ab5392c   Thomas Abraham   spi/s3c64xx: let ...
1285
  	if (sci->cfg_gpio)
2b9080754   Thomas Abraham   spi: s3c64xx: add...
1286
  		sci->cfg_gpio();
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1287

4fcd9b9e0   Heiner Kallweit   spi: s3c64xx: sim...
1288
1289
1290
  	ret = pm_runtime_force_resume(dev);
  	if (ret < 0)
  		return ret;
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1291

347de6bab   Krzysztof Kozlowski   spi/s3c64xx: Do n...
1292
  	return spi_master_resume(master);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1293
  }
997230d02   Jingoo Han   spi/s3c64xx: add ...
1294
  #endif /* CONFIG_PM_SLEEP */
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1295

ec8330503   Rafael J. Wysocki   spi: Replace CONF...
1296
  #ifdef CONFIG_PM
b97b66217   Mark Brown   spi/s3c64xx: Impl...
1297
1298
  static int s3c64xx_spi_runtime_suspend(struct device *dev)
  {
9a2a52452   Guenter Roeck   spi/s3c64xx: Drop...
1299
  	struct spi_master *master = dev_get_drvdata(dev);
b97b66217   Mark Brown   spi/s3c64xx: Impl...
1300
  	struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
9f667bff0   Thomas Abraham   spi/s3c64xx: use ...
1301
1302
  	clk_disable_unprepare(sdd->clk);
  	clk_disable_unprepare(sdd->src_clk);
7990b0081   Andi Shyti   spi: s3c64xx: add...
1303
  	clk_disable_unprepare(sdd->ioclk);
b97b66217   Mark Brown   spi/s3c64xx: Impl...
1304
1305
1306
1307
1308
1309
  
  	return 0;
  }
  
  static int s3c64xx_spi_runtime_resume(struct device *dev)
  {
9a2a52452   Guenter Roeck   spi/s3c64xx: Drop...
1310
  	struct spi_master *master = dev_get_drvdata(dev);
b97b66217   Mark Brown   spi/s3c64xx: Impl...
1311
  	struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master);
8b06d5b85   Mark Brown   spi/s3c64xx: Chec...
1312
  	int ret;
b97b66217   Mark Brown   spi/s3c64xx: Impl...
1313

7990b0081   Andi Shyti   spi: s3c64xx: add...
1314
1315
1316
1317
1318
  	if (sdd->port_conf->clk_ioclk) {
  		ret = clk_prepare_enable(sdd->ioclk);
  		if (ret != 0)
  			return ret;
  	}
8b06d5b85   Mark Brown   spi/s3c64xx: Chec...
1319
1320
  	ret = clk_prepare_enable(sdd->src_clk);
  	if (ret != 0)
7990b0081   Andi Shyti   spi: s3c64xx: add...
1321
  		goto err_disable_ioclk;
8b06d5b85   Mark Brown   spi/s3c64xx: Chec...
1322
1323
  
  	ret = clk_prepare_enable(sdd->clk);
7990b0081   Andi Shyti   spi: s3c64xx: add...
1324
1325
  	if (ret != 0)
  		goto err_disable_src_clk;
b97b66217   Mark Brown   spi/s3c64xx: Impl...
1326

e935dba11   Marek Szyprowski   spi: spi-s3c64xx:...
1327
  	s3c64xx_spi_hwinit(sdd);
3f32131fb   Łukasz Stelmach   spi: spi-s3c64xx:...
1328
1329
1330
  	writel(S3C64XX_SPI_INT_RX_OVERRUN_EN | S3C64XX_SPI_INT_RX_UNDERRUN_EN |
  	       S3C64XX_SPI_INT_TX_OVERRUN_EN | S3C64XX_SPI_INT_TX_UNDERRUN_EN,
  	       sdd->regs + S3C64XX_SPI_INT_EN);
b97b66217   Mark Brown   spi/s3c64xx: Impl...
1331
  	return 0;
7990b0081   Andi Shyti   spi: s3c64xx: add...
1332
1333
1334
1335
1336
1337
1338
  
  err_disable_src_clk:
  	clk_disable_unprepare(sdd->src_clk);
  err_disable_ioclk:
  	clk_disable_unprepare(sdd->ioclk);
  
  	return ret;
b97b66217   Mark Brown   spi/s3c64xx: Impl...
1339
  }
ec8330503   Rafael J. Wysocki   spi: Replace CONF...
1340
  #endif /* CONFIG_PM */
b97b66217   Mark Brown   spi/s3c64xx: Impl...
1341

e25d0bf91   Mark Brown   spi/s3c64xx: Conv...
1342
1343
  static const struct dev_pm_ops s3c64xx_spi_pm = {
  	SET_SYSTEM_SLEEP_PM_OPS(s3c64xx_spi_suspend, s3c64xx_spi_resume)
b97b66217   Mark Brown   spi/s3c64xx: Impl...
1344
1345
  	SET_RUNTIME_PM_OPS(s3c64xx_spi_runtime_suspend,
  			   s3c64xx_spi_runtime_resume, NULL)
e25d0bf91   Mark Brown   spi/s3c64xx: Conv...
1346
  };
10ce0473e   Sachin Kamat   spi/s3c64xx: Add ...
1347
  static struct s3c64xx_spi_port_config s3c2443_spi_port_config = {
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
1348
1349
1350
1351
1352
  	.fifo_lvl_mask	= { 0x7f },
  	.rx_lvl_offset	= 13,
  	.tx_st_done	= 21,
  	.high_speed	= true,
  };
10ce0473e   Sachin Kamat   spi/s3c64xx: Add ...
1353
  static struct s3c64xx_spi_port_config s3c6410_spi_port_config = {
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
1354
1355
1356
1357
  	.fifo_lvl_mask	= { 0x7f, 0x7F },
  	.rx_lvl_offset	= 13,
  	.tx_st_done	= 21,
  };
10ce0473e   Sachin Kamat   spi/s3c64xx: Add ...
1358
  static struct s3c64xx_spi_port_config s5pv210_spi_port_config = {
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
1359
1360
1361
1362
1363
  	.fifo_lvl_mask	= { 0x1ff, 0x7F },
  	.rx_lvl_offset	= 15,
  	.tx_st_done	= 25,
  	.high_speed	= true,
  };
10ce0473e   Sachin Kamat   spi/s3c64xx: Add ...
1364
  static struct s3c64xx_spi_port_config exynos4_spi_port_config = {
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
1365
1366
1367
1368
1369
  	.fifo_lvl_mask	= { 0x1ff, 0x7F, 0x7F },
  	.rx_lvl_offset	= 15,
  	.tx_st_done	= 25,
  	.high_speed	= true,
  	.clk_from_cmu	= true,
ab4efca29   Łukasz Stelmach   spi: spi-s3s64xx:...
1370
  	.quirks		= S3C64XX_SPI_QUIRK_CS_AUTO,
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
1371
  };
bf77cba95   Padmavathi Venna   spi: s3c64xx: add...
1372
1373
1374
1375
1376
1377
1378
1379
  static struct s3c64xx_spi_port_config exynos7_spi_port_config = {
  	.fifo_lvl_mask	= { 0x1ff, 0x7F, 0x7F, 0x7F, 0x7F, 0x1ff},
  	.rx_lvl_offset	= 15,
  	.tx_st_done	= 25,
  	.high_speed	= true,
  	.clk_from_cmu	= true,
  	.quirks		= S3C64XX_SPI_QUIRK_CS_AUTO,
  };
7990b0081   Andi Shyti   spi: s3c64xx: add...
1380
1381
1382
1383
1384
1385
1386
1387
1388
  static struct s3c64xx_spi_port_config exynos5433_spi_port_config = {
  	.fifo_lvl_mask	= { 0x1ff, 0x7f, 0x7f, 0x7f, 0x7f, 0x1ff},
  	.rx_lvl_offset	= 15,
  	.tx_st_done	= 25,
  	.high_speed	= true,
  	.clk_from_cmu	= true,
  	.clk_ioclk	= true,
  	.quirks		= S3C64XX_SPI_QUIRK_CS_AUTO,
  };
23f6d39ec   Krzysztof Kozlowski   spi: s3c64xx: Con...
1389
  static const struct platform_device_id s3c64xx_spi_driver_ids[] = {
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
1390
1391
1392
1393
1394
1395
  	{
  		.name		= "s3c2443-spi",
  		.driver_data	= (kernel_ulong_t)&s3c2443_spi_port_config,
  	}, {
  		.name		= "s3c6410-spi",
  		.driver_data	= (kernel_ulong_t)&s3c6410_spi_port_config,
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
1396
1397
1398
  	},
  	{ },
  };
2b9080754   Thomas Abraham   spi: s3c64xx: add...
1399
  static const struct of_device_id s3c64xx_spi_dt_match[] = {
a3b924df8   Mateusz Krawczuk   spi: s3c64xx: Add...
1400
1401
1402
1403
1404
1405
  	{ .compatible = "samsung,s3c2443-spi",
  			.data = (void *)&s3c2443_spi_port_config,
  	},
  	{ .compatible = "samsung,s3c6410-spi",
  			.data = (void *)&s3c6410_spi_port_config,
  	},
a3b924df8   Mateusz Krawczuk   spi: s3c64xx: Add...
1406
1407
1408
  	{ .compatible = "samsung,s5pv210-spi",
  			.data = (void *)&s5pv210_spi_port_config,
  	},
2b9080754   Thomas Abraham   spi: s3c64xx: add...
1409
1410
1411
  	{ .compatible = "samsung,exynos4210-spi",
  			.data = (void *)&exynos4_spi_port_config,
  	},
bf77cba95   Padmavathi Venna   spi: s3c64xx: add...
1412
1413
1414
  	{ .compatible = "samsung,exynos7-spi",
  			.data = (void *)&exynos7_spi_port_config,
  	},
7990b0081   Andi Shyti   spi: s3c64xx: add...
1415
1416
1417
  	{ .compatible = "samsung,exynos5433-spi",
  			.data = (void *)&exynos5433_spi_port_config,
  	},
2b9080754   Thomas Abraham   spi: s3c64xx: add...
1418
1419
1420
  	{ },
  };
  MODULE_DEVICE_TABLE(of, s3c64xx_spi_dt_match);
2b9080754   Thomas Abraham   spi: s3c64xx: add...
1421

230d42d42   Jassi Brar   spi: Add s3c64xx ...
1422
1423
1424
  static struct platform_driver s3c64xx_spi_driver = {
  	.driver = {
  		.name	= "s3c64xx-spi",
e25d0bf91   Mark Brown   spi/s3c64xx: Conv...
1425
  		.pm = &s3c64xx_spi_pm,
2b9080754   Thomas Abraham   spi: s3c64xx: add...
1426
  		.of_match_table = of_match_ptr(s3c64xx_spi_dt_match),
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1427
  	},
50c959fc3   Lukasz Czerwinski   spi: spi-s3c64xx:...
1428
  	.probe = s3c64xx_spi_probe,
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1429
  	.remove = s3c64xx_spi_remove,
a5238e360   Thomas Abraham   spi: s3c64xx: mov...
1430
  	.id_table = s3c64xx_spi_driver_ids,
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1431
1432
  };
  MODULE_ALIAS("platform:s3c64xx-spi");
50c959fc3   Lukasz Czerwinski   spi: spi-s3c64xx:...
1433
  module_platform_driver(s3c64xx_spi_driver);
230d42d42   Jassi Brar   spi: Add s3c64xx ...
1434
1435
1436
1437
  
  MODULE_AUTHOR("Jaswinder Singh <jassi.brar@samsung.com>");
  MODULE_DESCRIPTION("S3C64XX SPI Controller Driver");
  MODULE_LICENSE("GPL");