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:
John Crispin 2015-11-22 11:49:04 +00:00
parent 95aa28da81
commit a941b34008

View file

@ -41,7 +41,7 @@ Acked-by: John Crispin <blogic@openwrt.org>
spi-s3c24xx-hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi-s3c24xx-fiq.o
--- /dev/null
+++ b/drivers/spi/spi-rt2880.c
@@ -0,0 +1,533 @@
@@ -0,0 +1,530 @@
+/*
+ * 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/spi/spi.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#define DRIVER_NAME "spi-rt2880"
+/* only one slave is supported*/
+#define RALINK_NUM_CHIPSELECTS 1
+
+#define RAMIPS_SPI_STAT 0x00
+#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 | \
+ SPI_CS_HIGH)
+
+static atomic_t hw_reset_count = ATOMIC_INIT(0);
+
+struct rt2880_spi {
+ struct spi_master *master;
+ void __iomem *base;
@ -248,12 +249,14 @@ Acked-by: John Crispin <blogic@openwrt.org>
+ 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)
+ rt2880_spi_clrbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
+ else
+ 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)
@ -269,22 +272,41 @@ Acked-by: John Crispin <blogic@openwrt.org>
+ return -ETIMEDOUT;
+}
+
+static unsigned int
+rt2880_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
+static void rt2880_dump_reg(struct spi_master *master)
+{
+ struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
+ unsigned count = 0;
+ u8 *rx = xfer->rx_buf;
+ const u8 *tx = xfer->tx_buf;
+ int err;
+ struct rt2880_spi *rs = spi_master_get_devdata(master);
+
+ dev_dbg(&spi->dev, "read (%d): %s %s\n", xfer->len,
+ (tx != NULL) ? "tx" : " ",
+ (rx != NULL) ? "rx" : " ");
+ dev_dbg(&master->dev, "stat: %08x, cfg: %08x, ctl: %08x, " \
+ "data: %08x, arb: %08x\n",
+ 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) {
+ for (count = 0; count < xfer->len; count++) {
+ rt2880_spi_write(rs, RAMIPS_SPI_DATA, tx[count]);
+ len = xfer->len;
+ while (len-- > 0) {
+ rt2880_spi_write(rs, RAMIPS_SPI_DATA, *tx++);
+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTWR);
+ err = rt2880_spi_wait_ready(rs, 1);
+ if (err) {
@ -295,63 +317,32 @@ Acked-by: John Crispin <blogic@openwrt.org>
+ }
+
+ if (rx) {
+ for (count = 0; count < xfer->len; count++) {
+ len = xfer->len;
+ while (len-- > 0) {
+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTRD);
+ err = rt2880_spi_wait_ready(rs, 1);
+ if (err) {
+ dev_err(&spi->dev, "RX failed, err=%d\n", err);
+ goto out;
+ }
+ rx[count] = (u8) rt2880_spi_read(rs, RAMIPS_SPI_DATA);
+ *rx++ = (u8) rt2880_spi_read(rs, RAMIPS_SPI_DATA);
+ }
+ }
+
+out:
+ return count;
+ return err;
+}
+
+static int rt2880_spi_transfer_one_message(struct spi_master *master,
+ struct spi_message *m)
+/* copy from spi.c */
+static void spi_set_cs(struct spi_device *spi, bool enable)
+{
+ struct rt2880_spi *rs = spi_master_get_devdata(master);
+ struct spi_device *spi = m->spi;
+ struct spi_transfer *t = NULL;
+ int status = 0;
+ int cs_active = 0;
+ if (spi->mode & SPI_CS_HIGH)
+ enable = !enable;
+
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
+ dev_err(&spi->dev,
+ "message rejected: invalid transfer data buffers\n");
+ 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;
+ if (spi->cs_gpio >= 0)
+ gpio_set_value(spi->cs_gpio, !enable);
+ else if (spi->master->set_cs)
+ spi->master->set_cs(spi, !enable);
+}
+
+static int rt2880_spi_setup(struct spi_device *spi)
@ -410,6 +401,11 @@ Acked-by: John Crispin <blogic@openwrt.org>
+ if (reg != old_reg)
+ rt2880_spi_write(rs, arbit_off, reg);
+
+ /* deselected the spi device */
+ spi_set_cs(spi, false);
+
+ rt2880_dump_reg(master);
+
+ return 0;
+}
+
@ -508,8 +504,8 @@ Acked-by: John Crispin <blogic@openwrt.org>
+ master->flags = SPI_MASTER_HALF_DUPLEX;
+ master->setup = rt2880_spi_setup;
+ master->prepare_message = rt2880_spi_prepare_message;
+ master->transfer_one_message = rt2880_spi_transfer_one_message;
+ master->num_chipselect = RALINK_NUM_CHIPSELECTS;
+ master->set_cs = rt2880_spi_set_cs;
+ master->transfer_one = rt2880_spi_transfer_one,
+
+ dev_set_drvdata(&pdev->dev, master);
+
@ -518,8 +514,8 @@ Acked-by: John Crispin <blogic@openwrt.org>
+ rs->base = base;
+ rs->clk = clk;
+
+ device_reset(&pdev->dev);
+
+ if (atomic_inc_return(&hw_reset_count) == 1)
+ device_reset(&pdev->dev);
+
+ ret = devm_spi_register_master(&pdev->dev, master);
+ if (ret < 0) {
@ -547,6 +543,7 @@ Acked-by: John Crispin <blogic@openwrt.org>
+ rs = spi_master_get_devdata(master);
+
+ clk_disable_unprepare(rs->clk);
+ atomic_dec(&hw_reset_count);
+
+ return 0;
+}