Blame view

drivers/spi/spi-mpc52xx-psc.c 13 KB
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
1
  /*
57cc09793   Grant Likely   mpc5200_psc_spi: ...
2
   * MPC52xx PSC in SPI mode driver.
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
3
4
5
6
7
8
9
10
11
12
13
14
   *
   * Maintainer: Dragos Carp
   *
   * Copyright (C) 2006 TOPTICA Photonics AG.
   *
   * This program is free software; you can redistribute  it and/or modify it
   * under  the terms of  the GNU General  Public License as published by the
   * Free Software Foundation;  either version 2 of the  License, or (at your
   * option) any later version.
   */
  
  #include <linux/module.h>
739028429   Anton Vorontsov   mpc52xx_psc_spi: ...
15
  #include <linux/types.h>
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
16
17
  #include <linux/errno.h>
  #include <linux/interrupt.h>
22ae782f8   Grant Likely   of/address: Clean...
18
  #include <linux/of_address.h>
76ef7dd03   Stephen Rothwell   powerpc/mpc52xx_p...
19
  #include <linux/of_platform.h>
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
20
21
22
23
24
25
  #include <linux/workqueue.h>
  #include <linux/completion.h>
  #include <linux/io.h>
  #include <linux/delay.h>
  #include <linux/spi/spi.h>
  #include <linux/fsl_devices.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
26
  #include <linux/slab.h>
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
27
28
29
30
31
32
33
34
  
  #include <asm/mpc52xx.h>
  #include <asm/mpc52xx_psc.h>
  
  #define MCLK 20000000 /* PSC port MClk in hz */
  
  struct mpc52xx_psc_spi {
  	/* fsl_spi_platform data */
739028429   Anton Vorontsov   mpc52xx_psc_spi: ...
35
  	void (*cs_control)(struct spi_device *spi, bool on);
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
36
37
38
39
  	u32 sysclk;
  
  	/* driver internal data */
  	struct mpc52xx_psc __iomem *psc;
4874cc1b5   Grant Likely   powerpc: mpc5200:...
40
  	struct mpc52xx_psc_fifo __iomem *fifo;
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
41
42
43
  	unsigned int irq;
  	u8 bits_per_word;
  	u8 busy;
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
  	struct work_struct work;
  
  	struct list_head queue;
  	spinlock_t lock;
  
  	struct completion done;
  };
  
  /* controller state */
  struct mpc52xx_psc_spi_cs {
  	int bits_per_word;
  	int speed_hz;
  };
  
  /* set clock freq, clock ramp, bits per work
   * if t is NULL then reset the values to the default values
   */
  static int mpc52xx_psc_spi_transfer_setup(struct spi_device *spi,
  		struct spi_transfer *t)
  {
  	struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
  
  	cs->speed_hz = (t && t->speed_hz)
  			? t->speed_hz : spi->max_speed_hz;
  	cs->bits_per_word = (t && t->bits_per_word)
  			? t->bits_per_word : spi->bits_per_word;
  	cs->bits_per_word = ((cs->bits_per_word + 7) / 8) * 8;
  	return 0;
  }
  
  static void mpc52xx_psc_spi_activate_cs(struct spi_device *spi)
  {
  	struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
  	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
  	struct mpc52xx_psc __iomem *psc = mps->psc;
  	u32 sicr;
  	u16 ccr;
  
  	sicr = in_be32(&psc->sicr);
  
  	/* Set clock phase and polarity */
  	if (spi->mode & SPI_CPHA)
  		sicr |= 0x00001000;
  	else
  		sicr &= ~0x00001000;
  	if (spi->mode & SPI_CPOL)
  		sicr |= 0x00002000;
  	else
  		sicr &= ~0x00002000;
  
  	if (spi->mode & SPI_LSB_FIRST)
  		sicr |= 0x10000000;
  	else
  		sicr &= ~0x10000000;
  	out_be32(&psc->sicr, sicr);
  
  	/* Set clock frequency and bits per word
  	 * Because psc->ccr is defined as 16bit register instead of 32bit
  	 * just set the lower byte of BitClkDiv
  	 */
a897ea13f   Grant Likely   powerpc/mpc5200: ...
104
  	ccr = in_be16((u16 __iomem *)&psc->ccr);
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
105
106
107
108
109
  	ccr &= 0xFF00;
  	if (cs->speed_hz)
  		ccr |= (MCLK / cs->speed_hz - 1) & 0xFF;
  	else /* by default SPI Clk 1MHz */
  		ccr |= (MCLK / 1000000 - 1) & 0xFF;
a897ea13f   Grant Likely   powerpc/mpc5200: ...
110
  	out_be16((u16 __iomem *)&psc->ccr, ccr);
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
111
  	mps->bits_per_word = cs->bits_per_word;
739028429   Anton Vorontsov   mpc52xx_psc_spi: ...
112
113
  	if (mps->cs_control)
  		mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 1 : 0);
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
114
115
116
117
118
  }
  
  static void mpc52xx_psc_spi_deactivate_cs(struct spi_device *spi)
  {
  	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
739028429   Anton Vorontsov   mpc52xx_psc_spi: ...
119
120
  	if (mps->cs_control)
  		mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 0 : 1);
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
121
122
123
124
125
126
127
128
129
130
131
  }
  
  #define MPC52xx_PSC_BUFSIZE (MPC52xx_PSC_RFNUM_MASK + 1)
  /* wake up when 80% fifo full */
  #define MPC52xx_PSC_RFALARM (MPC52xx_PSC_BUFSIZE * 20 / 100)
  
  static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi,
  						struct spi_transfer *t)
  {
  	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
  	struct mpc52xx_psc __iomem *psc = mps->psc;
4874cc1b5   Grant Likely   powerpc: mpc5200:...
132
  	struct mpc52xx_psc_fifo __iomem *fifo = mps->fifo;
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
133
134
135
136
137
138
139
  	unsigned rb = 0;	/* number of bytes receieved */
  	unsigned sb = 0;	/* number of bytes sent */
  	unsigned char *rx_buf = (unsigned char *)t->rx_buf;
  	unsigned char *tx_buf = (unsigned char *)t->tx_buf;
  	unsigned rfalarm;
  	unsigned send_at_once = MPC52xx_PSC_BUFSIZE;
  	unsigned recv_at_once;
b7d271df8   Stefano Babic   spi: mpc52xx_psc_...
140
  	int last_block = 0;
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
141
142
143
144
145
146
147
148
149
  
  	if (!t->tx_buf && !t->rx_buf && t->len)
  		return -EINVAL;
  
  	/* enable transmiter/receiver */
  	out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
  	while (rb < t->len) {
  		if (t->len - rb > MPC52xx_PSC_BUFSIZE) {
  			rfalarm = MPC52xx_PSC_RFALARM;
b7d271df8   Stefano Babic   spi: mpc52xx_psc_...
150
  			last_block = 0;
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
151
152
153
  		} else {
  			send_at_once = t->len - sb;
  			rfalarm = MPC52xx_PSC_BUFSIZE - (t->len - rb);
b7d271df8   Stefano Babic   spi: mpc52xx_psc_...
154
  			last_block = 1;
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
155
156
157
158
  		}
  
  		dev_dbg(&spi->dev, "send %d bytes...
  ", send_at_once);
9a7867e1b   Luotao Fu   mpc52xx_psc_spi: ...
159
160
  		for (; send_at_once; sb++, send_at_once--) {
  			/* set EOF flag before the last word is sent */
b7d271df8   Stefano Babic   spi: mpc52xx_psc_...
161
  			if (send_at_once == 1 && last_block)
9a7867e1b   Luotao Fu   mpc52xx_psc_spi: ...
162
163
164
  				out_8(&psc->ircr2, 0x01);
  
  			if (tx_buf)
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
165
  				out_8(&psc->mpc52xx_psc_buffer_8, tx_buf[sb]);
9a7867e1b   Luotao Fu   mpc52xx_psc_spi: ...
166
  			else
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
167
  				out_8(&psc->mpc52xx_psc_buffer_8, 0);
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
168
  		}
3a4fa0a25   Robert P. J. Day   Fix misspellings ...
169
  		/* enable interrupts and wait for wake up
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
170
171
172
173
174
175
176
177
  		 * if just one byte is expected the Rx FIFO genererates no
  		 * FFULL interrupt, so activate the RxRDY interrupt
  		 */
  		out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
  		if (t->len - rb == 1) {
  			out_8(&psc->mode, 0);
  		} else {
  			out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL);
4874cc1b5   Grant Likely   powerpc: mpc5200:...
178
  			out_be16(&fifo->rfalarm, rfalarm);
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
179
180
181
  		}
  		out_be16(&psc->mpc52xx_psc_imr, MPC52xx_PSC_IMR_RXRDY);
  		wait_for_completion(&mps->done);
4874cc1b5   Grant Likely   powerpc: mpc5200:...
182
  		recv_at_once = in_be16(&fifo->rfnum);
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
  		dev_dbg(&spi->dev, "%d bytes received
  ", recv_at_once);
  
  		send_at_once = recv_at_once;
  		if (rx_buf) {
  			for (; recv_at_once; rb++, recv_at_once--)
  				rx_buf[rb] = in_8(&psc->mpc52xx_psc_buffer_8);
  		} else {
  			for (; recv_at_once; rb++, recv_at_once--)
  				in_8(&psc->mpc52xx_psc_buffer_8);
  		}
  	}
  	/* disable transmiter/receiver */
  	out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
  
  	return 0;
  }
  
  static void mpc52xx_psc_spi_work(struct work_struct *work)
  {
  	struct mpc52xx_psc_spi *mps =
  		container_of(work, struct mpc52xx_psc_spi, work);
  
  	spin_lock_irq(&mps->lock);
  	mps->busy = 1;
  	while (!list_empty(&mps->queue)) {
  		struct spi_message *m;
  		struct spi_device *spi;
  		struct spi_transfer *t = NULL;
  		unsigned cs_change;
  		int status;
  
  		m = container_of(mps->queue.next, struct spi_message, queue);
  		list_del_init(&m->queue);
  		spin_unlock_irq(&mps->lock);
  
  		spi = m->spi;
  		cs_change = 1;
  		status = 0;
  		list_for_each_entry (t, &m->transfers, transfer_list) {
  			if (t->bits_per_word || t->speed_hz) {
  				status = mpc52xx_psc_spi_transfer_setup(spi, t);
  				if (status < 0)
  					break;
  			}
  
  			if (cs_change)
  				mpc52xx_psc_spi_activate_cs(spi);
  			cs_change = t->cs_change;
  
  			status = mpc52xx_psc_spi_transfer_rxtx(spi, t);
  			if (status)
  				break;
  			m->actual_length += t->len;
  
  			if (t->delay_usecs)
  				udelay(t->delay_usecs);
  
  			if (cs_change)
  				mpc52xx_psc_spi_deactivate_cs(spi);
  		}
  
  		m->status = status;
0a6d38795   Axel Lin   spi: Always check...
246
247
  		if (m->complete)
  			m->complete(m->context);
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
  
  		if (status || !cs_change)
  			mpc52xx_psc_spi_deactivate_cs(spi);
  
  		mpc52xx_psc_spi_transfer_setup(spi, NULL);
  
  		spin_lock_irq(&mps->lock);
  	}
  	mps->busy = 0;
  	spin_unlock_irq(&mps->lock);
  }
  
  static int mpc52xx_psc_spi_setup(struct spi_device *spi)
  {
  	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
  	struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
  	unsigned long flags;
  
  	if (spi->bits_per_word%8)
  		return -EINVAL;
  
  	if (!cs) {
  		cs = kzalloc(sizeof *cs, GFP_KERNEL);
  		if (!cs)
  			return -ENOMEM;
  		spi->controller_state = cs;
  	}
  
  	cs->bits_per_word = spi->bits_per_word;
  	cs->speed_hz = spi->max_speed_hz;
  
  	spin_lock_irqsave(&mps->lock, flags);
  	if (!mps->busy)
  		mpc52xx_psc_spi_deactivate_cs(spi);
  	spin_unlock_irqrestore(&mps->lock, flags);
  
  	return 0;
  }
  
  static int mpc52xx_psc_spi_transfer(struct spi_device *spi,
  		struct spi_message *m)
  {
  	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
  	unsigned long flags;
  
  	m->actual_length = 0;
  	m->status = -EINPROGRESS;
  
  	spin_lock_irqsave(&mps->lock, flags);
  	list_add_tail(&m->queue, &mps->queue);
ac96b737c   Bhaktipriya Shridhar   spi: spi-mpc52xx-...
298
  	schedule_work(&mps->work);
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
299
300
301
302
303
304
305
306
307
308
309
310
  	spin_unlock_irqrestore(&mps->lock, flags);
  
  	return 0;
  }
  
  static void mpc52xx_psc_spi_cleanup(struct spi_device *spi)
  {
  	kfree(spi->controller_state);
  }
  
  static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps)
  {
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
311
  	struct mpc52xx_psc __iomem *psc = mps->psc;
4874cc1b5   Grant Likely   powerpc: mpc5200:...
312
  	struct mpc52xx_psc_fifo __iomem *fifo = mps->fifo;
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
313
  	u32 mclken_div;
f856cf017   Wolfram Sang   spi/mpc52xx-psc-s...
314
  	int ret;
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
315

00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
316
  	/* default sysclk is 512MHz */
4fb4c5582   Grant Likely   [POWERPC] mpc52xx...
317
  	mclken_div = (mps->sysclk ? mps->sysclk : 512000000) / MCLK;
f856cf017   Wolfram Sang   spi/mpc52xx-psc-s...
318
319
320
  	ret = mpc52xx_set_psc_clkdiv(psc_id, mclken_div);
  	if (ret)
  		return ret;
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
321
322
323
324
325
326
327
328
329
  
  	/* Reset the PSC into a known state */
  	out_8(&psc->command, MPC52xx_PSC_RST_RX);
  	out_8(&psc->command, MPC52xx_PSC_RST_TX);
  	out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
  
  	/* Disable interrupts, interrupts are based on alarm level */
  	out_be16(&psc->mpc52xx_psc_imr, 0);
  	out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
4874cc1b5   Grant Likely   powerpc: mpc5200:...
330
  	out_8(&fifo->rfcntl, 0);
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
331
332
333
334
335
  	out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL);
  
  	/* Configure 8bit codec mode as a SPI master and use EOF flags */
  	/* SICR_SIM_CODEC8|SICR_GENCLK|SICR_SPI|SICR_MSTR|SICR_USEEOF */
  	out_be32(&psc->sicr, 0x0180C800);
a897ea13f   Grant Likely   powerpc/mpc5200: ...
336
  	out_be16((u16 __iomem *)&psc->ccr, 0x070F); /* default SPI Clk 1MHz */
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
337
338
339
340
341
342
  
  	/* Set 2ms DTL delay */
  	out_8(&psc->ctur, 0x00);
  	out_8(&psc->ctlr, 0x84);
  
  	mps->bits_per_word = 8;
f856cf017   Wolfram Sang   spi/mpc52xx-psc-s...
343
  	return 0;
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
  }
  
  static irqreturn_t mpc52xx_psc_spi_isr(int irq, void *dev_id)
  {
  	struct mpc52xx_psc_spi *mps = (struct mpc52xx_psc_spi *)dev_id;
  	struct mpc52xx_psc __iomem *psc = mps->psc;
  
  	/* disable interrupt and wake up the work queue */
  	if (in_be16(&psc->mpc52xx_psc_isr) & MPC52xx_PSC_IMR_RXRDY) {
  		out_be16(&psc->mpc52xx_psc_imr, 0);
  		complete(&mps->done);
  		return IRQ_HANDLED;
  	}
  	return IRQ_NONE;
  }
  
  /* bus_num is used only for the case dev->platform_data == NULL */
fd4a319bc   Grant Likely   spi: Remove HOTPL...
361
  static int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
362
363
  				u32 size, unsigned int irq, s16 bus_num)
  {
8074cf063   Jingoo Han   spi: use dev_get_...
364
  	struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
365
366
367
  	struct mpc52xx_psc_spi *mps;
  	struct spi_master *master;
  	int ret;
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
368
369
370
371
372
373
  	master = spi_alloc_master(dev, sizeof *mps);
  	if (master == NULL)
  		return -ENOMEM;
  
  	dev_set_drvdata(dev, master);
  	mps = spi_master_get_devdata(master);
e7db06b5d   David Brownell   spi: move more sp...
374
375
  	/* the spi->mode bits understood by this driver: */
  	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
376
377
  	mps->irq = irq;
  	if (pdata == NULL) {
f6bd03a74   Jarkko Nikula   spi: Don't break ...
378
379
380
  		dev_warn(dev,
  			 "probe called without platform data, no cs_control function will be called
  ");
739028429   Anton Vorontsov   mpc52xx_psc_spi: ...
381
  		mps->cs_control = NULL;
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
382
383
384
385
  		mps->sysclk = 0;
  		master->bus_num = bus_num;
  		master->num_chipselect = 255;
  	} else {
739028429   Anton Vorontsov   mpc52xx_psc_spi: ...
386
  		mps->cs_control = pdata->cs_control;
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
387
388
389
390
391
392
393
  		mps->sysclk = pdata->sysclk;
  		master->bus_num = pdata->bus_num;
  		master->num_chipselect = pdata->max_chipselect;
  	}
  	master->setup = mpc52xx_psc_spi_setup;
  	master->transfer = mpc52xx_psc_spi_transfer;
  	master->cleanup = mpc52xx_psc_spi_cleanup;
12b15e832   Anatolij Gustschin   of/spi: call of_r...
394
  	master->dev.of_node = dev->of_node;
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
395
396
397
398
399
400
401
402
  
  	mps->psc = ioremap(regaddr, size);
  	if (!mps->psc) {
  		dev_err(dev, "could not ioremap I/O port range
  ");
  		ret = -EFAULT;
  		goto free_master;
  	}
4874cc1b5   Grant Likely   powerpc: mpc5200:...
403
404
  	/* On the 5200, fifo regs are immediately ajacent to the psc regs */
  	mps->fifo = ((void __iomem *)mps->psc) + sizeof(struct mpc52xx_psc);
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
405
406
407
408
409
410
411
  
  	ret = request_irq(mps->irq, mpc52xx_psc_spi_isr, 0, "mpc52xx-psc-spi",
  				mps);
  	if (ret)
  		goto free_master;
  
  	ret = mpc52xx_psc_spi_port_config(master->bus_num, mps);
f856cf017   Wolfram Sang   spi/mpc52xx-psc-s...
412
413
414
  	if (ret < 0) {
  		dev_err(dev, "can't configure PSC! Is it capable of SPI?
  ");
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
415
  		goto free_irq;
f856cf017   Wolfram Sang   spi/mpc52xx-psc-s...
416
  	}
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
417
418
419
420
421
  
  	spin_lock_init(&mps->lock);
  	init_completion(&mps->done);
  	INIT_WORK(&mps->work, mpc52xx_psc_spi_work);
  	INIT_LIST_HEAD(&mps->queue);
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
422
423
  	ret = spi_register_master(master);
  	if (ret < 0)
ac96b737c   Bhaktipriya Shridhar   spi: spi-mpc52xx-...
424
  		goto free_irq;
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
425
426
  
  	return ret;
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
427
428
429
430
431
432
433
434
435
  free_irq:
  	free_irq(mps->irq, mps);
  free_master:
  	if (mps->psc)
  		iounmap(mps->psc);
  	spi_master_put(master);
  
  	return ret;
  }
fd4a319bc   Grant Likely   spi: Remove HOTPL...
436
  static int mpc52xx_psc_spi_of_probe(struct platform_device *op)
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
437
438
439
440
  {
  	const u32 *regaddr_p;
  	u64 regaddr64, size64;
  	s16 id = -1;
61c7a080a   Grant Likely   of: Always use 's...
441
  	regaddr_p = of_get_address(op->dev.of_node, 0, &size64, NULL);
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
442
  	if (!regaddr_p) {
5cc17d7e0   Wolfram Sang   spi/mpc52xx: repl...
443
444
  		dev_err(&op->dev, "Invalid PSC address
  ");
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
445
446
  		return -EINVAL;
  	}
61c7a080a   Grant Likely   of: Always use 's...
447
  	regaddr64 = of_translate_address(op->dev.of_node, regaddr_p);
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
448

8888735fc   Domen Puncer   mpc52xx_psc_spi: ...
449
  	/* get PSC id (1..6, used by port_config) */
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
450
  	if (op->dev.platform_data == NULL) {
8888735fc   Domen Puncer   mpc52xx_psc_spi: ...
451
  		const u32 *psc_nump;
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
452

61c7a080a   Grant Likely   of: Always use 's...
453
  		psc_nump = of_get_property(op->dev.of_node, "cell-index", NULL);
8888735fc   Domen Puncer   mpc52xx_psc_spi: ...
454
  		if (!psc_nump || *psc_nump > 5) {
5cc17d7e0   Wolfram Sang   spi/mpc52xx: repl...
455
456
  			dev_err(&op->dev, "Invalid cell-index property
  ");
8888735fc   Domen Puncer   mpc52xx_psc_spi: ...
457
  			return -EINVAL;
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
458
  		}
8888735fc   Domen Puncer   mpc52xx_psc_spi: ...
459
  		id = *psc_nump + 1;
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
460
  	}
12b15e832   Anatolij Gustschin   of/spi: call of_r...
461
  	return mpc52xx_psc_spi_do_probe(&op->dev, (u32)regaddr64, (u32)size64,
61c7a080a   Grant Likely   of: Always use 's...
462
  				irq_of_parse_and_map(op->dev.of_node, 0), id);
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
463
  }
fd4a319bc   Grant Likely   spi: Remove HOTPL...
464
  static int mpc52xx_psc_spi_of_remove(struct platform_device *op)
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
465
  {
24b5a82cf   Jingoo Han   spi: use platform...
466
  	struct spi_master *master = spi_master_get(platform_get_drvdata(op));
5aa68b859   Wolfram Sang   spi/mpc52xx-psc-s...
467
  	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
ac96b737c   Bhaktipriya Shridhar   spi: spi-mpc52xx-...
468
  	flush_work(&mps->work);
5aa68b859   Wolfram Sang   spi/mpc52xx-psc-s...
469
470
471
472
  	spi_unregister_master(master);
  	free_irq(mps->irq, mps);
  	if (mps->psc)
  		iounmap(mps->psc);
c8c87c656   Guenter Roeck   spi/mpc52xx-psc: ...
473
  	spi_master_put(master);
5aa68b859   Wolfram Sang   spi/mpc52xx-psc-s...
474
475
  
  	return 0;
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
476
  }
631e61b7c   Márton Németh   spi: make Open Fi...
477
  static const struct of_device_id mpc52xx_psc_spi_of_match[] = {
66ffbe490   Grant Likely   [POWERPC] mpc5200...
478
479
480
  	{ .compatible = "fsl,mpc5200-psc-spi", },
  	{ .compatible = "mpc5200-psc-spi", }, /* old */
  	{}
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
481
482
483
  };
  
  MODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match);
18d306d13   Grant Likely   dt/spi: Eliminate...
484
  static struct platform_driver mpc52xx_psc_spi_of_driver = {
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
485
  	.probe = mpc52xx_psc_spi_of_probe,
fd4a319bc   Grant Likely   spi: Remove HOTPL...
486
  	.remove = mpc52xx_psc_spi_of_remove,
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
487
488
  	.driver = {
  		.name = "mpc52xx-psc-spi",
4018294b5   Grant Likely   of: Remove duplic...
489
  		.of_match_table = mpc52xx_psc_spi_of_match,
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
490
491
  	},
  };
940ab8896   Grant Likely   drivercore: Add h...
492
  module_platform_driver(mpc52xx_psc_spi_of_driver);
00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
493

00b8fd236   Dragos Carp   MPC52xx PSC SPI m...
494
495
496
  MODULE_AUTHOR("Dragos Carp");
  MODULE_DESCRIPTION("MPC52xx PSC SPI Driver");
  MODULE_LICENSE("GPL");