SPI (multiple) chipselect(s) CS? i.mx23, 3.12 kernel

Started by olinuxino0000, December 12, 2013, 03:44:18 PM

Previous topic - Next topic

olinuxino0000

Has anyone SPI via /dev/spixxx with (multiple) chip selects working on iMX23 using a kernel 3.12 or knows how this is done 'correctly'?

.the. manual 'i.MX233 product datasheet' (IMX23RM.pdf) on p.1016 seems to suggest that SSP block can handle SSn0, SSn1, SSn2, so 3 lines.


Relevant file is imx-olinuxino.dts (includes imx23.dtsi), in (inux-stable/arch/arm/boot/dts/)
from which the below suggests at least one CS pin is there:

ssp1: ssp@80034000 {
            #address-cells = <1>;
            #size-cells = <0>;
            compatible = "fsl,imx23-spi";
            pinctrl-names = "default";
            pinctrl-0 = <&spi2_pins_a>;
...


and (in imx23.dtsi)
   spi2_pins_a: spi2@0 {
               reg = <0>;
               fsl,pinmux-ids = <
                  0x0182 /* MX23_PAD_GPMI_WRN__SSP2_SCK */
                  0x0142 /* MX23_PAD_GPMI_RDY1__SSP2_CMD */
                  0x0002 /* MX23_PAD_GPMI_D00__SSP2_DATA0 */
                  0x0032 /* MX23_PAD_GPMI_D03__SSP2_DATA3 */
               >;
               fsl,drive-strength = <1>;
               fsl,voltage = <1>;
               fsl,pull-up = <1>;
            };


0x0032 /* MX23_PAD_GPMI_D03__SSP2_DATA3 */ is chip pin 25 and "PIN12/LCD_D11/UEXT_CS" on the maxi board.

What needs to happen to make this work?

The documentation on this (is this out of sync with the actual driver code?) in mxs-spi.txt (Documentation/devicetree/bindings/spi/) and fsl-spi.txt have things like
   spi@4c0 {
      ...
      gpios = <&gpio 18 1   // device reg=<0>
          &gpio 19 1>;   // device reg=<1>
   };
or
   spi@110000 {
      ...
      fsl,espi-num-chipselects = <4>;
   };

but it is hard to make sense of this.

Side note:
if reg=<0> is used to reference the first SPI child node, why has the imx23-olinuxino.dts a spidev reg=<1> entry?

This here is interesting http://stackoverflow.com/questions/14053535/more-than-two-spi-devices-on-an-arm-board-that-supports-only-two because it states:
"... the IMX SPI driver supports GPIO toggle by passing a negative chip select number to denote a GPIO id."
Is this supported?

Someone hinted at a numbering catch gpio23 vs gpio24 (one nomenclature starts at 0, the other on 1), so same pin referred to as 23 or 24.

Also for reference: It seems to be possible to keep CS alive over several packets (https://community.freescale.com/thread/296700)

I could not find any documentation that would allow to make sense of what is going on in the device tree or how to use/set this up correctly. The people at http://free-electrons.com/docs/ have some nice slides, but this is not enough.


Does anyone know how this should be done or has any pointers or knows of (preferably working ;-) example (codes)?



Thanks.




Fadil Berisha

Quote from: olinuxino0000 on December 12, 2013, 03:44:18 PM

.the. manual 'i.MX233 product datasheet' (IMX23RM.pdf) on p.1016 seems to suggest that SSP block can handle SSn0, SSn1, SSn2, so 3 lines.

You are right, imx23 processor support also SPI interface with 3 slave select lines but imx23-olinuxino use SPI interface with one slave select line UEXT_CS.

You can modify imx23.dtsi and imx23-olinuxino.dts to make it with 3 slave select lines but 1st check if mxs spi driver support that option.

Quote
Side note:
if reg=<0> is used to reference the first SPI child node, why has the imx23-olinuxino.dts a spidev reg=<1> entry?

imx23-olinuxino.dts has no child nodes because board by default has nothing attached on UEXT connector. If you attach device on UEXT SPI connector, needed to add respective node and recompile DT file.
Please check  how to add spidev node; EXAMPLE-1 at http://g-lab.ca/spi-serial-periferial-interface/ . For 1st device reg is reg=<0>, second device has reg=<1> and so on. 

Hope this helps.

olinuxino0000


Dear Fadil, thanks for your reply!

I meanwhile managed to get one /CS signal working.

I added the below child node to the arch/arc/boot/dts/mx23-olinuxino.dts file and get as expected the /dev/spidev1.0 device and this has a working /CS line on UEXT_CS (-maxi at least) as expected.

My original mistake was to have spidev defined with "reg = <1>;". This probably selected the 2nd CS line, but as this does not seem to be related to a pin I don't know if the signal actually does show up anywhere (did not search for it).   

ssp1: ssp@80034000 {
            #address-cells = <1>;
            #size-cells = <0>;
            compatible = "fsl,imx23-spi";
            pinctrl-names = "default";
            pinctrl-0 = <&spi2_pins_a>;
            clock-frequency = <1000000>;
            status = "okay";

            spidev: spidev@0 {
               compatible = "spidev";
               spi-max-frequency = <1000000>;
               reg = <0>;
            };
         };
      };


This directory is extremely useful (thanks go to this beagleboard related page http://derekmolloy.ie/gpios-on-the-beaglebone-black-using-device-tree-overlays/) as it shows who claims which pins for what.

/sys/kernel/debug/pinctrl/80018000.pinctrl

Still interesting is if additional CS pins can be used, and if >3 (the max the imx23 SSP block supports) are required if passing a neg cs number (how to find out what the syntax is?) as stated somewhere else will lead to gpio pins used for these signals.

I also found these two links helpful:

http://www.element14.com/community/community/knode/single-board_computers/next-gen_beaglebone/blog/2013/05/22/bbb--working-with-the-pru-icssprussv2

http://devicetree.org/Device_Tree_Usage

Fadil Berisha

Quote from: olinuxino0000 on December 13, 2013, 08:40:07 PM

ssp1: ssp@80034000 {
            #address-cells = <1>;
            #size-cells = <0>;
            compatible = "fsl,imx23-spi";
            pinctrl-names = "default";
            pinctrl-0 = <&spi2_pins_a>;
            clock-frequency = <1000000>;
            status = "okay";

            spidev: spidev@0 {
               compatible = "spidev";
               spi-max-frequency = <1000000>;
               reg = <0>;
            };
         };
      };


I'm happy to know that you come to same solution  as I pointed with EXAMPLE-1 from my web page http://g-lab.ca/spi-serial-periferial-interface/

olinuxino0000

ok trying to advance this to a second available /CS line.

p.1016 (IMX23RM.pdf) says SSP_DATA4 <-> SSn1
this  on
p. 1406 has
Pin Group    Type Pin Name Descr1 Descr2  Descr3
25  GPMI_D03 GPMI DIO NAND Data 3 LCD_D11 SSP2_DATA3
27  GPMI_D04 GPMI DIO NAND Data 4 LCD_D12 SSP2_DATA4


DATA3 is the one connected to UEXT_CS and already configured in arch/arm/boot/dts/imx23.dtsi
   spi2_pins_a: spi2@0 {
               reg = <0>;
               fsl,pinmux-ids = <
                  0x0182 /* MX23_PAD_GPMI_WRN__SSP2_SCK */
                  0x0142 /* MX23_PAD_GPMI_RDY1__SSP2_CMD */
                  0x0002 /* MX23_PAD_GPMI_D00__SSP2_DATA0 */
                  0x0032 /* MX23_PAD_GPMI_D03__SSP2_DATA3 */
                  >;
               fsl,drive-strength = <1>;
               fsl,voltage = <1>;
               fsl,pull-up = <1>;
            };


now to add this I changed this to

fsl,pinmux-ids = <
                  0x0182 /* MX23_PAD_GPMI_WRN__SSP2_SCK */
                  0x0142 /* MX23_PAD_GPMI_RDY1__SSP2_CMD */
                  0x0002 /* MX23_PAD_GPMI_D00__SSP2_DATA0 */
                  0x0032 /* MX23_PAD_GPMI_D03__SSP2_DATA3 */
                  0x0040   /* MX23_PAD_GPMI_D04__GPMI_D04 */
                  >;


but because /* MX23_PAD_GPMI_D04__GPMI_D04 */ is already part of the    'gpmi_pins_a: gpmi-nand@0 {' section
I changed this there to

   gpmi_pins_a: gpmi-nand@0 {
               reg = <0>;
               fsl,pinmux-ids = <
                  0x0000 /* MX23_PAD_GPMI_D00__GPMI_D00 */
                  ...
                  0x0030 /* MX23_PAD_GPMI_D03__GPMI_D03 */
               /*   0x0040   MX23_PAD_GPMI_D04__GPMI_D04 */
                  0x0050 /* MX23_PAD_GPMI_D05__GPMI_D05 */
                  ...
                  0x21c0 /* MX23_PAD_GPMI_CE0N__GPMI_CE0N   */
               >;
               fsl,drive-strength = <0>;
               fsl,voltage = <1>;
               fsl,pull-up = <0>;
            };


This does only work partially.

There are /dev/spidev1.0 and /dev/spidev1.1
but only a call (echo "x"> /dev/spidev1.0) outputs the CS on UEXT_CS.
No /CS happening on  /dev/spidev1.1 (PIN13/LCD_D12).


The ssp section is at present
   ssp1: ssp@80034000 {
            #address-cells = <1>;
            #size-cells = <0>;
            compatible = "fsl,imx23-spi";
            pinctrl-names = "default";
            pinctrl-0 = <&spi2_pins_a>;
            clock-frequency = <1000000>;
            num-cs = <2>;
            status = "okay";

            spidev: spidev@0 {
               compatible = "spidev";
               spi-max-frequency = <500000>;
               reg = <0>;
            };

            spidevv: spidevv@0 {
               compatible = "spidev";
               spi-max-frequency = <500000>;
               reg = <1>;
            };


         };
      };



Where is all this documented, or in which mailing lists do the people who know about this hang around?

From instrumenting the kernel drivers this does not look too wrong:


[root@alarm ~]# echo "X" > /dev/spidev1.0
[ 1268.370000] SPIDEBUG mxs_spi_set_cs(... unsigned cs=0
[ 1268.370000] SPIDEBUG static uint32_t mxs_spi_cs_to_reg(unsigned cs) cs=0
[root@alarm ~]# echo "X" > /dev/spidev1.1
[ 1275.940000] SPIDEBUG mxs_spi_set_cs(... unsigned cs=1
[ 1275.950000] SPIDEBUG static uint32_t mxs_spi_cs_to_reg(unsigned cs) cs=1


Ideas?


Kean

I've not got much experience with customising .dts files, and I pretty much gave up on hardware SPI...
but I note in the "fsl,pinmux-ids" section that all the "addresses" have a lower nibble of 2.
It seems like the all GPMI indexes are shifted left 4 bits and 2 has been added (don't know why).

So maybe try this:

fsl,pinmux-ids = <
                  0x0182 /* MX23_PAD_GPMI_WRN__SSP2_SCK */
                  0x0142 /* MX23_PAD_GPMI_RDY1__SSP2_CMD */
                  0x0002 /* MX23_PAD_GPMI_D00__SSP2_DATA0 */
                  0x0032 /* MX23_PAD_GPMI_D03__SSP2_DATA3 */
                  0x0042   /* MX23_PAD_GPMI_D04__GPMI_D04 */
                  >;

I also don't think you should be commenting that line out of the "gpmi_pins_a" section.

Christian Jann

#6
I don't know whether it helps but I can bring a bit light into the pinmux-ids:

https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/Documentation/devicetree/bindings/pinctrl/fsl,mxs-pinctrl.txt:


Required subnode-properties:
- fsl,pinmux-ids: An integer array.  Each integer in the array specify a pin
  with given mux function, with bank, pin and mux packed as below.

    [15..12] : bank number
    [11..4]  : pin number
    [3..0]   : mux selection

0000000000000000
[  ][      ][  ]
bank  pin    mux

0000000001000010 0x0042 /* MX23_PAD_GPMI_D04__SSP2_DATA4 */
  0b00001110 = 4 (bank 0, pin 4)


From the reference manual http://www.freescale.com/files/dsp/doc/ref_manual/IMX23RM.pdf (Table 37-8.HW_PINCTRL_MUXSEL0 Bit Field Descriptions):


BANK0_PIN04
Pin 49, GPMI_D0400= gpmi_data04;
01= lcd_d12;
10= ssp2_d4;
11= GPIO.
pin function selection:


0x0042 looks good indeed, because it ends in "10" binary, which sets the pinmux to ssp2_d4

And also inside Documentation/devicetree/bindings/pinctrl/fsl,mxs-pinctrl.txt:
MX23_PAD_GPMI_D04__SSP2_DATA4 0x0042


But maybe it has to be a gpio if you want to use it as chip select?
https://www.kernel.org/doc/Documentation/devicetree/bindings/spi/spi-bus.txt:


- cs-gpios   - (optional) gpios chip select.

It is assumed that a driver for an SPI bus device will understand that it is an SPI bus.
However, the binding does not attempt to define the specific method for
assigning chip select numbers.  Since SPI chip select configuration is
flexible and non-standardized, it is left out of this binding with the
assumption that board specific platform code will be used to manage
chip selects.  Individual drivers can define additional properties to
support describing the chip select layout.

Optional property:
- num-cs : total number of chipselects

If cs-gpios is used the number of chip select will automatically increased
with max(cs-gpios > hw cs)

So if for example the controller has 2 CS lines, and the cs-gpios
property looks like this:

cs-gpios = <&gpio1 0 0> <0> <&gpio1 1 0> <&gpio1 2 0>;

Then it should be configured so that num_chipselect = 4 with the
following mapping:

cs0 : &gpio1 0 0
cs1 : native
cs2 : &gpio1 1 0
cs3 : &gpio1 2 0

SPI slave nodes must be children of the SPI master node and can
contain the following properties.
- reg             - (required) chip select address of device.
- compatible      - (required) name of SPI device following generic names
- compatible      - (required) name of SPI device following generic names
    recommended practice
- spi-max-frequency - (required) Maximum SPI clocking speed of device in Hz
- spi-cpol        - (optional) Empty property indicating device requires
    inverse clock polarity (CPOL) mode
- spi-cpha        - (optional) Empty property indicating device requires
    shifted clock phase (CPHA) mode
- spi-cs-high     - (optional) Empty property indicating device requires
    chip select active high
- spi-3wire       - (optional) Empty property indicating device requires
        3-wire mode.
- spi-tx-bus-width - (optional) The bus width(number of data wires) that
                      used for MOSI. Defaults to 1 if not present.
- spi-rx-bus-width - (optional) The bus width(number of data wires) that
                      used for MISO. Defaults to 1 if not present.

Some SPI controllers and devices support Dual and Quad SPI transfer mode.
It allows data in SPI system transfered in 2 wires(DUAL) or 4 wires(QUAD).
Now the value that spi-tx-bus-width and spi-rx-bus-width can receive is
only 1(SINGLE), 2(DUAL) and 4(QUAD).
Dual/Quad mode is not allowed when 3-wire mode is used.

If a gpio chipselect is used for the SPI slave the gpio number will be passed
via the cs_gpio

SPI example for an MPC5200 SPI bus:
spi@f00 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,mpc5200b-spi","fsl,mpc5200-spi";
reg = <0xf00 0x20>;
interrupts = <2 13 0 2 14 0>;
interrupt-parent = <&mpc5200_pic>;

ethernet-switch@0 {
compatible = "micrel,ks8995m";
spi-max-frequency = <1000000>;
reg = <0>;
};

codec@1 {
compatible = "ti,tlv320aic26";
spi-max-frequency = <100000>;
reg = <1>;
};
};


I'm just dumping a bit information, I haven't actually done something useful with the SPI yet. (OK, I have Quad SPI transfer mode running with ssp1 and a second SD card)

Maybe it helps to have a look inside the SPI driver (https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/drivers/spi/spi-mxs.c) how chip select pins are handled there?



olinuxino0000

Guys thanks for the information - this is great!

Kean's suggestion is exactly what is needed using:

0000000001000010 0x0042 /* MX23_PAD_GPMI_D04__SSP2_DATA4 */


does make it work and in addition I also get the third /CS line (SSn2).

There are some issues still.
The lines only work, if you always access only the same one (spidev1.0 e.g.). As soon as you try a different one, all of them stop working. Or something like that. I don't fully understand what is going on at the moment. Power-up reset recovers from this state.

What I found is that cluttering spi-mxc.c with printk statements seems to make it work, which seems to hint at a timing issue with setting/clearing registers somewhere. I'll try to narrow this down and post a more complete update (also dts modifications) and some documentation pointers I meanwhile found on the net.