summaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
authorBrian Niebuhr <bniebuhr@efjohnson.com>2010-08-13 13:27:23 +0530
committerSekhar Nori <nsekhar@ti.com>2010-11-18 18:38:25 +0530
commit7fe0092b1f55f58a749d68ace3a3597e8a2a9163 (patch)
tree95df072f92ab7766aba26869d42777f817d3c6e1 /drivers/spi
parent23853973d9b76eb8b3cf46157689bc6187e141d9 (diff)
spi: davinci: simplify prescalar calculation
Simplify pre-scalar calculation and move it into a seprate function. Refuse to correct invalid pre-scalar values silently as this might lead to unexpected bugs and lower performance. Instead an error will force users to dig into the root-cause of the issue. While at it, remove some device specific checks on the maximum SPI frequency. As the driver supports the SPI interface implemented on various devices, it should only take care of core SPI limitations and leave the device specific handling to platform code. Signed-off-by: Brian Niebuhr <bniebuhr@efjohnson.com> Tested-By: Michael Williamson <michael.williamson@criticallink.com> Signed-off-by: Sekhar Nori <nsekhar@ti.com>
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/davinci_spi.c53
1 files changed, 31 insertions, 22 deletions
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c
index d5d7014e6ae..17269ad54a9 100644
--- a/drivers/spi/davinci_spi.c
+++ b/drivers/spi/davinci_spi.c
@@ -53,6 +53,7 @@
#define SPIFMT_WDELAY_MASK 0x3f000000u
#define SPIFMT_WDELAY_SHIFT 24
#define SPIFMT_CHARLEN_MASK 0x0000001Fu
+#define SPIFMT_PRESCALE_SHIFT 8
/* SPIPC0 */
@@ -267,6 +268,29 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
}
/**
+ * davinci_spi_get_prescale - Calculates the correct prescale value
+ * @maxspeed_hz: the maximum rate the SPI clock can run at
+ *
+ * This function calculates the prescale value that generates a clock rate
+ * less than or equal to the specified maximum.
+ *
+ * Returns: calculated prescale - 1 for easy programming into SPI registers
+ * or negative error number if valid prescalar cannot be updated.
+ */
+static inline int davinci_spi_get_prescale(struct davinci_spi *davinci_spi,
+ u32 max_speed_hz)
+{
+ int ret;
+
+ ret = DIV_ROUND_UP(clk_get_rate(davinci_spi->clk), max_speed_hz);
+
+ if (ret < 3 || ret > 256)
+ return -EINVAL;
+
+ return ret - 1;
+}
+
+/**
* davinci_spi_setup_transfer - This functions will determine transfer method
* @spi: spi device on which data transfer to be done
* @t: spi transfer in which transfer info is filled
@@ -281,7 +305,7 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
struct davinci_spi *davinci_spi;
u8 bits_per_word = 0;
- u32 hz = 0, prescale = 0, clkspeed;
+ u32 hz = 0, prescale = 0;
davinci_spi = spi_master_get_devdata(spi->master);
@@ -312,21 +336,18 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
if (!hz)
hz = spi->max_speed_hz;
+ prescale = davinci_spi_get_prescale(davinci_spi, hz);
+ if (prescale < 0)
+ return prescale;
+
clear_fmt_bits(davinci_spi->base, SPIFMT_CHARLEN_MASK,
spi->chip_select);
set_fmt_bits(davinci_spi->base, bits_per_word & 0x1f,
spi->chip_select);
- clkspeed = clk_get_rate(davinci_spi->clk);
- if (hz > clkspeed / 2)
- prescale = 1 << 8;
- if (hz < clkspeed / 256)
- prescale = 255 << 8;
- if (!prescale)
- prescale = ((clkspeed / hz - 1) << 8) & 0x0000ff00;
-
clear_fmt_bits(davinci_spi->base, 0x0000ff00, spi->chip_select);
- set_fmt_bits(davinci_spi->base, prescale, spi->chip_select);
+ set_fmt_bits(davinci_spi->base,
+ prescale << SPIFMT_PRESCALE_SHIFT, spi->chip_select);
return 0;
}
@@ -413,10 +434,8 @@ static int davinci_spi_setup(struct spi_device *spi)
int retval;
struct davinci_spi *davinci_spi;
struct davinci_spi_dma *davinci_spi_dma;
- struct device *sdev;
davinci_spi = spi_master_get_devdata(spi->master);
- sdev = davinci_spi->bitbang.master->dev.parent;
/* if bits per word length is zero then set it default 8 */
if (!spi->bits_per_word)
@@ -436,16 +455,6 @@ static int davinci_spi_setup(struct spi_device *spi)
}
/*
- * SPI in DaVinci and DA8xx operate between
- * 600 KHz and 50 MHz
- */
- if (spi->max_speed_hz < 600000 || spi->max_speed_hz > 50000000) {
- dev_dbg(sdev, "Operating frequency is not in acceptable "
- "range\n");
- return -EINVAL;
- }
-
- /*
* Set up SPIFMTn register, unique to this chipselect.
*
* NOTE: we could do all of these with one write. Also, some