spi: mpc512x-psc: add support for Freescale MPC5125
The register layout of the PSC devices differ between MPC5121 and
MPC5125, but the registers are named nearly identical and their purpose
is similar enough ("freescale identical") such that substituting
mpc52xx_psc by mpc5125_psc is nearly enough to make the driver work on
MPC5125. To keep supporting MPC5121 this patch introduces a cpp
macro to select the right struct that defines the register layout.
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Mark Brown <broonie@kernel.org>
diff --git a/arch/powerpc/include/asm/mpc52xx_psc.h b/arch/powerpc/include/asm/mpc52xx_psc.h
index d0ece25..04c7e8f 100644
--- a/arch/powerpc/include/asm/mpc52xx_psc.h
+++ b/arch/powerpc/include/asm/mpc52xx_psc.h
@@ -150,7 +150,10 @@
/* Structure of the hardware registers */
struct mpc52xx_psc {
- u8 mode; /* PSC + 0x00 */
+ union {
+ u8 mode; /* PSC + 0x00 */
+ u8 mr2;
+ };
u8 reserved0[3];
union { /* PSC + 0x04 */
u16 status;
diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c
index 965d2bd..280794d 100644
--- a/drivers/spi/spi-mpc512x-psc.c
+++ b/drivers/spi/spi-mpc512x-psc.c
@@ -30,11 +30,37 @@
#include <linux/gpio.h>
#include <asm/mpc52xx_psc.h>
+enum {
+ TYPE_MPC5121,
+ TYPE_MPC5125,
+};
+
+/*
+ * This macro abstracts the differences in the PSC register layout between
+ * MPC5121 (which uses a struct mpc52xx_psc) and MPC5125 (using mpc5125_psc).
+ */
+#define psc_addr(mps, regname) ({ \
+ void *__ret; \
+ switch(mps->type) { \
+ case TYPE_MPC5121: { \
+ struct mpc52xx_psc __iomem *psc = mps->psc; \
+ __ret = &psc->regname; \
+ }; \
+ break; \
+ case TYPE_MPC5125: { \
+ struct mpc5125_psc __iomem *psc = mps->psc; \
+ __ret = &psc->regname; \
+ }; \
+ break; \
+ } \
+ __ret; })
+
struct mpc512x_psc_spi {
void (*cs_control)(struct spi_device *spi, bool on);
/* driver internal data */
- struct mpc52xx_psc __iomem *psc;
+ int type;
+ void __iomem *psc;
struct mpc512x_psc_fifo __iomem *fifo;
unsigned int irq;
u8 bits_per_word;
@@ -71,13 +97,12 @@
{
struct mpc512x_psc_spi_cs *cs = spi->controller_state;
struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
- struct mpc52xx_psc __iomem *psc = mps->psc;
u32 sicr;
u32 ccr;
int speed;
u16 bclkdiv;
- sicr = in_be32(&psc->sicr);
+ sicr = in_be32(psc_addr(mps, sicr));
/* Set clock phase and polarity */
if (spi->mode & SPI_CPHA)
@@ -94,9 +119,9 @@
sicr |= 0x10000000;
else
sicr &= ~0x10000000;
- out_be32(&psc->sicr, sicr);
+ out_be32(psc_addr(mps, sicr), sicr);
- ccr = in_be32(&psc->ccr);
+ ccr = in_be32(psc_addr(mps, ccr));
ccr &= 0xFF000000;
speed = cs->speed_hz;
if (!speed)
@@ -104,7 +129,7 @@
bclkdiv = (mps->mclk_rate / speed) - 1;
ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
- out_be32(&psc->ccr, ccr);
+ out_be32(psc_addr(mps, ccr), ccr);
mps->bits_per_word = cs->bits_per_word;
if (mps->cs_control && gpio_is_valid(spi->cs_gpio))
@@ -315,16 +340,15 @@
static int mpc512x_psc_spi_prep_xfer_hw(struct spi_master *master)
{
struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
- struct mpc52xx_psc __iomem *psc = mps->psc;
dev_dbg(&master->dev, "%s()\n", __func__);
/* Zero MR2 */
- in_8(&psc->mode);
- out_8(&psc->mode, 0x0);
+ in_8(psc_addr(mps, mr2));
+ out_8(psc_addr(mps, mr2), 0x0);
/* enable transmitter/receiver */
- out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
+ out_8(psc_addr(mps, command), MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
return 0;
}
@@ -332,13 +356,12 @@
static int mpc512x_psc_spi_unprep_xfer_hw(struct spi_master *master)
{
struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
- struct mpc52xx_psc __iomem *psc = mps->psc;
struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
dev_dbg(&master->dev, "%s()\n", __func__);
/* disable transmitter/receiver and fifo interrupt */
- out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
+ out_8(psc_addr(mps, command), MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
out_be32(&fifo->tximr, 0);
return 0;
@@ -388,7 +411,6 @@
static int mpc512x_psc_spi_port_config(struct spi_master *master,
struct mpc512x_psc_spi *mps)
{
- struct mpc52xx_psc __iomem *psc = mps->psc;
struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
u32 sicr;
u32 ccr;
@@ -396,12 +418,12 @@
u16 bclkdiv;
/* 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);
+ out_8(psc_addr(mps, command), MPC52xx_PSC_RST_RX);
+ out_8(psc_addr(mps, command), MPC52xx_PSC_RST_TX);
+ out_8(psc_addr(mps, command), MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
/* Disable psc interrupts all useful interrupts are in fifo */
- out_be16(&psc->isr_imr.imr, 0);
+ out_be16(psc_addr(mps, isr_imr.imr), 0);
/* Disable fifo interrupts, will be enabled later */
out_be32(&fifo->tximr, 0);
@@ -417,18 +439,18 @@
0x00004000 | /* MSTR = 1 -- SPI master */
0x00000800; /* UseEOF = 1 -- SS low until EOF */
- out_be32(&psc->sicr, sicr);
+ out_be32(psc_addr(mps, sicr), sicr);
- ccr = in_be32(&psc->ccr);
+ ccr = in_be32(psc_addr(mps, ccr));
ccr &= 0xFF000000;
speed = 1000000; /* default 1MHz */
bclkdiv = (mps->mclk_rate / speed) - 1;
ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
- out_be32(&psc->ccr, ccr);
+ out_be32(psc_addr(mps, ccr), ccr);
/* Set 2ms DTL delay */
- out_8(&psc->ctur, 0x00);
- out_8(&psc->ctlr, 0x82);
+ out_8(psc_addr(mps, ctur), 0x00);
+ out_8(psc_addr(mps, ctlr), 0x82);
/* we don't use the alarms */
out_be32(&fifo->rxalarm, 0xfff);
@@ -482,6 +504,7 @@
dev_set_drvdata(dev, master);
mps = spi_master_get_devdata(master);
+ mps->type = (int)of_device_get_match_data(dev);
mps->irq = irq;
if (pdata == NULL) {
@@ -589,7 +612,8 @@
}
static const struct of_device_id mpc512x_psc_spi_of_match[] = {
- { .compatible = "fsl,mpc5121-psc-spi", },
+ { .compatible = "fsl,mpc5121-psc-spi", .data = (void *)TYPE_MPC5121 },
+ { .compatible = "fsl,mpc5125-psc-spi", .data = (void *)TYPE_MPC5125 },
{},
};