mirror of https://github.com/hak5/openwrt.git
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: 47578lede-17.01
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) {
|
||||||
|
|
Loading…
Reference in New Issue