100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp/*
257cc097931e2d28a27e19515c549dc301ba6b6b2Grant Likely * MPC52xx PSC in SPI mode driver.
300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp *
400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp * Maintainer: Dragos Carp
500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp *
600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp * Copyright (C) 2006 TOPTICA Photonics AG.
700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp *
800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp * This program is free software; you can redistribute  it and/or modify it
900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp * under  the terms of  the GNU General  Public License as published by the
1000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp * Free Software Foundation;  either version 2 of the  License, or (at your
1100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp * option) any later version.
1200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp */
1300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
1400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <linux/module.h>
157390284290b184a7f4bb648ca15dc62c3dea3e75Anton Vorontsov#include <linux/types.h>
1600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <linux/errno.h>
1700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <linux/interrupt.h>
1822ae782f86b726f9cea752c0f269ff6dcdf2f6e1Grant Likely#include <linux/of_address.h>
1976ef7dd030823518506d65237a12666fc3f5a0d4Stephen Rothwell#include <linux/of_platform.h>
2000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <linux/workqueue.h>
2100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <linux/completion.h>
2200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <linux/io.h>
2300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <linux/delay.h>
2400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <linux/spi/spi.h>
2500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <linux/fsl_devices.h>
265a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
2700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
2800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <asm/mpc52xx.h>
2900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#include <asm/mpc52xx_psc.h>
3000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
3100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#define MCLK 20000000 /* PSC port MClk in hz */
3200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
3300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstruct mpc52xx_psc_spi {
3400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	/* fsl_spi_platform data */
357390284290b184a7f4bb648ca15dc62c3dea3e75Anton Vorontsov	void (*cs_control)(struct spi_device *spi, bool on);
3600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	u32 sysclk;
3700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
3800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	/* driver internal data */
3900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	struct mpc52xx_psc __iomem *psc;
404874cc1b5142397d585c63d84b3d6d3afff60354Grant Likely	struct mpc52xx_psc_fifo __iomem *fifo;
4100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	unsigned int irq;
4200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	u8 bits_per_word;
4300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	u8 busy;
4400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
4500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	struct workqueue_struct *workqueue;
4600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	struct work_struct work;
4700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
4800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	struct list_head queue;
4900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	spinlock_t lock;
5000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
5100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	struct completion done;
5200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp};
5300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
5400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp/* controller state */
5500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstruct mpc52xx_psc_spi_cs {
5600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	int bits_per_word;
5700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	int speed_hz;
5800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp};
5900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
6000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp/* set clock freq, clock ramp, bits per work
6100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp * if t is NULL then reset the values to the default values
6200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp */
6300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstatic int mpc52xx_psc_spi_transfer_setup(struct spi_device *spi,
6400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		struct spi_transfer *t)
6500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{
6600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
6700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
6800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	cs->speed_hz = (t && t->speed_hz)
6900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp			? t->speed_hz : spi->max_speed_hz;
7000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	cs->bits_per_word = (t && t->bits_per_word)
7100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp			? t->bits_per_word : spi->bits_per_word;
7200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	cs->bits_per_word = ((cs->bits_per_word + 7) / 8) * 8;
7300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	return 0;
7400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp}
7500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
7600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstatic void mpc52xx_psc_spi_activate_cs(struct spi_device *spi)
7700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{
7800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
7900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
8000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	struct mpc52xx_psc __iomem *psc = mps->psc;
8100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	u32 sicr;
8200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	u16 ccr;
8300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
8400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	sicr = in_be32(&psc->sicr);
8500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
8600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	/* Set clock phase and polarity */
8700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	if (spi->mode & SPI_CPHA)
8800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		sicr |= 0x00001000;
8900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	else
9000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		sicr &= ~0x00001000;
9100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	if (spi->mode & SPI_CPOL)
9200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		sicr |= 0x00002000;
9300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	else
9400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		sicr &= ~0x00002000;
9500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
9600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	if (spi->mode & SPI_LSB_FIRST)
9700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		sicr |= 0x10000000;
9800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	else
9900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		sicr &= ~0x10000000;
10000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	out_be32(&psc->sicr, sicr);
10100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
10200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	/* Set clock frequency and bits per word
10300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	 * Because psc->ccr is defined as 16bit register instead of 32bit
10400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	 * just set the lower byte of BitClkDiv
10500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	 */
106a897ea13f7a801e6baba8d4985f459042712244cGrant Likely	ccr = in_be16((u16 __iomem *)&psc->ccr);
10700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	ccr &= 0xFF00;
10800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	if (cs->speed_hz)
10900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		ccr |= (MCLK / cs->speed_hz - 1) & 0xFF;
11000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	else /* by default SPI Clk 1MHz */
11100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		ccr |= (MCLK / 1000000 - 1) & 0xFF;
112a897ea13f7a801e6baba8d4985f459042712244cGrant Likely	out_be16((u16 __iomem *)&psc->ccr, ccr);
11300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	mps->bits_per_word = cs->bits_per_word;
11400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
1157390284290b184a7f4bb648ca15dc62c3dea3e75Anton Vorontsov	if (mps->cs_control)
1167390284290b184a7f4bb648ca15dc62c3dea3e75Anton Vorontsov		mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 1 : 0);
11700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp}
11800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
11900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstatic void mpc52xx_psc_spi_deactivate_cs(struct spi_device *spi)
12000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{
12100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
12200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
1237390284290b184a7f4bb648ca15dc62c3dea3e75Anton Vorontsov	if (mps->cs_control)
1247390284290b184a7f4bb648ca15dc62c3dea3e75Anton Vorontsov		mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 0 : 1);
12500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp}
12600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
12700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#define MPC52xx_PSC_BUFSIZE (MPC52xx_PSC_RFNUM_MASK + 1)
12800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp/* wake up when 80% fifo full */
12900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp#define MPC52xx_PSC_RFALARM (MPC52xx_PSC_BUFSIZE * 20 / 100)
13000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
13100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstatic int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi,
13200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp						struct spi_transfer *t)
13300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{
13400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
13500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	struct mpc52xx_psc __iomem *psc = mps->psc;
1364874cc1b5142397d585c63d84b3d6d3afff60354Grant Likely	struct mpc52xx_psc_fifo __iomem *fifo = mps->fifo;
13700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	unsigned rb = 0;	/* number of bytes receieved */
13800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	unsigned sb = 0;	/* number of bytes sent */
13900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	unsigned char *rx_buf = (unsigned char *)t->rx_buf;
14000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	unsigned char *tx_buf = (unsigned char *)t->tx_buf;
14100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	unsigned rfalarm;
14200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	unsigned send_at_once = MPC52xx_PSC_BUFSIZE;
14300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	unsigned recv_at_once;
144b7d271df873c5121a4ca1c70dea126b5920ec2f1Stefano Babic	int last_block = 0;
14500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
14600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	if (!t->tx_buf && !t->rx_buf && t->len)
14700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		return -EINVAL;
14800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
14900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	/* enable transmiter/receiver */
15000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
15100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	while (rb < t->len) {
15200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		if (t->len - rb > MPC52xx_PSC_BUFSIZE) {
15300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp			rfalarm = MPC52xx_PSC_RFALARM;
154b7d271df873c5121a4ca1c70dea126b5920ec2f1Stefano Babic			last_block = 0;
15500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		} else {
15600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp			send_at_once = t->len - sb;
15700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp			rfalarm = MPC52xx_PSC_BUFSIZE - (t->len - rb);
158b7d271df873c5121a4ca1c70dea126b5920ec2f1Stefano Babic			last_block = 1;
15900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		}
16000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
16100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		dev_dbg(&spi->dev, "send %d bytes...\n", send_at_once);
1629a7867e1b34c3575e7e76a05c0c54c6edbdae2a4Luotao Fu		for (; send_at_once; sb++, send_at_once--) {
1639a7867e1b34c3575e7e76a05c0c54c6edbdae2a4Luotao Fu			/* set EOF flag before the last word is sent */
164b7d271df873c5121a4ca1c70dea126b5920ec2f1Stefano Babic			if (send_at_once == 1 && last_block)
1659a7867e1b34c3575e7e76a05c0c54c6edbdae2a4Luotao Fu				out_8(&psc->ircr2, 0x01);
1669a7867e1b34c3575e7e76a05c0c54c6edbdae2a4Luotao Fu
1679a7867e1b34c3575e7e76a05c0c54c6edbdae2a4Luotao Fu			if (tx_buf)
16800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp				out_8(&psc->mpc52xx_psc_buffer_8, tx_buf[sb]);
1699a7867e1b34c3575e7e76a05c0c54c6edbdae2a4Luotao Fu			else
17000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp				out_8(&psc->mpc52xx_psc_buffer_8, 0);
17100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		}
17200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
17300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
1743a4fa0a25da81600ea0bcd75692ae8ca6050d165Robert P. J. Day		/* enable interrupts and wait for wake up
17500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		 * if just one byte is expected the Rx FIFO genererates no
17600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		 * FFULL interrupt, so activate the RxRDY interrupt
17700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		 */
17800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
17900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		if (t->len - rb == 1) {
18000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp			out_8(&psc->mode, 0);
18100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		} else {
18200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp			out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL);
1834874cc1b5142397d585c63d84b3d6d3afff60354Grant Likely			out_be16(&fifo->rfalarm, rfalarm);
18400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		}
18500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		out_be16(&psc->mpc52xx_psc_imr, MPC52xx_PSC_IMR_RXRDY);
18600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		wait_for_completion(&mps->done);
1874874cc1b5142397d585c63d84b3d6d3afff60354Grant Likely		recv_at_once = in_be16(&fifo->rfnum);
18800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		dev_dbg(&spi->dev, "%d bytes received\n", recv_at_once);
18900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
19000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		send_at_once = recv_at_once;
19100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		if (rx_buf) {
19200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp			for (; recv_at_once; rb++, recv_at_once--)
19300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp				rx_buf[rb] = in_8(&psc->mpc52xx_psc_buffer_8);
19400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		} else {
19500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp			for (; recv_at_once; rb++, recv_at_once--)
19600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp				in_8(&psc->mpc52xx_psc_buffer_8);
19700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		}
19800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	}
19900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	/* disable transmiter/receiver */
20000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
20100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
20200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	return 0;
20300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp}
20400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
20500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstatic void mpc52xx_psc_spi_work(struct work_struct *work)
20600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{
20700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	struct mpc52xx_psc_spi *mps =
20800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		container_of(work, struct mpc52xx_psc_spi, work);
20900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
21000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	spin_lock_irq(&mps->lock);
21100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	mps->busy = 1;
21200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	while (!list_empty(&mps->queue)) {
21300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		struct spi_message *m;
21400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		struct spi_device *spi;
21500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		struct spi_transfer *t = NULL;
21600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		unsigned cs_change;
21700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		int status;
21800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
21900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		m = container_of(mps->queue.next, struct spi_message, queue);
22000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		list_del_init(&m->queue);
22100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		spin_unlock_irq(&mps->lock);
22200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
22300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		spi = m->spi;
22400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		cs_change = 1;
22500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		status = 0;
22600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		list_for_each_entry (t, &m->transfers, transfer_list) {
22700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp			if (t->bits_per_word || t->speed_hz) {
22800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp				status = mpc52xx_psc_spi_transfer_setup(spi, t);
22900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp				if (status < 0)
23000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp					break;
23100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp			}
23200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
23300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp			if (cs_change)
23400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp				mpc52xx_psc_spi_activate_cs(spi);
23500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp			cs_change = t->cs_change;
23600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
23700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp			status = mpc52xx_psc_spi_transfer_rxtx(spi, t);
23800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp			if (status)
23900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp				break;
24000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp			m->actual_length += t->len;
24100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
24200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp			if (t->delay_usecs)
24300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp				udelay(t->delay_usecs);
24400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
24500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp			if (cs_change)
24600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp				mpc52xx_psc_spi_deactivate_cs(spi);
24700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		}
24800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
24900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		m->status = status;
2500a6d38795a405c49ea0012f04173613382def58cAxel Lin		if (m->complete)
2510a6d38795a405c49ea0012f04173613382def58cAxel Lin			m->complete(m->context);
25200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
25300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		if (status || !cs_change)
25400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp			mpc52xx_psc_spi_deactivate_cs(spi);
25500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
25600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		mpc52xx_psc_spi_transfer_setup(spi, NULL);
25700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
25800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		spin_lock_irq(&mps->lock);
25900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	}
26000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	mps->busy = 0;
26100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	spin_unlock_irq(&mps->lock);
26200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp}
26300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
26400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstatic int mpc52xx_psc_spi_setup(struct spi_device *spi)
26500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{
26600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
26700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
26800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	unsigned long flags;
26900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
27000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	if (spi->bits_per_word%8)
27100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		return -EINVAL;
27200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
27300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	if (!cs) {
27400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		cs = kzalloc(sizeof *cs, GFP_KERNEL);
27500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		if (!cs)
27600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp			return -ENOMEM;
27700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		spi->controller_state = cs;
27800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	}
27900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
28000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	cs->bits_per_word = spi->bits_per_word;
28100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	cs->speed_hz = spi->max_speed_hz;
28200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
28300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	spin_lock_irqsave(&mps->lock, flags);
28400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	if (!mps->busy)
28500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		mpc52xx_psc_spi_deactivate_cs(spi);
28600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	spin_unlock_irqrestore(&mps->lock, flags);
28700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
28800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	return 0;
28900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp}
29000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
29100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstatic int mpc52xx_psc_spi_transfer(struct spi_device *spi,
29200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		struct spi_message *m)
29300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{
29400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
29500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	unsigned long flags;
29600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
29700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	m->actual_length = 0;
29800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	m->status = -EINPROGRESS;
29900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
30000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	spin_lock_irqsave(&mps->lock, flags);
30100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	list_add_tail(&m->queue, &mps->queue);
30200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	queue_work(mps->workqueue, &mps->work);
30300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	spin_unlock_irqrestore(&mps->lock, flags);
30400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
30500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	return 0;
30600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp}
30700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
30800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstatic void mpc52xx_psc_spi_cleanup(struct spi_device *spi)
30900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{
31000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	kfree(spi->controller_state);
31100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp}
31200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
31300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstatic int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps)
31400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{
31500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	struct mpc52xx_psc __iomem *psc = mps->psc;
3164874cc1b5142397d585c63d84b3d6d3afff60354Grant Likely	struct mpc52xx_psc_fifo __iomem *fifo = mps->fifo;
31700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	u32 mclken_div;
318f856cf01787354fb3c8cde0a80de606f368b21edWolfram Sang	int ret;
31900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
32000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	/* default sysclk is 512MHz */
3214fb4c5582475452d3bf7c5072ef2d15ee06f7723Grant Likely	mclken_div = (mps->sysclk ? mps->sysclk : 512000000) / MCLK;
322f856cf01787354fb3c8cde0a80de606f368b21edWolfram Sang	ret = mpc52xx_set_psc_clkdiv(psc_id, mclken_div);
323f856cf01787354fb3c8cde0a80de606f368b21edWolfram Sang	if (ret)
324f856cf01787354fb3c8cde0a80de606f368b21edWolfram Sang		return ret;
32500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
32600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	/* Reset the PSC into a known state */
32700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	out_8(&psc->command, MPC52xx_PSC_RST_RX);
32800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	out_8(&psc->command, MPC52xx_PSC_RST_TX);
32900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
33000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
33100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	/* Disable interrupts, interrupts are based on alarm level */
33200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	out_be16(&psc->mpc52xx_psc_imr, 0);
33300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
3344874cc1b5142397d585c63d84b3d6d3afff60354Grant Likely	out_8(&fifo->rfcntl, 0);
33500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL);
33600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
33700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	/* Configure 8bit codec mode as a SPI master and use EOF flags */
33800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	/* SICR_SIM_CODEC8|SICR_GENCLK|SICR_SPI|SICR_MSTR|SICR_USEEOF */
33900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	out_be32(&psc->sicr, 0x0180C800);
340a897ea13f7a801e6baba8d4985f459042712244cGrant Likely	out_be16((u16 __iomem *)&psc->ccr, 0x070F); /* default SPI Clk 1MHz */
34100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
34200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	/* Set 2ms DTL delay */
34300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	out_8(&psc->ctur, 0x00);
34400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	out_8(&psc->ctlr, 0x84);
34500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
34600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	mps->bits_per_word = 8;
34700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
348f856cf01787354fb3c8cde0a80de606f368b21edWolfram Sang	return 0;
34900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp}
35000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
35100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpstatic irqreturn_t mpc52xx_psc_spi_isr(int irq, void *dev_id)
35200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{
35300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	struct mpc52xx_psc_spi *mps = (struct mpc52xx_psc_spi *)dev_id;
35400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	struct mpc52xx_psc __iomem *psc = mps->psc;
35500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
35600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	/* disable interrupt and wake up the work queue */
35700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	if (in_be16(&psc->mpc52xx_psc_isr) & MPC52xx_PSC_IMR_RXRDY) {
35800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		out_be16(&psc->mpc52xx_psc_imr, 0);
35900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		complete(&mps->done);
36000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		return IRQ_HANDLED;
36100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	}
36200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	return IRQ_NONE;
36300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp}
36400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
36500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp/* bus_num is used only for the case dev->platform_data == NULL */
366fd4a319bc933ae93e68935b21924a9ca4ba2d060Grant Likelystatic int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
36700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp				u32 size, unsigned int irq, s16 bus_num)
36800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{
3698074cf063e410a2c0cf1704c3b31002e21f5df7cJingoo Han	struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
37000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	struct mpc52xx_psc_spi *mps;
37100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	struct spi_master *master;
37200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	int ret;
37300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
37400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	master = spi_alloc_master(dev, sizeof *mps);
37500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	if (master == NULL)
37600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		return -ENOMEM;
37700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
37800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	dev_set_drvdata(dev, master);
37900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	mps = spi_master_get_devdata(master);
38000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
381e7db06b5d5afcef15c4c3e61c3a7441ed7ad1407David Brownell	/* the spi->mode bits understood by this driver: */
382e7db06b5d5afcef15c4c3e61c3a7441ed7ad1407David Brownell	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
383e7db06b5d5afcef15c4c3e61c3a7441ed7ad1407David Brownell
38400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	mps->irq = irq;
38500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	if (pdata == NULL) {
386f6bd03a746271f298aa5bfb6e049b245757efaedJarkko Nikula		dev_warn(dev,
387f6bd03a746271f298aa5bfb6e049b245757efaedJarkko Nikula			 "probe called without platform data, no cs_control function will be called\n");
3887390284290b184a7f4bb648ca15dc62c3dea3e75Anton Vorontsov		mps->cs_control = NULL;
38900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		mps->sysclk = 0;
39000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		master->bus_num = bus_num;
39100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		master->num_chipselect = 255;
39200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	} else {
3937390284290b184a7f4bb648ca15dc62c3dea3e75Anton Vorontsov		mps->cs_control = pdata->cs_control;
39400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		mps->sysclk = pdata->sysclk;
39500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		master->bus_num = pdata->bus_num;
39600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		master->num_chipselect = pdata->max_chipselect;
39700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	}
39800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	master->setup = mpc52xx_psc_spi_setup;
39900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	master->transfer = mpc52xx_psc_spi_transfer;
40000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	master->cleanup = mpc52xx_psc_spi_cleanup;
40112b15e83289bc7cf2ec9a342412e0c955beeb395Anatolij Gustschin	master->dev.of_node = dev->of_node;
40200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
40300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	mps->psc = ioremap(regaddr, size);
40400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	if (!mps->psc) {
40500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		dev_err(dev, "could not ioremap I/O port range\n");
40600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		ret = -EFAULT;
40700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		goto free_master;
40800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	}
4094874cc1b5142397d585c63d84b3d6d3afff60354Grant Likely	/* On the 5200, fifo regs are immediately ajacent to the psc regs */
4104874cc1b5142397d585c63d84b3d6d3afff60354Grant Likely	mps->fifo = ((void __iomem *)mps->psc) + sizeof(struct mpc52xx_psc);
41100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
41200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	ret = request_irq(mps->irq, mpc52xx_psc_spi_isr, 0, "mpc52xx-psc-spi",
41300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp				mps);
41400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	if (ret)
41500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		goto free_master;
41600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
41700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	ret = mpc52xx_psc_spi_port_config(master->bus_num, mps);
418f856cf01787354fb3c8cde0a80de606f368b21edWolfram Sang	if (ret < 0) {
419f856cf01787354fb3c8cde0a80de606f368b21edWolfram Sang		dev_err(dev, "can't configure PSC! Is it capable of SPI?\n");
42000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		goto free_irq;
421f856cf01787354fb3c8cde0a80de606f368b21edWolfram Sang	}
42200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
42300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	spin_lock_init(&mps->lock);
42400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	init_completion(&mps->done);
42500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	INIT_WORK(&mps->work, mpc52xx_psc_spi_work);
42600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	INIT_LIST_HEAD(&mps->queue);
42700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
42800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	mps->workqueue = create_singlethread_workqueue(
4296c7377ab6814c247d7600955a4ead2e3db490697Kay Sievers		dev_name(master->dev.parent));
43000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	if (mps->workqueue == NULL) {
43100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		ret = -EBUSY;
43200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		goto free_irq;
43300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	}
43400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
43500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	ret = spi_register_master(master);
43600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	if (ret < 0)
43700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		goto unreg_master;
43800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
43900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	return ret;
44000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
44100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpunreg_master:
44200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	destroy_workqueue(mps->workqueue);
44300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpfree_irq:
44400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	free_irq(mps->irq, mps);
44500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carpfree_master:
44600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	if (mps->psc)
44700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		iounmap(mps->psc);
44800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	spi_master_put(master);
44900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
45000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	return ret;
45100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp}
45200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
453fd4a319bc933ae93e68935b21924a9ca4ba2d060Grant Likelystatic int mpc52xx_psc_spi_of_probe(struct platform_device *op)
45400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{
45500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	const u32 *regaddr_p;
45600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	u64 regaddr64, size64;
45700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	s16 id = -1;
45800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
45961c7a080a5a061c976988fd4b844dfb468dda255Grant Likely	regaddr_p = of_get_address(op->dev.of_node, 0, &size64, NULL);
46000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	if (!regaddr_p) {
4615cc17d7e01abd77eda1267a75748cfc84c92a523Wolfram Sang		dev_err(&op->dev, "Invalid PSC address\n");
46200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		return -EINVAL;
46300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	}
46461c7a080a5a061c976988fd4b844dfb468dda255Grant Likely	regaddr64 = of_translate_address(op->dev.of_node, regaddr_p);
46500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
4668888735fcaac7681dbcca67fbcc88cf627c47b3aDomen Puncer	/* get PSC id (1..6, used by port_config) */
46700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	if (op->dev.platform_data == NULL) {
4688888735fcaac7681dbcca67fbcc88cf627c47b3aDomen Puncer		const u32 *psc_nump;
46900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
47061c7a080a5a061c976988fd4b844dfb468dda255Grant Likely		psc_nump = of_get_property(op->dev.of_node, "cell-index", NULL);
4718888735fcaac7681dbcca67fbcc88cf627c47b3aDomen Puncer		if (!psc_nump || *psc_nump > 5) {
4725cc17d7e01abd77eda1267a75748cfc84c92a523Wolfram Sang			dev_err(&op->dev, "Invalid cell-index property\n");
4738888735fcaac7681dbcca67fbcc88cf627c47b3aDomen Puncer			return -EINVAL;
47400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		}
4758888735fcaac7681dbcca67fbcc88cf627c47b3aDomen Puncer		id = *psc_nump + 1;
47600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	}
47700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
47812b15e83289bc7cf2ec9a342412e0c955beeb395Anatolij Gustschin	return mpc52xx_psc_spi_do_probe(&op->dev, (u32)regaddr64, (u32)size64,
47961c7a080a5a061c976988fd4b844dfb468dda255Grant Likely				irq_of_parse_and_map(op->dev.of_node, 0), id);
48000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp}
48100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
482fd4a319bc933ae93e68935b21924a9ca4ba2d060Grant Likelystatic int mpc52xx_psc_spi_of_remove(struct platform_device *op)
48300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp{
48424b5a82cf5709a4bc577f42fdaa61b23a7f58f08Jingoo Han	struct spi_master *master = spi_master_get(platform_get_drvdata(op));
4855aa68b85951aec91d6a955d1de861325fc9a3ba1Wolfram Sang	struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
4865aa68b85951aec91d6a955d1de861325fc9a3ba1Wolfram Sang
4875aa68b85951aec91d6a955d1de861325fc9a3ba1Wolfram Sang	flush_workqueue(mps->workqueue);
4885aa68b85951aec91d6a955d1de861325fc9a3ba1Wolfram Sang	destroy_workqueue(mps->workqueue);
4895aa68b85951aec91d6a955d1de861325fc9a3ba1Wolfram Sang	spi_unregister_master(master);
4905aa68b85951aec91d6a955d1de861325fc9a3ba1Wolfram Sang	free_irq(mps->irq, mps);
4915aa68b85951aec91d6a955d1de861325fc9a3ba1Wolfram Sang	if (mps->psc)
4925aa68b85951aec91d6a955d1de861325fc9a3ba1Wolfram Sang		iounmap(mps->psc);
493c8c87c656f95d764eb2b460b46b0144794108da4Guenter Roeck	spi_master_put(master);
4945aa68b85951aec91d6a955d1de861325fc9a3ba1Wolfram Sang
4955aa68b85951aec91d6a955d1de861325fc9a3ba1Wolfram Sang	return 0;
49600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp}
49700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
498631e61b7ca12ef14c834f99f8948e410c539f585Márton Némethstatic const struct of_device_id mpc52xx_psc_spi_of_match[] = {
49966ffbe490b6156898364b3f20a571a78f8d77bc8Grant Likely	{ .compatible = "fsl,mpc5200-psc-spi", },
50066ffbe490b6156898364b3f20a571a78f8d77bc8Grant Likely	{ .compatible = "mpc5200-psc-spi", }, /* old */
50166ffbe490b6156898364b3f20a571a78f8d77bc8Grant Likely	{}
50200b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp};
50300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
50400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos CarpMODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match);
50500b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
50618d306d1375696b0e6b5b39e4744d7fa2ad5e170Grant Likelystatic struct platform_driver mpc52xx_psc_spi_of_driver = {
50700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	.probe = mpc52xx_psc_spi_of_probe,
508fd4a319bc933ae93e68935b21924a9ca4ba2d060Grant Likely	.remove = mpc52xx_psc_spi_of_remove,
50900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	.driver = {
51000b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		.name = "mpc52xx-psc-spi",
51100b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp		.owner = THIS_MODULE,
5124018294b53d1dae026880e45f174c1cc63b5d435Grant Likely		.of_match_table = mpc52xx_psc_spi_of_match,
51300b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp	},
51400b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp};
515940ab88962bc1aff3273a8356d64577a6e386736Grant Likelymodule_platform_driver(mpc52xx_psc_spi_of_driver);
51600b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos Carp
51700b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos CarpMODULE_AUTHOR("Dragos Carp");
51800b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos CarpMODULE_DESCRIPTION("MPC52xx PSC SPI Driver");
51900b8fd236764e3d5bc1d30dc65e256e283de4c3dDragos CarpMODULE_LICENSE("GPL");
520