* [PATCH v2 01/12] spi: cosmetic style fixes
@ 2024-12-16 13:03 Marco Felsch
2024-12-16 13:03 ` [PATCH v2 02/12] spi: fix spi_message init during __spi_validate Marco Felsch
` (11 more replies)
0 siblings, 12 replies; 14+ messages in thread
From: Marco Felsch @ 2024-12-16 13:03 UTC (permalink / raw)
To: barebox
Replace <space><tab> by <tab> only. While on it move the forward
declaration on the file top to sync it with the Linux spi.h.
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
Changelog:
v2:
- no changes
include/spi/spi.h | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/include/spi/spi.h b/include/spi/spi.h
index 45d6f5931c3f..622de732fa6d 100644
--- a/include/spi/spi.h
+++ b/include/spi/spi.h
@@ -10,10 +10,11 @@
#include <linux/bitops.h>
struct spi_controller_mem_ops;
+struct spi_message;
struct spi_board_info {
char *name;
- int max_speed_hz;
+ int max_speed_hz;
int bus_num;
int chip_select;
@@ -115,8 +116,6 @@ static inline struct spi_device *to_spi_device(struct device *dev)
return dev ? container_of(dev, struct spi_device, dev) : NULL;
}
-struct spi_message;
-
/**
* struct spi_controller - interface to SPI master or slave controller
* @dev: device interface to this driver
@@ -260,7 +259,7 @@ static inline size_t spi_max_transfer_size(struct spi_device *spi)
return min(tr_max, msg_max);
}
-#define spi_master spi_controller
+#define spi_master spi_controller
#define spi_register_master(_ctrl) spi_register_controller(_ctrl)
/*---------------------------------------------------------------------------*/
--
2.39.5
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 02/12] spi: fix spi_message init during __spi_validate
2024-12-16 13:03 [PATCH v2 01/12] spi: cosmetic style fixes Marco Felsch
@ 2024-12-16 13:03 ` Marco Felsch
2024-12-16 13:03 ` [PATCH v2 03/12] spi: add spi_{set,get}_ctldata accessors Marco Felsch
` (10 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Marco Felsch @ 2024-12-16 13:03 UTC (permalink / raw)
To: barebox
Set the spi_device pointer accordingly to allow drivers to use it.
While on it, set the actual_length to 0 before passing the message to
the .transfer() hook as well.
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
Changelog:
v2:
- no changes
drivers/spi/spi.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index c627d88954a7..36d0653a191c 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -321,6 +321,8 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
if (list_empty(&message->transfers))
return -EINVAL;
+ message->spi = spi;
+
list_for_each_entry(xfer, &message->transfers, transfer_list) {
if (!xfer->bits_per_word)
xfer->bits_per_word = spi->bits_per_word;
@@ -347,6 +349,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
return -EINVAL;
}
+ message->actual_length = 0;
message->status = -EINPROGRESS;
return 0;
--
2.39.5
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 03/12] spi: add spi_{set,get}_ctldata accessors
2024-12-16 13:03 [PATCH v2 01/12] spi: cosmetic style fixes Marco Felsch
2024-12-16 13:03 ` [PATCH v2 02/12] spi: fix spi_message init during __spi_validate Marco Felsch
@ 2024-12-16 13:03 ` Marco Felsch
2024-12-16 13:03 ` [PATCH v2 04/12] gpiolib: add support for gpiod_get_index and gpiod_get_index_optional Marco Felsch
` (9 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Marco Felsch @ 2024-12-16 13:03 UTC (permalink / raw)
To: barebox
We alreary support the controller_state priv data pointer, add the Linux
APIs to set/get the data.
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
Changelog:
v2:
- no changes
include/spi/spi.h | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/include/spi/spi.h b/include/spi/spi.h
index 622de732fa6d..9261d508befd 100644
--- a/include/spi/spi.h
+++ b/include/spi/spi.h
@@ -116,6 +116,17 @@ static inline struct spi_device *to_spi_device(struct device *dev)
return dev ? container_of(dev, struct spi_device, dev) : NULL;
}
+/* ctldata is for the bus_controller driver's runtime state */
+static inline void *spi_get_ctldata(const struct spi_device *spi)
+{
+ return spi->controller_state;
+}
+
+static inline void spi_set_ctldata(struct spi_device *spi, void *state)
+{
+ spi->controller_state = state;
+}
+
/**
* struct spi_controller - interface to SPI master or slave controller
* @dev: device interface to this driver
--
2.39.5
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 04/12] gpiolib: add support for gpiod_get_index and gpiod_get_index_optional
2024-12-16 13:03 [PATCH v2 01/12] spi: cosmetic style fixes Marco Felsch
2024-12-16 13:03 ` [PATCH v2 02/12] spi: fix spi_message init during __spi_validate Marco Felsch
2024-12-16 13:03 ` [PATCH v2 03/12] spi: add spi_{set,get}_ctldata accessors Marco Felsch
@ 2024-12-16 13:03 ` Marco Felsch
2024-12-16 13:03 ` [PATCH v2 05/12] gpiolib: add support for gpiod_set_consumer_name Marco Felsch
` (8 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Marco Felsch @ 2024-12-16 13:03 UTC (permalink / raw)
To: barebox
Add Linux compatible APIs to make it easier to port code from Linux to
barebox. Also it aligns the GPIO label naming scheme with Linux.
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
Changelog:
v2:
- no changes
drivers/gpio/gpiolib.c | 62 +++++++++++++++++++++++++++++++++++
include/linux/gpio/consumer.h | 26 +++++++++++++++
2 files changed, 88 insertions(+)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 146eaf9af138..55beaba6acbc 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -22,6 +22,8 @@ struct gpio_desc {
u32 flags; /* OR-d enum of_gpio_flags */
};
+#define gpiod_not_found(desc) (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT)
+
/*
* This descriptor validation needs to be inserted verbatim into each
* function taking a descriptor, so we need to use a preprocessor
@@ -1053,6 +1055,66 @@ struct gpio_desc *dev_gpiod_get_index(struct device *dev,
return ret ? ERR_PTR(ret): desc;
}
+/**
+ * gpiod_get_index - obtain a GPIO from a multi-index GPIO function
+ * @dev: GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id: function within the GPIO consumer
+ * @idx: index of the GPIO to obtain in the consumer
+ * @flags: optional GPIO initialization flags
+ *
+ * This variant of gpiod_get() allows to access GPIOs other than the first
+ * defined one for functions that define several GPIOs.
+ *
+ * Returns:
+ * A valid GPIO descriptor, -ENOENT if no GPIO has been assigned to the
+ * requested function and/or index, or another IS_ERR() code if an error
+ * occurred while trying to acquire the GPIO.
+ */
+struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
+ const char *con_id,
+ unsigned int idx,
+ enum gpiod_flags flags)
+{
+ struct device_node *np = dev_of_node(dev);
+ const char *devname = dev ? dev_name(dev) : "?";
+ const char *label = con_id ?: devname;
+
+ return dev_gpiod_get_index(dev, np, con_id, idx, flags, label);
+}
+EXPORT_SYMBOL_GPL(gpiod_get_index);
+
+/**
+ * gpiod_get_index_optional - obtain an optional GPIO from a multi-index GPIO
+ * function
+ * @dev: GPIO consumer, can be NULL for system-global GPIOs
+ * @con_id: function within the GPIO consumer
+ * @index: index of the GPIO to obtain in the consumer
+ * @flags: optional GPIO initialization flags
+ *
+ * This is equivalent to gpiod_get_index(), except that when no GPIO with the
+ * specified index was assigned to the requested function it will return NULL.
+ * This is convenient for drivers that need to handle optional GPIOs.
+ *
+ * Returns:
+ * A valid GPIO descriptor, NULL if no GPIO has been assigned to the
+ * requested function and/or index, or another IS_ERR() code if an error
+ * occurred while trying to acquire the GPIO.
+ */
+struct gpio_desc *__must_check gpiod_get_index_optional(struct device *dev,
+ const char *con_id,
+ unsigned int index,
+ enum gpiod_flags flags)
+{
+ struct gpio_desc *desc;
+
+ desc = gpiod_get_index(dev, con_id, index, flags);
+ if (gpiod_not_found(desc))
+ return NULL;
+
+ return desc;
+}
+EXPORT_SYMBOL_GPL(gpiod_get_index_optional);
+
/**
* gpiod_count - return the number of GPIOs associated with a device / function
* or -ENOENT if no GPIO has been assigned to the requested function
diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
index f0d5bf7b255b..34e5795cbc07 100644
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -86,6 +86,16 @@ void gpiod_put(struct gpio_desc *desc);
int gpiod_count(struct device *dev, const char *con_id);
+struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
+ const char *con_id,
+ unsigned int idx,
+ enum gpiod_flags flags);
+
+struct gpio_desc *__must_check gpiod_get_index_optional(struct device *dev,
+ const char *con_id,
+ unsigned int index,
+ enum gpiod_flags flags);
+
struct gpio_descs *__must_check gpiod_get_array(struct device *dev,
const char *con_id,
enum gpiod_flags flags);
@@ -167,6 +177,22 @@ static inline int gpiod_count(struct device *dev, const char *con_id)
return 0;
}
+static inline struct gpio_desc *__must_check
+gpiod_get_index(struct device *dev,
+ const char *con_id,
+ unsigned int idx,
+ enum gpiod_flags flags)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline struct gpio_desc *__must_check
+gpiod_get_index_optional(struct device *dev, const char *con_id,
+ unsigned int index, enum gpiod_flags flags)
+{
+ return NULL;
+}
+
static inline struct gpio_descs *__must_check
gpiod_get_array(struct device *dev, const char *con_id, enum gpiod_flags flags)
{
--
2.39.5
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 05/12] gpiolib: add support for gpiod_set_consumer_name
2024-12-16 13:03 [PATCH v2 01/12] spi: cosmetic style fixes Marco Felsch
` (2 preceding siblings ...)
2024-12-16 13:03 ` [PATCH v2 04/12] gpiolib: add support for gpiod_get_index and gpiod_get_index_optional Marco Felsch
@ 2024-12-16 13:03 ` Marco Felsch
2024-12-16 13:03 ` [PATCH v2 06/12] spi: add support to handle cs-gpios Marco Felsch
` (7 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Marco Felsch @ 2024-12-16 13:03 UTC (permalink / raw)
To: barebox
Add support for the Linux gpiod_set_consumer_name() API to make it
easier to port drivers. Compared to Linux the function itself is very
different.
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
Changelog:
v2:
- no changes
drivers/gpio/gpiolib.c | 19 +++++++++++++++++++
include/linux/gpio/consumer.h | 10 ++++++++++
2 files changed, 29 insertions(+)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 55beaba6acbc..ec4d8e889bb1 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1223,6 +1223,25 @@ int gpiod_set_array_value(unsigned int array_size,
}
EXPORT_SYMBOL_GPL(gpiod_set_array_value);
+/**
+ * gpiod_set_consumer_name() - set the consumer name for the descriptor
+ * @desc: gpio to set the consumer name on
+ * @name: the new consumer name
+ *
+ * Returns:
+ * 0 on success, or negative errno on failure.
+ */
+int gpiod_set_consumer_name(struct gpio_desc *desc, const char *name)
+{
+ VALIDATE_DESC(desc);
+
+ free(desc->label);
+ desc->label = xstrdup(name);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gpiod_set_consumer_name);
+
int gpiochip_add(struct gpio_chip *chip)
{
int i;
diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
index 34e5795cbc07..d411c3aa3608 100644
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -84,6 +84,8 @@ int gpiod_get_value(const struct gpio_desc *desc);
void gpiod_put(struct gpio_desc *desc);
+int gpiod_set_consumer_name(struct gpio_desc *desc, const char *name);
+
int gpiod_count(struct device *dev, const char *con_id);
struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
@@ -172,6 +174,14 @@ static inline void gpiod_put(struct gpio_desc *desc)
WARN_ON(desc);
}
+static inline int gpiod_set_consumer_name(struct gpio_desc *desc,
+ const char *name)
+{
+ /* GPIO can never have been requested */
+ WARN_ON(desc);
+ return -EINVAL;
+}
+
static inline int gpiod_count(struct device *dev, const char *con_id)
{
return 0;
--
2.39.5
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 06/12] spi: add support to handle cs-gpios
2024-12-16 13:03 [PATCH v2 01/12] spi: cosmetic style fixes Marco Felsch
` (3 preceding siblings ...)
2024-12-16 13:03 ` [PATCH v2 05/12] gpiolib: add support for gpiod_set_consumer_name Marco Felsch
@ 2024-12-16 13:03 ` Marco Felsch
2024-12-20 9:51 ` Sascha Hauer
2024-12-16 13:03 ` [PATCH v2 07/12] spi: add support to setup spi-cs-{setup,hold,inactive}-delay-ns Marco Felsch
` (6 subsequent siblings)
11 siblings, 1 reply; 14+ messages in thread
From: Marco Felsch @ 2024-12-16 13:03 UTC (permalink / raw)
To: barebox
At the moment all drivers have to parse the cs-gpios on their own and
have to implement the mapping. By this commit we add the support to
handle this within the core and if there is valid CS GPIO for a device
we assign it accordingly.
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
Changelog:
v2:
- add missing 'use_gpio_descriptor' member documentation
drivers/spi/spi.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++
include/spi/spi.h | 12 +++++++++
2 files changed, 78 insertions(+)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 36d0653a191c..c239de9d8549 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -8,6 +8,8 @@
*/
#include <common.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
#include <linux/spi/spi-mem.h>
#include <spi/spi.h>
#include <xfuncs.h>
@@ -64,6 +66,8 @@ struct spi_device *spi_new_device(struct spi_controller *ctrl,
proxy = xzalloc(sizeof *proxy);
proxy->master = ctrl;
proxy->chip_select = chip->chip_select;
+ if (ctrl->cs_gpiods)
+ proxy->cs_gpiod = ctrl->cs_gpiods[chip->chip_select];
proxy->max_speed_hz = chip->max_speed_hz;
proxy->mode = chip->mode;
proxy->bits_per_word = chip->bits_per_word ? chip->bits_per_word : 8;
@@ -215,6 +219,62 @@ static void scan_boardinfo(struct spi_controller *ctrl)
}
}
+/**
+ * spi_get_gpio_descs() - grab chip select GPIOs for the master
+ * @ctlr: The SPI master to grab GPIO descriptors for
+ */
+static int spi_get_gpio_descs(struct spi_controller *ctlr)
+{
+ int nb, i;
+ struct gpio_desc **cs;
+ struct device *dev = ctlr->dev;
+
+ nb = gpiod_count(dev, "cs");
+ if (nb < 0) {
+ /* No GPIOs at all is fine, else return the error */
+ if (nb == -ENOENT)
+ return 0;
+ return nb;
+ }
+
+ ctlr->num_chipselect = max_t(int, nb, ctlr->num_chipselect);
+
+ cs = devm_kcalloc(dev, ctlr->num_chipselect, sizeof(*cs),
+ GFP_KERNEL);
+ if (!cs)
+ return -ENOMEM;
+ ctlr->cs_gpiods = cs;
+
+ for (i = 0; i < nb; i++) {
+ /*
+ * Most chipselects are active low, the inverted
+ * semantics are handled by special quirks in gpiolib,
+ * so initializing them GPIOD_OUT_LOW here means
+ * "unasserted", in most cases this will drive the physical
+ * line high.
+ */
+ cs[i] = gpiod_get_index_optional(dev, "cs", i, GPIOD_OUT_LOW);
+ if (IS_ERR(cs[i]))
+ return PTR_ERR(cs[i]);
+
+ if (cs[i]) {
+ /*
+ * If we find a CS GPIO, name it after the device and
+ * chip select line.
+ */
+ char *gpioname;
+
+ gpioname = basprintf("%s CS%d", dev_name(dev), i);
+ if (!gpioname)
+ return -ENOMEM;
+ gpiod_set_consumer_name(cs[i], gpioname);
+ free(gpioname);
+ }
+ }
+
+ return 0;
+}
+
static int spi_controller_check_ops(struct spi_controller *ctlr)
{
/*
@@ -285,6 +345,12 @@ int spi_register_controller(struct spi_controller *ctrl)
if (ctrl->bus_num < 0)
ctrl->bus_num = dyn_bus_id--;
+ if (ctrl->use_gpio_descriptors) {
+ status = spi_get_gpio_descs(ctrl);
+ if (status)
+ return status;
+ }
+
list_add_tail(&ctrl->list, &spi_controller_list);
spi_of_register_slaves(ctrl);
diff --git a/include/spi/spi.h b/include/spi/spi.h
index 9261d508befd..d643b83a7dbb 100644
--- a/include/spi/spi.h
+++ b/include/spi/spi.h
@@ -8,6 +8,7 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/bitops.h>
+#include <linux/gpio/consumer.h>
struct spi_controller_mem_ops;
struct spi_message;
@@ -99,6 +100,7 @@ struct spi_device {
void *controller_state;
void *controller_data;
const char *modalias;
+ struct gpio_desc *cs_gpiod; /* Chip select gpio desc */
/*
* likely need more hooks for more protocol options affecting how
@@ -156,6 +158,12 @@ static inline void spi_set_ctldata(struct spi_device *spi, void *state)
* the device whose settings are being modified.
* @transfer: adds a message to the controller's transfer queue.
* @cleanup: frees controller-specific state
+ * @cs_gpiods: Array of GPIO descriptors to use as chip select lines; one per CS
+ * number. Any individual value may be NULL for CS lines that
+ * are not GPIOs (driven by the SPI controller itself).
+ * @use_gpio_descriptors: Turns on the code in the SPI core to parse and grab
+ * GPIO descriptors. This will fill in @cs_gpiods and SPI devices will have
+ * the cs_gpiod assigned if a GPIO line is found for the chipselect.
* @list: link with the global spi_controller list
*
* Each SPI controller can communicate with one or more @spi_device
@@ -233,6 +241,10 @@ struct spi_controller {
/* called on release() to free memory provided by spi_controller */
void (*cleanup)(struct spi_device *spi);
+ /* GPIO chip select */
+ struct gpio_desc **cs_gpiods;
+ bool use_gpio_descriptors;
+
struct list_head list;
};
--
2.39.5
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 07/12] spi: add support to setup spi-cs-{setup,hold,inactive}-delay-ns
2024-12-16 13:03 [PATCH v2 01/12] spi: cosmetic style fixes Marco Felsch
` (4 preceding siblings ...)
2024-12-16 13:03 ` [PATCH v2 06/12] spi: add support to handle cs-gpios Marco Felsch
@ 2024-12-16 13:03 ` Marco Felsch
2024-12-16 13:03 ` [PATCH v2 08/12] spi: allow reporting the effectivly used speed_hz for a transfer Marco Felsch
` (5 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Marco Felsch @ 2024-12-16 13:03 UTC (permalink / raw)
To: barebox
Add support to parse and setup the common OF properties. The parsing is
quite confusing since the kernel driver API decided to use a u16 for the
value. I kept it this way to be closer to the Linux code.
This prepares the core for the upcoming core based message handling.
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
Changelog:
v2:
- no changes
drivers/spi/spi.c | 25 +++++++++++++++++++++++++
include/spi/spi.h | 22 ++++++++++++++++++++++
2 files changed, 47 insertions(+)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index c239de9d8549..e8a0b1b84be5 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -70,6 +70,9 @@ struct spi_device *spi_new_device(struct spi_controller *ctrl,
proxy->cs_gpiod = ctrl->cs_gpiods[chip->chip_select];
proxy->max_speed_hz = chip->max_speed_hz;
proxy->mode = chip->mode;
+ proxy->cs_setup = chip->cs_setup;
+ proxy->cs_hold = chip->cs_hold;
+ proxy->cs_inactive = chip->cs_inactive;
proxy->bits_per_word = chip->bits_per_word ? chip->bits_per_word : 8;
proxy->dev.platform_data = chip->platform_data;
proxy->dev.bus = &spi_bus;
@@ -111,6 +114,22 @@ struct spi_device *spi_new_device(struct spi_controller *ctrl,
}
EXPORT_SYMBOL(spi_new_device);
+static void of_spi_parse_dt_cs_delay(struct device_node *nc,
+ struct spi_delay *delay, const char *prop)
+{
+ u32 value;
+
+ if (!of_property_read_u32(nc, prop, &value)) {
+ if (value > U16_MAX) {
+ delay->value = DIV_ROUND_UP(value, 1000);
+ delay->unit = SPI_DELAY_UNIT_USECS;
+ } else {
+ delay->value = value;
+ delay->unit = SPI_DELAY_UNIT_NSECS;
+ }
+ }
+}
+
static void spi_of_register_slaves(struct spi_controller *ctrl)
{
struct device_node *n;
@@ -145,6 +164,12 @@ static void spi_of_register_slaves(struct spi_controller *ctrl)
chip.mode |= SPI_3WIRE;
of_property_read_u32(n, "spi-max-frequency",
&chip.max_speed_hz);
+
+ /* Device CS delays */
+ of_spi_parse_dt_cs_delay(n, &chip.cs_setup, "spi-cs-setup-delay-ns");
+ of_spi_parse_dt_cs_delay(n, &chip.cs_hold, "spi-cs-hold-delay-ns");
+ of_spi_parse_dt_cs_delay(n, &chip.cs_inactive, "spi-cs-inactive-delay-ns");
+
reg = of_find_property(n, "reg", NULL);
if (!reg)
continue;
diff --git a/include/spi/spi.h b/include/spi/spi.h
index d643b83a7dbb..2061a44134d0 100644
--- a/include/spi/spi.h
+++ b/include/spi/spi.h
@@ -13,6 +13,19 @@
struct spi_controller_mem_ops;
struct spi_message;
+/**
+ * struct spi_delay - SPI delay information
+ * @value: Value for the delay
+ * @unit: Unit for the delay
+ */
+struct spi_delay {
+#define SPI_DELAY_UNIT_USECS 0
+#define SPI_DELAY_UNIT_NSECS 1
+#define SPI_DELAY_UNIT_SCK 2
+ u16 value;
+ u8 unit;
+};
+
struct spi_board_info {
char *name;
int max_speed_hz;
@@ -26,6 +39,11 @@ struct spi_board_info {
u8 bits_per_word;
void *platform_data;
struct device_node *device_node;
+
+ /* CS delays */
+ struct spi_delay cs_setup;
+ struct spi_delay cs_hold;
+ struct spi_delay cs_inactive;
};
/**
@@ -101,6 +119,10 @@ struct spi_device {
void *controller_data;
const char *modalias;
struct gpio_desc *cs_gpiod; /* Chip select gpio desc */
+ /* CS delays */
+ struct spi_delay cs_setup;
+ struct spi_delay cs_hold;
+ struct spi_delay cs_inactive;
/*
* likely need more hooks for more protocol options affecting how
--
2.39.5
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 08/12] spi: allow reporting the effectivly used speed_hz for a transfer
2024-12-16 13:03 [PATCH v2 01/12] spi: cosmetic style fixes Marco Felsch
` (5 preceding siblings ...)
2024-12-16 13:03 ` [PATCH v2 07/12] spi: add support to setup spi-cs-{setup,hold,inactive}-delay-ns Marco Felsch
@ 2024-12-16 13:03 ` Marco Felsch
2024-12-16 13:03 ` [PATCH v2 09/12] spi: import spi_controller::flags Marco Felsch
` (4 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Marco Felsch @ 2024-12-16 13:03 UTC (permalink / raw)
To: barebox
This is a copy of Linux commit:
8<-------------------------------------------------------------------------
commit 5d7e2b5ed5858fe739d4cb8ad22dcce7bd9dbe7b
Author: Martin Sperl <kernel@martin.sperl.org>
Date: Sat Feb 23 08:49:49 2019 +0000
spi: core: allow reporting the effectivly used speed_hz for a transfer
Provide a means for the spi bus driver to report the effectively used
spi clock frequency used for each spi_transfer.
Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
8<-------------------------------------------------------------------------
to sync the spi core more with Linux which is required for the later
core common message handling.
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
Changelog:
v2:
- no changes
drivers/spi/spi.c | 1 +
include/spi/spi.h | 5 +++++
2 files changed, 6 insertions(+)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index e8a0b1b84be5..78569301776f 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -415,6 +415,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
message->spi = spi;
list_for_each_entry(xfer, &message->transfers, transfer_list) {
+ xfer->effective_speed_hz = 0;
if (!xfer->bits_per_word)
xfer->bits_per_word = spi->bits_per_word;
diff --git a/include/spi/spi.h b/include/spi/spi.h
index 2061a44134d0..8458d890f4e6 100644
--- a/include/spi/spi.h
+++ b/include/spi/spi.h
@@ -333,6 +333,9 @@ static inline size_t spi_max_transfer_size(struct spi_device *spi)
* @len: size of rx and tx buffers (in bytes)
* @speed_hz: Select a speed other then the device default for this
* transfer. If 0 the default (from @spi_device) is used.
+ * @effective_speed_hz: the effective SCK-speed that was used to
+ * transfer this transfer. Set to 0 if the SPI bus driver does
+ * not support it.
* @bits_per_word: select a bits_per_word other then the device default
* for this transfer. If 0 the default (from @spi_device) is used.
* @cs_change: affects chipselect after this transfer completes
@@ -402,6 +405,8 @@ struct spi_transfer {
u16 delay_usecs;
u32 speed_hz;
+ u32 effective_speed_hz;
+
struct list_head transfer_list;
};
--
2.39.5
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 09/12] spi: import spi_controller::flags
2024-12-16 13:03 [PATCH v2 01/12] spi: cosmetic style fixes Marco Felsch
` (6 preceding siblings ...)
2024-12-16 13:03 ` [PATCH v2 08/12] spi: allow reporting the effectivly used speed_hz for a transfer Marco Felsch
@ 2024-12-16 13:03 ` Marco Felsch
2024-12-16 13:03 ` [PATCH v2 10/12] spi: add support for spi_controller::set_cs_timing Marco Felsch
` (3 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Marco Felsch @ 2024-12-16 13:03 UTC (permalink / raw)
To: barebox
Import the flags supported by the Linux spi controller implementation to
make it easier to port driver from Linux.
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
Changelog:
v2:
- no changes
include/spi/spi.h | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/include/spi/spi.h b/include/spi/spi.h
index 8458d890f4e6..a8bbf55e0a5a 100644
--- a/include/spi/spi.h
+++ b/include/spi/spi.h
@@ -173,6 +173,7 @@ static inline void spi_set_ctldata(struct spi_device *spi, void *state)
* unsupported bits_per_word. If not set, this value is simply ignored,
* and it's up to the individual driver to perform any validation.
* @max_speed_hz: Highest supported transfer speed
+ * @flags: other constraints relevant to this driver
* @setup: updates the device mode and clocking records used by a
* device's SPI controller; protocol code may call this. This
* must fail if an unrecognized or unsupported mode is requested.
@@ -235,6 +236,16 @@ struct spi_controller {
/* limits on transfer speed */
u32 max_speed_hz;
+ /* Other constraints relevant to this driver */
+ u16 flags;
+#define SPI_CONTROLLER_HALF_DUPLEX BIT(0) /* Can't do full duplex */
+#define SPI_CONTROLLER_NO_RX BIT(1) /* Can't do buffer read */
+#define SPI_CONTROLLER_NO_TX BIT(2) /* Can't do buffer write */
+#define SPI_CONTROLLER_MUST_RX BIT(3) /* Requires rx */
+#define SPI_CONTROLLER_MUST_TX BIT(4) /* Requires tx */
+#define SPI_CONTROLLER_GPIO_SS BIT(5) /* GPIO CS must select slave */
+#define SPI_CONTROLLER_SUSPENDED BIT(6) /* Currently suspended */
+
/* setup mode and clock, etc (spi driver may call many times) */
int (*setup)(struct spi_device *spi);
--
2.39.5
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 10/12] spi: add support for spi_controller::set_cs_timing
2024-12-16 13:03 [PATCH v2 01/12] spi: cosmetic style fixes Marco Felsch
` (7 preceding siblings ...)
2024-12-16 13:03 ` [PATCH v2 09/12] spi: import spi_controller::flags Marco Felsch
@ 2024-12-16 13:03 ` Marco Felsch
2024-12-16 13:03 ` [PATCH v2 11/12] spi: Provide common spi_message processing loop Marco Felsch
` (2 subsequent siblings)
11 siblings, 0 replies; 14+ messages in thread
From: Marco Felsch @ 2024-12-16 13:03 UTC (permalink / raw)
To: barebox
Import the spi_controller set_cs_timing() hook to make it easier to port
Linux spi drivers.
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
Changelog:
v2:
- add spi_set_cs_timing()
drivers/spi/spi.c | 20 ++++++++++++++++++++
include/spi/spi.h | 12 ++++++++++++
2 files changed, 32 insertions(+)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 78569301776f..425c35759045 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -34,6 +34,22 @@ struct boardinfo {
static LIST_HEAD(board_list);
static LIST_HEAD(spi_controller_list);
+/**
+ * spi_set_cs_timing - configure CS setup, hold, and inactive delays
+ * @spi: the device that requires specific CS timing configuration
+ *
+ * Return: zero on success, else a negative error code.
+ */
+static int spi_set_cs_timing(struct spi_device *spi)
+{
+ int status = 0;
+
+ if (spi->controller->set_cs_timing && !spi->cs_gpiod)
+ status = spi->controller->set_cs_timing(spi);
+
+ return status;
+}
+
/**
* spi_new_device - instantiate one new SPI device
* @master: Controller to which device is connected
@@ -101,6 +117,10 @@ struct spi_device *spi_new_device(struct spi_controller *ctrl,
goto fail;
}
+ status = spi_set_cs_timing(proxy);
+ if (status)
+ goto fail;
+
status = register_device(&proxy->dev);
if (status)
goto fail;
diff --git a/include/spi/spi.h b/include/spi/spi.h
index a8bbf55e0a5a..106cca664068 100644
--- a/include/spi/spi.h
+++ b/include/spi/spi.h
@@ -179,6 +179,9 @@ static inline void spi_set_ctldata(struct spi_device *spi, void *state)
* must fail if an unrecognized or unsupported mode is requested.
* It's always safe to call this unless transfers are pending on
* the device whose settings are being modified.
+ * @set_cs_timing: optional hook for SPI devices to request SPI master
+ * controller for configuring specific CS setup time, hold time and inactive
+ * delay interms of clock counts
* @transfer: adds a message to the controller's transfer queue.
* @cleanup: frees controller-specific state
* @cs_gpiods: Array of GPIO descriptors to use as chip select lines; one per CS
@@ -249,6 +252,15 @@ struct spi_controller {
/* setup mode and clock, etc (spi driver may call many times) */
int (*setup)(struct spi_device *spi);
+ /*
+ * set_cs_timing() method is for SPI controllers that supports
+ * configuring CS timing.
+ *
+ * This hook allows SPI client drivers to request SPI controllers
+ * to configure specific CS timing through spi_set_cs_timing().
+ */
+ int (*set_cs_timing)(struct spi_device *spi);
+
/* bidirectional bulk transfers
*
* + The transfer() method may not sleep; its main role is
--
2.39.5
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 11/12] spi: Provide common spi_message processing loop
2024-12-16 13:03 [PATCH v2 01/12] spi: cosmetic style fixes Marco Felsch
` (8 preceding siblings ...)
2024-12-16 13:03 ` [PATCH v2 10/12] spi: add support for spi_controller::set_cs_timing Marco Felsch
@ 2024-12-16 13:03 ` Marco Felsch
2024-12-16 13:03 ` [PATCH v2 12/12] spi: add support for BCM2835 SPI controller Marco Felsch
2024-12-20 9:16 ` [PATCH v2 01/12] spi: cosmetic style fixes Sascha Hauer
11 siblings, 0 replies; 14+ messages in thread
From: Marco Felsch @ 2024-12-16 13:03 UTC (permalink / raw)
To: barebox
Add barebox spi core message handling support. This mimics the current
Linux spi core handling and the initial Linux commit:
8<--------------------------------------------------------------------------------
commit b158935f70b9c156903338053216dd0adf7ce31c
Author: Mark Brown <broonie@linaro.org>
Date: Sat Oct 5 11:50:40 2013 +0100
spi: Provide common spi_message processing loop
The loops which SPI controller drivers use to process the list of transfers
in a spi_message are typically very similar and have some error prone areas
such as the handling of /CS. Help simplify drivers by factoring this code
out into the core - if drivers provide a transfer_one() function instead
of a transfer_one_message() function the core will handle processing at the
message level.
/CS can be controlled by either setting cs_gpio or providing a set_cs
function. If this is not possible for hardware reasons then both can be
omitted and the driver should continue to implement manual /CS handling.
This is a first step in refactoring and it is expected that there will be
further enhancements, for example factoring out of the mapping of transfers
for DMA and the initiation and completion of interrupt driven transfers.
Signed-off-by: Mark Brown <broonie@linaro.org>
8<--------------------------------------------------------------------------------
The spi core message handling implemented by this commit is much simpler
than the current Linux spi core handling but it should definitly improve
the current situation regarding the barebox spi framework. After this
commit it should be much simpler to port spi driver from Linux to
barebox.
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
Changelog:
v2:
- no changes
drivers/spi/spi.c | 182 +++++++++++++++++++++++++++++++++++++++++++++-
include/spi/spi.h | 44 +++++++++++
2 files changed, 225 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 425c35759045..205ef794c505 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -320,6 +320,183 @@ static int spi_get_gpio_descs(struct spi_controller *ctlr)
return 0;
}
+static void _spi_transfer_delay_ns(u32 ns)
+{
+ if (!ns)
+ return;
+ if (ns <= NSEC_PER_USEC) {
+ ndelay(ns);
+ } else {
+ u32 us = DIV_ROUND_UP(ns, NSEC_PER_USEC);
+
+ udelay(us);
+ }
+}
+
+int spi_delay_to_ns(struct spi_delay *_delay, struct spi_transfer *xfer)
+{
+ u32 delay = _delay->value;
+ u32 unit = _delay->unit;
+ u32 hz;
+
+ if (!delay)
+ return 0;
+
+ switch (unit) {
+ case SPI_DELAY_UNIT_USECS:
+ delay *= NSEC_PER_USEC;
+ break;
+ case SPI_DELAY_UNIT_NSECS:
+ /* Nothing to do here */
+ break;
+ case SPI_DELAY_UNIT_SCK:
+ /* Clock cycles need to be obtained from spi_transfer */
+ if (!xfer)
+ return -EINVAL;
+ /*
+ * If there is unknown effective speed, approximate it
+ * by underestimating with half of the requested Hz.
+ */
+ hz = xfer->effective_speed_hz ?: xfer->speed_hz / 2;
+ if (!hz)
+ return -EINVAL;
+
+ /* Convert delay to nanoseconds */
+ delay *= DIV_ROUND_UP(NSEC_PER_SEC, hz);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return delay;
+}
+EXPORT_SYMBOL_GPL(spi_delay_to_ns);
+
+int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer)
+{
+ int delay;
+
+ if (!_delay)
+ return -EINVAL;
+
+ delay = spi_delay_to_ns(_delay, xfer);
+ if (delay < 0)
+ return delay;
+
+ _spi_transfer_delay_ns(delay);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(spi_delay_exec);
+
+static void spi_set_cs(struct spi_device *spi, bool enable)
+{
+ bool activate = enable;
+
+ if (spi->cs_gpiod && !activate)
+ spi_delay_exec(&spi->cs_hold, NULL);
+
+ if (spi->mode & SPI_CS_HIGH)
+ enable = !enable;
+
+ if (spi->cs_gpiod) {
+ if (!(spi->mode & SPI_NO_CS)) {
+ /* Polarity handled by GPIO library */
+ gpiod_set_value(spi->cs_gpiod, activate);
+ }
+ /* Some SPI masters need both GPIO CS & slave_select */
+ if ((spi->controller->flags & SPI_CONTROLLER_GPIO_SS) &&
+ spi->controller->set_cs)
+ spi->controller->set_cs(spi, !enable);
+ } else if (spi->controller->set_cs) {
+ spi->controller->set_cs(spi, !enable);
+ }
+
+ if (spi->cs_gpiod || !spi->controller->set_cs_timing) {
+ if (activate)
+ spi_delay_exec(&spi->cs_setup, NULL);
+ else
+ spi_delay_exec(&spi->cs_inactive, NULL);
+ }
+}
+
+/*
+ * spi_transfer_one_message - Default implementation of transfer()
+ *
+ * This is a standard implementation of transfer() for drivers which implement a
+ * transfer_one() operation. It provides standard handling of delays and chip
+ * select management.
+ *
+ */
+static int spi_transfer_one_message(struct spi_device *spi, struct spi_message *msg)
+{
+ struct spi_controller *ctlr = spi->controller;
+ struct spi_transfer *xfer;
+ bool keep_cs = false;
+ int ret = 0;
+
+ if (ctlr->prepare_message) {
+ ret = ctlr->prepare_message(ctlr, msg);
+ if (ret) {
+ dev_err(ctlr->dev, "failed to prepare message: %d\n",
+ ret);
+ msg->status = ret;
+ return ret;
+ }
+ }
+
+ spi_set_cs(msg->spi, true);
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ if ((xfer->tx_buf || xfer->rx_buf) && xfer->len) {
+ ret = ctlr->transfer_one(ctlr, msg->spi, xfer);
+ if (ret < 0) {
+ dev_err(&msg->spi->dev,
+ "SPI transfer failed: %d\n", ret);
+ goto out;
+ }
+ } else {
+ if (xfer->len)
+ dev_err(&msg->spi->dev,
+ "Bufferless transfer has length %u\n",
+ xfer->len);
+ }
+
+ if (msg->status != -EINPROGRESS)
+ goto out;
+
+ /* TODO: Convert to new spi_delay API */
+ if (xfer->delay_usecs)
+ udelay(xfer->delay_usecs);
+
+ if (xfer->cs_change) {
+ if (list_is_last(&xfer->transfer_list,
+ &msg->transfers)) {
+ keep_cs = true;
+ } else {
+ spi_set_cs(msg->spi, false);
+ /* TODO: Convert to new spi_delay API */
+ udelay(10);
+ spi_set_cs(msg->spi, true);
+ }
+ }
+
+ msg->actual_length += xfer->len;
+ }
+
+out:
+ if (ret != 0 || !keep_cs)
+ spi_set_cs(msg->spi, false);
+
+ if (msg->status == -EINPROGRESS)
+ msg->status = ret;
+
+ if (msg->status && ctlr->handle_err)
+ ctlr->handle_err(ctlr, msg);
+
+ return ret;
+}
+
static int spi_controller_check_ops(struct spi_controller *ctlr)
{
/*
@@ -332,7 +509,7 @@ static int spi_controller_check_ops(struct spi_controller *ctlr)
if (ctlr->mem_ops) {
if (!ctlr->mem_ops->exec_op)
return -EINVAL;
- } else if (!ctlr->transfer) {
+ } else if (!ctlr->transfer && !ctlr->transfer_one) {
return -EINVAL;
}
@@ -375,6 +552,9 @@ int spi_register_controller(struct spi_controller *ctrl)
if (status)
return status;
+ if (ctrl->transfer_one)
+ ctrl->transfer = spi_transfer_one_message;
+
slice_init(&ctrl->slice, dev_name(ctrl->dev));
/* even if it's just one always-selected device, there must
diff --git a/include/spi/spi.h b/include/spi/spi.h
index 106cca664068..85b8aca256f0 100644
--- a/include/spi/spi.h
+++ b/include/spi/spi.h
@@ -10,6 +10,8 @@
#include <linux/bitops.h>
#include <linux/gpio/consumer.h>
+struct spi_controller;
+struct spi_transfer;
struct spi_controller_mem_ops;
struct spi_message;
@@ -26,6 +28,9 @@ struct spi_delay {
u8 unit;
};
+extern int spi_delay_to_ns(struct spi_delay *_delay, struct spi_transfer *xfer);
+extern int spi_delay_exec(struct spi_delay *_delay, struct spi_transfer *xfer);
+
struct spi_board_info {
char *name;
int max_speed_hz;
@@ -184,6 +189,26 @@ static inline void spi_set_ctldata(struct spi_device *spi, void *state)
* delay interms of clock counts
* @transfer: adds a message to the controller's transfer queue.
* @cleanup: frees controller-specific state
+ * @set_cs: set the logic level of the chip select line. May be called
+ * from interrupt context.
+ * @prepare_message: set up the controller to transfer a single message,
+ * for example doing DMA mapping. Called from threaded
+ * context.
+ * @transfer_one: transfer a single spi_transfer.
+ *
+ * - return 0 if the transfer is finished,
+ * - return 1 if the transfer is still in progress. When
+ * the driver is finished with this transfer it must
+ * call spi_finalize_current_transfer() so the subsystem
+ * can issue the next transfer. If the transfer fails, the
+ * driver must set the flag SPI_TRANS_FAIL_IO to
+ * spi_transfer->error first, before calling
+ * spi_finalize_current_transfer().
+ * Note: transfer_one and transfer_one_message are mutually
+ * exclusive; when both are set, the generic subsystem does
+ * not call your transfer_one callback.
+ * @handle_err: the subsystem calls the driver to handle an error that occurs
+ * in the generic implementation of transfer_one_message().
* @cs_gpiods: Array of GPIO descriptors to use as chip select lines; one per CS
* number. Any individual value may be NULL for CS lines that
* are not GPIOs (driven by the SPI controller itself).
@@ -286,6 +311,25 @@ struct spi_controller {
/* called on release() to free memory provided by spi_controller */
void (*cleanup)(struct spi_device *spi);
+ /*
+ * These hooks are for drivers that want to use the generic
+ * controller transfer mechanism. If these are used, the
+ * transfer() function above must NOT be specified by the driver.
+ * Over time we expect SPI drivers to be phased over to this API.
+ */
+ int (*prepare_message)(struct spi_controller *ctlr,
+ struct spi_message *message);
+
+ /*
+ * These hooks are for drivers that use a generic implementation
+ * of transfer_one_message() provided by the core.
+ */
+ void (*set_cs)(struct spi_device *spi, bool enable);
+ int (*transfer_one)(struct spi_controller *ctlr, struct spi_device *spi,
+ struct spi_transfer *transfer);
+ void (*handle_err)(struct spi_controller *ctlr,
+ struct spi_message *message);
+
/* GPIO chip select */
struct gpio_desc **cs_gpiods;
bool use_gpio_descriptors;
--
2.39.5
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2 12/12] spi: add support for BCM2835 SPI controller
2024-12-16 13:03 [PATCH v2 01/12] spi: cosmetic style fixes Marco Felsch
` (9 preceding siblings ...)
2024-12-16 13:03 ` [PATCH v2 11/12] spi: Provide common spi_message processing loop Marco Felsch
@ 2024-12-16 13:03 ` Marco Felsch
2024-12-20 9:16 ` [PATCH v2 01/12] spi: cosmetic style fixes Sascha Hauer
11 siblings, 0 replies; 14+ messages in thread
From: Marco Felsch @ 2024-12-16 13:03 UTC (permalink / raw)
To: barebox
This ports the Linux spi-bcm2835 driver to barebox.
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
Changelog:
v2:
- no changes
drivers/spi/Kconfig | 11 ++
drivers/spi/Makefile | 1 +
drivers/spi/spi-bcm2835.c | 400 ++++++++++++++++++++++++++++++++++++++
3 files changed, 412 insertions(+)
create mode 100644 drivers/spi/spi-bcm2835.c
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 445c756a38a2..8357f7806e3c 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -95,6 +95,17 @@ config DRIVER_SPI_DSPI
This enables support for the Freescale DSPI controller in master
mode. VF610 platform uses the controller.
+config SPI_BCM2835
+ tristate "BCM2835 SPI controller"
+ depends on ARCH_BCM283X || COMPILE_TEST
+ help
+ This selects a driver for the Broadcom BCM2835 SPI master.
+
+ The BCM2835 contains two types of SPI master controller; the
+ "universal SPI master", and the regular SPI controller. This driver
+ is for the regular SPI controller. Slave mode operation is not also
+ not supported.
+
config SPI_ZYNQ_QSPI
tristate "Xilinx Zynq QSPI controller"
depends on ARCH_ZYNQ
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 68a8c4e675a5..e0f1124090a4 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_SPI_FSL_DSPI) += spi-fsl-dspi.o
obj-$(CONFIG_SPI_ATMEL_QUADSPI) += atmel-quadspi.o
obj-$(CONFIG_DRIVER_SPI_OMAP3) += omap3_spi.o
obj-$(CONFIG_DRIVER_SPI_DSPI) += dspi_spi.o
+obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o
obj-$(CONFIG_SPI_ZYNQ_QSPI) += zynq_qspi.o
obj-$(CONFIG_SPI_NXP_FLEXSPI) += spi-nxp-fspi.o
obj-$(CONFIG_DRIVER_SPI_STM32) += stm32_spi.o
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
new file mode 100644
index 000000000000..f0dc76a956f7
--- /dev/null
+++ b/drivers/spi/spi-bcm2835.c
@@ -0,0 +1,400 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for Broadcom BCM2835 SPI Controllers
+ *
+ * Copyright (C) 2012 Chris Boot
+ * Copyright (C) 2013 Stephen Warren
+ * Copyright (C) 2015 Martin Sperl
+ *
+ * This driver is inspired by:
+ * spi-ath79.c, Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ * spi-atmel.c, Copyright (C) 2006 Atmel Corporation
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <spi/spi.h>
+
+/* SPI register offsets */
+#define BCM2835_SPI_CS 0x00
+#define BCM2835_SPI_FIFO 0x04
+#define BCM2835_SPI_CLK 0x08
+#define BCM2835_SPI_DLEN 0x0c
+
+/* Bitfields in CS */
+#define BCM2835_SPI_CS_TXD 0x00040000
+#define BCM2835_SPI_CS_RXD 0x00020000
+#define BCM2835_SPI_CS_DONE 0x00010000
+#define BCM2835_SPI_CS_REN 0x00001000
+#define BCM2835_SPI_CS_ADCS 0x00000800
+#define BCM2835_SPI_CS_INTR 0x00000400
+#define BCM2835_SPI_CS_INTD 0x00000200
+#define BCM2835_SPI_CS_DMAEN 0x00000100
+#define BCM2835_SPI_CS_TA 0x00000080
+#define BCM2835_SPI_CS_CLEAR_RX 0x00000020
+#define BCM2835_SPI_CS_CLEAR_TX 0x00000010
+#define BCM2835_SPI_CS_CPOL 0x00000008
+#define BCM2835_SPI_CS_CPHA 0x00000004
+#define BCM2835_SPI_CS_CS_10 0x00000002
+#define BCM2835_SPI_CS_CS_01 0x00000001
+
+#define BCM2835_SPI_FIFO_SIZE 64
+#define BCM2835_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
+ | SPI_NO_CS | SPI_3WIRE)
+
+#define DRV_NAME "spi-bcm2835"
+
+/**
+ * struct bcm2835_spi - BCM2835 SPI controller
+ * @regs: base address of register map
+ * @clk: core clock, divided to calculate serial clock
+ * @clk_hz: core clock cached speed
+ * @tfr: SPI transfer currently processed
+ * @ctlr: SPI controller reverse lookup
+ * @tx_buf: pointer whence next transmitted byte is read
+ * @rx_buf: pointer where next received byte is written
+ * @tx_len: remaining bytes to transmit
+ * @rx_len: remaining bytes to receive
+ */
+struct bcm2835_spi {
+ void __iomem *regs;
+ struct clk *clk;
+ unsigned long clk_hz;
+ struct spi_transfer *tfr;
+ struct spi_controller ctlr;
+ const u8 *tx_buf;
+ u8 *rx_buf;
+ int tx_len;
+ int rx_len;
+};
+
+/**
+ * struct bcm2835_spidev - BCM2835 SPI target
+ * @prepare_cs: precalculated CS register value for ->prepare_message()
+ * (uses target-specific clock polarity and phase settings)
+ */
+struct bcm2835_spidev {
+ u32 prepare_cs;
+};
+
+static inline u32 bcm2835_rd(struct bcm2835_spi *bs, unsigned int reg)
+{
+ return readl(bs->regs + reg);
+}
+
+static inline void bcm2835_wr(struct bcm2835_spi *bs, unsigned int reg, u32 val)
+{
+ writel(val, bs->regs + reg);
+}
+
+static inline void bcm2835_rd_fifo(struct bcm2835_spi *bs)
+{
+ u8 byte;
+
+ while ((bs->rx_len) &&
+ (bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_RXD)) {
+ byte = bcm2835_rd(bs, BCM2835_SPI_FIFO);
+ if (bs->rx_buf)
+ *bs->rx_buf++ = byte;
+ bs->rx_len--;
+ }
+}
+
+static inline void bcm2835_wr_fifo(struct bcm2835_spi *bs)
+{
+ u8 byte;
+
+ while ((bs->tx_len) &&
+ (bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_TXD)) {
+ byte = bs->tx_buf ? *bs->tx_buf++ : 0;
+ bcm2835_wr(bs, BCM2835_SPI_FIFO, byte);
+ bs->tx_len--;
+ }
+}
+
+/**
+ * bcm2835_rd_fifo_count() - blindly read exactly @count bytes from RX FIFO
+ * @bs: BCM2835 SPI controller
+ * @count: bytes to read from RX FIFO
+ *
+ * The caller must ensure that @bs->rx_len is greater than or equal to @count,
+ * that the RX FIFO contains at least @count bytes and that the DMA Enable flag
+ * in the CS register is set (such that a read from the FIFO register receives
+ * 32-bit instead of just 8-bit). Moreover @bs->rx_buf must not be %NULL.
+ */
+static inline void bcm2835_rd_fifo_count(struct bcm2835_spi *bs, int count)
+{
+ u32 val;
+ int len;
+
+ bs->rx_len -= count;
+
+ do {
+ val = bcm2835_rd(bs, BCM2835_SPI_FIFO);
+ len = min(count, 4);
+ memcpy(bs->rx_buf, &val, len);
+ bs->rx_buf += len;
+ count -= 4;
+ } while (count > 0);
+}
+
+/**
+ * bcm2835_wr_fifo_blind() - blindly write up to @count bytes to TX FIFO
+ * @bs: BCM2835 SPI controller
+ * @count: bytes available for writing in TX FIFO
+ */
+static inline void bcm2835_wr_fifo_blind(struct bcm2835_spi *bs, int count)
+{
+ u8 val;
+
+ count = min(count, bs->tx_len);
+ bs->tx_len -= count;
+
+ do {
+ val = bs->tx_buf ? *bs->tx_buf++ : 0;
+ bcm2835_wr(bs, BCM2835_SPI_FIFO, val);
+ } while (--count);
+}
+
+static void bcm2835_spi_reset_hw(struct bcm2835_spi *bs)
+{
+ u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
+
+ /* Disable SPI interrupts and transfer */
+ cs &= ~(BCM2835_SPI_CS_INTR |
+ BCM2835_SPI_CS_INTD |
+ BCM2835_SPI_CS_DMAEN |
+ BCM2835_SPI_CS_TA);
+ /*
+ * Transmission sometimes breaks unless the DONE bit is written at the
+ * end of every transfer. The spec says it's a RO bit. Either the
+ * spec is wrong and the bit is actually of type RW1C, or it's a
+ * hardware erratum.
+ */
+ cs |= BCM2835_SPI_CS_DONE;
+ /* and reset RX/TX FIFOS */
+ cs |= BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX;
+
+ /* and reset the SPI_HW */
+ bcm2835_wr(bs, BCM2835_SPI_CS, cs);
+ /* as well as DLEN */
+ bcm2835_wr(bs, BCM2835_SPI_DLEN, 0);
+}
+
+static int bcm2835_spi_transfer_one_poll(struct spi_controller *ctlr,
+ struct spi_device *spi,
+ struct spi_transfer *tfr,
+ u32 cs)
+{
+ struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+
+ /* enable HW block without interrupts */
+ bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA);
+
+ bcm2835_wr_fifo_blind(bs, BCM2835_SPI_FIFO_SIZE);
+
+ /* loop until finished the transfer */
+ while (bs->rx_len) {
+ /* fill in tx fifo with remaining data */
+ bcm2835_wr_fifo(bs);
+
+ /* read from fifo as much as possible */
+ bcm2835_rd_fifo(bs);
+ }
+
+ /* Transfer complete - reset SPI HW */
+ bcm2835_spi_reset_hw(bs);
+ /* and return without waiting for completion */
+ return 0;
+}
+
+static int bcm2835_spi_transfer_one(struct spi_controller *ctlr,
+ struct spi_device *spi,
+ struct spi_transfer *tfr)
+{
+ struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+ struct bcm2835_spidev *target = spi_get_ctldata(spi);
+ unsigned long spi_hz, cdiv;
+ u32 cs = target->prepare_cs;
+
+ /* set clock */
+ spi_hz = tfr->speed_hz;
+
+ if (spi_hz >= bs->clk_hz / 2) {
+ cdiv = 2; /* clk_hz/2 is the fastest we can go */
+ } else if (spi_hz) {
+ /* CDIV must be a multiple of two */
+ cdiv = DIV_ROUND_UP(bs->clk_hz, spi_hz);
+ cdiv += (cdiv % 2);
+
+ if (cdiv >= 65536)
+ cdiv = 0; /* 0 is the slowest we can go */
+ } else {
+ cdiv = 0; /* 0 is the slowest we can go */
+ }
+ tfr->effective_speed_hz = cdiv ? (bs->clk_hz / cdiv) : (bs->clk_hz / 65536);
+ bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv);
+
+ /* handle all the 3-wire mode */
+ if (spi->mode & SPI_3WIRE && tfr->rx_buf)
+ cs |= BCM2835_SPI_CS_REN;
+
+ /* set transmit buffers and length */
+ bs->tx_buf = tfr->tx_buf;
+ bs->rx_buf = tfr->rx_buf;
+ bs->tx_len = tfr->len;
+ bs->rx_len = tfr->len;
+
+ return bcm2835_spi_transfer_one_poll(ctlr, spi, tfr, cs);
+}
+
+static int bcm2835_spi_prepare_message(struct spi_controller *ctlr,
+ struct spi_message *msg)
+{
+ struct spi_device *spi = msg->spi;
+ struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+ struct bcm2835_spidev *target = spi_get_ctldata(spi);
+
+ /*
+ * Set up clock polarity before spi_transfer_one_message() asserts
+ * chip select to avoid a gratuitous clock signal edge.
+ */
+ bcm2835_wr(bs, BCM2835_SPI_CS, target->prepare_cs);
+
+ return 0;
+}
+
+static void bcm2835_spi_handle_err(struct spi_controller *ctlr,
+ struct spi_message *msg)
+{
+ struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+
+ /* and reset */
+ bcm2835_spi_reset_hw(bs);
+}
+
+
+static void bcm2835_spi_cleanup(struct spi_device *spi)
+{
+ struct bcm2835_spidev *target = spi_get_ctldata(spi);
+
+ kfree(target);
+}
+
+static size_t bcm2835_spi_max_transfer_size(struct spi_device *spi)
+{
+ return SIZE_MAX;
+}
+
+static int bcm2835_spi_setup(struct spi_device *spi)
+{
+ struct bcm2835_spidev *target = spi_get_ctldata(spi);
+ u32 cs;
+
+ if (!target) {
+ target = kzalloc(sizeof(*target), GFP_KERNEL);
+ if (!target)
+ return -ENOMEM;
+
+ spi_set_ctldata(spi, target);
+ }
+
+ /*
+ * Precalculate SPI target's CS register value for ->prepare_message():
+ * The driver always uses software-controlled GPIO chip select, hence
+ * set the hardware-controlled native chip select to an invalid value
+ * to prevent it from interfering.
+ */
+ cs = BCM2835_SPI_CS_CS_10 | BCM2835_SPI_CS_CS_01;
+ if (spi->mode & SPI_CPOL)
+ cs |= BCM2835_SPI_CS_CPOL;
+ if (spi->mode & SPI_CPHA)
+ cs |= BCM2835_SPI_CS_CPHA;
+ target->prepare_cs = cs;
+
+ /*
+ * sanity checking the native-chipselects
+ */
+ if (spi->mode & SPI_NO_CS)
+ return 0;
+
+ if (!spi->cs_gpiod) {
+ dev_err(&spi->dev, "Driver supports only cs-gpios at the moment\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int bcm2835_spi_probe(struct device *dev)
+{
+ struct spi_controller *ctlr;
+ struct resource *iores;
+ struct bcm2835_spi *bs;
+ int err;
+
+ bs = xzalloc(sizeof(*bs));
+
+ ctlr = &bs->ctlr;
+
+ /* ctlr->mode_bits = BCM2835_SPI_MODE_BITS; */
+ ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
+ ctlr->num_chipselect = 3;
+ ctlr->use_gpio_descriptors = true;
+ ctlr->max_transfer_size = bcm2835_spi_max_transfer_size;
+ ctlr->setup = bcm2835_spi_setup;
+ ctlr->cleanup = bcm2835_spi_cleanup;
+ ctlr->transfer_one = bcm2835_spi_transfer_one;
+ ctlr->handle_err = bcm2835_spi_handle_err;
+ ctlr->prepare_message = bcm2835_spi_prepare_message;
+ ctlr->dev = dev;
+
+ spi_controller_set_devdata(ctlr, bs);
+
+ iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores))
+ return dev_err_probe(dev, PTR_ERR(iores),
+ "failed to get io-resource\n");
+ bs->regs = IOMEM(iores->start);
+
+ bs->clk = clk_get_enabled(dev, NULL);
+ if (IS_ERR(bs->clk))
+ return dev_err_probe(dev, PTR_ERR(bs->clk),
+ "could not get clk\n");
+
+ ctlr->max_speed_hz = clk_get_rate(bs->clk) / 2;
+
+ bs->clk_hz = clk_get_rate(bs->clk);
+
+ /* initialise the hardware with the default polarities */
+ bcm2835_wr(bs, BCM2835_SPI_CS,
+ BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
+
+ err = spi_register_controller(ctlr);
+ if (err)
+ return dev_err_probe(dev, err,
+ "could not register SPI controller\n");
+
+ return 0;
+}
+
+static const struct of_device_id bcm2835_spi_match[] = {
+ { .compatible = "brcm,bcm2835-spi", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, bcm2835_spi_match);
+
+static struct driver bcm2835_spi_driver = {
+ .name = DRV_NAME,
+ .of_compatible = DRV_OF_COMPAT(bcm2835_spi_match),
+ .probe = bcm2835_spi_probe,
+};
+coredevice_platform_driver(bcm2835_spi_driver);
+
+MODULE_DESCRIPTION("SPI controller driver for Broadcom BCM2835");
+MODULE_AUTHOR("Chris Boot <bootc@bootc.net>");
+MODULE_LICENSE("GPL");
--
2.39.5
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 01/12] spi: cosmetic style fixes
2024-12-16 13:03 [PATCH v2 01/12] spi: cosmetic style fixes Marco Felsch
` (10 preceding siblings ...)
2024-12-16 13:03 ` [PATCH v2 12/12] spi: add support for BCM2835 SPI controller Marco Felsch
@ 2024-12-20 9:16 ` Sascha Hauer
11 siblings, 0 replies; 14+ messages in thread
From: Sascha Hauer @ 2024-12-20 9:16 UTC (permalink / raw)
To: barebox, Marco Felsch
On Mon, 16 Dec 2024 14:03:13 +0100, Marco Felsch wrote:
> Replace <space><tab> by <tab> only. While on it move the forward
> declaration on the file top to sync it with the Linux spi.h.
>
>
Applied, thanks!
[01/12] spi: cosmetic style fixes
https://git.pengutronix.de/cgit/barebox/commit/?id=971d680834c3 (link may not be stable)
[02/12] spi: fix spi_message init during __spi_validate
https://git.pengutronix.de/cgit/barebox/commit/?id=a94723bc1096 (link may not be stable)
[03/12] spi: add spi_{set,get}_ctldata accessors
https://git.pengutronix.de/cgit/barebox/commit/?id=54409e934e68 (link may not be stable)
[04/12] gpiolib: add support for gpiod_get_index and gpiod_get_index_optional
https://git.pengutronix.de/cgit/barebox/commit/?id=5d3d3cde390a (link may not be stable)
[05/12] gpiolib: add support for gpiod_set_consumer_name
https://git.pengutronix.de/cgit/barebox/commit/?id=36c526f67557 (link may not be stable)
[06/12] spi: add support to handle cs-gpios
https://git.pengutronix.de/cgit/barebox/commit/?id=428c21711c51 (link may not be stable)
[07/12] spi: add support to setup spi-cs-{setup,hold,inactive}-delay-ns
https://git.pengutronix.de/cgit/barebox/commit/?id=d5c540ed7203 (link may not be stable)
[08/12] spi: allow reporting the effectivly used speed_hz for a transfer
https://git.pengutronix.de/cgit/barebox/commit/?id=2e6906488aa4 (link may not be stable)
[09/12] spi: import spi_controller::flags
https://git.pengutronix.de/cgit/barebox/commit/?id=8562b7b2d792 (link may not be stable)
[10/12] spi: add support for spi_controller::set_cs_timing
https://git.pengutronix.de/cgit/barebox/commit/?id=c18276085ffd (link may not be stable)
[11/12] spi: Provide common spi_message processing loop
https://git.pengutronix.de/cgit/barebox/commit/?id=64112e839a33 (link may not be stable)
[12/12] spi: add support for BCM2835 SPI controller
https://git.pengutronix.de/cgit/barebox/commit/?id=2851606ff823 (link may not be stable)
Best regards,
--
Sascha Hauer <s.hauer@pengutronix.de>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v2 06/12] spi: add support to handle cs-gpios
2024-12-16 13:03 ` [PATCH v2 06/12] spi: add support to handle cs-gpios Marco Felsch
@ 2024-12-20 9:51 ` Sascha Hauer
0 siblings, 0 replies; 14+ messages in thread
From: Sascha Hauer @ 2024-12-20 9:51 UTC (permalink / raw)
To: Marco Felsch; +Cc: barebox
On Mon, Dec 16, 2024 at 02:03:18PM +0100, Marco Felsch wrote:
> At the moment all drivers have to parse the cs-gpios on their own and
> have to implement the mapping. By this commit we add the support to
> handle this within the core and if there is valid CS GPIO for a device
> we assign it accordingly.
>
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> ---
> Changelog:
> v2:
> - add missing 'use_gpio_descriptor' member documentation
>
> drivers/spi/spi.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++
> include/spi/spi.h | 12 +++++++++
> 2 files changed, 78 insertions(+)
>
> diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> index 36d0653a191c..c239de9d8549 100644
> --- a/drivers/spi/spi.c
> +++ b/drivers/spi/spi.c
> @@ -8,6 +8,8 @@
> */
>
> #include <common.h>
> +#include <linux/device.h>
> +#include <linux/gpio/consumer.h>
> #include <linux/spi/spi-mem.h>
> #include <spi/spi.h>
> #include <xfuncs.h>
> @@ -64,6 +66,8 @@ struct spi_device *spi_new_device(struct spi_controller *ctrl,
> proxy = xzalloc(sizeof *proxy);
> proxy->master = ctrl;
> proxy->chip_select = chip->chip_select;
> + if (ctrl->cs_gpiods)
> + proxy->cs_gpiod = ctrl->cs_gpiods[chip->chip_select];
> proxy->max_speed_hz = chip->max_speed_hz;
> proxy->mode = chip->mode;
> proxy->bits_per_word = chip->bits_per_word ? chip->bits_per_word : 8;
> @@ -215,6 +219,62 @@ static void scan_boardinfo(struct spi_controller *ctrl)
> }
> }
>
> +/**
> + * spi_get_gpio_descs() - grab chip select GPIOs for the master
> + * @ctlr: The SPI master to grab GPIO descriptors for
> + */
> +static int spi_get_gpio_descs(struct spi_controller *ctlr)
> +{
> + int nb, i;
> + struct gpio_desc **cs;
> + struct device *dev = ctlr->dev;
> +
> + nb = gpiod_count(dev, "cs");
> + if (nb < 0) {
> + /* No GPIOs at all is fine, else return the error */
> + if (nb == -ENOENT)
> + return 0;
> + return nb;
> + }
This breaks a number of non device tree defconfigs:
drivers/spi/spi.o: in function `spi_get_gpio_descs':
/__w/barebox/barebox/drivers/spi/spi.c:277:(.text.spi_register_controller+0x15c): undefined reference to `gpiod_count'
I haven't looked into it yet what we can best do about it.
Sascha
--
Pengutronix e.K. | |
Steuerwalder Str. 21 | http://www.pengutronix.de/ |
31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2024-12-20 11:12 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-12-16 13:03 [PATCH v2 01/12] spi: cosmetic style fixes Marco Felsch
2024-12-16 13:03 ` [PATCH v2 02/12] spi: fix spi_message init during __spi_validate Marco Felsch
2024-12-16 13:03 ` [PATCH v2 03/12] spi: add spi_{set,get}_ctldata accessors Marco Felsch
2024-12-16 13:03 ` [PATCH v2 04/12] gpiolib: add support for gpiod_get_index and gpiod_get_index_optional Marco Felsch
2024-12-16 13:03 ` [PATCH v2 05/12] gpiolib: add support for gpiod_set_consumer_name Marco Felsch
2024-12-16 13:03 ` [PATCH v2 06/12] spi: add support to handle cs-gpios Marco Felsch
2024-12-20 9:51 ` Sascha Hauer
2024-12-16 13:03 ` [PATCH v2 07/12] spi: add support to setup spi-cs-{setup,hold,inactive}-delay-ns Marco Felsch
2024-12-16 13:03 ` [PATCH v2 08/12] spi: allow reporting the effectivly used speed_hz for a transfer Marco Felsch
2024-12-16 13:03 ` [PATCH v2 09/12] spi: import spi_controller::flags Marco Felsch
2024-12-16 13:03 ` [PATCH v2 10/12] spi: add support for spi_controller::set_cs_timing Marco Felsch
2024-12-16 13:03 ` [PATCH v2 11/12] spi: Provide common spi_message processing loop Marco Felsch
2024-12-16 13:03 ` [PATCH v2 12/12] spi: add support for BCM2835 SPI controller Marco Felsch
2024-12-20 9:16 ` [PATCH v2 01/12] spi: cosmetic style fixes Sascha Hauer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox