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 <sean...@gmail.com> >> Reviewed-by: Simon Glass <s...@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 <s...@denx.de> >> + * Copyright (C) 2020 Sean Anderson <sean...@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 >>