* [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 @@
};
ð0 {
+ 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(®, 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(®, 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(®, 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(®, 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(®, 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(®, 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(®, 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(®, 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(®, 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(®, 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
* Re: [PATCH v2 1/3] clk: vc5: Add structure to describe particular chip features
From: Alexey Firago @ 2017-04-05 15:09 UTC (permalink / raw)
To: Marek Vasut, Geert Uytterhoeven
Cc: Michael Turquette, Stephen Boyd, Rob Herring, linux-clk,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <23dd9324-ee97-633d-129e-6063af757f47-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Hi Marek,
On 05.04.2017 17:20, Marek Vasut wrote:
>>>> +
>>>> +/* flags to describe chip features */
>>>> +/* chip has built-in oscilator */
>>>> +#define VC5_HAS_INTERNAL_XTAL BIT(0)
>>>
>>> VC5_HAS_INTERNAL_OSC?
>>
>> I'm fine with renaming it, but shouldn't it be consistent with the rest
>> of the driver (see "internal-xtal", VC5_XTAL*, etc) and IDT datasheet?
>>
>
> Do you have one with internal ring oscillator or with internal xtal ?
> The one I had has internal xtal according to the datasheet.
>
The one I have (5P49V5935) has internal 25MHz crystal according to the
datasheet.
--
Alexey
--
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 04/11] mfd: axp20x: support AXP803 variant
From: Chen-Yu Tsai @ 2017-04-05 14:58 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-5-icenowy-h8G6r0blFSE@public.gmane.org>
On Wed, Apr 5, 2017 at 2:01 AM, Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org> wrote:
> AXP803 is a new PMIC chip produced by X-Powers, usually paired with A64
> via RSB bus. The PMIC itself is like AXP288, but with RSB support and
> dedicated VBUS and ACIN.
>
> Add support for it in the axp20x mfd driver.
>
> Currently only power key function is supported.
>
> Signed-off-by: Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
> ---
> drivers/mfd/axp20x-rsb.c | 1 +
> drivers/mfd/axp20x.c | 113 +++++++++++++++++++++++++++++++++++++++++++++
> include/linux/mfd/axp20x.h | 40 +++++++++++++++-
> 3 files changed, 153 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/mfd/axp20x-rsb.c b/drivers/mfd/axp20x-rsb.c
> index a732cb50bcff..3ff8a7d1ce88 100644
> --- a/drivers/mfd/axp20x-rsb.c
> +++ b/drivers/mfd/axp20x-rsb.c
> @@ -63,6 +63,7 @@ static const struct of_device_id axp20x_rsb_of_match[] = {
> { .compatible = "x-powers,axp223", .data = (void *)AXP223_ID },
> { .compatible = "x-powers,axp806", .data = (void *)AXP806_ID },
> { .compatible = "x-powers,axp809", .data = (void *)AXP809_ID },
> + { .compatible = "x-powers,axp803", .data = (void *)AXP803_ID },
As mentioned in the previous patches, please sort them in ascending order.
> { },
> };
> MODULE_DEVICE_TABLE(of, axp20x_rsb_of_match);
> diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
> index 5ba3b04cc9b1..e468e08d84db 100644
> --- a/drivers/mfd/axp20x.c
> +++ b/drivers/mfd/axp20x.c
> @@ -43,6 +43,7 @@ static const char * const axp20x_model_names[] = {
> "AXP288",
> "AXP806",
> "AXP809",
> + "AXP803",
Same here.
> };
>
> static const struct regmap_range axp152_writeable_ranges[] = {
> @@ -165,6 +166,32 @@ static const struct regmap_access_table axp806_volatile_table = {
> .n_yes_ranges = ARRAY_SIZE(axp806_volatile_ranges),
> };
>
> +static const struct regmap_range axp803_writeable_ranges[] = {
> + regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ6_STATE),
> + regmap_reg_range(AXP20X_DCDC_MODE, AXP288_FG_TUNE5),
> +};
> +
> +static const struct regmap_range axp803_volatile_ranges[] = {
> + regmap_reg_range(AXP20X_PWR_INPUT_STATUS, AXP288_POWER_REASON),
> + regmap_reg_range(AXP288_BC_GLOBAL, AXP288_BC_GLOBAL),
> + regmap_reg_range(AXP288_BC_DET_STAT, AXP288_BC_DET_STAT),
> + regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IPSOUT_V_HIGH_L),
> + regmap_reg_range(AXP20X_TIMER_CTRL, AXP20X_TIMER_CTRL),
> + regmap_reg_range(AXP22X_GPIO_STATE, AXP22X_GPIO_STATE),
> + regmap_reg_range(AXP288_RT_BATT_V_H, AXP288_RT_BATT_V_L),
> + regmap_reg_range(AXP20X_FG_RES, AXP288_FG_CC_CAP_REG),
> +};
> +
> +static const struct regmap_access_table axp803_writeable_table = {
> + .yes_ranges = axp803_writeable_ranges,
> + .n_yes_ranges = ARRAY_SIZE(axp803_writeable_ranges),
> +};
> +
> +static const struct regmap_access_table axp803_volatile_table = {
> + .yes_ranges = axp803_volatile_ranges,
> + .n_yes_ranges = ARRAY_SIZE(axp803_volatile_ranges),
> +};
> +
If they are the same as the AXP288, please just use that set,
instead of duplicating it. You can add a note, like what I did
for the AXP22x/AXP809.
> static struct resource axp152_pek_resources[] = {
> DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_RIS_EDGE, "PEK_DBR"),
> DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_FAL_EDGE, "PEK_DBF"),
> @@ -278,6 +305,20 @@ static struct resource axp809_pek_resources[] = {
> },
> };
>
> +static struct resource axp803_pek_resources[] = {
> + {
> + .name = "PEK_DBR",
> + .start = AXP803_IRQ_PEK_RIS_EDGE,
> + .end = AXP803_IRQ_PEK_RIS_EDGE,
> + .flags = IORESOURCE_IRQ,
> + }, {
> + .name = "PEK_DBF",
> + .start = AXP803_IRQ_PEK_FAL_EDGE,
> + .end = AXP803_IRQ_PEK_FAL_EDGE,
> + .flags = IORESOURCE_IRQ,
> + },
> +};
> +
You can use axp288_power_button_resources directly. See below
about the interrupts and symbol names.
> static const struct regmap_config axp152_regmap_config = {
> .reg_bits = 8,
> .val_bits = 8,
> @@ -323,6 +364,15 @@ static const struct regmap_config axp806_regmap_config = {
> .cache_type = REGCACHE_RBTREE,
> };
>
> +static const struct regmap_config axp803_regmap_config = {
> + .reg_bits = 8,
> + .val_bits = 8,
> + .wr_table = &axp803_writeable_table,
> + .volatile_table = &axp803_volatile_table,
> + .max_register = AXP288_FG_TUNE5,
> + .cache_type = REGCACHE_RBTREE,
> +};
> +
Drop this and use axp288_regmap_config.
> #define INIT_REGMAP_IRQ(_variant, _irq, _off, _mask) \
> [_variant##_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
>
> @@ -507,6 +557,43 @@ static const struct regmap_irq axp809_regmap_irqs[] = {
> INIT_REGMAP_IRQ(AXP809, GPIO0_INPUT, 4, 0),
> };
>
> +static const struct regmap_irq axp803_regmap_irqs[] = {
> + INIT_REGMAP_IRQ(AXP803, ACIN_OVER_V, 0, 7),
> + INIT_REGMAP_IRQ(AXP803, ACIN_PLUGIN, 0, 6),
> + INIT_REGMAP_IRQ(AXP803, ACIN_REMOVAL, 0, 5),
> + INIT_REGMAP_IRQ(AXP803, VBUS_OVER_V, 0, 4),
> + INIT_REGMAP_IRQ(AXP803, VBUS_PLUGIN, 0, 3),
> + INIT_REGMAP_IRQ(AXP803, VBUS_REMOVAL, 0, 2),
> + INIT_REGMAP_IRQ(AXP803, BATT_PLUGIN, 1, 7),
> + INIT_REGMAP_IRQ(AXP803, BATT_REMOVAL, 1, 6),
> + INIT_REGMAP_IRQ(AXP803, BATT_ENT_ACT_MODE, 1, 5),
> + INIT_REGMAP_IRQ(AXP803, BATT_EXIT_ACT_MODE, 1, 4),
> + INIT_REGMAP_IRQ(AXP803, CHARG, 1, 3),
> + INIT_REGMAP_IRQ(AXP803, CHARG_DONE, 1, 2),
> + INIT_REGMAP_IRQ(AXP803, BATT_CHG_TEMP_HIGH, 2, 7),
> + INIT_REGMAP_IRQ(AXP803, BATT_CHG_TEMP_HIGH_END, 2, 6),
> + INIT_REGMAP_IRQ(AXP803, BATT_CHG_TEMP_LOW, 2, 5),
> + INIT_REGMAP_IRQ(AXP803, BATT_CHG_TEMP_LOW_END, 2, 4),
> + INIT_REGMAP_IRQ(AXP803, BATT_ACT_TEMP_HIGH, 2, 3),
> + INIT_REGMAP_IRQ(AXP803, BATT_ACT_TEMP_HIGH_END, 2, 2),
> + INIT_REGMAP_IRQ(AXP803, BATT_ACT_TEMP_LOW, 2, 1),
> + INIT_REGMAP_IRQ(AXP803, BATT_ACT_TEMP_LOW_END, 2, 0),
> + INIT_REGMAP_IRQ(AXP803, DIE_TEMP_HIGH, 3, 7),
> + INIT_REGMAP_IRQ(AXP803, GPADC, 3, 2),
> + INIT_REGMAP_IRQ(AXP803, LOW_PWR_LVL1, 3, 1),
> + INIT_REGMAP_IRQ(AXP803, LOW_PWR_LVL2, 3, 0),
> + INIT_REGMAP_IRQ(AXP803, TIMER, 4, 7),
> + INIT_REGMAP_IRQ(AXP803, PEK_RIS_EDGE, 4, 6),
> + INIT_REGMAP_IRQ(AXP803, PEK_FAL_EDGE, 4, 5),
> + INIT_REGMAP_IRQ(AXP803, PEK_SHORT, 4, 4),
> + INIT_REGMAP_IRQ(AXP803, PEK_LONG, 4, 3),
> + INIT_REGMAP_IRQ(AXP803, PEK_OVER_OFF, 4, 2),
> + INIT_REGMAP_IRQ(AXP803, GPIO1_INPUT, 4, 1),
> + INIT_REGMAP_IRQ(AXP803, GPIO0_INPUT, 4, 0),
> + INIT_REGMAP_IRQ(AXP803, BC_USB_CHNG, 5, 1),
> + INIT_REGMAP_IRQ(AXP803, MV_CHNG, 5, 0),
> +};
> +
Looks like the same set as AXP288, albeit with different names.
Please use that set instead of duplicating it. The different naming
scheme is OK, as the symbols really only get used when defining
resources for the various sub-devices.
> static const struct regmap_irq_chip axp152_regmap_irq_chip = {
> .name = "axp152_irq_chip",
> .status_base = AXP152_IRQ1_STATE,
> @@ -581,6 +668,18 @@ static const struct regmap_irq_chip axp809_regmap_irq_chip = {
> .num_regs = 5,
> };
>
> +static const struct regmap_irq_chip axp803_regmap_irq_chip = {
> + .name = "axp803",
> + .status_base = AXP20X_IRQ1_STATE,
> + .ack_base = AXP20X_IRQ1_STATE,
> + .mask_base = AXP20X_IRQ1_EN,
> + .mask_invert = true,
> + .init_ack_masked = true,
> + .irqs = axp803_regmap_irqs,
> + .num_irqs = ARRAY_SIZE(axp803_regmap_irqs),
> + .num_regs = 6,
> +};
> +
Same here.
In general we want to be able to share as much as possible.
Otherwise we'd just have separate drivers.
Regards
ChenYu
> static struct mfd_cell axp20x_cells[] = {
> {
> .name = "axp20x-gpio",
> @@ -787,6 +886,14 @@ static struct mfd_cell axp809_cells[] = {
> },
> };
>
> +static struct mfd_cell axp803_cells[] = {
> + {
> + .name = "axp20x-pek",
> + .num_resources = ARRAY_SIZE(axp803_pek_resources),
> + .resources = axp803_pek_resources,
> + }
> +};
> +
> static struct axp20x_dev *axp20x_pm_power_off;
> static void axp20x_power_off(void)
> {
> @@ -867,6 +974,12 @@ int axp20x_match_device(struct axp20x_dev *axp20x)
> axp20x->regmap_cfg = &axp22x_regmap_config;
> axp20x->regmap_irq_chip = &axp809_regmap_irq_chip;
> break;
> + case AXP803_ID:
> + axp20x->nr_cells = ARRAY_SIZE(axp803_cells);
> + axp20x->cells = axp803_cells;
> + axp20x->regmap_cfg = &axp803_regmap_config;
> + axp20x->regmap_irq_chip = &axp803_regmap_irq_chip;
> + break;
> default:
> dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant);
> return -EINVAL;
> diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
> index dc8798cf2a24..b3220ef374d3 100644
> --- a/include/linux/mfd/axp20x.h
> +++ b/include/linux/mfd/axp20x.h
> @@ -22,6 +22,7 @@ enum axp20x_variants {
> AXP288_ID,
> AXP806_ID,
> AXP809_ID,
> + AXP803_ID,
> NR_AXP20X_VARIANTS,
> };
>
> @@ -234,7 +235,7 @@ enum axp20x_variants {
> #define AXP22X_TS_ADC_L 0x59
> #define AXP22X_BATLOW_THRES1 0xe6
>
> -/* AXP288 specific registers */
> +/* AXP288/AXP803 specific registers */
> #define AXP288_POWER_REASON 0x02
> #define AXP288_BC_GLOBAL 0x2c
> #define AXP288_BC_VBUS_CNTL 0x2d
> @@ -525,6 +526,43 @@ enum axp809_irqs {
> AXP809_IRQ_GPIO0_INPUT,
> };
>
> +enum axp803_irqs {
> + AXP803_IRQ_ACIN_OVER_V = 1,
> + AXP803_IRQ_ACIN_PLUGIN,
> + AXP803_IRQ_ACIN_REMOVAL,
> + AXP803_IRQ_VBUS_OVER_V,
> + AXP803_IRQ_VBUS_PLUGIN,
> + AXP803_IRQ_VBUS_REMOVAL,
> + AXP803_IRQ_BATT_PLUGIN,
> + AXP803_IRQ_BATT_REMOVAL,
> + AXP803_IRQ_BATT_ENT_ACT_MODE,
> + AXP803_IRQ_BATT_EXIT_ACT_MODE,
> + AXP803_IRQ_CHARG,
> + AXP803_IRQ_CHARG_DONE,
> + AXP803_IRQ_BATT_CHG_TEMP_HIGH,
> + AXP803_IRQ_BATT_CHG_TEMP_HIGH_END,
> + AXP803_IRQ_BATT_CHG_TEMP_LOW,
> + AXP803_IRQ_BATT_CHG_TEMP_LOW_END,
> + AXP803_IRQ_BATT_ACT_TEMP_HIGH,
> + AXP803_IRQ_BATT_ACT_TEMP_HIGH_END,
> + AXP803_IRQ_BATT_ACT_TEMP_LOW,
> + AXP803_IRQ_BATT_ACT_TEMP_LOW_END,
> + AXP803_IRQ_DIE_TEMP_HIGH,
> + AXP803_IRQ_GPADC,
> + AXP803_IRQ_LOW_PWR_LVL1,
> + AXP803_IRQ_LOW_PWR_LVL2,
> + AXP803_IRQ_TIMER,
> + AXP803_IRQ_PEK_RIS_EDGE,
> + AXP803_IRQ_PEK_FAL_EDGE,
> + AXP803_IRQ_PEK_SHORT,
> + AXP803_IRQ_PEK_LONG,
> + AXP803_IRQ_PEK_OVER_OFF,
> + AXP803_IRQ_GPIO1_INPUT,
> + AXP803_IRQ_GPIO0_INPUT,
> + AXP803_IRQ_BC_USB_CHNG,
> + AXP803_IRQ_MV_CHNG,
> +};
> +
> struct axp20x_dev {
> struct device *dev;
> int irq;
> --
> 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: [RFC] [media] imx: assume MEDIA_ENT_F_ATV_DECODER entities output video on pad 1
From: Mauro Carvalho Chehab @ 2017-04-05 14:53 UTC (permalink / raw)
To: Philipp Zabel
Cc: mark.rutland, andrew-ct.chen, minghsiu.tsai, nick, songjun.wu,
hverkuil, Steve Longerbeam, pavel, robert.jarzmik, devel,
markus.heiser, laurent.pinchart+renesas, shuah,
Russell King - ARM Linux, geert, Steve Longerbeam, linux-media,
devicetree, sakari.ailus, arnd, mchehab, bparrot, robh+dt,
horms+renesas, tiffany.lin, linux-arm-kernel,
niklas.soderlund+renesas, gregkh, linux-kernel,
jean-christophe.trotin, kernel, fabio.estevam
In-Reply-To: <1491384859.2381.51.camel@pengutronix.de>
Em Wed, 05 Apr 2017 11:34:19 +0200
Philipp Zabel <p.zabel@pengutronix.de> escreveu:
> On Wed, 2017-04-05 at 09:21 +0100, Russell King - ARM Linux wrote:
> [...]
> > > Actually what was I thinking, the TVP5150 is already an example of
> > > such a device.
> > >
> > > All of this could be solved if there was some direction information
> > > in port nodes.
> >
> > I disagree.
> >
> > Philipp identified that the TVP5150 has four pads:
> >
> > * Input pad
> > * Video output pad
> > * VBI output pad
> > * Audio output pad
>
> I didn't think hard enough about this earlier, but there are really only
> two hardware interfaces on TVP5150. The ADC input, which can be
> connected to either of two composite input pins (AIP1A, AIP1B), or use
> both for s-video, and the digital output connected to pins (YOUT[7:0]).
>
> VBI data can be transferred via the output pins during horizontal or
> vertical blanking, if I understand correctly, or read from a FIFO via
> I2C.
>
> There is no apparent support for audio data whatsoever, and the only
> mention of audio in the data manual is a vague reference about an "audio
> interface available on the TVP5150" providing a clock to an audio
> interface between an external audio decoder and the backend processor.
>
> Further, commit 55606310e77f ("[media] tvp5150: create the expected
> number of pads") creates DEMOD_NUM_PADS pads, but doesn't mention or
> initialize the audio pad. It clearly expects the value of DEMOD_NUM_PADS
> to be 3. And indeed the fourth pad was added later in commit
> bddc418787cc ("[media] au0828: use standard demod pads struct").
>
> So to me it looks like the VBI and audio pads should be removed from
> TVP5150.
There are a number of drivers that can work with different
types of TV demodulators. Typical examples of such hardware can be
found at em28xx, saa7134, cx88 drivers (among lots of other drivers).
Those drivers don't use the subdev API. Instead, they use a generic
helper function with sets the pipelines, based on the pad number.
The problem here is that, currently, both MC API and MC core
lacks a way to identify PAD ports per type, as the only information
that a bridge driver has is a pad number. So, in order for a
generic helper function to work, we had to hardcode pad numbers,
in a way that it would work for all possible types of demods.
It shouldn't be hard to add a "pad_type" information at media_pad
struct, but passing such info to userspace requires a new API
(we're calling it as "properties API"). Sakari was meant to send
us an updated RFC for it[1] with a patchset, back in 2015, but
this never happened.
[1] https://linuxtv.org/news.php?entry=2015-08-17.mchehab
Each vendor chooses the demod using some random criteria
(usually, they use whatever costs less by the time they create a
hardware model). Newer versions of the same hardware frequently
has a different model.
For example, in the case of em28xx driver, there are currently
several types of demods supported there, like (among other options):
- demods with tda9887, with is actually part of a tuner that has
an outputs for IF luminance, IF chrominance and IF audio;
- demods with xc3028, with is an integrated tuner + audio demod,
with outputs both video as a baseband signal and audio data via IF,
(or outputs a single IF signal, for Digital TV);
- demods with both xc3028 and msp3400. The last one transforms
audio IF into I2S;
- demods with saa711x (supported by saa7115 driver), with may or may
not have raw VBI and/or sliced VBI, depending on the specific model,
with is detected during driver's probe.
The generic function should be robust enough to handle all above
cases.
Without a way to report the PAD type to userspace, applications
that need to setup or recognize such pipelines need to hardcode the
pad numbers on userspace. That's, by the way, one of the issues why
it is currently impossible to write a full generic MC plugin at libv4l:
there's currently no way for userspace to recognize what type of
signals each PAD input or output carries.
So, in short, the tvp5150 demod doesn't decode audio, but there
are other demods that do it.
In the case of VBI, tvp5150 has actually two ways of reporting
it:
1) via YOUT[7:0] pins. VBI information is transmitted as a
set of raw samples, via an ancillary data block, during
vertical/horizontal blanking intervals. So, yes, it shares
the same hardware output, although the VBI contents are
actually multiplexed there. Please notice that not all
video out PADS encapsulate raw VBI the same way as tvp5150
(and some devices even don't support raw VBI, like saa7110 and
some models supported by saa7115 driver).
2) via an interrupt that indicates that it decoded VBI data. The
VBI information itself is there on FIFO, accessible via a set of
registers (see "VBI Data processor" chapter at the datasheet).
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.
So, in the case of tvp5150 hardware, have those PADS:
- Input baseband;
- Video + raw VBI output;
- sliced VBI output.
Yet, we need an always unconnected audio output, in order to support
different demods out there.
[1] tvp5150 was written to support some em28xx-based devices
>
> > So, it has one input and three outputs. How does marking the direction
> > in the port node (which would indicate that there was a data flow out of
> > TVP5150 into the iMX6 capture) help identify which of those pads should
> > be used?
> >
> > It would eliminate the input pad, but you still have three output pads
> > to choose from.
> >
> > So no, your idea can't work.
>
> In this case, removal of the VBI and audio pads might make this work,
> but in general this is true. In my opinion, to make this truly generic,
> we need an interface to ask the driver which media entity pad a given
> device tree port corresponds to, as there might not even be a single
> media entity corresponding to all ports for more complex devices.
Yes. We also need something like that at the userspace API.
Thanks,
Mauro
^ permalink raw reply
* Re: [PATCH 2/2] memory: ti-emif-sram: introduce relocatable suspend/resume handlers
From: Dave Gerlach @ 2017-04-05 14:48 UTC (permalink / raw)
To: Tony Lindgren, Russell King - ARM Linux
Cc: Rob Herring, Santosh Shilimkar,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-omap-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Keerthy J
In-Reply-To: <20170405143318.GE13234-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>
Russell,
On 04/05/2017 09:33 AM, Tony Lindgren wrote:
> * Russell King - ARM Linux <linux-I+IVW8TIWO2tmTQ+vhA3Yw@public.gmane.org> [170405 07:02]:
>> On Tue, Apr 04, 2017 at 09:11:52AM -0700, Tony Lindgren wrote:
>>> Russell,
>>>
>>> * Dave Gerlach <d-gerlach-l0cyMroinI0@public.gmane.org> [170328 13:57]:
>>>> Certain SoCs like Texas Instruments AM335x and AM437x require parts
>>>> of the EMIF PM code to run late in the suspend sequence from SRAM,
>>>> such as saving and restoring the EMIF context and placing the memory
>>>> into self-refresh.
>>>>
>>>> One requirement for these SoCs to suspend and enter its lowest power
>>>> mode, called DeepSleep0, is that the PER power domain must be shut off.
>>>> Because the EMIF (DDR Controller) resides within this power domain, it
>>>> will lose context during a suspend operation, so we must save it so we
>>>> can restore once we resume. However, we cannot execute this code from
>>>> external memory, as it is not available at this point, so the code must
>>>> be executed late in the suspend path from SRAM.
>>>>
>>>> This patch introduces a ti-emif-sram driver that includes several
>>>> functions written in ARM ASM that are relocatable so the PM SRAM
>>>> code can use them. It also allocates a region of writable SRAM to
>>>> be used by the code running in the executable region of SRAM to save
>>>> and restore the EMIF context. It can export a table containing the
>>>> absolute addresses of the available PM functions so that other SRAM
>>>> code can branch to them. This code is required for suspend/resume on
>>>> AM335x and AM437x to work.
>>>>
>>>> In addition to this, to be able to share data structures between C and
>>>> the ti-emif-sram-pm assembly code, we can automatically generate all of
>>>> the C struct member offsets and sizes as macros by making use of the ARM
>>>> asm-offsets file. In the same header that we define our data structures
>>>> in we also define all the macros in an inline function and by adding a
>>>> call to this in the asm_offsets file all macros are properly generated
>>>> and available to the assembly code without cluttering up the asm-offsets
>>>> file.
>>>>
>>>> Signed-off-by: Dave Gerlach <d-gerlach-l0cyMroinI0@public.gmane.org>
>>>> ---
>>>> arch/arm/kernel/asm-offsets.c | 6 +
>>>> drivers/memory/Kconfig | 10 ++
>>>> drivers/memory/Makefile | 4 +
>>>> drivers/memory/emif.h | 17 ++
>>>> drivers/memory/ti-emif-pm.c | 295 ++++++++++++++++++++++++++++++++++
>>>> drivers/memory/ti-emif-sram-pm.S | 334 +++++++++++++++++++++++++++++++++++++++
>>>> include/linux/ti-emif-sram.h | 143 +++++++++++++++++
>>>> 7 files changed, 809 insertions(+)
>>>> create mode 100644 drivers/memory/ti-emif-pm.c
>>>> create mode 100644 drivers/memory/ti-emif-sram-pm.S
>>>> create mode 100644 include/linux/ti-emif-sram.h
>>>>
>>>> diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
>>>> index 608008229c7d..d728b5660e36 100644
>>>> --- a/arch/arm/kernel/asm-offsets.c
>>>> +++ b/arch/arm/kernel/asm-offsets.c
>>>> @@ -28,6 +28,7 @@
>>>> #include <asm/vdso_datapage.h>
>>>> #include <asm/hardware/cache-l2x0.h>
>>>> #include <linux/kbuild.h>
>>>> +#include <linux/ti-emif-sram.h>
>>>>
>>>> /*
>>>> * Make sure that the compiler and target are compatible.
>>>> @@ -183,5 +184,10 @@ int main(void)
>>>> #ifdef CONFIG_VDSO
>>>> DEFINE(VDSO_DATA_SIZE, sizeof(union vdso_data_store));
>>>> #endif
>>>> +#if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX)
>>>> + BLANK();
>>>> + ti_emif_offsets();
>>>> +#endif
>>>> +
>>>> return 0;
>>>> }
>>>
>>> Does the above look OK to you?
>>
>> I'm not going to comment on this yet, but I'll instead comment on the
>> newly appeared sram_exec_copy() stuff.
>>
>> So, a few years ago, we went to significant effort in ARM land to come
>> up with a way to _safely_ copy assembler from the kernel into SRAM,
>> because copying code to SRAM that is compiled in thumb mode and then
>> executing it is _not_ as simple as memcpy(), cast the pointer to a
>> function pointer, and then call the function pointer.
>>
>> The SRAM stuff throws all that out, instead preferring the dumb memcpy()
>> approach.
>>
>> This needs resolving, and I'd like to see it resolved to the satisfaction
>> of architecture maintainers before we progress any further down this
>> route.
I'm sure you are referring to fncpy, correct? This is what we used before with
ARM specific code to do the copy, but we've moved into drivers now. What are
your thoughts on exposing fncpy outside of arch/arm?
Regards,
Dave
>
> OK thanks, will wait until that is sorted out before merging any
> of the SRAM code.
>
> Regards,
>
> Tony
>
--
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/4] dt-bindings: iio: stm32-dac: Add support for STM32 DAC
From: Fabrice Gasnier @ 2017-04-05 14:48 UTC (permalink / raw)
To: Rob Herring
Cc: mark.rutland, devicetree, benjamin.gaignard, lars,
alexandre.torgue, amelie.delaunay, linux-iio, pmeerw, linux,
linux-kernel, jic23, mcoquelin.stm32, knaack.h, linus.walleij,
linux-arm-kernel, benjamin.gaignard
In-Reply-To: <20170403164240.hw4wza7y3s5faivb@rob-hp-laptop>
On 04/03/2017 06:42 PM, Rob Herring wrote:
> On Fri, Mar 31, 2017 at 01:45:04PM +0200, Fabrice Gasnier wrote:
>> Document STMicroelectronics STM32 DAC (digital-to-analog converter).
>>
>> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
>> ---
>> .../devicetree/bindings/iio/dac/st,stm32-dac.txt | 56 ++++++++++++++++++++++
>> 1 file changed, 56 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/iio/dac/st,stm32-dac.txt
>>
>> diff --git a/Documentation/devicetree/bindings/iio/dac/st,stm32-dac.txt b/Documentation/devicetree/bindings/iio/dac/st,stm32-dac.txt
>> new file mode 100644
>> index 0000000..1981983
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/iio/dac/st,stm32-dac.txt
>> @@ -0,0 +1,56 @@
>> +STMicroelectronics STM32 DAC
>> +
>> +The STM32 DAC is a 12-bit voltage output digital-to-analog converter. The DAC
>> +can be configured in 8- or 12-bit mode. In 12-bit mode, the data could be
>> +left- or right-aligned. It has two output channels, each with its own converter.
>> +It has built-in noise and triangle waveform generator and supports external
>> +triggers for conversions. The DAC's output buffer allows a high drive output
>> +current.
>> +
>> +Contents of a stm32 dac root node:
>> +-----------------------------------
>> +Required properties:
>> +- compatible: Must be "st,stm32h7-dac-core".
>> +- reg: Offset and length of the device's register set.
>> +- clocks: Must contain an entry for pclk (which feeds the peripheral bus
>> + interface)
>> +- clock-names: Must be "pclk".
>> +- vref-supply: Phandle to the vref+ input analog reference supply.
>> +
>> +Optional properties:
>> +- resets: Must contain the phandle to the reset controller.
>> +- A pinctrl state named "default" for each DAC channel may be defined to set
>> + DAC_OUTx pin in mode of operation for analog output on external pin.
>> +
>> +Contents of a stm32 dac child node:
>> +-----------------------------------
>> +DAC core node should contain at least one subnode, representing a
>> +DAC instance/channel available on the machine.
>> +
>> +Required properties:
>> +- compatible: Must be "st,stm32-dac".
>> +- #io-channel-cells = <1>: See the IIO bindings section "IIO consumers" in
>> + Documentation/devicetree/bindings/iio/iio-bindings.txt
>> +- st,dac-channel: Must be either 1 or 2, to define channel in use (e.g.
>> + single channels: 1 or 2)
>
> Use "reg" instead.
Hi Rob,
Thanks your reviewing. I'll update this in V2
Best Regards,
Fabrice
>
>> +
>> +Example:
>> + dac: dac@40007400 {
>> + compatible = "st,stm32h7-dac-core";
>> + reg = <0x40007400 0x400>;
>> + clocks = <&clk>;
>> + clock-names = "pclk";
>> + vref-supply = <®_vref>;
>> +
>> + dac1: dac@1 {
>> + compatible = "st,stm32-dac";
>> + #io-channels-cells = <1>;
>> + st,dac-channel = <1>;
>> + };
>> +
>> + dac2: dac@2 {
>> + compatible = "st,stm32-dac";
>> + #io-channels-cells = <1>;
>> + st,dac-channel = <2>;
>> + };
>> + };
>> --
>> 1.9.1
>>
^ permalink raw reply
* Re: [PATCH 1/4] dt-bindings: iio: stm32-dac: Add support for STM32 DAC
From: Fabrice Gasnier @ 2017-04-05 14:47 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: <a6c51b90-c14b-412c-1006-cf0dd7abda0d@kernel.org>
On 04/02/2017 01:16 PM, Jonathan Cameron wrote:
> On 31/03/17 12:45, Fabrice Gasnier wrote:
>> Document STMicroelectronics STM32 DAC (digital-to-analog converter).
>>
>> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
>> ---
>> .../devicetree/bindings/iio/dac/st,stm32-dac.txt | 56 ++++++++++++++++++++++
>> 1 file changed, 56 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/iio/dac/st,stm32-dac.txt
>>
>> diff --git a/Documentation/devicetree/bindings/iio/dac/st,stm32-dac.txt b/Documentation/devicetree/bindings/iio/dac/st,stm32-dac.txt
>> new file mode 100644
>> index 0000000..1981983
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/iio/dac/st,stm32-dac.txt
>> @@ -0,0 +1,56 @@
>> +STMicroelectronics STM32 DAC
>> +
>> +The STM32 DAC is a 12-bit voltage output digital-to-analog converter. The DAC
>> +can be configured in 8- or 12-bit mode. In 12-bit mode, the data could be
>> +left- or right-aligned.
> Whilst possibly true, do we care about the alignment? That'll all get wrapped
> up in the driver.
Hi Jonathan,
I'll update this description in V2
>
>> It has two output channels, each with its own converter.
>> +It has built-in noise and triangle waveform generator and supports external
>> +triggers for conversions. The DAC's output buffer allows a high drive output
>> +current.
> Ah.. This is going to be fun :) More unusual hardware to find in an SoC.
Yes, let's discuss this on following patches.
Thanks your review,
Best Regards,
Fabrice
>> +
>> +Contents of a stm32 dac root node:
>> +-----------------------------------
>> +Required properties:
>> +- compatible: Must be "st,stm32h7-dac-core".
>> +- reg: Offset and length of the device's register set.
>> +- clocks: Must contain an entry for pclk (which feeds the peripheral bus
>> + interface)
>> +- clock-names: Must be "pclk".
>> +- vref-supply: Phandle to the vref+ input analog reference supply.
>> +
>> +Optional properties:
>> +- resets: Must contain the phandle to the reset controller.
>> +- A pinctrl state named "default" for each DAC channel may be defined to set
>> + DAC_OUTx pin in mode of operation for analog output on external pin.
>> +
>> +Contents of a stm32 dac child node:
>> +-----------------------------------
>> +DAC core node should contain at least one subnode, representing a
>> +DAC instance/channel available on the machine.
>> +
>> +Required properties:
>> +- compatible: Must be "st,stm32-dac".
>> +- #io-channel-cells = <1>: See the IIO bindings section "IIO consumers" in
>> + Documentation/devicetree/bindings/iio/iio-bindings.txt
>> +- st,dac-channel: Must be either 1 or 2, to define channel in use (e.g.
>> + single channels: 1 or 2)
>> +
>> +Example:
>> + dac: dac@40007400 {
>> + compatible = "st,stm32h7-dac-core";
>> + reg = <0x40007400 0x400>;
>> + clocks = <&clk>;
>> + clock-names = "pclk";
>> + vref-supply = <®_vref>;
>> +
>> + dac1: dac@1 {
>> + compatible = "st,stm32-dac";
>> + #io-channels-cells = <1>;
>> + st,dac-channel = <1>;
>> + };
>> +
>> + dac2: dac@2 {
>> + compatible = "st,stm32-dac";
>> + #io-channels-cells = <1>;
>> + st,dac-channel = <2>;
>> + };
>> + };
>>
>
^ permalink raw reply
* Re: [PATCH 2/2] memory: ti-emif-sram: introduce relocatable suspend/resume handlers
From: Tony Lindgren @ 2017-04-05 14:33 UTC (permalink / raw)
To: Russell King - ARM Linux
Cc: devicetree, Dave Gerlach, Keerthy J, linux-kernel, Rob Herring,
Santosh Shilimkar, linux-omap, linux-arm-kernel
In-Reply-To: <20170405135933.GN23750@n2100.armlinux.org.uk>
* Russell King - ARM Linux <linux@armlinux.org.uk> [170405 07:02]:
> On Tue, Apr 04, 2017 at 09:11:52AM -0700, Tony Lindgren wrote:
> > Russell,
> >
> > * Dave Gerlach <d-gerlach@ti.com> [170328 13:57]:
> > > Certain SoCs like Texas Instruments AM335x and AM437x require parts
> > > of the EMIF PM code to run late in the suspend sequence from SRAM,
> > > such as saving and restoring the EMIF context and placing the memory
> > > into self-refresh.
> > >
> > > One requirement for these SoCs to suspend and enter its lowest power
> > > mode, called DeepSleep0, is that the PER power domain must be shut off.
> > > Because the EMIF (DDR Controller) resides within this power domain, it
> > > will lose context during a suspend operation, so we must save it so we
> > > can restore once we resume. However, we cannot execute this code from
> > > external memory, as it is not available at this point, so the code must
> > > be executed late in the suspend path from SRAM.
> > >
> > > This patch introduces a ti-emif-sram driver that includes several
> > > functions written in ARM ASM that are relocatable so the PM SRAM
> > > code can use them. It also allocates a region of writable SRAM to
> > > be used by the code running in the executable region of SRAM to save
> > > and restore the EMIF context. It can export a table containing the
> > > absolute addresses of the available PM functions so that other SRAM
> > > code can branch to them. This code is required for suspend/resume on
> > > AM335x and AM437x to work.
> > >
> > > In addition to this, to be able to share data structures between C and
> > > the ti-emif-sram-pm assembly code, we can automatically generate all of
> > > the C struct member offsets and sizes as macros by making use of the ARM
> > > asm-offsets file. In the same header that we define our data structures
> > > in we also define all the macros in an inline function and by adding a
> > > call to this in the asm_offsets file all macros are properly generated
> > > and available to the assembly code without cluttering up the asm-offsets
> > > file.
> > >
> > > Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
> > > ---
> > > arch/arm/kernel/asm-offsets.c | 6 +
> > > drivers/memory/Kconfig | 10 ++
> > > drivers/memory/Makefile | 4 +
> > > drivers/memory/emif.h | 17 ++
> > > drivers/memory/ti-emif-pm.c | 295 ++++++++++++++++++++++++++++++++++
> > > drivers/memory/ti-emif-sram-pm.S | 334 +++++++++++++++++++++++++++++++++++++++
> > > include/linux/ti-emif-sram.h | 143 +++++++++++++++++
> > > 7 files changed, 809 insertions(+)
> > > create mode 100644 drivers/memory/ti-emif-pm.c
> > > create mode 100644 drivers/memory/ti-emif-sram-pm.S
> > > create mode 100644 include/linux/ti-emif-sram.h
> > >
> > > diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
> > > index 608008229c7d..d728b5660e36 100644
> > > --- a/arch/arm/kernel/asm-offsets.c
> > > +++ b/arch/arm/kernel/asm-offsets.c
> > > @@ -28,6 +28,7 @@
> > > #include <asm/vdso_datapage.h>
> > > #include <asm/hardware/cache-l2x0.h>
> > > #include <linux/kbuild.h>
> > > +#include <linux/ti-emif-sram.h>
> > >
> > > /*
> > > * Make sure that the compiler and target are compatible.
> > > @@ -183,5 +184,10 @@ int main(void)
> > > #ifdef CONFIG_VDSO
> > > DEFINE(VDSO_DATA_SIZE, sizeof(union vdso_data_store));
> > > #endif
> > > +#if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX)
> > > + BLANK();
> > > + ti_emif_offsets();
> > > +#endif
> > > +
> > > return 0;
> > > }
> >
> > Does the above look OK to you?
>
> I'm not going to comment on this yet, but I'll instead comment on the
> newly appeared sram_exec_copy() stuff.
>
> So, a few years ago, we went to significant effort in ARM land to come
> up with a way to _safely_ copy assembler from the kernel into SRAM,
> because copying code to SRAM that is compiled in thumb mode and then
> executing it is _not_ as simple as memcpy(), cast the pointer to a
> function pointer, and then call the function pointer.
>
> The SRAM stuff throws all that out, instead preferring the dumb memcpy()
> approach.
>
> This needs resolving, and I'd like to see it resolved to the satisfaction
> of architecture maintainers before we progress any further down this
> route.
OK thanks, will wait until that is sorted out before merging any
of the SRAM code.
Regards,
Tony
^ permalink raw reply
* [PATCH 2/2] arm64: allwinner: a64: add pmu0 regs for USB PHY
From: Icenowy Zheng @ 2017-04-05 14:30 UTC (permalink / raw)
To: Maxime Ripard, Chen-Yu Tsai, Kishon Vijay Abraham I,
Greg Kroah-Hartman
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Icenowy Zheng
In-Reply-To: <20170405143034.8868-1-icenowy-h8G6r0blFSE@public.gmane.org>
The USB PHY in A64 has a "pmu0" region, which controls the EHCI/OHCI
controller pair that can be connected to the PHY0.
Add the MMIO region for PHY node.
Signed-off-by: Icenowy Zheng <icenowy-h8G6r0blFSE@public.gmane.org>
---
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
index 1c64ea2d23f9..0565779e66fa 100644
--- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
+++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
@@ -179,8 +179,10 @@
usbphy: phy@01c19400 {
compatible = "allwinner,sun50i-a64-usb-phy";
reg = <0x01c19400 0x14>,
+ <0x01c1a800 0x4>,
<0x01c1b800 0x4>;
reg-names = "phy_ctrl",
+ "pmu0",
"pmu1";
clocks = <&ccu CLK_USB_PHY0>,
<&ccu CLK_USB_PHY1>;
--
2.12.2
^ permalink raw reply related
* [PATCH 1/2] dt: bindings: add pmu0 regs for USB PHYs on Allwinner H3/V3s/A64
From: Icenowy Zheng @ 2017-04-05 14:30 UTC (permalink / raw)
To: Maxime Ripard, Chen-Yu Tsai, Kishon Vijay Abraham I,
Greg Kroah-Hartman
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Icenowy Zheng
In-Reply-To: <20170405143034.8868-1-icenowy-h8G6r0blFSE@public.gmane.org>
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>
---
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
--
2.12.2
^ permalink raw reply related
* [PATCH 0/2] pmu0 MMIO region for A64 USB PHY
From: Icenowy Zheng @ 2017-04-05 14:30 UTC (permalink / raw)
To: Maxime Ripard, Chen-Yu Tsai, Kishon Vijay Abraham I,
Greg Kroah-Hartman
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-sunxi-/JYPxA39Uh5TLH3MbocFFw, Icenowy Zheng
The USB PHY of A64 contains a "pmu0" MMIO region, which contains some control
registers for the EHCI0/OHCI0 pair on A64 SoC.
This pair is not used currently in 4.11, but when enabling it in 4.12, the
MMIO region is needed.
In order to prevent device tree compatibility breakage, add this region in
4.11.
Icenowy Zheng (2):
dt: bindings: add pmu0 regs for USB PHYs on Allwinner H3/V3s/A64
arm64: allwinner: a64: add pmu0 regs for USB PHY
Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt | 1 +
arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 2 ++
2 files changed, 3 insertions(+)
--
2.12.2
^ 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 14:28 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: <20170405052847.326-1-ralph.sennhauser@gmail.com>
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-*.
> 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.
Andrew
^ permalink raw reply
* Re: [PATCH v4 4/9] arm: dts: dt-bindings: Add Renesas RZ/A1 pinctrl header
From: Geert Uytterhoeven @ 2017-04-05 14:27 UTC (permalink / raw)
To: Jacopo Mondi
Cc: Linus Walleij, Geert Uytterhoeven, Laurent Pinchart, Chris Brandt,
Rob Herring, Mark Rutland, Russell King, Linux-Renesas,
linux-gpio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <1491401247-7030-5-git-send-email-jacopo+renesas-AW8dsiIh9cEdnm+yROfE0A@public.gmane.org>
On Wed, Apr 5, 2017 at 4:07 PM, Jacopo Mondi <jacopo+renesas-AW8dsiIh9cEdnm+yROfE0A@public.gmane.org> wrote:
> --- /dev/null
> +++ b/include/dt-bindings/pinctrl/r7s72100-pinctrl.h
> @@ -0,0 +1,16 @@
> +/*
> + * Defines macros and constants for Renesas RZ/A1 pin controller pin
> + * muxing functions.
> + */
> +#ifndef __DT_BINDINGS_PINCTRL_RENESAS_RZA1_H
> +#define __DT_BINDINGS_PINCTRL_RENESAS_RZA1_H
> +
> +#define RZA1_PINS_PER_PORT 16
> +
> +/*
> + * Create the pin index from its bank and position numbers and store in
> + * the upper 16 bits the alternate function identifier
> + */
> +#define RZA1_PINMUX(b, p, f) ((b) * RZA1_PINS_PER_PORT + (p) | (f << 16))
... | (f) << 16)
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert-Td1EMuHUCqxL1ZNQvxDV9g@public.gmane.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
--
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/2] doc: Add bindings document for Xilinx LogiCore PR Decoupler
From: Alan Tull @ 2017-04-05 14:24 UTC (permalink / raw)
To: Moritz Fischer
Cc: Rob Herring, Greg Kroah-Hartman, Linux Kernel Mailing List,
linux-fpga-u79uwXL29TY76Z2rM5mHXA, Moritz Fischer, Michal Simek,
Sören Brinkmann, Devicetree List
In-Reply-To: <CAAtXAHe0qnu7Ub6sing4VUgFa-tkdvH767kNbZnu1S5THHS2oQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On Tue, Apr 4, 2017 at 6:36 PM, Moritz Fischer <moritz.fischer-+aYTwkv1SeIAvxtiuMwx3w@public.gmane.org> wrote:
> On Thu, Mar 30, 2017 at 05:44:29PM -0500, Rob Herring wrote:
>> On Fri, Mar 24, 2017 at 10:33:20AM -0500, Alan Tull wrote:
>> > From: Moritz Fischer <mdf-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>>
>> Please use "dt-bindings: fpga: ..." for the subject.
>>
>>
>> >
>> > This adds the binding documentation for the Xilinx LogiCORE PR
>> > Decoupler soft core.
>> >
>> > Signed-off-by: Moritz Fischer <mdf-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>> > Signed-off-by: Michal Simek <michal.simek-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org>
>> > Acked-by: Alan Tull <atull-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>>
>> I'm confused why you are sending these instead of Moritz? If it goes
>> through you, then it should have your S-o-B too.
Greg asked me to send patches to him. I should have started adding my
signed-of-by
at that point.
>
> Do you want me to resend this Alan (with Rob's suggestions)?
I sent a set of patches to Greg on March 24. Looking back on that I realize
that it didn't have Rob's ack yet (as well as having my ack where it should
have been my signed-of-by).
Yes, please resend this patchset with Rob's feedback.
Thanks,
ALan
>>
>> > Cc: Sören Brinkmann <soren.brinkmann-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org>
>> > Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>> > Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>> > ---
>> > .../bindings/fpga/xilinx-pr-decoupler.txt | 35 ++++++++++++++++++++++
>> > 1 file changed, 35 insertions(+)
>> > create mode 100644 Documentation/devicetree/bindings/fpga/xilinx-pr-decoupler.txt
>> >
>> > diff --git a/Documentation/devicetree/bindings/fpga/xilinx-pr-decoupler.txt b/Documentation/devicetree/bindings/fpga/xilinx-pr-decoupler.txt
>> > new file mode 100644
>> > index 000000000000..2c527ac30398
>> > --- /dev/null
>> > +++ b/Documentation/devicetree/bindings/fpga/xilinx-pr-decoupler.txt
>> > @@ -0,0 +1,35 @@
>> > +Xilinx LogiCORE Partial Reconfig Decoupler Softcore
>> > +
>> > +The Xilinx LogiCORE Partial Reconfig Decoupler manages one or more
>> > +decouplers / fpga bridges.
>> > +The controller can decouple/disable the bridges which prevents signal
>> > +changes from passing through the bridge. The controller can also
>> > +couple / enable the bridges which allows traffic to pass through the
>> > +bridge normally.
>> > +
>> > +The Driver supports only MMIO handling. A PR region can have multiple
>> > +PR Decouplers which can be handled independently or chained via decouple/
>> > +decouple_status signals.
>> > +
>> > +Required properties:
>> > +- compatible : Should contain "xlnx,pr-decoupler-1.00" or "xlnx,pr-decoupler"
>>
>> I'd drop xlnx,pr-decoupler, but in any case, it should not be OR rather
>> "followed by". Plus the example has both.
>
> Michal wanted to have both, so I put both. Personally I don't care. I
> think they have some downstream stuff that relied on it.
>
>>
>> > +- regs : base address and size for decoupler module
>> > +- clocks : input clock to IP
>> > +- clock-names : should contain "aclk"
>> > +
>> > +Optional properties:
>> > +- bridge-enable : 0 if driver should disable bridge at startup
>> > + 1 if driver should enable bridge at startup
>> > + Default is to leave bridge in current state.
>> > +
>> > +See Documentation/devicetree/bindings/fpga/fpga-region.txt for generic bindings.
>> > +
>> > +Example:
>> > + fpga-bridge@100000450 {
>> > + compatible = "xlnx,pr-decoupler-1.00",
>> > + "xlnx-pr-decoupler";
>> > + regs = <0x10000045 0x10>;
>> > + clocks = <&clkc 15>;
>> > + clock-names = "aclk";
>> > + bridge-enable = <0>;
>> > + };
>> > --
>> > 2.11.0
>> >
>> > --
>> > 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
>
> Thanks,
> Moritz
--
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 v2 1/3] clk: vc5: Add structure to describe particular chip features
From: Marek Vasut @ 2017-04-05 14:20 UTC (permalink / raw)
To: Alexey Firago, Geert Uytterhoeven
Cc: Michael Turquette, Stephen Boyd, Rob Herring, linux-clk,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <de978809-5bec-d675-1ea3-cc61804e2c61-nmGgyN9QBj3QT0dZR+AlfA@public.gmane.org>
On 04/05/2017 02:36 PM, Alexey Firago wrote:
> Hi Geert,
>
> On 05.04.2017 15:15, Geert Uytterhoeven wrote:
>> Hi Alexey,
>>
>> On Wed, Apr 5, 2017 at 1:46 PM, Alexey Firago
>> <alexey_firago-nmGgyN9QBj3QT0dZR+AlfA@public.gmane.org> wrote:
>>> Introduce vc5_chip_info structure to describe features of a particular
>>> VC5 chip (id, number of FODs, number of outputs, flags).
>>> For now flags are only used to indicate if chip has internal XTAL.
>>> vc5_chip_info is set on probe from the matched of_device_id->data.
>>>
>>> Also add defines to specify maximum number of FODs and clock outputs
>>> supported by the driver.
>>>
>>> With these changes it should be easier to extend driver to support
>>> more VC5 models.
>>>
>>> Signed-off-by: Alexey Firago <alexey_firago-nmGgyN9QBj3QT0dZR+AlfA@public.gmane.org>
>>
>> Thanks for your patch!
>>
>> Reviewed-by: Geert Uytterhoeven <geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ@public.gmane.org>
>>
>>> --- a/drivers/clk/clk-versaclock5.c
>>> +++ b/drivers/clk/clk-versaclock5.c
>>> @@ -113,12 +113,30 @@
>>> #define VC5_MUX_IN_XIN BIT(0)
>>> #define VC5_MUX_IN_CLKIN BIT(1)
>>>
>>> +/* Maximum number of clk_out supported by this driver */
>>> +#define VC5_MAX_CLK_OUT_NUM 3
>>> +
>>> +/* Maximum number of FODs supported by this driver */
>>> +#define VC5_MAX_FOD_NUM 2
>>> +
>>> +/* flags to describe chip features */
>>> +/* chip has built-in oscilator */
>>> +#define VC5_HAS_INTERNAL_XTAL BIT(0)
>>
>> VC5_HAS_INTERNAL_OSC?
>
> I'm fine with renaming it, but shouldn't it be consistent with the rest
> of the driver (see "internal-xtal", VC5_XTAL*, etc) and IDT datasheet?
>
Do you have one with internal ring oscillator or with internal xtal ?
The one I had has internal xtal according to the datasheet.
--
Best regards,
Marek Vasut
--
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
* [PATCH 4/4] pwm: tegra: Add support to configure pin state in suspends/resume
From: Laxman Dewangan @ 2017-04-05 14:13 UTC (permalink / raw)
To: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8
Cc: jonathanh-DDmLM1+adcrQT0dZR+AlfA,
linux-pwm-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-tegra-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Laxman Dewangan
In-Reply-To: <1491401626-31303-1-git-send-email-ldewangan-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
In some of NVIDIA Tegra's platform, PWM controller is used to
control the PWM controlled regulators. PWM signal is connected to
the VID pin of the regulator where duty cycle of PWM signal decide
the voltage level of the regulator output.
The tristate (high impedance of PWM pin form Tegra) also define
one of the state of PWM regulator which needs to be configure in
suspend state of system.
Add support to configure the pin state via pinctrl frameworks in
suspend and active state of the system.
Signed-off-by: Laxman Dewangan <ldewangan-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/pwm/pwm-tegra.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c
index e9c4de5..60ed522 100644
--- a/drivers/pwm/pwm-tegra.c
+++ b/drivers/pwm/pwm-tegra.c
@@ -29,6 +29,7 @@
#include <linux/of_device.h>
#include <linux/pwm.h>
#include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/slab.h>
#include <linux/reset.h>
@@ -52,6 +53,9 @@ struct tegra_pwm_chip {
void __iomem *regs;
const struct tegra_pwm_soc *soc;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *suspend_state;
+ struct pinctrl_state *resume_state;
};
static inline struct tegra_pwm_chip *to_tegra_pwm_chip(struct pwm_chip *chip)
@@ -215,6 +219,27 @@ static int tegra_pwm_probe(struct platform_device *pdev)
pwm->chip.base = -1;
pwm->chip.npwm = pwm->soc->num_channels;
+ pwm->pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (!IS_ERR(pwm->pinctrl)) {
+ pwm->suspend_state = pinctrl_lookup_state(pwm->pinctrl,
+ "suspend");
+ if (IS_ERR(pwm->suspend_state)) {
+ /* Ignore error other than PROBE_DEFER */
+ ret = PTR_ERR(pwm->suspend_state);
+ if (ret == -EPROBE_DEFER)
+ return ret;
+ }
+
+ pwm->resume_state = pinctrl_lookup_state(pwm->pinctrl,
+ "resume");
+ if (IS_ERR(pwm->resume_state)) {
+ /* Ignore error other than PROBE_DEFER */
+ ret = PTR_ERR(pwm->resume_state);
+ if (ret == -EPROBE_DEFER)
+ return ret;
+ }
+ }
+
ret = pwmchip_add(&pwm->chip);
if (ret < 0) {
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
@@ -256,6 +281,42 @@ static int tegra_pwm_remove(struct platform_device *pdev)
return pwmchip_remove(&pc->chip);
}
+#ifdef CONFIG_PM_SLEEP
+static int tegra_pwm_suspend(struct device *dev)
+{
+ struct tegra_pwm_chip *pc = dev_get_drvdata(dev);
+ int ret;
+
+ if (IS_ERR(pc->pinctrl) || IS_ERR(pc->suspend_state))
+ return 0;
+
+ ret = pinctrl_select_state(pc->pinctrl, pc->suspend_state);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set pin into suspend state:%d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int tegra_pwm_resume(struct device *dev)
+{
+ struct tegra_pwm_chip *pc = dev_get_drvdata(dev);
+ int ret;
+
+ if (IS_ERR(pc->pinctrl) || IS_ERR(pc->resume_state))
+ return 0;
+
+ ret = pinctrl_select_state(pc->pinctrl, pc->resume_state);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set pin into resume state:%d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
static const struct tegra_pwm_soc tegra20_pwm_soc = {
.num_channels = 4,
};
@@ -272,10 +333,15 @@ static const struct of_device_id tegra_pwm_of_match[] = {
MODULE_DEVICE_TABLE(of, tegra_pwm_of_match);
+static const struct dev_pm_ops tegra_pwm_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(tegra_pwm_suspend, tegra_pwm_resume)
+};
+
static struct platform_driver tegra_pwm_driver = {
.driver = {
.name = "tegra-pwm",
.of_match_table = tegra_pwm_of_match,
+ .pm = &tegra_pwm_pm_ops,
},
.probe = tegra_pwm_probe,
.remove = tegra_pwm_remove,
--
2.1.4
--
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 3/4] pwm: tegra: Add DT binding details to configure pin in suspends/resume
From: Laxman Dewangan @ 2017-04-05 14:13 UTC (permalink / raw)
To: thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8
Cc: jonathanh-DDmLM1+adcrQT0dZR+AlfA,
linux-pwm-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-tegra-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Laxman Dewangan
In-Reply-To: <1491401626-31303-1-git-send-email-ldewangan-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
In some of NVIDIA Tegra's platform, PWM controller is used to
control the PWM controlled regulators. PWM signal is connected to
the VID pin of the regulator where duty cycle of PWM signal decide
the voltage level of the regulator output.
The tristate (high impedance of PWM pin form Tegra) also define
one of the state of PWM regulator which needs to be configure in
suspend state of system.
Add DT binding details to provide the pin configuration state
from PWM and pinctrl DT node in suspend and active state of
the system.
Signed-off-by: Laxman Dewangan <ldewangan-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
.../devicetree/bindings/pwm/nvidia,tegra20-pwm.txt | 43 ++++++++++++++++++++++
1 file changed, 43 insertions(+)
diff --git a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
index b4e7377..145c323 100644
--- a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
+++ b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt
@@ -19,6 +19,19 @@ Required properties:
- reset-names: Must include the following entries:
- pwm
+Optional properties:
+============================
+In some of the interface like PWM based regualator device, it is required
+to configure the pins diffrently in different states, specially in suspend
+state of the system. The configuration of pin is provided via the pinctrl
+DT node as detailed in the pinctrl DT binding document
+ Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+
+The PWM node will have following optional properties.
+pinctrl-names: Pin state names. Must be "suspend" and "resume".
+pinctrl-0: Node handle of the suspend state configuration of pins.
+pinctrl-1: Node handle of the resume state configuration of pins.
+
Example:
pwm: pwm@7000a000 {
@@ -29,3 +42,33 @@ Example:
resets = <&tegra_car 17>;
reset-names = "pwm";
};
+
+
+Example with the pin configuration for suspend and resume:
+=========================================================
+Here Pin PE7 is used as PWM.
+
+#include <dt-bindings/pinctrl/pinctrl-tegra.h>
+
+ pinmux@70000868 {
+ pwm_suspend: pwm_suspend_state {
+ pe7 {
+ nvidia,pins = "pe7";
+ nvidia,tristate = <TEGRA_PIN_DISABLE>;
+ };
+ };
+
+ pwm_resume: pwm_resume_state {
+ pe7 {
+ nvidia,pins = "pe7";
+ nvidia,tristate = <TEGRA_PIN_DISABLE>;
+ };
+ };
+ };
+
+ pwm@7000a000 {
+ /* Mandatory pwm properties */
+ pinctrl-names = "suspend", "resume";
+ pinctrl-0 = <&pwm_suspend>;
+ pinctrl-1 = <&pwm_resume>;
+ };
--
2.1.4
^ permalink raw reply related
* [PATCH 2/4] pwm: tegra: Increase precision in pwm rate calculation
From: Laxman Dewangan @ 2017-04-05 14:13 UTC (permalink / raw)
To: thierry.reding, robh+dt, mark.rutland
Cc: jonathanh, linux-pwm, devicetree, linux-tegra, linux-kernel,
Laxman Dewangan
In-Reply-To: <1491401626-31303-1-git-send-email-ldewangan@nvidia.com>
The rate of the PWM calculated as follows:
hz = NSEC_PER_SEC / period_ns;
rate = (rate + (hz / 2)) / hz;
This has the precision loss in lower PWM rate.
Changing this to have more precision as:
hz = DIV_ROUND_CLOSE(NSEC_PER_SEC * 100, period_ns);
rate = DIV_ROUND_CLOSE(rate * 100, hz)
Example:
1. period_ns = 16672000, PWM clock rate is 200KHz.
Based on old formula
hz = NSEC_PER_SEC / period_ns
= 1000000000ul/16672000
= 59 (59.98)
rate = (200K + 59/2)/59 = 3390
Based on new method:
hz = 5998
rate = DIV_ROUND_CLOSE(200000*100, 5998) = 3334
If we measure the PWM signal rate, we will get more accurate period
with rate value of 3334 instead of 3390.
2. period_ns = 16803898, PWM clock rate is 200KHz.
Based on old formula:
hz = 60, rate = 3333
Based on new formula:
hz = 5951, rate = 3360
The rate of 3360 is more near to requested period then the 3333.
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
---
drivers/pwm/pwm-tegra.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c
index 0a688da..e9c4de5 100644
--- a/drivers/pwm/pwm-tegra.c
+++ b/drivers/pwm/pwm-tegra.c
@@ -76,6 +76,8 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip);
unsigned long long c = duty_ns;
unsigned long rate, hz;
+ unsigned long long ns100 = NSEC_PER_SEC;
+ unsigned long precision = 100; /* Consider 2 digit precision */
u32 val = 0;
int err;
@@ -94,9 +96,11 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
* cycles at the PWM clock rate will take period_ns nanoseconds.
*/
rate = clk_get_rate(pc->clk) >> PWM_DUTY_WIDTH;
- hz = NSEC_PER_SEC / period_ns;
- rate = (rate + (hz / 2)) / hz;
+ /* Consider precision in PWM_SCALE_WIDTH rate calculation */
+ ns100 *= precision;
+ hz = DIV_ROUND_CLOSEST_ULL(ns100, period_ns);
+ rate = DIV_ROUND_CLOSEST(rate * precision, hz);
/*
* Since the actual PWM divider is the register's frequency divider
--
2.1.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox