1
0
mirror of https://git.openwrt.org/openwrt/openwrt.git synced 2024-10-19 14:08:17 +02:00

ramips: move rt2880 spi clock and reset init code to spi_prepare_message

before spi transfer. use spi_prepare_message to setup spi hardware. it
will setup MSB, spi mode and speed
remove sys_freq member and speed check code

Signed-off-by: Michael Lee <igvtee@gmail.com>

SVN-Revision: 47578
This commit is contained in:
John Crispin 2015-11-22 11:48:57 +00:00
parent a58dec6275
commit 95aa28da81

@ -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,539 @@ @@ -0,0 +1,533 @@
+/* +/*
+ * spi-rt2880.c -- Ralink RT288x/RT305x SPI controller driver + * spi-rt2880.c -- Ralink RT288x/RT305x SPI controller driver
+ * + *
@ -172,8 +172,7 @@ Acked-by: John Crispin <blogic@openwrt.org>
+struct rt2880_spi { +struct rt2880_spi {
+ struct spi_master *master; + struct spi_master *master;
+ void __iomem *base; + void __iomem *base;
+ unsigned int sys_freq; + u32 speed;
+ unsigned int speed;
+ u16 wait_loops; + u16 wait_loops;
+ u16 mode; + u16 mode;
+ struct clk *clk; + struct clk *clk;
@ -209,61 +208,33 @@ Acked-by: John Crispin <blogic@openwrt.org>
+ iowrite32((ioread32(addr) & ~mask), addr); + iowrite32((ioread32(addr) & ~mask), addr);
+} +}
+ +
+static int rt2880_spi_baudrate_set(struct spi_device *spi, unsigned int speed) +static u32 rt2880_spi_baudrate_get(struct spi_device *spi, unsigned int speed)
+{ +{
+ struct rt2880_spi *rs = spidev_to_rt2880_spi(spi); + struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
+ u32 rate; + u32 rate;
+ u32 prescale; + u32 prescale;
+ u32 reg;
+
+ dev_dbg(&spi->dev, "speed:%u\n", speed);
+ +
+ /* + /*
+ * the supported rates are: 2, 4, 8, ... 128 + * the supported rates are: 2, 4, 8, ... 128
+ * round up as we look for equal or less speed + * round up as we look for equal or less speed
+ */ + */
+ rate = DIV_ROUND_UP(rs->sys_freq, speed); + rate = DIV_ROUND_UP(clk_get_rate(rs->clk), speed);
+ dev_dbg(&spi->dev, "rate-1:%u\n", rate);
+ rate = roundup_pow_of_two(rate); + rate = roundup_pow_of_two(rate);
+ dev_dbg(&spi->dev, "rate-2:%u\n", rate);
+ +
+ /* Convert the rate to SPI clock divisor value. */ + /* Convert the rate to SPI clock divisor value. */
+ prescale = ilog2(rate / 2); + prescale = ilog2(rate / 2);
+ dev_dbg(&spi->dev, "prescale:%u\n", prescale);
+
+ reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG);
+ reg = ((reg & ~SPICFG_SPICLK_PRESCALE_MASK) | prescale);
+ rt2880_spi_write(rs, RAMIPS_SPI_CFG, reg);
+ +
+ /* some tolerance. double and add 100 */ + /* some tolerance. double and add 100 */
+ rs->wait_loops = (8 * HZ * loops_per_jiffy) / + rs->wait_loops = (8 * HZ * loops_per_jiffy) /
+ (clk_get_rate(rs->clk) / rate); + (clk_get_rate(rs->clk) / rate);
+ rs->wait_loops = (rs->wait_loops << 1) + 100; + rs->wait_loops = (rs->wait_loops << 1) + 100;
+ rs->speed = speed; + rs->speed = speed;
+ return 0;
+}
+ +
+/* + dev_dbg(&spi->dev, "speed: %lu/%u, rate: %u, prescal: %u, loops: %hu\n",
+ * called only when no transfer is active on the bus + clk_get_rate(rs->clk) / rate, speed, rate, prescale,
+ */ + rs->wait_loops);
+static int
+rt2880_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
+ unsigned int speed = spi->max_speed_hz;
+ int rc;
+ +
+ if ((t != NULL) && t->speed_hz) + return prescale;
+ speed = t->speed_hz;
+
+ if (rs->speed != speed) {
+ dev_dbg(&spi->dev, "speed_hz:%u\n", speed);
+ rc = rt2880_spi_baudrate_set(spi, speed);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+} +}
+ +
+static u32 get_arbiter_offset(struct spi_master *master) +static u32 get_arbiter_offset(struct spi_master *master)
@ -345,15 +316,9 @@ Acked-by: John Crispin <blogic@openwrt.org>
+ struct rt2880_spi *rs = spi_master_get_devdata(master); + struct rt2880_spi *rs = spi_master_get_devdata(master);
+ struct spi_device *spi = m->spi; + struct spi_device *spi = m->spi;
+ struct spi_transfer *t = NULL; + struct spi_transfer *t = NULL;
+ int par_override = 0;
+ int status = 0; + int status = 0;
+ int cs_active = 0; + int cs_active = 0;
+ +
+ /* Load defaults */
+ status = rt2880_spi_setup_transfer(spi, NULL);
+ if (status < 0)
+ goto msg_done;
+
+ list_for_each_entry(t, &m->transfers, transfer_list) { + list_for_each_entry(t, &m->transfers, transfer_list) {
+ if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { + if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
+ dev_err(&spi->dev, + dev_err(&spi->dev,
@ -362,23 +327,6 @@ Acked-by: John Crispin <blogic@openwrt.org>
+ goto msg_done; + goto msg_done;
+ } + }
+ +
+ if (t->speed_hz && t->speed_hz < (rs->sys_freq / 128)) {
+ dev_err(&spi->dev,
+ "message rejected: device min speed (%d Hz) exceeds required transfer speed (%d Hz)\n",
+ (rs->sys_freq / 128), t->speed_hz);
+ status = -EIO;
+ goto msg_done;
+ }
+
+ if (par_override || t->speed_hz || t->bits_per_word) {
+ par_override = 1;
+ status = rt2880_spi_setup_transfer(spi, t);
+ if (status < 0)
+ goto msg_done;
+ if (!t->speed_hz && !t->bits_per_word)
+ par_override = 0;
+ }
+
+ if (!cs_active) { + if (!cs_active) {
+ rt2880_spi_set_cs(rs, 1); + rt2880_spi_set_cs(rs, 1);
+ cs_active = 1; + cs_active = 1;
@ -465,12 +413,60 @@ Acked-by: John Crispin <blogic@openwrt.org>
+ return 0; + return 0;
+} +}
+ +
+static void rt2880_spi_reset(struct rt2880_spi *rs) +static int rt2880_spi_prepare_message(struct spi_master *master,
+ struct spi_message *msg)
+{ +{
+ rt2880_spi_write(rs, RAMIPS_SPI_CFG, + struct rt2880_spi *rs = spi_master_get_devdata(master);
+ SPICFG_MSBFIRST | SPICFG_TXCLKEDGE_FALLING | + struct spi_device *spi = msg->spi;
+ SPICFG_SPICLK_DIV16 | SPICFG_SPICLKPOL); + u32 reg;
+ rt2880_spi_write(rs, RAMIPS_SPI_CTL, SPICTL_HIZSDO | SPICTL_SPIENA); +
+ if ((rs->mode == spi->mode) && (rs->speed == spi->max_speed_hz))
+ return 0;
+
+#if 0
+ /* set spido to tri-state */
+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_HIZSDO);
+#endif
+
+ reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG);
+
+ reg &= ~(SPICFG_MSBFIRST | SPICFG_SPICLKPOL |
+ SPICFG_RXCLKEDGE_FALLING |
+ SPICFG_TXCLKEDGE_FALLING |
+ SPICFG_SPICLK_PRESCALE_MASK);
+
+ /* MSB */
+ if (!(spi->mode & SPI_LSB_FIRST))
+ reg |= SPICFG_MSBFIRST;
+
+ /* spi mode */
+ switch (spi->mode & (SPI_CPOL | SPI_CPHA)) {
+ case SPI_MODE_0:
+ reg |= SPICFG_TXCLKEDGE_FALLING;
+ break;
+ case SPI_MODE_1:
+ reg |= SPICFG_RXCLKEDGE_FALLING;
+ break;
+ case SPI_MODE_2:
+ reg |= SPICFG_SPICLKPOL | SPICFG_RXCLKEDGE_FALLING;
+ break;
+ case SPI_MODE_3:
+ reg |= SPICFG_SPICLKPOL | SPICFG_TXCLKEDGE_FALLING;
+ break;
+ }
+ rs->mode = spi->mode;
+
+#if 0
+ /* set spiclk and spiena to tri-state */
+ reg |= SPICFG_HIZSPI;
+#endif
+
+ /* clock divide */
+ reg |= rt2880_spi_baudrate_get(spi, spi->max_speed_hz);
+
+ rt2880_spi_write(rs, RAMIPS_SPI_CFG, reg);
+
+ return 0;
+} +}
+ +
+static int rt2880_spi_probe(struct platform_device *pdev) +static int rt2880_spi_probe(struct platform_device *pdev)
@ -511,6 +507,7 @@ Acked-by: John Crispin <blogic@openwrt.org>
+ master->max_speed_hz = clk_get_rate(clk) / 2; + master->max_speed_hz = clk_get_rate(clk) / 2;
+ 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->transfer_one_message = rt2880_spi_transfer_one_message; + master->transfer_one_message = rt2880_spi_transfer_one_message;
+ master->num_chipselect = RALINK_NUM_CHIPSELECTS; + master->num_chipselect = RALINK_NUM_CHIPSELECTS;
+ +
@ -520,12 +517,9 @@ Acked-by: John Crispin <blogic@openwrt.org>
+ rs->master = master; + rs->master = master;
+ rs->base = base; + rs->base = base;
+ rs->clk = clk; + rs->clk = clk;
+ rs->sys_freq = clk_get_rate(rs->clk);
+ dev_dbg(&pdev->dev, "sys_freq: %u\n", rs->sys_freq);
+ +
+ device_reset(&pdev->dev); + device_reset(&pdev->dev);
+ +
+ rt2880_spi_reset(rs);
+ +
+ ret = devm_spi_register_master(&pdev->dev, master); + ret = devm_spi_register_master(&pdev->dev, master);
+ if (ret < 0) { + if (ret < 0) {