summaryrefslogtreecommitdiffstats
path: root/drivers/spi/stm32_spi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi/stm32_spi.c')
-rw-r--r--drivers/spi/stm32_spi.c85
1 files changed, 67 insertions, 18 deletions
diff --git a/drivers/spi/stm32_spi.c b/drivers/spi/stm32_spi.c
index 0cb04a968c..9ef405a788 100644
--- a/drivers/spi/stm32_spi.c
+++ b/drivers/spi/stm32_spi.c
@@ -11,6 +11,7 @@
#include <init.h>
#include <errno.h>
#include <linux/reset.h>
+#include <linux/spi/spi-mem.h>
#include <spi/spi.h>
#include <linux/bitops.h>
#include <clock.h>
@@ -110,6 +111,24 @@ static inline struct stm32_spi_priv *to_stm32_spi_priv(struct spi_master *master
return container_of(master, struct stm32_spi_priv, master);
}
+static int stm32_spi_get_bpw_mask(struct stm32_spi_priv *priv)
+{
+ u32 cfg1, max_bpw;
+
+ /*
+ * The most significant bit at DSIZE bit field is reserved when the
+ * maximum data size of periperal instances is limited to 16-bit
+ */
+ setbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_DSIZE);
+
+ cfg1 = readl(priv->base + STM32_SPI_CFG1);
+ max_bpw = FIELD_GET(SPI_CFG1_DSIZE, cfg1) + 1;
+
+ dev_dbg(priv->master.dev, "%d-bit maximum data frame\n", max_bpw);
+
+ return SPI_BPW_RANGE_MASK(4, max_bpw);
+}
+
static void stm32_spi_write_txfifo(struct stm32_spi_priv *priv)
{
while ((priv->tx_len > 0) &&
@@ -189,7 +208,7 @@ static void stm32_spi_disable(struct stm32_spi_priv *priv)
static void stm32_spi_stopxfer(struct stm32_spi_priv *priv)
{
- struct device_d *dev = priv->master.dev;
+ struct device *dev = priv->master.dev;
u32 cr1, sr;
int ret;
@@ -260,19 +279,15 @@ static void stm32_spi_set_mode(struct stm32_spi_priv *priv, unsigned mode)
static void stm32_spi_set_fthlv(struct stm32_spi_priv *priv, u32 xfer_len)
{
- u32 fthlv, half_fifo;
+ u32 fthlv, packet, bpw;
/* data packet should not exceed 1/2 of fifo space */
- half_fifo = (priv->fifo_size / 2);
-
- /* data_packet should not exceed transfer length */
- fthlv = (half_fifo > xfer_len) ? xfer_len : half_fifo;
+ packet = clamp(xfer_len, 1U, priv->fifo_size / 2);
/* align packet size with data registers access */
- fthlv -= (fthlv % 4);
+ bpw = DIV_ROUND_UP(priv->cur_bpw, 8);
+ fthlv = DIV_ROUND_UP(packet, bpw);
- if (!fthlv)
- fthlv = 1;
clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_FTHLV,
(fthlv - 1) << SPI_CFG1_FTHLV_SHIFT);
}
@@ -338,14 +353,22 @@ out:
static int stm32_spi_transfer_one(struct stm32_spi_priv *priv,
struct spi_transfer *t)
{
- struct device_d *dev = priv->master.dev;
+ struct device *dev = priv->master.dev;
u32 sr;
u32 ifcr = 0;
u32 mode;
int xfer_status = 0;
+ int nb_words;
+
+ if (t->bits_per_word <= 8)
+ nb_words = t->len;
+ else if (t->bits_per_word <= 16)
+ nb_words = DIV_ROUND_UP(t->len * 8, 16);
+ else
+ nb_words = DIV_ROUND_UP(t->len * 8, 32);
- if (t->len <= SPI_CR2_TSIZE)
- writel(t->len, priv->base + STM32_SPI_CR2);
+ if (nb_words <= SPI_CR2_TSIZE)
+ writel(nb_words, priv->base + STM32_SPI_CR2);
else
return -EMSGSIZE;
@@ -360,9 +383,11 @@ static int stm32_spi_transfer_one(struct stm32_spi_priv *priv,
else if (!priv->rx_buf)
mode = SPI_SIMPLEX_TX;
- if (priv->cur_xferlen != t->len || priv->cur_mode != mode) {
+ if (priv->cur_xferlen != t->len || priv->cur_mode != mode ||
+ priv->cur_bpw != t->bits_per_word) {
priv->cur_mode = mode;
priv->cur_xferlen = t->len;
+ priv->cur_bpw = t->bits_per_word;
/* Disable the SPI hardware to unlock CFG1/CFG2 registers */
stm32_spi_disable(priv);
@@ -372,6 +397,9 @@ static int stm32_spi_transfer_one(struct stm32_spi_priv *priv,
stm32_spi_set_fthlv(priv, t->len);
+ clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_DSIZE,
+ priv->cur_bpw - 1);
+
/* Enable the SPI hardware */
stm32_spi_enable(priv);
}
@@ -474,6 +502,24 @@ out:
return ret;
}
+static int stm32_spi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
+{
+ if (op->data.nbytes > SPI_CR2_TSIZE)
+ op->data.nbytes = SPI_CR2_TSIZE;
+
+ return 0;
+}
+
+static int stm32_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
+{
+ return -ENOTSUPP;
+}
+
+static const struct spi_controller_mem_ops stm32_spi_mem_ops = {
+ .adjust_op_size = stm32_spi_adjust_op_size,
+ .exec_op = stm32_spi_exec_op,
+};
+
static int stm32_spi_get_fifo_size(struct stm32_spi_priv *priv)
{
u32 count = 0;
@@ -492,17 +538,17 @@ static int stm32_spi_get_fifo_size(struct stm32_spi_priv *priv)
static void stm32_spi_dt_probe(struct stm32_spi_priv *priv)
{
- struct device_node *node = priv->master.dev->device_node;
+ struct device_node *node = priv->master.dev->of_node;
int i;
- priv->master.num_chipselect = of_gpio_named_count(node, "cs-gpios");
+ priv->master.num_chipselect = of_gpio_count_csgpios(node);
priv->cs_gpios = xzalloc(sizeof(u32) * priv->master.num_chipselect);
for (i = 0; i < priv->master.num_chipselect; i++)
priv->cs_gpios[i] = of_get_named_gpio(node, "cs-gpios", i);
}
-static int stm32_spi_probe(struct device_d *dev)
+static int stm32_spi_probe(struct device *dev)
{
struct resource *iores;
struct spi_master *master;
@@ -522,6 +568,7 @@ static int stm32_spi_probe(struct device_d *dev)
master->setup = stm32_spi_setup;
master->transfer = stm32_spi_transfer;
+ master->mem_ops = &stm32_spi_mem_ops;
master->bus_num = -1;
stm32_spi_dt_probe(priv);
@@ -540,6 +587,7 @@ static int stm32_spi_probe(struct device_d *dev)
if (ret)
return ret;
+ master->bits_per_word_mask = stm32_spi_get_bpw_mask(priv);
priv->fifo_size = stm32_spi_get_fifo_size(priv);
priv->cur_mode = SPI_FULL_DUPLEX;
@@ -568,7 +616,7 @@ static int stm32_spi_probe(struct device_d *dev)
return spi_register_master(master);
}
-static void stm32_spi_remove(struct device_d *dev)
+static void stm32_spi_remove(struct device *dev)
{
struct stm32_spi_priv *priv = dev->priv;
@@ -580,8 +628,9 @@ static const struct of_device_id stm32_spi_ids[] = {
{ .compatible = "st,stm32h7-spi", },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, stm32_spi_ids);
-static struct driver_d stm32_spi_driver = {
+static struct driver stm32_spi_driver = {
.name = "stm32_spi",
.probe = stm32_spi_probe,
.remove = stm32_spi_remove,