
On 3/4/20 1:15 AM, Rick Chen wrote:
Hi Sean
Some devices have different layouts for the fields in CTRL1 (e.g. the
Still not fix this typo in commit message CTRL1 -> CTRL0
Thanks, Rick
Ah, whoops. I think I fixed it, the forgot I had done so, and changed it again. Hopefully I can get this straight.
--Sean
Kendryte K210). Allow this layout to be configurable from the device tree. The documentation has been taken from Linux.
Signed-off-by: Sean Anderson seanga2@gmail.com Reviewed-by: Simon Glass sjg@chromium.org
Changes in v4:
- New
.../spi/snps,dw-apb-ssi.txt | 43 +++++++++++++++++++ drivers/spi/designware_spi.c | 40 ++++++++++------- 2 files changed, 68 insertions(+), 15 deletions(-) create mode 100644 doc/device-tree-bindings/spi/snps,dw-apb-ssi.txt
diff --git a/doc/device-tree-bindings/spi/snps,dw-apb-ssi.txt b/doc/device-tree-bindings/spi/snps,dw-apb-ssi.txt new file mode 100644 index 0000000000..4b6152f6b7 --- /dev/null +++ b/doc/device-tree-bindings/spi/snps,dw-apb-ssi.txt @@ -0,0 +1,43 @@ +Synopsys DesignWare AMBA 2.0 Synchronous Serial Interface.
+Required properties: +- compatible : "snps,dw-apb-ssi" +- reg : The register base for the controller. For "mscc,<soc>-spi", a second
- register set is required (named ICPU_CFG:SPI_MST)
+- #address-cells : <1>, as required by generic SPI binding. +- #size-cells : <0>, also as required by generic SPI binding. +- clocks : phandles for the clocks, see the description of clock-names below.
- The phandle for the "ssi_clk" is required. The phandle for the "pclk" clock
- is optional. If a single clock is specified but no clock-name, it is the
- "ssi_clk" clock. If both clocks are listed, the "ssi_clk" must be first.
+Optional properties: +- clock-names : Contains the names of the clocks:
- "ssi_clk", for the core clock used to generate the external SPI clock.
- "pclk", the interface clock, required for register access.
+- cs-gpios : Specifies the gpio pins to be used for chipselects. +- num-cs : The number of chipselects. If omitted, this will default to 4. +- reg-io-width : The I/O register width (in bytes) implemented by this
- device. Supported values are 2 or 4 (the default).
+- snps,dfs-offset The offset in bits of the DFS field in CTRL0, defaulting to 0 +- snps,frf-offset The offset in bits of the FRF field in CTRL0, defaulting to 4 +- snps,tmod-offset The offset in bits of the tmode field in CTRL0, defaulting
- to 6
+- snps,mode-offset The offset in bits of the work mode field in CTRL0,
- defaulting to 8
+Child nodes as per the generic SPI binding.
+Example:
spi@fff00000 {
compatible = "snps,dw-apb-ssi";
reg = <0xfff00000 0x1000>;
interrupts = <0 154 4>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&spi_m_clk>;
num-cs = <2>;
cs-gpios = <&gpio0 13 0>,
<&gpio0 14 0>;
};
diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c index 2dc16736a3..6e1c289297 100644 --- a/drivers/spi/designware_spi.c +++ b/drivers/spi/designware_spi.c @@ -3,6 +3,7 @@
- Designware master SPI core controller driver
- Copyright (C) 2014 Stefan Roese sr@denx.de
- Copyright (C) 2020 Sean Anderson seanga2@gmail.com
- Very loosely based on the Linux driver:
- drivers/spi/spi-dw.c, which is:
@@ -51,20 +52,14 @@ #define DW_SPI_DR 0x60
/* Bit fields in CTRLR0 */ -#define SPI_DFS_OFFSET 0
-#define SPI_FRF_OFFSET 4 #define SPI_FRF_SPI 0x0 #define SPI_FRF_SSP 0x1 #define SPI_FRF_MICROWIRE 0x2 #define SPI_FRF_RESV 0x3
-#define SPI_MODE_OFFSET 6 -#define SPI_SCPH_OFFSET 6 -#define SPI_SCOL_OFFSET 7 +#define SPI_MODE_SCPH 0x1 +#define SPI_MODE_SCOL 0x2
-#define SPI_TMOD_OFFSET 8 -#define SPI_TMOD_MASK (0x3 << SPI_TMOD_OFFSET) #define SPI_TMOD_TR 0x0 /* xmit & recv */ #define SPI_TMOD_TO 0x1 /* xmit only */ #define SPI_TMOD_RO 0x2 /* recv only */ @@ -89,6 +84,12 @@ struct dw_spi_platdata { s32 frequency; /* Default clock frequency, -1 for none */ void __iomem *regs;
/* Offsets in CTRL0 */
u8 dfs_off;
u8 frf_off;
u8 tmod_off;
u8 mode_off;
};
struct dw_spi_priv { @@ -115,6 +116,15 @@ struct dw_spi_priv { struct reset_ctl_bulk resets; };
+static inline u32 GEN_CTRL0(struct dw_spi_priv *priv,
struct dw_spi_platdata *plat)
+{
return ((priv->bits_per_word - 1) << plat->dfs_off |
(priv->type << plat->frf_off) |
(priv->mode << plat->mode_off) |
(priv->tmode << plat->tmod_off));
+}
static inline u32 dw_read(struct dw_spi_priv *priv, u32 offset) { return __raw_readl(priv->regs + offset); @@ -160,6 +170,10 @@ static int dw_spi_ofdata_to_platdata(struct udevice *bus) /* Use 500KHz as a suitable default */ plat->frequency = dev_read_u32_default(bus, "spi-max-frequency", 500000);
plat->dfs_off = dev_read_u32_default(bus, "snps,dfs-offset", 0);
plat->frf_off = dev_read_u32_default(bus, "snps,frf-offset", 4);
plat->mode_off = dev_read_u32_default(bus, "snps,mode-offset", 6);
plat->tmod_off = dev_read_u32_default(bus, "snps,tmod-offset", 8); debug("%s: regs=%p max-frequency=%d\n", __func__, plat->regs, plat->frequency);
@@ -388,6 +402,7 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { struct udevice *bus = dev->parent;
struct dw_spi_platdata *plat = dev_get_platdata(bus); struct dw_spi_priv *priv = dev_get_priv(bus); const u8 *tx = dout; u8 *rx = din;
@@ -406,10 +421,6 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen, if (flags & SPI_XFER_BEGIN) external_cs_manage(dev, false);
cr0 = (priv->bits_per_word - 1) | (priv->type << SPI_FRF_OFFSET) |
(priv->mode << SPI_MODE_OFFSET) |
(priv->tmode << SPI_TMOD_OFFSET);
if (rx && tx) priv->tmode = SPI_TMOD_TR; else if (rx)
@@ -421,8 +432,7 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen, */ priv->tmode = SPI_TMOD_TR;
cr0 &= ~SPI_TMOD_MASK;
cr0 |= (priv->tmode << SPI_TMOD_OFFSET);
cr0 = GEN_CTRL0(priv, plat); priv->len = bitlen >> 3; debug("%s: rx=%p tx=%p len=%d [bytes]\n", __func__, rx, tx, priv->len);
@@ -476,7 +486,7 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen,
static int dw_spi_set_speed(struct udevice *bus, uint speed) {
struct dw_spi_platdata *plat = bus->platdata;
struct dw_spi_platdata *plat = dev_get_platdata(bus); struct dw_spi_priv *priv = dev_get_priv(bus); u16 clk_div;
-- 2.25.0