diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
index 35df377..d7df311 100644
--- a/drivers/mtd/devices/docg3.c
+++ b/drivers/mtd/devices/docg3.c
@@ -1513,6 +1513,123 @@ static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
 	return ret;
 }
 
+static struct docg3 *sysfs_dev2docg3(struct device *dev,
+				     struct device_attribute *attr)
+{
+	int floor;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct mtd_info **docg3_floors = platform_get_drvdata(pdev);
+
+	floor = attr->attr.name[1] - '0';
+	if (floor < 0 || floor >= DOC_MAX_NBFLOORS)
+		return NULL;
+	else
+		return docg3_floors[floor]->priv;
+}
+
+static ssize_t dps0_is_key_locked(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct docg3 *docg3 = sysfs_dev2docg3(dev, attr);
+	int dps0;
+
+	doc_set_device_id(docg3, docg3->device_id);
+	dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS);
+	doc_set_device_id(docg3, 0);
+
+	return sprintf(buf, "%d\n", !(dps0 & DOC_DPS_KEY_OK));
+}
+
+static ssize_t dps1_is_key_locked(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct docg3 *docg3 = sysfs_dev2docg3(dev, attr);
+	int dps1;
+
+	doc_set_device_id(docg3, docg3->device_id);
+	dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS);
+	doc_set_device_id(docg3, 0);
+
+	return sprintf(buf, "%d\n", !(dps1 & DOC_DPS_KEY_OK));
+}
+
+static ssize_t dps0_insert_key(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct docg3 *docg3 = sysfs_dev2docg3(dev, attr);
+	int i;
+
+	if (count != DOC_LAYOUT_DPS_KEY_LENGTH)
+		return -EINVAL;
+
+	doc_set_device_id(docg3, docg3->device_id);
+	for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++)
+		doc_writeb(docg3, buf[i], DOC_DPS0_KEY);
+	doc_set_device_id(docg3, 0);
+	return count;
+}
+
+static ssize_t dps1_insert_key(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct docg3 *docg3 = sysfs_dev2docg3(dev, attr);
+	int i;
+
+	if (count != DOC_LAYOUT_DPS_KEY_LENGTH)
+		return -EINVAL;
+
+	doc_set_device_id(docg3, docg3->device_id);
+	for (i = 0; i < DOC_LAYOUT_DPS_KEY_LENGTH; i++)
+		doc_writeb(docg3, buf[i], DOC_DPS1_KEY);
+	doc_set_device_id(docg3, 0);
+	return count;
+}
+
+#define FLOOR_SYSFS(id) { \
+	__ATTR(f##id##_dps0_is_keylocked, S_IRUGO, dps0_is_key_locked, NULL), \
+	__ATTR(f##id##_dps1_is_keylocked, S_IRUGO, dps1_is_key_locked, NULL), \
+	__ATTR(f##id##_dps0_protection_key, S_IWUGO, NULL, dps0_insert_key), \
+	__ATTR(f##id##_dps1_protection_key, S_IWUGO, NULL, dps1_insert_key), \
+}
+
+static struct device_attribute doc_sys_attrs[DOC_MAX_NBFLOORS][4] = {
+	FLOOR_SYSFS(0), FLOOR_SYSFS(1), FLOOR_SYSFS(2), FLOOR_SYSFS(3)
+};
+
+static int doc_register_sysfs(struct platform_device *pdev,
+			      struct mtd_info **floors)
+{
+	int ret = 0, floor, i = 0;
+	struct device *dev = &pdev->dev;
+
+	for (floor = 0; !ret && floor < DOC_MAX_NBFLOORS && floors[floor];
+	     floor++)
+		for (i = 0; !ret && i < 4; i++)
+			ret = device_create_file(dev, &doc_sys_attrs[floor][i]);
+	if (!ret)
+		return 0;
+	do {
+		while (--i >= 0)
+			device_remove_file(dev, &doc_sys_attrs[floor][i]);
+		i = 4;
+	} while (--floor >= 0);
+	return ret;
+}
+
+static void doc_unregister_sysfs(struct platform_device *pdev,
+				 struct mtd_info **floors)
+{
+	struct device *dev = &pdev->dev;
+	int floor, i;
+
+	for (floor = 0; floor < DOC_MAX_NBFLOORS && floors[floor];
+	     floor++)
+		for (i = 0; i < 4; i++)
+			device_remove_file(dev, &doc_sys_attrs[floor][i]);
+}
+
 /*
  * Debug sysfs entries
  */
@@ -1927,6 +2044,9 @@ static int __init docg3_probe(struct platform_device *pdev)
 			found++;
 	}
 
+	ret = doc_register_sysfs(pdev, docg3_floors);
+	if (ret)
+		goto err_probe;
 	if (!found)
 		goto notfound;
 
@@ -1963,6 +2083,7 @@ static int __exit docg3_release(struct platform_device *pdev)
 	void __iomem *base = docg3->base;
 	int floor;
 
+	doc_unregister_sysfs(pdev, docg3_floors);
 	doc_dbg_unregister(docg3);
 	for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++)
 		if (docg3_floors[floor])
diff --git a/drivers/mtd/devices/docg3.h b/drivers/mtd/devices/docg3.h
index 07182f9..a349915 100644
--- a/drivers/mtd/devices/docg3.h
+++ b/drivers/mtd/devices/docg3.h
@@ -118,6 +118,8 @@
 #define DOC_BCH_SYNDROM(idx)		(0x1048 + (idx << 0))
 
 #define DOC_PROTECTION			0x1056
+#define DOC_DPS0_KEY			0x105c
+#define DOC_DPS1_KEY			0x105e
 #define DOC_DPS0_ADDRLOW		0x1060
 #define DOC_DPS0_ADDRHIGH		0x1062
 #define DOC_DPS1_ADDRLOW		0x1064
@@ -252,6 +254,17 @@
 #define DOC_PLANES_STATUS_PLANE0_KO	0x02
 #define DOC_PLANES_STATUS_PLANE1_KO	0x04
 
+/*
+ * DPS key management
+ *
+ * Each floor of docg3 has 2 protection areas: DPS0 and DPS1. These areas span
+ * across block boundaries, and define whether these blocks can be read or
+ * written.
+ * The definition is dynamically stored in page 0 of blocks (2,3) for DPS0, and
+ * page 0 of blocks (4,5) for DPS1.
+ */
+#define DOC_LAYOUT_DPS_KEY_LENGTH	8
+
 /**
  * struct docg3 - DiskOnChip driver private data
  * @dev: the device currently under control
