Some spi controller switch the mosi line to high, whenever they are
idle. This may not be desired in all use cases. For example neopixel
leds can get confused and flicker due to misinterpreting the idle state.
Therefore, we introduce a new spi-mode bit, with which the idle behaviour
can be overwritten on a per device basis.
Signed-off-by: Boerge Struempfel <[email protected]>
---
include/uapi/linux/spi/spi.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/include/uapi/linux/spi/spi.h b/include/uapi/linux/spi/spi.h
index 9d5f58059703..ca56e477d161 100644
--- a/include/uapi/linux/spi/spi.h
+++ b/include/uapi/linux/spi/spi.h
@@ -28,6 +28,7 @@
#define SPI_RX_OCTAL _BITUL(14) /* receive with 8 wires */
#define SPI_3WIRE_HIZ _BITUL(15) /* high impedance turnaround */
#define SPI_RX_CPHA_FLIP _BITUL(16) /* flip CPHA on Rx only xfer */
+#define SPI_MOSI_IDLE_LOW _BITUL(17) /* leave mosi line low when idle */
/*
* All the bits defined above should be covered by SPI_MODE_USER_MASK.
@@ -37,6 +38,6 @@
* These bits must not overlap. A static assert check should make sure of that.
* If adding extra bits, make sure to increase the bit index below as well.
*/
-#define SPI_MODE_USER_MASK (_BITUL(17) - 1)
+#define SPI_MODE_USER_MASK (_BITUL(18) - 1)
#endif /* _UAPI_SPI_H */
--
2.25.1
Allow userspace to set SPI_MOSI_IDLE_LOW mode bit using the
SPI_IOC_WR_MODE32 ioctl.
Signed-off-by: Boerge Struempfel <[email protected]>
---
drivers/spi/spidev.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 39d94c850839..e50da54468ec 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -64,7 +64,7 @@ static_assert(N_SPI_MINORS > 0 && N_SPI_MINORS <= 256);
| SPI_NO_CS | SPI_READY | SPI_TX_DUAL \
| SPI_TX_QUAD | SPI_TX_OCTAL | SPI_RX_DUAL \
| SPI_RX_QUAD | SPI_RX_OCTAL \
- | SPI_RX_CPHA_FLIP)
+ | SPI_RX_CPHA_FLIP | SPI_MOSI_IDLE_LOW)
struct spidev_data {
dev_t devt;
--
2.25.1
By default, the spi-imx controller pulls the mosi line high, whenever it
is idle. This behaviour can be inverted per CS by setting the
corresponding DATA_CTL bit in the config register of the controller.
Also, since the controller mode-bits have to be touched anyways, the
SPI_CPOL and SPI_CPHA are replaced by the combined SPI_MODE_X_MASK flag.
Signed-off-by: Boerge Struempfel <[email protected]>
---
drivers/spi/spi-imx.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 34e5f81ec431..e5e55d66fecc 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -281,6 +281,7 @@ static bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device
#define MX51_ECSPI_CONFIG_SCLKPOL(cs) (1 << ((cs & 3) + 4))
#define MX51_ECSPI_CONFIG_SBBCTRL(cs) (1 << ((cs & 3) + 8))
#define MX51_ECSPI_CONFIG_SSBPOL(cs) (1 << ((cs & 3) + 12))
+#define MX51_ECSPI_CONFIG_DATACTL(cs) (1 << ((cs & 3) + 16))
#define MX51_ECSPI_CONFIG_SCLKCTL(cs) (1 << ((cs & 3) + 20))
#define MX51_ECSPI_INT 0x10
@@ -573,6 +574,11 @@ static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
cfg &= ~MX51_ECSPI_CONFIG_SCLKCTL(spi_get_chipselect(spi, 0));
}
+ if (spi->mode & SPI_MOSI_IDLE_LOW)
+ cfg |= MX51_ECSPI_CONFIG_DATACTL(spi_get_chipselect(spi, 0));
+ else
+ cfg &= ~MX51_ECSPI_CONFIG_DATACTL(spi_get_chipselect(spi, 0);
+
if (spi->mode & SPI_CS_HIGH)
cfg |= MX51_ECSPI_CONFIG_SSBPOL(spi_get_chipselect(spi, 0));
else
@@ -1743,7 +1749,8 @@ static int spi_imx_probe(struct platform_device *pdev)
spi_imx->controller->prepare_message = spi_imx_prepare_message;
spi_imx->controller->unprepare_message = spi_imx_unprepare_message;
spi_imx->controller->slave_abort = spi_imx_slave_abort;
- spi_imx->controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_NO_CS;
+ spi_imx->controller->mode_bits = SPI_MODE_X_MASK | SPI_CS_HIGH | SPI_NO_CS |
+ SPI_MOSI_IDLE_LOW;
if (is_imx35_cspi(spi_imx) || is_imx51_ecspi(spi_imx) ||
is_imx53_ecspi(spi_imx))
--
2.25.1
Hi Boerge,
kernel test robot noticed the following build errors:
[auto build test ERROR on broonie-spi/for-next]
[also build test ERROR on shawnguo/for-next linus/master v6.4-rc2 next-20230517]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Boerge-Struempfel/spi-spi-imx-add-support-for-SPI_MOSI_IDLE_LOW-mode-bit/20230517-183245
base: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
patch link: https://lore.kernel.org/r/20230517103007.26287-2-boerge.struempfel%40gmail.com
patch subject: [PATCH 2/3] spi: spi-imx: add support for SPI_MOSI_IDLE_LOW mode bit
config: riscv-randconfig-r001-20230517
compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project b0fb98227c90adf2536c9ad644a74d5e92961111)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install riscv cross compiling tool for clang build
# apt-get install binutils-riscv64-linux-gnu
# https://github.com/intel-lab-lkp/linux/commit/62dc97266153cfe514c983e9baeb51766f16daa2
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Boerge-Struempfel/spi-spi-imx-add-support-for-SPI_MOSI_IDLE_LOW-mode-bit/20230517-183245
git checkout 62dc97266153cfe514c983e9baeb51766f16daa2
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=riscv olddefconfig
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=riscv SHELL=/bin/bash drivers/spi/
If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All errors (new ones prefixed by >>):
>> drivers/spi/spi-imx.c:580:11: error: unterminated function-like macro invocation
cfg &= ~MX51_ECSPI_CONFIG_DATACTL(spi_get_chipselect(spi, 0);
^
drivers/spi/spi-imx.c:284:9: note: macro 'MX51_ECSPI_CONFIG_DATACTL' defined here
#define MX51_ECSPI_CONFIG_DATACTL(cs) (1 << ((cs & 3) + 16))
^
>> drivers/spi/spi-imx.c:1956:39: error: expected expression
MODULE_ALIAS("platform:" DRIVER_NAME);
^
>> drivers/spi/spi-imx.c:1956:39: error: expected '}'
drivers/spi/spi-imx.c:522:1: note: to match this '{'
{
^
3 errors generated.
vim +580 drivers/spi/spi-imx.c
519
520 static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
521 struct spi_message *msg)
522 {
523 struct spi_device *spi = msg->spi;
524 struct spi_transfer *xfer;
525 u32 ctrl = MX51_ECSPI_CTRL_ENABLE;
526 u32 min_speed_hz = ~0U;
527 u32 testreg, delay;
528 u32 cfg = readl(spi_imx->base + MX51_ECSPI_CONFIG);
529 u32 current_cfg = cfg;
530
531 /* set Master or Slave mode */
532 if (spi_imx->slave_mode)
533 ctrl &= ~MX51_ECSPI_CTRL_MODE_MASK;
534 else
535 ctrl |= MX51_ECSPI_CTRL_MODE_MASK;
536
537 /*
538 * Enable SPI_RDY handling (falling edge/level triggered).
539 */
540 if (spi->mode & SPI_READY)
541 ctrl |= MX51_ECSPI_CTRL_DRCTL(spi_imx->spi_drctl);
542
543 /* set chip select to use */
544 ctrl |= MX51_ECSPI_CTRL_CS(spi_get_chipselect(spi, 0));
545
546 /*
547 * The ctrl register must be written first, with the EN bit set other
548 * registers must not be written to.
549 */
550 writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
551
552 testreg = readl(spi_imx->base + MX51_ECSPI_TESTREG);
553 if (spi->mode & SPI_LOOP)
554 testreg |= MX51_ECSPI_TESTREG_LBC;
555 else
556 testreg &= ~MX51_ECSPI_TESTREG_LBC;
557 writel(testreg, spi_imx->base + MX51_ECSPI_TESTREG);
558
559 /*
560 * eCSPI burst completion by Chip Select signal in Slave mode
561 * is not functional for imx53 Soc, config SPI burst completed when
562 * BURST_LENGTH + 1 bits are received
563 */
564 if (spi_imx->slave_mode && is_imx53_ecspi(spi_imx))
565 cfg &= ~MX51_ECSPI_CONFIG_SBBCTRL(spi_get_chipselect(spi, 0));
566 else
567 cfg |= MX51_ECSPI_CONFIG_SBBCTRL(spi_get_chipselect(spi, 0));
568
569 if (spi->mode & SPI_CPOL) {
570 cfg |= MX51_ECSPI_CONFIG_SCLKPOL(spi_get_chipselect(spi, 0));
571 cfg |= MX51_ECSPI_CONFIG_SCLKCTL(spi_get_chipselect(spi, 0));
572 } else {
573 cfg &= ~MX51_ECSPI_CONFIG_SCLKPOL(spi_get_chipselect(spi, 0));
574 cfg &= ~MX51_ECSPI_CONFIG_SCLKCTL(spi_get_chipselect(spi, 0));
575 }
576
577 if (spi->mode & SPI_MOSI_IDLE_LOW)
578 cfg |= MX51_ECSPI_CONFIG_DATACTL(spi_get_chipselect(spi, 0));
579 else
> 580 cfg &= ~MX51_ECSPI_CONFIG_DATACTL(spi_get_chipselect(spi, 0);
581
582 if (spi->mode & SPI_CS_HIGH)
583 cfg |= MX51_ECSPI_CONFIG_SSBPOL(spi_get_chipselect(spi, 0));
584 else
585 cfg &= ~MX51_ECSPI_CONFIG_SSBPOL(spi_get_chipselect(spi, 0));
586
587 if (cfg == current_cfg)
588 return 0;
589
590 writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG);
591
592 /*
593 * Wait until the changes in the configuration register CONFIGREG
594 * propagate into the hardware. It takes exactly one tick of the
595 * SCLK clock, but we will wait two SCLK clock just to be sure. The
596 * effect of the delay it takes for the hardware to apply changes
597 * is noticable if the SCLK clock run very slow. In such a case, if
598 * the polarity of SCLK should be inverted, the GPIO ChipSelect might
599 * be asserted before the SCLK polarity changes, which would disrupt
600 * the SPI communication as the device on the other end would consider
601 * the change of SCLK polarity as a clock tick already.
602 *
603 * Because spi_imx->spi_bus_clk is only set in prepare_message
604 * callback, iterate over all the transfers in spi_message, find the
605 * one with lowest bus frequency, and use that bus frequency for the
606 * delay calculation. In case all transfers have speed_hz == 0, then
607 * min_speed_hz is ~0 and the resulting delay is zero.
608 */
609 list_for_each_entry(xfer, &msg->transfers, transfer_list) {
610 if (!xfer->speed_hz)
611 continue;
612 min_speed_hz = min(xfer->speed_hz, min_speed_hz);
613 }
614
615 delay = (2 * 1000000) / min_speed_hz;
616 if (likely(delay < 10)) /* SCLK is faster than 200 kHz */
617 udelay(delay);
618 else /* SCLK is _very_ slow */
619 usleep_range(delay, delay + 10);
620
621 return 0;
622 }
623
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Hi Boerge,
kernel test robot noticed the following build errors:
[auto build test ERROR on broonie-spi/for-next]
[also build test ERROR on shawnguo/for-next linus/master v6.4-rc2 next-20230517]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Boerge-Struempfel/spi-spi-imx-add-support-for-SPI_MOSI_IDLE_LOW-mode-bit/20230517-183245
base: https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next
patch link: https://lore.kernel.org/r/20230517103007.26287-2-boerge.struempfel%40gmail.com
patch subject: [PATCH 2/3] spi: spi-imx: add support for SPI_MOSI_IDLE_LOW mode bit
config: m68k-allyesconfig
compiler: m68k-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/62dc97266153cfe514c983e9baeb51766f16daa2
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Boerge-Struempfel/spi-spi-imx-add-support-for-SPI_MOSI_IDLE_LOW-mode-bit/20230517-183245
git checkout 62dc97266153cfe514c983e9baeb51766f16daa2
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=m68k olddefconfig
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=m68k SHELL=/bin/bash drivers/spi/
If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All errors (new ones prefixed by >>):
drivers/spi/spi-imx.c: In function 'mx51_ecspi_prepare_message':
>> drivers/spi/spi-imx.c:1956:39: error: unterminated argument list invoking macro "MX51_ECSPI_CONFIG_DATACTL"
1956 | MODULE_ALIAS("platform:" DRIVER_NAME);
| ^
>> drivers/spi/spi-imx.c:580:25: error: 'MX51_ECSPI_CONFIG_DATACTL' undeclared (first use in this function)
580 | cfg &= ~MX51_ECSPI_CONFIG_DATACTL(spi_get_chipselect(spi, 0);
| ^~~~~~~~~~~~~~~~~~~~~~~~~
drivers/spi/spi-imx.c:580:25: note: each undeclared identifier is reported only once for each function it appears in
>> drivers/spi/spi-imx.c:580:50: error: expected ';' at end of input
580 | cfg &= ~MX51_ECSPI_CONFIG_DATACTL(spi_get_chipselect(spi, 0);
| ^
| ;
......
drivers/spi/spi-imx.c:579:9: note: '-Wmisleading-indentation' is disabled from this point onwards, since column-tracking was disabled due to the size of the code/headers
579 | else
| ^~~~
drivers/spi/spi-imx.c:579:9: note: adding '-flarge-source-files' will allow for more column-tracking support, at the expense of compilation time and memory
>> drivers/spi/spi-imx.c:580:17: error: expected declaration or statement at end of input
580 | cfg &= ~MX51_ECSPI_CONFIG_DATACTL(spi_get_chipselect(spi, 0);
| ^~~
drivers/spi/spi-imx.c:529:13: warning: unused variable 'current_cfg' [-Wunused-variable]
529 | u32 current_cfg = cfg;
| ^~~~~~~~~~~
drivers/spi/spi-imx.c:527:22: warning: unused variable 'delay' [-Wunused-variable]
527 | u32 testreg, delay;
| ^~~~~
drivers/spi/spi-imx.c:526:13: warning: unused variable 'min_speed_hz' [-Wunused-variable]
526 | u32 min_speed_hz = ~0U;
| ^~~~~~~~~~~~
drivers/spi/spi-imx.c:524:30: warning: unused variable 'xfer' [-Wunused-variable]
524 | struct spi_transfer *xfer;
| ^~~~
drivers/spi/spi-imx.c:580:17: error: no return statement in function returning non-void [-Werror=return-type]
580 | cfg &= ~MX51_ECSPI_CONFIG_DATACTL(spi_get_chipselect(spi, 0);
| ^~~
drivers/spi/spi-imx.c: At top level:
drivers/spi/spi-imx.c:520:12: warning: 'mx51_ecspi_prepare_message' defined but not used [-Wunused-function]
520 | static int mx51_ecspi_prepare_message(struct spi_imx_data *spi_imx,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/spi/spi-imx.c:511:13: warning: 'mx51_ecspi_disable' defined but not used [-Wunused-function]
511 | static void mx51_ecspi_disable(struct spi_imx_data *spi_imx)
| ^~~~~~~~~~~~~~~~~~
drivers/spi/spi-imx.c:502:13: warning: 'mx51_ecspi_trigger' defined but not used [-Wunused-function]
502 | static void mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
| ^~~~~~~~~~~~~~~~~~
drivers/spi/spi-imx.c:486:13: warning: 'mx51_ecspi_intctrl' defined but not used [-Wunused-function]
486 | static void mx51_ecspi_intctrl(struct spi_imx_data *spi_imx, int enable)
| ^~~~~~~~~~~~~~~~~~
drivers/spi/spi-imx.c:449:21: warning: 'mx51_ecspi_clkdiv' defined but not used [-Wunused-function]
449 | static unsigned int mx51_ecspi_clkdiv(struct spi_imx_data *spi_imx,
| ^~~~~~~~~~~~~~~~~
drivers/spi/spi-imx.c:428:13: warning: 'mx53_ecspi_tx_slave' defined but not used [-Wunused-function]
428 | static void mx53_ecspi_tx_slave(struct spi_imx_data *spi_imx)
| ^~~~~~~~~~~~~~~~~~~
drivers/spi/spi-imx.c:408:13: warning: 'mx53_ecspi_rx_slave' defined but not used [-Wunused-function]
408 | static void mx53_ecspi_rx_slave(struct spi_imx_data *spi_imx)
| ^~~~~~~~~~~~~~~~~~~
drivers/spi/spi-imx.c:380:13: warning: 'spi_imx_buf_tx_swap' defined but not used [-Wunused-function]
380 | static void spi_imx_buf_tx_swap(struct spi_imx_data *spi_imx)
| ^~~~~~~~~~~~~~~~~~~
drivers/spi/spi-imx.c:328:13: warning: 'spi_imx_buf_rx_swap' defined but not used [-Wunused-function]
328 | static void spi_imx_buf_rx_swap(struct spi_imx_data *spi_imx)
| ^~~~~~~~~~~~~~~~~~~
drivers/spi/spi-imx.c:233:13: warning: 'spi_imx_can_dma' defined but not used [-Wunused-function]
233 | static bool spi_imx_can_dma(struct spi_controller *controller, struct spi_device *spi,
| ^~~~~~~~~~~~~~~
drivers/spi/spi-imx.c:207:21: warning: 'spi_imx_clkdiv_2' defined but not used [-Wunused-function]
207 | static unsigned int spi_imx_clkdiv_2(unsigned int fin,
| ^~~~~~~~~~~~~~~~
drivers/spi/spi-imx.c:193:21: warning: 'spi_imx_clkdiv_1' defined but not used [-Wunused-function]
193 | static unsigned int spi_imx_clkdiv_1(unsigned int fin,
| ^~~~~~~~~~~~~~~~
drivers/spi/spi-imx.c:165:13: warning: 'spi_imx_buf_tx_u32' defined but not used [-Wunused-function]
165 | static void spi_imx_buf_tx_##type(struct spi_imx_data *spi_imx) \
| ^~~~~~~~~~~~~~~
drivers/spi/spi-imx.c:184:1: note: in expansion of macro 'MXC_SPI_BUF_TX'
184 | MXC_SPI_BUF_TX(u32)
| ^~~~~~~~~~~~~~
drivers/spi/spi-imx.c:152:13: warning: 'spi_imx_buf_rx_u32' defined but not used [-Wunused-function]
152 | static void spi_imx_buf_rx_##type(struct spi_imx_data *spi_imx) \
| ^~~~~~~~~~~~~~~
drivers/spi/spi-imx.c:183:1: note: in expansion of macro 'MXC_SPI_BUF_RX'
183 | MXC_SPI_BUF_RX(u32)
| ^~~~~~~~~~~~~~
drivers/spi/spi-imx.c:165:13: warning: 'spi_imx_buf_tx_u8' defined but not used [-Wunused-function]
165 | static void spi_imx_buf_tx_##type(struct spi_imx_data *spi_imx) \
| ^~~~~~~~~~~~~~~
drivers/spi/spi-imx.c:180:1: note: in expansion of macro 'MXC_SPI_BUF_TX'
180 | MXC_SPI_BUF_TX(u8)
| ^~~~~~~~~~~~~~
drivers/spi/spi-imx.c:152:13: warning: 'spi_imx_buf_rx_u8' defined but not used [-Wunused-function]
152 | static void spi_imx_buf_rx_##type(struct spi_imx_data *spi_imx) \
| ^~~~~~~~~~~~~~~
drivers/spi/spi-imx.c:179:1: note: in expansion of macro 'MXC_SPI_BUF_RX'
179 | MXC_SPI_BUF_RX(u8)
| ^~~~~~~~~~~~~~
cc1: some warnings being treated as errors
vim +/MX51_ECSPI_CONFIG_DATACTL +1956 drivers/spi/spi-imx.c
b5f3294f0be549 drivers/spi/mxc_spi.c Sascha Hauer 2009-09-22 1952
92bad4a4c755cd drivers/spi/spi-imx.c Fabio Estevam 2021-03-16 1953 MODULE_DESCRIPTION("i.MX SPI Controller driver");
b5f3294f0be549 drivers/spi/mxc_spi.c Sascha Hauer 2009-09-22 1954 MODULE_AUTHOR("Sascha Hauer, Pengutronix");
b5f3294f0be549 drivers/spi/mxc_spi.c Sascha Hauer 2009-09-22 1955 MODULE_LICENSE("GPL");
3133fba3bb3a37 drivers/spi/spi-imx.c Fabio Estevam 2013-01-07 @1956 MODULE_ALIAS("platform:" DRIVER_NAME);
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki