Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH v5 19/23] drivers/fsi: Add GPIO based FSI master
From: Randy Dunlap @ 2017-04-05 16:35 UTC (permalink / raw)
  To: Christopher Bostic, robh+dt, mark.rutland, linux, rostedt, mingo,
	gregkh, devicetree, linux-arm-kernel
  Cc: andrew, alistair, linux-kernel, joel, Edward A . James, benh,
	Jeremy Kerr
In-Reply-To: <20170405020607.79939-20-cbostic@linux.vnet.ibm.com>

On 04/04/17 19:06, Christopher Bostic wrote:
> From: Chris Bostic <cbostic@linux.vnet.ibm.com>
> 
> Implement a FSI master using GPIO.  Will generate FSI protocol for
> read and write commands to particular addresses.  Sends master command
> and waits for and decodes a slave response.
> 
> Includes changes from Edward A. James <eajames@us.ibm.com> and Jeremy
> Kerr <jk@ozlabs.org>.
> 
> Signed-off-by: Edward A. James <eajames@us.ibm.com>
> Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
> Signed-off-by: Chris Bostic <cbostic@linux.vnet.ibm.com>
> Signed-off-by: Joel Stanley <joel@jms.id.au>
> ---
>  drivers/fsi/Kconfig           |  11 +
>  drivers/fsi/Makefile          |   1 +
>  drivers/fsi/fsi-master-gpio.c | 610 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 622 insertions(+)
>  create mode 100644 drivers/fsi/fsi-master-gpio.c
> 
> diff --git a/drivers/fsi/Kconfig b/drivers/fsi/Kconfig
> index 04c1a0e..9cf8345 100644
> --- a/drivers/fsi/Kconfig
> +++ b/drivers/fsi/Kconfig
> @@ -9,4 +9,15 @@ config FSI
>  	---help---
>  	  FSI - the FRU Support Interface - is a simple bus for low-level
>  	  access to POWER-based hardware.
> +
> +if FSI
> +
> +config FSI_MASTER_GPIO
> +	tristate "GPIO-based FSI master"
> +	depends on FSI && GPIOLIB

depends on FSI is redundant since "if FSI" does the same thing.

> +	---help---
> +	This option enables a FSI master driver using GPIO lines.
> +
> +endif
> +


-- 
~Randy

^ permalink raw reply

* Re: [PATCH 0/2] mtd: spi-nor: add stm32 qspi driver
From: Ludovic BARRE @ 2017-04-05 16:20 UTC (permalink / raw)
  To: Marek Vasut, Cyrille Pitchen, Cyrille Pitchen
  Cc: Boris Brezillon, Alexandre Torgue, devicetree, Richard Weinberger,
	linux-kernel, Rob Herring, linux-mtd, Brian Norris,
	David Woodhouse
In-Reply-To: <e04fa293-63d4-7a7e-a998-37aab31167e5@gmail.com>

hi Cyrille, Marek

I've re-based and tested my patchset onto

"mtd: spi-nor: introduce more SPI protocols and the Dual Transfer Mode"

So I can deliver my patchset before or after Cyrille patchset

How do you wish process? what version do you want for the v3?


BR

Ludo

On 03/30/2017 12:15 PM, Marek Vasut wrote:
> On 03/30/2017 09:31 AM, Ludovic BARRE wrote:
>> hi Cyrille
>>
>> I see your patch series
>>
>> [PATCH v5 0/6] mtd: spi-nor: parse SFDP tables to setup (Q)SPI memories
>>
>> No problem, I rebase my V2 onto your patch
> I still didn't review that, so it might take a bit until it hits
> mainline. I think the stm32 stuff looks pretty OK, so we can take that
> before the SFDP stuff, no?
>


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply

* Re: [RFC] [media] imx: assume MEDIA_ENT_F_ATV_DECODER entities output video on pad 1
From: Mauro Carvalho Chehab @ 2017-04-05 16:17 UTC (permalink / raw)
  To: Devin Heitmueller
  Cc: mark.rutland, andrew-ct.chen, minghsiu.tsai,
	sakari.ailus@linux.intel.com, nick, songjun.wu, Hans Verkuil,
	Steve Longerbeam, Pavel Machek, robert.jarzmik, devel,
	markus.heiser, laurent.pinchart+renesas, shuah,
	Russell King - ARM Linux, geert, Steve Longerbeam,
	Linux Media Mailing List, devicetree, Philipp Zabel,
	Arnd Bergmann, Mauro Carvalho Chehab, bparrot, robh+dt,
	horms+renesas, tiffany.lin, linux-arm-kernel
In-Reply-To: <CAGoCfizXdDV_Eo1NSOAb+-wrC7F47iFQKyP8-wiJMpb-nsYArA@mail.gmail.com>

Em Wed, 5 Apr 2017 11:39:06 -0400
Devin Heitmueller <dheitmueller@kernellabs.com> escreveu:

> > Currently, the driver doesn't support (2), because, at the time
> > I wrote the driver, I didn't find a way to read the interrupts generated
> > by tvp5150 at em28xx[1], due to the lack of em28xx documentation,
> > but adding support for it shoudn't be hard. I may eventually do it
> > when I have some time to play with my ISEE hardware.  
> 
> For what it's worth, I doubt most of the em28xx designs have the
> tvp5150 interrupt request line connected in any way.

True. But, on embedded hardware, such line may be connected into the
SoC. Actually, from the IGEPv3 expansion diagram:

	https://www.isee.biz/support/downloads/item/igepv2-expansion-rc-schematics

The INT line is connected to CAM_IRQ. That's connected to GPIO_154 pin
at OMAP3.

So, on a first glance, it seems possible to use it, instead of polling.

> You would likely
> have to poll the FIFO status register via I2C,

Yes, I considered this option when I wrote the driver. It could work, 
although it would likely have some performance drawback, as the driver
would need to poll it at least 60 times per second.

> or use the feature to
> embed the sliced data into as VANC data in the 656 output (as
> described in sec 3.9 of the tvp5150am1 spec).

True, but the bridge driver would need to handle such data. 

I remember I looked on this when I wrote the driver, but I was
unable to find a way for em28xx to parse (or forward) such
data packets.

Thanks,
Mauro

^ permalink raw reply

* Re: [PATCH 1/3] dt: bindings: add pmu0 regs for USB PHYs on Allwinner H3/V3s/A64
From: Chen-Yu Tsai @ 2017-04-05 16:13 UTC (permalink / raw)
  To: Kishon Vijay Abraham I
  Cc: Icenowy Zheng, Rob Herring, Maxime Ripard, Chen-Yu Tsai,
	devicetree, linux-arm-kernel, linux-kernel, linux-sunxi,
	Icenowy Zheng
In-Reply-To: <1524732c-b72f-61ce-8ae7-1d764f85c903-l0cyMroinI0@public.gmane.org>

On Wed, Apr 5, 2017 at 8:58 PM, Kishon Vijay Abraham I <kishon-l0cyMroinI0@public.gmane.org> wrote:
>
>
> On Wednesday 05 April 2017 06:20 PM, Icenowy Zheng wrote:
>> From: Icenowy Zheng <icenowy-ymACFijhrKM@public.gmane.org>
>>
>> Allwinner H3/V3s/A64 SoCs have a special USB PHY0 that can route to two
>> controllers: one is MUSB and the other is a EHCI/OHCI pair.
>>
>> When it's routed to EHCI/OHCI pair, it will needs a "pmu0" regs to
>> tweak, like other EHCI/OHCI pairs in Allwinner SoCs.
>>
>> Add this to the binding of USB PHYs on Allwinner H3/V3s/A64.
>>
>> Signed-off-by: Icenowy Zheng <icenowy-ymACFijhrKM@public.gmane.org>
>> Acked-by: Chen-Yu Tsai <wens-jdAy2FN1RRM@public.gmane.org>
>> Signed-off-by: Kishon Vijay Abraham I <kishon-l0cyMroinI0@public.gmane.org>
>> ---
>>
>> Kishon, could you push this to 4.11?
>
> Is this for the patch titled "phy: sun4i-usb: add support for V3s USB PHY" that
> was added during the last merge window.

Yes. In fact, as the description suggests, this also applies retroactively to
H3 and A64, which were added in the following commits:

4.9  732e35da7b4a ("dt: bindings: add bindings for Allwinner A64 usb phy")
4.5  626a630e003c ("phy-sun4i-usb: Add support for the host usb-phys found
                    on the H3 SoC")

Though this was missed at the time the binding was added.

ChenYu

> this patch looks simpler enough to be merged in this -rc cycle. However it
> depends on Greg KH.
>
> Thanks
> Kishon
>
>>
>>  Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt | 1 +
>>  1 file changed, 1 insertion(+)
>>
>> diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
>> index e42334258185..005bc22938ff 100644
>> --- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
>> +++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
>> @@ -15,6 +15,7 @@ Required properties:
>>  - reg : a list of offset + length pairs
>>  - reg-names :
>>    * "phy_ctrl"
>> +  * "pmu0" for H3, V3s and A64
>>    * "pmu1"
>>    * "pmu2" for sun4i, sun6i or sun7i
>>  - #phy-cells : from the generic phy bindings, must be 1
>>

^ permalink raw reply

* Re: [PATCH 1/1] ARM: dts: armada-xp-linksys-mamba: use wan instead of internet for DSA port
From: Ralph Sennhauser @ 2017-04-05 16:08 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Mark Rutland, devicetree, Jason Cooper, linux-kernel,
	Russell King, Rob Herring, Gregory Clement, linux-arm-kernel,
	Sebastian Hesselbarth
In-Reply-To: <20170405155032.GL13449@lunn.ch>

Hi Andrew,

On Wed, 5 Apr 2017 17:50:32 +0200
Andrew Lunn <andrew@lunn.ch> wrote:

> > In fact "internet" label on the case is uppercase, would this matter
> > for you for new bindings, or would you still use the lowercase
> > version?  
> 
> I would use lower case, just to fix with the general convention that
> interface names are lower case.

Thanks

> 
> > > I would say, this is now too late. Changing an interface name will
> > > break configuration scripts. We are stuck with it.
> > >   
> > 
> > If it weren't for commit cb4f71c42988 that would have been obvious
> > for me as well.  
> 
> Yes, that was not nice. But it was also very earlier in the life of
> 38x, so it just affected a few developers with reference boards, not
> real products out in the wild, as far as i remember.
> 
>      Andrew

The mentioned commit bit me amongst others, see
https://lkml.org/lkml/2016/8/21/62

In fact I expect the impact to be much lower this time around, before
4.10 DSA was no contender for swconfig (out of tree switch driver as
used by OpenWrt and others). On Mamba ~200Mbit was top speed. Now they
perform roughly the same.


Thanks
Ralph

^ permalink raw reply

* Re: [PATCH v2] clk/axs10x: introduce AXS10X pll driver
From: Vlad Zakharov @ 2017-04-05 16:06 UTC (permalink / raw)
  To: sboyd@codeaurora.org
  Cc: mark.rutland@arm.com, linux-kernel@vger.kernel.org,
	Jose.Abreu@synopsys.com, mturquette@baylibre.com,
	devicetree@vger.kernel.org, linux-clk@vger.kernel.org,
	linux-snps-arc@lists.infradead.org
In-Reply-To: <20170405013525.GJ18246@codeaurora.org>

Hi Stephen,

On Tue, 2017-04-04 at 18:35 -0700, Stephen Boyd wrote:
> > +     .pll_table = (struct pll_of_table []){
> > +             {
> > +                     .prate = 27000000,
> 
> Can this be another clk in the framework instead of hardcoding
> the parent rate?

In fact there is another clk in the framework that represents this parent clock. But this field is needed to get
appropriate pll_cfg_table as it depends on parent clock frequency. Below in pll_cfg_get function we are searching for
the correct table comparing .parent_node field with real hardware parent clock frequency:
---------------------------------->8------------------------------------
for (i = 0; pll_table[i].prate != 0; i++)
    if (pll_table[i].prate == prate)
        return pll_table[i].pll_cfg_table;
---------------------------------->8------------------------------------

> 
> > +                     .pll_cfg_table = (struct pll_cfg []){
> > +                             { 25200000, 1, 84, 90 },
> > +                             { 50000000, 1, 100, 54 },
> > +                             { 74250000, 1, 44, 16 },
> > +                             { },
> > +                     },
> > +             },
> > +             /* Used as list limiter */
> > +             { },
> 
> There's only ever one, so I'm confused why we're making a list.

By this patch we only add support of core arc pll and pgu pll and today they are clocked by the only parent clocks
introduced here. But other plls on axs10x may be driven by different or configurable clocks, so in such cases we will
have more than one entry in this list. And we are going to add more supported plls to this driver in the nearest future.

> > +
> > +     clk = clk_register(NULL, &pll_clk->hw);
> > +     if (IS_ERR(clk)) {
> > +             pr_err("failed to register %s clock (%ld)\n",
> > +                             node->name, PTR_ERR(clk));
> > +             kfree(pll_clk);
> > +             return;
> > +     }
> > +
> > +     of_clk_add_provider(node, of_clk_src_simple_get, clk);
> 
> Can you please use the clk_hw based provider and clk registration
> functions?

Sure. Could you be so kind to explain what is the difference between hw and non-hw based provider and clk registration
functions please? In which cases they are preferred? 

> 
> > +}
> > +
> > +CLK_OF_DECLARE(axs10x_pll_clock, "snps,axs10x-arc-pll-clock", of_pll_clk_setup);
> 
> Does this need to be CLK_OF_DECLARE_DRIVER? I mean does the
> driver need to probe and also have this of declare happen? Is the
> PLL special and needs to be used for the timers?

It is special and is used for the timers, so we have to CLK_OF_DECLARE it. On the other hand similar pll is used to
drive PGU clock frequency and other subsystems and so we add usual probe func.

-- 
Best regards,
Vlad Zakharov <vzakhar@synopsys.com>

^ permalink raw reply

* Re: [PATCH v4 5/7] pinctrl: aramda-37xx: Add irqchip support
From: Gregory CLEMENT @ 2017-04-05 16:03 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Thomas Petazzoni, Andrew Lunn, Jason Cooper, devicetree,
	linux-kernel, Nadav Haklai, linux-gpio, Rob Herring,
	Neta Zur Hershkovits, Victor Gu, Hua Jing, Marcin Wojtas,
	Wilson Ding, linux-arm-kernel, Sebastian Hesselbarth
In-Reply-To: <70ffe3343c13d01737bf74e5de4898d0c0be07a0.1491405475.git-series.gregory.clement@free-electrons.com>


Argh, I sill have the typo in the title of this patch! :(

If you are going to apply it could you fix it, else it will be fixed in
the next version.

Sorry,

Gregory

 
 On mer., avril 05 2017, Gregory CLEMENT <gregory.clement@free-electrons.com> wrote:

> The Armada 37xx SoCs can handle interrupt through GPIO. However it can
> only manage the edge ones.
>
> The way the interrupt are managed are classical so we can use the generic
> interrupt chip model.
>
> The only unusual "feature" is that many interrupts are connected to the
> parent interrupt controller. But we do not take advantage of this and use
> the chained irq with all of them.
>
> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
> ---
>  drivers/pinctrl/mvebu/pinctrl-armada-37xx.c | 221 +++++++++++++++++++++-
>  1 file changed, 221 insertions(+)
>
> diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
> index 5c96f5558310..7356516e0921 100644
> --- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
> +++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
> @@ -13,7 +13,9 @@
>  #include <linux/gpio/driver.h>
>  #include <linux/mfd/syscon.h>
>  #include <linux/of.h>
> +#include <linux/of_address.h>
>  #include <linux/of_device.h>
> +#include <linux/of_irq.h>
>  #include <linux/pinctrl/pinconf-generic.h>
>  #include <linux/pinctrl/pinconf.h>
>  #include <linux/pinctrl/pinctrl.h>
> @@ -30,6 +32,11 @@
>  #define OUTPUT_CTL	0x20
>  #define SELECTION	0x30
>  
> +#define IRQ_EN		0x0
> +#define IRQ_POL		0x08
> +#define IRQ_STATUS	0x10
> +#define IRQ_WKUP	0x18
> +
>  #define NB_FUNCS 2
>  #define GPIO_PER_REG	32
>  
> @@ -75,9 +82,12 @@ struct armada_37xx_pmx_func {
>  
>  struct armada_37xx_pinctrl {
>  	struct regmap			*regmap;
> +	void __iomem			*base;
>  	const struct armada_37xx_pin_data	*data;
>  	struct device			*dev;
>  	struct gpio_chip		gpio_chip;
> +	struct irq_chip			irq_chip;
> +	spinlock_t			irq_lock;
>  	struct pinctrl_desc		pctl;
>  	struct pinctrl_dev		*pctl_dev;
>  	struct armada_37xx_pin_group	*groups;
> @@ -346,6 +356,14 @@ static int armada_37xx_pmx_set(struct pinctrl_dev *pctldev,
>  	return armada_37xx_pmx_set_by_name(pctldev, name, grp);
>  }
>  
> +static inline void armada_37xx_irq_update_reg(unsigned int *reg,
> +					  struct irq_data *d)
> +{
> +	int offset = irqd_to_hwirq(d);
> +
> +	armada_37xx_update_reg(reg, offset);
> +}
> +
>  static int armada_37xx_gpio_direction_input(struct gpio_chip *chip,
>  					    unsigned int offset)
>  {
> @@ -468,6 +486,206 @@ static const struct gpio_chip armada_37xx_gpiolib_chip = {
>  	.owner = THIS_MODULE,
>  };
>  
> +void armada_37xx_irq_ack(struct irq_data *d)
> +{
> +	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
> +	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
> +	u32 reg = IRQ_STATUS, mask = d->mask;
> +	unsigned long flags;
> +
> +	armada_37xx_irq_update_reg(&reg, d);
> +	spin_lock_irqsave(&info->irq_lock, flags);
> +	writel(mask, info->base + reg);
> +	spin_unlock_irqrestore(&info->irq_lock, flags);
> +}
> +
> +void armada_37xx_irq_mask(struct irq_data *d)
> +{
> +	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
> +	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
> +	u32 val, reg = IRQ_EN, mask = d->mask;
> +	unsigned long flags;
> +
> +	armada_37xx_irq_update_reg(&reg, d);
> +	spin_lock_irqsave(&info->irq_lock, flags);
> +	val = readl(info->base + reg);
> +	writel(val & ~mask, info->base + reg);
> +	spin_unlock_irqrestore(&info->irq_lock, flags);
> +}
> +
> +void armada_37xx_irq_unmask(struct irq_data *d)
> +{
> +	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
> +	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
> +	u32 val, reg = IRQ_EN, mask = d->mask;
> +	unsigned long flags;
> +
> +	armada_37xx_irq_update_reg(&reg, d);
> +	spin_lock_irqsave(&info->irq_lock, flags);
> +	val = readl(info->base + reg);
> +	writel(val | mask, info->base + reg);
> +	spin_unlock_irqrestore(&info->irq_lock, flags);
> +}
> +
> +static int armada_37xx_irq_set_wake(struct irq_data *d, unsigned int on)
> +{
> +	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
> +	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
> +	u32 val, reg = IRQ_WKUP, mask = d->mask;
> +	unsigned long flags;
> +
> +	armada_37xx_irq_update_reg(&reg, d);
> +	spin_lock_irqsave(&info->irq_lock, flags);
> +	val = readl(info->base + reg);
> +	if (on)
> +		val |= mask;
> +	else
> +		val &= ~mask;
> +	writel(val, info->base + reg);
> +	spin_unlock_irqrestore(&info->irq_lock, flags);
> +
> +	return 0;
> +}
> +
> +static int armada_37xx_irq_set_type(struct irq_data *d, unsigned int type)
> +{
> +	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
> +	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
> +	u32 val, reg = IRQ_POL, mask = d->mask;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&info->irq_lock, flags);
> +	armada_37xx_irq_update_reg(&reg, d);
> +	val = readl(info->base + reg);
> +	switch (type) {
> +	case IRQ_TYPE_EDGE_RISING:
> +		val &= ~mask;
> +		break;
> +	case IRQ_TYPE_EDGE_FALLING:
> +		val |= mask;
> +		break;
> +	default:
> +		spin_unlock_irqrestore(&info->irq_lock, flags);
> +		return -EINVAL;
> +	}
> +	writel(val, info->base + reg);
> +	spin_unlock_irqrestore(&info->irq_lock, flags);
> +
> +	return 0;
> +}
> +
> +
> +static void armada_37xx_irq_handler(struct irq_desc *desc)
> +{
> +	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
> +	struct irq_chip *chip = irq_desc_get_chip(desc);
> +	struct armada_37xx_pinctrl *info = gpiochip_get_data(gc);
> +	struct irq_domain *d = gc->irqdomain;
> +	int i;
> +
> +	chained_irq_enter(chip, desc);
> +	for (i = 0; i <= d->revmap_size / GPIO_PER_REG; i++) {
> +		u32 status;
> +		unsigned long flags;
> +
> +		spin_lock_irqsave(&info->irq_lock, flags);
> +		status = readl_relaxed(info->base + IRQ_STATUS + 4 * i);
> +		/* Manage only the interrupt that was enabled */
> +		status &= readl_relaxed(info->base + IRQ_EN + 4 * i);
> +		spin_unlock_irqrestore(&info->irq_lock, flags);
> +		while (status) {
> +			u32 hwirq = ffs(status) - 1;
> +			u32 virq = irq_find_mapping(d, hwirq +
> +						     i * GPIO_PER_REG);
> +
> +			generic_handle_irq(virq);
> +			status &= ~BIT(hwirq);
> +		}
> +	}
> +	chained_irq_exit(chip, desc);
> +}
> +
> +static int armada_37xx_irqchip_register(struct platform_device *pdev,
> +					struct armada_37xx_pinctrl *info)
> +{
> +	struct device_node *np = info->dev->of_node;
> +	int nrirqs = info->data->nr_pins;
> +	struct gpio_chip *gc = &info->gpio_chip;
> +	struct irq_chip *irqchip = &info->irq_chip;
> +	struct resource res;
> +	int ret = -ENODEV, i, nr_irq_parent;
> +
> +	for_each_child_of_node(info->dev->of_node, np) {
> +		if (of_find_property(np, "gpio-controller", NULL)) {
> +			ret = 0;
> +			break;
> +		}
> +	};
> +	if (ret)
> +		return ret;
> +
> +	nr_irq_parent = of_irq_count(np);
> +	spin_lock_init(&info->irq_lock);
> +
> +	if (!nr_irq_parent) {
> +		dev_err(&pdev->dev, "Invalid or no IRQ\n");
> +		return 0;
> +	}
> +
> +	if (of_address_to_resource(info->dev->of_node, 1, &res)) {
> +		dev_err(info->dev, "cannot find IO resource\n");
> +		return -ENOENT;
> +	}
> +
> +	info->base = devm_ioremap_resource(info->dev, &res);
> +	if (IS_ERR(info->base))
> +		return PTR_ERR(info->base);
> +
> +	irqchip->irq_ack = armada_37xx_irq_ack;
> +	irqchip->irq_mask = armada_37xx_irq_mask;
> +	irqchip->irq_unmask = armada_37xx_irq_unmask;
> +	irqchip->irq_set_wake = armada_37xx_irq_set_wake;
> +	irqchip->irq_set_type = armada_37xx_irq_set_type;
> +	irqchip->name = info->data->name;
> +
> +	ret = gpiochip_irqchip_add(gc, irqchip, 0,
> +				   handle_edge_irq, IRQ_TYPE_NONE);
> +	if (ret) {
> +		dev_info(&pdev->dev, "could not add irqchip\n");
> +		return ret;
> +	}
> +
> +	/*
> +	 * Many interrupts are connected to the parent interrupt
> +	 * controller. But we do not take advantage of this and use
> +	 * the chained irq with all of them.
> +	 */
> +	for (i = 0; i < nrirqs; i++) {
> +		struct irq_data *d = irq_get_irq_data(gc->irq_base + i);
> +
> +		/*
> +		 * The mask field is a "precomputed bitmask for
> +		 * accessing the chip registers" which was introduced
> +		 * for the generic irqchip framework. As we don't use
> +		 * this framework, we can reuse this field for our own
> +		 * usage.
> +		 */
> +		d->mask = BIT(i % GPIO_PER_REG);
> +	}
> +
> +	for (i = 0; i < nr_irq_parent; i++) {
> +		int irq = irq_of_parse_and_map(np, i);
> +
> +		if (irq < 0)
> +			continue;
> +
> +		gpiochip_set_chained_irqchip(gc, irqchip, irq,
> +					     armada_37xx_irq_handler);
> +	}
> +
> +	return 0;
> +}
> +
>  static int armada_37xx_gpiochip_register(struct platform_device *pdev,
>  					struct armada_37xx_pinctrl *info)
>  {
> @@ -496,6 +714,9 @@ static int armada_37xx_gpiochip_register(struct platform_device *pdev,
>  	ret = devm_gpiochip_add_data(&pdev->dev, gc, info);
>  	if (ret)
>  		return ret;
> +	ret = armada_37xx_irqchip_register(pdev, info);
> +	if (ret)
> +		return ret;
>  
>  	return 0;
>  }
> -- 
> git-series 0.9.1

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply

* Re: [PATCH 07/11] regulator: axp20x-regulator: add support for AXP803
From: Chen-Yu Tsai @ 2017-04-05 16:01 UTC (permalink / raw)
  To: Icenowy Zheng
  Cc: Lee Jones, Rob Herring, Chen-Yu Tsai, Maxime Ripard,
	Liam Girdwood, devicetree, linux-sunxi, linux-kernel,
	linux-arm-kernel
In-Reply-To: <20170404180145.12897-8-icenowy-h8G6r0blFSE@public.gmane.org>

Hi,

On Wed, Apr 5, 2017 at 2:01 AM, Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org> wrote:
> AXP803 PMIC also have a series of regulators (DCDCs and LDOs)
> controllable via I2C/RSB bus.
>
> Add support for them.
>
> Signed-off-by: Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
> ---
>  drivers/regulator/axp20x-regulator.c | 135 +++++++++++++++++++++++++++++++----
>  include/linux/mfd/axp20x.h           |  37 ++++++++++
>  2 files changed, 158 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
> index 0b9d4e3e52c7..219a731df392 100644
> --- a/drivers/regulator/axp20x-regulator.c
> +++ b/drivers/regulator/axp20x-regulator.c
> @@ -355,6 +355,81 @@ static const struct regulator_desc axp809_regulators[] = {
>         AXP_DESC_SW(AXP809, SW, "sw", "swin", AXP22X_PWR_OUT_CTRL2, BIT(6)),
>  };
>
> +static const struct regulator_linear_range axp803_dcdc234_ranges[] = {
> +       REGULATOR_LINEAR_RANGE(500000, 0x0, 0x46, 10000),
> +       REGULATOR_LINEAR_RANGE(1200000, 0x47, 0x4b, 20000),
> +};

Can you keep the ranges the datasheet uses? It makes it easier to compare.

> +
> +static const struct regulator_linear_range axp803_dcdc5_ranges[] = {
> +       REGULATOR_LINEAR_RANGE(800000, 0x0, 0x20, 10000),
> +       REGULATOR_LINEAR_RANGE(1140000, 0x21, 0x43, 20000),

1.14 ~ 1.84 / 0.02 = 36 steps. This would end at 0x44.

> +};
> +
> +static const struct regulator_linear_range axp803_dcdc6_ranges[] = {
> +       REGULATOR_LINEAR_RANGE(600000, 0x0, 0x32, 10000),
> +       REGULATOR_LINEAR_RANGE(1120000, 0x33, 0x47, 20000),
> +};
> +
> +static const struct regulator_linear_range axp803_dldo2_ranges[] = {
> +       REGULATOR_LINEAR_RANGE(700000, 0x0, 0x1a, 100000),
> +       REGULATOR_LINEAR_RANGE(3400000, 0x1b, 0x1f, 200000),
> +};

This is the same as axp806_cldo2_ranges. To keep the variants sorted
in ascending order, you could keep this version but replace references
to axp806_cldo2_ranges with this one.

> +
> +static const struct regulator_desc axp803_regulators[] = {
> +       AXP_DESC(AXP803, DCDC1, "dcdc1", "vin1", 1600, 3400, 100,
> +                AXP803_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(0)),
> +       AXP_DESC_RANGES(AXP803, DCDC2, "dcdc2", "vin2", axp803_dcdc234_ranges,
> +                       76, AXP803_DCDC2_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
> +                       BIT(1)),
> +       AXP_DESC_RANGES(AXP803, DCDC3, "dcdc3", "vin3", axp803_dcdc234_ranges,
> +                       76, AXP803_DCDC3_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
> +                       BIT(2)),
> +       AXP_DESC_RANGES(AXP803, DCDC4, "dcdc4", "vin4", axp803_dcdc234_ranges,
> +                       76, AXP803_DCDC4_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
> +                       BIT(3)),
> +       AXP_DESC_RANGES(AXP803, DCDC5, "dcdc5", "vin5", axp803_dcdc5_ranges,
> +                       68, AXP803_DCDC5_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
> +                       BIT(4)),
> +       AXP_DESC_RANGES(AXP803, DCDC6, "dcdc6", "vin6", axp803_dcdc6_ranges,
> +                       72, AXP803_DCDC6_V_OUT, 0x7f, AXP22X_PWR_OUT_CTRL1,
> +                       BIT(5)),
> +       /* secondary switchable output of DCDC1 */
> +       AXP_DESC_SW(AXP803, DC1SW, "dc1sw", NULL, AXP22X_PWR_OUT_CTRL2,
> +                   BIT(7)),
> +       AXP_DESC(AXP803, ALDO1, "aldo1", "aldoin", 700, 3300, 100,
> +                AXP22X_ALDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(5)),
> +       AXP_DESC(AXP803, ALDO2, "aldo2", "aldoin", 700, 3300, 100,
> +                AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(6)),
> +       AXP_DESC(AXP803, ALDO3, "aldo3", "aldoin", 700, 3300, 100,
> +                AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(7)),
> +       AXP_DESC(AXP803, DLDO1, "dldo1", "dldoin", 700, 3300, 100,
> +                AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(3)),
> +       AXP_DESC_RANGES(AXP803, DLDO2, "dldo2", "dldoin", axp803_dldo2_ranges,
> +                       32, AXP22X_DLDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2,
> +                       BIT(4)),
> +       AXP_DESC(AXP803, DLDO3, "dldo3", "dldoin", 700, 3300, 100,
> +                AXP22X_DLDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(5)),
> +       AXP_DESC(AXP803, DLDO4, "dldo4", "dldoin", 700, 3300, 100,
> +                AXP22X_DLDO4_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(6)),

dldo3 and dldo4 are controlled from AXP22X_PWR_OUT_CTRL2.

> +       AXP_DESC(AXP803, ELDO1, "eldo1", "eldoin", 700, 1900, 50,
> +                AXP22X_ELDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(0)),
> +       AXP_DESC(AXP803, ELDO2, "eldo2", "eldoin", 700, 1900, 50,
> +                AXP22X_ELDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(1)),
> +       AXP_DESC(AXP803, ELDO3, "eldo3", "eldoin", 700, 1900, 50,
> +                AXP22X_ELDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(2)),
> +       AXP_DESC(AXP803, FLDO1, "fldo1", "fldoin", 700, 1450, 50,
> +                AXP803_FLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(2)),
> +       AXP_DESC(AXP803, FLDO2, "fldo2", "fldoin", 700, 1450, 50,
> +                AXP803_FLDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(3)),

The fields for fldo* are only four bits wide.

> +       AXP_DESC_IO(AXP803, LDO_IO0, "ldo_io0", "ips", 700, 3300, 100,
> +                   AXP22X_LDO_IO0_V_OUT, 0x1f, AXP20X_GPIO0_CTRL, 0x07,
> +                   AXP22X_IO_ENABLED, AXP22X_IO_DISABLED),
> +       AXP_DESC_IO(AXP803, LDO_IO1, "ldo_io1", "ips", 700, 3300, 100,
> +                   AXP22X_LDO_IO1_V_OUT, 0x1f, AXP20X_GPIO1_CTRL, 0x07,
> +                   AXP22X_IO_ENABLED, AXP22X_IO_DISABLED),
> +       AXP_DESC_FIXED(AXP803, RTC_LDO, "rtc_ldo", "ips", 3000),
> +};
> +
>  static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
>  {
>         struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
> @@ -377,6 +452,13 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
>                  * (See include/linux/mfd/axp20x.h)
>                  */
>                 reg = AXP806_DCDC_FREQ_CTRL;
> +       case AXP803_ID:

AXP803 should come before AXP806.

> +               /*
> +                * AXP803 also have DCDC work frequency setting register at a
> +                * different position.
> +                */
> +               if (axp20x->variant == AXP803_ID)
> +                       reg = AXP803_DCDC_FREQ_CTRL;
>         case AXP221_ID:
>         case AXP223_ID:
>         case AXP809_ID:
> @@ -474,7 +556,13 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work
>                 mask = AXP22X_WORKMODE_DCDCX_MASK(id - AXP22X_DCDC1);
>                 workmode <<= id - AXP22X_DCDC1;
>                 break;
> +       case AXP803_ID:

Same here. Also this switch block has empty lines separating each case.

> +               if (id < AXP803_DCDC1 || id > AXP803_DCDC6)
> +                       return -EINVAL;
>
> +               mask = AXP22X_WORKMODE_DCDCX_MASK(id - AXP803_DCDC1);
> +               workmode <<= id - AXP803_DCDC1;
> +               break;
>         default:
>                 /* should not happen */
>                 WARN_ON(1);
> @@ -492,20 +580,34 @@ static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id)
>  {
>         u32 reg = 0;
>
> -       /* Only AXP806 has poly-phase outputs */
> -       if (axp20x->variant != AXP806_ID)
> +       /*
> +        * Currently in our supported AXP variants, only AXP806 and AXP803
> +        * have polyphase regulators.
> +        */
> +       switch (axp20x->variant) {
> +       case AXP806_ID:
> +               regmap_read(axp20x->regmap, AXP806_DCDC_MODE_CTRL2, &reg);
> +
> +               switch (id) {
> +               case AXP806_DCDCB:
> +                       return (((reg & GENMASK(7, 6)) == BIT(6)) ||
> +                               ((reg & GENMASK(7, 6)) == BIT(7)));
> +               case AXP806_DCDCC:
> +                       return ((reg & GENMASK(7, 6)) == BIT(7));
> +               case AXP806_DCDCE:
> +                       return !!(reg & BIT(5));
> +               }
> +       case AXP803_ID:

803 before 806.

> +               regmap_read(axp20x->regmap, AXP803_POLYPHASE_CTRL, &reg);
> +
> +               switch (id) {
> +               case AXP803_DCDC3:
> +                       return !!(reg & BIT(6));
> +               case AXP803_DCDC6:
> +                       return !!(reg & BIT(7));
> +               }
> +       default:
>                 return false;
> -
> -       regmap_read(axp20x->regmap, AXP806_DCDC_MODE_CTRL2, &reg);
> -
> -       switch (id) {
> -       case AXP806_DCDCB:
> -               return (((reg & GENMASK(7, 6)) == BIT(6)) ||
> -                       ((reg & GENMASK(7, 6)) == BIT(7)));
> -       case AXP806_DCDCC:
> -               return ((reg & GENMASK(7, 6)) == BIT(7));
> -       case AXP806_DCDCE:
> -               return !!(reg & BIT(5));
>         }
>
>         return false;
> @@ -548,6 +650,10 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
>                 regulators = axp809_regulators;
>                 nregulators = AXP809_REG_ID_MAX;
>                 break;
> +       case AXP803_ID:
> +               regulators = axp803_regulators;
> +               nregulators = AXP803_REG_ID_MAX;
> +               break;

Ascending order.

>         default:
>                 dev_err(&pdev->dev, "Unsupported AXP variant: %ld\n",
>                         axp20x->variant);
> @@ -579,7 +685,8 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
>                  * name.
>                  */
>                 if ((regulators == axp22x_regulators && i == AXP22X_DC1SW) ||
> -                   (regulators == axp809_regulators && i == AXP809_DC1SW)) {
> +                   (regulators == axp809_regulators && i == AXP809_DC1SW) ||
> +                   (regulators == axp803_regulators && i == AXP803_DC1SW)) {

803 before 809.

So, mostly ordering issues, and a few minor errors.

Regards
ChenYu

>                         new_desc = devm_kzalloc(&pdev->dev, sizeof(*desc),
>                                                 GFP_KERNEL);
>                         *new_desc = regulators[i];
> diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
> index b3220ef374d3..858d5b1b43b9 100644
> --- a/include/linux/mfd/axp20x.h
> +++ b/include/linux/mfd/axp20x.h
> @@ -119,6 +119,17 @@ enum axp20x_variants {
>  #define AXP806_BUS_ADDR_EXT            0xfe
>  #define AXP806_REG_ADDR_EXT            0xff
>
> +#define AXP803_POLYPHASE_CTRL          0x14
> +#define AXP803_FLDO1_V_OUT             0x1c
> +#define AXP803_FLDO2_V_OUT             0x1d
> +#define AXP803_DCDC1_V_OUT             0x20
> +#define AXP803_DCDC2_V_OUT             0x21
> +#define AXP803_DCDC3_V_OUT             0x22
> +#define AXP803_DCDC4_V_OUT             0x23
> +#define AXP803_DCDC5_V_OUT             0x24
> +#define AXP803_DCDC6_V_OUT             0x25
> +#define AXP803_DCDC_FREQ_CTRL          0x3b
> +
>  /* Interrupt */
>  #define AXP152_IRQ1_EN                 0x40
>  #define AXP152_IRQ2_EN                 0x41
> @@ -350,6 +361,32 @@ enum {
>         AXP809_REG_ID_MAX,
>  };
>
> +enum {
> +       AXP803_DCDC1 = 0,
> +       AXP803_DCDC2,
> +       AXP803_DCDC3,
> +       AXP803_DCDC4,
> +       AXP803_DCDC5,
> +       AXP803_DCDC6,
> +       AXP803_DC1SW,
> +       AXP803_ALDO1,
> +       AXP803_ALDO2,
> +       AXP803_ALDO3,
> +       AXP803_DLDO1,
> +       AXP803_DLDO2,
> +       AXP803_DLDO3,
> +       AXP803_DLDO4,
> +       AXP803_ELDO1,
> +       AXP803_ELDO2,
> +       AXP803_ELDO3,
> +       AXP803_FLDO1,
> +       AXP803_FLDO2,
> +       AXP803_RTC_LDO,
> +       AXP803_LDO_IO0,
> +       AXP803_LDO_IO1,
> +       AXP803_REG_ID_MAX,
> +};
> +
>  /* IRQs */
>  enum {
>         AXP152_IRQ_LDO0IN_CONNECT = 1,
> --
> 2.12.2
>
> --
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
> For more options, visit https://groups.google.com/d/optout.

^ permalink raw reply

* Re: [PATCH v2 1/2] dt-bindings: Document the STM32 QSPI bindings
From: Ludovic BARRE @ 2017-04-05 16:00 UTC (permalink / raw)
  To: Rob Herring
  Cc: Cyrille Pitchen, Marek Vasut, David Woodhouse, Brian Norris,
	Boris Brezillon, Richard Weinberger, Alexandre Torgue,
	linux-mtd@lists.infradead.org, linux-kernel@vger.kernel.org,
	devicetree@vger.kernel.org
In-Reply-To: <CAL_JsqK5mZojW1fVRrg=TfO3sXd7Eqa6gS9NS9aDjXwn4_26_w@mail.gmail.com>


On 04/04/2017 02:20 PM, Rob Herring wrote:
> On Tue, Apr 4, 2017 at 2:28 AM, Ludovic BARRE <ludovic.barre@st.com> wrote:
>> Hi Rob
>>
>> thanks for review
>> my comments below
>>
>> br
>> Ludo
>>
>> On 04/03/2017 06:57 PM, Rob Herring wrote:
>>> On Fri, Mar 31, 2017 at 07:02:03PM +0200, Ludovic Barre wrote:
>>>> From: Ludovic Barre <ludovic.barre@st.com>
>>>>
>>>> This patch adds documentation of device tree bindings for the STM32
>>>> QSPI controller.
>>>>
>>>> Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
>>>> ---
>>>>    .../devicetree/bindings/mtd/stm32-quadspi.txt      | 45
>>>> ++++++++++++++++++++++
>>>>    1 file changed, 45 insertions(+)
>>>>    create mode 100644
>>>> Documentation/devicetree/bindings/mtd/stm32-quadspi.txt
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/mtd/stm32-quadspi.txt
>>>> b/Documentation/devicetree/bindings/mtd/stm32-quadspi.txt
>>>> new file mode 100644
>>>> index 0000000..95a8ebd
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/mtd/stm32-quadspi.txt
>>>> @@ -0,0 +1,45 @@
>>>> +* STMicroelectronics Quad Serial Peripheral Interface(QuadSPI)
>>>> +
>>>> +Required properties:
>>>> +- compatible: should be "st,stm32f469-qspi"
>>>> +- reg: contains the register location and length.
>>>> +  (optional) the memory mapping address and length
>>> Why optional? Either the h/w has it or doesn't. If some chips don't,
>>> they should have a different compatible string.
>> in fact, the stm32 qspi controller can operate in any of the following
>> modes:
>> -indirect mode: all the operations are performed using the qspi registers
>> with read/write.
>> -read memory-mapped mode: the external Flash memory is mapped to the
>>   microcontroller address space and is seen by the system as if it was
>>   an internal memory (use memcpy_fromio). this mode improve read throughput
>>
>> if qspi_mm is defined the qspi controller use read memory-mapped mode
>> else the controller transfers in indirect mode.
> You should always have the memory region defined because that's what
> the h/w has. If you want another property to select the mode, then
> perhaps that's fine. But why? Can't the OS figure out which to use?
> Why would you ever not use memory mapped mode unless the driver
> doesn't yet support it?
ok, I always map the memory region (qspi_mm is now required).
if the nor-flash is more bigger than "qspi memory region", I force to use
the indirect mode.
> Rob

^ permalink raw reply

* Re: [PATCH 2/3] of/fdt: introduce of_scan_flat_dt_subnodes and of_get_flat_dt_phandle
From: Rob Herring @ 2017-04-05 15:58 UTC (permalink / raw)
  To: Nicholas Piggin
  Cc: Michael Ellerman,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linuxppc-dev,
	Benjamin Herrenschmidt, Frank Rowand
In-Reply-To: <20170406003251.533e2845-a5aMA/AkCkgK5Ils6ZIQy0EOCMrvLtNR@public.gmane.org>

On Wed, Apr 5, 2017 at 9:32 AM, Nicholas Piggin <npiggin-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On Wed, 5 Apr 2017 08:35:06 -0500
> Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
>
>> On Wed, Apr 5, 2017 at 7:37 AM, Nicholas Piggin <npiggin-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
>> > Introduce primitives for FDT parsing. These will be used for powerpc
>> > cpufeatures node scanning, which has quite complex structure but should
>> > be processed early.
>>
>> Have you looked at unflattening the FDT earlier?
>
> Hi, thanks for taking a look. Did you mean to trim the cc list?

Ugg, no. I've added everyone back.

> It may be possible but I'd like to avoid it if we can. There might
> turn out to be some errata or feature that requires early setup. And
> the current cpu feature parsing code does it with flat dt.

Well, I'd like to avoid expanding usage of flat DT parsing in the
kernel. But you could just put this function into arch/powerpc and I'd
never see it, but I like that even less. Mainly, I just wanted to
raise the point.

Your argument works until you need that setup in assembly code, then
you are in the situation that you need to either handle the setup in
bootloader/firmware or have an simple way to determine that condition.

Rob

>
>> > Signed-off-by: Nicholas Piggin <npiggin-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>> > ---
>> >  drivers/of/fdt.c       | 39 +++++++++++++++++++++++++++++++++++++++
>> >  include/linux/of_fdt.h |  6 ++++++
>> >  2 files changed, 45 insertions(+)
>> >
>> > diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
>> > index e5ce4b59e162..a45854fe5156 100644
>> > --- a/drivers/of/fdt.c
>> > +++ b/drivers/of/fdt.c
>> > @@ -754,6 +754,37 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node,
>> >  }
>> >
>> >  /**
>> > + * of_scan_flat_dt_subnodes - scan sub-nodes of a node call callback on each.
>> > + * @it: callback function
>> > + * @data: context data pointer
>> > + *
>> > + * This function is used to scan sub-nodes of a node.
>> > + */
>> > +int __init of_scan_flat_dt_subnodes(unsigned long node,
>> > +                                   int (*it)(unsigned long node,
>> > +                                             const char *uname,
>> > +                                             void *data),
>> > +                                   void *data)
>> > +{
>> > +       const void *blob = initial_boot_params;
>> > +       const char *pathp;
>> > +       int offset, rc = 0;
>> > +
>> > +       offset = node;
>> > +        for (offset = fdt_first_subnode(blob, offset);
>> > +             offset >= 0 && !rc;
>> > +             offset = fdt_next_subnode(blob, offset)) {
>>
>> fdt_for_each_subnode()
>
> Got it.
>
>>
>> > +
>> > +               pathp = fdt_get_name(blob, offset, NULL);
>> > +               if (*pathp == '/')
>> > +                       pathp = kbasename(pathp);
>>
>> Seems a bit odd that you parse the name in this function. Perhaps the
>> caller should do that, or if you want subnodes matching a certain
>> name, then do the matching here. But you didn't copy me on the rest of
>> the series, so I don't know how you are using this.
>
> Hmm, it was a while since writing that part. I guess I just copied
> of_scan_flat_dt interface.
>
> Caller is in this patch:
>
> https://patchwork.ozlabs.org/patch/747262/
>
> I'll include you in subsequent post if you prefer.
>
> Thanks,
> Nick
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 1/1] ARM: dts: armada-xp-linksys-mamba: use wan instead of internet for DSA port
From: Andrew Lunn @ 2017-04-05 15:50 UTC (permalink / raw)
  To: Ralph Sennhauser
  Cc: Mark Rutland, devicetree, Jason Cooper, linux-kernel,
	Russell King, Rob Herring, Gregory Clement, linux-arm-kernel,
	Sebastian Hesselbarth
In-Reply-To: <20170405172224.38c1f9fb@gmail.com>

> In fact "internet" label on the case is uppercase, would this matter
> for you for new bindings, or would you still use the lowercase version?

I would use lower case, just to fix with the general convention that
interface names are lower case.

> > I would say, this is now too late. Changing an interface name will
> > break configuration scripts. We are stuck with it.
> > 
> 
> If it weren't for commit cb4f71c42988 that would have been obvious for
> me as well.

Yes, that was not nice. But it was also very earlier in the life of
38x, so it just affected a few developers with reference boards, not
real products out in the wild, as far as i remember.

     Andrew

^ permalink raw reply

* Re: [PATCH] ARM: dts: armada-38x: label USB and SATA nodes
From: Gregory CLEMENT @ 2017-04-05 15:49 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Ralph Sennhauser,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jason Cooper,
	Sebastian Hesselbarth, Rob Herring, Mark Rutland, Russell King,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20170331182111.GJ22609-g2DYL2Zd6BY@public.gmane.org>

Hi Andrew,
 
 On ven., mars 31 2017, Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org> wrote:

> On Fri, Mar 31, 2017 at 07:39:20PM +0200, Ralph Sennhauser wrote:
>> On Fri, 31 Mar 2017 18:50:15 +0200
>> Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org> wrote:
>> 
>> > > -			sata@a8000 {
>> > > +			satac0: sata@a8000 {  
>> > 
>> > Hi Ralph
>> > 
>> > Why the c in satac0?
>> 
>> For controller and to not conflict with a use case of sata0 for a port,
>> similarly to pciec and pcie1. See armada-385-synology-ds116.dts.
>
> :~/linux/arch/arm/boot/dts$ ls *ds116*
> ls: cannot access '*ds116*': No such file or directory
>
> But anyway, a few boards seem to solve this by calling the controller
> node ahci0: and the port sata0:
>
>> > > -			usb3@f0000 {
>> > > +			usb3_0: usb3@f0000 {
>> > >  				compatible =
>> > > "marvell,armada-380-xhci"; reg = <0xf0000 0x4000>,<0xf4000 0x4000>;
>> > >  				interrupts = <GIC_SPI 16
>> > > IRQ_TYPE_LEVEL_HIGH>; @@ -598,7 +598,7 @@
>> > >  				status = "disabled";
>> > >  			};
>> > >  
>> > > -			usb3@f8000 {
>> > > +			usb3_1: usb3@f8000 {
>> > >  				compatible =
>> > > "marvell,armada-380-xhci"; reg = <0xf8000 0x4000>,<0xfc000 0x4000>;
>> > >  				interrupts = <GIC_SPI 17
>> > > IRQ_TYPE_LEVEL_HIGH>;  
>> > 
>> > I can understand what you are saying. But does anybody else care? Are
>> > there other .dtsi files differentiating between USB 1.1, 2 and 3?
>> 
>> It's handled differently where ever I looked, some do some don't. A
>> case for distinguishing USB 2.0 and USB 3.0 like this is
>> armada-388-gp.dts.

Actually I care and I found confusing calling usb2 the second usb port if
it is controlled by an USB3 controller.

>
> Humm...
>
>                         /* CON4 */
>                         usb@58000 {
>                                 vcc-supply = <&reg_usb2_0_vbus>;
>                                 status = "okay";
>                         };
>
>
> 			/* CON5 */
>                         usb3@f0000 {
>                                 usb-phy = <&usb2_1_phy>;
>                                 status = "okay";
>                         };
>
>                         /* CON7 */
>                         usb3@f8000 {
>                                 usb-phy = <&usb3_phy>;
>                                 status = "okay";
>                         };
>
> Is this clear? Is CON5 a USB 3 host, but has a USB 2 PHY connected to
> it? CON7 is the only true USB 3 port? I think some comments written in

I can answer it: CON5 is indeed an USB3 host with a USB2 PHY connected
to it so we can use it only as an USB2. And indeed CON7 is the only true
USB3 port.

> schwiizerdütsch would be clearre.:-)

Actually all your assumption were correct so maybe it is not as
confusing as it looks! :)  But I can add a comment if needed.

Gregory

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 2/4] iio: dac: add support for stm32 DAC
From: Fabrice Gasnier @ 2017-04-05 15:48 UTC (permalink / raw)
  To: Jonathan Cameron, linux, robh+dt, linux-arm-kernel, devicetree,
	linux-kernel
  Cc: mark.rutland, benjamin.gaignard, lars, alexandre.torgue,
	linux-iio, pmeerw, amelie.delaunay, mcoquelin.stm32, knaack.h,
	linus.walleij, benjamin.gaignard
In-Reply-To: <fd46ba6c-98f3-8dc9-5f71-9a09d60acf8e@kernel.org>

On 04/02/2017 01:32 PM, Jonathan Cameron wrote:
> On 31/03/17 12:45, Fabrice Gasnier wrote:
>> Add support for STMicroelectronics STM32 DAC. It's a 12-bit, voltage
>> output digital-to-analog converter. It has two output channels, each
>> with its own converter.
>> It supports 8 bits or 12bits left/right aligned data format. Only
>> 12bits right-aligned is used here. It has built-in noise or
>> triangle waveform generator, and supports external triggers for
>> conversions.
>> Each channel can be used independently, with separate trigger, then
>> separate IIO devices are used to handle this. Core driver is intended
>> to share common resources such as clock, reset, reference voltage and
>> registers.
>>
>> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
> Annoyingly my laptop just crashed mid way through reviewing this..
> 
Hi Jonathan,
I hope I have nothing to do with this ;-)

> Ah well, hopefully I'll remember everything (there wasn't much).
> 
> For DACs the 'enable' attribute is not normally used. Rather we
> use the powerdown one.  The reasoning being that we care about what
> the state is when it is powered down.  Even if that isn't controllable
> I would expect to see it exported as powerdown_mode with a fixed value.
> 
Ok, I'll try to use powerdown_mode in V2 as other DACs do. For now,
basically, I'll remap same functionality as 'enable' of this patch.

What do you mean by 'fixed value' ?

But, this also raise me one question:
Current patch use 'enable' to set EN bits in control register. Then, DAC
output goes from Hi-Z to buffered output.
There is also other power modes available. One of them is 'unbuffered':
output buffer can be disabled/bypassed.
This typically can save power, but it only makes sense to use it
depending on output load impedance (This is explained in AN3126 as you
pointed out in later patch).
Current patch uses buffered output (which suits all needs regarding
output load impedance). And the question is...

Should I expose this power modes to userland by using 'powerdown_mode' ?

OR... I'd rather rely on a dt property like st,dac-output-mode to manage
this, because buffered/unbuffered output modes depends on HW output load
impedance. Do you agree with this approach to use:
- powerdown_mode as Hi-Z / enable switch, with dedicated dt property to
set output power mode ?

Please let me know your opinion.

But, I think this can be part of another patchset...

> Other than that - looks pretty good to me.
> 
> Jonathan
> 
>> ---
>>  drivers/iio/dac/Kconfig          |  15 ++
>>  drivers/iio/dac/Makefile         |   2 +
>>  drivers/iio/dac/stm32-dac-core.c | 180 ++++++++++++++++++++++++
>>  drivers/iio/dac/stm32-dac-core.h |  51 +++++++
>>  drivers/iio/dac/stm32-dac.c      | 296 +++++++++++++++++++++++++++++++++++++++
>>  5 files changed, 544 insertions(+)
>>  create mode 100644 drivers/iio/dac/stm32-dac-core.c
>>  create mode 100644 drivers/iio/dac/stm32-dac-core.h
>>  create mode 100644 drivers/iio/dac/stm32-dac.c
>>
>> diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
>> index d3084028..7198648 100644
>> --- a/drivers/iio/dac/Kconfig
>> +++ b/drivers/iio/dac/Kconfig
>> @@ -274,6 +274,21 @@ config MCP4922
>>  	  To compile this driver as a module, choose M here: the module
>>  	  will be called mcp4922.
>>  
>> +config STM32_DAC
>> +	tristate "STMicroelectronics STM32 DAC"
>> +	depends on (ARCH_STM32 && OF) || COMPILE_TEST
>> +	depends on REGULATOR
>> +	select STM32_DAC_CORE
>> +	help
>> +	  Say yes here to build support for STMicroelectronics STM32 Digital
>> +	  to Analog Converter (DAC).
>> +
>> +	  This driver can also be built as a module.  If so, the module
>> +	  will be called stm32-dac.
>> +
>> +config STM32_DAC_CORE
>> +	tristate
>> +
>>  config VF610_DAC
>>  	tristate "Vybrid vf610 DAC driver"
>>  	depends on OF
>> diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
>> index f01bf4a..afe8ae7 100644
>> --- a/drivers/iio/dac/Makefile
>> +++ b/drivers/iio/dac/Makefile
>> @@ -29,4 +29,6 @@ obj-$(CONFIG_MAX517) += max517.o
>>  obj-$(CONFIG_MAX5821) += max5821.o
>>  obj-$(CONFIG_MCP4725) += mcp4725.o
>>  obj-$(CONFIG_MCP4922) += mcp4922.o
>> +obj-$(CONFIG_STM32_DAC_CORE) += stm32-dac-core.o
>> +obj-$(CONFIG_STM32_DAC) += stm32-dac.o
>>  obj-$(CONFIG_VF610_DAC) += vf610_dac.o
>> diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c
>> new file mode 100644
>> index 0000000..75e4878
>> --- /dev/null
>> +++ b/drivers/iio/dac/stm32-dac-core.c
>> @@ -0,0 +1,180 @@
>> +/*
>> + * This file is part of STM32 DAC driver
>> + *
>> + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
>> + * Author: Fabrice Gasnier <fabrice.gasnier@st.com>.
>> + *
>> + * License type: GPLv2
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2 as published by
>> + * the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful, but
>> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
>> + * or FITNESS FOR A PARTICULAR PURPOSE.
>> + * See the GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License along with
>> + * this program. If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +#include <linux/module.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/regulator/consumer.h>
>> +#include <linux/reset.h>
>> +
>> +#include "stm32-dac-core.h"
>> +
>> +/**
>> + * struct stm32_dac_priv - stm32 DAC core private data
>> + * @pclk:		peripheral clock common for all DACs
>> + * @rst:		peripheral reset control
>> + * @vref:		regulator reference
>> + * @common:		Common data for all DAC instances
>> + */
>> +struct stm32_dac_priv {
>> +	struct clk *pclk;
>> +	struct reset_control *rst;
>> +	struct regulator *vref;
>> +	struct stm32_dac_common common;
>> +};
>> +
>> +static struct stm32_dac_priv *to_stm32_dac_priv(struct stm32_dac_common *com)
>> +{
>> +	return container_of(com, struct stm32_dac_priv, common);
>> +}
>> +
>> +static const struct regmap_config stm32_dac_regmap_cfg = {
>> +	.reg_bits = 32,
>> +	.val_bits = 32,
>> +	.reg_stride = sizeof(u32),
>> +	.max_register = 0x3fc,
>> +};
>> +
>> +static int stm32_dac_probe(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct stm32_dac_priv *priv;
>> +	struct regmap *regmap;
>> +	struct resource *res;
>> +	void __iomem *mmio;
>> +	int ret;
>> +
>> +	if (!dev->of_node)
>> +		return -ENODEV;
>> +
>> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>> +	if (!priv)
>> +		return -ENOMEM;
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	mmio = devm_ioremap_resource(dev, res);
>> +	if (IS_ERR(mmio))
>> +		return PTR_ERR(mmio);
>> +
>> +	regmap = devm_regmap_init_mmio(dev, mmio, &stm32_dac_regmap_cfg);
>> +	if (IS_ERR(regmap))
>> +		return PTR_ERR(regmap);
>> +	priv->common.regmap = regmap;
>> +
>> +	priv->vref = devm_regulator_get(dev, "vref");
>> +	if (IS_ERR(priv->vref)) {
>> +		ret = PTR_ERR(priv->vref);
>> +		dev_err(dev, "vref get failed, %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	ret = regulator_enable(priv->vref);
>> +	if (ret < 0) {
>> +		dev_err(dev, "vref enable failed\n");
>> +		return ret;
>> +	}
>> +
>> +	ret = regulator_get_voltage(priv->vref);
>> +	if (ret < 0) {
>> +		dev_err(dev, "vref get voltage failed, %d\n", ret);
>> +		goto err_vref;
>> +	}
>> +	priv->common.vref_mv = ret / 1000;
>> +	dev_dbg(dev, "vref+=%dmV\n", priv->common.vref_mv);
>> +
>> +	priv->pclk = devm_clk_get(dev, "pclk");
>> +	if (IS_ERR(priv->pclk)) {
>> +		ret = PTR_ERR(priv->pclk);
>> +		dev_err(dev, "pclk get failed\n");
>> +		goto err_vref;
>> +	}
>> +
>> +	ret = clk_prepare_enable(priv->pclk);
>> +	if (ret < 0) {
>> +		dev_err(dev, "pclk enable failed\n");
>> +		goto err_vref;
>> +	}
>> +
>> +	priv->rst = devm_reset_control_get(dev, NULL);
>> +	if (!IS_ERR(priv->rst)) {
>> +		reset_control_assert(priv->rst);
>> +		udelay(2);
>> +		reset_control_deassert(priv->rst);
>> +	}
>> +
>> +	/* When clock speed is higher than 80MHz, set HFSEL */
>> +	priv->common.hfsel = (clk_get_rate(priv->pclk) > 80000000UL);
>> +	ret = regmap_update_bits(regmap, STM32_DAC_CR, STM32H7_DAC_CR_HFSEL,
>> +				 priv->common.hfsel ? STM32H7_DAC_CR_HFSEL : 0);
>> +	if (ret)
>> +		goto err_pclk;
>> +
>> +	platform_set_drvdata(pdev, &priv->common);
>> +
>> +	ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, dev);
>> +	if (ret < 0) {
>> +		dev_err(dev, "failed to populate DT children\n");
>> +		goto err_pclk;
>> +	}
>> +
>> +	return 0;
>> +
>> +err_pclk:
>> +	clk_disable_unprepare(priv->pclk);
>> +err_vref:
>> +	regulator_disable(priv->vref);
>> +
>> +	return ret;
>> +}
>> +
>> +static int stm32_dac_remove(struct platform_device *pdev)
>> +{
>> +	struct stm32_dac_common *common = platform_get_drvdata(pdev);
>> +	struct stm32_dac_priv *priv = to_stm32_dac_priv(common);
>> +
>> +	of_platform_depopulate(&pdev->dev);
>> +	clk_disable_unprepare(priv->pclk);
>> +	regulator_disable(priv->vref);
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct of_device_id stm32_dac_of_match[] = {
>> +	{ .compatible = "st,stm32h7-dac-core", },
>> +	{},
>> +};
>> +MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
>> +
>> +static struct platform_driver stm32_dac_driver = {
>> +	.probe = stm32_dac_probe,
>> +	.remove = stm32_dac_remove,
>> +	.driver = {
>> +		.name = "stm32-dac-core",
>> +		.of_match_table = stm32_dac_of_match,
>> +	},
>> +};
>> +module_platform_driver(stm32_dac_driver);
>> +
>> +MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
>> +MODULE_DESCRIPTION("STMicroelectronics STM32 DAC core driver");
>> +MODULE_LICENSE("GPL v2");
>> +MODULE_ALIAS("platform:stm32-dac-core");
>> diff --git a/drivers/iio/dac/stm32-dac-core.h b/drivers/iio/dac/stm32-dac-core.h
>> new file mode 100644
>> index 0000000..d3099f7
>> --- /dev/null
>> +++ b/drivers/iio/dac/stm32-dac-core.h
>> @@ -0,0 +1,51 @@
>> +/*
>> + * This file is part of STM32 DAC driver
>> + *
>> + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
>> + * Author: Fabrice Gasnier <fabrice.gasnier@st.com>.
>> + *
>> + * License type: GPLv2
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2 as published by
>> + * the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful, but
>> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
>> + * or FITNESS FOR A PARTICULAR PURPOSE.
>> + * See the GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License along with
>> + * this program. If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#ifndef __STM32_DAC_CORE_H
>> +#define __STM32_DAC_CORE_H
>> +
>> +#include <linux/regmap.h>
>> +
>> +/* STM32 DAC registers */
>> +#define STM32_DAC_CR		0x00
>> +#define STM32_DAC_DHR12R1	0x08
>> +#define STM32_DAC_DHR12R2	0x14
>> +#define STM32_DAC_DOR1		0x2C
>> +#define STM32_DAC_DOR2		0x30
>> +
>> +/* STM32_DAC_CR bit fields */
>> +#define STM32_DAC_CR_EN1		BIT(0)
>> +#define STM32H7_DAC_CR_HFSEL		BIT(15)
>> +#define STM32_DAC_CR_EN2		BIT(16)
>> +
>> +/**
>> + * struct stm32_dac_common - stm32 DAC driver common data (for all instances)
>> + * @regmap: DAC registers shared via regmap
>> + * @vref_mv: reference voltage (mv)
>> + * @hfsel: high speed bus clock
>> + */
>> +struct stm32_dac_common {
>> +	struct regmap			*regmap;
>> +	int				vref_mv;
>> +	bool				hfsel;
>> +};
>> +
>> +#endif
>> diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c
>> new file mode 100644
>> index 0000000..ee9711d
>> --- /dev/null
>> +++ b/drivers/iio/dac/stm32-dac.c
>> @@ -0,0 +1,296 @@
>> +/*
>> + * This file is part of STM32 DAC driver
>> + *
>> + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
>> + * Authors: Amelie Delaunay <amelie.delaunay@st.com>
>> + *	    Fabrice Gasnier <fabrice.gasnier@st.com>
>> + *
>> + * License type: GPLv2
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2 as published by
>> + * the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope that it will be useful, but
>> + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
>> + * or FITNESS FOR A PARTICULAR PURPOSE.
>> + * See the GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License along with
>> + * this program. If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include <linux/bitfield.h>
>> +#include <linux/delay.h>
>> +#include <linux/iio/iio.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +
>> +#include "stm32-dac-core.h"
>> +
>> +#define STM32_DAC_CHANNEL_1		1
>> +#define STM32_DAC_CHANNEL_2		2
>> +
>> +/**
>> + * struct stm32_dac - private data of DAC driver
>> + * @common:		reference to DAC common data
>> + */
>> +struct stm32_dac {
>> +	struct stm32_dac_common *common;
>> +};
>> +
>> +static int stm32_dac_is_enabled(struct stm32_dac *dac, int channel)
>> +{
>> +	u32 en, val;
>> +	int ret;
>> +
>> +	ret = regmap_read(dac->common->regmap, STM32_DAC_CR, &val);
>> +	if (ret < 0)
>> +		return ret;
>> +	if (channel == STM32_DAC_CHANNEL_1)
>> +		en = FIELD_GET(STM32_DAC_CR_EN1, val);
>> +	else
>> +		en = FIELD_GET(STM32_DAC_CR_EN2, val);
>> +
>> +	return !!en;
>> +}
>> +
>> +static int stm32_dac_enable(struct iio_dev *indio_dev, int channel)
>> +{
>> +	struct stm32_dac *dac = iio_priv(indio_dev);
>> +	u32 en = (channel == STM32_DAC_CHANNEL_1) ?
>> +		STM32_DAC_CR_EN1 : STM32_DAC_CR_EN2;
>> +	int ret;
>> +
>> +	ret = regmap_update_bits(dac->common->regmap, STM32_DAC_CR, en, en);
>> +	if (ret < 0) {
>> +		dev_err(&indio_dev->dev, "Enable failed\n");
>> +		return ret;
>> +	}
>> +
>> +	/*
>> +	 * When HFSEL is set, it is not allowed to write the DHRx register
>> +	 * during 8 clock cycles after the ENx bit is set. It is not allowed
>> +	 * to make software/hardware trigger during this period neither.
>> +	 */
>> +	if (dac->common->hfsel)
>> +		udelay(1);
>> +
>> +	return 0;
>> +}
>> +
>> +static int stm32_dac_disable(struct iio_dev *indio_dev, int channel)
>> +{
>> +	struct stm32_dac *dac = iio_priv(indio_dev);
>> +	u32 en = (channel == STM32_DAC_CHANNEL_1) ?
>> +		STM32_DAC_CR_EN1 : STM32_DAC_CR_EN2;
>> +	int ret;
>> +
>> +	ret = regmap_update_bits(dac->common->regmap, STM32_DAC_CR, en, 0);
>> +	if (ret)
>> +		dev_err(&indio_dev->dev, "Disable failed\n");
>> +
>> +	return ret;
>> +}
>> +
>> +static int stm32_dac_get_value(struct stm32_dac *dac, int channel, int *val)
>> +{
>> +	int ret;
>> +
>> +	if (channel == STM32_DAC_CHANNEL_1)
>> +		ret = regmap_read(dac->common->regmap, STM32_DAC_DOR1, val);
>> +	else
>> +		ret = regmap_read(dac->common->regmap, STM32_DAC_DOR2, val);
>> +
>> +	return ret ? ret : IIO_VAL_INT;
>> +}
>> +
>> +static int stm32_dac_set_value(struct stm32_dac *dac, int channel, int val)
>> +{
>> +	int ret;
>> +
>> +	if (channel == STM32_DAC_CHANNEL_1)
>> +		ret = regmap_write(dac->common->regmap, STM32_DAC_DHR12R1, val);
>> +	else
>> +		ret = regmap_write(dac->common->regmap, STM32_DAC_DHR12R2, val);
>> +
>> +	return ret;
>> +}
>> +
>> +static int stm32_dac_read_raw(struct iio_dev *indio_dev,
>> +			      struct iio_chan_spec const *chan,
>> +			      int *val, int *val2, long mask)
>> +{
>> +	struct stm32_dac *dac = iio_priv(indio_dev);
>> +	int ret;
>> +
>> +	switch (mask) {
>> +	case IIO_CHAN_INFO_RAW:
>> +		return stm32_dac_get_value(dac, chan->channel, val);
>> +	case IIO_CHAN_INFO_SCALE:
>> +		*val = dac->common->vref_mv;
>> +		*val2 = chan->scan_type.realbits;
>> +		return IIO_VAL_FRACTIONAL_LOG2;
>> +	case IIO_CHAN_INFO_ENABLE:
>> +		ret = stm32_dac_is_enabled(dac, chan->channel);
>> +		if (ret < 0)
>> +			return ret;
>> +		*val = ret;
>> +		return IIO_VAL_INT;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +}
>> +
>> +static int stm32_dac_write_raw(struct iio_dev *indio_dev,
>> +			       struct iio_chan_spec const *chan,
>> +			       int val, int val2, long mask)
>> +{
>> +	struct stm32_dac *dac = iio_priv(indio_dev);
>> +
>> +	switch (mask) {
>> +	case IIO_CHAN_INFO_RAW:
>> +		return stm32_dac_set_value(dac, chan->channel, val);
>> +	case IIO_CHAN_INFO_ENABLE:
>> +		if (!!val)
>> +			return stm32_dac_enable(indio_dev, chan->channel);
>> +		else
>> +			return stm32_dac_disable(indio_dev, chan->channel);
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +}
>> +
>> +static int stm32_dac_debugfs_reg_access(struct iio_dev *indio_dev,
>> +					unsigned reg, unsigned writeval,
>> +					unsigned *readval)
>> +{
>> +	struct stm32_dac *dac = iio_priv(indio_dev);
>> +
>> +	if (!readval)
>> +		return regmap_write(dac->common->regmap, reg, writeval);
>> +	else
>> +		return regmap_read(dac->common->regmap, reg, readval);
>> +}
>> +
>> +static const struct iio_info stm32_dac_iio_info = {
>> +	.read_raw = &stm32_dac_read_raw,
>> +	.write_raw = &stm32_dac_write_raw,
>> +	.debugfs_reg_access = &stm32_dac_debugfs_reg_access,
>> +	.driver_module = THIS_MODULE,
>> +};
>> +
>> +#define STM32_DAC_CHANNEL(chan, name) {		\
>> +	.type = IIO_VOLTAGE,			\
>> +	.indexed = 1,				\
>> +	.output = 1,				\
>> +	.channel = chan,			\
>> +	.info_mask_separate =			\
>> +		BIT(IIO_CHAN_INFO_RAW) |	\
>> +		BIT(IIO_CHAN_INFO_ENABLE) |	\
>> +		BIT(IIO_CHAN_INFO_SCALE),	\
>> +	.scan_type = {				\
>> +		.sign = 'u',			\
>> +		.realbits = 12,			\
>> +		.storagebits = 16,		\
>> +	},					\
>> +	.datasheet_name = name,			\
>> +}
>> +
>> +static const struct iio_chan_spec stm32_dac_channels[] = {
>> +	STM32_DAC_CHANNEL(STM32_DAC_CHANNEL_1, "out1"),
>> +	STM32_DAC_CHANNEL(STM32_DAC_CHANNEL_2, "out2"),
>> +};
>> +
>> +static int stm32_dac_chan_of_init(struct iio_dev *indio_dev)
>> +{
>> +	struct device_node *np = indio_dev->dev.of_node;
>> +	unsigned int i;
>> +	u32 channel;
>> +	int ret;
>> +
>> +	ret = of_property_read_u32(np, "st,dac-channel", &channel);
>> +	if (ret) {
>> +		dev_err(&indio_dev->dev, "Failed to read st,dac-channel\n");
>> +		return ret;
>> +	}
>> +
>> +	for (i = 0; i < ARRAY_SIZE(stm32_dac_channels); i++) {
>> +		if (stm32_dac_channels[i].channel == channel)
>> +			break;
>> +	}
>> +	if (i >= ARRAY_SIZE(stm32_dac_channels)) {
>> +		dev_err(&indio_dev->dev, "Invalid st,dac-channel\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	indio_dev->channels = &stm32_dac_channels[i];
>> +	indio_dev->num_channels = 1;
>> +
>> +	return 0;
>> +};
>> +
>> +static int stm32_dac_probe(struct platform_device *pdev)
>> +{
>> +	struct device_node *np = pdev->dev.of_node;
>> +	struct iio_dev *indio_dev;
>> +	struct stm32_dac *dac;
>> +	int ret;
>> +
>> +	if (!np)
>> +		return -ENODEV;
>> +
>> +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*dac));
>> +	if (!indio_dev)
>> +		return -ENOMEM;
>> +	platform_set_drvdata(pdev, indio_dev);
>> +
>> +	dac = iio_priv(indio_dev);
>> +	dac->common = dev_get_drvdata(pdev->dev.parent);
>> +	indio_dev->name = dev_name(&pdev->dev);
>> +	indio_dev->dev.parent = &pdev->dev;
>> +	indio_dev->dev.of_node = pdev->dev.of_node;
>> +	indio_dev->info = &stm32_dac_iio_info;
>> +	indio_dev->modes = INDIO_DIRECT_MODE;
>> +
>> +	ret = stm32_dac_chan_of_init(indio_dev);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	ret = iio_device_register(indio_dev);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return 0;
>> +}
>> +
>> +static int stm32_dac_remove(struct platform_device *pdev)
>> +{
>> +	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
>> +
>> +	iio_device_unregister(indio_dev);
> use devm_iio_device_register and drop the remove entirely
> (I guess this may make no sense once I've looked at later
> patches however!)
Good guess ;-)
But okay, I'll use devm_ anyway, regardless of other patches.

Thanks & Regards,
Fabrice

>> +
>> +	return 0;
>> +}
>> +
>> +static const struct of_device_id stm32_dac_of_match[] = {
>> +	{ .compatible = "st,stm32-dac", },
>> +	{},
>> +};
>> +MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
>> +
>> +static struct platform_driver stm32_dac_driver = {
>> +	.probe = stm32_dac_probe,
>> +	.remove = stm32_dac_remove,
>> +	.driver = {
>> +		.name = "stm32-dac",
>> +		.of_match_table = stm32_dac_of_match,
>> +	},
>> +};
>> +module_platform_driver(stm32_dac_driver);
>> +
>> +MODULE_ALIAS("platform:stm32-dac");
>> +MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>");
>> +MODULE_DESCRIPTION("STMicroelectronics STM32 DAC driver");
>> +MODULE_LICENSE("GPL v2");
>>
> 

^ permalink raw reply

* Re: [RFC] [media] imx: assume MEDIA_ENT_F_ATV_DECODER entities output video on pad 1
From: Devin Heitmueller @ 2017-04-05 15:39 UTC (permalink / raw)
  To: Mauro Carvalho Chehab
  Cc: mark.rutland, andrew-ct.chen, minghsiu.tsai,
	sakari.ailus@linux.intel.com, nick, songjun.wu, Hans Verkuil,
	Steve Longerbeam, Pavel Machek, robert.jarzmik, devel,
	markus.heiser, laurent.pinchart+renesas, shuah,
	Russell King - ARM Linux, geert, Steve Longerbeam,
	Linux Media Mailing List, devicetree, Philipp Zabel,
	Arnd Bergmann, Mauro Carvalho Chehab, bparrot, robh+dt,
	horms+renesas, tiffany.lin, linux-arm-kernel
In-Reply-To: <20170405115336.7135e542@vento.lan>

> Currently, the driver doesn't support (2), because, at the time
> I wrote the driver, I didn't find a way to read the interrupts generated
> by tvp5150 at em28xx[1], due to the lack of em28xx documentation,
> but adding support for it shoudn't be hard. I may eventually do it
> when I have some time to play with my ISEE hardware.

For what it's worth, I doubt most of the em28xx designs have the
tvp5150 interrupt request line connected in any way.  You would likely
have to poll the FIFO status register via I2C, or use the feature to
embed the sliced data into as VANC data in the 656 output (as
described in sec 3.9 of the tvp5150am1 spec).

Devin

-- 
Devin J. Heitmueller - Kernel Labs
http://www.kernellabs.com

^ permalink raw reply

* Re: [PATCH] ARM: dts: armada-385-linksys: disk-activity trigger for all
From: Gregory CLEMENT @ 2017-04-05 15:27 UTC (permalink / raw)
  To: Ralph Sennhauser
  Cc: Andrew Lunn, linux-arm-kernel, Jason Cooper,
	Sebastian Hesselbarth, Rob Herring, Mark Rutland, Russell King,
	devicetree, linux-kernel
In-Reply-To: <20170331153549.GA12814@lunn.ch>

Hi Ralph,
 
 On ven., mars 31 2017, Andrew Lunn <andrew@lunn.ch> wrote:

> On Thu, Mar 30, 2017 at 06:54:04PM +0200, Ralph Sennhauser wrote:
>> Commit a4ee7e18d808 ("ARM: dts: armada: Add default trigger for sata
>> led") adds the default trigger to individual boards, move it to
>> armada-385-linksys.dtsi which effectively enables the definition for
>> the WRT1900ACS (Shelby) as well as for future boards.
>> 
>> Signed-off-by: Ralph Sennhauser <ralph.sennhauser@gmail.com>
>
> Centralising this makes sense.
>
> Reviewed-by: Andrew Lunn <andrew@lunn.ch>

Applied on mvebu/dt

Thanks,

Gregory


-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply

* Re: [PATCH V7 0/4] phy: USB and PCIe phy drivers for Qcom chipsets
From: Vivek Gautam @ 2017-04-05 15:24 UTC (permalink / raw)
  To: Kishon Vijay Abraham I
  Cc: robh+dt, linux-arm-kernel@lists.infradead.org, linux-arm-msm,
	linux-kernel@vger.kernel.org, Linux USB Mailing List,
	devicetree@vger.kernel.org, Mark Rutland, Stephen Boyd,
	Bjorn Andersson, Srinivas Kandagatla
In-Reply-To: <a59d6776-5855-9d04-a5be-de03456b8d2e@ti.com>

Hi Kishon,


On Wed, Apr 5, 2017 at 7:08 PM, Kishon Vijay Abraham I <kishon@ti.com> wrote:
> Hi Vivek,
>
> On Wednesday 05 April 2017 06:02 PM, Vivek Gautam wrote:
>> This patch series adds couple of PHY drivers for Qualcomm chipsets.
>> a) qcom-qusb2 phy driver: that provides High Speed USB functionality.
>> b) qcom-qmp phy driver: that is a combo phy providing support for
>>    USB3, PCIe, UFS and few other controllers.
>>
>> The patches are based on next branch of linux-phy tree.
>>
>> These patches have been tested on Dragon board db820c hardware with
>> required set of dt patches and the patches to get rpm up on msm8996.
>> Couple of other patches [1, 2] fixing DMA config for XHCI are also
>> pulled in for testing.
>> A branch based on torvald's master is available in github [3].
>
> I get a bunch of checkpatch errors/warnings when I run checkpatch with --strict
> option. Those look simple enough to be fixed. Can you respin your series fixing
> those?

Sure, I am on it.
Thanks for pointing out.

Regards
Vivek

>
> Thanks
> Kishon
>
>>
>> Changes since v6:
>>  - Rebased on phy/next and *not* including phy grouping series[4].
>>  - qusb2-phy: addressed Stephen's comment.
>>    - Dropped pm8994_s2 corner regulator from QUSB2 phy bindings.
>>  - qmp-phy: none on functionality side.
>>
>> Changes since v5:
>>  - Addressed review comments from Bjorn:
>>    - Removed instances of readl/wirtel_relaxed calls from the drivers.
>>      Instead, using simple readl/writel. Inserting a readl after a writel
>>      to ensure the write is through to the device.
>>    - Replaced regulator handling with regulator_bulk_** apis. This helps
>>      in cutting down a lot of regulator handling code.
>>    - Fixed minor return statements.
>>
>> Changes since v4:
>>  - Addressed comment to add child nodes for qmp phy driver. Each phy lane
>>    now has a separate child node under the main qmp node.
>>  - Modified the clock and reset initialization and enable methods.
>>    Different phys - pcie, usb and later ufs, have varying number of clocks
>>    and resets that are mandatory. So adding provision for clocks and reset
>>    lists helps in requesting all mandatory resources for individual phys
>>    and handle their failure cases accordingly.
>>
>> Changes since v3:
>>  - Addressed review comments given by Rob and Stephen for qusb2 phy
>>    and qmp phy bindings respectively.
>>  - Addressed review comments given by Stephen and Bjorn for qmp phy driver.
>>
>> Changes since v2:
>>  - Addressed review comments given by Rob and Stephen for bindings.
>>  - Addressed the review comments given by Stephen for the qusb2 and qmp
>>    phy drivers.
>>
>> Changes since v1:
>>  - Moved device tree binding documentation to separate patches, as suggested
>>    by Rob.
>>  - Addressed review comment regarding qfprom accesses by qusb2 phy driver,
>>    given by Rob.
>>  - Addressed review comments from Kishon.
>>  - Addressed review comments from Srinivas for QMP phy driver.
>>  - Addressed kbuild warning.
>>
>> Please see individual patches for detailed changelogs.
>>
>> [1] https://patchwork.kernel.org/patch/9567767/
>> [2] https://patchwork.kernel.org/patch/9567779/
>> [3] https://github.com/vivekgautam1/linux/tree/linux-v4.11-rc5-qmp-phy-db820c
>> [4] https://lkml.org/lkml/2017/3/20/407
>>
>> Vivek Gautam (4):
>>   dt-bindings: phy: Add support for QUSB2 phy
>>   phy: qcom-qusb2: New driver for QUSB2 PHY on Qcom chips
>>   dt-bindings: phy: Add support for QMP phy
>>   phy: qcom-qmp: new qmp phy driver for qcom-chipsets
>>
>>  .../devicetree/bindings/phy/qcom-qmp-phy.txt       |  106 ++
>>  .../devicetree/bindings/phy/qcom-qusb2-phy.txt     |   43 +
>>  drivers/phy/Kconfig                                |   18 +
>>  drivers/phy/Makefile                               |    2 +
>>  drivers/phy/phy-qcom-qmp.c                         | 1153 ++++++++++++++++++++
>>  drivers/phy/phy-qcom-qusb2.c                       |  491 +++++++++
>>  6 files changed, 1813 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
>>  create mode 100644 Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
>>  create mode 100644 drivers/phy/phy-qcom-qmp.c
>>  create mode 100644 drivers/phy/phy-qcom-qusb2.c
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* Re: [PATCH 1/1] ARM: dts: armada-xp-linksys-mamba: use wan instead of internet for DSA port
From: Ralph Sennhauser @ 2017-04-05 15:22 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Mark Rutland,
	Jason Cooper, devicetree-u79uwXL29TY76Z2rM5mHXA, Russell King,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Gregory Clement, Rob Herring,
	Sebastian Hesselbarth
In-Reply-To: <20170405142824.GB13449-g2DYL2Zd6BY@public.gmane.org>

On Wed, 5 Apr 2017 16:28:24 +0200
Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org> wrote:

> On Wed, Apr 05, 2017 at 07:28:46AM +0200, Ralph Sennhauser wrote:
> > The LEDs for the "wan" port are already labeled "mamba:amber:wan"
> > resp. "mamba:white:wan". So besides being an outlier with regard to
> > the rest of the product line (see table below) changing the label
> > fixes an internal inconsistency as well.
> > 
> > This will be visible in user space. Given commit cb4f71c42988 ("ARM:
> > dts: armada-38x: change order of ethernet DT nodes on Armada 38x")
> > it's expected to happen anyway. Commit 499400c9ac20 ("ARM: dts:
> > armada-xp-linksys-mamba: Utilize new DSA binding") switches to the
> > new bindings, use this opportunity to do it now rather than later.
> > 
> > |-----------------------------------------------------------------|
> > | Labels used for the case and those used for the DSA ports       |
> > |-----------------------------------------------------------------|
> > | case labels	| armada-385-linksys-*	|
> > armada-xp-linksys-mamba |
> > |---------------|-----------------------|-------------------------|
> > | internet	| wan			|
> > internet		  | | 1		|
> > lan1			| lan1			  | |
> > 2		| lan2			|
> > lan2			  | | 3		|
> > lan3			| lan3			  | |
> > 4		| lan4			|
> > lan4			  |
> > |-----------------------------------------------------------------|  
> 
> Hi Ralph
> 
> I always encourage people to use the case labels as interface names.
> So if i was going to make a change, it would be wan->internet for the 
> armada-385-linksys-*.

Glad Imre used lan1 instead of 1 ;) 

The reverse I have appended to this mail so people know what it would
look like.

In fact "internet" label on the case is uppercase, would this matter
for you for new bindings, or would you still use the lowercase version?
It's not relevant here, just wondering.

> 
> > I underestimated the urge of people to make all the same before.
> > While I do not particularly like this sort of change I see it
> > coming anyway. So this patch is meant to make it a deliberate
> > decision so it no longer is an item lurking in the shadows. Whether
> > this patch gets taken or rejected my goal is reached.  
> 
> I would say, this is now too late. Changing an interface name will
> break configuration scripts. We are stuck with it.
> 

If it weren't for commit cb4f71c42988 that would have been obvious for
me as well.

Thanks
Ralph



The inverse (following trough all the way) would look the following,
same changes applies to Rango which is not yet supported by vanilla
kernel.

diff --git a/arch/arm/boot/dts/armada-385-linksys-caiman.dts b/arch/arm/boot/dts/armada-385-linksys-caiman.dts
index a1b6e68..3efceda 100644
--- a/arch/arm/boot/dts/armada-385-linksys-caiman.dts
+++ b/arch/arm/boot/dts/armada-385-linksys-caiman.dts
@@ -53,13 +53,13 @@
 				#address-cells = <1>;
 				#size-cells = <0>;
 
-					wan_amber@0 {
-						label = "caiman:amber:wan";
+					internet_amber@0 {
+						label = "caiman:amber:internet";
 						reg = <0x0>;
 					};
 
-					wan_white@1 {
-						label = "caiman:white:wan";
+					internet_white@1 {
+						label = "caiman:white:internet";
 						reg = <0x1>;
 					};
 
diff --git a/arch/arm/boot/dts/armada-385-linksys-cobra.dts b/arch/arm/boot/dts/armada-385-linksys-cobra.dts
index a1a75af..4f2e7f6 100644
--- a/arch/arm/boot/dts/armada-385-linksys-cobra.dts
+++ b/arch/arm/boot/dts/armada-385-linksys-cobra.dts
@@ -53,13 +53,13 @@
 				#address-cells = <1>;
 				#size-cells = <0>;
 
-					wan_amber@0 {
-						label = "cobra:amber:wan";
+					internet_amber@0 {
+						label = "cobra:amber:internet";
 						reg = <0x0>;
 					};
 
-					wan_white@1 {
-						label = "cobra:white:wan";
+					internet_white@1 {
+						label = "cobra:white:internet";
 						reg = <0x1>;
 					};
 
diff --git a/arch/arm/boot/dts/armada-385-linksys-shelby.dts b/arch/arm/boot/dts/armada-385-linksys-shelby.dts
index c7a8ddd..a7b47f7 100644
--- a/arch/arm/boot/dts/armada-385-linksys-shelby.dts
+++ b/arch/arm/boot/dts/armada-385-linksys-shelby.dts
@@ -53,13 +53,13 @@
 				#address-cells = <1>;
 				#size-cells = <0>;
 
-					wan_amber@0 {
-						label = "shelby:amber:wan";
+					internet_amber@0 {
+						label = "shelby:amber:internet";
 						reg = <0x0>;
 					};
 
-					wan_white@1 {
-						label = "shelby:white:wan";
+					internet_white@1 {
+						label = "shelby:white:internet";
 						reg = <0x1>;
 					};
 
diff --git a/arch/arm/boot/dts/armada-385-linksys.dtsi b/arch/arm/boot/dts/armada-385-linksys.dtsi
index aa0d225..8460066 100644
--- a/arch/arm/boot/dts/armada-385-linksys.dtsi
+++ b/arch/arm/boot/dts/armada-385-linksys.dtsi
@@ -145,7 +145,7 @@
 
 						port@4 {
 							reg = <4>;
-							label = "wan";
+							label = "internet";
 						};
 
 						port@5 {
@@ -360,7 +360,7 @@
 
 			port@4 {
 				reg = <4>;
-				label = "wan";
+				label = "internet";
 			};
 
 			port@5 {
diff --git a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
index 9efcf59..ed2fe8f 100644
--- a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
+++ b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
@@ -140,13 +140,13 @@
 					compatible = "ti,tlc59116";
 					reg = <0x68>;
 
-					wan_amber@0 {
-						label = "mamba:amber:wan";
+					internet_amber@0 {
+						label = "mamba:amber:internet";
 						reg = <0x0>;
 					};
 
-					wan_white@1 {
-						label = "mamba:white:wan";
+					internet_white@1 {
+						label = "mamba:white:internet";
 						reg = <0x1>;
 					};
 
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v4 7/7] ARM64: dts: marvell: armada37xx: add pinctrl definition
From: Gregory CLEMENT @ 2017-04-05 15:18 UTC (permalink / raw)
  To: Linus Walleij, linux-gpio
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, Gregory CLEMENT,
	Thomas Petazzoni, linux-arm-kernel, Rob Herring, devicetree,
	linux-kernel, Nadav Haklai, Victor Gu, Marcin Wojtas, Wilson Ding,
	Hua Jing, Neta Zur Hershkovits
In-Reply-To: <cover.65d0e6796fecf1fe6c5d07b981160b54dc9b4acd.1491405475.git-series.gregory.clement@free-electrons.com>

Start to populate the device tree of the Armada 37xx with the pincontrol
configuration used on the board providing a dts.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 arch/arm64/boot/dts/marvell/armada-3720-db.dts |  8 +++++-
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi   | 31 +++++++++++++++++++-
 2 files changed, 39 insertions(+)

diff --git a/arch/arm64/boot/dts/marvell/armada-3720-db.dts b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
index 86602c907a61..e749c5727490 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-db.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
@@ -63,6 +63,8 @@
 };
 
 &i2c0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c1_pins>;
 	status = "okay";
 };
 
@@ -73,6 +75,8 @@
 
 &spi0 {
 	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi_quad_pins>;
 
 	m25p80@0 {
 		compatible = "jedec,spi-nor";
@@ -103,6 +107,8 @@
 
 /* Exported on the micro USB connector CON32 through an FTDI */
 &uart0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart1_pins>;
 	status = "okay";
 };
 
@@ -128,6 +134,8 @@
 };
 
 &eth0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&rgmii_pins>;
 	phy-mode = "rgmii-id";
 	phy = <&phy0>;
 	status = "okay";
diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index c02b13479458..2ac25f54d01d 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -186,6 +186,31 @@
 					clock-output-names = "xtal";
 					#clock-cells = <0>;
 				};
+
+				spi_quad_pins: spi-quad-pins {
+					groups = "spi_quad";
+					function = "spi";
+				};
+
+				i2c1_pins: i2c1-pins {
+					groups = "i2c1";
+					function = "i2c";
+				};
+
+				i2c2_pins: i2c2-pins {
+					groups = "i2c2";
+					function = "i2c";
+				};
+
+				uart1_pins: uart1-pins {
+					groups = "uart1";
+					function = "uart";
+				};
+
+				uart2_pins: uart2-pins {
+					groups = "uart2";
+					function = "uart";
+				};
 			};
 
 			pinctrl_sb: pinctrl-sb@18800 {
@@ -203,6 +228,12 @@
 					<GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
 					<GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
 				};
+
+				rgmii_pins: mii-pins {
+					groups = "rgmii";
+					function = "mii";
+				};
+
 			};
 
 			eth0: ethernet@30000 {
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH v4 6/7] ARM64: dts: marvell: Add pinctrl nodes for Armada 3700
From: Gregory CLEMENT @ 2017-04-05 15:18 UTC (permalink / raw)
  To: Linus Walleij, linux-gpio-u79uwXL29TY76Z2rM5mHXA
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, Gregory CLEMENT,
	Thomas Petazzoni,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Rob Herring,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Nadav Haklai, Victor Gu,
	Marcin Wojtas, Wilson Ding, Hua Jing, Neta Zur Hershkovits
In-Reply-To: <cover.65d0e6796fecf1fe6c5d07b981160b54dc9b4acd.1491405475.git-series.gregory.clement-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

Add the nodes for the two pin controller present in the Armada 37xx SoCs.

Initially the node was named gpio1 using the same name that for the
register range in the datasheet. However renaming it pinctr_nb (nb for
North Bridge) makes more sens.

Signed-off-by: Gregory CLEMENT <gregory.clement-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 42 +++++++++++++++++++--
 1 file changed, 39 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index b48d668a6ab6..c02b13479458 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -157,10 +157,29 @@
 				#clock-cells = <1>;
 			};
 
-			gpio1: gpio@13800 {
-				compatible = "marvell,mvebu-gpio-3700",
+			pinctrl_nb: pinctrl-nb@13800 {
+				compatible = "marvell,armada3710-nb-pinctrl",
 				"syscon", "simple-mfd";
-				reg = <0x13800 0x500>;
+				reg = <0x13800 0x100>, <0x13C00 0x20>;
+				gpionb: gpionb {
+					#gpio-cells = <2>;
+					gpio-ranges = <&pinctrl_nb 0 0 36>;
+					gpio-controller;
+					interrupts =
+					<GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 153 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 154 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 155 IRQ_TYPE_LEVEL_HIGH>;
+
+				};
 
 				xtalclk: xtal-clk {
 					compatible = "marvell,armada-3700-xtal-clock";
@@ -169,6 +188,23 @@
 				};
 			};
 
+			pinctrl_sb: pinctrl-sb@18800 {
+				compatible = "marvell,armada3710-sb-pinctrl",
+				"syscon", "simple-mfd";
+				reg = <0x18800 0x100>, <0x18C00 0x20>;
+				gpiosb: gpiosb {
+					#gpio-cells = <2>;
+					gpio-ranges = <&pinctrl_sb 0 0 29>;
+					gpio-controller;
+					interrupts =
+					<GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
+					<GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
+				};
+			};
+
 			eth0: ethernet@30000 {
 				   compatible = "marvell,armada-3700-neta";
 				   reg = <0x30000 0x4000>;
-- 
git-series 0.9.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v4 5/7] pinctrl: aramda-37xx: Add irqchip support
From: Gregory CLEMENT @ 2017-04-05 15:18 UTC (permalink / raw)
  To: Linus Walleij, linux-gpio
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, Gregory CLEMENT,
	Thomas Petazzoni, linux-arm-kernel, Rob Herring, devicetree,
	linux-kernel, Nadav Haklai, Victor Gu, Marcin Wojtas, Wilson Ding,
	Hua Jing, Neta Zur Hershkovits
In-Reply-To: <cover.65d0e6796fecf1fe6c5d07b981160b54dc9b4acd.1491405475.git-series.gregory.clement@free-electrons.com>

The Armada 37xx SoCs can handle interrupt through GPIO. However it can
only manage the edge ones.

The way the interrupt are managed are classical so we can use the generic
interrupt chip model.

The only unusual "feature" is that many interrupts are connected to the
parent interrupt controller. But we do not take advantage of this and use
the chained irq with all of them.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c | 221 +++++++++++++++++++++-
 1 file changed, 221 insertions(+)

diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
index 5c96f5558310..7356516e0921 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
@@ -13,7 +13,9 @@
 #include <linux/gpio/driver.h>
 #include <linux/mfd/syscon.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
 #include <linux/of_device.h>
+#include <linux/of_irq.h>
 #include <linux/pinctrl/pinconf-generic.h>
 #include <linux/pinctrl/pinconf.h>
 #include <linux/pinctrl/pinctrl.h>
@@ -30,6 +32,11 @@
 #define OUTPUT_CTL	0x20
 #define SELECTION	0x30
 
+#define IRQ_EN		0x0
+#define IRQ_POL		0x08
+#define IRQ_STATUS	0x10
+#define IRQ_WKUP	0x18
+
 #define NB_FUNCS 2
 #define GPIO_PER_REG	32
 
@@ -75,9 +82,12 @@ struct armada_37xx_pmx_func {
 
 struct armada_37xx_pinctrl {
 	struct regmap			*regmap;
+	void __iomem			*base;
 	const struct armada_37xx_pin_data	*data;
 	struct device			*dev;
 	struct gpio_chip		gpio_chip;
+	struct irq_chip			irq_chip;
+	spinlock_t			irq_lock;
 	struct pinctrl_desc		pctl;
 	struct pinctrl_dev		*pctl_dev;
 	struct armada_37xx_pin_group	*groups;
@@ -346,6 +356,14 @@ static int armada_37xx_pmx_set(struct pinctrl_dev *pctldev,
 	return armada_37xx_pmx_set_by_name(pctldev, name, grp);
 }
 
+static inline void armada_37xx_irq_update_reg(unsigned int *reg,
+					  struct irq_data *d)
+{
+	int offset = irqd_to_hwirq(d);
+
+	armada_37xx_update_reg(reg, offset);
+}
+
 static int armada_37xx_gpio_direction_input(struct gpio_chip *chip,
 					    unsigned int offset)
 {
@@ -468,6 +486,206 @@ static const struct gpio_chip armada_37xx_gpiolib_chip = {
 	.owner = THIS_MODULE,
 };
 
+void armada_37xx_irq_ack(struct irq_data *d)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
+	u32 reg = IRQ_STATUS, mask = d->mask;
+	unsigned long flags;
+
+	armada_37xx_irq_update_reg(&reg, d);
+	spin_lock_irqsave(&info->irq_lock, flags);
+	writel(mask, info->base + reg);
+	spin_unlock_irqrestore(&info->irq_lock, flags);
+}
+
+void armada_37xx_irq_mask(struct irq_data *d)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
+	u32 val, reg = IRQ_EN, mask = d->mask;
+	unsigned long flags;
+
+	armada_37xx_irq_update_reg(&reg, d);
+	spin_lock_irqsave(&info->irq_lock, flags);
+	val = readl(info->base + reg);
+	writel(val & ~mask, info->base + reg);
+	spin_unlock_irqrestore(&info->irq_lock, flags);
+}
+
+void armada_37xx_irq_unmask(struct irq_data *d)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
+	u32 val, reg = IRQ_EN, mask = d->mask;
+	unsigned long flags;
+
+	armada_37xx_irq_update_reg(&reg, d);
+	spin_lock_irqsave(&info->irq_lock, flags);
+	val = readl(info->base + reg);
+	writel(val | mask, info->base + reg);
+	spin_unlock_irqrestore(&info->irq_lock, flags);
+}
+
+static int armada_37xx_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
+	u32 val, reg = IRQ_WKUP, mask = d->mask;
+	unsigned long flags;
+
+	armada_37xx_irq_update_reg(&reg, d);
+	spin_lock_irqsave(&info->irq_lock, flags);
+	val = readl(info->base + reg);
+	if (on)
+		val |= mask;
+	else
+		val &= ~mask;
+	writel(val, info->base + reg);
+	spin_unlock_irqrestore(&info->irq_lock, flags);
+
+	return 0;
+}
+
+static int armada_37xx_irq_set_type(struct irq_data *d, unsigned int type)
+{
+	struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
+	u32 val, reg = IRQ_POL, mask = d->mask;
+	unsigned long flags;
+
+	spin_lock_irqsave(&info->irq_lock, flags);
+	armada_37xx_irq_update_reg(&reg, d);
+	val = readl(info->base + reg);
+	switch (type) {
+	case IRQ_TYPE_EDGE_RISING:
+		val &= ~mask;
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		val |= mask;
+		break;
+	default:
+		spin_unlock_irqrestore(&info->irq_lock, flags);
+		return -EINVAL;
+	}
+	writel(val, info->base + reg);
+	spin_unlock_irqrestore(&info->irq_lock, flags);
+
+	return 0;
+}
+
+
+static void armada_37xx_irq_handler(struct irq_desc *desc)
+{
+	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(gc);
+	struct irq_domain *d = gc->irqdomain;
+	int i;
+
+	chained_irq_enter(chip, desc);
+	for (i = 0; i <= d->revmap_size / GPIO_PER_REG; i++) {
+		u32 status;
+		unsigned long flags;
+
+		spin_lock_irqsave(&info->irq_lock, flags);
+		status = readl_relaxed(info->base + IRQ_STATUS + 4 * i);
+		/* Manage only the interrupt that was enabled */
+		status &= readl_relaxed(info->base + IRQ_EN + 4 * i);
+		spin_unlock_irqrestore(&info->irq_lock, flags);
+		while (status) {
+			u32 hwirq = ffs(status) - 1;
+			u32 virq = irq_find_mapping(d, hwirq +
+						     i * GPIO_PER_REG);
+
+			generic_handle_irq(virq);
+			status &= ~BIT(hwirq);
+		}
+	}
+	chained_irq_exit(chip, desc);
+}
+
+static int armada_37xx_irqchip_register(struct platform_device *pdev,
+					struct armada_37xx_pinctrl *info)
+{
+	struct device_node *np = info->dev->of_node;
+	int nrirqs = info->data->nr_pins;
+	struct gpio_chip *gc = &info->gpio_chip;
+	struct irq_chip *irqchip = &info->irq_chip;
+	struct resource res;
+	int ret = -ENODEV, i, nr_irq_parent;
+
+	for_each_child_of_node(info->dev->of_node, np) {
+		if (of_find_property(np, "gpio-controller", NULL)) {
+			ret = 0;
+			break;
+		}
+	};
+	if (ret)
+		return ret;
+
+	nr_irq_parent = of_irq_count(np);
+	spin_lock_init(&info->irq_lock);
+
+	if (!nr_irq_parent) {
+		dev_err(&pdev->dev, "Invalid or no IRQ\n");
+		return 0;
+	}
+
+	if (of_address_to_resource(info->dev->of_node, 1, &res)) {
+		dev_err(info->dev, "cannot find IO resource\n");
+		return -ENOENT;
+	}
+
+	info->base = devm_ioremap_resource(info->dev, &res);
+	if (IS_ERR(info->base))
+		return PTR_ERR(info->base);
+
+	irqchip->irq_ack = armada_37xx_irq_ack;
+	irqchip->irq_mask = armada_37xx_irq_mask;
+	irqchip->irq_unmask = armada_37xx_irq_unmask;
+	irqchip->irq_set_wake = armada_37xx_irq_set_wake;
+	irqchip->irq_set_type = armada_37xx_irq_set_type;
+	irqchip->name = info->data->name;
+
+	ret = gpiochip_irqchip_add(gc, irqchip, 0,
+				   handle_edge_irq, IRQ_TYPE_NONE);
+	if (ret) {
+		dev_info(&pdev->dev, "could not add irqchip\n");
+		return ret;
+	}
+
+	/*
+	 * Many interrupts are connected to the parent interrupt
+	 * controller. But we do not take advantage of this and use
+	 * the chained irq with all of them.
+	 */
+	for (i = 0; i < nrirqs; i++) {
+		struct irq_data *d = irq_get_irq_data(gc->irq_base + i);
+
+		/*
+		 * The mask field is a "precomputed bitmask for
+		 * accessing the chip registers" which was introduced
+		 * for the generic irqchip framework. As we don't use
+		 * this framework, we can reuse this field for our own
+		 * usage.
+		 */
+		d->mask = BIT(i % GPIO_PER_REG);
+	}
+
+	for (i = 0; i < nr_irq_parent; i++) {
+		int irq = irq_of_parse_and_map(np, i);
+
+		if (irq < 0)
+			continue;
+
+		gpiochip_set_chained_irqchip(gc, irqchip, irq,
+					     armada_37xx_irq_handler);
+	}
+
+	return 0;
+}
+
 static int armada_37xx_gpiochip_register(struct platform_device *pdev,
 					struct armada_37xx_pinctrl *info)
 {
@@ -496,6 +714,9 @@ static int armada_37xx_gpiochip_register(struct platform_device *pdev,
 	ret = devm_gpiochip_add_data(&pdev->dev, gc, info);
 	if (ret)
 		return ret;
+	ret = armada_37xx_irqchip_register(pdev, info);
+	if (ret)
+		return ret;
 
 	return 0;
 }
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH v4 4/7] pinctrl: armada-37xx: Add gpio support
From: Gregory CLEMENT @ 2017-04-05 15:18 UTC (permalink / raw)
  To: Linus Walleij, linux-gpio
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, Gregory CLEMENT,
	Thomas Petazzoni, linux-arm-kernel, Rob Herring, devicetree,
	linux-kernel, Nadav Haklai, Victor Gu, Marcin Wojtas, Wilson Ding,
	Hua Jing, Neta Zur Hershkovits
In-Reply-To: <cover.65d0e6796fecf1fe6c5d07b981160b54dc9b4acd.1491405475.git-series.gregory.clement@free-electrons.com>

GPIO management is pretty simple and is part of the same IP than the pin
controller for the Armada 37xx SoCs.  This patch adds the GPIO support to
the pinctrl-armada-37xx.c file, it also allows sharing common functions
between the gpiolib and the pinctrl drivers.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c | 128 ++++++++++++++++++---
 1 file changed, 114 insertions(+), 14 deletions(-)

diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
index 8b769d77db22..5c96f5558310 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
@@ -10,6 +10,7 @@
  * without any warranty of any kind, whether express or implied.
  */
 
+#include <linux/gpio/driver.h>
 #include <linux/mfd/syscon.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -24,6 +25,8 @@
 #include "../pinctrl-utils.h"
 
 #define OUTPUT_EN	0x0
+#define INPUT_VAL	0x10
+#define OUTPUT_VAL	0x18
 #define OUTPUT_CTL	0x20
 #define SELECTION	0x30
 
@@ -74,6 +77,7 @@ struct armada_37xx_pinctrl {
 	struct regmap			*regmap;
 	const struct armada_37xx_pin_data	*data;
 	struct device			*dev;
+	struct gpio_chip		gpio_chip;
 	struct pinctrl_desc		pctl;
 	struct pinctrl_dev		*pctl_dev;
 	struct armada_37xx_pin_group	*groups;
@@ -178,6 +182,16 @@ const struct armada_37xx_pin_data armada_37xx_pin_sb = {
 	.ngroups = ARRAY_SIZE(armada_37xx_sb_groups),
 };
 
+static inline void armada_37xx_update_reg(unsigned int *reg,
+					  unsigned int offset)
+{
+	/* We never have more than 2 registers */
+	if (offset >= GPIO_PER_REG) {
+		offset -= GPIO_PER_REG;
+		*reg += sizeof(u32);
+	}
+}
+
 static int armada_37xx_get_func_reg(struct armada_37xx_pin_group *grp,
 				    const char *func)
 {
@@ -332,49 +346,88 @@ static int armada_37xx_pmx_set(struct pinctrl_dev *pctldev,
 	return armada_37xx_pmx_set_by_name(pctldev, name, grp);
 }
 
-static int armada_37xx_pmx_direction_input(struct armada_37xx_pinctrl *info,
-					   unsigned int offset)
+static int armada_37xx_gpio_direction_input(struct gpio_chip *chip,
+					    unsigned int offset)
 {
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
 	unsigned int reg = OUTPUT_EN;
 	unsigned int mask;
 
-	if (offset >= GPIO_PER_REG) {
-		offset -= GPIO_PER_REG;
-		reg += sizeof(u32);
-	}
+	armada_37xx_update_reg(&reg, offset);
 	mask = BIT(offset);
 
 	return regmap_update_bits(info->regmap, reg, mask, 0);
 }
 
-static int armada_37xx_pmx_direction_output(struct armada_37xx_pinctrl *info,
-					    unsigned int offset, int value)
+static int armada_37xx_gpio_get_direction(struct gpio_chip *chip,
+					  unsigned int offset)
 {
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
+	unsigned int reg = OUTPUT_EN;
+	unsigned int val, mask;
+
+	armada_37xx_update_reg(&reg, offset);
+	mask = BIT(offset);
+	regmap_read(info->regmap, reg, &val);
+
+	return !(val & mask);
+}
+
+static int armada_37xx_gpio_direction_output(struct gpio_chip *chip,
+					     unsigned int offset, int value)
+{
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
 	unsigned int reg = OUTPUT_EN;
 	unsigned int mask;
 
-	if (offset >= GPIO_PER_REG) {
-		offset -= GPIO_PER_REG;
-		reg += sizeof(u32);
-	}
+	armada_37xx_update_reg(&reg, offset);
 	mask = BIT(offset);
 
 	return regmap_update_bits(info->regmap, reg, mask, mask);
 }
 
+static int armada_37xx_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
+	unsigned int reg = INPUT_VAL;
+	unsigned int val, mask;
+
+	armada_37xx_update_reg(&reg, offset);
+	mask = BIT(offset);
+
+	regmap_read(info->regmap, reg, &val);
+
+	return (val & mask) != 0;
+}
+
+static void armada_37xx_gpio_set(struct gpio_chip *chip, unsigned int offset,
+				 int value)
+{
+	struct armada_37xx_pinctrl *info = gpiochip_get_data(chip);
+	unsigned int reg = OUTPUT_VAL;
+	unsigned int mask, val;
+
+	armada_37xx_update_reg(&reg, offset);
+	mask = BIT(offset);
+	val = value ? mask : 0;
+
+	regmap_update_bits(info->regmap, reg, mask, val);
+}
+
 static int armada_37xx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
 					      struct pinctrl_gpio_range *range,
 					      unsigned int offset, bool input)
 {
 	struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+	struct gpio_chip *chip = range->gc;
 
 	dev_dbg(info->dev, "gpio_direction for pin %u as %s-%d to %s\n",
 		offset, range->name, offset, input ? "input" : "output");
 
 	if (input)
-		armada_37xx_pmx_direction_input(info, offset);
+		armada_37xx_gpio_direction_input(chip, offset);
 	else
-		armada_37xx_pmx_direction_output(info, offset, 0);
+		armada_37xx_gpio_direction_output(chip, offset, 0);
 
 	return 0;
 }
@@ -404,6 +457,49 @@ static const struct pinmux_ops armada_37xx_pmx_ops = {
 	.gpio_set_direction	= armada_37xx_pmx_gpio_set_direction,
 };
 
+static const struct gpio_chip armada_37xx_gpiolib_chip = {
+	.request = gpiochip_generic_request,
+	.free = gpiochip_generic_free,
+	.set = armada_37xx_gpio_set,
+	.get = armada_37xx_gpio_get,
+	.get_direction	= armada_37xx_gpio_get_direction,
+	.direction_input = armada_37xx_gpio_direction_input,
+	.direction_output = armada_37xx_gpio_direction_output,
+	.owner = THIS_MODULE,
+};
+
+static int armada_37xx_gpiochip_register(struct platform_device *pdev,
+					struct armada_37xx_pinctrl *info)
+{
+	struct device_node *np;
+	struct gpio_chip *gc;
+	int ret = -ENODEV;
+
+	for_each_child_of_node(info->dev->of_node, np) {
+		if (of_find_property(np, "gpio-controller", NULL)) {
+			ret = 0;
+			break;
+		}
+	};
+	if (ret)
+		return ret;
+
+	info->gpio_chip = armada_37xx_gpiolib_chip;
+
+	gc = &info->gpio_chip;
+	gc->ngpio = info->data->nr_pins;
+	gc->parent = &pdev->dev;
+	gc->base = -1;
+	gc->of_node = np;
+	gc->label = info->data->name;
+
+	ret = devm_gpiochip_add_data(&pdev->dev, gc, info);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
 /**
  * armada_37xx_add_function() - Add a new function to the list
  * @funcs: array of function to add the new one
@@ -632,6 +728,10 @@ static int __init armada_37xx_pinctrl_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	ret = armada_37xx_gpiochip_register(pdev, info);
+	if (ret)
+		return ret;
+
 	platform_set_drvdata(pdev, info);
 
 	return 0;
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH v4 3/7] pinctrl: armada-37xx: Add pin controller support for Armada 37xx
From: Gregory CLEMENT @ 2017-04-05 15:18 UTC (permalink / raw)
  To: Linus Walleij, linux-gpio
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, Gregory CLEMENT,
	Thomas Petazzoni, linux-arm-kernel, Rob Herring, devicetree,
	linux-kernel, Nadav Haklai, Victor Gu, Marcin Wojtas, Wilson Ding,
	Hua Jing, Neta Zur Hershkovits
In-Reply-To: <cover.65d0e6796fecf1fe6c5d07b981160b54dc9b4acd.1491405475.git-series.gregory.clement@free-electrons.com>

The Armada 37xx SoC come with 2 pin controllers: one on the south
bridge (managing 28 pins) and one on the north bridge (managing 36 pins).

At the hardware level the controller configure the pins by group and not
pin by pin. This constraint is reflected in the design of the driver:
only the group related functions are implemented.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 drivers/pinctrl/Makefile                    |   2 +-
 drivers/pinctrl/mvebu/Kconfig               |   7 +-
 drivers/pinctrl/mvebu/Makefile              |   3 +-
 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c | 648 +++++++++++++++++++++-
 4 files changed, 658 insertions(+), 2 deletions(-)
 create mode 100644 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c

diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index a251f439626f..95080811f36f 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -44,7 +44,7 @@ obj-y				+= bcm/
 obj-$(CONFIG_PINCTRL_BERLIN)	+= berlin/
 obj-y				+= freescale/
 obj-$(CONFIG_X86)		+= intel/
-obj-$(CONFIG_PINCTRL_MVEBU)	+= mvebu/
+obj-y				+= mvebu/
 obj-y				+= nomadik/
 obj-$(CONFIG_PINCTRL_PXA)	+= pxa/
 obj-$(CONFIG_ARCH_QCOM)		+= qcom/
diff --git a/drivers/pinctrl/mvebu/Kconfig b/drivers/pinctrl/mvebu/Kconfig
index 170602407c0d..5bade32d3089 100644
--- a/drivers/pinctrl/mvebu/Kconfig
+++ b/drivers/pinctrl/mvebu/Kconfig
@@ -39,3 +39,10 @@ config PINCTRL_ORION
 	select PINCTRL_MVEBU
 
 endif
+
+config PINCTRL_ARMADA_37XX
+       bool
+       select GENERIC_PINCONF
+       select MFD_SYSCON
+       select PINCONF
+       select PINMUX
diff --git a/drivers/pinctrl/mvebu/Makefile b/drivers/pinctrl/mvebu/Makefile
index 18270cd5ea43..60c245a60f39 100644
--- a/drivers/pinctrl/mvebu/Makefile
+++ b/drivers/pinctrl/mvebu/Makefile
@@ -1,4 +1,4 @@
-obj-y				+= pinctrl-mvebu.o
+obj-$(CONFIG_PINCTRL_MVEBU)	+= pinctrl-mvebu.o
 obj-$(CONFIG_PINCTRL_DOVE)	+= pinctrl-dove.o
 obj-$(CONFIG_PINCTRL_KIRKWOOD)	+= pinctrl-kirkwood.o
 obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o
@@ -6,4 +6,5 @@ obj-$(CONFIG_PINCTRL_ARMADA_375) += pinctrl-armada-375.o
 obj-$(CONFIG_PINCTRL_ARMADA_38X) += pinctrl-armada-38x.o
 obj-$(CONFIG_PINCTRL_ARMADA_39X) += pinctrl-armada-39x.o
 obj-$(CONFIG_PINCTRL_ARMADA_XP)  += pinctrl-armada-xp.o
+obj-$(CONFIG_PINCTRL_ARMADA_37XX)  += pinctrl-armada-37xx.o
 obj-$(CONFIG_PINCTRL_ORION)  += pinctrl-orion.o
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
new file mode 100644
index 000000000000..8b769d77db22
--- /dev/null
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
@@ -0,0 +1,648 @@
+/*
+ * Marvell 37xx SoC pinctrl driver
+ *
+ * Copyright (C) 2017 Marvell
+ *
+ * Gregory CLEMENT <gregory.clement@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2 or later. This program is licensed "as is"
+ * without any warranty of any kind, whether express or implied.
+ */
+
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include "../pinctrl-utils.h"
+
+#define OUTPUT_EN	0x0
+#define OUTPUT_CTL	0x20
+#define SELECTION	0x30
+
+#define NB_FUNCS 2
+#define GPIO_PER_REG	32
+
+/**
+ * struct armada_37xx_pin_group: represents group of pins of a pinmux function.
+ * The pins of a pinmux groups are composed of one or two groups of contiguous
+ * pins.
+ * @name:	Name of the pin group, used to lookup the group.
+ * @start_pins:	Index of the first pin of the main range of pins belonging to
+ *		the group
+ * @npins:	Number of pins included in the first range
+ * @reg_mask:	Bit mask matching the group in the selection register
+ * @extra_pins:	Index of the first pin of the optional second range of pins
+ *		belonging to the group
+ * @npins:	Number of pins included in the second optional range
+ * @funcs:	A list of pinmux functions that can be selected for this group.
+ * @pins:	List of the pins included in the group
+ */
+struct armada_37xx_pin_group {
+	const char	*name;
+	unsigned int	start_pin;
+	unsigned int	npins;
+	u32		reg_mask;
+	u32		val[NB_FUNCS];
+	unsigned int	extra_pin;
+	unsigned int	extra_npins;
+	const char	*funcs[NB_FUNCS];
+	unsigned int	*pins;
+};
+
+struct armada_37xx_pin_data {
+	u8				nr_pins;
+	char				*name;
+	struct armada_37xx_pin_group	*groups;
+	int				ngroups;
+};
+
+struct armada_37xx_pmx_func {
+	const char		*name;
+	const char		**groups;
+	unsigned int		ngroups;
+};
+
+struct armada_37xx_pinctrl {
+	struct regmap			*regmap;
+	const struct armada_37xx_pin_data	*data;
+	struct device			*dev;
+	struct pinctrl_desc		pctl;
+	struct pinctrl_dev		*pctl_dev;
+	struct armada_37xx_pin_group	*groups;
+	unsigned int			ngroups;
+	struct armada_37xx_pmx_func	*funcs;
+	unsigned int			nfuncs;
+};
+
+#define PIN_GRP(_name, _start, _nr, _mask, _func1, _func2)	\
+	{					\
+		.name = _name,			\
+		.start_pin = _start,		\
+		.npins = _nr,			\
+		.reg_mask = _mask,		\
+		.val = {0, _mask},		\
+		.funcs = {_func1, _func2}	\
+	}
+
+#define PIN_GRP_GPIO(_name, _start, _nr, _mask, _func1)	\
+	{					\
+		.name = _name,			\
+		.start_pin = _start,		\
+		.npins = _nr,			\
+		.reg_mask = _mask,		\
+		.val = {0, _mask},		\
+		.funcs = {_func1, "gpio"}	\
+	}
+
+#define PIN_GRP_GPIO_2(_name, _start, _nr, _mask, _val1, _val2, _func1)   \
+	{					\
+		.name = _name,			\
+		.start_pin = _start,		\
+		.npins = _nr,			\
+		.reg_mask = _mask,		\
+		.val = {_val1, _val2},		\
+		.funcs = {_func1, "gpio"}	\
+	}
+
+#define PIN_GRP_EXTRA(_name, _start, _nr, _mask, _v1, _v2, _start2, _nr2, \
+		      _f1, _f2)				\
+	{						\
+		.name = _name,				\
+		.start_pin = _start,			\
+		.npins = _nr,				\
+		.reg_mask = _mask,			\
+		.val = {_v1, _v2},			\
+		.extra_pin = _start2,			\
+		.extra_npins = _nr2,			\
+		.funcs = {_f1, _f2}			\
+	}
+
+static struct armada_37xx_pin_group armada_37xx_nb_groups[] = {
+	PIN_GRP_GPIO("jtag", 20, 5, BIT(0), "jtag"),
+	PIN_GRP_GPIO("sdio0", 8, 3, BIT(1), "sdio"),
+	PIN_GRP_GPIO("emmc_nb", 27, 9, BIT(2), "emmc"),
+	PIN_GRP_GPIO("pwm0", 11, 1, BIT(3), "pwm"),
+	PIN_GRP_GPIO("pwm1", 12, 1, BIT(4), "pwm"),
+	PIN_GRP_GPIO("pwm2", 13, 1, BIT(5), "pwm"),
+	PIN_GRP_GPIO("pwm3", 14, 1, BIT(6), "pwm"),
+	PIN_GRP_GPIO("pmic1", 17, 1, BIT(7), "pmic"),
+	PIN_GRP_GPIO("pmic0", 16, 1, BIT(8), "pmic"),
+	PIN_GRP_GPIO("i2c2", 2, 2, BIT(9), "i2c"),
+	PIN_GRP_GPIO("i2c1", 0, 2, BIT(10), "i2c"),
+	PIN_GRP_GPIO("spi_cs1", 17, 1, BIT(12), "spi"),
+	PIN_GRP_GPIO_2("spi_cs2", 18, 1, BIT(13) | BIT(19), 0, BIT(13), "spi"),
+	PIN_GRP_GPIO_2("spi_cs3", 19, 1, BIT(14) | BIT(19), 0, BIT(14), "spi"),
+	PIN_GRP_GPIO("onewire", 4, 1, BIT(16), "onewire"),
+	PIN_GRP_GPIO("uart1", 25, 2, BIT(17), "uart"),
+	PIN_GRP_GPIO("spi_quad", 15, 2, BIT(18), "spi"),
+	PIN_GRP_EXTRA("uart2", 9, 2, BIT(13) | BIT(14) | BIT(19),
+		      BIT(13) | BIT(14), BIT(19), 18, 2, "gpio", "uart"),
+	PIN_GRP_GPIO("led0_od", 11, 1, BIT(20), "led"),
+	PIN_GRP_GPIO("led1_od", 12, 1, BIT(21), "led"),
+	PIN_GRP_GPIO("led2_od", 13, 1, BIT(22), "led"),
+	PIN_GRP_GPIO("led3_od", 14, 1, BIT(23), "led"),
+
+};
+
+static struct armada_37xx_pin_group armada_37xx_sb_groups[] = {
+	PIN_GRP_GPIO("usb32_drvvbus0", 0, 1, BIT(0), "drvbus"),
+	PIN_GRP_GPIO("usb2_drvvbus1", 1, 1, BIT(1), "drvbus"),
+	PIN_GRP_GPIO("sdio_sb", 24, 5, BIT(2), "sdio"),
+	PIN_GRP_EXTRA("rgmii", 6, 14, BIT(3), 0, BIT(3), 23, 1, "mii", "gpio"),
+	PIN_GRP_GPIO("pcie1", 3, 2, BIT(4), "pcie"),
+	PIN_GRP_GPIO("ptp", 20, 3, BIT(5), "ptp"),
+	PIN_GRP("ptp_clk", 21, 1, BIT(6), "ptp", "mii"),
+	PIN_GRP("ptp_trig", 22, 1, BIT(7), "ptp", "mii"),
+	PIN_GRP("mii_col", 23, 1, BIT(8), "mii", "mii_err"),
+};
+
+const struct armada_37xx_pin_data armada_37xx_pin_nb = {
+	.nr_pins = 36,
+	.name = "GPIO1",
+	.groups = armada_37xx_nb_groups,
+	.ngroups = ARRAY_SIZE(armada_37xx_nb_groups),
+};
+
+const struct armada_37xx_pin_data armada_37xx_pin_sb = {
+	.nr_pins = 29,
+	.name = "GPIO2",
+	.groups = armada_37xx_sb_groups,
+	.ngroups = ARRAY_SIZE(armada_37xx_sb_groups),
+};
+
+static int armada_37xx_get_func_reg(struct armada_37xx_pin_group *grp,
+				    const char *func)
+{
+	int f;
+
+	for (f = 0; f < NB_FUNCS; f++)
+		if (!strcmp(grp->funcs[f], func))
+			return f;
+
+	return -ENOTSUPP;
+}
+
+static struct armada_37xx_pin_group *armada_37xx_find_next_grp_by_pin(
+	struct armada_37xx_pinctrl *info, int pin, int *grp)
+{
+	while (*grp < info->ngroups) {
+		struct armada_37xx_pin_group *group = &info->groups[*grp];
+		int j;
+
+		*grp = *grp + 1;
+		for (j = 0; j < (group->npins + group->extra_npins); j++)
+			if (group->pins[j] == pin)
+				return group;
+	}
+	return NULL;
+}
+
+static int armada_37xx_pin_config_group_get(struct pinctrl_dev *pctldev,
+			    unsigned int selector, unsigned long *config)
+{
+	return -ENOTSUPP;
+}
+
+static int armada_37xx_pin_config_group_set(struct pinctrl_dev *pctldev,
+			    unsigned int selector, unsigned long *configs,
+			    unsigned int num_configs)
+{
+	return -ENOTSUPP;
+}
+
+static struct pinconf_ops armada_37xx_pinconf_ops = {
+	.is_generic = true,
+	.pin_config_group_get = armada_37xx_pin_config_group_get,
+	.pin_config_group_set = armada_37xx_pin_config_group_set,
+};
+
+static int armada_37xx_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+	return info->ngroups;
+}
+
+static const char *armada_37xx_get_group_name(struct pinctrl_dev *pctldev,
+					      unsigned int group)
+{
+	struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+	return info->groups[group].name;
+}
+
+static int armada_37xx_get_group_pins(struct pinctrl_dev *pctldev,
+				      unsigned int selector,
+				      const unsigned int **pins,
+				      unsigned int *npins)
+{
+	struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+	if (selector >= info->ngroups)
+		return -EINVAL;
+
+	*pins = info->groups[selector].pins;
+	*npins = info->groups[selector].npins +
+		info->groups[selector].extra_npins;
+
+	return 0;
+}
+
+static const struct pinctrl_ops armada_37xx_pctrl_ops = {
+	.get_groups_count	= armada_37xx_get_groups_count,
+	.get_group_name		= armada_37xx_get_group_name,
+	.get_group_pins		= armada_37xx_get_group_pins,
+	.dt_node_to_map		= pinconf_generic_dt_node_to_map_group,
+	.dt_free_map		= pinctrl_utils_free_map,
+};
+
+/*
+ * Pinmux_ops handling
+ */
+
+static int armada_37xx_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
+{
+	struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+	return info->nfuncs;
+}
+
+static const char *armada_37xx_pmx_get_func_name(struct pinctrl_dev *pctldev,
+						 unsigned int selector)
+{
+	struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+	return info->funcs[selector].name;
+}
+
+static int armada_37xx_pmx_get_groups(struct pinctrl_dev *pctldev,
+				      unsigned int selector,
+				      const char * const **groups,
+				      unsigned int * const num_groups)
+{
+	struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+	*groups = info->funcs[selector].groups;
+	*num_groups = info->funcs[selector].ngroups;
+
+	return 0;
+}
+
+static int armada_37xx_pmx_set_by_name(struct pinctrl_dev *pctldev,
+				       const char *name,
+				       struct armada_37xx_pin_group *grp)
+{
+	struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+	unsigned int reg = SELECTION;
+	unsigned int mask = grp->reg_mask;
+	int func, val;
+
+	dev_dbg(info->dev, "enable function %s group %s\n",
+		name, grp->name);
+
+	func = armada_37xx_get_func_reg(grp, name);
+
+	if (func < 0)
+		return func;
+
+	val = grp->val[func];
+
+	regmap_update_bits(info->regmap, reg, mask, val);
+
+	return 0;
+}
+
+static int armada_37xx_pmx_set(struct pinctrl_dev *pctldev,
+			       unsigned int selector,
+			       unsigned int group)
+{
+
+	struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+	struct armada_37xx_pin_group *grp = &info->groups[group];
+	const char *name = info->funcs[selector].name;
+
+	return armada_37xx_pmx_set_by_name(pctldev, name, grp);
+}
+
+static int armada_37xx_pmx_direction_input(struct armada_37xx_pinctrl *info,
+					   unsigned int offset)
+{
+	unsigned int reg = OUTPUT_EN;
+	unsigned int mask;
+
+	if (offset >= GPIO_PER_REG) {
+		offset -= GPIO_PER_REG;
+		reg += sizeof(u32);
+	}
+	mask = BIT(offset);
+
+	return regmap_update_bits(info->regmap, reg, mask, 0);
+}
+
+static int armada_37xx_pmx_direction_output(struct armada_37xx_pinctrl *info,
+					    unsigned int offset, int value)
+{
+	unsigned int reg = OUTPUT_EN;
+	unsigned int mask;
+
+	if (offset >= GPIO_PER_REG) {
+		offset -= GPIO_PER_REG;
+		reg += sizeof(u32);
+	}
+	mask = BIT(offset);
+
+	return regmap_update_bits(info->regmap, reg, mask, mask);
+}
+
+static int armada_37xx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
+					      struct pinctrl_gpio_range *range,
+					      unsigned int offset, bool input)
+{
+	struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+
+	dev_dbg(info->dev, "gpio_direction for pin %u as %s-%d to %s\n",
+		offset, range->name, offset, input ? "input" : "output");
+
+	if (input)
+		armada_37xx_pmx_direction_input(info, offset);
+	else
+		armada_37xx_pmx_direction_output(info, offset, 0);
+
+	return 0;
+}
+
+static int armada_37xx_gpio_request_enable(struct pinctrl_dev *pctldev,
+					   struct pinctrl_gpio_range *range,
+					   unsigned int offset)
+{
+	struct armada_37xx_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+	struct armada_37xx_pin_group *group;
+	int grp = 0;
+
+	dev_dbg(info->dev, "requesting gpio %d\n", offset);
+
+	while ((group = armada_37xx_find_next_grp_by_pin(info, offset, &grp)))
+		armada_37xx_pmx_set_by_name(pctldev, "gpio", group);
+
+	return 0;
+}
+
+static const struct pinmux_ops armada_37xx_pmx_ops = {
+	.get_functions_count	= armada_37xx_pmx_get_funcs_count,
+	.get_function_name	= armada_37xx_pmx_get_func_name,
+	.get_function_groups	= armada_37xx_pmx_get_groups,
+	.set_mux		= armada_37xx_pmx_set,
+	.gpio_request_enable	= armada_37xx_gpio_request_enable,
+	.gpio_set_direction	= armada_37xx_pmx_gpio_set_direction,
+};
+
+/**
+ * armada_37xx_add_function() - Add a new function to the list
+ * @funcs: array of function to add the new one
+ * @funcsize: size of the remaining space for the function
+ * @name: name of the function to add
+ *
+ * If it is a new function then create it by adding its name else
+ * increment the number of group associated to this function.
+ */
+static int armada_37xx_add_function(struct armada_37xx_pmx_func *funcs,
+				    int *funcsize, const char *name)
+{
+	int i = 0;
+
+	if (*funcsize <= 0)
+		return -EOVERFLOW;
+
+	while (funcs->ngroups) {
+		/* function already there */
+		if (strcmp(funcs->name, name) == 0) {
+			funcs->ngroups++;
+
+			return -EEXIST;
+		}
+		funcs++;
+		i++;
+	}
+
+	/* append new unique function */
+	funcs->name = name;
+	funcs->ngroups = 1;
+	(*funcsize)--;
+
+	return 0;
+}
+
+/**
+ * armada_37xx_fill_group() - complete the group array
+ * @info: info driver instance
+ *
+ * Based on the data available from the armada_37xx_pin_group array
+ * completes the last member of the struct for each function: the list
+ * of the groups associated to this function.
+ *
+ */
+static int armada_37xx_fill_group(struct armada_37xx_pinctrl *info)
+{
+	int n, num = 0, funcsize = info->data->nr_pins;
+
+	for (n = 0; n < info->ngroups; n++) {
+		struct armada_37xx_pin_group *grp = &info->groups[n];
+		int i, j, f;
+
+		grp->pins = devm_kzalloc(info->dev,
+					 (grp->npins + grp->extra_npins) *
+					 sizeof(*grp->pins), GFP_KERNEL);
+		if (!grp->pins)
+			return -ENOMEM;
+
+		for (i = 0; i < grp->npins; i++)
+			grp->pins[i] = grp->start_pin + i;
+
+		for (j = 0; j < grp->extra_npins; j++)
+			grp->pins[i+j] = grp->extra_pin + j;
+
+		for (f = 0; f < NB_FUNCS; f++) {
+			int ret;
+			/* check for unique functions and count groups */
+			ret = armada_37xx_add_function(info->funcs, &funcsize,
+					    grp->funcs[f]);
+			if (ret == -EOVERFLOW)
+				dev_err(info->dev,
+					"More functions than pins(%d)\n",
+					info->data->nr_pins);
+			if (ret < 0)
+				continue;
+			num++;
+		}
+	}
+
+	info->nfuncs = num;
+
+	return 0;
+}
+
+/**
+ * armada_37xx_fill_funcs() - complete the funcs array
+ * @info: info driver instance
+ *
+ * Based on the data available from the armada_37xx_pin_group array
+ * completes the last two member of the struct for each group:
+ * - the list of the pins included in the group
+ * - the list of pinmux functions that can be selected for this group
+ *
+ */
+static int armada_37xx_fill_func(struct armada_37xx_pinctrl *info)
+{
+	struct armada_37xx_pmx_func *funcs = info->funcs;
+	int n;
+
+	for (n = 0; n < info->nfuncs; n++) {
+		const char *name = funcs[n].name;
+		const char **groups;
+		int g;
+
+		funcs[n].groups = devm_kzalloc(info->dev, funcs[n].ngroups *
+					       sizeof(*(funcs[n].groups)),
+					       GFP_KERNEL);
+		if (!funcs[n].groups)
+			return -ENOMEM;
+
+		groups = funcs[n].groups;
+
+		for (g = 0; g < info->ngroups; g++) {
+			struct armada_37xx_pin_group *gp = &info->groups[g];
+			int f;
+
+			for (f = 0; f < NB_FUNCS; f++) {
+				if (strcmp(gp->funcs[f], name) == 0) {
+					*groups = gp->name;
+					groups++;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+static int armada_37xx_pinctrl_register(struct platform_device *pdev,
+					struct armada_37xx_pinctrl *info)
+{
+	const struct armada_37xx_pin_data *pin_data = info->data;
+	struct pinctrl_desc *ctrldesc = &info->pctl;
+	struct pinctrl_pin_desc *pindesc, *pdesc;
+	int pin, ret;
+
+	info->groups = pin_data->groups;
+	info->ngroups = pin_data->ngroups;
+
+	ctrldesc->name = "armada_37xx-pinctrl";
+	ctrldesc->owner = THIS_MODULE;
+	ctrldesc->pctlops = &armada_37xx_pctrl_ops;
+	ctrldesc->pmxops = &armada_37xx_pmx_ops;
+	ctrldesc->confops = &armada_37xx_pinconf_ops;
+
+	pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) *
+			       pin_data->nr_pins, GFP_KERNEL);
+	if (!pindesc)
+		return -ENOMEM;
+
+	ctrldesc->pins = pindesc;
+	ctrldesc->npins = pin_data->nr_pins;
+
+	pdesc = pindesc;
+	for (pin = 0; pin < pin_data->nr_pins; pin++) {
+		pdesc->number = pin;
+		pdesc->name = kasprintf(GFP_KERNEL, "%s-%d",
+					pin_data->name, pin);
+		pdesc++;
+	}
+
+	/*
+	 * we allocate functions for number of pins and hope there are
+	 * fewer unique functions than pins available
+	 */
+	info->funcs = devm_kzalloc(&pdev->dev, pin_data->nr_pins *
+			   sizeof(struct armada_37xx_pmx_func), GFP_KERNEL);
+	if (!info->funcs)
+		return -ENOMEM;
+
+
+	ret = armada_37xx_fill_group(info);
+	if (ret)
+		return ret;
+
+	ret = armada_37xx_fill_func(info);
+	if (ret)
+		return ret;
+
+	info->pctl_dev = devm_pinctrl_register(&pdev->dev, ctrldesc, info);
+	if (IS_ERR(info->pctl_dev)) {
+		dev_err(&pdev->dev, "could not register pinctrl driver\n");
+		return PTR_ERR(info->pctl_dev);
+	}
+
+	return 0;
+}
+
+static const struct of_device_id armada_37xx_pinctrl_of_match[] = {
+	{
+		.compatible = "marvell,armada3710-sb-pinctrl",
+		.data = (void *)&armada_37xx_pin_sb,
+	},
+	{
+		.compatible = "marvell,armada3710-nb-pinctrl",
+		.data = (void *)&armada_37xx_pin_nb,
+	},
+	{ },
+};
+
+static int __init armada_37xx_pinctrl_probe(struct platform_device *pdev)
+{
+	struct armada_37xx_pinctrl *info;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct regmap *regmap;
+	int ret;
+
+	info = devm_kzalloc(dev, sizeof(struct armada_37xx_pinctrl),
+			    GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->dev = dev;
+
+	regmap = syscon_node_to_regmap(np);
+	if (IS_ERR(regmap)) {
+		dev_err(&pdev->dev, "cannot get regmap\n");
+		return PTR_ERR(regmap);
+	}
+	info->regmap = regmap;
+
+	info->data = of_device_get_match_data(dev);
+
+	ret = armada_37xx_pinctrl_register(pdev, info);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, info);
+
+	return 0;
+}
+
+static struct platform_driver armada_37xx_pinctrl_driver = {
+	.driver = {
+		.name = "armada-37xx-pinctrl",
+		.of_match_table = armada_37xx_pinctrl_of_match,
+	},
+};
+
+builtin_platform_driver_probe(armada_37xx_pinctrl_driver,
+			      armada_37xx_pinctrl_probe);
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH v4 2/7] arm64: marvell: enable the Armada 37xx pinctrl driver
From: Gregory CLEMENT @ 2017-04-05 15:18 UTC (permalink / raw)
  To: Linus Walleij, linux-gpio
  Cc: Thomas Petazzoni, Andrew Lunn, Hua Jing, Jason Cooper, devicetree,
	linux-kernel, Nadav Haklai, Rob Herring, Neta Zur Hershkovits,
	Gregory CLEMENT, Victor Gu, Marcin Wojtas, Wilson Ding,
	linux-arm-kernel, Sebastian Hesselbarth
In-Reply-To: <cover.65d0e6796fecf1fe6c5d07b981160b54dc9b4acd.1491405475.git-series.gregory.clement@free-electrons.com>

This commit makes sure the driver for the Armada 37xx pin controller is
enabled.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 arch/arm64/Kconfig.platforms | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 129cc5ae4091..9aa71a3f3f50 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -103,8 +103,13 @@ config ARCH_MVEBU
 	select ARMADA_AP806_SYSCON
 	select ARMADA_CP110_SYSCON
 	select ARMADA_37XX_CLK
+	select GPIOLIB
+	select GPIOLIB_IRQCHIP
 	select MVEBU_ODMI
 	select MVEBU_PIC
+	select OF_GPIO
+	select PINCTRL
+	select PINCTRL_ARMADA_37XX
 	help
 	  This enables support for Marvell EBU familly, including:
 	   - Armada 3700 SoC Family
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH v4 1/7] pinctrl: dt-bindings: Add documentation for Armada 37xx pin controllers
From: Gregory CLEMENT @ 2017-04-05 15:18 UTC (permalink / raw)
  To: Linus Walleij, linux-gpio
  Cc: Thomas Petazzoni, Andrew Lunn, Hua Jing, Jason Cooper, devicetree,
	linux-kernel, Nadav Haklai, Rob Herring, Neta Zur Hershkovits,
	Gregory CLEMENT, Victor Gu, Marcin Wojtas, Wilson Ding,
	linux-arm-kernel, Sebastian Hesselbarth
In-Reply-To: <cover.65d0e6796fecf1fe6c5d07b981160b54dc9b4acd.1491405475.git-series.gregory.clement@free-electrons.com>

Document the device tree binding for the pin controllers found on the
Armada 37xx SoCs.

Update the binding documention of the xtal clk which is a subnode of this
syscon node.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
---
 Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt         |   7 +--
 Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 187 insertions(+), 3 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt

diff --git a/Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt b/Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt
index a88f1f05fbd6..4c0807f28cfa 100644
--- a/Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt
+++ b/Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt
@@ -5,6 +5,7 @@ reading the gpio latch register.
 
 This node must be a subnode of the node exposing the register address
 of the GPIO block where the gpio latch is located.
+See Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt
 
 Required properties:
 - compatible : shall be one of the following:
@@ -16,9 +17,9 @@ Optional properties:
 	output names ("xtal")
 
 Example:
-gpio1: gpio@13800 {
-	compatible = "marvell,armada-3700-gpio", "syscon", "simple-mfd";
-	reg = <0x13800 0x1000>;
+pinctrl_nb: pinctrl-nb@13800 {
+	compatible = "armada3710-nb-pinctrl", "syscon", "simple-mfd";
+	reg = <0x13800 0x100>, <0x13C00 0x20>;
 
 	xtalclk: xtal-clk {
 		compatible = "marvell,armada-3700-xtal-clock";
diff --git a/Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt
new file mode 100644
index 000000000000..2eda81e0bca1
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt
@@ -0,0 +1,183 @@
+* Marvell Armada 37xx SoC pin and gpio controller
+
+Each Armada 37xx SoC come with two pin and gpio controller one for the
+south bridge and the other for the north bridge.
+
+Inside this set of register the gpio latch allows exposing some
+configuration of the SoC and especially the clock frequency of the
+xtal. Hence, this node is a represent as syscon allowing sharing the
+register between multiple hardware block.
+
+GPIO and pin controller:
+------------------------
+
+Main node:
+
+Refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning
+of the phrase "pin configuration node".
+
+Required properties for pinctrl driver:
+
+- compatible:	"marvell,armada3710-sb-pinctrl", "syscon, "simple-mfd"
+		for the south bridge
+		"marvell,armada3710-nb-pinctrl", "syscon, "simple-mfd"
+		for the north bridge
+- reg: The first set of register are for pinctrl/gpio and the second
+  set for the interrupt controller
+- interrupts: list of the interrupt use by the gpio
+
+Available groups and functions for the North bridge:
+
+group: jtag
+ - pins 20-24
+ - functions jtag, gpio
+
+group sdio0
+ - pins 8-10
+ - functions sdio, gpio
+
+group emmc_nb
+ - pins 27-35
+ - functions emmc, gpio
+
+group pwm0
+ - pin 11 (GPIO1-11)
+ - functions pwm, gpio
+
+group pwm1
+ - pin 12
+ - functions pwm, gpio
+
+group pwm2
+ - pin 13
+ - functions pwm, gpio
+
+group pwm3
+ - pin 14
+ - functions pwm, gpio
+
+group pmic1
+ - pin 17
+ - functions pmic, gpio
+
+group pmic0
+ - pin 16
+ - functions pmic, gpio
+
+group i2c2
+ - pins 2-3
+ - functions i2c, gpio
+
+group i2c1
+ - pins 0-1
+ - functions i2c, gpio
+
+group spi_cs1
+ - pin 17
+ - functions spi, gpio
+
+group spi_cs2
+ - pin 18
+ - functions spi, gpio
+
+group spi_cs3
+ - pin 19
+ - functions spi, gpio
+
+group onewire
+ - pin 4
+ - functions onewire, gpio
+
+group uart1
+ - pins 25-26
+ - functions uart, gpio
+
+group spi_quad
+ - pins 15-16
+ - functions spi, gpio
+
+group uart_2
+ - pins 9-10
+ - functions uart, gpio
+
+Available groups and functions for the South bridge:
+
+group usb32_drvvbus0
+ - pin 36
+ - functions drvbus, gpio
+
+group usb2_drvvbus1
+ - pin 37
+ - functions drvbus, gpio
+
+group sdio_sb
+ - pins 60-64
+ - functions sdio, gpio
+
+group rgmii
+ - pins 42-55
+ - functions mii, gpio
+
+group pcie1
+ - pins 39-40
+ - functions pcie, gpio
+
+group ptp
+ - pins 56-58
+ - functions ptp, gpio
+
+group ptp_clk
+ - pin 57
+ - functions ptp, mii
+
+group ptp_trig
+ - pin 58
+ - functions ptp, mii
+
+group mii_col
+ - pin 59
+ - functions mii, mii_err
+
+GPIO subnode:
+
+Please refer to gpio.txt in this directory for details of gpio-ranges property
+and the common GPIO bindings used by client devices.
+
+Required properties for gpio driver under the gpio subnode:
+- interrupts: List of interrupt specifier for the controllers interrupt.
+- gpio-controller: Marks the device node as a gpio controller.
+- #gpio-cells: Should be 2. The first cell is the GPIO number and the
+   second cell specifies GPIO flags, as defined in
+   <dt-bindings/gpio/gpio.h>. Only the GPIO_ACTIVE_HIGH and
+   GPIO_ACTIVE_LOW flags are supported.
+- gpio-ranges: Range of pins managed by the GPIO controller.
+
+Xtal Clock bindings for Marvell Armada 37xx SoCs
+------------------------------------------------
+
+see Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt
+
+
+Example:
+pinctrl_sb: pinctrl-sb@18800 {
+	compatible = "marvell,armada3710-sb-pinctrl", "syscon", "simple-mfd";
+	reg = <0x18800 0x100>, <0x18C00 0x20>;
+	gpiosb: gpiosb {
+		#gpio-cells = <2>;
+		gpio-ranges = <&pinctrl_sb 0 0 29>;
+		gpio-controller;
+		interrupts =
+		<GIC_SPI 160 IRQ_TYPE_LEVEL_HIGH>,
+		<GIC_SPI 159 IRQ_TYPE_LEVEL_HIGH>,
+		<GIC_SPI 158 IRQ_TYPE_LEVEL_HIGH>,
+		<GIC_SPI 157 IRQ_TYPE_LEVEL_HIGH>,
+		<GIC_SPI 156 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	rgmii_pins: mii-pins {
+		groups = "rgmii";
+		function = "mii";
+	};
+
+};
-- 
git-series 0.9.1

^ permalink raw reply related

* [PATCH v4 0/7] Add support for pinctrl/gpio on Armada 37xx
From: Gregory CLEMENT @ 2017-04-05 15:18 UTC (permalink / raw)
  To: Linus Walleij, linux-gpio
  Cc: Thomas Petazzoni, Andrew Lunn, Hua Jing, Jason Cooper, devicetree,
	linux-kernel, Nadav Haklai, Rob Herring, Neta Zur Hershkovits,
	Gregory CLEMENT, Victor Gu, Marcin Wojtas, Wilson Ding,
	linux-arm-kernel, Sebastian Hesselbarth

Hi,

In this forth version I improved the driver based on the review from
Linus Walleij and I fixed a configuration issue with uart2. For the
record, this series adds support for the pin and gpio controllers
present on the Armada 37xx SoCs.

Each Armada 37xx SoC comes with 2 pin controllers: one on the south
bridge (managing 28 pins) and one on the north bridge (managing 36 pins).

At the hardware level the controller configure the pins by group and not
pin by pin.

The gpio controller is also capable to handle interrupt from gpio.

Changelog

v3 -> v4
- Some group are configured by several bits in the register:
  extend the armada_37xx_pin_group struct to manage it.

- Fix the uart2 and cspi2/3 configuration

- Document the armada_37xx_add_function(), armada_37xx_fill_group()
  and armada_37xx_fill_funcs().

- Use devm_gpiochip_add_data()

- Use irq_find_mapping instead of irq_linear_revmap

- Use handle_edge_irq instead of the wrong handle_level_irq

- Add comment about the fact the we have multiple parent interrupt

- Add comment about the mask usage of the irq_data struct

- Use BIT() macro when possible

- Select more CONFIG symbol needed for GPIO and interrupt support

v2 -> v3
 - use gpio-ranges (patch 4)

 - Document gpio-ranges usage (patch 1)

 - do not use anymore a global pin index (patch 3)

v1 -> v2:
- Update binding documentation making clear that mfd and syscon must
  be used (patch 1).

- Split the fist patch adding pin controller support for Armada 37xx
  in arm64 part (for kconfig) and pinctrl part (patch 2 and 3)

- Add MFD_SYSCON dependency (patch 3)

- Add kerneldoc for the armada_37xx_pin_group struct (patch 3)

- Rename _add_function() to armada_37xx_add_function() (patch 3)

- Use an inline function to update the reg offset (patch 4)

- Rename gpiolib_register to gpiochip_register (patch 4)

- Add a comment about the two registers limit (patch 4)

- Add explicit gpio node in the device tree (patch 4)

- Convert the driver to use GPIOLIB_IRQCHIP (patch 5)

- Add a critical section when accessing the hardware registers (patch 5)

- Use the gpio subnode (patch 5)

Thanks,

Gregory

Gregory CLEMENT (7):
  pinctrl: dt-bindings: Add documentation for Armada 37xx pin controllers
  arm64: marvell: enable the Armada 37xx pinctrl driver
  pinctrl: armada-37xx: Add pin controller support for Armada 37xx
  pinctrl: armada-37xx: Add gpio support
  pinctrl: aramda-37xx: Add irqchip support
  ARM64: dts: marvell: Add pinctrl nodes for Armada 3700
  ARM64: dts: marvell: armada37xx: add pinctrl definition

 Documentation/devicetree/bindings/clock/armada3700-xtal-clock.txt         |   7 +-
 Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt | 183 ++++++++++++++-
 arch/arm64/Kconfig.platforms                                              |   5 +-
 arch/arm64/boot/dts/marvell/armada-3720-db.dts                            |   8 +-
 arch/arm64/boot/dts/marvell/armada-37xx.dtsi                              |  73 ++++-
 drivers/pinctrl/Makefile                                                  |   2 +-
 drivers/pinctrl/mvebu/Kconfig                                             |   7 +-
 drivers/pinctrl/mvebu/Makefile                                            |   3 +-
 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c                               | 969 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 9 files changed, 1249 insertions(+), 8 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/marvell,armada-37xx-pinctrl.txt
 create mode 100644 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c

base-commit: c1ae3cfa0e89fa1a7ecc4c99031f5e9ae99d9201
-- 
git-series 0.9.1

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox