Subject: [PATCH 2/3] support for mpc52xx PSC as an SPI bus master

From: Grant Likely <[email-masked]>
Date: Sat, 23 Jul 2005 10:15:20 -0400

SPI bus master driver for the Freescale MPC52xx.

Note: This patch as it stands right now will compile cleanly, but may
not bind the driver to the PSC.  arch/ppc/syslib/mpc52xx_devices.c
needs to be modified to rename the desired PSC platform devices to
match the driver.  (rename  to "mpc52xx-psc:spi")  This is a board
specific hack, and I need to make it cleaner before I resubmit this
patch.

Signed-off-by: Grant Likely <[email-masked]>

diff -ruNp linux-spi/arch/ppc/platforms/lite5200.c
linux-spi-mpc5200/arch/ppc/platforms/lite5200.c
--- linux-spi/arch/ppc/platforms/lite5200.c	2005-06-17 15:48:29.000000000 -0400
+++ linux-spi-mpc5200/arch/ppc/platforms/lite5200.c	2005-07-23
03:17:39.000000000 -0400
@@ -76,6 +76,21 @@ lite5200_map_irq(struct pci_dev *dev, un
 }
 #endif
 
+#if defined(CONFIG_SPI_BUS_MPC52XX_PSC) ||
defined(CONFIG_SPI_BUS_MPC52XX_PSC_MODULE)
+void
+spi_mpc52xx_psc_slave_select(int psc_id, int slave_id)
+{
+}
+
+void
+spi_mpc52xx_psc_slave_deselect(int psc_id)
+{
+}
+
+EXPORT_SYMBOL(spi_mpc52xx_psc_slave_select);
+EXPORT_SYMBOL(spi_mpc52xx_psc_slave_deselect);
+#endif
+
 static void __init
 lite5200_setup_cpu(void)
 {
@@ -107,15 +122,30 @@ lite5200_setup_cpu(void)
 	else
 		out_be16(&cdm->fd_counters, 0x5555);
 
+	/* Setup clocks for PSC3 SPI mode */
+	out_be16(&cdm->mclken_div_psc3, 0x8020);  /* Enable MClk for PSC3 */
+
 	/* Get port mux config */
 	port_config = in_be32(&gpio->port_config);
 
 	/* 48Mhz internal, pin is GPIO */
-	port_config &= ~0x00800000;
+	port_config &= ~PORT_CONFIG_IR_USB_CLK;
 
-	/* USB port */
-	port_config &= ~0x00007000;	/* Differential mode - USB1 only */
-	port_config |=  0x00001000;
+	/* USB port: Differential mode; USB1 only */
+	port_config &= ~(PORT_CONFIG_USB_SE | PORT_CONFIG_USB_MASK);
+	port_config |=  PORT_CONFIG_USB_USB;
+
+	/* PSC2 (I2S Codec mode) */
+	port_config &= ~PORT_CONFIG_PSC2_MASK;
+	port_config |=  PORT_CONFIG_PSC2_CODEC; /* Codec mode */
+
+	/* PSC3 (SPI Codec mode) */
+	port_config &= ~PORT_CONFIG_PSC3_MASK;
+	port_config |=  PORT_CONFIG_PSC3_CODEC; /* Codec mode */
+
+	/* PSC6 (I2S Codec mode) */
+	port_config &= ~PORT_CONFIG_IRDA_MASK;
+	port_config |=  PORT_CONFIG_IRDA_CODEC; /* Codec mode */
 
 	/* Commit port config */
 	out_be32(&gpio->port_config, port_config);
diff -ruNp linux-spi/drivers/spi/Kconfig linux-spi-mpc5200/drivers/spi/Kconfig
--- linux-spi/drivers/spi/Kconfig	2005-07-22 17:08:00.000000000 -0400
+++ linux-spi-mpc5200/drivers/spi/Kconfig	2005-07-22 17:16:13.000000000 -0400
@@ -20,6 +20,13 @@ config SPI
 comment "SPI Bus Drivers"
 	depends on SPI
 
+config SPI_BUS_MPC52XX_PSC
+	tristate "SPI bus via MPC52xx PSC port"
+	depends on SPI && PPC_MPC52xx
+	help
+	  Say Y here if you want to use an MPC52xx PSC port as an SPI bus
+	  master.
+
 comment "SPI slaves"
 	depends on SPI
 
diff -ruNp linux-spi/drivers/spi/Makefile linux-spi-mpc5200/drivers/spi/Makefile
--- linux-spi/drivers/spi/Makefile	2005-07-22 17:08:00.000000000 -0400
+++ linux-spi-mpc5200/drivers/spi/Makefile	2005-07-22 17:16:13.000000000 -0400
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_SPI)			+= spi-core.o
+obj-$(CONFIG_SPI_BUS_MPC52XX_PSC)	+= spi-mpc52xx-psc.o
diff -ruNp linux-spi/drivers/spi/spi-mpc52xx-psc.c
linux-spi-mpc5200/drivers/spi/spi-mpc52xx-psc.c
--- linux-spi/drivers/spi/spi-mpc52xx-psc.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-spi-mpc5200/drivers/spi/spi-mpc52xx-psc.c	2005-07-22
17:16:13.000000000 -0400
@@ -0,0 +1,307 @@
+/*
+ * drivers/spi/mpc5xxx-psc.c
+ *
+ * Driver for the SPI mode of the MPC52xx PSC peripherals
+ *
+ * Maintainer : Grant Likely <[email-masked]>
+ *
+ * This file is in the public domain
+ */
+
+/* Platform device Usage :
+ * (Blatantly copied from drivers/serial/mpc52xx_uart.c)
+ *
+ * Since PSCs can have multiple function, the correct driver for each one
+ * is selected based on the name assigned to the psc.  By convention, the
+ * function is appended to the device name in the board setup code.  For
+ * example, this spi psc driver will only bind to mpc52xx_psc.spi devices.
+ *
+ * The driver init all necessary registers to place the PSC in spi mode.
+ * However, the pin multiplexing aren't changed and should be set either
+ * by the bootloader or in the platform init code.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/spi.h>
+
+#include <asm/io.h>
+#include <asm/mpc52xx.h>
+#include <asm/mpc52xx_psc.h>
+
+
+/* The magic data is all in this structure.  This structure contains
+ * everything we need to keep track of the PSC
+ */
+struct mpc52xx_psc_spi_port {
+	struct platform_device *pdev;		/* PSC dev (on platform bus) */
+	struct mpc52xx_psc __iomem *psc;	/* PSC registers */
+	struct spi_bus spi_bus;
+	int irq;				/* Assigned irq */
+
+	/* Current state variables */
+	struct semaphore sema; /* mutex to enforce one transfer at a time */
+	wait_queue_head_t wait_queue; /* Wait on this queue during transfer */
+
+	/* Warning: The following fields are not protected by a mutex.
+	 * They can only be changed before a transfer starts or after
+	 * a transfer ends.  During a transfer the isr will fiddle with
+	 * them */
+	int rx_count;		/* remaining bytes to be received */
+	uint8_t *rx_ptr;	/* pointer for next RX character */
+};
+#define to_spi_port(bus) container_of(bus, struct
mpc52xx_psc_spi_port, spi_bus);
+
+struct mpc52xx_psc_spi_port mpc52xx_psc_spi_ports[MPC52xx_PSC_MAXNUM];
+
+
+/* Dynamically update the alarm level so interrupts don't occur too fast */
+static void mpc52xx_psc_spi_adjust_alarm(struct mpc52xx_psc_spi_port *port)
+{
+	struct mpc52xx_psc __iomem *psc = port->psc;
+	int alarm;
+
+	alarm = 0x200 - port->rx_count;
+	if (alarm < 0) alarm = 0;
+	if (alarm > 0x1ff) alarm = 0x1ff;
+	out_be16(&psc->rfalarm, alarm);
+}
+
+static irqreturn_t
+mpc52xx_psc_spi_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct mpc52xx_psc_spi_port *port = (struct uart_port *)dev_id;
+	struct mpc52xx_psc __iomem *psc = port->psc;
+	int num, i;
+
+	if ( irq != port->irq ) {
+		printk( KERN_WARNING "mpc52xx_psc_spi: " \
+		        "Received wrong int %d. Waiting for %d\n",
+		       irq, port->irq);
+		return IRQ_NONE;
+	}
+	
+	if (in_be16(&psc->mpc52xx_psc_isr) & MPC52xx_PSC_IMR_RXRDY)
+	{
+		num = in_be16(&psc->rfnum);
+
+		/* Discard unexpected rx data */
+		if ((!port->rx_count) || (!port->rx_ptr))
+		{
+			printk(KERN_WARNING "mpc52xx_psc_spi: "
+				"discarding %i unexpected bytes\n", num);
+			for (i = 0; i < num; i++)
+				in_8(&psc->mpc52xx_psc_buffer_8);
+			return IRQ_NONE;
+		}
+
+		/* Don't overflow the buffer */
+		if (num > port->rx_count)
+			num = port->rx_count;
+
+		/* Transfer data into rx buffer */
+		ioread8_rep(&psc->mpc52xx_psc_buffer_8, port->rx_ptr, num);
+		port->rx_ptr += num;
+		port->rx_count -= num;
+
+		/* Dynamically update the alarm level so interrupts don't
+		 * occur too frequently */
+		mpc52xx_psc_spi_adjust_alarm(port);
+
+		/* Only wakeup process if data transfer is complete */
+		if (port->rx_count == 0)
+			wake_up_interruptible(&port->wait_queue);
+	}
+
+	return IRQ_NONE;
+}
+
+static int mpc52xx_psc_spi_startup(struct mpc52xx_psc_spi_port *port)
+{
+	int ret;
+	struct mpc52xx_psc __iomem *psc = port->psc;
+
+	ret = request_irq(port->irq, mpc52xx_psc_spi_isr,
+		SA_INTERRUPT | SA_SAMPLE_RANDOM, "mpc52xx_psc_spi", port);
+	if (ret)
+	{
+		printk(KERN_ALERT "mpc52xx_psc_spi: request_irq failed (%i)\n",
+			ret);
+		return ret;
+	}
+
+	init_MUTEX(&port->sema);
+	init_waitqueue_head(&port->wait_queue);
+	port->rx_count = 0;
+	port->rx_ptr = NULL;
+
+	/* 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);
+
+	/* Interrupts must be based on alarm levels */
+	out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
+	out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL);
+
+	/* Configure 8bit codec mode as an SPI master and use EOF flags */
+	out_be32(&psc->sicr, MPC52xx_PSC_SICR_SIM_CODEC8 |
+	                     MPC52xx_PSC_SICR_GENCLK |
+	                     MPC52xx_PSC_SICR_SPI |
+	                     MPC52xx_PSC_SICR_MSTR |
+	                     MPC52xx_PSC_SICR_USEEOF );
+	out_be16(&psc->ccr, 0x070F);
+
+	/* Set 2ms DTL delay */
+	out_8(&psc->ctur, 0x00);
+	out_8(&psc->ctlr, 0x84);
+}
+
+static int mpc52xx_psc_spi_transfer(struct spi_bus *bus, int id, int clkedge,
+				uint8_t *in, const uint8_t *out, size_t count)
+{
+	struct mpc52xx_psc_spi_port *port;
+	struct mpc52xx_psc __iomem *psc;
+	uint32_t	sicr;
+	int err;
+
+	port = to_spi_port(bus);
+	psc = port->psc;
+
+	//printk(KERN_ALERT "mpc52xx_psc_spi: transfer; count=%i\n", count);
+
+	if (count < 1)
+		return -1;
+
+	/* Grab the semaphore, only one transfer allowed at a time */
+	err = down_interruptible(&port->sema);
+	if (err)
+		return err;
+
+	/* Disable SPI interrupts so rx buffer can be manipulated */
+	out_be16(&psc->mpc52xx_psc_imr, 0);
+
+	/* Set the clock polarity */
+	sicr = in_be32(&psc->sicr);
+	if (clkedge == SPI_CLKEDGE_RISING)
+		sicr &= ~MPC52xx_PSC_SICR_CPOL; /* Clear means rising edge */
+	else
+		sicr |= MPC52xx_PSC_SICR_CPOL; /* Set means falling edge */
+	out_be32(&psc->sicr, sicr);
+
+	/* Initialize the receive buffer; this can be done without locking
+	 * because the ISR doesn't touch it until after interrupts are
+	 * enabled
+	 */
+	port->rx_ptr = in;
+	port->rx_count = count;
+	mpc52xx_psc_spi_adjust_alarm(port);
+
+	/* Select the slave, start the engine and transfer data to fifo */
+	spi_mpc52xx_psc_slave_select(port->pdev->id, id);
+	iowrite8(MPC52xx_PSC_RX_ENABLE | MPC52xx_PSC_TX_ENABLE, &psc->command);
+	if (count > 1)
+		iowrite8_rep(&psc->mpc52xx_psc_buffer_8, out, count-1);
+
+	/* Signal EOF for the last byte to terminate the transfer */
+	iowrite8(MPC52xx_PSC_IRCR2_NXTEOF, &psc->ircr2);
+	iowrite8(out[count-1], &psc->mpc52xx_psc_buffer_8);
+
+	/* Enable interrupts and go to sleep until transfer is complete*/
+	out_be16(&psc->mpc52xx_psc_imr, MPC52xx_PSC_IMR_RXRDY);
+	err = wait_event_interruptible(port->wait_queue, port->rx_count == 0);
+
+	/* Terminate the transfer, and deselect the slave */
+	port->rx_ptr = NULL;
+	out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
+	spi_mpc52xx_psc_slave_deselect(port->pdev->id);
+
+	/* Release the semaphore to allow other transfers */
+	up(&port->sema);
+	return err;
+}
+
+static struct spi_bus_ops mpc52xx_psc_spi_ops = {
+	.transfer = mpc52xx_psc_spi_transfer,
+};
+
+static int __devinit
+mpc52xx_psc_spi_probe(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct resource *res = pdev->resource;
+	struct mpc52xx_psc_spi_port *port;
+	int idx = pdev->id;
+	int i;
+
+	printk(KERN_ALERT "mpc52xx-psc-spi: probing idx=%i\n", idx);
+
+	if ((idx != 0) && (idx != 1) && (idx !=2) && (idx != 5))
+	{
+		printk(KERN_ALERT "mpc52xx-psc-spi: PSC%i can't do SPI\n",
+		       idx+1);
+		return -ENODEV;
+	}
+
+	port = &mpc52xx_psc_spi_ports[idx];
+	port->pdev = pdev;
+	for (i = 0; i < pdev->num_resources; i++, res++)
+	{
+		if (res->flags & IORESOURCE_MEM)
+			port->psc = (struct mpc52xx_psc __iomem *) res->start;
+		else if (res->flags & IORESOURCE_IRQ)
+			port->irq = res->start;
+	}
+
+	mpc52xx_psc_spi_startup(port);
+	port->spi_bus.ops = &mpc52xx_psc_spi_ops;
+	port->spi_bus.dev.parent = dev;  /* The psc is the parent of the bus */
+	spi_bus_register(&port->spi_bus);
+
+	/* Ahhh!!! Run away from the board specific hack (This won't be 
+	 * part of the real patch)
+	 */
+	spi_device_create(&port->spi_bus, "ks8995m_spi", 0);
+	spi_device_create(&port->spi_bus, "tlv320aic26", 1);
+	return 0;
+}
+
+static int 
+mpc52xx_psc_spi_remove(struct device *dev)
+{
+	return 0;
+}
+
+static struct device_driver mpc52xx_psc_spi_platform_driver = {
+	.name		= "mpc52xx-psc:spi",
+	.bus		= &platform_bus_type,
+	.probe		= mpc52xx_psc_spi_probe,
+	.remove		= mpc52xx_psc_spi_remove,
+};
+
+static int __init mpc52xx_psc_spi_init(void)
+{
+	int ret;
+
+	printk(KERN_ALERT "mpc52xx_psc_spi: initializing\n");
+
+	ret = driver_register(&mpc52xx_psc_spi_platform_driver);
+	return ret;
+
+
+}
+
+static void __exit mpc52xx_psc_spi_exit(void)
+{
+	driver_unregister(&mpc52xx_psc_spi_platform_driver);
+	printk(KERN_ALERT "mpc52xx_psc_spi: exiting\n");
+}
+
+module_init(mpc52xx_psc_spi_init);
+module_exit(mpc52xx_psc_spi_exit);
+
+MODULE_AUTHOR("Grant Likely <[email-masked]>");
+MODULE_DESCRIPTION("Freescale MPC52xx PSC driver for SPI mode");
+MODULE_LICENSE("Dual BSD/GPL");
diff -ruNp linux-spi/include/asm-ppc/mpc52xx.h
linux-spi-mpc5200/include/asm-ppc/mpc52xx.h
--- linux-spi/include/asm-ppc/mpc52xx.h	2005-06-17 15:48:29.000000000 -0400
+++ linux-spi-mpc5200/include/asm-ppc/mpc52xx.h	2005-07-23
02:29:41.000000000 -0400
@@ -146,6 +146,28 @@ enum ppc_sys_devices {
 #define MPC52xx_XLB_ARB_IRQ		(MPC52xx_PERP_IRQ_BASE + 21)
 #define MPC52xx_BDLC_IRQ		(MPC52xx_PERP_IRQ_BASE + 22)
 
+/* CDM Cloke enable bits */
+#define MPC52xx_CDM_CLKENABLE_MEM_CLK		(0x00080000)
+#define MPC52xx_CDM_CLKENABLE_PCI_CLK		(0x00040000)
+#define MPC52xx_CDM_CLKENABLE_LPC_CLK		(0x00020000)
+#define MPC52xx_CDM_CLKENABLE_SIT_CLK		(0x00010000)
+#define MPC52xx_CDM_CLKENABLE_SCOM_CLK		(0x00008000)
+#define MPC52xx_CDM_CLKENABLE_ATA_CLK		(0x00004000)
+#define MPC52xx_CDM_CLKENABLE_ETH_CLK		(0x00002000)
+#define MPC52xx_CDM_CLKENABLE_USB_CLK		(0x00001000)
+#define MPC52xx_CDM_CLKENABLE_SPI_CLK		(0x00000800)
+#define MPC52xx_CDM_CLKENABLE_BDLC_CLK		(0x00000400)
+#define MPC52xx_CDM_CLKENABLE_IRRX_CLK		(0x00000200)
+#define MPC52xx_CDM_CLKENABLE_IRTX_CLK		(0x00000100)
+#define MPC52xx_CDM_CLKENABLE_PSC345_CLK	(0x00000080)
+#define MPC52xx_CDM_CLKENABLE_PSC2_CLK		(0x00000040)
+#define MPC52xx_CDM_CLKENABLE_PSC1_CLK		(0x00000020)
+#define MPC52xx_CDM_CLKENABLE_PSC6_CLK		(0x00000010)
+#define MPC52xx_CDM_CLKENABLE_MSCAN_CLK		(0x00000008)
+#define MPC52xx_CDM_CLKENABLE_I2C_CLK		(0x00000004)
+#define MPC52xx_CDM_CLKENABLE_TIMER_CLK		(0x00000002)
+#define MPC52xx_CDM_CLKENABLE_GPIO_CLK		(0x00000001)
+

 /* ======================================================================== */
@@ -266,6 +288,49 @@ struct mpc52xx_rtc {
 };
 
 /* GPIO */
+#define PORT_CONFIG_CS1			0x80000000
+#define PORT_CONFIG_ALT_MASK		0x30000000
+#define PORT_CONFIG_CS7			0x08000000
+#define PORT_CONFIG_CS6			0x04000000
+#define PORT_CONFIG_ATA			0x03000000
+#define PORT_CONFIG_IR_USB_CLK		0x00800000
+#define PORT_CONFIG_IRDA_MASK		0x00700000 /* PSC6 */
+#define PORT_CONFIG_IRDA_GPIO		0x00000000
+#define PORT_CONFIG_IRDA_UART		0x00500000
+#define PORT_CONFIG_IRDA_CODEC		0x00700000
+#define PORT_CONFIG_ETHER_MASK		0x000F0000
+#define PORT_CONFIG_PCI_DIS		0x00008000
+#define PORT_CONFIG_USB_SE		0x00004000 /* Single ended mode */
+#define PORT_CONFIG_USB_MASK		0x00004000 /* (USB1 or 2 UARTs) */
+#define PORT_CONFIG_USB_USB		0x00001000
+#define PORT_CONFIG_USB_2UART		0x00002000
+#define PORT_CONFIG_PSC3_MASK		0x00000F00
+#define PORT_CONFIG_PSC3_GPIO		0x00000000
+#define PORT_CONFIG_PSC3_USB2		0x00000100
+#define PORT_CONFIG_PSC3_UART		0x00000400
+#define PORT_CONFIG_PSC3_UARTE_CD	0x00000500
+#define PORT_CONFIG_PSC3_CODEC		0x00000600
+#define PORT_CONFIG_PSC3_CODEC_MCLK	0x00000700
+#define PORT_CONFIG_PSC3_SPI		0x00000800
+#define PORT_CONFIG_PSC3_SPI_UART	0x00000C00
+#define PORT_CONFIG_PSC3_SPI_UARTE	0x00000D00
+#define PORT_CONFIG_PSC3_SPI_CODEC	0x00000E00
+#define PORT_CONFIG_PSC2_MASK		0x00000070
+#define PORT_CONFIG_PSC2_GPIO		0x00000000
+#define PORT_CONFIG_PSC2_CAN		0x00000010
+#define PORT_CONFIG_PSC2_AC97		0x00000020
+#define PORT_CONFIG_PSC2_UART		0x00000040
+#define PORT_CONFIG_PSC2_UARTE_CD	0x00000050
+#define PORT_CONFIG_PSC2_CODEC		0x00000060
+#define PORT_CONFIG_PSC2_CODEC_MCLK	0x00000070
+#define PORT_CONFIG_PSC1_MASK		0x00000007
+#define PORT_CONFIG_PSC1_GPIO		0x00000000
+#define PORT_CONFIG_PSC1_AC97		0x00000002
+#define PORT_CONFIG_PSC1_UART		0x00000004
+#define PORT_CONFIG_PSC1_UARTE_CD	0x00000005
+#define PORT_CONFIG_PSC1_CODEC		0x00000006
+#define PORT_CONFIG_PSC1_CODEC_MCLK	0x00000007
+
 struct mpc52xx_gpio {
 	u32	port_config;	/* GPIO + 0x00 */
 	u32	simple_gpioe;	/* GPIO + 0x04 */
diff -ruNp linux-spi/include/asm-ppc/mpc52xx_psc.h
linux-spi-mpc5200/include/asm-ppc/mpc52xx_psc.h
--- linux-spi/include/asm-ppc/mpc52xx_psc.h	2005-06-17 15:48:29.000000000 -0400
+++ linux-spi-mpc5200/include/asm-ppc/mpc52xx_psc.h	2005-07-22
17:16:13.000000000 -0400
@@ -72,6 +72,51 @@
 #define MPC52xx_PSC_D_CTS		0x10
 #define MPC52xx_PSC_D_DCD		0x20
 
+/* PSC Serial Interface Control Register (SICR) bits */
+/* SICR Field masks */
+#define MPC52xx_PSC_SICR_ACRB		0x80000000
+#define MPC52xx_PSC_SICR_AWR		0x40000000
+#define MPC52xx_PSC_SICR_DTS1		0x20000000
+#define MPC52xx_PSC_SICR_SHDIR		0x10000000
+#define MPC52xx_PSC_SICR_SIM		0x0F000000
+#define MPC52xx_PSC_SICR_GENCLK		0x00800000
+#define MPC52xx_PSC_SICR_MULTIWD	0x00400000
+#define MPC52xx_PSC_SICR_CLKPOL		0x00200000
+#define MPC52xx_PSC_SICR_SYNCPOL	0x00100000
+#define MPC52xx_PSC_SICR_CELLSLAVE	0x00080000
+#define MPC52xx_PSC_SICR_CELL2XCLK	0x00040000
+#define MPC52xx_PSC_SICR_SPI		0x00008000
+#define MPC52xx_PSC_SICR_MSTR		0x00004000
+#define MPC52xx_PSC_SICR_CPOL		0x00002000
+#define MPC52xx_PSC_SICR_CPHA		0x00001000
+#define MPC52xx_PSC_SICR_USEEOF		0x00000800
+/* Operation modes */
+#define MPC52xx_PSC_SICR_SIM_UART		0x00000000
+#define MPC52xx_PSC_SICR_SIM_UART_DCD		0x08000000
+#define MPC52xx_PSC_SICR_SIM_CODEC8		0x01000000
+#define MPC52xx_PSC_SICR_SIM_CODEC16		0x02000000
+#define MPC52xx_PSC_SICR_SIM_AC97		0x03000000
+#define MPC52xx_PSC_SICR_SIM_SIR		0x04000000
+#define MPC52xx_PSC_SICR_SIM_SIR_DCD		0x0C000000
+#define MPC52xx_PSC_SICR_SIM_MIR		0x05000000
+#define MPC52xx_PSC_SICR_SIM_FIR		0x06000000
+#define MPC52xx_PSC_SICR_SIM_CODEC24		0x07000000
+#define MPC52xx_PSC_SICR_SIM_CODEC32		0x0F000000
+
+/* IRCR1 bit masks */
+#define MPC52xx_PSC_IRCR1_FD			0x04
+#define MPC52xx_PSC_IRCR1_SIPEN			0x02
+#define MPC52xx_PSC_IRCR1_SPUL			0x01
+
+/* IRCR2 bit masks */
+#define MPC52xx_PSC_IRCR2_SIPREQ		0x04
+#define MPC52xx_PSC_IRCR2_ABORT			0x02
+#define MPC52xx_PSC_IRCR2_NXTEOF		0x01
+
+/* Codec Clock Register fields */
+#define MPC52xx_PSC_CCR_FRAME_SYNC_DIV		0xFF00
+#define MPC52xx_PSC_CCR_BIT_CLK_DIV		0xFF00
+
 /* PSC mode fields */
 #define MPC52xx_PSC_MODE_5_BITS			0x00
 #define MPC52xx_PSC_MODE_6_BITS			0x01
@@ -187,5 +232,10 @@ struct mpc52xx_psc {
 	u16		tflwfptr;	/* PSC + 0x9e */
 };
 
+#if defined(CONFIG_SPI_BUS_MPC52XX_PSC) ||
defined(CONFIG_SPI_BUS_MPC52XX_PSC_MODULE)
+/* Helper functions for selecting slaves SPI mode */
+extern void spi_mpc52xx_psc_slave_select(int psc_id, int slave_id);
+extern void spi_mpc52xx_psc_slave_deselect(int psc_id);
+#endif
 
 #endif  /* __ASM_MPC52xx_PSC_H__ */