diff mbox

[2/2] mtd: maps: physmap_of: Add GPIO VPP control

Message ID 1342111121-23161-3-git-send-email-pawel.moll@arm.com
State New, archived
Headers show

Commit Message

Pawel Moll July 12, 2012, 4:38 p.m. UTC
Add a GPIO control of the VPP signal and "vpp-gpios"
tree property, specifying the GPIO line in a standard
DT way, including polarity flags.

Signed-off-by: Pawel Moll <pawel.moll@arm.com>
---
 .../devicetree/bindings/mtd/mtd-physmap.txt        |    7 +++-
 drivers/mtd/maps/physmap_of.c                      |   42 ++++++++++++++++++++
 2 files changed, 48 insertions(+), 1 deletion(-)
diff mbox

Patch

diff --git a/Documentation/devicetree/bindings/mtd/mtd-physmap.txt b/Documentation/devicetree/bindings/mtd/mtd-physmap.txt
index a63c2bd7..28084cf 100644
--- a/Documentation/devicetree/bindings/mtd/mtd-physmap.txt
+++ b/Documentation/devicetree/bindings/mtd/mtd-physmap.txt
@@ -13,10 +13,13 @@  file systems on embedded devices.
    device width times the number of interleaved chips.
  - device-width : (optional) Width of a single mtd chip.  If
    omitted, assumed to be equal to 'bank-width'.
+ - vpp-gpios : (optional) specifies the GPIO line to control
+   VPP signal of the flash chip, the polarity is defined as a
+   standard flag (see Documentation/devicetree/bindings/gpio/gpio.txt
+   for more details and examples below)
  - #address-cells, #size-cells : Must be present if the device has
    sub-nodes representing partitions (see below).  In this case
    both #address-cells and #size-cells must be equal to 1.
-
 For JEDEC compatible devices, the following additional properties
 are defined:
 
@@ -33,6 +36,7 @@  Example:
 		reg = <ff000000 01000000>;
 		bank-width = <4>;
 		device-width = <1>;
+		vpp-gpios = <&pio2 1 0>; /* PIO2.1 active high */
 		#address-cells = <1>;
 		#size-cells = <1>;
 		fs@0 {
@@ -55,6 +59,7 @@  Here an example with multiple "reg" tuples:
 		reg = <0 0x00000000 0x02000000
 		       0 0x02000000 0x02000000>;
 		bank-width = <2>;
+		vpp-gpios = <&pio3 2 1>; /* PIO3.2 active low */
 		partition@0 {
 			label = "test-part1";
 			reg = <0 0x04000000>;
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index 2e6fb68..81caa77 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -17,12 +17,14 @@ 
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/gpio.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/concat.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/of_gpio.h>
 #include <linux/of_platform.h>
 #include <linux/slab.h>
 
@@ -74,6 +76,24 @@  static int of_flash_remove(struct platform_device *dev)
 	return 0;
 }
 
+static void of_flash_set_vpp_high(struct map_info *map, int state)
+{
+	/* map_priv_1 = gpio, map_priv_2 = "reference counter" */
+	if (state && !map->map_priv_2++)
+		gpio_set_value(map->map_priv_1, 1);
+	else if (!state && !--map->map_priv_2)
+		gpio_set_value(map->map_priv_1, 0);
+}
+
+static void of_flash_set_vpp_low(struct map_info *map, int state)
+{
+	/* map_priv_1 = gpio, map_priv_2 = "reference counter" */
+	if (state && !map->map_priv_2++)
+		gpio_set_value(map->map_priv_1, 0);
+	else if (!state && !--map->map_priv_2)
+		gpio_set_value(map->map_priv_1, 1);
+}
+
 /* Helper function to handle probing of the obsolete "direct-mapped"
  * compatible binding, which has an extra "probe-type" property
  * describing the type of flash probe necessary. */
@@ -169,6 +189,9 @@  static int __devinit of_flash_probe(struct platform_device *dev)
 	struct mtd_info **mtd_list = NULL;
 	resource_size_t res_size;
 	struct mtd_part_parser_data ppdata;
+	void (*set_vpp)(struct map_info *, int) = NULL;
+	int gpio_vpp;
+	enum of_gpio_flags gpio_flags;
 
 	match = of_match_device(of_flash_match, &dev->dev);
 	if (!match)
@@ -200,6 +223,23 @@  static int __devinit of_flash_probe(struct platform_device *dev)
 
 	dev_set_drvdata(&dev->dev, info);
 
+	gpio_vpp = of_get_named_gpio_flags(dp, "vpp-gpios", 0, &gpio_flags);
+	if (gpio_is_valid(gpio_vpp)) {
+		unsigned long dir = GPIOF_DIR_OUT;
+
+		if (gpio_flags & OF_GPIO_ACTIVE_LOW) {
+			set_vpp = of_flash_set_vpp_low;
+			dir |= GPIOF_INIT_HIGH;
+		} else {
+			set_vpp = of_flash_set_vpp_high;
+			dir |= GPIOF_INIT_LOW;
+		}
+		err = devm_gpio_request_one(&dev->dev, gpio_vpp, dir,
+				dev_name(&dev->dev));
+		if (err)
+			goto err_flash_remove;
+	}
+
 	mtd_list = kzalloc(sizeof(*mtd_list) * count, GFP_KERNEL);
 	if (!mtd_list)
 		goto err_flash_remove;
@@ -235,6 +275,8 @@  static int __devinit of_flash_probe(struct platform_device *dev)
 		info->list[i].map.phys = res.start;
 		info->list[i].map.size = res_size;
 		info->list[i].map.bankwidth = be32_to_cpup(width);
+		info->list[i].map.set_vpp = set_vpp;
+		info->list[i].map.map_priv_1 = gpio_vpp;
 
 		err = -ENOMEM;
 		info->list[i].map.virt = ioremap(info->list[i].map.phys,