ramips: use transfer_one instead of transfer_one_message on rt2880 spi
* use kernel buildin transfer_one_message. we only need to implement transfer_one and set_cs function * should support use gpio as cs pin * deselected the spi device when setup and add debug info * only reset device when first driver probe Signed-off-by: Michael Lee <igvtee@gmail.com> SVN-Revision: 47579
This commit is contained in:
parent
95aa28da81
commit
a941b34008
1 changed files with 62 additions and 65 deletions
|
@ -41,7 +41,7 @@ Acked-by: John Crispin <blogic@openwrt.org>
|
||||||
spi-s3c24xx-hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi-s3c24xx-fiq.o
|
spi-s3c24xx-hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi-s3c24xx-fiq.o
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/drivers/spi/spi-rt2880.c
|
+++ b/drivers/spi/spi-rt2880.c
|
||||||
@@ -0,0 +1,533 @@
|
@@ -0,0 +1,530 @@
|
||||||
+/*
|
+/*
|
||||||
+ * spi-rt2880.c -- Ralink RT288x/RT305x SPI controller driver
|
+ * spi-rt2880.c -- Ralink RT288x/RT305x SPI controller driver
|
||||||
+ *
|
+ *
|
||||||
|
@ -66,10 +66,9 @@ Acked-by: John Crispin <blogic@openwrt.org>
|
||||||
+#include <linux/reset.h>
|
+#include <linux/reset.h>
|
||||||
+#include <linux/spi/spi.h>
|
+#include <linux/spi/spi.h>
|
||||||
+#include <linux/platform_device.h>
|
+#include <linux/platform_device.h>
|
||||||
|
+#include <linux/gpio.h>
|
||||||
+
|
+
|
||||||
+#define DRIVER_NAME "spi-rt2880"
|
+#define DRIVER_NAME "spi-rt2880"
|
||||||
+/* only one slave is supported*/
|
|
||||||
+#define RALINK_NUM_CHIPSELECTS 1
|
|
||||||
+
|
+
|
||||||
+#define RAMIPS_SPI_STAT 0x00
|
+#define RAMIPS_SPI_STAT 0x00
|
||||||
+#define RAMIPS_SPI_CFG 0x10
|
+#define RAMIPS_SPI_CFG 0x10
|
||||||
|
@ -169,6 +168,8 @@ Acked-by: John Crispin <blogic@openwrt.org>
|
||||||
+#define RT2880_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | \
|
+#define RT2880_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | \
|
||||||
+ SPI_CS_HIGH)
|
+ SPI_CS_HIGH)
|
||||||
+
|
+
|
||||||
|
+static atomic_t hw_reset_count = ATOMIC_INIT(0);
|
||||||
|
+
|
||||||
+struct rt2880_spi {
|
+struct rt2880_spi {
|
||||||
+ struct spi_master *master;
|
+ struct spi_master *master;
|
||||||
+ void __iomem *base;
|
+ void __iomem *base;
|
||||||
|
@ -248,12 +249,14 @@ Acked-by: John Crispin <blogic@openwrt.org>
|
||||||
+ return offset;
|
+ return offset;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+static void rt2880_spi_set_cs(struct rt2880_spi *rs, int enable)
|
+static void rt2880_spi_set_cs(struct spi_device *spi, bool enable)
|
||||||
+{
|
+{
|
||||||
|
+ struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
|
||||||
|
+
|
||||||
+ if (enable)
|
+ if (enable)
|
||||||
+ rt2880_spi_clrbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
|
|
||||||
+ else
|
|
||||||
+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
|
+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
|
||||||
|
+ else
|
||||||
|
+ rt2880_spi_clrbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+static int rt2880_spi_wait_ready(struct rt2880_spi *rs, int len)
|
+static int rt2880_spi_wait_ready(struct rt2880_spi *rs, int len)
|
||||||
|
@ -269,22 +272,41 @@ Acked-by: John Crispin <blogic@openwrt.org>
|
||||||
+ return -ETIMEDOUT;
|
+ return -ETIMEDOUT;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+static unsigned int
|
+static void rt2880_dump_reg(struct spi_master *master)
|
||||||
+rt2880_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
|
|
||||||
+{
|
+{
|
||||||
+ struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
|
+ struct rt2880_spi *rs = spi_master_get_devdata(master);
|
||||||
+ unsigned count = 0;
|
|
||||||
+ u8 *rx = xfer->rx_buf;
|
|
||||||
+ const u8 *tx = xfer->tx_buf;
|
|
||||||
+ int err;
|
|
||||||
+
|
+
|
||||||
+ dev_dbg(&spi->dev, "read (%d): %s %s\n", xfer->len,
|
+ dev_dbg(&master->dev, "stat: %08x, cfg: %08x, ctl: %08x, " \
|
||||||
+ (tx != NULL) ? "tx" : " ",
|
+ "data: %08x, arb: %08x\n",
|
||||||
+ (rx != NULL) ? "rx" : " ");
|
+ rt2880_spi_read(rs, RAMIPS_SPI_STAT),
|
||||||
|
+ rt2880_spi_read(rs, RAMIPS_SPI_CFG),
|
||||||
|
+ rt2880_spi_read(rs, RAMIPS_SPI_CTL),
|
||||||
|
+ rt2880_spi_read(rs, RAMIPS_SPI_DATA),
|
||||||
|
+ rt2880_spi_read(rs, get_arbiter_offset(master)));
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int rt2880_spi_transfer_one(struct spi_master *master,
|
||||||
|
+ struct spi_device *spi, struct spi_transfer *xfer)
|
||||||
|
+{
|
||||||
|
+ struct rt2880_spi *rs = spi_master_get_devdata(master);
|
||||||
|
+ unsigned len;
|
||||||
|
+ const u8 *tx = xfer->tx_buf;
|
||||||
|
+ u8 *rx = xfer->rx_buf;
|
||||||
|
+ int err = 0;
|
||||||
|
+
|
||||||
|
+ /* change clock speed */
|
||||||
|
+ if (unlikely(rs->speed != xfer->speed_hz)) {
|
||||||
|
+ u32 reg;
|
||||||
|
+ reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG);
|
||||||
|
+ reg &= ~SPICFG_SPICLK_PRESCALE_MASK;
|
||||||
|
+ reg |= rt2880_spi_baudrate_get(spi, xfer->speed_hz);
|
||||||
|
+ rt2880_spi_write(rs, RAMIPS_SPI_CFG, reg);
|
||||||
|
+ }
|
||||||
+
|
+
|
||||||
+ if (tx) {
|
+ if (tx) {
|
||||||
+ for (count = 0; count < xfer->len; count++) {
|
+ len = xfer->len;
|
||||||
+ rt2880_spi_write(rs, RAMIPS_SPI_DATA, tx[count]);
|
+ while (len-- > 0) {
|
||||||
|
+ rt2880_spi_write(rs, RAMIPS_SPI_DATA, *tx++);
|
||||||
+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTWR);
|
+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTWR);
|
||||||
+ err = rt2880_spi_wait_ready(rs, 1);
|
+ err = rt2880_spi_wait_ready(rs, 1);
|
||||||
+ if (err) {
|
+ if (err) {
|
||||||
|
@ -295,63 +317,32 @@ Acked-by: John Crispin <blogic@openwrt.org>
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ if (rx) {
|
+ if (rx) {
|
||||||
+ for (count = 0; count < xfer->len; count++) {
|
+ len = xfer->len;
|
||||||
|
+ while (len-- > 0) {
|
||||||
+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTRD);
|
+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTRD);
|
||||||
+ err = rt2880_spi_wait_ready(rs, 1);
|
+ err = rt2880_spi_wait_ready(rs, 1);
|
||||||
+ if (err) {
|
+ if (err) {
|
||||||
+ dev_err(&spi->dev, "RX failed, err=%d\n", err);
|
+ dev_err(&spi->dev, "RX failed, err=%d\n", err);
|
||||||
+ goto out;
|
+ goto out;
|
||||||
+ }
|
+ }
|
||||||
+ rx[count] = (u8) rt2880_spi_read(rs, RAMIPS_SPI_DATA);
|
+ *rx++ = (u8) rt2880_spi_read(rs, RAMIPS_SPI_DATA);
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+out:
|
+out:
|
||||||
+ return count;
|
+ return err;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+static int rt2880_spi_transfer_one_message(struct spi_master *master,
|
+/* copy from spi.c */
|
||||||
+ struct spi_message *m)
|
+static void spi_set_cs(struct spi_device *spi, bool enable)
|
||||||
+{
|
+{
|
||||||
+ struct rt2880_spi *rs = spi_master_get_devdata(master);
|
+ if (spi->mode & SPI_CS_HIGH)
|
||||||
+ struct spi_device *spi = m->spi;
|
+ enable = !enable;
|
||||||
+ struct spi_transfer *t = NULL;
|
|
||||||
+ int status = 0;
|
|
||||||
+ int cs_active = 0;
|
|
||||||
+
|
+
|
||||||
+ list_for_each_entry(t, &m->transfers, transfer_list) {
|
+ if (spi->cs_gpio >= 0)
|
||||||
+ if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
|
+ gpio_set_value(spi->cs_gpio, !enable);
|
||||||
+ dev_err(&spi->dev,
|
+ else if (spi->master->set_cs)
|
||||||
+ "message rejected: invalid transfer data buffers\n");
|
+ spi->master->set_cs(spi, !enable);
|
||||||
+ status = -EIO;
|
|
||||||
+ goto msg_done;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (!cs_active) {
|
|
||||||
+ rt2880_spi_set_cs(rs, 1);
|
|
||||||
+ cs_active = 1;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (t->len)
|
|
||||||
+ m->actual_length += rt2880_spi_write_read(spi, t);
|
|
||||||
+
|
|
||||||
+ if (t->delay_usecs)
|
|
||||||
+ udelay(t->delay_usecs);
|
|
||||||
+
|
|
||||||
+ if (t->cs_change) {
|
|
||||||
+ rt2880_spi_set_cs(rs, 0);
|
|
||||||
+ cs_active = 0;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+msg_done:
|
|
||||||
+ if (cs_active)
|
|
||||||
+ rt2880_spi_set_cs(rs, 0);
|
|
||||||
+
|
|
||||||
+ m->status = status;
|
|
||||||
+ spi_finalize_current_message(master);
|
|
||||||
+
|
|
||||||
+ return 0;
|
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+static int rt2880_spi_setup(struct spi_device *spi)
|
+static int rt2880_spi_setup(struct spi_device *spi)
|
||||||
|
@ -410,6 +401,11 @@ Acked-by: John Crispin <blogic@openwrt.org>
|
||||||
+ if (reg != old_reg)
|
+ if (reg != old_reg)
|
||||||
+ rt2880_spi_write(rs, arbit_off, reg);
|
+ rt2880_spi_write(rs, arbit_off, reg);
|
||||||
+
|
+
|
||||||
|
+ /* deselected the spi device */
|
||||||
|
+ spi_set_cs(spi, false);
|
||||||
|
+
|
||||||
|
+ rt2880_dump_reg(master);
|
||||||
|
+
|
||||||
+ return 0;
|
+ return 0;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
|
@ -508,8 +504,8 @@ Acked-by: John Crispin <blogic@openwrt.org>
|
||||||
+ master->flags = SPI_MASTER_HALF_DUPLEX;
|
+ master->flags = SPI_MASTER_HALF_DUPLEX;
|
||||||
+ master->setup = rt2880_spi_setup;
|
+ master->setup = rt2880_spi_setup;
|
||||||
+ master->prepare_message = rt2880_spi_prepare_message;
|
+ master->prepare_message = rt2880_spi_prepare_message;
|
||||||
+ master->transfer_one_message = rt2880_spi_transfer_one_message;
|
+ master->set_cs = rt2880_spi_set_cs;
|
||||||
+ master->num_chipselect = RALINK_NUM_CHIPSELECTS;
|
+ master->transfer_one = rt2880_spi_transfer_one,
|
||||||
+
|
+
|
||||||
+ dev_set_drvdata(&pdev->dev, master);
|
+ dev_set_drvdata(&pdev->dev, master);
|
||||||
+
|
+
|
||||||
|
@ -518,9 +514,9 @@ Acked-by: John Crispin <blogic@openwrt.org>
|
||||||
+ rs->base = base;
|
+ rs->base = base;
|
||||||
+ rs->clk = clk;
|
+ rs->clk = clk;
|
||||||
+
|
+
|
||||||
|
+ if (atomic_inc_return(&hw_reset_count) == 1)
|
||||||
+ device_reset(&pdev->dev);
|
+ device_reset(&pdev->dev);
|
||||||
+
|
+
|
||||||
+
|
|
||||||
+ ret = devm_spi_register_master(&pdev->dev, master);
|
+ ret = devm_spi_register_master(&pdev->dev, master);
|
||||||
+ if (ret < 0) {
|
+ if (ret < 0) {
|
||||||
+ dev_err(&pdev->dev, "devm_spi_register_master error.\n");
|
+ dev_err(&pdev->dev, "devm_spi_register_master error.\n");
|
||||||
|
@ -547,6 +543,7 @@ Acked-by: John Crispin <blogic@openwrt.org>
|
||||||
+ rs = spi_master_get_devdata(master);
|
+ rs = spi_master_get_devdata(master);
|
||||||
+
|
+
|
||||||
+ clk_disable_unprepare(rs->clk);
|
+ clk_disable_unprepare(rs->clk);
|
||||||
|
+ atomic_dec(&hw_reset_count);
|
||||||
+
|
+
|
||||||
+ return 0;
|
+ return 0;
|
||||||
+}
|
+}
|
||||||
|
|
Loading…
Reference in a new issue