#include <linux/acpi.h>
 #include <linux/bitops.h>
+#include <linux/capability.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
 
        struct nvmem_device *nvmem;
        struct regulator *vcc_reg;
+       void (*read_post)(unsigned int off, char *buf, size_t count);
 
        /*
         * Some chips tie up multiple I2C addresses; dummy devices reserve
 struct at24_chip_data {
        u32 byte_len;
        u8 flags;
+       void (*read_post)(unsigned int off, char *buf, size_t count);
 };
 
 #define AT24_CHIP_DATA(_name, _len, _flags)                            \
                .byte_len = _len, .flags = _flags,                      \
        }
 
+#define AT24_CHIP_DATA_CB(_name, _len, _flags, _read_post)             \
+       static const struct at24_chip_data _name = {                    \
+               .byte_len = _len, .flags = _flags,                      \
+               .read_post = _read_post,                                \
+       }
+
+static void at24_read_post_vaio(unsigned int off, char *buf, size_t count)
+{
+       int i;
+
+       if (capable(CAP_SYS_ADMIN))
+               return;
+
+       /*
+        * Hide VAIO private settings to regular users:
+        * - BIOS passwords: bytes 0x00 to 0x0f
+        * - UUID: bytes 0x10 to 0x1f
+        * - Serial number: 0xc0 to 0xdf
+        */
+       for (i = 0; i < count; i++) {
+               if ((off + i <= 0x1f) ||
+                   (off + i >= 0xc0 && off + i <= 0xdf))
+                       buf[i] = 0;
+       }
+}
+
 /* needs 8 addresses as A0-A2 are ignored */
 AT24_CHIP_DATA(at24_data_24c00, 128 / 8, AT24_FLAG_TAKE8ADDR);
 /* old variants can't be handled with this generic entry! */
 /* spd is a 24c02 in memory DIMMs */
 AT24_CHIP_DATA(at24_data_spd, 2048 / 8,
        AT24_FLAG_READONLY | AT24_FLAG_IRUGO);
+/* 24c02_vaio is a 24c02 on some Sony laptops */
+AT24_CHIP_DATA_CB(at24_data_24c02_vaio, 2048 / 8,
+       AT24_FLAG_READONLY | AT24_FLAG_IRUGO,
+       at24_read_post_vaio);
 AT24_CHIP_DATA(at24_data_24c04, 4096 / 8, 0);
 AT24_CHIP_DATA(at24_data_24cs04, 16,
        AT24_FLAG_SERIAL | AT24_FLAG_READONLY);
        { "24mac402",   (kernel_ulong_t)&at24_data_24mac402 },
        { "24mac602",   (kernel_ulong_t)&at24_data_24mac602 },
        { "spd",        (kernel_ulong_t)&at24_data_spd },
+       { "24c02-vaio", (kernel_ulong_t)&at24_data_24c02_vaio },
        { "24c04",      (kernel_ulong_t)&at24_data_24c04 },
        { "24cs04",     (kernel_ulong_t)&at24_data_24cs04 },
        { "24c08",      (kernel_ulong_t)&at24_data_24c08 },
        struct device *dev;
        char *buf = val;
        int ret;
+       unsigned int orig_off = off;
+       char *orig_buf = buf;
+       size_t orig_count = count;
 
        at24 = priv;
        dev = at24_base_client_dev(at24);
 
        pm_runtime_put(dev);
 
+       if (unlikely(at24->read_post))
+               at24->read_post(orig_off, orig_buf, orig_count);
+
        return 0;
 }
 
        at24->byte_len = byte_len;
        at24->page_size = page_size;
        at24->flags = flags;
+       at24->read_post = cdata->read_post;
        at24->num_addresses = num_addresses;
        at24->offset_adj = at24_get_offset_adj(flags, byte_len);
        at24->client[0].client = client;