Forum: PC-Programmierung Openwrt: SPI über GPIOs


von ALrK3uMW (Gast)


Lesenswert?

Hi,

wie kriege ich den SPI-Bus unter dem aktuellen Openwrt (backfire) mit 
GPIOs zum Laufen? Wo finde ich Einstellungen zu den verwendeten GPIOs, 
oder eine zugehörige Doku?

Openwrt kompiliert, kmod-spi-bitbang, kmod-spi-dev, kmod-spi-gpio und 
spidev-test sind fest eingebaut, scheinen aber kein device zu erzeugen.

Hardware: Edimax BR-6104KP

VG

von MBS (Gast)


Lesenswert?

Weiß nicht, ob es noch aktuell ist. Die Infos findet man im Quellcode 
(spi_gpio.c). Gibt also 2 Möglichkeiten:
1.: entsprechende platform_data in deiner 
arch/mips/adm5120/edimax/br-6104kp.c definieren. Näheres dazu beschreibt 
auch die Datei include/linux/spi/spi_gpio.h. Komplettes Image neu bauen.
2.: in spi_gpio.c gleich folgende Sachen auskommentieren und auf deine 
GPIO-Nummern ändern:
 *    #define DRIVER_NAME  "myboard_spi2"
 *    #define  SPI_MISO_GPIO  119
 *    #define  SPI_MOSI_GPIO  120
 *    #define  SPI_SCK_GPIO  121
 *    #define  SPI_N_CHIPSEL  4
 *    #include "spi_gpio.c"
Also das abschließende */ entsprechend vor die erste Zeile hier 
verschieben und die Zeichen vor der Raute entfernen. Dann müsste man 
eigentlich nur noch diese Datei kompilieren.

von Alex E. (alex_0xff)


Lesenswert?

Hallo ALrK3uMW,
  bist du schon weiter... ich versuche nun seit ein paar Tagen SPI am 
WGT634 zum laufen zu bringen. Und habe zur Zeit die "selbe" Frage / bin 
auf dem selben Stand wie du.

-alex

von Mountain (Gast)


Lesenswert?

Hallo,

ich habe ein CAN-Bus Controller mit einem BR-6104K (SoC ADM5120)
verbunden. Über SPI kann ich den Controller initialisieren:
1
BusyBox v1.19.3 (2012-04-05 12:15:53 CEST) built-in shell (ash)
2
Enter 'help' for a list of built-in commands.
3
4
  _______                     ________        __
5
 |       |.-----.-----.-----.|  |  |  |.----.|  |_
6
 |   -   ||  _  |  -__|     ||  |  |  ||   _||   _|
7
 |_______||   __|_____|__|__||________||__|  |____|
8
          |__| W I R E L E S S   F R E E D O M
9
 ATTITUDE ADJUSTMENT (bleeding edge, r30857) ----------
10
11
root@OpenWrt:/# uname -a
12
Linux OpenWrt 3.1.10 #6 Thu Apr 5 16:39:22 CEST 2012 mips GNU/Linux
13
14
root@OpenWrt:/# insmod mcp251x
15
root@OpenWrt:/# cat /sys/kernel/debug/gpio 
16
GPIOs 0-3, adm5120 gpio0:
17
 gpio-2   (MCP251x CAN INT     ) in  hi
18
19
GPIOs 8-22, adm5120 gpio1:
20
 gpio-17  (spi_gpio.1          ) in  lo
21
 gpio-18  (spi_gpio.1          ) out lo
22
 gpio-20  (spi_gpio.1          ) out lo
23
 gpio-21  (spi1.0              ) out hi
24
root@OpenWrt:/# insmod mcp251x
25
[  368.736000] mcp251x spi1.0: probed
26
27
root@OpenWrt:/# ip link set can0 type can bitrate 125000 loopback on
28
29
root@OpenWrt:/# ifconfig can0 up
30
[  402.324000] mcp251x spi1.0: CNF: 0x03 0xb5 0x01
31
32
root@OpenWrt:/# ip -details link show can0
33
10: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UNKNOWN qlen 10
34
    link/can 
35
    can <LOOPBACK> state ERROR-ACTIVE restart-ms 0 
36
    bitrate 125000 sample-point 0.875 
37
    tq 500 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1
38
    mcp251x: tseg1 3..16 tseg2 2..8 sjw 1..4 brp 1..64 brp-inc 1
39
    clock 8000000
40
41
root@OpenWrt:/# cat /sys/kernel/debug/gpio 
42
GPIOs 0-3, adm5120 gpio0:
43
 gpio-2   (MCP251x CAN INT     ) in  hi
44
45
GPIOs 8-22, adm5120 gpio1:
46
 gpio-17  (spi_gpio.1          ) in  lo
47
 gpio-18  (spi_gpio.1          ) out lo
48
 gpio-20  (spi_gpio.1          ) out lo
49
 gpio-21  (spi1.0              ) out hi
50
51
root@OpenWrt:/# cat /proc/interrupts 
52
           CPU0       
53
  2:          0      MIPS  cascade [INTC]
54
  7:      33933      MIPS  timer
55
  9:       2477      INTC  uart-pl010
56
 12:          0      INTC  mcp251x
57
 17:        614      INTC  eth0, eth1
58
ERR:          0
59
60
root@OpenWrt:/# dmesg | tail -5
61
[  368.732000] mcp251x spi1.0: CANSTAT 0x80 CANCTRL 0x07
62
[  368.736000] mcp251x spi1.0: probed
63
[  402.308000] mcp251x spi1.0:  INTC_REG_IRQ_ENABLE = 0x212
64
[  402.308000] mcp251x spi1.0:  GPIO2 IRQ initialized
65
[  402.324000] mcp251x spi1.0: CNF: 0x03 0xb5 0x01
Sieht soweit gut aus, aber es wird kein IRQ ausgelöst, wenn ich eine CAN
Nachricht sende:
1
root@OpenWrt:/# cansend can0 123#DEADBEEF
2
root@OpenWrt:/# cat /proc/interrupts 
3
           CPU0       
4
  2:          0      MIPS  cascade [INTC]
5
  7:      34334      MIPS  timer
6
  9:       2845      INTC  uart-pl010
7
 12:          0      INTC  mcp251x
8
 17:        669      INTC  eth0, eth1
9
ERR:          0
10
11
root@OpenWrt:/# cat /sys/kernel/debug/gpio 
12
GPIOs 0-3, adm5120 gpio0:
13
 gpio-2   (MCP251x CAN INT     ) in  lo
14
15
GPIOs 8-22, adm5120 gpio1:
16
 gpio-17  (spi_gpio.1          ) in  lo
17
 gpio-18  (spi_gpio.1          ) out lo
18
 gpio-20  (spi_gpio.1          ) out lo
19
 gpio-21  (spi1.0              ) out hi
GPIO2 ist im Status "in lo" und sollte einen IRQ auslösen.

Ich habe zuerst versucht, den IRQ Initialisierung in der Board
Definition unterzubringen - ohne Erfolg. Daher habe ich
versuchsweise dies nun in den CAN Controller Treiber
eingebaut (mcp251x.c):
1
 static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
2
{
3
        struct mcp251x_priv *priv = dev_id;
4
        struct spi_device *spi = priv->spi;
5
        struct net_device *net = priv->net;
6
        unsigned long flags;
7
        unsigned int intc_reg_int_level;
8
9
        mutex_lock(&priv->mcp_lock);
10
        dev_dbg(&spi->dev, " in mcp251x_can_ist ...\n");
11
12
        // ADM5120 IRQs can only be level, not edge so we are going
13
        //   switch level and only use high to low trigger
14
        spin_lock_irqsave(&level_register_lock, flags);
15
        {
16
                intc_reg_int_level = BIT(4) ^ intc_read_reg(INTC_REG_INT_LEVEL);
17
                intc_write_reg(INTC_REG_INT_LEVEL, intc_reg_int_level);
18
        }
19
        spin_unlock_irqrestore(&level_register_lock, flags);
20
        // we only need falling edge
21
        if (BIT(4) & intc_reg_int_level)
22
                return(IRQ_HANDLED);
23
        while (!priv->force_quit) {
24
        ...
25
        }
26
}
27
28
...
29
static int mcp251x_open(struct net_device *net)
30
{
31
        struct mcp251x_priv *priv = netdev_priv(net);
32
        struct spi_device *spi = priv->spi;
33
        struct mcp251x_platform_data *pdata = spi->dev.platform_data;
34
        int ret;
35
        unsigned int ire;
36
        unsigned long flags;
37
38
        ret = open_candev(net);
39
        if (ret) {
40
                dev_err(&spi->dev, "unable to set initial baudrate!\n");
41
                return ret;
42
        }
43
44
        mutex_lock(&priv->mcp_lock);
45
        if (pdata->transceiver_enable)
46
                pdata->transceiver_enable(1);
47
48
        priv->force_quit = 0;
49
        priv->tx_skb = NULL;
50
        priv->tx_len = 0;
51
52
        ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist,
53
                  pdata->irq_flags ? pdata->irq_flags : IRQF_TRIGGER_FALLING,
54
                  DEVICE_NAME, priv);
55
        if (ret) {
56
                dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
57
                if (pdata->transceiver_enable)
58
                        pdata->transceiver_enable(0);
59
                close_candev(net);
60
                goto open_unlock;
61
        } else {
62
                spin_lock_irqsave(&level_register_lock, flags);
63
                // enable interrupt on GPIO 2
64
                // pp37 ADM5120 manual
65
                ire = intc_read_reg(INTC_REG_IRQ_ENABLE);
66
                ire |= BIT(4) | BIT(9); // II0E | SWIE
67
                intc_write_reg(INTC_REG_IRQ_ENABLE, ire);
68
                dev_dbg(&spi->dev, " INTC_REG_IRQ_ENABLE = 0x%x\n", ire);
69
70
                // Enable CSX0/INTX0 processing as described on pp131 of ADM5120 manual
71
                SW_WRITE_REG(SWITCH_REG_GPIO_CONF2, BIT(4));
72
                // sets GPIO4 and 2 as active low
73
                // pp41/42 of ADM5120 manual.
74
                intc_write_reg(INTC_REG_INT_LEVEL, BIT(4) | intc_read_reg(INTC_REG_INT_LEVEL));
75
                spin_unlock_irqrestore(&level_register_lock, flags);
76
                dev_dbg(&spi->dev, " GPIO2 IRQ initialized\n");
77
        }
78
...
79
}
Ein simples GPIO2 Modul hingegen funktioniert:
http://www.omnima.co.uk/forums/lofiversion/index.php?t72.html
1
root@OpenWrt:/# insmod gpio2
2
[  130.380000] INTC_REG_IRQ_ENABLE = 0x212
3
[  130.384000] GPIO_RESET: requesting IRQ -> fine
4
root@OpenWrt:/# [  133.820000] pressed
5
[  134.040000] released
6
[  135.196000] pressed
7
[  135.412000] released
8
[  136.076000] pressed
9
[  136.220000] released
10
11
root@OpenWrt:/# cat /proc/interrupts 
12
           CPU0       
13
  2:          0      MIPS  cascade [INTC]
14
  7:      28970      MIPS  timer
15
  9:        180      INTC  uart-pl010
16
 12:          6      INTC  gpio_reset
17
 17:        334      INTC  eth0, eth1
18
ERR:          0

Hier die Board Initialisierung:
1
nizza ~/projekte/openwrt/trunk_3.1 (svn)-[trunk:30857] % cat build_dir/linux-adm5120_router_le/linux-3.1.10/arch/mips/adm5120/edimax/br-61xx.c
2
/*
3
 *  Edimax BR-61xx support
4
 *
5
 *  Copyright (C) 2007-2008 Gabor Juhos <juhosg@openwrt.org>
6
 *
7
 *  This program is free software; you can redistribute it and/or modify it
8
 *  under the terms of the GNU General Public License version 2 as published
9
 *  by the Free Software Foundation.
10
 *
11
 */
12
13
#include "br-61xx.h"
14
15
#include <prom/admboot.h>
16
#include <linux/spi/spi_gpio.h>
17
#include <linux/can/platform/mcp251x.h>
18
19
#include <linux/irq.h>
20
#include <linux/interrupt.h>
21
#include <linux/kernel.h>

Hat jemand eine Idee, warum der IRQ im MCP251x Modul nicht ausgelöst
wird ?

von Mountain (Gast)


Angehängte Dateien:

Lesenswert?

Hoppla,

die Board Definitions-Datei wurde abgeschnitten

von Mountain (Gast)


Lesenswert?

:-) habs zum Fliegen bekommen:
1
root@OpenWrt:~# cansend can0 666#DEADBEEF
2
3
root@OpenWrt:~# candump any,0:0,#FFFFFFFF
4
  can0  666  [4] DE AD BE EF
5
  can0  666  [4] DE AD BE EF
6
7
root@OpenWrt:~# ip -s -details link show can0
8
9: can0: <NOARP,UP,LOWER_UP,ECHO> mtu 16 qdisc pfifo_fast state UNKNOWN
9
qlen 10
10
    link/can
11
    can <LOOPBACK> state ERROR-ACTIVE restart-ms 0
12
    bitrate 125000 sample-point 0.875
13
    tq 500 prop-seg 6 phase-seg1 7 phase-seg2 2 sjw 1
14
    mcp251x: tseg1 3..16 tseg2 2..8 sjw 1..4 brp 1..64 brp-inc 1
15
    clock 8000000
16
    re-started bus-errors arbit-lost error-warn error-pass bus-off
17
    0          0          0          0          0          0
18
    RX: bytes  packets  errors  dropped overrun mcast
19
    48         10       0       0       0       0
20
    TX: bytes  packets  errors  dropped carrier collsns
21
    48         10       0       0       0       0
22
23
root@OpenWrt:~# cat /sys/kernel/debug/gpio
24
GPIOs 0-3, adm5120 gpio0:
25
 gpio-2   (MCP251x /INT        ) in  hi
26
27
GPIOs 8-22, adm5120 gpio1:
28
 gpio-17  (spi_gpio.1          ) in  lo
29
 gpio-18  (spi_gpio.1          ) out lo
30
 gpio-20  (spi_gpio.1          ) out lo
31
 gpio-21  (spi1.0              ) out hi
32
33
root@OpenWrt:~# cat /proc/interrupts
34
           CPU0
35
  2:          0      MIPS  cascade [INTC]
36
  7:     553160      MIPS  timer
37
  9:       1482      INTC  uart-pl010
38
 12:         20      INTC  mcp251x
39
 17:     119245      INTC  eth0, eth1
40
ERR:          0
1
--- mcp251x.c   2012-01-18 16:33:18.000000000 +0100
2
+++ mcp251x_funkt2.c    2012-04-18 15:33:49.926203717 +0200
3
@@ -76,6 +76,15 @@
4
 #include <linux/spi/spi.h>
5
 #include <linux/uaccess.h>
6
7
+#include <linux/irq.h>
8
+#include <linux/interrupt.h>
9
+
10
+#include <adm5120_defs.h>
11
+#include <asm/mipsregs.h>
12
+#include <asm/mach-adm5120/adm5120_info.h>
13
+#include <asm/mach-adm5120/adm5120_defs.h>
14
+#include <asm/mach-adm5120/adm5120_switch.h>
15
+
16
 /* SPI interface instruction set */
17
 #define INSTRUCTION_WRITE      0x02
18
 #define INSTRUCTION_READ       0x03
19
@@ -210,6 +219,21 @@
20
21
 #define DEVICE_NAME "mcp251x"
22
23
+static inline void intc_write_reg(unsigned int reg, u32 val)
24
+{
25
+        void __iomem *base = (void __iomem *)KSEG1ADDR(ADM5120_INTC_BASE);
26
+
27
+        __raw_writel(val, base + reg);
28
+}
29
+
30
+static inline u32 intc_read_reg(unsigned int reg)
31
+{
32
+        void __iomem *base = (void __iomem *)KSEG1ADDR(ADM5120_INTC_BASE);
33
+
34
+        return __raw_readl(base + reg);
35
+}
36
+
37
+
38
 static int mcp251x_enable_dma; /* Enable SPI DMA. Default: 0 (Off) */
39
 module_param(mcp251x_enable_dma, int, S_IRUGO);
40
 MODULE_PARM_DESC(mcp251x_enable_dma, "Enable SPI DMA. Default: 0 (Off)");
41
@@ -779,6 +803,39 @@
42
        mutex_unlock(&priv->mcp_lock);
43
 }
44
45
+static DEFINE_SPINLOCK(level_register_lock);
46
+
47
+
48
+static irqreturn_t mcp251x_can_hardirq(int irq, void *dev_id)
49
+{
50
+       struct mcp251x_priv *priv = dev_id;
51
+       struct spi_device *spi = priv->spi;
52
+       unsigned long flags;
53
+       unsigned int intc_reg_int_level;
54
+
55
+        // ADM5120 IRQs can only be level, not edge so we are going
56
+        //   switch level and only use high to low trigger
57
+        spin_lock_irqsave(&level_register_lock, flags);
58
+        intc_reg_int_level = intc_read_reg(INTC_REG_INT_LEVEL) ^ BIT(4);
59
+        intc_write_reg(INTC_REG_INT_LEVEL, intc_reg_int_level);
60
+       dev_info(&spi->dev, " mcp251x INT level 0x%X \n",intc_reg_int_level);
61
+
62
+        // we ignore raising edge - we have already xored
63
+        // if (intc_reg_int_level && BIT(4))
64
+       if (intc_reg_int_level &= 0x10)
65
+       {
66
+               dev_info(&spi->dev, "  mcp251x INT high -> IRQ_HANDLED\n");
67
+               spin_unlock_irqrestore(&level_register_lock, flags);
68
+               return IRQ_HANDLED;
69
+       } else {
70
+               dev_info(&spi->dev, "  mcp251x INT low  -> IRQ_WAKE_THREAD\n");
71
+               spin_unlock_irqrestore(&level_register_lock, flags);
72
+               return IRQ_WAKE_THREAD;
73
+       }
74
+}
75
+
76
+
77
+
78
 static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
79
 {
80
        struct mcp251x_priv *priv = dev_id;
81
@@ -786,6 +843,8 @@
82
        struct net_device *net = priv->net;
83
84
        mutex_lock(&priv->mcp_lock);
85
+       dev_info(&spi->dev, " in mcp251x_can_ist ...\n");
86
+
87
        while (!priv->force_quit) {
88
                enum can_state new_state;
89
                u8 intf, eflag;
90
@@ -909,12 +968,15 @@
91
        return IRQ_HANDLED;
92
 }
93
94
+
95
 static int mcp251x_open(struct net_device *net)
96
 {
97
        struct mcp251x_priv *priv = netdev_priv(net);
98
        struct spi_device *spi = priv->spi;
99
        struct mcp251x_platform_data *pdata = spi->dev.platform_data;
100
        int ret;
101
+       unsigned int ire;
102
+       unsigned long flags;
103
104
        ret = open_candev(net);
105
        if (ret) {
106
@@ -930,8 +992,9 @@
107
        priv->tx_skb = NULL;
108
        priv->tx_len = 0;
109
110
-       ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist,
111
-                 pdata->irq_flags ? pdata->irq_flags : IRQF_TRIGGER_FALLING,
112
+       ret = request_threaded_irq(spi->irq, mcp251x_can_hardirq, mcp251x_can_ist,
113
+                 // pdata->irq_flags ? pdata->irq_flags : IRQF_TRIGGER_FALLING,
114
+                 pdata->irq_flags ? pdata->irq_flags : IRQF_TRIGGER_NONE,
115
                  DEVICE_NAME, priv);
116
        if (ret) {
117
                dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
118
@@ -939,6 +1002,24 @@
119
                        pdata->transceiver_enable(0);
120
                close_candev(net);
121
                goto open_unlock;
122
+       } else {
123
+               spin_lock_irqsave(&level_register_lock, flags);
124
+               // enable interrupt on GPIO 2
125
+               // pp37 ADM5120 manual
126
+              ire = intc_read_reg(INTC_REG_IRQ_ENABLE);
127
+              dev_info(&spi->dev, " INTC_REG_IRQ_ENABLE was = 0x%x\n", ire);
128
+              ire |= BIT(4) | BIT(9); // II0E | SWIE
129
+              // ire |= BIT(4); // II0E
130
+              intc_write_reg(INTC_REG_IRQ_ENABLE, ire);
131
+               dev_info(&spi->dev, " INTC_REG_IRQ_ENABLE now = 0x%x\n", ire);
132
+
133
+               // Enable CSX0/INTX0 processing as described on pp131 of ADM5120 manual
134
+               SW_WRITE_REG(SWITCH_REG_GPIO_CONF2, BIT(4));
135
+               // sets GPIO4 and 2 as active low
136
+                // pp41/42 of ADM5120 manual.
137
+               intc_write_reg(INTC_REG_INT_LEVEL, BIT(4) | intc_read_reg(INTC_REG_INT_LEVEL));
138
+               spin_unlock_irqrestore(&level_register_lock, flags);
139
+               dev_info(&spi->dev, " GPIO2 IRQ initialized: IRQ %d\n",spi->irq);
140
        }
141
142
        priv->wq = create_freezable_workqueue("mcp251x_wq");
Boardefintionsdatei br-61xx.c:
1
static struct mcp251x_platform_data mcp251x_info = {
2
        .oscillator_frequency    = 16000000,
3
        .board_specific_setup    = NULL,
4
        .irq_flags               = IRQF_TRIGGER_NONE,
5
        .power_enable            = NULL,
6
        .transceiver_enable      = NULL,
7
};

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.