* [PATCH v3 01/13] arm/tegra: Prep boards for gpio/pinmux conversion to pdevs
[not found] ` <1314315824-9687-1-git-send-email-swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
@ 2011-08-25 23:43 ` Stephen Warren
2011-08-25 23:43 ` [PATCH v3 02/13] docs/dt: Document nvidia, tegra20-gpio's nvidia, enabled-gpios property Stephen Warren
` (9 subsequent siblings)
10 siblings, 0 replies; 24+ messages in thread
From: Stephen Warren @ 2011-08-25 23:43 UTC (permalink / raw)
To: Grant Likely, Colin Cross, Erik Gilling, Olof Johansson
Cc: Russell King, Sergei Shtylyov, Belisko Marek,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-tegra-u79uwXL29TY76Z2rM5mHXA, Linus Walleij,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
The Tegra GPIO driver will be converted from static registration via
postcore_initcall() to be a platform device later in this patch series.
A new Tegra pinmux platform device will also be added.
Prepare for this by modifying all boards to register the appropriate
platform devices before-hand, so that when the drivers are converted,
those devices will be probed, and git bisectability will be maintained.
Signed-off-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
arch/arm/mach-tegra/board-harmony-pinmux.c | 8 ++++++++
arch/arm/mach-tegra/board-paz00-pinmux.c | 8 ++++++++
arch/arm/mach-tegra/board-seaboard-pinmux.c | 9 +++++++--
arch/arm/mach-tegra/board-trimslice-pinmux.c | 7 +++++++
arch/arm/mach-tegra/devices.c | 10 ++++++++++
arch/arm/mach-tegra/devices.h | 2 ++
6 files changed, 42 insertions(+), 2 deletions(-)
diff --git a/arch/arm/mach-tegra/board-harmony-pinmux.c b/arch/arm/mach-tegra/board-harmony-pinmux.c
index 4d63e2e..e99b456 100644
--- a/arch/arm/mach-tegra/board-harmony-pinmux.c
+++ b/arch/arm/mach-tegra/board-harmony-pinmux.c
@@ -20,6 +20,7 @@
#include "gpio-names.h"
#include "board-harmony.h"
+#include "devices.h"
static struct tegra_pingroup_config harmony_pinmux[] = {
{TEGRA_PINGROUP_ATA, TEGRA_MUX_IDE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
@@ -140,6 +141,11 @@ static struct tegra_pingroup_config harmony_pinmux[] = {
{TEGRA_PINGROUP_XM2D, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
};
+static struct platform_device *pinmux_devices[] = {
+ &tegra_gpio_device,
+ &tegra_pinmux_device,
+};
+
static struct tegra_gpio_table gpio_table[] = {
{ .gpio = TEGRA_GPIO_SD2_CD, .enable = true },
{ .gpio = TEGRA_GPIO_SD2_WP, .enable = true },
@@ -155,6 +161,8 @@ static struct tegra_gpio_table gpio_table[] = {
void harmony_pinmux_init(void)
{
+ platform_add_devices(pinmux_devices, ARRAY_SIZE(pinmux_devices));
+
tegra_pinmux_config_table(harmony_pinmux, ARRAY_SIZE(harmony_pinmux));
tegra_gpio_config(gpio_table, ARRAY_SIZE(gpio_table));
diff --git a/arch/arm/mach-tegra/board-paz00-pinmux.c b/arch/arm/mach-tegra/board-paz00-pinmux.c
index bdd2627..43633f4 100644
--- a/arch/arm/mach-tegra/board-paz00-pinmux.c
+++ b/arch/arm/mach-tegra/board-paz00-pinmux.c
@@ -20,6 +20,7 @@
#include "gpio-names.h"
#include "board-paz00.h"
+#include "devices.h"
static struct tegra_pingroup_config paz00_pinmux[] = {
{TEGRA_PINGROUP_ATA, TEGRA_MUX_GMI, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
@@ -140,6 +141,11 @@ static struct tegra_pingroup_config paz00_pinmux[] = {
{TEGRA_PINGROUP_XM2D, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
};
+static struct platform_device *pinmux_devices[] = {
+ &tegra_gpio_device,
+ &tegra_pinmux_device,
+};
+
static struct tegra_gpio_table gpio_table[] = {
{ .gpio = TEGRA_GPIO_SD1_CD, .enable = true },
{ .gpio = TEGRA_GPIO_SD1_WP, .enable = true },
@@ -149,6 +155,8 @@ static struct tegra_gpio_table gpio_table[] = {
void paz00_pinmux_init(void)
{
+ platform_add_devices(pinmux_devices, ARRAY_SIZE(pinmux_devices));
+
tegra_pinmux_config_table(paz00_pinmux, ARRAY_SIZE(paz00_pinmux));
tegra_gpio_config(gpio_table, ARRAY_SIZE(gpio_table));
diff --git a/arch/arm/mach-tegra/board-seaboard-pinmux.c b/arch/arm/mach-tegra/board-seaboard-pinmux.c
index 74f78b7..f092298 100644
--- a/arch/arm/mach-tegra/board-seaboard-pinmux.c
+++ b/arch/arm/mach-tegra/board-seaboard-pinmux.c
@@ -21,6 +21,7 @@
#include "gpio-names.h"
#include "board-seaboard.h"
+#include "devices.h"
#define DEFAULT_DRIVE(_name) \
{ \
@@ -157,8 +158,10 @@ static __initdata struct tegra_pingroup_config seaboard_pinmux[] = {
{TEGRA_PINGROUP_XM2D, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
};
-
-
+static struct platform_device *pinmux_devices[] = {
+ &tegra_gpio_device,
+ &tegra_pinmux_device,
+};
static struct tegra_gpio_table gpio_table[] = {
{ .gpio = TEGRA_GPIO_SD2_CD, .enable = true },
@@ -173,6 +176,8 @@ static struct tegra_gpio_table gpio_table[] = {
void __init seaboard_pinmux_init(void)
{
+ platform_add_devices(pinmux_devices, ARRAY_SIZE(pinmux_devices));
+
tegra_pinmux_config_table(seaboard_pinmux, ARRAY_SIZE(seaboard_pinmux));
tegra_drive_pinmux_config_table(seaboard_drive_pinmux,
diff --git a/arch/arm/mach-tegra/board-trimslice-pinmux.c b/arch/arm/mach-tegra/board-trimslice-pinmux.c
index bcb1916..4969dd2 100644
--- a/arch/arm/mach-tegra/board-trimslice-pinmux.c
+++ b/arch/arm/mach-tegra/board-trimslice-pinmux.c
@@ -21,6 +21,7 @@
#include "gpio-names.h"
#include "board-trimslice.h"
+#include "devices.h"
static __initdata struct tegra_pingroup_config trimslice_pinmux[] = {
{TEGRA_PINGROUP_ATA, TEGRA_MUX_IDE, TEGRA_PUPD_NORMAL, TEGRA_TRI_TRISTATE},
@@ -141,6 +142,11 @@ static __initdata struct tegra_pingroup_config trimslice_pinmux[] = {
{TEGRA_PINGROUP_XM2D, TEGRA_MUX_NONE, TEGRA_PUPD_NORMAL, TEGRA_TRI_NORMAL},
};
+static struct platform_device *pinmux_devices[] = {
+ &tegra_gpio_device,
+ &tegra_pinmux_device,
+};
+
static struct tegra_gpio_table gpio_table[] = {
{ .gpio = TRIMSLICE_GPIO_SD4_CD, .enable = true }, /* mmc4 cd */
{ .gpio = TRIMSLICE_GPIO_SD4_WP, .enable = true }, /* mmc4 wp */
@@ -151,6 +157,7 @@ static struct tegra_gpio_table gpio_table[] = {
void __init trimslice_pinmux_init(void)
{
+ platform_add_devices(pinmux_devices, ARRAY_SIZE(pinmux_devices));
tegra_pinmux_config_table(trimslice_pinmux, ARRAY_SIZE(trimslice_pinmux));
tegra_gpio_config(gpio_table, ARRAY_SIZE(gpio_table));
}
diff --git a/arch/arm/mach-tegra/devices.c b/arch/arm/mach-tegra/devices.c
index 57e35d2..48262bf 100644
--- a/arch/arm/mach-tegra/devices.c
+++ b/arch/arm/mach-tegra/devices.c
@@ -31,6 +31,16 @@
#include <mach/usb_phy.h>
#include "gpio-names.h"
+struct platform_device tegra_gpio_device = {
+ .name = "tegra-gpio",
+ .id = -1,
+};
+
+struct platform_device tegra_pinmux_device = {
+ .name = "tegra-pinmux",
+ .id = -1,
+};
+
static struct resource i2c_resource1[] = {
[0] = {
.start = INT_I2C,
diff --git a/arch/arm/mach-tegra/devices.h b/arch/arm/mach-tegra/devices.h
index 4a7dc0a..873ecb2 100644
--- a/arch/arm/mach-tegra/devices.h
+++ b/arch/arm/mach-tegra/devices.h
@@ -21,6 +21,8 @@
#include <linux/platform_device.h>
+extern struct platform_device tegra_gpio_device;
+extern struct platform_device tegra_pinmux_device;
extern struct platform_device tegra_sdhci_device1;
extern struct platform_device tegra_sdhci_device2;
extern struct platform_device tegra_sdhci_device3;
--
1.7.0.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH v3 02/13] docs/dt: Document nvidia, tegra20-gpio's nvidia, enabled-gpios property
[not found] ` <1314315824-9687-1-git-send-email-swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2011-08-25 23:43 ` [PATCH v3 01/13] arm/tegra: Prep boards for gpio/pinmux conversion to pdevs Stephen Warren
@ 2011-08-25 23:43 ` Stephen Warren
2011-08-25 23:43 ` [PATCH v3 03/13] arm/dt: Tegra: Add nvidia, enabled-gpios property to GPIO controller Stephen Warren
` (8 subsequent siblings)
10 siblings, 0 replies; 24+ messages in thread
From: Stephen Warren @ 2011-08-25 23:43 UTC (permalink / raw)
To: Grant Likely, Colin Cross, Erik Gilling, Olof Johansson
Cc: Russell King, Sergei Shtylyov, Belisko Marek,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-tegra-u79uwXL29TY76Z2rM5mHXA, Linus Walleij,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Signed-off-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
.../devicetree/bindings/gpio/gpio_nvidia.txt | 20 ++++++++++++++++++++
1 files changed, 20 insertions(+), 0 deletions(-)
diff --git a/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt b/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt
index eb4b530..b22fff3 100644
--- a/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio_nvidia.txt
@@ -6,3 +6,23 @@ Required properties:
second cell is used to specify optional parameters:
- bit 0 specifies polarity (0 for normal, 1 for inverted)
- gpio-controller : Marks the device node as a GPIO controller.
+
+Optional properties:
+- nvidia,enabled-gpios : The list of GPIOs that should be controlled by the
+ GPIO controller rather than the pinmux controller.
+
+Example of a gpio-controller node:
+
+ gpio: gpio@6000d000 {
+ compatible = "nvidia,tegra20-gpio";
+ reg = < 0x6000d000 0x1000 >;
+ interrupts = < 64 65 66 67 87 119 121 >;
+ #gpio-cells = <2>;
+ gpio-controller;
+ nvidia,enabled-gpios = <
+ 69 // TEGRA_GPIO_PI5 SD2_CD
+ 57 // TEGRA_GPIO_PH1 SD2_WP
+ 155 // TEGRA_GPIO_PT3 SD2_POWER
+ >;
+ };
+
--
1.7.0.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH v3 03/13] arm/dt: Tegra: Add nvidia, enabled-gpios property to GPIO controller
[not found] ` <1314315824-9687-1-git-send-email-swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2011-08-25 23:43 ` [PATCH v3 01/13] arm/tegra: Prep boards for gpio/pinmux conversion to pdevs Stephen Warren
2011-08-25 23:43 ` [PATCH v3 02/13] docs/dt: Document nvidia, tegra20-gpio's nvidia, enabled-gpios property Stephen Warren
@ 2011-08-25 23:43 ` Stephen Warren
2011-08-25 23:43 ` [PATCH v3 05/13] arm/dt: Tegra: Add pinmux node Stephen Warren
` (7 subsequent siblings)
10 siblings, 0 replies; 24+ messages in thread
From: Stephen Warren @ 2011-08-25 23:43 UTC (permalink / raw)
To: Grant Likely, Colin Cross, Erik Gilling, Olof Johansson
Cc: Russell King, Sergei Shtylyov, Belisko Marek,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-tegra-u79uwXL29TY76Z2rM5mHXA, Linus Walleij,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Add board-specific gpio node for Harmony and Seaboard. This lists the
GPIOs used by the board. Note that not all GPIOs that exist on the board
are listed; only those used by devices currently supported by device
tree.
Signed-off-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
arch/arm/boot/dts/tegra-harmony.dts | 15 +++++++++++++++
arch/arm/boot/dts/tegra-seaboard.dts | 8 ++++++++
2 files changed, 23 insertions(+), 0 deletions(-)
diff --git a/arch/arm/boot/dts/tegra-harmony.dts b/arch/arm/boot/dts/tegra-harmony.dts
index e581866..2bbe559 100644
--- a/arch/arm/boot/dts/tegra-harmony.dts
+++ b/arch/arm/boot/dts/tegra-harmony.dts
@@ -15,6 +15,21 @@
reg = < 0x00000000 0x40000000 >;
};
+ gpio: gpio@6000d000 {
+ nvidia,enabled-gpios = <
+ 69 // TEGRA_GPIO_PI5 SD2_CD
+ 57 // TEGRA_GPIO_PH1 SD2_WP
+ 155 // TEGRA_GPIO_PT3 SD2_POWER
+ 58 // TEGRA_GPIO_PH2 SD4_CD
+ 59 // TEGRA_GPIO_PH3 SD4_WP
+ 70 // TEGRA_GPIO_PI6 SD4_POWER
+ 187 // TEGRA_GPIO_PX3 CDC_IRQ
+ 178 // TEGRA_GPIO_PW2 HP_DET
+ 184 // TEGRA_GPIO_PX0 INT_MIC_EN
+ 185 // TEGRA_GPIO_PX1 EXT_MIC_EN
+ >;
+ };
+
i2c@7000c000 {
clock-frequency = <400000>;
diff --git a/arch/arm/boot/dts/tegra-seaboard.dts b/arch/arm/boot/dts/tegra-seaboard.dts
index 64cedca..ec8f8cf 100644
--- a/arch/arm/boot/dts/tegra-seaboard.dts
+++ b/arch/arm/boot/dts/tegra-seaboard.dts
@@ -16,6 +16,14 @@
reg = < 0x00000000 0x40000000 >;
};
+ gpio: gpio@6000d000 {
+ nvidia,enabled-gpios = <
+ 69 // TEGRA_GPIO_PI5 SD2_CD
+ 57 // TEGRA_GPIO_PH1 SD2_WP
+ 70 // TEGRA_GPIO_PI6 SD2_POWER
+ >;
+ };
+
serial@70006300 {
clock-frequency = < 216000000 >;
};
--
1.7.0.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH v3 05/13] arm/dt: Tegra: Add pinmux node
[not found] ` <1314315824-9687-1-git-send-email-swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (2 preceding siblings ...)
2011-08-25 23:43 ` [PATCH v3 03/13] arm/dt: Tegra: Add nvidia, enabled-gpios property to GPIO controller Stephen Warren
@ 2011-08-25 23:43 ` Stephen Warren
2011-08-25 23:43 ` [PATCH v3 07/13] gpio/tegra: Convert to a platform device Stephen Warren
` (6 subsequent siblings)
10 siblings, 0 replies; 24+ messages in thread
From: Stephen Warren @ 2011-08-25 23:43 UTC (permalink / raw)
To: Grant Likely, Colin Cross, Erik Gilling, Olof Johansson
Cc: Russell King, Sergei Shtylyov, Belisko Marek,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-tegra-u79uwXL29TY76Z2rM5mHXA, Linus Walleij,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Add a pinmux node to tegra20.dtsi in order to instantiate the future
pinmux device. Add pinmux nodes to Harmony and Seaboard, which detail
the entire initial pinmux configuration. This configuration is identical
to that in board-harmony/seaboard-pinmux.c.
Signed-off-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
arch/arm/boot/dts/tegra-harmony.dts | 243 ++++++++++++++++++++++++++++++++++
arch/arm/boot/dts/tegra-seaboard.dts | 239 +++++++++++++++++++++++++++++++++
arch/arm/boot/dts/tegra20.dtsi | 5 +
3 files changed, 487 insertions(+), 0 deletions(-)
diff --git a/arch/arm/boot/dts/tegra-harmony.dts b/arch/arm/boot/dts/tegra-harmony.dts
index 2bbe559..a2b8dec 100644
--- a/arch/arm/boot/dts/tegra-harmony.dts
+++ b/arch/arm/boot/dts/tegra-harmony.dts
@@ -30,6 +30,249 @@
>;
};
+ pinmux: pinmux@70000000 {
+ nvidia,mux-groups {
+ ata {
+ pins = "ata";
+ function = "ide";
+ };
+ atb {
+ pins = "atb", "gma", "gme";
+ function = "sdio4";
+ };
+ atc {
+ pins = "atc";
+ function = "nand";
+ };
+ atd {
+ pins = "atd", "ate", "gmb", "gmd", "spia", "spib";
+ function = "gmi";
+ };
+ cdev1 {
+ pins = "cdev1";
+ function = "plla_out";
+ };
+ cdev2 {
+ pins = "cdev2";
+ function = "pllp_out4";
+ pull-down;
+ tristate;
+ };
+ ck32 {
+ pins = "ck32", "ddrc", "pmca", "pmcb", "pmcc", "pmcd", "pmce", "xm2c", "xm2d";
+ function = "none";
+ };
+ crtp {
+ pins = "crtp";
+ function = "crt";
+ tristate;
+ };
+ csus {
+ pins = "csus";
+ function = "vi_sensor_clk";
+ pull-down;
+ tristate;
+ };
+ dap1 {
+ pins = "dap1";
+ function = "dap1";
+ };
+ dap2 {
+ pins = "dap2";
+ function = "dap2";
+ tristate;
+ };
+ dap3 {
+ pins = "dap3";
+ function = "dap3";
+ tristate;
+ };
+ dap4 {
+ pins = "dap4";
+ function = "dap4";
+ tristate;
+ };
+ ddc {
+ pins = "ddc";
+ function = "i2c2";
+ pull-up;
+ };
+ dta {
+ pins = "dta", "dtd";
+ function = "sdio2";
+ pull-up;
+ };
+ dtb {
+ pins = "dtb";
+ function = "rsvd1";
+ };
+ dtc {
+ pins = "dtc", "dte";
+ function = "rsvd1";
+ tristate;
+ };
+ dtf {
+ pins = "dtf";
+ function = "i2c3";
+ tristate;
+ };
+ gmc {
+ pins = "gmc";
+ function = "uartd";
+ };
+ gpu {
+ pins = "gpu";
+ function = "gmi";
+ tristate;
+ };
+ gpu7 {
+ pins = "gpu7";
+ function = "rtck";
+ };
+ gpv {
+ pins = "gpv", "slxa", "slxk";
+ function = "pcie";
+ tristate;
+ };
+ hdint {
+ pins = "hdint";
+ function = "hdmi";
+ pull-up;
+ tristate;
+ };
+ i2cp {
+ pins = "i2cp", "rm";
+ function = "i2c";
+ };
+ irrx {
+ pins = "irrx", "irtx";
+ function = "uarta";
+ pull-up;
+ tristate;
+ };
+ kbca {
+ pins = "kbca", "kbcb", "kbcc", "kbcd", "kbce", "kbcf";
+ function = "kbc";
+ pull-up;
+ };
+ lcsn {
+ pins = "lcsn", "ldc", "lm1", "lpw1", "lsc1", "lsck", "lsda", "lsdi", "lvp0";
+ function = "displaya";
+ pull-up;
+ tristate;
+ };
+ ld0 {
+ pins = "ld0", "ld1", "ld10", "ld11", "ld12", "ld13", "ld14", "ld15", "ld16", "ld17", "ld2", "ld3", "ld4", "ld5", "ld6", "ld7", "ld8", "ld9", "ldi", "lhp0", "lhp1", "lhp2", "lpp", "lvp1";
+ function = "displaya";
+ pull-down;
+ };
+ lhs {
+ pins = "lhs", "lm0", "lpw0", "lpw2", "lsc0", "lspi", "lvs";
+ function = "displaya";
+ pull-up;
+ };
+ owc {
+ pins = "owc";
+ function = "rsvd2";
+ pull-up;
+ tristate;
+ };
+ pmc {
+ pins = "pmc";
+ function = "pwr_on";
+ };
+ pta {
+ pins = "pta";
+ function = "hdmi";
+ };
+ sdb {
+ pins = "sdb";
+ function = "pwm";
+ tristate;
+ };
+ sdc {
+ pins = "sdc";
+ function = "pwm";
+ pull-up;
+ };
+ sdd {
+ pins = "sdd";
+ function = "pwm";
+ pull-up;
+ tristate;
+ };
+ sdio1 {
+ pins = "sdio1";
+ function = "sdio1";
+ tristate;
+ };
+ slxc {
+ pins = "slxc", "slxd";
+ function = "spdif";
+ tristate;
+ };
+ spdi {
+ pins = "spdi", "spdo", "uac";
+ function = "rsvd2";
+ tristate;
+ };
+ spic {
+ pins = "spic";
+ function = "gmi";
+ pull-up;
+ tristate;
+ };
+ spid {
+ pins = "spid", "spif";
+ function = "spi1";
+ pull-down;
+ tristate;
+ };
+ spie {
+ pins = "spie";
+ function = "spi1";
+ pull-up;
+ tristate;
+ };
+ spig {
+ pins = "spig";
+ function = "spi2_alt";
+ tristate;
+ };
+ spih {
+ pins = "spih";
+ function = "spi2_alt";
+ pull-up;
+ tristate;
+ };
+ uaa {
+ pins = "uaa", "uab";
+ function = "ulpi";
+ pull-up;
+ tristate;
+ };
+ uad {
+ pins = "uad";
+ function = "irda";
+ pull-up;
+ tristate;
+ };
+ uca {
+ pins = "uca", "ucb";
+ function = "uartc";
+ pull-up;
+ tristate;
+ };
+ uda {
+ pins = "uda";
+ function = "ulpi";
+ tristate;
+ };
+ };
+ nvidia,drive-groups {
+ };
+ };
+
i2c@7000c000 {
clock-frequency = <400000>;
diff --git a/arch/arm/boot/dts/tegra-seaboard.dts b/arch/arm/boot/dts/tegra-seaboard.dts
index ec8f8cf..b0677b2 100644
--- a/arch/arm/boot/dts/tegra-seaboard.dts
+++ b/arch/arm/boot/dts/tegra-seaboard.dts
@@ -24,6 +24,245 @@
>;
};
+ pinmux: pinmux@70000000 {
+ nvidia,mux-groups {
+ ata {
+ pins = "ata";
+ function = "ide";
+ };
+ atb {
+ pins = "atb", "gma", "gme";
+ function = "sdio4";
+ };
+ atc {
+ pins = "atc";
+ function = "nand";
+ };
+ atd {
+ pins = "atd";
+ function = "gmi";
+ };
+ ate {
+ pins = "ate", "spib";
+ function = "gmi";
+ tristate;
+ };
+ cdev1 {
+ pins = "cdev1";
+ function = "plla_out";
+ };
+ cdev2 {
+ pins = "cdev2";
+ function = "pllp_out4";
+ };
+ ck32 {
+ pins = "ck32", "ddrc", "pmca", "pmcb", "pmcc", "pmcd", "pmce", "xm2c", "xm2d";
+ function = "none";
+ };
+ crtp {
+ pins = "crtp";
+ function = "crt";
+ pull-up;
+ tristate;
+ };
+ csus {
+ pins = "csus";
+ function = "vi_sensor_clk";
+ tristate;
+ };
+ dap1 {
+ pins = "dap1";
+ function = "dap1";
+ };
+ dap2 {
+ pins = "dap2";
+ function = "dap2";
+ };
+ dap3 {
+ pins = "dap3";
+ function = "dap3";
+ tristate;
+ };
+ dap4 {
+ pins = "dap4";
+ function = "dap4";
+ };
+ ddc {
+ pins = "ddc", "owc";
+ function = "rsvd2";
+ tristate;
+ };
+ dta {
+ pins = "dta", "dtb", "dtc", "dtd";
+ function = "vi";
+ pull-down;
+ };
+ dte {
+ pins = "dte";
+ function = "vi";
+ pull-down;
+ tristate;
+ };
+ dtf {
+ pins = "dtf";
+ function = "i2c3";
+ };
+ gmb {
+ pins = "gmb", "spia";
+ function = "gmi";
+ pull-up;
+ tristate;
+ };
+ gmc {
+ pins = "gmc";
+ function = "uartd";
+ };
+ gmd {
+ pins = "gmd";
+ function = "sflash";
+ };
+ gpu {
+ pins = "gpu";
+ function = "pwm";
+ };
+ gpu7 {
+ pins = "gpu7";
+ function = "rtck";
+ };
+ gpv {
+ pins = "gpv";
+ function = "pcie";
+ tristate;
+ };
+ hdint {
+ pins = "hdint", "lsc1", "lsck", "lsda";
+ function = "hdmi";
+ tristate;
+ };
+ i2cp {
+ pins = "i2cp", "rm";
+ function = "i2c";
+ };
+ irrx {
+ pins = "irrx", "irtx";
+ function = "uartb";
+ };
+ kbca {
+ pins = "kbca", "kbcb", "kbcc", "kbcd", "kbce", "kbcf";
+ function = "kbc";
+ pull-up;
+ };
+ lcsn {
+ pins = "lcsn", "ldc", "lpw1", "lsdi", "lvp0";
+ function = "rsvd4";
+ tristate;
+ };
+ ld0 {
+ pins = "ld0", "ld1", "ld10", "ld11", "ld12", "ld13", "ld14", "ld15", "ld16", "ld17", "ld2", "ld3", "ld4", "ld5", "ld6", "ld7", "ld8", "ld9", "ldi", "lhp0", "lhp1", "lhp2", "lhs", "lpp", "lsc0", "lspi", "lvp1", "lvs";
+ function = "displaya";
+ };
+ lm0 {
+ pins = "lm0";
+ function = "rsvd4";
+ };
+ lm1 {
+ pins = "lm1";
+ function = "crt";
+ tristate;
+ };
+ lpw0 {
+ pins = "lpw0", "lpw2", "pta";
+ function = "hdmi";
+ };
+ pmc {
+ pins = "pmc";
+ function = "pwr_on";
+ };
+ sdb {
+ pins = "sdb", "sdc", "sdd";
+ function = "sdio3";
+ };
+ sdio1 {
+ pins = "sdio1";
+ function = "sdio1";
+ pull-up;
+ };
+ slxa {
+ pins = "slxa";
+ function = "pcie";
+ pull-up;
+ tristate;
+ };
+ slxc {
+ pins = "slxc";
+ function = "spdif";
+ tristate;
+ };
+ slxd {
+ pins = "slxd";
+ function = "spdif";
+ };
+ slxk {
+ pins = "slxk";
+ function = "pcie";
+ };
+ spdi {
+ pins = "spdi", "spdo", "uac";
+ function = "rsvd2";
+ };
+ spic {
+ pins = "spic";
+ function = "gmi";
+ pull-up;
+ };
+ spid {
+ pins = "spid", "spie";
+ function = "spi1";
+ tristate;
+ };
+ spif {
+ pins = "spif";
+ function = "spi1";
+ pull-down;
+ tristate;
+ };
+ spig {
+ pins = "spig", "spih";
+ function = "spi2_alt";
+ pull-up;
+ tristate;
+ };
+ uaa {
+ pins = "uaa", "uab";
+ function = "ulpi";
+ pull-up;
+ };
+ uad {
+ pins = "uad";
+ function = "irda";
+ };
+ uca {
+ pins = "uca", "ucb";
+ function = "uartc";
+ };
+ uda {
+ pins = "uda";
+ function = "ulpi";
+ };
+ };
+ nvidia,drive-groups {
+ sdio1 {
+ pins = "sdio1";
+ nvidia,schmitt;
+ nvidia,drive-power = <3>;
+ nvidia,pull-down-strength = <31>;
+ nvidia,pull-up-strength = <31>;
+ nvidia,slew-rate-rising = <3>;
+ nvidia,slew-rate-falling = <3>;
+ };
+ };
+ };
+
serial@70006300 {
clock-frequency = < 216000000 >;
};
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index 5727595..5921c1d 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -77,6 +77,11 @@
gpio-controller;
};
+ pinmux: pinmux@70000000 {
+ compatible = "nvidia,tegra20-pinmux";
+ reg = < 0x70000000 0xc00 >;
+ };
+
serial@70006000 {
compatible = "nvidia,tegra20-uart";
reg = <0x70006000 0x40>;
--
1.7.0.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH v3 07/13] gpio/tegra: Convert to a platform device
[not found] ` <1314315824-9687-1-git-send-email-swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (3 preceding siblings ...)
2011-08-25 23:43 ` [PATCH v3 05/13] arm/dt: Tegra: Add pinmux node Stephen Warren
@ 2011-08-25 23:43 ` Stephen Warren
2011-08-25 23:43 ` [PATCH v3 09/13] arm/tegra: Convert pinmux driver " Stephen Warren
` (5 subsequent siblings)
10 siblings, 0 replies; 24+ messages in thread
From: Stephen Warren @ 2011-08-25 23:43 UTC (permalink / raw)
To: Grant Likely, Colin Cross, Erik Gilling, Olof Johansson
Cc: Russell King, Sergei Shtylyov, Belisko Marek,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-tegra-u79uwXL29TY76Z2rM5mHXA, Linus Walleij,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Signed-off-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/gpio/gpio-tegra.c | 25 ++++++++++++++-----------
1 files changed, 14 insertions(+), 11 deletions(-)
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index df64536..4da4839 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -20,10 +20,10 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
-
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/of.h>
+#include <linux/platform_device.h>
#include <asm/mach/irq.h>
@@ -332,7 +332,7 @@ static struct irq_chip tegra_gpio_irq_chip = {
*/
static struct lock_class_key gpio_lock_class;
-static int __init tegra_gpio_init(void)
+static int __init tegra_gpio_probe(struct platform_device *pdev)
{
struct tegra_gpio_bank *bank;
int gpio;
@@ -346,15 +346,6 @@ static int __init tegra_gpio_init(void)
}
}
-#ifdef CONFIG_OF_GPIO
- /*
- * This isn't ideal, but it gets things hooked up until this
- * driver is converted into a platform_device
- */
- tegra_gpio_chip.of_node = of_find_compatible_node(NULL, NULL,
- "nvidia,tegra20-gpio");
-#endif /* CONFIG_OF_GPIO */
-
gpiochip_add(&tegra_gpio_chip);
for (gpio = 0; gpio < TEGRA_NR_GPIOS; gpio++) {
@@ -383,6 +374,18 @@ static int __init tegra_gpio_init(void)
return 0;
}
+static struct platform_driver tegra_gpio_driver = {
+ .driver = {
+ .name = "tegra-gpio",
+ .owner = THIS_MODULE,
+ },
+ .probe = tegra_gpio_probe,
+};
+
+static int __init tegra_gpio_init(void)
+{
+ return platform_driver_register(&tegra_gpio_driver);
+}
postcore_initcall(tegra_gpio_init);
void __init tegra_gpio_config(struct tegra_gpio_table *table, int num)
--
1.7.0.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH v3 09/13] arm/tegra: Convert pinmux driver to a platform device
[not found] ` <1314315824-9687-1-git-send-email-swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (4 preceding siblings ...)
2011-08-25 23:43 ` [PATCH v3 07/13] gpio/tegra: Convert to a platform device Stephen Warren
@ 2011-08-25 23:43 ` Stephen Warren
2011-08-25 23:43 ` [PATCH v3 10/13] of: add a generic pinmux helper Stephen Warren
` (4 subsequent siblings)
10 siblings, 0 replies; 24+ messages in thread
From: Stephen Warren @ 2011-08-25 23:43 UTC (permalink / raw)
To: Grant Likely, Colin Cross, Erik Gilling, Olof Johansson
Cc: Russell King, Sergei Shtylyov, Belisko Marek,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-tegra-u79uwXL29TY76Z2rM5mHXA, Linus Walleij,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Signed-off-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
arch/arm/mach-tegra/pinmux.c | 20 ++++++++++++++++++++
1 files changed, 20 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-tegra/pinmux.c b/arch/arm/mach-tegra/pinmux.c
index f80d507..ed316f9 100644
--- a/arch/arm/mach-tegra/pinmux.c
+++ b/arch/arm/mach-tegra/pinmux.c
@@ -20,6 +20,7 @@
#include <linux/errno.h>
#include <linux/spinlock.h>
#include <linux/io.h>
+#include <linux/platform_device.h>
#include <mach/iomap.h>
#include <mach/pinmux.h>
@@ -665,6 +666,25 @@ void tegra_pinmux_config_pullupdown_table(const struct tegra_pingroup_config *co
}
}
+static int __init tegra_pinmux_probe(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver tegra_pinmux_driver = {
+ .driver = {
+ .name = "tegra-pinmux",
+ .owner = THIS_MODULE,
+ },
+ .probe = tegra_pinmux_probe,
+};
+
+static int __init tegra_pinmux_init(void)
+{
+ return platform_driver_register(&tegra_pinmux_driver);
+}
+postcore_initcall(tegra_pinmux_init);
+
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
--
1.7.0.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH v3 10/13] of: add a generic pinmux helper
[not found] ` <1314315824-9687-1-git-send-email-swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (5 preceding siblings ...)
2011-08-25 23:43 ` [PATCH v3 09/13] arm/tegra: Convert pinmux driver " Stephen Warren
@ 2011-08-25 23:43 ` Stephen Warren
[not found] ` <1314315824-9687-11-git-send-email-swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2011-08-25 23:43 ` [PATCH v3 11/13] of: add property iteration helpers Stephen Warren
` (3 subsequent siblings)
10 siblings, 1 reply; 24+ messages in thread
From: Stephen Warren @ 2011-08-25 23:43 UTC (permalink / raw)
To: Grant Likely, Colin Cross, Erik Gilling, Olof Johansson
Cc: Russell King, Sergei Shtylyov, Belisko Marek,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-tegra-u79uwXL29TY76Z2rM5mHXA, Linus Walleij,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
From: Jamie Iles <jamie-wmLquQDDieKakBO8gow8eQ@public.gmane.org>
This patch adds a helper function of_pinmux_parse() that can be used to
extract common pinmux configuration to avoid each platform implementing
a parsing loop. Platforms supply the node containing the pinmux
definitions and a platform specific callback for configuring a pingroup.
Signed-off-by: Jamie Iles <jamie-wmLquQDDieKakBO8gow8eQ@public.gmane.org>
[swarren: Added support for pins property, added parse() callback, use
dev_err instead of pr_err, related minor changes]
Signed-off-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
drivers/of/Kconfig | 5 ++
drivers/of/Makefile | 1 +
drivers/of/of_pinmux.c | 109 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/of_pinmux.h | 74 ++++++++++++++++++++++++++++++
4 files changed, 189 insertions(+), 0 deletions(-)
create mode 100644 drivers/of/of_pinmux.c
create mode 100644 include/linux/of_pinmux.h
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index cac63c9..71a19a3 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -81,4 +81,9 @@ config OF_PCI_IRQ
help
OpenFirmware PCI IRQ routing helpers
+config OF_PINMUX
+ def_bool y
+ help
+ OpenFirmware pin multiplexing helpers
+
endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index dccb117..0666ff3 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_OF_SPI) += of_spi.o
obj-$(CONFIG_OF_MDIO) += of_mdio.o
obj-$(CONFIG_OF_PCI) += of_pci.o
obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
+obj-$(CONFIG_OF_PINMUX) += of_pinmux.o
diff --git a/drivers/of/of_pinmux.c b/drivers/of/of_pinmux.c
new file mode 100644
index 0000000..8050b8b
--- /dev/null
+++ b/drivers/of/of_pinmux.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2011 Picochip Ltd., Jamie Iles
+ * Copyright (c) 2011 NVIDIA, Inc.
+ *
+ * Generic pinmux bindings for device tree.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_iter_prop.h>
+#include <linux/of_pinmux.h>
+
+/**
+ * of_pinmux_parse - configure a set of pinmux groups for a pinmux controller
+ *
+ * @controller: the controller to configure the pinmux entries for. This
+ * defines the controller device node and the callback for configuring
+ * the pingroups.
+ *
+ * This helper loops over all of the child nodes of a pinmux controller and
+ * collects the configuration for each pinmux group. A pinmux group is
+ * defined as one or more pins that are configured to a common function. This
+ * handles common properties that many platforms may implement, but for
+ * platform specific properties these may be handled in the configure
+ * callback.
+ */
+int of_pinmux_parse(const struct of_pinmux_ctrl *ctrl,
+ struct of_pinmux_cfg *cfg)
+{
+ struct device_node *np;
+
+ if (!ctrl || !ctrl->dev || !ctrl->node || !ctrl->configure)
+ return -EINVAL;
+
+ for_each_child_of_node(ctrl->node, np) {
+ int ret;
+ bool hadpins = 0;
+ struct of_iter_string_prop iter;
+
+ cfg->node = np;
+
+ ret = of_property_read_string(np, "function",
+ &cfg->function);
+ if (ret < 0) {
+ dev_err(ctrl->dev, "no function for node %s\n",
+ np->name);
+ continue;
+ }
+
+ cfg->flags &= 0;
+
+ if (of_find_property(np, "pull-up", NULL))
+ cfg->flags |= OF_PINMUX_PULL_UP;
+ if (of_find_property(np, "pull-down", NULL))
+ cfg->flags |= OF_PINMUX_PULL_DOWN;
+
+ if ((cfg->flags & OF_PINMUX_PULL_MASK) ==
+ OF_PINMUX_PULL_MASK) {
+ dev_warn(ctrl->dev, "node %s has both "
+ "pull-up and pull-down properties - "
+ "defaulting to no pull\n",
+ np->name);
+ cfg->flags &= ~OF_PINMUX_PULL_MASK;
+ }
+
+ if (of_find_property(np, "tristate", NULL))
+ cfg->flags |= OF_PINMUX_TRISTATE;
+
+ if (ctrl->parse && ctrl->parse(ctrl, cfg)) {
+ dev_warn(ctrl->dev,
+ "failed to parse node %s\n",
+ np->name);
+ continue;
+ }
+
+ for_each_string_property_value(iter, np, "pins") {
+ hadpins = 1;
+
+ cfg->pin = iter.value;
+
+ dev_dbg(ctrl->dev,
+ "configure pin %s func=%s flags=0x%lx\n",
+ cfg->pin, cfg->function, cfg->flags);
+ if (ctrl->configure(ctrl, cfg))
+ dev_warn(ctrl->dev,
+ "failed to configure pin %s\n",
+ cfg->pin);
+ }
+
+ if (!hadpins)
+ dev_warn(ctrl->dev, "no pins for node %s\n",
+ np->name);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_pinmux_parse);
diff --git a/include/linux/of_pinmux.h b/include/linux/of_pinmux.h
new file mode 100644
index 0000000..7ccddcf
--- /dev/null
+++ b/include/linux/of_pinmux.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2011 Picochip Ltd., Jamie Iles
+ * Copyright (c) 2011 NVIDIA, Inc.
+ *
+ * Generic pinmux bindings for device tree.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __OF_PINMUX_H__
+#define __OF_PINMUX_H__
+
+struct device_node;
+
+#define OF_PINMUX_PULL_UP (1 << 0)
+#define OF_PINMUX_PULL_DOWN (1 << 1)
+#define OF_PINMUX_TRISTATE (1 << 2)
+
+#define OF_PINMUX_PULL_MASK (OF_PINMUX_PULL_UP | OF_PINMUX_PULL_DOWN)
+
+/**
+ * struct of_pinmux_cfg - configuration state for a single pinmux entry.
+ *
+ * @function: the name of the function that the pinmux entry should be
+ * configured to.
+ * @pin: the device_node of the pinmux entry that should be configured.
+ * Platform specific properties that aren't in the generic binding may be
+ * obtained from this device node.
+ * @flags: flags for common pinmux options such as pull and tristate.
+ */
+struct of_pinmux_cfg {
+ struct device_node *node;
+ const char *pin;
+ const char *function;
+ unsigned long flags;
+};
+
+/**
+ * struct of_pinmux_ctrl - platform specific pinmux control state.
+ *
+ * @pinmux: the pinmux device node. All child nodes are required to be the
+ * pinmux entry definitions. Depending on the platform, this may either be
+ * a single pin or a group of pins where they can be set to a common
+ * function.
+ * @configure: platform specific callback to configure the pinmux entry.
+ */
+struct of_pinmux_ctrl {
+ struct device *dev;
+ struct device_node *node;
+ int (*parse)(const struct of_pinmux_ctrl *ctrl,
+ struct of_pinmux_cfg *cfg);
+ int (*configure)(const struct of_pinmux_ctrl *ctrl,
+ const struct of_pinmux_cfg *cfg);
+};
+
+#ifdef CONFIG_OF
+extern int of_pinmux_parse(const struct of_pinmux_ctrl *ctrl,
+ struct of_pinmux_cfg *cfg);
+#else
+static inline int of_pinmux_parse(const struct of_pinmux_ctrl *ctrl,
+ struct of_pinmux_cfg *cfg)
+{
+ return -ENOSYS;
+}
+#endif /* CONFIG_OF */
+
+#endif /* __OF_PINMUX_H__ */
--
1.7.0.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH v3 11/13] of: add property iteration helpers
[not found] ` <1314315824-9687-1-git-send-email-swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (6 preceding siblings ...)
2011-08-25 23:43 ` [PATCH v3 10/13] of: add a generic pinmux helper Stephen Warren
@ 2011-08-25 23:43 ` Stephen Warren
[not found] ` <1314315824-9687-12-git-send-email-swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
2011-08-25 23:43 ` [PATCH v3 12/13] arm/tegra: Add device tree support to pinmux driver Stephen Warren
` (2 subsequent siblings)
10 siblings, 1 reply; 24+ messages in thread
From: Stephen Warren @ 2011-08-25 23:43 UTC (permalink / raw)
To: Grant Likely, Colin Cross, Erik Gilling, Olof Johansson
Cc: Russell King, Sergei Shtylyov, Belisko Marek,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-tegra-u79uwXL29TY76Z2rM5mHXA, Linus Walleij,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
This patch adds macros for_each_u32_property_value and
for_each_string_property_value, which iterate over an array of values
within a device-tree property. Usage is for example:
struct of_iter_string_prop iter;
for_each_string_property_value(iter, np, "pins")
printk("Got value %s\n", iter.value);
Signed-off-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
include/linux/of_iter_prop.h | 135 ++++++++++++++++++++++++++++++++++++++++++
1 files changed, 135 insertions(+), 0 deletions(-)
create mode 100644 include/linux/of_iter_prop.h
diff --git a/include/linux/of_iter_prop.h b/include/linux/of_iter_prop.h
new file mode 100644
index 0000000..c7fb2bf
--- /dev/null
+++ b/include/linux/of_iter_prop.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2011 NVIDIA Inc.
+ *
+ * Iterate over properties that store arrays.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __OF_ITER_PROP_H__
+#define __OF_ITER_PROP_H__
+
+#include <linux/of.h>
+
+#ifdef CONFIG_OF
+struct of_iter_u32_prop {
+ const struct property *prop;
+ int len;
+ const __be32 *pvalue;
+ u32 value;
+};
+
+static inline void of_iter_u32_next(struct of_iter_u32_prop *iter)
+{
+ if (iter->len < 0)
+ return;
+
+ iter->value = be32_to_cpup(iter->pvalue++);
+ iter->len--;
+}
+
+static inline void of_iter_u32_init(struct of_iter_u32_prop *iter,
+ const struct device_node *np,
+ const char *name)
+{
+ iter->prop = of_find_property(np, name, &iter->len);
+ if (!iter->prop) {
+ iter->len = -1;
+ return;
+ }
+
+ iter->pvalue = iter->prop->value;
+ if (!iter->pvalue) {
+ iter->len = -1;
+ return;
+ }
+
+ iter->len /= sizeof(*iter->pvalue);
+
+ of_iter_u32_next(iter);
+}
+
+static inline bool of_iter_u32_test(struct of_iter_u32_prop *iter)
+{
+ return iter->len >= 0;
+}
+
+#define for_each_u32_property_value(iter, np, prop_name) \
+ for (of_iter_u32_init(&iter, np, prop_name); \
+ of_iter_u32_test(&iter); \
+ of_iter_u32_next(&iter))
+
+struct of_iter_string_prop {
+ const struct property *prop;
+ int len;
+ const char *value;
+ const char *after;
+};
+
+static inline void of_iter_string_init(struct of_iter_string_prop *iter,
+ const struct device_node *np,
+ const char *name)
+{
+ iter->prop = of_find_property(np, name, &iter->len);
+ if (!iter->prop) {
+ iter->value = NULL;
+ return;
+ }
+
+ iter->value = iter->prop->value;
+ if (!iter->value)
+ return;
+
+ iter->after = iter->value + iter->len;
+}
+
+static inline bool of_iter_string_test(struct of_iter_string_prop *iter)
+{
+ if (!iter->value)
+ return false;
+
+ return iter->value < iter->after;
+}
+
+static inline void of_iter_string_next(struct of_iter_string_prop *iter)
+{
+ int len;
+
+ if (!iter->value)
+ return;
+
+ len = strnlen(iter->value, iter->len);
+ iter->len -= len;
+ iter->value += len + 1;
+}
+
+#define for_each_string_property_value(iter, np, prop_name) \
+ for (of_iter_string_init(&iter, np, prop_name); \
+ of_iter_string_test(&iter); \
+ of_iter_string_next(&iter))
+
+#else
+struct of_iter_u32_prop {
+ u32 value;
+};
+
+#define for_each_u32_property_value(iter, np, prop_name) \
+ while (0)
+
+struct of_iter_string_prop {
+ const char *value;
+};
+
+#define for_each_string_property_value(iter, np, prop_name) \
+ while (0)
+
+#endif /* CONFIG_OF */
+
+#endif /* __OF_ITER_PROP_H__ */
--
1.7.0.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH v3 12/13] arm/tegra: Add device tree support to pinmux driver
[not found] ` <1314315824-9687-1-git-send-email-swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (7 preceding siblings ...)
2011-08-25 23:43 ` [PATCH v3 11/13] of: add property iteration helpers Stephen Warren
@ 2011-08-25 23:43 ` Stephen Warren
2011-08-25 23:43 ` [PATCH v3 13/13] arm/tegra: board-dt: Remove dependency on non-dt pinmux functions Stephen Warren
2011-08-26 5:04 ` [PATCH v3 00/13] arm/tegra: Initialize GPIO & pinmux from DT Olof Johansson
10 siblings, 0 replies; 24+ messages in thread
From: Stephen Warren @ 2011-08-25 23:43 UTC (permalink / raw)
To: Grant Likely, Colin Cross, Erik Gilling, Olof Johansson
Cc: Russell King, Arnd Bergmann,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-tegra-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Belisko Marek, Jamie Iles,
Shawn Guo, Sergei Shtylyov, Linus Walleij, Stephen Warren
Signed-off-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
[j.iles: converted to generic of_pinmux_parse()]
Signed-off-by: Jamie Iles <jamie-wmLquQDDieKakBO8gow8eQ@public.gmane.org>
[swarren: Added support for pins property]
Signed-off-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
arch/arm/mach-tegra/pinmux.c | 260 ++++++++++++++++++++++++++++++++++++++++++
1 files changed, 260 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-tegra/pinmux.c b/arch/arm/mach-tegra/pinmux.c
index ed316f9..7526f7c 100644
--- a/arch/arm/mach-tegra/pinmux.c
+++ b/arch/arm/mach-tegra/pinmux.c
@@ -20,6 +20,9 @@
#include <linux/errno.h>
#include <linux/spinlock.h>
#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_iter_prop.h>
+#include <linux/of_pinmux.h>
#include <linux/platform_device.h>
#include <mach/iomap.h>
@@ -124,6 +127,19 @@ static const char *pingroup_name(enum tegra_pingroup pg)
return pingroups[pg].name;
}
+static int pingroup_enum(const char *name, enum tegra_pingroup *pg_out)
+{
+ int pg;
+
+ for (pg = 0; pg < TEGRA_MAX_PINGROUP; pg++)
+ if (!strcasecmp(name, tegra_soc_pingroups[pg].name)) {
+ *pg_out = pg;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
static const char *func_name(enum tegra_mux_func func)
{
if (func == TEGRA_MUX_RSVD1)
@@ -147,6 +163,39 @@ static const char *func_name(enum tegra_mux_func func)
return tegra_mux_names[func];
}
+static int func_enum(const char *name, enum tegra_mux_func *func_out)
+{
+ int func;
+
+ if (!strcasecmp(name, "RSVD1")) {
+ *func_out = TEGRA_MUX_RSVD1;
+ return 0;
+ }
+ if (!strcasecmp(name, "RSVD2")) {
+ *func_out = TEGRA_MUX_RSVD2;
+ return 0;
+ }
+ if (!strcasecmp(name, "RSVD3")) {
+ *func_out = TEGRA_MUX_RSVD3;
+ return 0;
+ }
+ if (!strcasecmp(name, "RSVD4")) {
+ *func_out = TEGRA_MUX_RSVD4;
+ return 0;
+ }
+ if (!strcasecmp(name, "NONE")) {
+ *func_out = TEGRA_MUX_NONE;
+ return 0;
+ }
+
+ for (func = 0; func < TEGRA_MAX_MUX; func++)
+ if (!strcasecmp(name, tegra_mux_names[func])) {
+ *func_out = func;
+ return 0;
+ }
+
+ return -EINVAL;
+}
static const char *tri_name(unsigned long val)
{
@@ -329,6 +378,20 @@ static const char *drive_pinmux_name(enum tegra_drive_pingroup pg)
return drive_pingroups[pg].name;
}
+static int drive_pinmux_enum(const char *name,
+ enum tegra_drive_pingroup *pg_out)
+{
+ int pg;
+
+ for (pg = 0; pg < TEGRA_MAX_DRIVE_PINGROUP; pg++)
+ if (!strcasecmp(name, drive_pingroups[pg].name)) {
+ *pg_out = pg;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
static const char *enable_name(unsigned long val)
{
return val ? "ENABLE" : "DISABLE";
@@ -666,15 +729,212 @@ void tegra_pinmux_config_pullupdown_table(const struct tegra_pingroup_config *co
}
}
+struct tegra_pinmux_configs {
+ struct tegra_pingroup_config tcfg;
+ struct of_pinmux_cfg ocfg;
+};
+
+static int __init tegra_pinmux_dt_parse(const struct of_pinmux_ctrl *ctrl,
+ struct of_pinmux_cfg *cfg)
+{
+ struct tegra_pinmux_configs *cfgs =
+ container_of(cfg, struct tegra_pinmux_configs, ocfg);
+ struct tegra_pingroup_config *tcfg = &cfgs->tcfg;
+ struct of_pinmux_cfg *ocfg = &cfgs->ocfg;
+ int ret;
+
+ ret = func_enum(ocfg->function, &tcfg->func);
+ if (ret < 0) {
+ dev_err(ctrl->dev, "invalid function %s in node %s\n",
+ ocfg->function, ocfg->node->name);
+ return ret;
+ }
+
+ if (ocfg->flags & OF_PINMUX_PULL_UP)
+ tcfg->pupd = TEGRA_PUPD_PULL_UP;
+ else if (ocfg->flags & OF_PINMUX_PULL_DOWN)
+ tcfg->pupd = TEGRA_PUPD_PULL_DOWN;
+ else
+ tcfg->pupd = TEGRA_PUPD_NORMAL;
+
+ tcfg->tristate = (ocfg->flags & OF_PINMUX_TRISTATE) ?
+ TEGRA_TRI_TRISTATE : TEGRA_TRI_NORMAL;
+
+ return 0;
+}
+
+static int __init tegra_pinmux_dt_configure(const struct of_pinmux_ctrl *ctrl,
+ const struct of_pinmux_cfg *cfg)
+{
+ struct tegra_pinmux_configs *cfgs =
+ container_of(cfg, struct tegra_pinmux_configs, ocfg);
+ struct tegra_pingroup_config *tcfg = &cfgs->tcfg;
+ struct of_pinmux_cfg *ocfg = &cfgs->ocfg;
+ int ret;
+
+ ret = pingroup_enum(ocfg->pin, &tcfg->pingroup);
+ if (ret < 0) {
+ dev_err(ctrl->dev, "invalid pingroup %s in node %s\n",
+ ocfg->pin, ocfg->node->name);
+ return ret;
+ }
+
+ tegra_pinmux_config_pingroup(tcfg);
+
+ return 0;
+}
+
+static void __init tegra_pinmux_parse_mux_groups(
+ struct platform_device *pdev,
+ struct device_node *mux_node)
+{
+ struct of_pinmux_ctrl tegra_pinmux_ctrl = {
+ .dev = &pdev->dev,
+ .node = mux_node,
+ .parse = tegra_pinmux_dt_parse,
+ .configure = tegra_pinmux_dt_configure,
+ };
+ struct tegra_pinmux_configs cfgs;
+
+ if (of_pinmux_parse(&tegra_pinmux_ctrl, &cfgs.ocfg))
+ pr_err("failed to parse pinmux configuration\n");
+}
+
+static void __init tegra_pinmux_parse_drive_groups(
+ struct platform_device *pdev,
+ struct device_node *drive_node)
+{
+ struct device_node *np;
+
+ for_each_child_of_node(drive_node, np) {
+ enum tegra_hsm hsm;
+ enum tegra_schmitt schmitt;
+ enum tegra_drive drive;
+ enum tegra_pull_strength pull_down;
+ enum tegra_pull_strength pull_up;
+ enum tegra_slew slew_rising;
+ enum tegra_slew slew_falling;
+ int ret;
+ bool hadpins = 0;
+ struct of_iter_string_prop iter;
+
+ if (of_find_property(np, "nvidia,high-speed-mode", NULL))
+ hsm = TEGRA_HSM_ENABLE;
+ else
+ hsm = TEGRA_HSM_DISABLE;
+
+ if (of_find_property(np, "nvidia,schmitt", NULL))
+ schmitt = TEGRA_SCHMITT_ENABLE;
+ else
+ schmitt = TEGRA_SCHMITT_DISABLE;
+
+ ret = of_property_read_u32(np, "nvidia,drive-power", &drive);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "no nvidia,drive-power for node %s\n",
+ np->name);
+ continue;
+ }
+
+ ret = of_property_read_u32(np, "nvidia,pull-down-strength",
+ &pull_down);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "no nvidia,pull-down-strength for node %s\n",
+ np->name);
+ continue;
+ }
+
+ ret = of_property_read_u32(np, "nvidia,pull-up-strength",
+ &pull_up);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "no nvidia,pull-up-strength for node %s\n",
+ np->name);
+ continue;
+ }
+
+ ret = of_property_read_u32(np, "nvidia,slew-rate-rising",
+ &slew_rising);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "no nvidia,slew_rate-rising for node %s\n",
+ np->name);
+ continue;
+ }
+
+ ret = of_property_read_u32(np, "nvidia,slew-rate-falling",
+ &slew_rising);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "no nvidia,slew_rate-falling for node %s\n",
+ np->name);
+ continue;
+ }
+
+ for_each_string_property_value(iter, np, "pins") {
+ enum tegra_drive_pingroup pg;
+
+ hadpins = 1;
+
+ ret = drive_pinmux_enum(iter.value, &pg);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "invalid pingroup %s in node %s\n",
+ iter.value, np->name);
+ continue;
+ }
+
+ dev_dbg(&pdev->dev,
+ "configure pin %s hsm %d schmitt %d drive %d "
+ "pull_down %d pull_up %d slew_r %d slew_f %d\n",
+ iter.value,
+ hsm, schmitt, drive,
+ pull_down, pull_up,
+ slew_rising, slew_falling);
+
+ tegra_drive_pinmux_config_pingroup(pg, hsm, schmitt,
+ drive, pull_down,
+ pull_up,
+ slew_rising,
+ slew_falling);
+ }
+
+ if (!hadpins)
+ dev_warn(&pdev->dev, "no pins for node %s\n",
+ np->name);
+ }
+}
+
static int __init tegra_pinmux_probe(struct platform_device *pdev)
{
+ if (pdev->dev.of_node != NULL) {
+ struct device_node *node;
+
+ for_each_child_of_node(pdev->dev.of_node, node) {
+ if (!strcmp(node->name, "nvidia,mux-groups"))
+ tegra_pinmux_parse_mux_groups(pdev, node);
+ else if (!strcmp(node->name, "nvidia,drive-groups"))
+ tegra_pinmux_parse_drive_groups(pdev, node);
+ else
+ dev_err(&pdev->dev, "%s: Unknown child node\n",
+ node->name);
+ }
+ }
+
return 0;
}
+static struct of_device_id tegra_pinmux_of_match[] __devinitdata = {
+ { .compatible = "nvidia,tegra20-pinmux", },
+ { },
+};
+
static struct platform_driver tegra_pinmux_driver = {
.driver = {
.name = "tegra-pinmux",
.owner = THIS_MODULE,
+ .of_match_table = tegra_pinmux_of_match,
},
.probe = tegra_pinmux_probe,
};
--
1.7.0.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* [PATCH v3 13/13] arm/tegra: board-dt: Remove dependency on non-dt pinmux functions
[not found] ` <1314315824-9687-1-git-send-email-swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (8 preceding siblings ...)
2011-08-25 23:43 ` [PATCH v3 12/13] arm/tegra: Add device tree support to pinmux driver Stephen Warren
@ 2011-08-25 23:43 ` Stephen Warren
2011-08-26 5:04 ` [PATCH v3 00/13] arm/tegra: Initialize GPIO & pinmux from DT Olof Johansson
10 siblings, 0 replies; 24+ messages in thread
From: Stephen Warren @ 2011-08-25 23:43 UTC (permalink / raw)
To: Grant Likely, Colin Cross, Erik Gilling, Olof Johansson
Cc: Russell King, Arnd Bergmann,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-tegra-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Belisko Marek, Jamie Iles,
Shawn Guo, Sergei Shtylyov, Linus Walleij, Stephen Warren
Signed-off-by: Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
---
arch/arm/mach-tegra/Makefile | 1 -
arch/arm/mach-tegra/board-dt.c | 10 ----------
2 files changed, 0 insertions(+), 11 deletions(-)
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index f11b910..bab6544 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -30,7 +30,6 @@ obj-${CONFIG_MACH_SEABOARD} += board-seaboard.o
obj-${CONFIG_MACH_SEABOARD} += board-seaboard-pinmux.o
obj-${CONFIG_MACH_TEGRA_DT} += board-dt.o
-obj-${CONFIG_MACH_TEGRA_DT} += board-harmony-pinmux.o
obj-${CONFIG_MACH_TRIMSLICE} += board-trimslice.o
obj-${CONFIG_MACH_TRIMSLICE} += board-trimslice-pinmux.o
diff --git a/arch/arm/mach-tegra/board-dt.c b/arch/arm/mach-tegra/board-dt.c
index 9f47e04..b6b3f28 100644
--- a/arch/arm/mach-tegra/board-dt.c
+++ b/arch/arm/mach-tegra/board-dt.c
@@ -41,14 +41,9 @@
#include <mach/irqs.h>
#include "board.h"
-#include "board-harmony.h"
#include "clock.h"
#include "devices.h"
-void harmony_pinmux_init(void);
-void seaboard_pinmux_init(void);
-
-
struct of_dev_auxdata tegra20_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC1_BASE, "sdhci-tegra.0", NULL),
OF_DEV_AUXDATA("nvidia,tegra20-sdhci", TEGRA_SDMMC2_BASE, "sdhci-tegra.1", NULL),
@@ -91,11 +86,6 @@ static void __init tegra_dt_init(void)
tegra_clk_init_from_table(tegra_dt_clk_init_table);
- if (of_machine_is_compatible("nvidia,harmony"))
- harmony_pinmux_init();
- else if (of_machine_is_compatible("nvidia,seaboard"))
- seaboard_pinmux_init();
-
/*
* Finished with the static registrations now; fill in the missing
* devices
--
1.7.0.4
^ permalink raw reply related [flat|nested] 24+ messages in thread* Re: [PATCH v3 00/13] arm/tegra: Initialize GPIO & pinmux from DT
[not found] ` <1314315824-9687-1-git-send-email-swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org>
` (9 preceding siblings ...)
2011-08-25 23:43 ` [PATCH v3 13/13] arm/tegra: board-dt: Remove dependency on non-dt pinmux functions Stephen Warren
@ 2011-08-26 5:04 ` Olof Johansson
[not found] ` <CAOesGMiygfaNkPa7uURCiJpC=WDinWhKi07LFgJ+5JoGW_fLKw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
10 siblings, 1 reply; 24+ messages in thread
From: Olof Johansson @ 2011-08-26 5:04 UTC (permalink / raw)
To: Stephen Warren
Cc: Grant Likely, Colin Cross, Erik Gilling, Russell King,
Arnd Bergmann, devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-tegra-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Belisko Marek, Jamie Iles,
Shawn Guo, Sergei Shtylyov, Linus Walleij
On Thu, Aug 25, 2011 at 4:43 PM, Stephen Warren <swarren-DDmLM1+adcrQT0dZR+AlfA@public.gmane.org> wrote:
> v3:
> * Build on Jamie Iles' patches to split some of the DT parsing into
> common code.
> * Renamed some properties to remove "nvidia," from name; they can be
> generic.
> * Support pins property, to apply DT nodes to multiple pins/groups
> * Some minor error-message changes driven by some of the above.
> * Removed requirement to #ifdef CONFIG_OF
> * Removed AUXDATA table entries in mach-tegra/board-dt.c
>
> TODO:
> * Convert from using strings to using integers for the function and pin
> names. This relies on the dtc patches I posted yesterday, but should
> be pretty simple once they're in.
>
> Jamie Iles (1):
> of: add a generic pinmux helper
>
> Stephen Warren (12):
> arm/tegra: Prep boards for gpio/pinmux conversion to pdevs
> docs/dt: Document nvidia,tegra20-gpio's nvidia,enabled-gpios property
> arm/dt: Tegra: Add nvidia,enabled-gpios property to GPIO controller
> docs/dt: Document nvidia,tegra20-pinmux binding
> arm/dt: Tegra: Add pinmux node
> dt: add empty for_each_child_of_node, of_find_property
> gpio/tegra: Convert to a platform device
> gpio/tegra: Add device tree support
> arm/tegra: Convert pinmux driver to a platform device
> of: add property iteration helpers
> arm/tegra: Add device tree support to pinmux driver
> arm/tegra: board-dt: Remove dependency on non-dt pinmux functions
This is looking pretty sane to me.
Grant, how do you prefer to handle this, since it spans of/dt, gpio
and tegra code? I can start a topic branch for Arnd to pull in for the
tegra parts, would you prefer picking up the of helper functions on
your own or is an ack from you and merge through the arm-soc tree
easier?
-Olof
^ permalink raw reply [flat|nested] 24+ messages in thread