2014-05-26 07:48:50

by Hans de Goede

[permalink] [raw]
Subject: [PATCH 00/11] sdio wifi oob irq support for sunxi

Hi All,

Here is a patch series adding support for oob irqs for the ap6210 sdio wifi
modules found on various Allwinner A20 boards.

A lot of it is ground work which should be useful for adding oob irq support
to other sdio wifi models too.

The first 5 patches are sunxi pinctrl patches and should go upstream through
the pinctrl tree.

Patch 6 adds generic support for having per sdio function child nodes in
devicetree and should go upstream through the mmc tree.

Patch 7 and 8 add oob irq support to the brcmfmac driver. Patch 9 pokes some
magic bits needed to enable the oob irq, this was taken from an android code
dump and good do with a good review from someone from Broadcom, Arend ?

Patch 10 and 11 add the necessary dts bits to actually enable the sdio irq
and should go upstream through Maxime's dt tree.

Please review / merge.

Thanks & Regards,

Hans


2014-05-26 07:49:11

by Hans de Goede

[permalink] [raw]
Subject: [PATCH 10/11] ARM: dts: sun7i: Add #interrupt-cells to pinctrl node

From: Chen-Yu Tsai <[email protected]>

The pinctrl device is also an interrupt controller for external
interrupts. Add the missing #interrupt-cells property.

Also remove the unused #address-cells property.

Signed-off-by: Chen-Yu Tsai <[email protected]>
Signed-off-by: Hans de Goede <[email protected]>
---
arch/arm/boot/dts/sun7i-a20.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index b82642c..19b1ced 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -594,7 +594,7 @@
clocks = <&apb0_gates 5>;
gpio-controller;
interrupt-controller;
- #address-cells = <1>;
+ #interrupt-cells = <2>;
#size-cells = <0>;
#gpio-cells = <3>;

--
1.9.3


2014-05-26 07:48:52

by Hans de Goede

[permalink] [raw]
Subject: [PATCH 01/11] pinctrl: sunxi: create irq/pin mapping during init

From: Chen-Yu Tsai <[email protected]>

The irq/pin mapping is used to lookup the pin to mux to the irq
function when the irq is enabled. It is created when gpio_to_irq
is called. Creating the mapping during init allows us to map the
interrupts directly from the device tree.

Signed-off-by: Chen-Yu Tsai <[email protected]>
Signed-off-by: Hans de Goede <[email protected]>
---
drivers/pinctrl/sunxi/pinctrl-sunxi.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index f6522b5..db9ccd6 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -529,8 +529,6 @@ static int sunxi_pinctrl_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
if (!desc)
return -EINVAL;

- pctl->irq_array[desc->irqnum] = offset;
-
dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
chip->label, offset + chip->base, desc->irqnum);

@@ -731,6 +729,9 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
struct sunxi_desc_function *func = pin->functions;

while (func->name) {
+ /* Create interrupt mapping while we're at it */
+ if (!strcmp(func->name, "irq"))
+ pctl->irq_array[func->irqnum] = pin->pin.number;
sunxi_pinctrl_add_function(pctl, func->name);
func++;
}
--
1.9.3


2014-05-26 07:48:58

by Hans de Goede

[permalink] [raw]
Subject: [PATCH 03/11] pinctrl: sunxi: Move setting of mux to irq type from unmask to set_type

With level triggered interrupt mask / unmask will get called for each
interrupt, doing the somewhat expensive mux setting on each unmask thus is
not a good idea. Instead move it to the set_type callback, which is typically
done only once for each irq.

Signed-off-by: Hans de Goede <[email protected]>
---
drivers/pinctrl/sunxi/pinctrl-sunxi.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index ec60c2e..d1675c9 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -542,6 +542,7 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d,
struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
u32 reg = sunxi_irq_cfg_reg(d->hwirq);
u8 index = sunxi_irq_cfg_offset(d->hwirq);
+ struct sunxi_desc_function *func;
unsigned long flags;
u32 regval;
u8 mode;
@@ -574,6 +575,12 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d,

spin_unlock_irqrestore(&pctl->lock, flags);

+ func = sunxi_pinctrl_desc_find_function_by_pin(pctl,
+ pctl->irq_array[d->hwirq], "irq");
+
+ /* Change muxing to INT mode */
+ sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval);
+
return 0;
}

@@ -619,19 +626,11 @@ static void sunxi_pinctrl_irq_mask(struct irq_data *d)
static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
{
struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
- struct sunxi_desc_function *func;
u32 reg = sunxi_irq_ctrl_reg(d->hwirq);
u8 idx = sunxi_irq_ctrl_offset(d->hwirq);
unsigned long flags;
u32 val;

- func = sunxi_pinctrl_desc_find_function_by_pin(pctl,
- pctl->irq_array[d->hwirq],
- "irq");
-
- /* Change muxing to INT mode */
- sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval);
-
spin_lock_irqsave(&pctl->lock, flags);

/* Unmask the IRQ */
--
1.9.3


2014-05-26 07:49:17

by Hans de Goede

[permalink] [raw]
Subject: [PATCH 07/11] dt: bindings: add bindings for Broadcom bcm43xx sdio devices

From: Arend van Spriel <[email protected]>

The Broadcom bcm43xx sdio devices are fullmac devices that may be
integrated in ARM platforms. Currently, the brcmfmac driver for
these devices support use of platform data. This patch specifies
the bindings that allow this platform data to be expressed in the
devicetree.

Reviewed-by: Hante Meuleman <[email protected]>
Reviewed-by: Franky (Zhenhui) Lin <[email protected]>
Reviewed-by: Daniel (Deognyoun) Kim <[email protected]>
Reviewed-by: Pieter-Paul Giesberts <[email protected]>
Signed-off-by: Arend van Spriel <[email protected]>
[[email protected]: drop clk / reg_on gpio handling, as there is no consensus
on how to handle this yet]
[[email protected]: move from bindings/staging to bindings]
Signed-off-by: Hans de Goede <[email protected]>
---
.../bindings/net/wireless/brcm,bcm43xx-fmac.txt | 29 ++++++++++++++++++++++
1 file changed, 29 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/wireless/brcm,bcm43xx-fmac.txt

diff --git a/Documentation/devicetree/bindings/net/wireless/brcm,bcm43xx-fmac.txt b/Documentation/devicetree/bindings/net/wireless/brcm,bcm43xx-fmac.txt
new file mode 100644
index 0000000..6a0aaf2
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/wireless/brcm,bcm43xx-fmac.txt
@@ -0,0 +1,29 @@
+Broadcom BCM43xx Fullmac wireless SDIO devices
+
+This node provides properties for controlling the Broadcom wireless device. The
+node is expected to be specified as a child node to the SDIO controller that
+connects the device to the system.
+
+Required properties:
+
+ - compatible : Should be "brcm,bcm43xx-fmac".
+
+Optional properties:
+ - brcm,drive-strength : drive strength used for SDIO pins on device.
+ (default = 6mA).
+ - interrupt-parent : the phandle for the interrupt controller to which the
+ device interrupts are connected.
+ - interrupts : specifies attributes for the out-of-band interrupt (host-wake).
+ When not specified the device will use in-band SDIO interrupts.
+ - interrupt-names : name of the out-of-band interrupt, which must be set
+ to "host-wake".
+
+Example:
+
+bcm4335 {
+ compatible = "brcm,bcm43xx-fmac";
+ brcm,drive-strength = <4>;
+ interrupt-parent = <&gpx2>;
+ interrupts = <5 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "host-wake";
+};
--
1.9.3


2014-05-28 09:40:05

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH 03/11] pinctrl: sunxi: Move setting of mux to irq type from unmask to set_type

On Tue, May 27, 2014 at 04:18:29PM +0200, Linus Walleij wrote:
> On Mon, May 26, 2014 at 9:47 AM, Hans de Goede <[email protected]> wrote:
>
> > With level triggered interrupt mask / unmask will get called for each
> > interrupt, doing the somewhat expensive mux setting on each unmask thus is
> > not a good idea. Instead move it to the set_type callback, which is typically
> > done only once for each irq.
> >
> > Signed-off-by: Hans de Goede <[email protected]>
>
> Yes move it out of mask/unmask but no, not into set_type().
>
> Can you not use the irqchip startup()/shutdown() callbacks
> instead?

I think we can use irq_request_resources then
https://lkml.org/lkml/2014/3/12/307

We could even merge the gpio_to_irq code into it.

It's called in __setup_irq, so it's guaranteed to be called, and it
will bail out early without doing anything, since it's one of the
first thing __setup_irq does.

> And how come we have no clean separation between gpiochip
> and the pinmux parts here, why cant we just call
> pinctrl_request_gpio() and pinctrl_free_gpio() here instead?
> Or maybe pinctrl_gpio_direction_input() and have that set
> up the muxing in the pinctrl driver side?

Because the function it has to be muxed to is neither gpio_in or
gpio_out, and it's not even considered a gpio. It really is just
another muxing function, like i2c or mmc.

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (1.44 kB)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-05-28 10:51:18

by Tomasz Figa

[permalink] [raw]
Subject: Re: [PATCH 02/11] pinctrl: sunxi: add IRQCHIP_SKIP_SET_WAKE flag for pinctrl irq chip

On 28.05.2014 12:29, Maxime Ripard wrote:
> On Tue, May 27, 2014 at 06:14:31PM +0200, Tomasz Figa wrote:
>> On 27.05.2014 10:07, Maxime Ripard wrote:
>>> On Mon, May 26, 2014 at 09:47:57AM +0200, Hans de Goede wrote:
>>>> From: Chen-Yu Tsai <[email protected]>
>>>>
>>>> The sunxi pinctrl irq chip driver does not support wakeup at
>>>> the moment. Adding IRQCHIP_SKIP_SET_WAKE lets the irqs work
>>>> with drivers using wakeup.
>>>>
>>>> Also add a name to the irq chip.
>>>>
>>>> Signed-off-by: Chen-Yu Tsai <[email protected]> Signed-off-by:
>>>> Hans de Goede <[email protected]> ---
>>>> drivers/pinctrl/sunxi/pinctrl-sunxi.c | 2 ++ 1 file changed,
>>>> 2 insertions(+)
>>>>
>>>> diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
>>>> b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index
>>>> db9ccd6..ec60c2e 100644 ---
>>>> a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++
>>>> b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -646,6 +646,8 @@
>>>> static struct irq_chip sunxi_pinctrl_irq_chip = {
>>>> .irq_mask_ack = sunxi_pinctrl_irq_mask_ack, .irq_unmask =
>>>> sunxi_pinctrl_irq_unmask, .irq_set_type =
>>>> sunxi_pinctrl_irq_set_type, + .name = "sunxi-pio", + .flags
>>>> = IRQCHIP_SKIP_SET_WAKE,
>>>
>>> I'd rather see the name set to dev_name() or something like
>>> that. This will not work that great with multiple pin
>>> controller supporting interrupts.
>>
>> Correct me if I'm wrong, but I've always thought that struct
>> irq_chip describes a class of IRQ controllers, not particular
>> instances.
>
> It's not said as such in <linux/irq.h>, but maybe..

It is not said the otherwise as well, so hopefully someone could
clarify this. Thomas?

My conclusion about the purpose of this struct is based on its
contents - name, flags and a number of callbacks, nothing that could
be per-instance of identical chips. Moreover there is per interrupt
chip_data, which is usually used to store per-instance data by irqchip
drivers.

Best regards,
Tomasz

2014-05-27 09:01:54

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH 03/11] pinctrl: sunxi: Move setting of mux to irq type from unmask to set_type

Hi,

On 05/27/2014 10:09 AM, Maxime Ripard wrote:
> On Mon, May 26, 2014 at 09:47:58AM +0200, Hans de Goede wrote:
>> With level triggered interrupt mask / unmask will get called for each
>> interrupt, doing the somewhat expensive mux setting on each unmask thus is
>> not a good idea. Instead move it to the set_type callback, which is typically
>> done only once for each irq.
>
> *This* is the bad idea. Nothing prevents you from calling
> gpio_get_value whenever you just got your interrupt, that will change
> the muxing, and never change it back, effectively breaking the
> interrupts.

Hmm, interesting point, but your assuming 2 things which are both not true:

1) That calling gpiod_get_value changes the muxing, which is not true, all
gpiod_get_value variants end up in drivers/gpio/gpiolib.c _gpiod_get_raw_value()
which does no such thing

2) That unmask will always get called after the gpio_get_value to restore the mux
setting for us, which is not guaranteed at all. Before this patch set pinctrl-sunxi.c
was using handle_simple_irq which does not mask / unmask at all.

And even with an irq-handler which masks / unmasks, what if the irq wakes up
a thread and that thread then does the gpio_get_value ?

Note this is *exactly* what e.g. the mmc gpio card-detect code does, it uses
a thread to read the gpio for debouncing.

Luckily 2. is not a problem, since 1. means that the mux won't get changed at all
so we don't need to change it back.

Regards,

Hans

2014-05-27 16:50:59

by Arend van Spriel

[permalink] [raw]
Subject: Re: [PATCH 00/11] sdio wifi oob irq support for sunxi

On 05/27/14 17:26, John W. Linville wrote:
> On Mon, May 26, 2014 at 09:47:55AM +0200, Hans de Goede wrote:
>> Hi All,
>>
>> Here is a patch series adding support for oob irqs for the ap6210 sdio wifi
>> modules found on various Allwinner A20 boards.
>>
>> A lot of it is ground work which should be useful for adding oob irq support
>> to other sdio wifi models too.
>>
>> The first 5 patches are sunxi pinctrl patches and should go upstream through
>> the pinctrl tree.
>>
>> Patch 6 adds generic support for having per sdio function child nodes in
>> devicetree and should go upstream through the mmc tree.
>>
>> Patch 7 and 8 add oob irq support to the brcmfmac driver. Patch 9 pokes some
>> magic bits needed to enable the oob irq, this was taken from an android code
>> dump and good do with a good review from someone from Broadcom, Arend ?
>
> If Arend approves, I'm fine with these going through another appropriate tree.

Not sure in what tree these patches were created (assume some sunxi
tree), but if it conflicts with wireless-next I am pretty sure Stephen
will find that. I am fine with any tree. Patch 9 indeed has some magic
bits that need some clarification, but I will sort that out with Hans.

Regards,
Arend

>> Patch 10 and 11 add the necessary dts bits to actually enable the sdio irq
>> and should go upstream through Maxime's dt tree.
>>
>> Please review / merge.
>>
>> Thanks& Regards,
>>
>> Hans
>>
>


2014-05-27 09:53:18

by Chen-Yu Tsai

[permalink] [raw]
Subject: Re: [PATCH 02/11] pinctrl: sunxi: add IRQCHIP_SKIP_SET_WAKE flag for pinctrl irq chip

On Tue, May 27, 2014 at 5:09 PM, Hans de Goede <[email protected]> wrote:
> Hi,
>
> On 05/27/2014 10:07 AM, Maxime Ripard wrote:
>> On Mon, May 26, 2014 at 09:47:57AM +0200, Hans de Goede wrote:
>>> From: Chen-Yu Tsai <[email protected]>
>>>
>>> The sunxi pinctrl irq chip driver does not support wakeup at the
>>> moment. Adding IRQCHIP_SKIP_SET_WAKE lets the irqs work with drivers
>>> using wakeup.
>>>
>>> Also add a name to the irq chip.
>>>
>>> Signed-off-by: Chen-Yu Tsai <[email protected]>
>>> Signed-off-by: Hans de Goede <[email protected]>
>>> ---
>>> drivers/pinctrl/sunxi/pinctrl-sunxi.c | 2 ++
>>> 1 file changed, 2 insertions(+)
>>>
>>> diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
>>> index db9ccd6..ec60c2e 100644
>>> --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
>>> +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
>>> @@ -646,6 +646,8 @@ static struct irq_chip sunxi_pinctrl_irq_chip = {
>>> .irq_mask_ack = sunxi_pinctrl_irq_mask_ack,
>>> .irq_unmask = sunxi_pinctrl_irq_unmask,
>>> .irq_set_type = sunxi_pinctrl_irq_set_type,
>>> + .name = "sunxi-pio",
>>> + .flags = IRQCHIP_SKIP_SET_WAKE,
>>
>> I'd rather see the name set to dev_name() or something like that. This
>> will not work that great with multiple pin controller supporting
>> interrupts.
>
> That would require moving the irq_chip struct to become a member of the
> sunxi_pinctrl struct. Not undoable, but that seems like something which
> should be done in a separate patch. So shall I just drop the .name part
> of this patch for now ?

Please do. AFAIK, .name is only used for the debugfs representation.
This change was only meant for cosmetic purposes.


ChenYu

2014-05-27 09:09:58

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH 02/11] pinctrl: sunxi: add IRQCHIP_SKIP_SET_WAKE flag for pinctrl irq chip

Hi,

On 05/27/2014 10:07 AM, Maxime Ripard wrote:
> On Mon, May 26, 2014 at 09:47:57AM +0200, Hans de Goede wrote:
>> From: Chen-Yu Tsai <[email protected]>
>>
>> The sunxi pinctrl irq chip driver does not support wakeup at the
>> moment. Adding IRQCHIP_SKIP_SET_WAKE lets the irqs work with drivers
>> using wakeup.
>>
>> Also add a name to the irq chip.
>>
>> Signed-off-by: Chen-Yu Tsai <[email protected]>
>> Signed-off-by: Hans de Goede <[email protected]>
>> ---
>> drivers/pinctrl/sunxi/pinctrl-sunxi.c | 2 ++
>> 1 file changed, 2 insertions(+)
>>
>> diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
>> index db9ccd6..ec60c2e 100644
>> --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
>> +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
>> @@ -646,6 +646,8 @@ static struct irq_chip sunxi_pinctrl_irq_chip = {
>> .irq_mask_ack = sunxi_pinctrl_irq_mask_ack,
>> .irq_unmask = sunxi_pinctrl_irq_unmask,
>> .irq_set_type = sunxi_pinctrl_irq_set_type,
>> + .name = "sunxi-pio",
>> + .flags = IRQCHIP_SKIP_SET_WAKE,
>
> I'd rather see the name set to dev_name() or something like that. This
> will not work that great with multiple pin controller supporting
> interrupts.

That would require moving the irq_chip struct to become a member of the
sunxi_pinctrl struct. Not undoable, but that seems like something which
should be done in a separate patch. So shall I just drop the .name part
of this patch for now ?

Regards,

Hans

2014-05-28 08:53:20

by Linus Walleij

[permalink] [raw]
Subject: Re: [linux-sunxi] Re: [PATCH 01/11] pinctrl: sunxi: create irq/pin mapping during init

On Tue, May 27, 2014 at 4:21 PM, Chen-Yu Tsai <[email protected]> wrote:
> On Tue, May 27, 2014 at 10:11 PM, Linus Walleij

>> I tried to hack the sunxi driver to even use the gpiolib
>> irqchip helpers but exactly this complex map thing in
>> ->irq_array[] git me stuck. If any of you guys could be so
>> nice to take a stab at this (compare to other commits
>> converting drivers to use gpiolibs irqchip helpers) then
>> I'd be very happy.
>
> We still need to rework the whole irqchip stuff for sun6i/sun8i,
> which have 1 parent interrupt per EINT capable pin bank.
>
> Earlier discussions with Maxime (on IRC IIRC) suggested moving this
> over to gpiolib irqchip helpers might be more work than using our own
> irqchip implementation, requiring 1 gpiochip per pin group? (not sure)

OK then keep your current code. I do not intend to cover all
cases in the world with these helpers, just the simple cases.
Complex hardware merits complex code.

Yours,
Linus Walleij

2014-05-26 07:49:28

by Hans de Goede

[permalink] [raw]
Subject: [PATCH 06/11] mmc: Add SDIO function devicetree subnode parsing

From: Sascha Hauer <[email protected]>

This adds SDIO devicetree subnode parsing to the mmc core. While
SDIO devices are runtime probable they sometimes need nonprobable
additional information on embedded systems, like an additional gpio
interrupt or a clock. This patch makes it possible to supply this
information from the devicetree. SDIO drivers will find a pointer
to the devicenode in their devices of_node pointer.

Signed-off-by: Sascha Hauer <[email protected]>
Signed-off-by: Hans de Goede <[email protected]>
---
Documentation/devicetree/bindings/mmc/mmc.txt | 30 +++++++++++++++++++++++++++
drivers/mmc/core/bus.c | 14 +++++++++++++
drivers/mmc/core/core.c | 25 ++++++++++++++++++++++
drivers/mmc/core/core.h | 3 +++
drivers/mmc/core/sdio_bus.c | 16 ++++++++++++++
5 files changed, 88 insertions(+)

diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt
index 9dce540..5e54089 100644
--- a/Documentation/devicetree/bindings/mmc/mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc.txt
@@ -60,6 +60,15 @@ Optional SDIO properties:
- keep-power-in-suspend: Preserves card power during a suspend/resume cycle
- enable-sdio-wakeup: Enables wake up of host system on SDIO IRQ assertion

+Function subnodes:
+On embedded systems the cards connected to a host may need additional properties.
+These can be specified in subnodes to the host controller node. The subnodes are
+identified by the standard 'reg' property.
+Required properties:
+- reg: Must contain the SDIO function number of the function this subnode describes.
+ A value of 0 denotes the memory SD function, values from 1 to 7 denote the
+ SDIO functions.
+
Example:

sdhci@ab000000 {
@@ -74,3 +83,24 @@ sdhci@ab000000 {
keep-power-in-suspend;
enable-sdio-wakeup;
}
+
+Example with SDIO subnode:
+
+sdhci@ab000000 {
+ compatible = "sdhci";
+ reg = <0xab000000 0x200>;
+ interrupts = <23>;
+ bus-width = <4>;
+ cd-gpios = <&gpio 69 0>;
+ cd-inverted;
+ wp-gpios = <&gpio 70 0>;
+ max-frequency = <50000000>;
+ keep-power-in-suspend;
+ enable-sdio-wakeup;
+
+ func@2 {
+ reg = <2>;
+ reset-gpios = <&gpio 69 0>;
+ clock-frequency = <26000000>;
+ };
+}
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 8246448..58d12b7 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -16,6 +16,7 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/stat.h>
+#include <linux/of.h>
#include <linux/pm_runtime.h>

#include <linux/mmc/card.h>
@@ -289,6 +290,16 @@ struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type)
return card;
}

+static void mmc_set_of_node(struct mmc_card *card)
+{
+ struct mmc_host *host = card->host;
+
+ if (!host->parent->of_node)
+ return;
+
+ card->dev.of_node = mmc_of_find_child_device(host->parent->of_node, 0);
+}
+
/*
* Register a new MMC card with the driver model.
*/
@@ -359,6 +370,8 @@ int mmc_add_card(struct mmc_card *card)
#endif
mmc_init_context_info(card->host);

+ mmc_set_of_node(card);
+
ret = device_add(&card->dev);
if (ret)
return ret;
@@ -387,6 +400,7 @@ void mmc_remove_card(struct mmc_card *card)
mmc_hostname(card->host), card->rca);
}
device_del(&card->dev);
+ of_node_put(card->dev.of_node);
}

put_device(&card->dev);
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index acbc3f2..6f86949 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1201,6 +1201,31 @@ EXPORT_SYMBOL(mmc_of_parse_voltage);

#endif /* CONFIG_OF */

+static int mmc_of_get_func_num(struct device_node *node)
+{
+ u32 reg;
+ int ret;
+
+ ret = of_property_read_u32(node, "reg", &reg);
+ if (ret < 0)
+ return ret;
+
+ return reg;
+}
+
+struct device_node *mmc_of_find_child_device(struct device_node *parent,
+ unsigned func_num)
+{
+ struct device_node *node;
+
+ for_each_child_of_node(parent, node) {
+ if (mmc_of_get_func_num(node) == func_num)
+ return node;
+ }
+
+ return NULL;
+}
+
#ifdef CONFIG_REGULATOR

/**
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 443a584..65615f3 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -32,6 +32,9 @@ struct mmc_bus_ops {
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
void mmc_detach_bus(struct mmc_host *host);

+struct device_node *mmc_of_find_child_device(struct device_node *parent,
+ unsigned func_num);
+
void mmc_init_erase(struct mmc_card *card);

void mmc_set_chip_select(struct mmc_host *host, int mode);
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
index 92d1ba8..0bff9e8 100644
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -22,6 +22,7 @@
#include <linux/mmc/host.h>
#include <linux/mmc/sdio_func.h>

+#include "core.h"
#include "sdio_cis.h"
#include "sdio_bus.h"

@@ -314,6 +315,19 @@ static void sdio_acpi_set_handle(struct sdio_func *func)
static inline void sdio_acpi_set_handle(struct sdio_func *func) {}
#endif

+#include <linux/of.h>
+
+void sdio_set_of_node(struct sdio_func *func)
+{
+ struct mmc_host *host = func->card->host;
+
+ if (!host->parent->of_node)
+ return;
+
+ func->dev.of_node = mmc_of_find_child_device(host->parent->of_node,
+ func->num);
+}
+
/*
* Register a new SDIO function with the driver model.
*/
@@ -323,6 +337,7 @@ int sdio_add_func(struct sdio_func *func)

dev_set_name(&func->dev, "%s:%d", mmc_card_id(func->card), func->num);

+ sdio_set_of_node(func);
sdio_acpi_set_handle(func);
ret = device_add(&func->dev);
if (ret == 0) {
@@ -346,6 +361,7 @@ void sdio_remove_func(struct sdio_func *func)

acpi_dev_pm_detach(&func->dev, false);
device_del(&func->dev);
+ of_node_put(func->dev.of_node);
put_device(&func->dev);
}

--
1.9.3


2014-05-27 21:29:49

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH 09/11] brcmfmac: Fix OOB interrupt not working for BCM43362

Hi,

On 05/27/2014 07:03 PM, Arend van Spriel wrote:
> On 05/26/14 09:48, Hans de Goede wrote:
>> It has taken me a long long time to get the OOB interrupt working on the
>> AP6210 sdio wifi/bt module found on various Allwinner A20 boards. In the
>> end I found these magic register pokes in the cubietruck kernel tree:
>> https://github.com/cubieboard2/linux-sunxi/commit/7f08ba395617d17e7a711507503d89a50406fe7a
>>
>> I'm not entirely sure if this specific to the AP6210 module, or if this
>> should be done for all BCM43362 sdio devices.
>
> Let keep it as this for now. I added some remarks below.
>
> Regards,
> Arend
>
>> Signed-off-by: Hans de Goede<[email protected]>
>> ---
>> drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 18 ++++++++++++++++++
>> 1 file changed, 18 insertions(+)
>>
>> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
>> index 0fc707c..2369a0f 100644
>> --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
>> +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
>> @@ -39,7 +39,9 @@
>> #include<brcm_hw_ids.h>
>> #include<brcmu_utils.h>
>> #include<brcmu_wifi.h>
>> +#include<chipcommon.h>
>> #include<soc.h>
>> +#include "chip.h"
>> #include "dhd_bus.h"
>> #include "dhd_dbg.h"
>> #include "sdio_host.h"
>> @@ -119,6 +121,7 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
>> {
>> int ret = 0;
>> u8 data;
>> + u32 addr, gpiocontrol;
>> unsigned long flags;
>>
>> if ((sdiodev->pdata)&& (sdiodev->pdata->oob_irq_supported)) {
>> @@ -148,6 +151,21 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
>>
>> sdio_claim_host(sdiodev->func[1]);
>>
>> + if (sdiodev->bus_if->chip == BCM43362_CHIP_ID) {
> + /* assign GPIO to SDIO core */
>> + addr = CORE_CC_REG(SI_ENUM_BASE, gpiocontrol);
>> + gpiocontrol = brcmf_sdiod_regrl(sdiodev, addr,&ret);
>> + gpiocontrol |= 0x2;
>> + brcmf_sdiod_regwl(sdiodev, addr, gpiocontrol,&ret);
>> +
>> + /* SPROM_ADDR_HIGH ? perhaps the defines name is off */
>
> These names are all off. These should be:
> SBSDIO_SPROM_ADDR_HIGH = SBSDIO_GPIO_SELECT
> SBSDIO_CHIP_CTRL_DATA = SBSDIO_GPIO_OUT
> SBSDIO_CHIP_CTRL_EN = SBSDIO_GPIO_EN

Ok, so I guess I should do a pre-patch adding defines for these, should
these replace the existing defines for these addresses in:
drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h

Or should the pre-patch add defines with the new names and keep the old
ones ?

Regards,

Hans

2014-05-26 07:49:09

by Hans de Goede

[permalink] [raw]
Subject: [PATCH 04/11] pinctrl: sunxi: Properly handle level triggered gpio interrupts

For level triggered gpio interrupts we need to use handle_fasteoi_irq,
like we do with the irq-sunxi-nmi driver. This is necessary to give threaded
interrupt handlers a chance to actuall clear the source of the interrupt
(which may involve sleeping waitnig for i2c / spi / mmc transfers), before
acknowledging the interrupt.

Signed-off-by: Hans de Goede <[email protected]>
---
drivers/pinctrl/sunxi/pinctrl-sunxi.c | 71 +++++++++++++++++++++++++++--------
1 file changed, 56 insertions(+), 15 deletions(-)

diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index d1675c9..083691e 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -31,6 +31,12 @@
#include "../core.h"
#include "pinctrl-sunxi.h"

+static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type);
+static void sunxi_pinctrl_irq_mask_ack(struct irq_data *d);
+static void sunxi_pinctrl_irq_mask(struct irq_data *d);
+static void sunxi_pinctrl_irq_unmask(struct irq_data *d);
+static void sunxi_pinctrl_irq_ack(struct irq_data *d);
+
static struct sunxi_pinctrl_group *
sunxi_pinctrl_find_group_by_name(struct sunxi_pinctrl *pctl, const char *group)
{
@@ -535,11 +541,31 @@ static int sunxi_pinctrl_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
return irq_find_mapping(pctl->domain, desc->irqnum);
}

+static struct irq_chip sunxi_pinctrl_edge_irq_chip = {
+ .irq_mask = sunxi_pinctrl_irq_mask,
+ .irq_mask_ack = sunxi_pinctrl_irq_mask_ack,
+ .irq_unmask = sunxi_pinctrl_irq_unmask,
+ .irq_ack = sunxi_pinctrl_irq_ack,
+ .irq_set_type = sunxi_pinctrl_irq_set_type,
+ .name = "sunxi-pio",
+ .flags = IRQCHIP_SKIP_SET_WAKE,
+};
+
+static struct irq_chip sunxi_pinctrl_level_irq_chip = {
+ .irq_mask = sunxi_pinctrl_irq_mask,
+ .irq_mask_ack = sunxi_pinctrl_irq_mask_ack,
+ .irq_unmask = sunxi_pinctrl_irq_unmask,
+ .irq_eoi = sunxi_pinctrl_irq_ack,
+ .irq_set_type = sunxi_pinctrl_irq_set_type,
+ .name = "sunxi-pio",
+ .flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_EOI_THREADED |
+ IRQCHIP_EOI_IF_HANDLED,
+};

-static int sunxi_pinctrl_irq_set_type(struct irq_data *d,
- unsigned int type)
+static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type)
{
struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
+ struct irq_desc *desc = container_of(d, struct irq_desc, irq_data);
u32 reg = sunxi_irq_cfg_reg(d->hwirq);
u8 index = sunxi_irq_cfg_offset(d->hwirq);
struct sunxi_desc_function *func;
@@ -567,6 +593,14 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d,
return -EINVAL;
}

+ if (type & IRQ_TYPE_LEVEL_MASK) {
+ d->chip = &sunxi_pinctrl_level_irq_chip;
+ desc->handle_irq = handle_fasteoi_irq;
+ } else {
+ d->chip = &sunxi_pinctrl_edge_irq_chip;
+ desc->handle_irq = handle_edge_irq;
+ }
+
spin_lock_irqsave(&pctl->lock, flags);

regval = readl(pctl->membase + reg);
@@ -640,14 +674,20 @@ static void sunxi_pinctrl_irq_unmask(struct irq_data *d)
spin_unlock_irqrestore(&pctl->lock, flags);
}

-static struct irq_chip sunxi_pinctrl_irq_chip = {
- .irq_mask = sunxi_pinctrl_irq_mask,
- .irq_mask_ack = sunxi_pinctrl_irq_mask_ack,
- .irq_unmask = sunxi_pinctrl_irq_unmask,
- .irq_set_type = sunxi_pinctrl_irq_set_type,
- .name = "sunxi-pio",
- .flags = IRQCHIP_SKIP_SET_WAKE,
-};
+static void sunxi_pinctrl_irq_ack(struct irq_data *d)
+{
+ struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
+ u32 status_reg = sunxi_irq_status_reg(d->hwirq);
+ u8 status_idx = sunxi_irq_status_offset(d->hwirq);
+ unsigned long flags;
+
+ spin_lock_irqsave(&pctl->lock, flags);
+
+ /* Clear the IRQ */
+ writel(1 << status_idx, pctl->membase + status_reg);
+
+ spin_unlock_irqrestore(&pctl->lock, flags);
+}

static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
{
@@ -655,9 +695,6 @@ static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
struct sunxi_pinctrl *pctl = irq_get_handler_data(irq);
const unsigned long reg = readl(pctl->membase + IRQ_STATUS_REG);

- /* Clear all interrupts */
- writel(reg, pctl->membase + IRQ_STATUS_REG);
-
if (reg) {
int irqoffset;

@@ -892,11 +929,15 @@ int sunxi_pinctrl_init(struct platform_device *pdev,
for (i = 0; i < SUNXI_IRQ_NUMBER; i++) {
int irqno = irq_create_mapping(pctl->domain, i);

- irq_set_chip_and_handler(irqno, &sunxi_pinctrl_irq_chip,
- handle_simple_irq);
+ irq_set_chip_and_handler(irqno, &sunxi_pinctrl_edge_irq_chip,
+ handle_edge_irq);
irq_set_chip_data(irqno, pctl);
};

+ /* Mask and clear all IRQs before registering a handler */
+ writel(0, pctl->membase + IRQ_CTRL_REG);
+ writel(0xffffffff, pctl->membase + IRQ_STATUS_REG);
+
irq_set_chained_handler(pctl->irq, sunxi_pinctrl_irq_handler);
irq_set_handler_data(pctl->irq, pctl);

--
1.9.3


2014-05-27 08:10:03

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH 02/11] pinctrl: sunxi: add IRQCHIP_SKIP_SET_WAKE flag for pinctrl irq chip

On Mon, May 26, 2014 at 09:47:57AM +0200, Hans de Goede wrote:
> From: Chen-Yu Tsai <[email protected]>
>
> The sunxi pinctrl irq chip driver does not support wakeup at the
> moment. Adding IRQCHIP_SKIP_SET_WAKE lets the irqs work with drivers
> using wakeup.
>
> Also add a name to the irq chip.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>
> Signed-off-by: Hans de Goede <[email protected]>
> ---
> drivers/pinctrl/sunxi/pinctrl-sunxi.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
> index db9ccd6..ec60c2e 100644
> --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
> +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
> @@ -646,6 +646,8 @@ static struct irq_chip sunxi_pinctrl_irq_chip = {
> .irq_mask_ack = sunxi_pinctrl_irq_mask_ack,
> .irq_unmask = sunxi_pinctrl_irq_unmask,
> .irq_set_type = sunxi_pinctrl_irq_set_type,
> + .name = "sunxi-pio",
> + .flags = IRQCHIP_SKIP_SET_WAKE,

I'd rather see the name set to dev_name() or something like that. This
will not work that great with multiple pin controller supporting
interrupts.

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (1.22 kB)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-05-26 07:49:25

by Hans de Goede

[permalink] [raw]
Subject: [PATCH 11/11] ARM: dts: sun7i: Add OOB irq support to boards with broadcom sdio wifi

Signed-off-by: Hans de Goede <[email protected]>
---
arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 12 ++++++++++++
arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts | 12 ++++++++++++
2 files changed, 24 insertions(+)

diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
index 3931986..d3dcd8e 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
@@ -31,12 +31,24 @@
};

mmc3: mmc@01c12000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
pinctrl-names = "default";
pinctrl-0 = <&mmc3_pins_a>;
vmmc-supply = <&reg_vmmc3>;
bus-width = <4>;
non-removable;
status = "okay";
+
+ brcmf: bcrmf@1 {
+ reg = <1>;
+ compatible = "brcm,bcm43xx-fmac";
+ interrupt-parent = <&pio>;
+ interrupts = <10 8>; /* PH10 / EINT10 */
+ interrupt-names = "host-wake";
+ status = "okay";
+ };
};

usbphy: phy@01c13400 {
diff --git a/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts b/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts
index 4aad09c..806f236 100644
--- a/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts
+++ b/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts
@@ -29,12 +29,24 @@
};

mmc3: mmc@01c12000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
pinctrl-names = "default";
pinctrl-0 = <&mmc3_pins_a>;
vmmc-supply = <&reg_vmmc3>;
bus-width = <4>;
non-removable;
status = "okay";
+
+ brcmf: bcrmf@1 {
+ reg = <1>;
+ compatible = "brcm,bcm43xx-fmac";
+ interrupt-parent = <&pio>;
+ interrupts = <10 8>; /* PH10 / EINT10 */
+ interrupt-names = "host-wake";
+ status = "okay";
+ };
};

usbphy: phy@01c13400 {
--
1.9.3


2014-05-26 07:48:51

by Hans de Goede

[permalink] [raw]
Subject: [PATCH 02/11] pinctrl: sunxi: add IRQCHIP_SKIP_SET_WAKE flag for pinctrl irq chip

From: Chen-Yu Tsai <[email protected]>

The sunxi pinctrl irq chip driver does not support wakeup at the
moment. Adding IRQCHIP_SKIP_SET_WAKE lets the irqs work with drivers
using wakeup.

Also add a name to the irq chip.

Signed-off-by: Chen-Yu Tsai <[email protected]>
Signed-off-by: Hans de Goede <[email protected]>
---
drivers/pinctrl/sunxi/pinctrl-sunxi.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index db9ccd6..ec60c2e 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -646,6 +646,8 @@ static struct irq_chip sunxi_pinctrl_irq_chip = {
.irq_mask_ack = sunxi_pinctrl_irq_mask_ack,
.irq_unmask = sunxi_pinctrl_irq_unmask,
.irq_set_type = sunxi_pinctrl_irq_set_type,
+ .name = "sunxi-pio",
+ .flags = IRQCHIP_SKIP_SET_WAKE,
};

static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
--
1.9.3


2014-05-28 10:30:13

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH 02/11] pinctrl: sunxi: add IRQCHIP_SKIP_SET_WAKE flag for pinctrl irq chip

On Tue, May 27, 2014 at 06:14:31PM +0200, Tomasz Figa wrote:
> On 27.05.2014 10:07, Maxime Ripard wrote:
> > On Mon, May 26, 2014 at 09:47:57AM +0200, Hans de Goede wrote:
> >> From: Chen-Yu Tsai <[email protected]>
> >>
> >> The sunxi pinctrl irq chip driver does not support wakeup at the
> >> moment. Adding IRQCHIP_SKIP_SET_WAKE lets the irqs work with
> >> drivers using wakeup.
> >>
> >> Also add a name to the irq chip.
> >>
> >> Signed-off-by: Chen-Yu Tsai <[email protected]> Signed-off-by: Hans
> >> de Goede <[email protected]> ---
> >> drivers/pinctrl/sunxi/pinctrl-sunxi.c | 2 ++ 1 file changed, 2
> >> insertions(+)
> >>
> >> diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
> >> b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index db9ccd6..ec60c2e
> >> 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++
> >> b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -646,6 +646,8 @@
> >> static struct irq_chip sunxi_pinctrl_irq_chip = { .irq_mask_ack =
> >> sunxi_pinctrl_irq_mask_ack, .irq_unmask =
> >> sunxi_pinctrl_irq_unmask, .irq_set_type =
> >> sunxi_pinctrl_irq_set_type, + .name = "sunxi-pio", + .flags =
> >> IRQCHIP_SKIP_SET_WAKE,
> >
> > I'd rather see the name set to dev_name() or something like that.
> > This will not work that great with multiple pin controller
> > supporting interrupts.
>
> Correct me if I'm wrong, but I've always thought that struct irq_chip
> describes a class of IRQ controllers, not particular instances.

It's not said as such in <linux/irq.h>, but maybe..

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (1.58 kB)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-05-26 07:49:15

by Hans de Goede

[permalink] [raw]
Subject: [PATCH 09/11] brcmfmac: Fix OOB interrupt not working for BCM43362

It has taken me a long long time to get the OOB interrupt working on the
AP6210 sdio wifi/bt module found on various Allwinner A20 boards. In the
end I found these magic register pokes in the cubietruck kernel tree:
https://github.com/cubieboard2/linux-sunxi/commit/7f08ba395617d17e7a711507503d89a50406fe7a

I'm not entirely sure if this specific to the AP6210 module, or if this
should be done for all BCM43362 sdio devices.

Signed-off-by: Hans de Goede <[email protected]>
---
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)

diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
index 0fc707c..2369a0f 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
@@ -39,7 +39,9 @@
#include <brcm_hw_ids.h>
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
+#include <chipcommon.h>
#include <soc.h>
+#include "chip.h"
#include "dhd_bus.h"
#include "dhd_dbg.h"
#include "sdio_host.h"
@@ -119,6 +121,7 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
{
int ret = 0;
u8 data;
+ u32 addr, gpiocontrol;
unsigned long flags;

if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) {
@@ -148,6 +151,21 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)

sdio_claim_host(sdiodev->func[1]);

+ if (sdiodev->bus_if->chip == BCM43362_CHIP_ID) {
+ addr = CORE_CC_REG(SI_ENUM_BASE, gpiocontrol);
+ gpiocontrol = brcmf_sdiod_regrl(sdiodev, addr, &ret);
+ gpiocontrol |= 0x2;
+ brcmf_sdiod_regwl(sdiodev, addr, gpiocontrol, &ret);
+
+ /* SPROM_ADDR_HIGH ? perhaps the defines name is off */
+ brcmf_sdiod_regwb(sdiodev, SBSDIO_SPROM_ADDR_HIGH, 0xf,
+ &ret);
+ brcmf_sdiod_regwb(sdiodev, SBSDIO_CHIP_CTRL_DATA, 0,
+ &ret);
+ brcmf_sdiod_regwb(sdiodev, SBSDIO_CHIP_CTRL_EN, 0x2,
+ &ret);
+ }
+
/* must configure SDIO_CCCR_IENx to enable irq */
data = brcmf_sdiod_regrb(sdiodev, SDIO_CCCR_IENx, &ret);
data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
--
1.9.3


2014-05-28 09:07:33

by Arend van Spriel

[permalink] [raw]
Subject: Re: [PATCH 09/11] brcmfmac: Fix OOB interrupt not working for BCM43362

On 05/27/14 23:28, Hans de Goede wrote:
> Hi,
>
> On 05/27/2014 07:03 PM, Arend van Spriel wrote:
>> On 05/26/14 09:48, Hans de Goede wrote:
>>> It has taken me a long long time to get the OOB interrupt working on the
>>> AP6210 sdio wifi/bt module found on various Allwinner A20 boards. In the
>>> end I found these magic register pokes in the cubietruck kernel tree:
>>> https://github.com/cubieboard2/linux-sunxi/commit/7f08ba395617d17e7a711507503d89a50406fe7a
>>>
>>>
>>> I'm not entirely sure if this specific to the AP6210 module, or if this
>>> should be done for all BCM43362 sdio devices.
>>
>> Let keep it as this for now. I added some remarks below.
>>
>> Regards,
>> Arend
>>
>>> Signed-off-by: Hans de Goede<[email protected]>
>>> ---
>>> drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 18 ++++++++++++++++++
>>> 1 file changed, 18 insertions(+)
>>>
>>> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
>>> b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
>>> index 0fc707c..2369a0f 100644
>>> --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
>>> +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
>>> @@ -39,7 +39,9 @@
>>> #include<brcm_hw_ids.h>
>>> #include<brcmu_utils.h>
>>> #include<brcmu_wifi.h>
>>> +#include<chipcommon.h>
>>> #include<soc.h>
>>> +#include "chip.h"
>>> #include "dhd_bus.h"
>>> #include "dhd_dbg.h"
>>> #include "sdio_host.h"
>>> @@ -119,6 +121,7 @@ int brcmf_sdiod_intr_register(struct
>>> brcmf_sdio_dev *sdiodev)
>>> {
>>> int ret = 0;
>>> u8 data;
>>> + u32 addr, gpiocontrol;
>>> unsigned long flags;
>>>
>>> if ((sdiodev->pdata)&& (sdiodev->pdata->oob_irq_supported)) {
>>> @@ -148,6 +151,21 @@ int brcmf_sdiod_intr_register(struct
>>> brcmf_sdio_dev *sdiodev)
>>>
>>> sdio_claim_host(sdiodev->func[1]);
>>>
>>> + if (sdiodev->bus_if->chip == BCM43362_CHIP_ID) {
>> + /* assign GPIO to SDIO core */
>>> + addr = CORE_CC_REG(SI_ENUM_BASE, gpiocontrol);
>>> + gpiocontrol = brcmf_sdiod_regrl(sdiodev, addr,&ret);
>>> + gpiocontrol |= 0x2;
>>> + brcmf_sdiod_regwl(sdiodev, addr, gpiocontrol,&ret);
>>> +
>>> + /* SPROM_ADDR_HIGH ? perhaps the defines name is off */
>>
>> These names are all off. These should be:
>> SBSDIO_SPROM_ADDR_HIGH = SBSDIO_GPIO_SELECT
>> SBSDIO_CHIP_CTRL_DATA = SBSDIO_GPIO_OUT
>> SBSDIO_CHIP_CTRL_EN = SBSDIO_GPIO_EN
>
> Ok, so I guess I should do a pre-patch adding defines for these, should
> these replace the existing defines for these addresses in:
> drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
>
> Or should the pre-patch add defines with the new names and keep the old
> ones ?

These defines are not used in the code so go ahead and replace them. It
needs some more cleanup, but I can do a subsequent patch for that.

Gr. AvS

2014-05-27 14:18:30

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH 03/11] pinctrl: sunxi: Move setting of mux to irq type from unmask to set_type

On Mon, May 26, 2014 at 9:47 AM, Hans de Goede <[email protected]> wrote:

> With level triggered interrupt mask / unmask will get called for each
> interrupt, doing the somewhat expensive mux setting on each unmask thus is
> not a good idea. Instead move it to the set_type callback, which is typically
> done only once for each irq.
>
> Signed-off-by: Hans de Goede <[email protected]>

Yes move it out of mask/unmask but no, not into set_type().

Can you not use the irqchip startup()/shutdown() callbacks
instead?

And how come we have no clean separation between gpiochip
and the pinmux parts here, why cant we just call
pinctrl_request_gpio() and pinctrl_free_gpio() here instead?
Or maybe pinctrl_gpio_direction_input() and have that set
up the muxing in the pinctrl driver side?

It looks slightly convoluted.

Yours,
Linus Walleij

2014-05-27 16:14:36

by Tomasz Figa

[permalink] [raw]
Subject: Re: [PATCH 02/11] pinctrl: sunxi: add IRQCHIP_SKIP_SET_WAKE flag for pinctrl irq chip

On 27.05.2014 10:07, Maxime Ripard wrote:
> On Mon, May 26, 2014 at 09:47:57AM +0200, Hans de Goede wrote:
>> From: Chen-Yu Tsai <[email protected]>
>>
>> The sunxi pinctrl irq chip driver does not support wakeup at the
>> moment. Adding IRQCHIP_SKIP_SET_WAKE lets the irqs work with
>> drivers using wakeup.
>>
>> Also add a name to the irq chip.
>>
>> Signed-off-by: Chen-Yu Tsai <[email protected]> Signed-off-by: Hans
>> de Goede <[email protected]> ---
>> drivers/pinctrl/sunxi/pinctrl-sunxi.c | 2 ++ 1 file changed, 2
>> insertions(+)
>>
>> diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
>> b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index db9ccd6..ec60c2e
>> 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++
>> b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -646,6 +646,8 @@
>> static struct irq_chip sunxi_pinctrl_irq_chip = { .irq_mask_ack =
>> sunxi_pinctrl_irq_mask_ack, .irq_unmask =
>> sunxi_pinctrl_irq_unmask, .irq_set_type =
>> sunxi_pinctrl_irq_set_type, + .name = "sunxi-pio", + .flags =
>> IRQCHIP_SKIP_SET_WAKE,
>
> I'd rather see the name set to dev_name() or something like that.
> This will not work that great with multiple pin controller
> supporting interrupts.

Correct me if I'm wrong, but I've always thought that struct irq_chip
describes a class of IRQ controllers, not particular instances.

Best regards,
Tomasz

2014-05-27 08:05:04

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH 01/11] pinctrl: sunxi: create irq/pin mapping during init

Hi,

On Mon, May 26, 2014 at 09:47:56AM +0200, Hans de Goede wrote:
> From: Chen-Yu Tsai <[email protected]>
>
> The irq/pin mapping is used to lookup the pin to mux to the irq
> function when the irq is enabled. It is created when gpio_to_irq
> is called. Creating the mapping during init allows us to map the
> interrupts directly from the device tree.

Can you be a bit more precise on this?

What is the issue that this patch fix?

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (548.00 B)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-05-26 07:49:06

by Hans de Goede

[permalink] [raw]
Subject: [PATCH 05/11] pinctrl: sunxi: Define enable / disable irq callbacks for level triggered irqs

Some drivers use disable_irq / enable_irq and do the work clearing the source
in another thread instead of using a threaded interrupt handler.

The irqchip used not having irq_disable and irq_enable callbacks in this case,
will lead to unnecessary spurious interrupts:

On a disable_irq in a chip without a handller for this, the irq core will
remember the disable, but not actually call into the irqchip. With a level
triggered interrupt (where the source has not been cleared) this will lead
to an immediate retrigger, at which point the irq-core will mask the irq.
So having an irq_disable callback in the irqchip will save us the interrupt
firing a 2nd time for nothing.

Drivers using disable / enable_irq like this, will call enable_irq when
they finally have cleared the interrupt source, without an enable_irq callback,
this will turn into an unmask, at which point the irq will trigger immediately
because when it was originally acked the level was still high, so the ack was
a nop.

Signed-off-by: Hans de Goede <[email protected]>
---
drivers/pinctrl/sunxi/pinctrl-sunxi.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)

diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index 083691e..66a36cf 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -36,6 +36,7 @@ static void sunxi_pinctrl_irq_mask_ack(struct irq_data *d);
static void sunxi_pinctrl_irq_mask(struct irq_data *d);
static void sunxi_pinctrl_irq_unmask(struct irq_data *d);
static void sunxi_pinctrl_irq_ack(struct irq_data *d);
+static void sunxi_pinctrl_irq_ack_unmask(struct irq_data *d);

static struct sunxi_pinctrl_group *
sunxi_pinctrl_find_group_by_name(struct sunxi_pinctrl *pctl, const char *group)
@@ -556,6 +557,10 @@ static struct irq_chip sunxi_pinctrl_level_irq_chip = {
.irq_mask_ack = sunxi_pinctrl_irq_mask_ack,
.irq_unmask = sunxi_pinctrl_irq_unmask,
.irq_eoi = sunxi_pinctrl_irq_ack,
+ /* Define irq_enable / disable to avoid spurious irqs for drivers
+ * using these to suppress irqs while they clear the irq source */
+ .irq_enable = sunxi_pinctrl_irq_ack_unmask,
+ .irq_disable = sunxi_pinctrl_irq_mask,
.irq_set_type = sunxi_pinctrl_irq_set_type,
.name = "sunxi-pio",
.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_EOI_THREADED |
@@ -689,6 +694,28 @@ static void sunxi_pinctrl_irq_ack(struct irq_data *d)
spin_unlock_irqrestore(&pctl->lock, flags);
}

+static void sunxi_pinctrl_irq_ack_unmask(struct irq_data *d)
+{
+ struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d);
+ u32 ctrl_reg = sunxi_irq_ctrl_reg(d->hwirq);
+ u8 ctrl_idx = sunxi_irq_ctrl_offset(d->hwirq);
+ u32 status_reg = sunxi_irq_status_reg(d->hwirq);
+ u8 status_idx = sunxi_irq_status_offset(d->hwirq);
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&pctl->lock, flags);
+
+ /* Clear the IRQ */
+ writel(1 << status_idx, pctl->membase + status_reg);
+
+ /* Unmask the IRQ */
+ val = readl(pctl->membase + ctrl_reg);
+ writel(val | (1 << ctrl_idx), pctl->membase + ctrl_reg);
+
+ spin_unlock_irqrestore(&pctl->lock, flags);
+}
+
static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
{
struct irq_chip *chip = irq_get_chip(irq);
--
1.9.3


2014-05-27 15:30:19

by John W. Linville

[permalink] [raw]
Subject: Re: [PATCH 00/11] sdio wifi oob irq support for sunxi

On Mon, May 26, 2014 at 09:47:55AM +0200, Hans de Goede wrote:
> Hi All,
>
> Here is a patch series adding support for oob irqs for the ap6210 sdio wifi
> modules found on various Allwinner A20 boards.
>
> A lot of it is ground work which should be useful for adding oob irq support
> to other sdio wifi models too.
>
> The first 5 patches are sunxi pinctrl patches and should go upstream through
> the pinctrl tree.
>
> Patch 6 adds generic support for having per sdio function child nodes in
> devicetree and should go upstream through the mmc tree.
>
> Patch 7 and 8 add oob irq support to the brcmfmac driver. Patch 9 pokes some
> magic bits needed to enable the oob irq, this was taken from an android code
> dump and good do with a good review from someone from Broadcom, Arend ?

If Arend approves, I'm fine with these going through another appropriate tree.

> Patch 10 and 11 add the necessary dts bits to actually enable the sdio irq
> and should go upstream through Maxime's dt tree.
>
> Please review / merge.
>
> Thanks & Regards,
>
> Hans
>

--
John W. Linville Someday the world will need a hero, and you
[email protected] might be all we have. Be ready.

2014-05-28 09:40:05

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH 03/11] pinctrl: sunxi: Move setting of mux to irq type from unmask to set_type

On Tue, May 27, 2014 at 11:01:03AM +0200, Hans de Goede wrote:
> Hi,
>
> On 05/27/2014 10:09 AM, Maxime Ripard wrote:
> > On Mon, May 26, 2014 at 09:47:58AM +0200, Hans de Goede wrote:
> >> With level triggered interrupt mask / unmask will get called for each
> >> interrupt, doing the somewhat expensive mux setting on each unmask thus is
> >> not a good idea. Instead move it to the set_type callback, which is typically
> >> done only once for each irq.
> >
> > *This* is the bad idea. Nothing prevents you from calling
> > gpio_get_value whenever you just got your interrupt, that will change
> > the muxing, and never change it back, effectively breaking the
> > interrupts.
>
> Hmm, interesting point, but your assuming 2 things which are both not true:
>
> 1) That calling gpiod_get_value changes the muxing, which is not true, all
> gpiod_get_value variants end up in drivers/gpio/gpiolib.c _gpiod_get_raw_value()
> which does no such thing

Somehow I was convinced it was the case, but yeah, it doesn't really
make much sense, especially since you can get the value of an output,
without wanting to change it to input.

>
> 2) That unmask will always get called after the gpio_get_value to restore the mux
> setting for us, which is not guaranteed at all. Before this patch set pinctrl-sunxi.c
> was using handle_simple_irq which does not mask / unmask at all.
>
> And even with an irq-handler which masks / unmasks, what if the irq wakes up
> a thread and that thread then does the gpio_get_value ?
>
> Note this is *exactly* what e.g. the mmc gpio card-detect code does, it uses
> a thread to read the gpio for debouncing.
>
> Luckily 2. is not a problem, since 1. means that the mux won't get changed at all
> so we don't need to change it back.

Ok.

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (1.84 kB)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-05-27 14:21:25

by Chen-Yu Tsai

[permalink] [raw]
Subject: Re: [linux-sunxi] Re: [PATCH 01/11] pinctrl: sunxi: create irq/pin mapping during init

On Tue, May 27, 2014 at 10:11 PM, Linus Walleij
<[email protected]> wrote:
> On Mon, May 26, 2014 at 9:47 AM, Hans de Goede <[email protected]> wrote:
>
>> From: Chen-Yu Tsai <[email protected]>
>>
>> The irq/pin mapping is used to lookup the pin to mux to the irq
>> function when the irq is enabled. It is created when gpio_to_irq
>> is called. Creating the mapping during init allows us to map the
>> interrupts directly from the device tree.
>>
>> Signed-off-by: Chen-Yu Tsai <[email protected]>
>> Signed-off-by: Hans de Goede <[email protected]>
>
> This is exactly correct. Patch applied.

Thanks.

> I tried to hack the sunxi driver to even use the gpiolib
> irqchip helpers but exactly this complex map thing in
> ->irq_array[] git me stuck. If any of you guys could be so
> nice to take a stab at this (compare to other commits
> converting drivers to use gpiolibs irqchip helpers) then
> I'd be very happy.

We still need to rework the whole irqchip stuff for sun6i/sun8i,
which have 1 parent interrupt per EINT capable pin bank.

Earlier discussions with Maxime (on IRC IIRC) suggested moving this
over to gpiolib irqchip helpers might be more work than using our own
irqchip implementation, requiring 1 gpiochip per pin group? (not sure)


ChenYu

2014-05-27 14:11:10

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH 01/11] pinctrl: sunxi: create irq/pin mapping during init

On Mon, May 26, 2014 at 9:47 AM, Hans de Goede <[email protected]> wrote:

> From: Chen-Yu Tsai <[email protected]>
>
> The irq/pin mapping is used to lookup the pin to mux to the irq
> function when the irq is enabled. It is created when gpio_to_irq
> is called. Creating the mapping during init allows us to map the
> interrupts directly from the device tree.
>
> Signed-off-by: Chen-Yu Tsai <[email protected]>
> Signed-off-by: Hans de Goede <[email protected]>

This is exactly correct. Patch applied.

I tried to hack the sunxi driver to even use the gpiolib
irqchip helpers but exactly this complex map thing in
->irq_array[] git me stuck. If any of you guys could be so
nice to take a stab at this (compare to other commits
converting drivers to use gpiolibs irqchip helpers) then
I'd be very happy.

Yours,
Linus Walleij

2014-05-28 10:35:04

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH 03/11] pinctrl: sunxi: Move setting of mux to irq type from unmask to set_type

On Wed, May 28, 2014 at 11:51:52AM +0200, Hans de Goede wrote:
> Hi,
>
> On 05/28/2014 11:36 AM, Maxime Ripard wrote:
> > On Tue, May 27, 2014 at 04:18:29PM +0200, Linus Walleij wrote:
> >> On Mon, May 26, 2014 at 9:47 AM, Hans de Goede <[email protected]> wrote:
> >>
> >>> With level triggered interrupt mask / unmask will get called for each
> >>> interrupt, doing the somewhat expensive mux setting on each unmask thus is
> >>> not a good idea. Instead move it to the set_type callback, which is typically
> >>> done only once for each irq.
> >>>
> >>> Signed-off-by: Hans de Goede <[email protected]>
> >>
> >> Yes move it out of mask/unmask but no, not into set_type().
> >>
> >> Can you not use the irqchip startup()/shutdown() callbacks
> >> instead?
> >
> > I think we can use irq_request_resources then
> > https://lkml.org/lkml/2014/3/12/307
>
> Sounds good, I'll modify the patch to move it here before posting a v2 of
> this series. Note v2 likely won't happen till this weekend, -ENOTIME.
>
> > We could even merge the gpio_to_irq code into it.
>
> Erm, no we need that as a separate function for the gpio_chip's to_irq
> callback.

Linus sent a patch stating otherwise a few weeks ago, and was
suggesting moving it to irq_startup.

https://lkml.org/lkml/2014/5/9/50

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (1.37 kB)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-05-28 09:52:34

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH 03/11] pinctrl: sunxi: Move setting of mux to irq type from unmask to set_type

Hi,

On 05/28/2014 11:36 AM, Maxime Ripard wrote:
> On Tue, May 27, 2014 at 04:18:29PM +0200, Linus Walleij wrote:
>> On Mon, May 26, 2014 at 9:47 AM, Hans de Goede <[email protected]> wrote:
>>
>>> With level triggered interrupt mask / unmask will get called for each
>>> interrupt, doing the somewhat expensive mux setting on each unmask thus is
>>> not a good idea. Instead move it to the set_type callback, which is typically
>>> done only once for each irq.
>>>
>>> Signed-off-by: Hans de Goede <[email protected]>
>>
>> Yes move it out of mask/unmask but no, not into set_type().
>>
>> Can you not use the irqchip startup()/shutdown() callbacks
>> instead?
>
> I think we can use irq_request_resources then
> https://lkml.org/lkml/2014/3/12/307

Sounds good, I'll modify the patch to move it here before posting a v2 of
this series. Note v2 likely won't happen till this weekend, -ENOTIME.

> We could even merge the gpio_to_irq code into it.

Erm, no we need that as a separate function for the gpio_chip's to_irq
callback.

> It's called in __setup_irq, so it's guaranteed to be called, and it
> will bail out early without doing anything, since it's one of the
> first thing __setup_irq does.

Right, as I said above, this sounds good.

Regards,

Hans

2014-05-27 17:03:05

by Arend van Spriel

[permalink] [raw]
Subject: Re: [PATCH 09/11] brcmfmac: Fix OOB interrupt not working for BCM43362

On 05/26/14 09:48, Hans de Goede wrote:
> It has taken me a long long time to get the OOB interrupt working on the
> AP6210 sdio wifi/bt module found on various Allwinner A20 boards. In the
> end I found these magic register pokes in the cubietruck kernel tree:
> https://github.com/cubieboard2/linux-sunxi/commit/7f08ba395617d17e7a711507503d89a50406fe7a
>
> I'm not entirely sure if this specific to the AP6210 module, or if this
> should be done for all BCM43362 sdio devices.

Let keep it as this for now. I added some remarks below.

Regards,
Arend

> Signed-off-by: Hans de Goede<[email protected]>
> ---
> drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 18 ++++++++++++++++++
> 1 file changed, 18 insertions(+)
>
> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
> index 0fc707c..2369a0f 100644
> --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
> +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
> @@ -39,7 +39,9 @@
> #include<brcm_hw_ids.h>
> #include<brcmu_utils.h>
> #include<brcmu_wifi.h>
> +#include<chipcommon.h>
> #include<soc.h>
> +#include "chip.h"
> #include "dhd_bus.h"
> #include "dhd_dbg.h"
> #include "sdio_host.h"
> @@ -119,6 +121,7 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
> {
> int ret = 0;
> u8 data;
> + u32 addr, gpiocontrol;
> unsigned long flags;
>
> if ((sdiodev->pdata)&& (sdiodev->pdata->oob_irq_supported)) {
> @@ -148,6 +151,21 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
>
> sdio_claim_host(sdiodev->func[1]);
>
> + if (sdiodev->bus_if->chip == BCM43362_CHIP_ID) {
+ /* assign GPIO to SDIO core */
> + addr = CORE_CC_REG(SI_ENUM_BASE, gpiocontrol);
> + gpiocontrol = brcmf_sdiod_regrl(sdiodev, addr,&ret);
> + gpiocontrol |= 0x2;
> + brcmf_sdiod_regwl(sdiodev, addr, gpiocontrol,&ret);
> +
> + /* SPROM_ADDR_HIGH ? perhaps the defines name is off */

These names are all off. These should be:
SBSDIO_SPROM_ADDR_HIGH = SBSDIO_GPIO_SELECT
SBSDIO_CHIP_CTRL_DATA = SBSDIO_GPIO_OUT
SBSDIO_CHIP_CTRL_EN = SBSDIO_GPIO_EN

> + brcmf_sdiod_regwb(sdiodev, SBSDIO_SPROM_ADDR_HIGH, 0xf,
> + &ret);
> + brcmf_sdiod_regwb(sdiodev, SBSDIO_CHIP_CTRL_DATA, 0,
> + &ret);
> + brcmf_sdiod_regwb(sdiodev, SBSDIO_CHIP_CTRL_EN, 0x2,
> + &ret);
> + }
> +
> /* must configure SDIO_CCCR_IENx to enable irq */
> data = brcmf_sdiod_regrb(sdiodev, SDIO_CCCR_IENx,&ret);
> data |= 1<< SDIO_FUNC_1 | 1<< SDIO_FUNC_2 | 1;


2014-05-26 09:20:58

by Arend van Spriel

[permalink] [raw]
Subject: Re: [PATCH 09/11] brcmfmac: Fix OOB interrupt not working for BCM43362

On 05/26/14 09:48, Hans de Goede wrote:
> It has taken me a long long time to get the OOB interrupt working on the
> AP6210 sdio wifi/bt module found on various Allwinner A20 boards. In the
> end I found these magic register pokes in the cubietruck kernel tree:
> https://github.com/cubieboard2/linux-sunxi/commit/7f08ba395617d17e7a711507503d89a50406fe7a
>
> I'm not entirely sure if this specific to the AP6210 module, or if this
> should be done for all BCM43362 sdio devices.

This magic is not in our host drivers so my guess is that it is board
specific. This means the nvram file provided to the firmware should have
this specified. Can you send me yours?

Regards,
Arend

> Signed-off-by: Hans de Goede<[email protected]>
> ---
> drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 18 ++++++++++++++++++
> 1 file changed, 18 insertions(+)
>
> diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
> index 0fc707c..2369a0f 100644
> --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
> +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
> @@ -39,7 +39,9 @@
> #include<brcm_hw_ids.h>
> #include<brcmu_utils.h>
> #include<brcmu_wifi.h>
> +#include<chipcommon.h>
> #include<soc.h>
> +#include "chip.h"
> #include "dhd_bus.h"
> #include "dhd_dbg.h"
> #include "sdio_host.h"
> @@ -119,6 +121,7 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
> {
> int ret = 0;
> u8 data;
> + u32 addr, gpiocontrol;
> unsigned long flags;
>
> if ((sdiodev->pdata)&& (sdiodev->pdata->oob_irq_supported)) {
> @@ -148,6 +151,21 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
>
> sdio_claim_host(sdiodev->func[1]);
>
> + if (sdiodev->bus_if->chip == BCM43362_CHIP_ID) {
> + addr = CORE_CC_REG(SI_ENUM_BASE, gpiocontrol);
> + gpiocontrol = brcmf_sdiod_regrl(sdiodev, addr,&ret);
> + gpiocontrol |= 0x2;
> + brcmf_sdiod_regwl(sdiodev, addr, gpiocontrol,&ret);
> +
> + /* SPROM_ADDR_HIGH ? perhaps the defines name is off */
> + brcmf_sdiod_regwb(sdiodev, SBSDIO_SPROM_ADDR_HIGH, 0xf,
> + &ret);
> + brcmf_sdiod_regwb(sdiodev, SBSDIO_CHIP_CTRL_DATA, 0,
> + &ret);
> + brcmf_sdiod_regwb(sdiodev, SBSDIO_CHIP_CTRL_EN, 0x2,
> + &ret);
> + }
> +
> /* must configure SDIO_CCCR_IENx to enable irq */
> data = brcmf_sdiod_regrb(sdiodev, SDIO_CCCR_IENx,&ret);
> data |= 1<< SDIO_FUNC_1 | 1<< SDIO_FUNC_2 | 1;


2014-05-26 07:49:10

by Hans de Goede

[permalink] [raw]
Subject: [PATCH 08/11] brcmfmac: add device tree support for SDIO devices

From: Chen-Yu Tsai <[email protected]>

brcmfmac devices can use an out-of-band interrupt on a GPIO line.
Currently this is specified using platform data. Add support for
specifying out-of-band interrupt via device tree.

Signed-off-by: Chen-Yu Tsai <[email protected]>
[[email protected]: conditionalize more of-code, use driver debug routines]
Signed-off-by: Arend van Spriel <[email protected]>
[[email protected]: drop clk / reg_on gpio handling, as there is no consensus
on how to handle this yet]
Signed-off-by: Hans de Goede <[email protected]>
---
drivers/net/wireless/brcm80211/brcmfmac/Makefile | 2 +
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 4 ++
drivers/net/wireless/brcm80211/brcmfmac/of.c | 56 ++++++++++++++++++++++++
drivers/net/wireless/brcm80211/brcmfmac/of.h | 22 ++++++++++
4 files changed, 84 insertions(+)
create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/of.c
create mode 100644 drivers/net/wireless/brcm80211/brcmfmac/of.h

diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
index 1d2ceac..7f8f641 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile
+++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile
@@ -44,3 +44,5 @@ brcmfmac-$(CONFIG_BRCMDBG) += \
dhd_dbg.o
brcmfmac-$(CONFIG_BRCM_TRACING) += \
tracepoint.o
+brcmfmac-$(CONFIG_OF) += \
+ of.o
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
index a16e644..0fc707c 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
@@ -43,6 +43,7 @@
#include "dhd_bus.h"
#include "dhd_dbg.h"
#include "sdio_host.h"
+#include "of.h"

#define SDIOH_API_ACCESS_RETRY_LIMIT 2

@@ -1043,6 +1044,9 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
sdiodev->dev = &sdiodev->func[1]->dev;
sdiodev->pdata = brcmfmac_sdio_pdata;

+ if (!sdiodev->pdata)
+ brcmf_of_probe(sdiodev);
+
atomic_set(&sdiodev->suspend, false);
init_waitqueue_head(&sdiodev->request_word_wait);
init_waitqueue_head(&sdiodev->request_buffer_wait);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/of.c b/drivers/net/wireless/brcm80211/brcmfmac/of.c
new file mode 100644
index 0000000..78ff906
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/of.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2014 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/mmc/card.h>
+#include <linux/platform_data/brcmfmac-sdio.h>
+#include <linux/mmc/sdio_func.h>
+
+#include <defs.h>
+#include "dhd_dbg.h"
+#include "sdio_host.h"
+
+void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev)
+{
+ struct device *dev = sdiodev->dev;
+ struct device_node *np = dev->of_node;
+ int irq;
+ u32 irqf;
+ u32 val;
+
+ if (!np || !of_device_is_compatible(np, "brcm,bcm43xx-fmac"))
+ return;
+
+ sdiodev->pdata = devm_kzalloc(dev, sizeof(*sdiodev->pdata), GFP_KERNEL);
+ if (!sdiodev->pdata)
+ return;
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (irq < 0) {
+ brcmf_err("interrupt could not be mapped: err=%d\n", irq);
+ devm_kfree(dev, sdiodev->pdata);
+ return;
+ }
+ irqf = irqd_get_trigger_type(irq_get_irq_data(irq));
+
+ sdiodev->pdata->oob_irq_supported = true;
+ sdiodev->pdata->oob_irq_nr = irq;
+ sdiodev->pdata->oob_irq_flags = irqf;
+
+ if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0)
+ sdiodev->pdata->drive_strength = val;
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/of.h b/drivers/net/wireless/brcm80211/brcmfmac/of.h
new file mode 100644
index 0000000..5f7c355
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/of.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2014 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifdef CONFIG_OF
+void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev);
+#else
+static void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev)
+{
+}
+#endif /* CONFIG_OF */
--
1.9.3


2014-05-27 08:10:05

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH 03/11] pinctrl: sunxi: Move setting of mux to irq type from unmask to set_type

On Mon, May 26, 2014 at 09:47:58AM +0200, Hans de Goede wrote:
> With level triggered interrupt mask / unmask will get called for each
> interrupt, doing the somewhat expensive mux setting on each unmask thus is
> not a good idea. Instead move it to the set_type callback, which is typically
> done only once for each irq.

*This* is the bad idea. Nothing prevents you from calling
gpio_get_value whenever you just got your interrupt, that will change
the muxing, and never change it back, effectively breaking the
interrupts.

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (643.00 B)
signature.asc (819.00 B)
Digital signature
Download all attachments

2014-05-31 09:14:01

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH 03/11] pinctrl: sunxi: Move setting of mux to irq type from unmask to set_type

Hi,

On 05/28/2014 12:33 PM, Maxime Ripard wrote:
> On Wed, May 28, 2014 at 11:51:52AM +0200, Hans de Goede wrote:
>> Hi,
>>
>> On 05/28/2014 11:36 AM, Maxime Ripard wrote:
>>> On Tue, May 27, 2014 at 04:18:29PM +0200, Linus Walleij wrote:
>>>> On Mon, May 26, 2014 at 9:47 AM, Hans de Goede <[email protected]> wrote:
>>>>
>>>>> With level triggered interrupt mask / unmask will get called for each
>>>>> interrupt, doing the somewhat expensive mux setting on each unmask thus is
>>>>> not a good idea. Instead move it to the set_type callback, which is typically
>>>>> done only once for each irq.
>>>>>
>>>>> Signed-off-by: Hans de Goede <[email protected]>
>>>>
>>>> Yes move it out of mask/unmask but no, not into set_type().
>>>>
>>>> Can you not use the irqchip startup()/shutdown() callbacks
>>>> instead?
>>>
>>> I think we can use irq_request_resources then
>>> https://lkml.org/lkml/2014/3/12/307
>>
>> Sounds good, I'll modify the patch to move it here before posting a v2 of
>> this series. Note v2 likely won't happen till this weekend, -ENOTIME.
>>
>>> We could even merge the gpio_to_irq code into it.
>>
>> Erm, no we need that as a separate function for the gpio_chip's to_irq
>> callback.
>
> Linus sent a patch stating otherwise a few weeks ago, and was
> suggesting moving it to irq_startup.
>
> https://lkml.org/lkml/2014/5/9/50

That is not going to work, that patch uses gpiochip_irqchip_add,
which in turn uses gpiochip_to_irq as to_irq handler, which
assumes that gpio offset == irq offset, which is not true for
sunxi-pinctrl.

Specifically gpio_chio_to_irq does:

static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
{
return irq_find_mapping(chip->irqdomain, offset);
}

Where as the sunxi code does (simplified):

static int sunxi_pinctrl_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct sunxi_desc_function *desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, offset, "irq");
return irq_find_mapping(pctl->domain, desc->irqnum);\
}

Note the extra level of indirection.

Regards,

Hans

2014-05-27 08:35:24

by Chen-Yu Tsai

[permalink] [raw]
Subject: Re: [linux-sunxi] Re: [PATCH 01/11] pinctrl: sunxi: create irq/pin mapping during init

On Tue, May 27, 2014 at 4:02 PM, Maxime Ripard
<[email protected]> wrote:
> Hi,
>
> On Mon, May 26, 2014 at 09:47:56AM +0200, Hans de Goede wrote:
>> From: Chen-Yu Tsai <[email protected]>
>>
>> The irq/pin mapping is used to lookup the pin to mux to the irq
>> function when the irq is enabled. It is created when gpio_to_irq
>> is called. Creating the mapping during init allows us to map the
>> interrupts directly from the device tree.
>
> Can you be a bit more precise on this?
>
> What is the issue that this patch fix?

IIRC, originally the IRQ to pin mapping was created when gpio_to_irq
was called with a GPIO handle. The mapping in turn is used to mux
the pin into EINT mode.

If the mapping is created during gpio_to_irq, we can't use the
interrupts directly, i.e. through the DT with "interrupts = <&pio A 4>".

Instead we'd have to use "gpios = <&pio A B>", then pass the gpio
through to gpio_to_irq.


ChenYu

2014-06-11 09:13:51

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH 04/11] pinctrl: sunxi: Properly handle level triggered gpio interrupts

Hi Linus,

On 06/11/2014 11:00 AM, Linus Walleij wrote:
> On Mon, May 26, 2014 at 9:47 AM, Hans de Goede <[email protected]> wrote:
>
>> For level triggered gpio interrupts we need to use handle_fasteoi_irq,
>> like we do with the irq-sunxi-nmi driver. This is necessary to give threaded
>> interrupt handlers a chance to actuall clear the source of the interrupt
>> (which may involve sleeping waitnig for i2c / spi / mmc transfers), before
>> acknowledging the interrupt.
>>
>> Signed-off-by: Hans de Goede <[email protected]>
>
> I haven't seen any feedback on the pin controller patches in this
> series from Maxime, I might have missed it due to being tied to
> some other patch in the series.
>
> Anyway, this needs to be rebased and reposted anyway, I
> just merged some base patches from Maxime for external
> interrupts that will go in after the merge window, I need some
> help to figure out what and how to merge here.

No problem I plan to do a rebased v2 of the pinctrl bits in
this series (and only the pinctrl bits) with some remarks
from Maxime fixed soon.

Regards,

Hans

2014-06-11 09:00:31

by Linus Walleij

[permalink] [raw]
Subject: Re: [PATCH 04/11] pinctrl: sunxi: Properly handle level triggered gpio interrupts

On Mon, May 26, 2014 at 9:47 AM, Hans de Goede <[email protected]> wrote:

> For level triggered gpio interrupts we need to use handle_fasteoi_irq,
> like we do with the irq-sunxi-nmi driver. This is necessary to give threaded
> interrupt handlers a chance to actuall clear the source of the interrupt
> (which may involve sleeping waitnig for i2c / spi / mmc transfers), before
> acknowledging the interrupt.
>
> Signed-off-by: Hans de Goede <[email protected]>

I haven't seen any feedback on the pin controller patches in this
series from Maxime, I might have missed it due to being tied to
some other patch in the series.

Anyway, this needs to be rebased and reposted anyway, I
just merged some base patches from Maxime for external
interrupts that will go in after the merge window, I need some
help to figure out what and how to merge here.

Yours,
Linus Walleij

2014-06-02 10:35:04

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH 03/11] pinctrl: sunxi: Move setting of mux to irq type from unmask to set_type

On Sat, May 31, 2014 at 11:13:05AM +0200, Hans de Goede wrote:
> Hi,
>
> On 05/28/2014 12:33 PM, Maxime Ripard wrote:
> >On Wed, May 28, 2014 at 11:51:52AM +0200, Hans de Goede wrote:
> >>Hi,
> >>
> >>On 05/28/2014 11:36 AM, Maxime Ripard wrote:
> >>>On Tue, May 27, 2014 at 04:18:29PM +0200, Linus Walleij wrote:
> >>>>On Mon, May 26, 2014 at 9:47 AM, Hans de Goede <[email protected]> wrote:
> >>>>
> >>>>>With level triggered interrupt mask / unmask will get called for each
> >>>>>interrupt, doing the somewhat expensive mux setting on each unmask thus is
> >>>>>not a good idea. Instead move it to the set_type callback, which is typically
> >>>>>done only once for each irq.
> >>>>>
> >>>>>Signed-off-by: Hans de Goede <[email protected]>
> >>>>
> >>>>Yes move it out of mask/unmask but no, not into set_type().
> >>>>
> >>>>Can you not use the irqchip startup()/shutdown() callbacks
> >>>>instead?
> >>>
> >>>I think we can use irq_request_resources then
> >>>https://lkml.org/lkml/2014/3/12/307
> >>
> >>Sounds good, I'll modify the patch to move it here before posting a v2 of
> >>this series. Note v2 likely won't happen till this weekend, -ENOTIME.
> >>
> >>>We could even merge the gpio_to_irq code into it.
> >>
> >>Erm, no we need that as a separate function for the gpio_chip's to_irq
> >>callback.
> >
> >Linus sent a patch stating otherwise a few weeks ago, and was
> >suggesting moving it to irq_startup.
> >
> >https://lkml.org/lkml/2014/5/9/50
>
> That is not going to work, that patch uses gpiochip_irqchip_add,
> which in turn uses gpiochip_to_irq as to_irq handler, which
> assumes that gpio offset == irq offset, which is not true for
> sunxi-pinctrl.
>
> Specifically gpio_chio_to_irq does:
>
> static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
> {
> return irq_find_mapping(chip->irqdomain, offset);
> }
>
> Where as the sunxi code does (simplified):
>
> static int sunxi_pinctrl_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
> {
> struct sunxi_desc_function *desc = sunxi_pinctrl_desc_find_function_by_pin(pctl, offset, "irq");
> return irq_find_mapping(pctl->domain, desc->irqnum);\
> }

Yes, I know it's not going to work, but my point was that gpio_to_irq
might not be called by the drivers, and it's still valid not to do
it. So we might end up with a driver requesting an interrupt that
won't be muxed to it.

But thinking more about it, it would be wrong to remove the .to_irq
callback completely either, since drivers might need a "secondary"
interrupt (like the card detect one for an MMC driver), and a lot of
these use an additional gpio property to do so. So we need to keep it.


Nevermind then.

Maxime

--
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com


Attachments:
(No filename) (2.73 kB)
signature.asc (819.00 B)
Digital signature
Download all attachments