Search code examples
linuxuartdevice-treers485

Enable RS485 mode for max310x SPI-UART converter


In my application I need RS485 interfaces. I am using some UARTs from am3352 but I need few more, so I'm trying to expand using SPI and max3109 chip.

I have successfully added max3109 to my device tree using module max310x - it shows two devices: /dev/ttyMAX0 and /dev/ttyMAX1. Here is the device tree fragment:

&spi1 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&spi1_pins>;
    num_cs = <1>;
    cs-gpios = <&gpio2 17 0>;
    ti,pindir-d0-out-d1-in;

    max310x_0: max0@0 {
        compatible = "maxim,max3109";
        reg = <0>;
        spi-max-frequency = <24000000>;
        clocks = <&clk1m8>;
        clock-names = "xtal";
        interrupt-parent = <&gpio2>;
        interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
        gpio-controller;
        #gpio-cells = <2>;
        clk1m8: clk1m8 {
            compatible = "fixed-clock";
            #clock-cells = <0>;
            clock-frequency = <1843200>;
        };
    };
};

and the pins:

spi1_pins: pinmux_spi1_pins {
    pinctrl-single,pins = <
        0x108 (PIN_INPUT_PULLUP | MUX_MODE2) /* (H16) gmii1_col.spi1_sclk */
        0x10c (PIN_INPUT_PULLUP | MUX_MODE2) /* (H17) gmii1_crs.spi1_d0 */
        0x110 (PIN_INPUT_PULLUP | MUX_MODE2) /* (J15) gmii1_rxer.spi1_d1 */
    >;
};

UARTs from max3109 are connected to rs232/rs485 converter with max3109's RTSn pins conected to both DE and RE pins.

The problem: UARTS on max3109 seems to work fine - both rs485 are transmitting data, but not reciving. Problem is that RTS is always at 0V level...

In UARTs from am3352 I am using in device tree the following property: "linux,rs485-enabled-at-boot-time". But adding it to main max310x_0 node is not giving any effect - this node is the expander node (containing 2 UARTs and gpio-controller), not the UART itself.

My idea is that I need to add a child-nodes for each UART and in it place the property "linux,rs485-enabled-at-boot-time". But I don't have a clue how to do it. I tried something like this:

&spi1 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&spi1_pins>;
    num_cs = <1>;
    cs-gpios = <&gpio2 17 0>;
    ti,pindir-d0-out-d1-in;

    max310x_0: max0@0 {
        compatible = "maxim,max3109";
        reg = <0>;
        spi-max-frequency = <24000000>;
        clocks = <&clk1m8>;
        clock-names = "xtal";
        interrupt-parent = <&gpio2>;
        interrupts = <12 IRQ_TYPE_EDGE_FALLING>;
        gpio-controller;
        #gpio-cells = <2>;
        clk1m8: clk1m8 {
            compatible = "fixed-clock";
            #clock-cells = <0>;
            clock-frequency = <1843200>;
        };
        ttyMAX0 {
            linux,rs485-enabled-at-boot-time;
        };
        ttyMAX1 {
            linux,rs485-enabled-at-boot-time;
        };
    };
};

but it didn't worked.

My question: How am I supposed to add those child-nodes (if that's the proper way) and what should I place in them to make RTS work?

EDIT: after sawdust suggestion it seems it's impossible to add rs485 mode in device tree. So I tried to add this functionality to device tree and I think I'm starting to understand how things work down in here. To start with something I'm printing port.flags value to dmesg and it seems my little insertion works (a bit) - it changes the value depending on presence of linux,rs485-enabled-at-boot-time parameter in device tree. Here is the code I have inserted:

    if (of_property_read_bool(dev->of_node, "linux,rs485-enabled-at-boot-time")) 
    s->p[i].port.flags |= SER_RS485_ENABLED; 
    printk("s->p[i].port.flags is: %d\n",s->p[i].port.flags); 

The value of port.flags toggles from 134225920 to 134225921 depending on presence of linux,rs485-enabled-at-boot-time. but the RTS pin still have constant 0V on my oscilloscope... I'm trying to figure out if SER_RS485_RTS_ON_SEND and SER_RS485_RTS_AFTER_SEND have something to do with this, but I'm prete sure it's only for reverting RTS signal.


Solution

  • After few attempts IOCTL was the best and easiest solution. Here is some example code that helped me much. https://gist.github.com/amarburg/07564916d8d32e20e6ae375c1c83a995

    It's basic example how to turn RS485 mode on and off using IOCTL and read it's current mode. Works with both CPUs internal UARTS and MAX3109.