summaryrefslogtreecommitdiff
path: root/drivers/spi/spi.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-12-13 12:54:31 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2022-12-13 12:54:31 -0800
commitd0f3ad23cf4f4046e88eef92c608d43cad9e4f7e (patch)
treef22a64cac48017fab350b4a954652f687a952a5d /drivers/spi/spi.c
parentc5589c436d4646e0dc23f64264db8e04cf67c88f (diff)
parent3cf241c3d56ff19f5192cb42a025bc6582b6e8fa (diff)
Merge tag 'spi-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
Pull spi updates from Mark Brown: "A busy enough release, but not for the core which has only seen very small updates. The biggest addition is the readdition of support for detailed configuration of the timings around chip selects. That had been removed for lack of use but there's been applications found for it on Atmel systems. Otherwise the updates are mostly feature additions and cleanups to existing drivers. Summary: - Provide a helper for getting device match data in a way that abstracts away which firmware interface is being used. - Re-add the spi_set_cs_timing() API for detailed configuration of the timing around chip select and support it on Atmel. - Support for MediaTek MT7986, Microchip PCI1xxxx, Nuvoton WPCM450 FIU and Socionext F_OSPI" * tag 'spi-v6.2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (66 commits) spi: dt-bindings: Convert Synquacer SPI to DT schema spi: spi-gpio: Don't set MOSI as an input if not 3WIRE mode spi: spi-mtk-nor: Add recovery mechanism for dma read timeout spi: spi-fsl-lpspi: add num-cs binding for lpspi spi: spi-fsl-lpspi: support multiple cs for lpspi spi: mtk-snfi: Add snfi support for MT7986 IC spi: spidev: mask SPI_CS_HIGH in SPI_IOC_RD_MODE spi: cadence-quadspi: Add minimum operable clock rate warning to baudrate divisor calculation spi: microchip: pci1xxxx: Add suspend and resume support for PCI1XXXX SPI driver spi: dt-bindings: nuvoton,wpcm450-fiu: Fix warning in example (missing reg property) spi: dt-bindings: nuvoton,wpcm450-fiu: Fix error in example (bogus include) spi: mediatek: Enable irq when pdata is ready spi: spi-mtk-nor: Unify write buffer on/off spi: intel: Add support for SFDP opcode spi: intel: Take possible chip address into account in intel_spi_read/write_reg() spi: intel: Implement adjust_op_size() spi: intel: Use ->replacement_op in intel_spi_hw_cycle() spi: cadence: Drop obsolete dependency on COMPILE_TEST spi: Add Nuvoton WPCM450 Flash Interface Unit (FIU) bindings spi: wpcm-fiu: Add direct map support ...
Diffstat (limited to 'drivers/spi/spi.c')
-rw-r--r--drivers/spi/spi.c70
1 files changed, 68 insertions, 2 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 5f9aedd1f0b6..3cc7bb4d03de 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -127,10 +127,10 @@ do { \
unsigned int start; \
pcpu_stats = per_cpu_ptr(in, i); \
do { \
- start = u64_stats_fetch_begin_irq( \
+ start = u64_stats_fetch_begin( \
&pcpu_stats->syncp); \
inc = u64_stats_read(&pcpu_stats->field); \
- } while (u64_stats_fetch_retry_irq( \
+ } while (u64_stats_fetch_retry( \
&pcpu_stats->syncp, start)); \
ret += inc; \
} \
@@ -360,6 +360,18 @@ const struct spi_device_id *spi_get_device_id(const struct spi_device *sdev)
}
EXPORT_SYMBOL_GPL(spi_get_device_id);
+const void *spi_get_device_match_data(const struct spi_device *sdev)
+{
+ const void *match;
+
+ match = device_get_match_data(&sdev->dev);
+ if (match)
+ return match;
+
+ return (const void *)spi_get_device_id(sdev)->driver_data;
+}
+EXPORT_SYMBOL_GPL(spi_get_device_match_data);
+
static int spi_match_device(struct device *dev, struct device_driver *drv)
{
const struct spi_device *spi = to_spi_device(dev);
@@ -2212,6 +2224,7 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
struct device_node *nc)
{
u32 value;
+ u16 cs_setup;
int rc;
/* Mode (clock phase/polarity/etc.) */
@@ -2297,6 +2310,11 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
if (!of_property_read_u32(nc, "spi-max-frequency", &value))
spi->max_speed_hz = value;
+ if (!of_property_read_u16(nc, "spi-cs-setup-ns", &cs_setup)) {
+ spi->cs_setup.value = cs_setup;
+ spi->cs_setup.unit = SPI_DELAY_UNIT_NSECS;
+ }
+
return 0;
}
@@ -2759,6 +2777,17 @@ int spi_slave_abort(struct spi_device *spi)
}
EXPORT_SYMBOL_GPL(spi_slave_abort);
+int spi_target_abort(struct spi_device *spi)
+{
+ struct spi_controller *ctlr = spi->controller;
+
+ if (spi_controller_is_target(ctlr) && ctlr->target_abort)
+ return ctlr->target_abort(ctlr);
+
+ return -ENOTSUPP;
+}
+EXPORT_SYMBOL_GPL(spi_target_abort);
+
static ssize_t slave_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -3593,6 +3622,37 @@ static int __spi_validate_bits_per_word(struct spi_controller *ctlr,
}
/**
+ * 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)
+{
+ struct device *parent = spi->controller->dev.parent;
+ int status = 0;
+
+ if (spi->controller->set_cs_timing && !spi->cs_gpiod) {
+ if (spi->controller->auto_runtime_pm) {
+ status = pm_runtime_get_sync(parent);
+ if (status < 0) {
+ pm_runtime_put_noidle(parent);
+ dev_err(&spi->controller->dev, "Failed to power device: %d\n",
+ status);
+ return status;
+ }
+
+ status = spi->controller->set_cs_timing(spi);
+ pm_runtime_mark_last_busy(parent);
+ pm_runtime_put_autosuspend(parent);
+ } else {
+ status = spi->controller->set_cs_timing(spi);
+ }
+ }
+ return status;
+}
+
+/**
* spi_setup - setup SPI mode and clock rate
* @spi: the device whose settings are being modified
* Context: can sleep, and no requests are queued to the device
@@ -3688,6 +3748,12 @@ int spi_setup(struct spi_device *spi)
}
}
+ status = spi_set_cs_timing(spi);
+ if (status) {
+ mutex_unlock(&spi->controller->io_mutex);
+ return status;
+ }
+
if (spi->controller->auto_runtime_pm && spi->controller->set_cs) {
status = pm_runtime_resume_and_get(spi->controller->dev.parent);
if (status < 0) {