Advertisement
ReuzeLeuk

0001-spi-add-driver-for-bcm2835-bsc.patch

Feb 9th, 2020
357
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 22.35 KB | None | 0 0
  1. From 7661790f85f44433fe368985dced95775ad48b91 Mon Sep 17 00:00:00 2001
  2. From: Jacko Dirks <[email protected]>
  3. Date: Sun, 19 Jan 2020 17:46:27 +0100
  4. Subject: [PATCH] spi: add driver for bcm2835 bsc
  5.  
  6. The BCM2835 contains a Broadcom Serial Device. This device can act as a
  7. SPI slave or an I2C slave. This driver implements the device as an SPI
  8. slave with IRQ support.
  9.  
  10. This commit also includes the necessary changes to the DTS system so
  11. that the driver is included when booting the RPI 4 with the correct
  12. overlay selected. This driver might work on different devices with
  13. different DTS settings, only the Raspberry Pi 4 has been tested at this
  14. point.
  15. ---
  16. arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 10 +
  17. arch/arm/boot/dts/bcm2838.dtsi | 5 +
  18. arch/arm/boot/dts/bcm283x.dtsi | 10 +
  19. arch/arm/boot/dts/overlays/Makefile | 1 +
  20. .../dts/overlays/spislave-1cs-overlay.dts | 44 ++
  21. arch/arm/configs/bcm2711_defconfig | 1 +
  22. drivers/spi/Kconfig | 11 +
  23. drivers/spi/Makefile | 3 +
  24. drivers/spi/spi-bcm2835-slave.c | 502 ++++++++++++++++++
  25. 9 files changed, 587 insertions(+)
  26. create mode 100644 arch/arm/boot/dts/overlays/spislave-1cs-overlay.dts
  27. create mode 100644 drivers/spi/spi-bcm2835-slave.c
  28.  
  29. diff --git a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
  30. index a967a7b86f2c..ebc25d985db9 100644
  31. --- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
  32. +++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts
  33. @@ -209,6 +209,16 @@
  34. brcm,function = <BCM2835_FSEL_GPIO_OUT>;
  35. };
  36.  
  37. + spi_slave_pins: spi_slave_pins {
  38. + brcm,pins = <9 10 11>;
  39. + brcm,function = <BCM2835_FSEL_ALT3>;
  40. + };
  41. +
  42. + spi_slave_cs_pins: spi_slave_cs_pins {
  43. + brcm,pins = <8>;
  44. + brcm,function = <BCM2835_FSEL_GPIO_IN>;
  45. + };
  46. +
  47. i2c0_pins: i2c0 {
  48. brcm,pins = <0 1>;
  49. brcm,function = <BCM2835_FSEL_ALT0>;
  50. diff --git a/arch/arm/boot/dts/bcm2838.dtsi b/arch/arm/boot/dts/bcm2838.dtsi
  51. index 5aef393c09a6..7ed68cbf5824 100644
  52. --- a/arch/arm/boot/dts/bcm2838.dtsi
  53. +++ b/arch/arm/boot/dts/bcm2838.dtsi
  54. @@ -148,6 +148,11 @@
  55. status = "disabled";
  56. };
  57.  
  58. + spi_slave: spi_slave@7e214000 {
  59. + reg = <0x7e214000 0x0200>;
  60. + interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
  61. + };
  62. +
  63. i2c3: i2c@7e205600 {
  64. compatible = "brcm,bcm2835-i2c";
  65. reg = <0x7e205600 0x200>;
  66. diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
  67. index c8eaaf608df5..709e985516d6 100644
  68. --- a/arch/arm/boot/dts/bcm283x.dtsi
  69. +++ b/arch/arm/boot/dts/bcm283x.dtsi
  70. @@ -410,6 +410,16 @@
  71. status = "disabled";
  72. };
  73.  
  74. + spi_slave: spi_slave@7e214000 {
  75. + compatible = "brcm,bcm2835-spi-slave";
  76. + reg = <0x7e214000 0x200>;
  77. + interrupts = <2 11>;
  78. + clocks = <&clocks BCM2835_CLOCK_VPU>;
  79. + #address-cells = <1>;
  80. + #size-cells = <0>;
  81. + status = "disabled";
  82. + };
  83. +
  84. i2c0: i2c@7e205000 {
  85. compatible = "brcm,bcm2835-i2c";
  86. reg = <0x7e205000 0x200>;
  87. diff --git a/arch/arm/boot/dts/overlays/Makefile b/arch/arm/boot/dts/overlays/Makefile
  88. index e5e7183d2cdb..edd76b76eda0 100644
  89. --- a/arch/arm/boot/dts/overlays/Makefile
  90. +++ b/arch/arm/boot/dts/overlays/Makefile
  91. @@ -167,6 +167,7 @@ dtbo-$(CONFIG_ARCH_BCM2835) += \
  92. spi5-2cs.dtbo \
  93. spi6-1cs.dtbo \
  94. spi6-2cs.dtbo \
  95. + spislave-1cs.dtbo \
  96. ssd1306.dtbo \
  97. superaudioboard.dtbo \
  98. sx150x.dtbo \
  99. diff --git a/arch/arm/boot/dts/overlays/spislave-1cs-overlay.dts b/arch/arm/boot/dts/overlays/spislave-1cs-overlay.dts
  100. new file mode 100644
  101. index 000000000000..b4df98215f03
  102. --- /dev/null
  103. +++ b/arch/arm/boot/dts/overlays/spislave-1cs-overlay.dts
  104. @@ -0,0 +1,44 @@
  105. +/dts-v1/;
  106. +/plugin/;
  107. +
  108. +
  109. +/ {
  110. + compatible = "brcm,bcm2711";
  111. +
  112. + fragment@0 {
  113. + target = <&spi_slave_cs_pins>;
  114. + frag0: __overlay__ {
  115. + brcm,pins = <8>;
  116. + brcm,function = <1>; /* output */
  117. + };
  118. + };
  119. +
  120. + fragment@1 {
  121. + target = <&spi_slave>;
  122. + frag1: __overlay__ {
  123. + /* needed to avoid dtc warning */
  124. + #address-cells = <1>;
  125. + #size-cells = <0>;
  126. +
  127. + pinctrl-names = "default";
  128. + pinctrl-0 = <&spi_slave_pins &spi_slave_cs_pins>;
  129. + cs-gpios = <&gpio 8 1>;
  130. + status = "okay";
  131. +
  132. + spidev0_0: slave@0 {
  133. + compatible = "spidev";
  134. + reg = <0>; /* CE0 */
  135. + #address-cells = <1>;
  136. + #size-cells = <0>;
  137. + spi-max-frequency = <125000000>;
  138. + status = "okay";
  139. + };
  140. + };
  141. + };
  142. +
  143. + __overrides__ {
  144. + cs0_pin = <&frag0>,"brcm,pins:0",
  145. + <&frag1>,"cs-gpios:4";
  146. + cs0_spidev = <&spidev0_0>,"status";
  147. + };
  148. +};
  149. diff --git a/arch/arm/configs/bcm2711_defconfig b/arch/arm/configs/bcm2711_defconfig
  150. index ea4c5ccde850..7784da699f19 100644
  151. --- a/arch/arm/configs/bcm2711_defconfig
  152. +++ b/arch/arm/configs/bcm2711_defconfig
  153. @@ -694,6 +694,7 @@ CONFIG_I2C_TINY_USB=m
  154. CONFIG_SPI=y
  155. CONFIG_SPI_BCM2835=m
  156. CONFIG_SPI_BCM2835AUX=m
  157. +CONFIG_SPI_BCM2835_BSC=m
  158. CONFIG_SPI_GPIO=m
  159. CONFIG_SPI_SPIDEV=m
  160. CONFIG_SPI_SLAVE=y
  161. diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
  162. index 671d078349cc..7fd3563e36d7 100644
  163. --- a/drivers/spi/Kconfig
  164. +++ b/drivers/spi/Kconfig
  165. @@ -815,6 +815,17 @@ config SPI_SLAVE_SYSTEM_CONTROL
  166. SPI slave handler to allow remote control of system reboot, power
  167. off, halt, and suspend.
  168.  
  169. +config SPI_BCM2835_SLAVE
  170. + tristate "BCM2835 SLAVE SPI controller"
  171. + depends on GPIOLIB
  172. + depends on ARCH_BCM2835 || COMPILE_TEST
  173. + help
  174. + This selects a driver for the Broadcom BCM2835 BSC SPI slave.
  175. +
  176. + The BCM2835 contains a Broadcom Serial Controller or BSC.
  177. + The BSC can be used as an SPI slave or an I2C slave.
  178. + This driver uses the BSC as an SPI slave.
  179. +
  180. endif # SPI_SLAVE
  181.  
  182. endif # SPI
  183. diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
  184. index a90d55970036..76c05023a80f 100644
  185. --- a/drivers/spi/Makefile
  186. +++ b/drivers/spi/Makefile
  187. @@ -111,3 +111,6 @@ obj-$(CONFIG_SPI_ZYNQMP_GQSPI) += spi-zynqmp-gqspi.o
  188. # SPI slave protocol handlers
  189. obj-$(CONFIG_SPI_SLAVE_TIME) += spi-slave-time.o
  190. obj-$(CONFIG_SPI_SLAVE_SYSTEM_CONTROL) += spi-slave-system-control.o
  191. +
  192. +# SPI slave controller drivers
  193. +obj-$(CONFIG_SPI_BCM2835_SLAVE) += spi-bcm2835-slave.o
  194. diff --git a/drivers/spi/spi-bcm2835-slave.c b/drivers/spi/spi-bcm2835-slave.c
  195. new file mode 100644
  196. index 000000000000..6162b4c7827c
  197. --- /dev/null
  198. +++ b/drivers/spi/spi-bcm2835-slave.c
  199. @@ -0,0 +1,502 @@
  200. +// SPDX-License-Identifier: GPL-2.0+
  201. +/*
  202. + * Driver for Broadcom BCM2835 BSC SPI slave Controller
  203. + *
  204. + * This device (BCM2835 BSC) is usable as an SPI and an I2C slave, therefore
  205. + * some registers are not used. The BSC does not support DMA.
  206. + *
  207. + * Copyright (C) 2020 Jacko Dirks
  208. + *
  209. + * This driver is inspired by:
  210. + * spi-bcm2835.c, Copyright (C) 2012 Chris Boot et al
  211. + * spi-sh-msiof.c, Copyright (c) 2009 Magnus Damm et al
  212. + *
  213. + * This program is free software; you can redistribute it and/or modify
  214. + * it under the terms of the GNU General Public License as published by
  215. + * the Free Software Foundation; either version 2 of the License, or
  216. + * (at your option) any later version.
  217. + *
  218. + * This program is distributed in the hope that it will be useful,
  219. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  220. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  221. + * GNU General Public License for more details.
  222. + */
  223. +
  224. +
  225. +/**
  226. + * TODO:
  227. + * - implement chip select
  228. + * Currently, we are acting as if the slave is always selected.
  229. + */
  230. +#include <linux/module.h>
  231. +#include <linux/completion.h>
  232. +#include <linux/of.h>
  233. +#include <linux/of_address.h>
  234. +#include <linux/of_device.h>
  235. +#include <linux/of_gpio.h>
  236. +#include <linux/of_irq.h>
  237. +#include <linux/spi/spi.h>
  238. +
  239. +/* BSC Register offsets */
  240. +#define BSC_DR 0x0
  241. +#define BSC_RSR 0x4
  242. +#define BSC_SLV 0x8
  243. +#define BSC_CR 0xc
  244. +#define BSC_FR 0x10
  245. +#define BSC_IFLS 0x14
  246. +#define BSC_IMSC 0x18
  247. +#define BSC_RIS 0x1c
  248. +#define BSC_MIS 0x20
  249. +#define BSC_ICR 0x24
  250. +#define BSC_DMACR 0x28
  251. +#define BSC_TDR 0x2c
  252. +#define BSC_GPUSTAT 0x30
  253. +#define BSC_HCTRL 0x34
  254. +#define BSC_DEBUG1 0x38
  255. +#define BSC_DEBUG2 0x4c
  256. +
  257. +/* CR register fields, only those relevant to SPI */
  258. +#define BSC_CR_INV_TXF 0x2000
  259. +#define BSC_CR_TESTFIFO 0x0800
  260. +#define BSC_CR_INV_RXF 0x0400
  261. +#define BSC_CR_RXE 0x0200
  262. +#define BSC_CR_TXE 0x0100
  263. +#define BSC_CR_BRK 0x0080
  264. +#define BSC_CR_CPOL 0x0010
  265. +#define BSC_CR_CPHA 0x0008
  266. +#define BSC_CR_I2C 0x0004
  267. +#define BSC_CR_SPI 0x0002
  268. +#define BSC_CR_EN 0x0001
  269. +
  270. +/* DR register fields, only those relevant to SPI */
  271. +#define BSC_DR_RXBUSY 0x200000
  272. +#define BSC_DR_TXFE 0x100000
  273. +#define BSC_DR_RXFF 0x080000
  274. +#define BSC_DR_TXFF 0x040000
  275. +#define BSC_DR_RXFE 0x020000
  276. +#define BSC_DR_TXBUSY 0x010000
  277. +#define BSC_DR_UE 0x000200
  278. +#define BSC_DR_OE 0x000100
  279. +
  280. +/* FR register fields */
  281. +#define BSC_FR_RXBUSY 0x20
  282. +#define BSC_FR_TXFE 0x10
  283. +#define BSC_FR_RXFF 0x08
  284. +#define BSC_FR_TXFF 0x04
  285. +#define BSC_FR_RXFE 0x02
  286. +#define BSC_FR_TXBUSY 0x01
  287. +
  288. +/* IMSC register_fields */
  289. +#define BSC_IMSC_OEIM 0x8
  290. +#define BSC_IMSC_BEIM 0x4
  291. +#define BSC_IMSC_TXIM 0x2
  292. +#define BSC_IMSC_RXIM 0x1
  293. +
  294. +/* ICR register fields */
  295. +#define BSC_ICR_OEIC 0x8
  296. +#define BSC_ICR_BEIC 0x4
  297. +#define BSC_ICR_TXIC 0x2
  298. +#define BSC_ICR_RXIC 0x1
  299. +
  300. +/* RIS register fields */
  301. +#define BSC_RIS_OERIS 0x8
  302. +#define BSC_RIS_BERIS 0x4
  303. +#define BSC_RIS_TXRIS 0x2
  304. +#define BSC_RIS_RXRIS 0x1
  305. +
  306. +/* IFLS TXIFLSEL FIFO level select */
  307. +#define BSC_IFLS_TXIFLSEL_ONE_EIGHTH 0x0
  308. +#define BSC_IFLS_TXIFLSEL_ONE_FOURTH 0x1
  309. +#define BSC_IFLS_TXIFLSEL_ONE_HALF 0x2
  310. +#define BSC_IFLS_TXIFLSEL_THREE_FOURTH 0x3
  311. +#define BSC_IFLS_TXIFLSEL_SEVEN_EIGHTHS 0x4
  312. +
  313. +#define DRV_NAME "spi-bcm2835-slave"
  314. +#define BCM2835_BSC_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_NO_CS)
  315. +
  316. +struct bcm2835_slave_spi {
  317. + void __iomem *regs;
  318. + int irq;
  319. + const uint8_t *tx_buf;
  320. + uint8_t *rx_buf;
  321. + int tx_len;
  322. + int rx_len;
  323. +};
  324. +
  325. +static uint32_t bcm2835_slave_read(struct bcm2835_slave_spi *bs, unsigned reg)
  326. +{
  327. + return readl(bs->regs + reg);
  328. +}
  329. +
  330. +static void bcm2835_slave_write(struct bcm2835_slave_spi *bs, unsigned reg, uint32_t val)
  331. +{
  332. + writel(val, bs->regs + reg);
  333. +}
  334. +
  335. +static void bcm2835_slave_fifo_write(struct bcm2835_slave_spi *bs)
  336. +{
  337. + uint8_t byte;
  338. + // While we expect bytes and the tx buffer is not full.
  339. + while (bs->tx_len > 0 && !(bcm2835_slave_read(bs, BSC_FR) & BSC_FR_TXFF) ) {
  340. + byte = bs->tx_buf ? *bs->tx_buf : 0;
  341. + bs->tx_buf++;
  342. + bs->tx_len--;
  343. + bcm2835_slave_write(bs, BSC_DR, byte);
  344. + }
  345. +}
  346. +
  347. +static void bcm2835_slave_fifo_read(struct bcm2835_slave_spi *bs)
  348. +{
  349. + uint8_t byte;
  350. + // While we expect bytes and the rx buffer is not empty.
  351. + while (bs->rx_len > 0 && !(bcm2835_slave_read(bs, BSC_FR) & BSC_FR_RXFE)) {
  352. + byte = bcm2835_slave_read(bs, BSC_DR) & 0xff;
  353. + if (bs->rx_buf) {
  354. + *bs->rx_buf = byte;
  355. + bs->rx_buf++;
  356. + }
  357. + bs->rx_len--;
  358. + }
  359. +}
  360. +
  361. +static int bcm2835_slave_validate(struct spi_device *spi)
  362. +{
  363. + uint16_t mode = spi->mode;
  364. + // 3 wire mode is not supported
  365. + if (mode & SPI_3WIRE)
  366. + return -EINVAL;
  367. + // Loop is not supported
  368. + if (mode & SPI_LOOP)
  369. + return -EINVAL;
  370. + return 0;
  371. +}
  372. +
  373. +static int bcm2835_test(struct bcm2835_slave_spi *bs, struct device *dev)
  374. +{
  375. + unsigned i, j;
  376. + // Test wether or not the BSC actually functions
  377. + // TODO remove in the future
  378. + bcm2835_slave_write(bs, BSC_SLV, 0);
  379. + bcm2835_slave_write(bs, BSC_DEBUG2, 0x400000);
  380. + bcm2835_slave_write(bs, BSC_ICR,
  381. + BSC_ICR_OEIC | BSC_ICR_BEIC | BSC_ICR_TXIC | BSC_ICR_RXIC);
  382. + uint32_t fr = bcm2835_slave_read(bs, BSC_FR);
  383. + printk("_TEST_INITIAL: 0x%X\n", fr);
  384. + printk("_TEST_INITIAL: RXFLEVEL 0x%X\n", (fr & 0xf800) >> 11);
  385. + printk("_TEST_INITIAL: TXLEVEL 0x%X\n", (fr & 0x7e0) >> 6);
  386. + printk("_TEST_INITIAL: RXBUSY: 0x%X\n", (fr & BSC_FR_RXBUSY));
  387. + printk("_TEST_INITIAL: TXFE: 0x%X\n", (fr & BSC_FR_TXFE));
  388. + printk("_TEST_INITIAL: RXFF: 0x%X\n", (fr & BSC_FR_RXFF));
  389. + printk("_TEST_INITIAL: TXFF: 0x%X\n", (fr & BSC_FR_TXFF));
  390. + printk("_TEST_INITIAL: RXFE: 0x%X\n", (fr & BSC_FR_RXFE));
  391. + printk("_TEST_INITIAL: TXBUSY: 0x%X\n", (fr & BSC_FR_TXBUSY));
  392. + printk("_TEST_INITIAL: RSR: 0x%x\n", bcm2835_slave_read(bs,BSC_RSR));
  393. + printk("_TEST_INITIAL: RIS: 0x%x\n", bcm2835_slave_read(bs,BSC_RIS));
  394. + printk("_TEST_INITIAL: IMSC: 0x%x\n", bcm2835_slave_read(bs,BSC_IMSC));
  395. + printk("_TEST_INITIAL: DEBUG1: 0x%x\n", bcm2835_slave_read(bs,BSC_DEBUG1));
  396. + printk("_TEST_INITIAL: DEBUG2: 0x%x\n", bcm2835_slave_read(bs,BSC_DEBUG2));
  397. + for (i = 0; i <= 0; ++i) {
  398. + bcm2835_slave_write(bs, BSC_DR, i & 0xff);
  399. + uint32_t fr = bcm2835_slave_read(bs, BSC_FR);
  400. + printk("_TEST: 0x%X\n", fr);
  401. + printk("_TEST: RXFLEVEL 0x%X\n", (fr & 0xf800) >> 11);
  402. + printk("_TEST: TXLEVEL 0x%X\n", (fr & 0x7e0) >> 6);
  403. + printk("_TEST: RXBUSY: 0x%X\n", (fr & BSC_FR_RXBUSY));
  404. + printk("_TEST: TXFE: 0x%X\n", (fr & BSC_FR_TXFE));
  405. + printk("_TEST: RXFF: 0x%X\n", (fr & BSC_FR_RXFF));
  406. + printk("_TEST: TXFF: 0x%X\n", (fr & BSC_FR_TXFF));
  407. + printk("_TEST: RXFE: 0x%X\n", (fr & BSC_FR_RXFE));
  408. + printk("_TEST: TXBUSY: 0x%X\n", (fr & BSC_FR_TXBUSY));
  409. + printk("_TEST: RSR: 0x%x\n", bcm2835_slave_read(bs,BSC_RSR));
  410. + printk("_TEST: RIS: 0x%x\n", bcm2835_slave_read(bs,BSC_RIS));
  411. + printk("_TEST: IMSC: 0x%x\n", bcm2835_slave_read(bs,BSC_IMSC));
  412. + printk("_TEST: DEBUG1: 0x%x\n", bcm2835_slave_read(bs,BSC_DEBUG1));
  413. + printk("_TEST: DEBUG2: 0x%x\n", bcm2835_slave_read(bs,BSC_DEBUG2));
  414. + j = bcm2835_slave_read(bs, BSC_TDR) & 0xff;
  415. + if (i != j) {
  416. + dev_err(dev,
  417. + "Device test failed (TX). Expected: %u, but got: %u\n",
  418. + i, j);
  419. + return -1;
  420. + }
  421. + }
  422. + for (i = 0; i <= 255; ++i) {
  423. + bcm2835_slave_write(bs, BSC_TDR, i & 0xff);
  424. + j = bcm2835_slave_read(bs, BSC_DR) & 0xff;
  425. + if (i != j) {
  426. + dev_err(dev,
  427. + "Device test failed (RX). Expected: %u, but got: %u\n",
  428. + i, j);
  429. + return -1;
  430. + }
  431. + }
  432. + return 0;
  433. +}
  434. +
  435. +static void bcm2835_slave_reset(struct bcm2835_slave_spi *bs)
  436. +{
  437. + uint32_t dr;
  438. + uint32_t cr = bcm2835_slave_read(bs, BSC_CR);
  439. + cr &= ~BSC_CR_SPI;
  440. + cr |= BSC_CR_BRK;
  441. + bcm2835_slave_write(bs, BSC_CR, 0);
  442. + bcm2835_slave_write(bs, BSC_IMSC, 0);
  443. + bcm2835_slave_write(bs, BSC_ICR,
  444. + BSC_ICR_OEIC | BSC_ICR_BEIC | BSC_ICR_TXIC | BSC_ICR_RXIC);
  445. + bcm2835_slave_write(bs, BSC_RSR, 0);
  446. + bcm2835_slave_write(bs, BSC_CR, cr);
  447. +}
  448. +
  449. +
  450. +static int bcm2835_slave_spi_setup(struct spi_device *spi)
  451. +{
  452. + int err;
  453. + err = bcm2835_slave_validate(spi);
  454. + if (err < 0)
  455. + return err;
  456. + // TODO
  457. + // There could be some stuff with CS, but we ignore that for now
  458. + return 0;
  459. +}
  460. +
  461. +static void bcm2835_slave_spi_set_cs(struct spi_device *spi, bool gpio_level)
  462. +{
  463. + // TODO
  464. +}
  465. +
  466. +static irqreturn_t bcm2835_slave_spi_interrupt(int irq, void *dev_id)
  467. +{
  468. + // TODO some interrupts might come from errors.
  469. + struct spi_controller *slave = dev_id;
  470. + struct bcm2835_slave_spi *bs = spi_controller_get_devdata(slave);
  471. + // Check if we enabled this interrupt
  472. + if (!bcm2835_slave_read(bs, BSC_IMSC))
  473. + return IRQ_NONE;
  474. + // Clear interrupt
  475. + bcm2835_slave_write(bs, BSC_ICR,
  476. + BSC_ICR_OEIC | BSC_ICR_BEIC | BSC_ICR_TXIC | BSC_ICR_RXIC);
  477. + // Read and write bytes
  478. + bcm2835_slave_fifo_read(bs);
  479. + bcm2835_slave_fifo_write(bs);
  480. + if (bs->rx_len <= 0) {
  481. + // Transaction finished.
  482. + bcm2835_slave_reset(bs);
  483. + complete(&slave->xfer_completion);
  484. + }
  485. + return IRQ_HANDLED;
  486. +}
  487. +
  488. +static int bcm2835_slave_spi_transfer_one(struct spi_controller *slave,
  489. + struct spi_device *spi, struct spi_transfer *tfr)
  490. +{
  491. + struct bcm2835_slave_spi *bs = spi_controller_get_devdata(slave);
  492. + uint32_t cr, dr;
  493. + int err = bcm2835_slave_validate(spi);
  494. + if (err < 0)
  495. + return err;
  496. + // We are a slave and there is no DMA support,
  497. + // this means that IRQ based transactions are the only viable option.
  498. + // Polling is not an option because we cannot know when the clock runs,
  499. + // so we cannot estimate when the transfer will be finished.
  500. +
  501. + // Set the buffers and lengths
  502. + bs->tx_buf = tfr->tx_buf;
  503. + bs->rx_buf = tfr->rx_buf;
  504. + bs->tx_len = tfr->len;
  505. + bs->rx_len = tfr->len;
  506. + // Fill the TX buffer
  507. + bcm2835_slave_fifo_write(bs);
  508. + printk("_T1: transfer_one");
  509. + uint32_t fr = bcm2835_slave_read(bs, BSC_FR);
  510. + printk("_T1: 0x%X\n", fr);
  511. + printk("_T1: RXFLEVEL 0x%X\n", (fr & 0xf800) >> 11);
  512. + printk("_T1: TXLEVEL 0x%X\n", (fr & 0x7e0) >> 6);
  513. + printk("_T1: RXBUSY: 0x%X\n", (fr & BSC_FR_RXBUSY));
  514. + printk("_T1: TXFE: 0x%X\n", (fr & BSC_FR_TXFE));
  515. + printk("_T1: RXFF: 0x%X\n", (fr & BSC_FR_RXFF));
  516. + printk("_T1: TXFF: 0x%X\n", (fr & BSC_FR_TXFF));
  517. + printk("_T1: RXFE: 0x%X\n", (fr & BSC_FR_RXFE));
  518. + printk("_T1: TXBUSY: 0x%X\n", (fr & BSC_FR_TXBUSY));
  519. + // Start running in interrupt mode.
  520. + // TODO do not interrupt after every byte (I suppose?)
  521. + // Reset underrun or overrun errors
  522. + bcm2835_slave_write(bs, BSC_RSR, 0);
  523. + cr = bcm2835_slave_read(bs, BSC_CR);
  524. + cr &= ~BSC_CR_BRK;
  525. + cr |= (BSC_CR_SPI);
  526. + bcm2835_slave_write(bs, BSC_IFLS, BSC_IFLS_TXIFLSEL_ONE_EIGHTH);
  527. + bcm2835_slave_write(bs, BSC_IMSC, BSC_IMSC_RXIM);
  528. + bcm2835_slave_write(bs, BSC_CR, cr);
  529. +
  530. + // Return one to signal that the transfer is not yet complete.
  531. + return 1;
  532. +}
  533. +
  534. +static void bcm2835_slave_spi_handle_err(struct spi_controller *master,
  535. + struct spi_message *msg)
  536. +{
  537. + // TODO
  538. +}
  539. +
  540. +static int bcm2835_slave_spi_slave_abort(struct spi_controller *slave)
  541. +{
  542. + struct bcm2835_slave_spi *bs = spi_controller_get_devdata(slave);
  543. + printk("_S_ABORT: transfer_one");
  544. + uint32_t fr = bcm2835_slave_read(bs, BSC_FR);
  545. + printk("_S_ABORT: 0x%X\n", fr);
  546. + printk("_S_ABORT: RXFLEVEL 0x%X\n", (fr & 0xf800) >> 11);
  547. + printk("_S_ABORT: TXLEVEL 0x%X\n", (fr & 0x7e0) >> 6);
  548. + printk("_S_ABORT: RXBUSY: 0x%X\n", (fr & BSC_FR_RXBUSY));
  549. + printk("_S_ABORT: TXFE: 0x%X\n", (fr & BSC_FR_TXFE));
  550. + printk("_S_ABORT: RXFF: 0x%X\n", (fr & BSC_FR_RXFF));
  551. + printk("_S_ABORT: TXFF: 0x%X\n", (fr & BSC_FR_TXFF));
  552. + printk("_S_ABORT: RXFE: 0x%X\n", (fr & BSC_FR_RXFE));
  553. + printk("_S_ABORT: TXBUSY: 0x%X\n", (fr & BSC_FR_TXBUSY));
  554. + bcm2835_slave_reset(bs);
  555. + return 0;
  556. +}
  557. +
  558. +static int bcm2835_slave_spi_prepare_message(struct spi_controller *slave,
  559. + struct spi_message *msg)
  560. +{
  561. +
  562. + uint32_t cr;
  563. + struct spi_device *spi = msg->spi;
  564. + struct bcm2835_slave_spi *bs = spi_controller_get_devdata(slave);
  565. + int err = bcm2835_slave_validate(spi);
  566. + if (err < 0)
  567. + return err;
  568. + cr = bcm2835_slave_read(bs, BSC_CR);
  569. + cr &= ~(BSC_CR_CPHA | BSC_CR_CPOL);
  570. +
  571. + if (spi->mode & SPI_CPOL)
  572. + cr |= BSC_CR_CPOL;
  573. + if (spi->mode & SPI_CPHA)
  574. + cr |= BSC_CR_CPHA;
  575. + bcm2835_slave_write(bs, BSC_CR, cr);
  576. + return 0;
  577. +}
  578. +
  579. +
  580. +static int bcm2835_slave_spi_probe(struct platform_device *pdev)
  581. +{
  582. + struct spi_controller *slave;
  583. + struct bcm2835_slave_spi *bs;
  584. + struct resource *res;
  585. + int err;
  586. + uint32_t cr;
  587. +
  588. + slave = spi_alloc_slave(&pdev->dev, sizeof(*bs));
  589. + if (!slave) {
  590. + dev_err(&pdev->dev,
  591. + "spi_alloc_slave() failed (is your kernel compiled with CONFIG_SPI_SLAVE?)\n");
  592. + return -ENOMEM;
  593. + }
  594. + platform_set_drvdata(pdev, slave);
  595. +
  596. + bs = spi_controller_get_devdata(slave);
  597. +
  598. + slave->dev.of_node = pdev->dev.of_node;
  599. + slave->mode_bits = BCM2835_BSC_MODE_BITS;
  600. + slave->bits_per_word_mask = SPI_BPW_MASK(8);
  601. + slave->setup = bcm2835_slave_spi_setup;
  602. + slave->set_cs = bcm2835_slave_spi_set_cs;
  603. + slave->transfer_one = bcm2835_slave_spi_transfer_one;
  604. + slave->prepare_message = bcm2835_slave_spi_prepare_message;
  605. + slave->handle_err = bcm2835_slave_spi_handle_err;
  606. + slave->slave_abort = bcm2835_slave_spi_slave_abort;
  607. + slave->num_chipselect = 1;
  608. +
  609. + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  610. + bs->regs = devm_ioremap_resource(&pdev->dev, res);
  611. + if (IS_ERR(bs->regs)) {
  612. + err = PTR_ERR(bs->regs);
  613. + goto out_err;
  614. + }
  615. +
  616. + bs->irq = platform_get_irq(pdev, 0);
  617. + if (bs->irq <= 0) {
  618. + dev_err(&pdev->dev, "could not get IRQ: %d\n", bs->irq);
  619. + err = bs->irq ? bs->irq : -ENODEV;
  620. + goto out_err;
  621. + }
  622. + cr = BSC_CR_EN|BSC_CR_SPI|BSC_CR_RXE|BSC_CR_TXE;
  623. + // reset
  624. + bcm2835_slave_write(bs, BSC_CR, 0);
  625. + // set the default CR
  626. + //bcm2835_slave_write(bs, BSC_CR, cr|BSC_CR_TESTFIFO);
  627. + // Sanity test the slave
  628. + //if (bcm2835_test(bs, &pdev->dev) < 0) {
  629. + // err = -EIO;
  630. + // goto out_err;
  631. + //}
  632. + // Clear interrupts and masks
  633. + bcm2835_slave_write(bs, BSC_IMSC, 0);
  634. + bcm2835_slave_write(bs, BSC_ICR,
  635. + BSC_ICR_OEIC | BSC_ICR_BEIC | BSC_ICR_TXIC | BSC_ICR_RXIC);
  636. + // Reinitialize with TESTFIFO disabled
  637. + bcm2835_slave_write(bs, BSC_CR, cr);
  638. + // Reset underrun or overrun errors
  639. + bcm2835_slave_write(bs, BSC_RSR, 0);
  640. +
  641. + uint32_t fr = bcm2835_slave_read(bs, BSC_FR);
  642. + printk("_INIT: 0x%X\n", fr);
  643. + printk("_INIT: RXFLEVEL 0x%X\n", (fr & 0xf800) >> 11);
  644. + printk("_INIT: TXLEVEL 0x%X\n", (fr & 0x7e0) >> 6);
  645. + printk("_INIT: RXBUSY: 0x%X\n", (fr & BSC_FR_RXBUSY));
  646. + printk("_INIT: TXFE: 0x%X\n", (fr & BSC_FR_TXFE));
  647. + printk("_INIT: RXFF: 0x%X\n", (fr & BSC_FR_RXFF));
  648. + printk("_INIT: TXFF: 0x%X\n", (fr & BSC_FR_TXFF));
  649. + printk("_INIT: RXFE: 0x%X\n", (fr & BSC_FR_RXFE));
  650. + printk("_INIT: TXBUSY: 0x%X\n", (fr & BSC_FR_TXBUSY));
  651. +
  652. + // Request the SPI BSC IRQ
  653. + err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_slave_spi_interrupt,
  654. + IRQF_SHARED,
  655. + dev_name(&pdev->dev), slave);
  656. + if (err) {
  657. + dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
  658. + goto out_err;
  659. + }
  660. +
  661. + err = devm_spi_register_controller(&pdev->dev, slave);
  662. + if (err) {
  663. + dev_err(&pdev->dev, "could not register SPI slave: %d\n", err);
  664. + goto out_err;
  665. + }
  666. +
  667. + return 0;
  668. +
  669. +out_err:
  670. + spi_controller_put(slave);
  671. + return err;
  672. +}
  673. +
  674. +static int bcm2835_slave_spi_remove(struct platform_device *pdev)
  675. +{
  676. + //struct spi_controller *slave = platform_get_drvdata(pdev);
  677. + //struct bcm2835_slave_spi *bs = spi_controller_get_devdata(master);
  678. + //TODO
  679. + return 0;
  680. +}
  681. +
  682. +static const struct of_device_id bcm2835_slave_spi_match[] = {
  683. + { .compatible = "brcm,bcm2835-spi-slave", },
  684. + {}
  685. +};
  686. +
  687. +MODULE_DEVICE_TABLE(of, bcm2835_slave_spi_match);
  688. +
  689. +static struct platform_driver bcm2835_slave_spi_driver = {
  690. + .driver = {
  691. + .name = DRV_NAME,
  692. + .of_match_table = bcm2835_slave_spi_match,
  693. + },
  694. + .probe = bcm2835_slave_spi_probe,
  695. + .remove = bcm2835_slave_spi_remove,
  696. +};
  697. +module_platform_driver(bcm2835_slave_spi_driver);
  698. +
  699. +MODULE_DESCRIPTION("SPI slave controller driver for Broadcom BCM2835 BSC");
  700. +MODULE_AUTHOR("Jacko Dirks <[email protected]>");
  701. +MODULE_LICENSE("GPL v2");
  702. --
  703. 2.25.0
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement