|
@@ -23,11 +23,11 @@
|
|
|
#include <linux/errno.h>
|
|
|
#include <linux/interrupt.h>
|
|
|
#include <linux/platform_device.h>
|
|
|
+#include <linux/spi/pxa2xx_spi.h>
|
|
|
#include <linux/dma-mapping.h>
|
|
|
#include <linux/spi/spi.h>
|
|
|
#include <linux/workqueue.h>
|
|
|
#include <linux/delay.h>
|
|
|
-#include <linux/clk.h>
|
|
|
#include <linux/gpio.h>
|
|
|
#include <linux/slab.h>
|
|
|
|
|
@@ -35,9 +35,6 @@
|
|
|
#include <asm/irq.h>
|
|
|
#include <asm/delay.h>
|
|
|
|
|
|
-#include <mach/dma.h>
|
|
|
-#include <plat/ssp.h>
|
|
|
-#include <mach/pxa2xx_spi.h>
|
|
|
|
|
|
MODULE_AUTHOR("Stephen Street");
|
|
|
MODULE_DESCRIPTION("PXA2xx SSP SPI Controller");
|
|
@@ -46,8 +43,6 @@ MODULE_ALIAS("platform:pxa2xx-spi");
|
|
|
|
|
|
#define MAX_BUSES 3
|
|
|
|
|
|
-#define RX_THRESH_DFLT 8
|
|
|
-#define TX_THRESH_DFLT 8
|
|
|
#define TIMOUT_DFLT 1000
|
|
|
|
|
|
#define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
|
|
@@ -168,7 +163,10 @@ struct chip_data {
|
|
|
u8 enable_dma;
|
|
|
u8 bits_per_word;
|
|
|
u32 speed_hz;
|
|
|
- int gpio_cs;
|
|
|
+ union {
|
|
|
+ int gpio_cs;
|
|
|
+ unsigned int frm;
|
|
|
+ };
|
|
|
int gpio_cs_inverted;
|
|
|
int (*write)(struct driver_data *drv_data);
|
|
|
int (*read)(struct driver_data *drv_data);
|
|
@@ -181,6 +179,11 @@ static void cs_assert(struct driver_data *drv_data)
|
|
|
{
|
|
|
struct chip_data *chip = drv_data->cur_chip;
|
|
|
|
|
|
+ if (drv_data->ssp_type == CE4100_SSP) {
|
|
|
+ write_SSSR(drv_data->cur_chip->frm, drv_data->ioaddr);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
if (chip->cs_control) {
|
|
|
chip->cs_control(PXA2XX_CS_ASSERT);
|
|
|
return;
|
|
@@ -194,6 +197,9 @@ static void cs_deassert(struct driver_data *drv_data)
|
|
|
{
|
|
|
struct chip_data *chip = drv_data->cur_chip;
|
|
|
|
|
|
+ if (drv_data->ssp_type == CE4100_SSP)
|
|
|
+ return;
|
|
|
+
|
|
|
if (chip->cs_control) {
|
|
|
chip->cs_control(PXA2XX_CS_DEASSERT);
|
|
|
return;
|
|
@@ -203,6 +209,25 @@ static void cs_deassert(struct driver_data *drv_data)
|
|
|
gpio_set_value(chip->gpio_cs, !chip->gpio_cs_inverted);
|
|
|
}
|
|
|
|
|
|
+static void write_SSSR_CS(struct driver_data *drv_data, u32 val)
|
|
|
+{
|
|
|
+ void __iomem *reg = drv_data->ioaddr;
|
|
|
+
|
|
|
+ if (drv_data->ssp_type == CE4100_SSP)
|
|
|
+ val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK;
|
|
|
+
|
|
|
+ write_SSSR(val, reg);
|
|
|
+}
|
|
|
+
|
|
|
+static int pxa25x_ssp_comp(struct driver_data *drv_data)
|
|
|
+{
|
|
|
+ if (drv_data->ssp_type == PXA25x_SSP)
|
|
|
+ return 1;
|
|
|
+ if (drv_data->ssp_type == CE4100_SSP)
|
|
|
+ return 1;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int flush(struct driver_data *drv_data)
|
|
|
{
|
|
|
unsigned long limit = loops_per_jiffy << 1;
|
|
@@ -214,7 +239,7 @@ static int flush(struct driver_data *drv_data)
|
|
|
read_SSDR(reg);
|
|
|
}
|
|
|
} while ((read_SSSR(reg) & SSSR_BSY) && --limit);
|
|
|
- write_SSSR(SSSR_ROR, reg);
|
|
|
+ write_SSSR_CS(drv_data, SSSR_ROR);
|
|
|
|
|
|
return limit;
|
|
|
}
|
|
@@ -224,7 +249,7 @@ static int null_writer(struct driver_data *drv_data)
|
|
|
void __iomem *reg = drv_data->ioaddr;
|
|
|
u8 n_bytes = drv_data->n_bytes;
|
|
|
|
|
|
- if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
|
|
|
+ if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
|
|
|
|| (drv_data->tx == drv_data->tx_end))
|
|
|
return 0;
|
|
|
|
|
@@ -252,7 +277,7 @@ static int u8_writer(struct driver_data *drv_data)
|
|
|
{
|
|
|
void __iomem *reg = drv_data->ioaddr;
|
|
|
|
|
|
- if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
|
|
|
+ if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
|
|
|
|| (drv_data->tx == drv_data->tx_end))
|
|
|
return 0;
|
|
|
|
|
@@ -279,7 +304,7 @@ static int u16_writer(struct driver_data *drv_data)
|
|
|
{
|
|
|
void __iomem *reg = drv_data->ioaddr;
|
|
|
|
|
|
- if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
|
|
|
+ if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
|
|
|
|| (drv_data->tx == drv_data->tx_end))
|
|
|
return 0;
|
|
|
|
|
@@ -306,7 +331,7 @@ static int u32_writer(struct driver_data *drv_data)
|
|
|
{
|
|
|
void __iomem *reg = drv_data->ioaddr;
|
|
|
|
|
|
- if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00)
|
|
|
+ if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
|
|
|
|| (drv_data->tx == drv_data->tx_end))
|
|
|
return 0;
|
|
|
|
|
@@ -507,9 +532,9 @@ static void dma_error_stop(struct driver_data *drv_data, const char *msg)
|
|
|
/* Stop and reset */
|
|
|
DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
|
|
|
DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
|
|
|
- write_SSSR(drv_data->clear_sr, reg);
|
|
|
+ write_SSSR_CS(drv_data, drv_data->clear_sr);
|
|
|
write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
|
|
|
- if (drv_data->ssp_type != PXA25x_SSP)
|
|
|
+ if (!pxa25x_ssp_comp(drv_data))
|
|
|
write_SSTO(0, reg);
|
|
|
flush(drv_data);
|
|
|
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
|
|
@@ -529,7 +554,7 @@ static void dma_transfer_complete(struct driver_data *drv_data)
|
|
|
|
|
|
/* Clear and disable interrupts on SSP and DMA channels*/
|
|
|
write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
|
|
|
- write_SSSR(drv_data->clear_sr, reg);
|
|
|
+ write_SSSR_CS(drv_data, drv_data->clear_sr);
|
|
|
DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
|
|
|
DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
|
|
|
|
|
@@ -622,7 +647,7 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
|
|
|
|
|
|
/* Clear and disable timeout interrupt, do the rest in
|
|
|
* dma_transfer_complete */
|
|
|
- if (drv_data->ssp_type != PXA25x_SSP)
|
|
|
+ if (!pxa25x_ssp_comp(drv_data))
|
|
|
write_SSTO(0, reg);
|
|
|
|
|
|
/* finish this transfer, start the next */
|
|
@@ -635,14 +660,26 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
|
|
|
return IRQ_NONE;
|
|
|
}
|
|
|
|
|
|
+static void reset_sccr1(struct driver_data *drv_data)
|
|
|
+{
|
|
|
+ void __iomem *reg = drv_data->ioaddr;
|
|
|
+ struct chip_data *chip = drv_data->cur_chip;
|
|
|
+ u32 sccr1_reg;
|
|
|
+
|
|
|
+ sccr1_reg = read_SSCR1(reg) & ~drv_data->int_cr1;
|
|
|
+ sccr1_reg &= ~SSCR1_RFT;
|
|
|
+ sccr1_reg |= chip->threshold;
|
|
|
+ write_SSCR1(sccr1_reg, reg);
|
|
|
+}
|
|
|
+
|
|
|
static void int_error_stop(struct driver_data *drv_data, const char* msg)
|
|
|
{
|
|
|
void __iomem *reg = drv_data->ioaddr;
|
|
|
|
|
|
/* Stop and reset SSP */
|
|
|
- write_SSSR(drv_data->clear_sr, reg);
|
|
|
- write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
|
|
|
- if (drv_data->ssp_type != PXA25x_SSP)
|
|
|
+ write_SSSR_CS(drv_data, drv_data->clear_sr);
|
|
|
+ reset_sccr1(drv_data);
|
|
|
+ if (!pxa25x_ssp_comp(drv_data))
|
|
|
write_SSTO(0, reg);
|
|
|
flush(drv_data);
|
|
|
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
|
|
@@ -658,9 +695,9 @@ static void int_transfer_complete(struct driver_data *drv_data)
|
|
|
void __iomem *reg = drv_data->ioaddr;
|
|
|
|
|
|
/* Stop SSP */
|
|
|
- write_SSSR(drv_data->clear_sr, reg);
|
|
|
- write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
|
|
|
- if (drv_data->ssp_type != PXA25x_SSP)
|
|
|
+ write_SSSR_CS(drv_data, drv_data->clear_sr);
|
|
|
+ reset_sccr1(drv_data);
|
|
|
+ if (!pxa25x_ssp_comp(drv_data))
|
|
|
write_SSTO(0, reg);
|
|
|
|
|
|
/* Update total byte transfered return count actual bytes read */
|
|
@@ -714,24 +751,34 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
|
|
|
}
|
|
|
|
|
|
if (drv_data->tx == drv_data->tx_end) {
|
|
|
- write_SSCR1(read_SSCR1(reg) & ~SSCR1_TIE, reg);
|
|
|
- /* PXA25x_SSP has no timeout, read trailing bytes */
|
|
|
- if (drv_data->ssp_type == PXA25x_SSP) {
|
|
|
- if (!wait_ssp_rx_stall(reg))
|
|
|
- {
|
|
|
- int_error_stop(drv_data, "interrupt_transfer: "
|
|
|
- "rx stall failed");
|
|
|
- return IRQ_HANDLED;
|
|
|
- }
|
|
|
- if (!drv_data->read(drv_data))
|
|
|
- {
|
|
|
- int_error_stop(drv_data,
|
|
|
- "interrupt_transfer: "
|
|
|
- "trailing byte read failed");
|
|
|
- return IRQ_HANDLED;
|
|
|
+ u32 bytes_left;
|
|
|
+ u32 sccr1_reg;
|
|
|
+
|
|
|
+ sccr1_reg = read_SSCR1(reg);
|
|
|
+ sccr1_reg &= ~SSCR1_TIE;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * PXA25x_SSP has no timeout, set up rx threshould for the
|
|
|
+ * remaing RX bytes.
|
|
|
+ */
|
|
|
+ if (pxa25x_ssp_comp(drv_data)) {
|
|
|
+
|
|
|
+ sccr1_reg &= ~SSCR1_RFT;
|
|
|
+
|
|
|
+ bytes_left = drv_data->rx_end - drv_data->rx;
|
|
|
+ switch (drv_data->n_bytes) {
|
|
|
+ case 4:
|
|
|
+ bytes_left >>= 1;
|
|
|
+ case 2:
|
|
|
+ bytes_left >>= 1;
|
|
|
}
|
|
|
- int_transfer_complete(drv_data);
|
|
|
+
|
|
|
+ if (bytes_left > RX_THRESH_DFLT)
|
|
|
+ bytes_left = RX_THRESH_DFLT;
|
|
|
+
|
|
|
+ sccr1_reg |= SSCR1_RxTresh(bytes_left);
|
|
|
}
|
|
|
+ write_SSCR1(sccr1_reg, reg);
|
|
|
}
|
|
|
|
|
|
/* We did something */
|
|
@@ -742,14 +789,26 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
|
|
|
{
|
|
|
struct driver_data *drv_data = dev_id;
|
|
|
void __iomem *reg = drv_data->ioaddr;
|
|
|
+ u32 sccr1_reg = read_SSCR1(reg);
|
|
|
+ u32 mask = drv_data->mask_sr;
|
|
|
+ u32 status;
|
|
|
+
|
|
|
+ status = read_SSSR(reg);
|
|
|
+
|
|
|
+ /* Ignore possible writes if we don't need to write */
|
|
|
+ if (!(sccr1_reg & SSCR1_TIE))
|
|
|
+ mask &= ~SSSR_TFS;
|
|
|
+
|
|
|
+ if (!(status & mask))
|
|
|
+ return IRQ_NONE;
|
|
|
|
|
|
if (!drv_data->cur_msg) {
|
|
|
|
|
|
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
|
|
|
write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
|
|
|
- if (drv_data->ssp_type != PXA25x_SSP)
|
|
|
+ if (!pxa25x_ssp_comp(drv_data))
|
|
|
write_SSTO(0, reg);
|
|
|
- write_SSSR(drv_data->clear_sr, reg);
|
|
|
+ write_SSSR_CS(drv_data, drv_data->clear_sr);
|
|
|
|
|
|
dev_err(&drv_data->pdev->dev, "bad message state "
|
|
|
"in interrupt handler\n");
|
|
@@ -862,7 +921,7 @@ static unsigned int ssp_get_clk_div(struct ssp_device *ssp, int rate)
|
|
|
{
|
|
|
unsigned long ssp_clk = clk_get_rate(ssp->clk);
|
|
|
|
|
|
- if (ssp->type == PXA25x_SSP)
|
|
|
+ if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP)
|
|
|
return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8;
|
|
|
else
|
|
|
return ((ssp_clk / rate - 1) & 0xfff) << 8;
|
|
@@ -1088,7 +1147,7 @@ static void pump_transfers(unsigned long data)
|
|
|
|
|
|
/* Clear status */
|
|
|
cr1 = chip->cr1 | chip->threshold | drv_data->int_cr1;
|
|
|
- write_SSSR(drv_data->clear_sr, reg);
|
|
|
+ write_SSSR_CS(drv_data, drv_data->clear_sr);
|
|
|
}
|
|
|
|
|
|
/* see if we need to reload the config registers */
|
|
@@ -1098,7 +1157,7 @@ static void pump_transfers(unsigned long data)
|
|
|
|
|
|
/* stop the SSP, and update the other bits */
|
|
|
write_SSCR0(cr0 & ~SSCR0_SSE, reg);
|
|
|
- if (drv_data->ssp_type != PXA25x_SSP)
|
|
|
+ if (!pxa25x_ssp_comp(drv_data))
|
|
|
write_SSTO(chip->timeout, reg);
|
|
|
/* first set CR1 without interrupt and service enables */
|
|
|
write_SSCR1(cr1 & SSCR1_CHANGE_MASK, reg);
|
|
@@ -1106,7 +1165,7 @@ static void pump_transfers(unsigned long data)
|
|
|
write_SSCR0(cr0, reg);
|
|
|
|
|
|
} else {
|
|
|
- if (drv_data->ssp_type != PXA25x_SSP)
|
|
|
+ if (!pxa25x_ssp_comp(drv_data))
|
|
|
write_SSTO(chip->timeout, reg);
|
|
|
}
|
|
|
|
|
@@ -1233,14 +1292,13 @@ static int setup(struct spi_device *spi)
|
|
|
uint tx_thres = TX_THRESH_DFLT;
|
|
|
uint rx_thres = RX_THRESH_DFLT;
|
|
|
|
|
|
- if (drv_data->ssp_type != PXA25x_SSP
|
|
|
+ if (!pxa25x_ssp_comp(drv_data)
|
|
|
&& (spi->bits_per_word < 4 || spi->bits_per_word > 32)) {
|
|
|
dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
|
|
|
"b/w not 4-32 for type non-PXA25x_SSP\n",
|
|
|
drv_data->ssp_type, spi->bits_per_word);
|
|
|
return -EINVAL;
|
|
|
- }
|
|
|
- else if (drv_data->ssp_type == PXA25x_SSP
|
|
|
+ } else if (pxa25x_ssp_comp(drv_data)
|
|
|
&& (spi->bits_per_word < 4
|
|
|
|| spi->bits_per_word > 16)) {
|
|
|
dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
|
|
@@ -1259,7 +1317,17 @@ static int setup(struct spi_device *spi)
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
|
|
|
- chip->gpio_cs = -1;
|
|
|
+ if (drv_data->ssp_type == CE4100_SSP) {
|
|
|
+ if (spi->chip_select > 4) {
|
|
|
+ dev_err(&spi->dev, "failed setup: "
|
|
|
+ "cs number must not be > 4.\n");
|
|
|
+ kfree(chip);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ chip->frm = spi->chip_select;
|
|
|
+ } else
|
|
|
+ chip->gpio_cs = -1;
|
|
|
chip->enable_dma = 0;
|
|
|
chip->timeout = TIMOUT_DFLT;
|
|
|
chip->dma_burst_size = drv_data->master_info->enable_dma ?
|
|
@@ -1315,7 +1383,7 @@ static int setup(struct spi_device *spi)
|
|
|
| (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0);
|
|
|
|
|
|
/* NOTE: PXA25x_SSP _could_ use external clocking ... */
|
|
|
- if (drv_data->ssp_type != PXA25x_SSP)
|
|
|
+ if (!pxa25x_ssp_comp(drv_data))
|
|
|
dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
|
|
|
clk_get_rate(ssp->clk)
|
|
|
/ (1 + ((chip->cr0 & SSCR0_SCR(0xfff)) >> 8)),
|
|
@@ -1350,23 +1418,27 @@ static int setup(struct spi_device *spi)
|
|
|
|
|
|
spi_set_ctldata(spi, chip);
|
|
|
|
|
|
+ if (drv_data->ssp_type == CE4100_SSP)
|
|
|
+ return 0;
|
|
|
+
|
|
|
return setup_cs(spi, chip, chip_info);
|
|
|
}
|
|
|
|
|
|
static void cleanup(struct spi_device *spi)
|
|
|
{
|
|
|
struct chip_data *chip = spi_get_ctldata(spi);
|
|
|
+ struct driver_data *drv_data = spi_master_get_devdata(spi->master);
|
|
|
|
|
|
if (!chip)
|
|
|
return;
|
|
|
|
|
|
- if (gpio_is_valid(chip->gpio_cs))
|
|
|
+ if (drv_data->ssp_type != CE4100_SSP && gpio_is_valid(chip->gpio_cs))
|
|
|
gpio_free(chip->gpio_cs);
|
|
|
|
|
|
kfree(chip);
|
|
|
}
|
|
|
|
|
|
-static int __init init_queue(struct driver_data *drv_data)
|
|
|
+static int __devinit init_queue(struct driver_data *drv_data)
|
|
|
{
|
|
|
INIT_LIST_HEAD(&drv_data->queue);
|
|
|
spin_lock_init(&drv_data->lock);
|
|
@@ -1454,7 +1526,7 @@ static int destroy_queue(struct driver_data *drv_data)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int __init pxa2xx_spi_probe(struct platform_device *pdev)
|
|
|
+static int __devinit pxa2xx_spi_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
struct device *dev = &pdev->dev;
|
|
|
struct pxa2xx_spi_master *platform_info;
|
|
@@ -1484,6 +1556,10 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
|
|
|
drv_data->pdev = pdev;
|
|
|
drv_data->ssp = ssp;
|
|
|
|
|
|
+ master->dev.parent = &pdev->dev;
|
|
|
+#ifdef CONFIG_OF
|
|
|
+ master->dev.of_node = pdev->dev.of_node;
|
|
|
+#endif
|
|
|
/* the spi->mode bits understood by this driver: */
|
|
|
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
|
|
|
|
|
@@ -1500,7 +1576,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
|
|
|
|
|
|
drv_data->ioaddr = ssp->mmio_base;
|
|
|
drv_data->ssdr_physical = ssp->phys_base + SSDR;
|
|
|
- if (ssp->type == PXA25x_SSP) {
|
|
|
+ if (pxa25x_ssp_comp(drv_data)) {
|
|
|
drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE;
|
|
|
drv_data->dma_cr1 = 0;
|
|
|
drv_data->clear_sr = SSSR_ROR;
|
|
@@ -1512,7 +1588,8 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
|
|
|
drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS | SSSR_ROR;
|
|
|
}
|
|
|
|
|
|
- status = request_irq(ssp->irq, ssp_int, 0, dev_name(dev), drv_data);
|
|
|
+ status = request_irq(ssp->irq, ssp_int, IRQF_SHARED, dev_name(dev),
|
|
|
+ drv_data);
|
|
|
if (status < 0) {
|
|
|
dev_err(&pdev->dev, "cannot get IRQ %d\n", ssp->irq);
|
|
|
goto out_error_master_alloc;
|
|
@@ -1561,7 +1638,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
|
|
|
| SSCR0_Motorola
|
|
|
| SSCR0_DataSize(8),
|
|
|
drv_data->ioaddr);
|
|
|
- if (drv_data->ssp_type != PXA25x_SSP)
|
|
|
+ if (!pxa25x_ssp_comp(drv_data))
|
|
|
write_SSTO(0, drv_data->ioaddr);
|
|
|
write_SSPSP(0, drv_data->ioaddr);
|
|
|
|
|
@@ -1723,13 +1800,14 @@ static struct platform_driver driver = {
|
|
|
.pm = &pxa2xx_spi_pm_ops,
|
|
|
#endif
|
|
|
},
|
|
|
+ .probe = pxa2xx_spi_probe,
|
|
|
.remove = pxa2xx_spi_remove,
|
|
|
.shutdown = pxa2xx_spi_shutdown,
|
|
|
};
|
|
|
|
|
|
static int __init pxa2xx_spi_init(void)
|
|
|
{
|
|
|
- return platform_driver_probe(&driver, pxa2xx_spi_probe);
|
|
|
+ return platform_driver_register(&driver);
|
|
|
}
|
|
|
subsys_initcall(pxa2xx_spi_init);
|
|
|
|